From b97de32a44d46dc1fa90ee35315b5090b161ee32 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 12 Dec 2023 15:41:36 -0800 Subject: [PATCH 1/9] IO-2501 Add Jobs Complete Not Invoiced Section to Stats --- .../scoreboard-timetickets.component.jsx | 19 ++++++++- ...scoreboard-timetickets.stats.component.jsx | 42 +++++++++++++++++-- client/src/graphql/timetickets.queries.js | 31 +++++++++++++- client/src/translations/en_us/common.json | 2 + client/src/translations/es/common.json | 2 + client/src/translations/fr/common.json | 2 + 6 files changed, 90 insertions(+), 8 deletions(-) diff --git a/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx b/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx index 0117279d5..af4f28695 100644 --- a/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx +++ b/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx @@ -29,7 +29,7 @@ export default connect( export function ScoreboardTimeTicketsStats({ bodyshop }) { const { t } = useTranslation(); - const startDate = moment().startOf("month") + const startDate = moment().startOf("month"); const endDate = moment().endOf("month"); const fixedPeriods = useMemo(() => { @@ -84,6 +84,8 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) { end: endDate.format("YYYY-MM-DD"), fixedStart: fixedPeriods.start.format("YYYY-MM-DD"), fixedEnd: fixedPeriods.end.format("YYYY-MM-DD"), + jobStart: startDate, + jobEnd: endDate, }, fetchPolicy: "network-only", nextFetchPolicy: "network-only", @@ -340,11 +342,21 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) { larData.push({ ...r, ...lar }); }); + const jobData = {}; + data.jobs.forEach((job) => { + job.tthrs = job.joblines.reduce((acc, val) => acc + val.mod_lb_hrs, 0); + }); + jobData.tthrs = data.jobs + .reduce((acc, val) => acc + val.tthrs, 0) + .toFixed(1); + jobData.count = data.jobs.length.toFixed(0); + return { fixed: ret, combinedData: combinedData, labData: labData, larData: larData, + jobData: jobData, }; }, [fixedPeriods, data, bodyshop]); @@ -356,7 +368,10 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) { - + {/* This Month */} - + @@ -482,7 +482,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) { {/* Last Month */} - + @@ -556,7 +556,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) { {/* Efficiency Over Period */} - + + + + + + + + + + + + {t("scoreboard.labels.totalhrs")} + + } + value={jobData.tthrs} + valueStyle={{ + fontSize: statisticSize, + fontWeight: statisticWeight, + }} + /> + + + + {/* Disclaimer */} diff --git a/client/src/graphql/timetickets.queries.js b/client/src/graphql/timetickets.queries.js index bb90c4e9d..9f3dec512 100644 --- a/client/src/graphql/timetickets.queries.js +++ b/client/src/graphql/timetickets.queries.js @@ -143,9 +143,14 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql` $end: date! $fixedStart: date! $fixedEnd: date! + $jobStart: timestamptz! + $jobEnd: timestamptz! ) { timetickets( - where: { date: { _gte: $start, _lte: $end }, cost_center: {_neq: "timetickets.labels.shift"} } + where: { + date: { _gte: $start, _lte: $end } + cost_center: { _neq: "timetickets.labels.shift" } + } order_by: { date: desc_nulls_first } ) { actualhrs @@ -176,7 +181,10 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql` } } fixedperiod: timetickets( - where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, cost_center: {_neq: "timetickets.labels.shift"} } + where: { + date: { _gte: $fixedStart, _lte: $fixedEnd } + cost_center: { _neq: "timetickets.labels.shift" } + } order_by: { date: desc_nulls_first } ) { actualhrs @@ -205,6 +213,25 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql` last_name } } + jobs( + where: { + date_invoiced: { _is_null: true } + ro_number: { _is_null: false } + voided: { _eq: false } + _or: [ + { actual_completion: { _gte: $jobStart, _lte: $jobEnd } } + { actual_delivery: { _gte: $jobStart, _lte: $jobEnd } } + ] + } + ) { + id + joblines(order_by: { line_no: asc }, where: { removed: { _eq: false } }) { + convertedtolbr + convertedtolbr_data + mod_lb_hrs + mod_lbr_ty + } + } } `; diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bbac4cc7b..04a647924 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2695,6 +2695,7 @@ "efficiencyoverperiod": "Efficiency over Selected Dates", "entries": "Scoreboard Entries", "jobs": "Jobs", + "jobscompletednotinvoiced": "Completed Not Invoiced", "lastmonth": "Last Month", "lastweek": "Last Week", "monthlytarget": "Monthly", @@ -2709,6 +2710,7 @@ "timetickets": "Time Tickets", "timeticketsemployee": "Time Tickets by Employee", "todateactual": "Actual (MTD)", + "totalhrs": "Total Hours", "totaloverperiod": "Total over Selected Dates", "weeklyactual": "Actual (W)", "weeklytarget": "Weekly", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 33cf621da..56ca50899 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2695,6 +2695,7 @@ "efficiencyoverperiod": "", "entries": "", "jobs": "", + "jobscompletednotinvoiced": "", "lastmonth": "", "lastweek": "", "monthlytarget": "", @@ -2709,6 +2710,7 @@ "timetickets": "", "timeticketsemployee": "", "todateactual": "", + "totalhrs": "", "totaloverperiod": "", "weeklyactual": "", "weeklytarget": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 3b5251fa7..690bf246b 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2695,6 +2695,7 @@ "efficiencyoverperiod": "", "entries": "", "jobs": "", + "jobscompletednotinvoiced": "", "lastmonth": "", "lastweek": "", "monthlytarget": "", @@ -2709,6 +2710,7 @@ "timetickets": "", "timeticketsemployee": "", "todateactual": "", + "totalhrs": "", "totaloverperiod": "", "weeklyactual": "", "weeklytarget": "", From 2dd56590d3f3d799c0b567b6bcc876dbfcf80e3f Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 14 Dec 2023 08:57:36 -0800 Subject: [PATCH 2/9] Admin panel to force email addresses to be lowercase to conform with firebase --- server/firebase/firebase-handler.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/firebase/firebase-handler.js b/server/firebase/firebase-handler.js index 7221649ec..e203bcbf3 100644 --- a/server/firebase/firebase-handler.js +++ b/server/firebase/firebase-handler.js @@ -50,7 +50,7 @@ exports.createUser = async (req, res) => { `, { user: { - email, + email: email.toLowerCase(), authid: userRecord.uid, associations: { data: [{ shopid, authlevel, active: true }], From 661bedbe5b555540a69246f480091a2e715670bf Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 18 Dec 2023 12:36:46 -0800 Subject: [PATCH 3/9] IO-2506 Federal Tax Exempt on Bill Entry Will Toggle Federal Tax off on any new line or retroactively toggle it off on all lines when switch is enabled. Limited to PBS or CDK setups. --- .../bill-form/bill-form.component.jsx | 25 +++++++++++++++++-- .../bill-form/bill-form.lines.component.jsx | 8 +++--- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 5 files changed, 31 insertions(+), 5 deletions(-) diff --git a/client/src/components/bill-form/bill-form.component.jsx b/client/src/components/bill-form/bill-form.component.jsx index 44b8cd815..579d11b7b 100644 --- a/client/src/components/bill-form/bill-form.component.jsx +++ b/client/src/components/bill-form/bill-form.component.jsx @@ -79,6 +79,18 @@ export function BillFormComponent({ }); }; + const handleFederalTaxExemptSwitchToggle = (checked) => { + if (checked) { + const values = form.getFieldsValue("billlines"); + if (values && values.billlines && values.billlines.length > 0) { + values.billlines.forEach((b) => { + b.applicable_taxes.federal = false; + }); + } + form.setFieldsValue({ billlines: values.billlines }); + } + }; + useEffect(() => { if (job) form.validateFields(["is_credit_memo"]); }, [job, form]); @@ -387,7 +399,16 @@ export function BillFormComponent({ > - + {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? ( + + + + ) : null} + {() => { const values = form.getFieldsValue([ "billlines", @@ -405,7 +426,7 @@ export function BillFormComponent({ totals = CalculateBillTotal(values); if (!!totals) return ( -
+
Date: Mon, 18 Dec 2023 14:12:21 -0800 Subject: [PATCH 4/9] IO-2509 Report Center RBAC --- .../components/rbac-wrapper/rbac-defaults.js | 5 +- .../report-center-modal.container.jsx | 5 +- .../shop-info/shop-info.rbac.component.jsx | 428 +++++++++--------- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + 6 files changed, 230 insertions(+), 211 deletions(-) diff --git a/client/src/components/rbac-wrapper/rbac-defaults.js b/client/src/components/rbac-wrapper/rbac-defaults.js index 24a564872..a01dd54c2 100644 --- a/client/src/components/rbac-wrapper/rbac-defaults.js +++ b/client/src/components/rbac-wrapper/rbac-defaults.js @@ -55,10 +55,11 @@ const ret = { "shiftclock:view": 2, "shop:config": 4, - "shop:rbac": 5, - "shop:vendors": 2, "shop:dashboard": 3, + "shop:rbac": 5, + "shop:reportcenter": 2, "shop:templates": 4, + "shop:vendors": 2, "temporarydocs:view": 2, diff --git a/client/src/components/report-center-modal/report-center-modal.container.jsx b/client/src/components/report-center-modal/report-center-modal.container.jsx index f0d361785..84fe65560 100644 --- a/client/src/components/report-center-modal/report-center-modal.container.jsx +++ b/client/src/components/report-center-modal/report-center-modal.container.jsx @@ -5,6 +5,7 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { selectReportCenter } from "../../redux/modals/modals.selectors"; +import RbacWrapperComponent from "../rbac-wrapper/rbac-wrapper.component"; import ReportCenterModalComponent from "./report-center-modal.component"; const mapStateToProps = createStructuredSelector({ @@ -33,7 +34,9 @@ export function ReportCenterModalContainer({ destroyOnClose width="80%" > - + + + ); } diff --git a/client/src/components/shop-info/shop-info.rbac.component.jsx b/client/src/components/shop-info/shop-info.rbac.component.jsx index fe4f80f31..e4152fb88 100644 --- a/client/src/components/shop-info/shop-info.rbac.component.jsx +++ b/client/src/components/shop-info/shop-info.rbac.component.jsx @@ -28,18 +28,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { return ( - - - + + + + + + + + + + + + @@ -173,26 +209,38 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { + + + @@ -208,30 +256,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { > - - - - - - - - - @@ -280,6 +292,18 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { > + + + + + + + + + + + + + + + @@ -329,74 +401,14 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { - - - - - - - - - - - - - - - @@ -412,18 +424,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { > - - - + + + + + + - - - - - - @@ -556,18 +556,6 @@ export function ShopInfoRbacComponent({ form, bodyshop }) { > - - - + + + + + + + + + + + + + + + - - - - - - - - - {Simple_Inventory.treatment === "on" && ( <> Config", "dashboard": "Shop -> Dashboard", "rbac": "Shop -> RBAC", + "reportcenter": "Shop -> Report Center", "templates": "Shop -> Templates", "vendors": "Shop -> Vendors" }, diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 33cf621da..1d3784879 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -447,6 +447,7 @@ "config": "", "dashboard": "", "rbac": "", + "reportcenter": "", "templates": "", "vendors": "" }, diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 3b5251fa7..abdb28e00 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -447,6 +447,7 @@ "config": "", "dashboard": "", "rbac": "", + "reportcenter": "", "templates": "", "vendors": "" }, From 0117237988a02fffb23da2e4f0021844cd2acd66 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 19 Dec 2023 09:18:00 -0800 Subject: [PATCH 5/9] IO-2506 Correct for variable immutibility and nested ifs --- .../bill-form/bill-form.component.jsx | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/client/src/components/bill-form/bill-form.component.jsx b/client/src/components/bill-form/bill-form.component.jsx index 579d11b7b..ba9f937ba 100644 --- a/client/src/components/bill-form/bill-form.component.jsx +++ b/client/src/components/bill-form/bill-form.component.jsx @@ -80,15 +80,17 @@ export function BillFormComponent({ }; const handleFederalTaxExemptSwitchToggle = (checked) => { - if (checked) { - const values = form.getFieldsValue("billlines"); - if (values && values.billlines && values.billlines.length > 0) { - values.billlines.forEach((b) => { - b.applicable_taxes.federal = false; - }); - } - form.setFieldsValue({ billlines: values.billlines }); - } + // Early gate + if (!checked) return; + const values = form.getFieldsValue("billlines"); + // Gate bill lines + if (!values?.billlines?.length) return; + + const billlines = values.billlines.map((b) => { + b.applicable_taxes.federal = false; + return b; + }); + form.setFieldsValue({ billlines }); }; useEffect(() => { From 1ff5ed414168c55a28c8fc2e3625a5edb4483055 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 20 Dec 2023 11:36:42 -0800 Subject: [PATCH 6/9] IO-1366 Audit Logging for Production Alert --- .../jobs-detail-header-actions.component.jsx | 8 +++++ ...roduction-list-columns.alert.component.jsx | 30 +++++++++++++++++-- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + client/src/utils/AuditTrailMappings.js | 1 + 6 files changed, 39 insertions(+), 3 deletions(-) diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx index ae3ba9a7b..bf0b049fb 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx @@ -108,6 +108,14 @@ export function JobsDetailHeaderActions({ }, }, }); + insertAuditTrail({ + jobid: job.id, + operation: AuditTrailMapping.alertToggle( + !!job.production_vars && !!job.production_vars.alert + ? !job.production_vars.alert + : true + ), + }); }; const handleSuspend = (e) => { diff --git a/client/src/components/production-list-columns/production-list-columns.alert.component.jsx b/client/src/components/production-list-columns/production-list-columns.alert.component.jsx index 8823afb46..8bad135ca 100644 --- a/client/src/components/production-list-columns/production-list-columns.alert.component.jsx +++ b/client/src/components/production-list-columns/production-list-columns.alert.component.jsx @@ -1,12 +1,23 @@ import { ExclamationCircleFilled } from "@ant-design/icons"; +import { useMutation } from "@apollo/client"; import { Dropdown, Menu } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; -import { useMutation } from "@apollo/client"; -import { UPDATE_JOB } from "../../graphql/jobs.queries"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; import { logImEXEvent } from "../../firebase/firebase.utils"; +import { UPDATE_JOB } from "../../graphql/jobs.queries"; +import { insertAuditTrail } from "../../redux/application/application.actions"; +import AuditTrailMapping from "../../utils/AuditTrailMappings"; -export default function ProductionListColumnAlert({ record }) { +const mapStateToProps = createStructuredSelector({}); + +const mapDispatchToProps = (dispatch) => ({ + insertAuditTrail: ({ jobid, operation }) => + dispatch(insertAuditTrail({ jobid, operation })), +}); + +export function ProductionListColumnAlert({ record, insertAuditTrail }) { const { t } = useTranslation(); const [updateAlert] = useMutation(UPDATE_JOB); @@ -27,6 +38,14 @@ export default function ProductionListColumnAlert({ record }) { }, }, }, + }); + insertAuditTrail({ + jobid: record.id, + operation: AuditTrailMapping.alertToggle( + !!record.production_vars && !!record.production_vars.alert + ? !record.production_vars.alert + : true + ), }).then(() => { if (record.refetch) record.refetch(); }); @@ -58,3 +77,8 @@ export default function ProductionListColumnAlert({ record }) { ); } + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ProductionListColumnAlert); diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bbac4cc7b..d8a8da68a 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -103,6 +103,7 @@ "admin_jobmarkforreexport": "ADMIN: Job marked for re-export.", "admin_jobuninvoice": "ADMIN: Job has been uninvoiced.", "admin_jobunvoid": "ADMIN: Job has been unvoided.", + "alerttoggle": "Alert Toggle set to {{status}}", "appointmentcancel": "Appointment canceled. Lost Reason: {{lost_sale_reason}}.", "appointmentinsert": "Appointment created. Appointment Date: {{start}}.", "billposted": "Bill with invoice number {{invoice_number}} posted.", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 33cf621da..4049e024b 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -103,6 +103,7 @@ "admin_jobmarkforreexport": "", "admin_jobuninvoice": "", "admin_jobunvoid": "", + "alerttoggle": "", "appointmentcancel": "", "appointmentinsert": "", "billposted": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 3b5251fa7..2f55093e1 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -103,6 +103,7 @@ "admin_jobmarkforreexport": "", "admin_jobuninvoice": "", "admin_jobunvoid": "", + "alerttoggle": "", "appointmentcancel": "", "appointmentinsert": "", "billposted": "", diff --git a/client/src/utils/AuditTrailMappings.js b/client/src/utils/AuditTrailMappings.js index afa0de1e5..edfebdab1 100644 --- a/client/src/utils/AuditTrailMappings.js +++ b/client/src/utils/AuditTrailMappings.js @@ -1,6 +1,7 @@ import i18n from "i18next"; const AuditTrailMapping = { + alertToggle: (status) => i18n.t("audit_trail.messages.alerttoggle", { status }), appointmentcancel: (lost_sale_reason) => i18n.t("audit_trail.messages.appointmentcancel", { lost_sale_reason }), appointmentinsert: (start) => From 482b03c2d19ef46fe8dbd9c50b4b39a7f9d9b329 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 20 Dec 2023 11:52:04 -0800 Subject: [PATCH 7/9] IO-1366 Invoice Job Audit Trail --- .../pages/jobs-close/jobs-close.component.jsx | 16 ++++++++++++++-- client/src/translations/en_us/common.json | 1 + client/src/translations/es/common.json | 1 + client/src/translations/fr/common.json | 1 + client/src/utils/AuditTrailMappings.js | 2 ++ 5 files changed, 19 insertions(+), 2 deletions(-) diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx index 91c8c7385..b6feb3ff5 100644 --- a/client/src/pages/jobs-close/jobs-close.component.jsx +++ b/client/src/pages/jobs-close/jobs-close.component.jsx @@ -36,14 +36,22 @@ import JobsCloseLines from "../../components/jobs-close-lines/jobs-close-lines.c import LayoutFormRow from "../../components/layout-form-row/layout-form-row.component"; import { generateJobLinesUpdatesForInvoicing } from "../../graphql/jobs-lines.queries"; import { UPDATE_JOB } from "../../graphql/jobs.queries"; +import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; +import AuditTrailMapping from "../../utils/AuditTrailMappings"; + const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, jobRO: selectJobReadOnly, }); -export function JobsCloseComponent({ job, bodyshop, jobRO }) { +const mapDispatchToProps = (dispatch) => ({ + insertAuditTrail: ({ jobid, operation }) => + dispatch(insertAuditTrail({ jobid, operation })), +}); + +export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, }) { const { t } = useTranslation(); const [form] = Form.useForm(); const client = useApolloClient(); @@ -110,6 +118,10 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) { notification["success"]({ message: t("jobs.successes.closed"), }); + insertAuditTrail({ + jobid: job.id, + operation: AuditTrailMapping.jobinvoiced(), + }); // history.push(`/manage/jobs/${job.id}`); } else { setLoading(false); @@ -527,4 +539,4 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
); } -export default connect(mapStateToProps, null)(JobsCloseComponent); +export default connect(mapStateToProps, mapDispatchToProps)(JobsCloseComponent); diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index d8a8da68a..cf55cfeb2 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -112,6 +112,7 @@ "jobassignmentchange": "Employee {{name}} assigned to {{operation}}", "jobassignmentremoved": "Employee assignment removed for {{operation}}", "jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.", + "jobinvoiced": "Job has been invoiced.", "jobconverted": "Job converted and assigned number {{ro_number}}.", "jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.", "jobimported": "Job imported.", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 4049e024b..fd3bebe6f 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -112,6 +112,7 @@ "jobassignmentchange": "", "jobassignmentremoved": "", "jobchecklist": "", + "jobinvoiced": "", "jobconverted": "", "jobfieldchanged": "", "jobimported": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 2f55093e1..dab607ebc 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -112,6 +112,7 @@ "jobassignmentchange": "", "jobassignmentremoved": "", "jobchecklist": "", + "jobinvoiced": "", "jobconverted": "", "jobfieldchanged": "", "jobimported": "", diff --git a/client/src/utils/AuditTrailMappings.js b/client/src/utils/AuditTrailMappings.js index edfebdab1..d7098fa2d 100644 --- a/client/src/utils/AuditTrailMappings.js +++ b/client/src/utils/AuditTrailMappings.js @@ -12,6 +12,8 @@ const AuditTrailMapping = { "ADMIN: " + i18n.t("audit_trail.messages.jobstatuschange", { status }), jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"), jobimported: () => i18n.t("audit_trail.messages.jobimported"), + jobinvoiced: () => + i18n.t("audit_trail.messages.jobinvoiced"), jobconverted: (ro_number) => i18n.t("audit_trail.messages.jobconverted", { ro_number }), jobfieldchange: (field, value) => From 25e8eaa1d40e0b1aa2af0472f63811308bfc849c Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 21 Dec 2023 09:24:25 -0800 Subject: [PATCH 8/9] IO-2505 Conversation List Print --- .../chat-conversation-title.component.jsx | 2 + .../chat-print-button.component.jsx | 59 +++++++++++++++++++ client/src/translations/en_us/common.json | 3 + client/src/translations/es/common.json | 3 + client/src/translations/fr/common.json | 3 + client/src/utils/TemplateConstants.js | 11 ++++ 6 files changed, 81 insertions(+) create mode 100644 client/src/components/chat-print-button/chat-print-button.component.jsx diff --git a/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx b/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx index 1503bf46f..110ea2ea3 100644 --- a/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx +++ b/client/src/components/chat-conversation-title/chat-conversation-title.component.jsx @@ -4,6 +4,7 @@ import PhoneNumberFormatter from "../../utils/PhoneFormatter"; import ChatArchiveButton from "../chat-archive-button/chat-archive-button.component"; import ChatConversationTitleTags from "../chat-conversation-title-tags/chat-conversation-title-tags.component"; import ChatLabelComponent from "../chat-label/chat-label.component"; +import ChatPrintButton from "../chat-print-button/chat-print-button.component"; import ChatTagRoContainer from "../chat-tag-ro/chat-tag-ro.container"; export default function ChatConversationTitle({ conversation }) { @@ -13,6 +14,7 @@ export default function ChatConversationTitle({ conversation }) { {conversation && conversation.phone_num} + ({ + setEmailOptions: (e) => dispatch(setEmailOptions(e)), +}); + +export function ChatPrintButton({ conversation }) { + const [loading, setLoading] = useState(false); + + return ( + + { + setLoading(true); + GenerateDocument( + { + name: TemplateList("messaging").conversation_list.key, + variables: { id: conversation.id }, + }, + { + subject: TemplateList("messaging").conversation_list.subject, + }, + "p", + conversation.id + ); + setLoading(false); + }} + /> + { + setLoading(true); + GenerateDocument( + { + name: TemplateList("messaging").conversation_list.key, + variables: { id: conversation.id }, + }, + { + subject: TemplateList("messaging").conversation_list.subject, + }, + "e", + conversation.id + ); + setLoading(false); + }} + /> + {loading && } + + ); +} +export default connect(mapStateToProps, mapDispatchToProps)(ChatPrintButton); diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bbac4cc7b..4d54c3b95 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2044,6 +2044,9 @@ "sentby": "Sent by {{by}} at {{time}}", "typeamessage": "Send a message...", "unarchive": "Unarchive" + }, + "render": { + "conversation_list": "Conversation List" } }, "notes": { diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 33cf621da..6e558f3f9 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2044,6 +2044,9 @@ "sentby": "", "typeamessage": "Enviar un mensaje...", "unarchive": "" + }, + "render": { + "conversation_list": "" } }, "notes": { diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 3b5251fa7..7874bc07e 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2044,6 +2044,9 @@ "sentby": "", "typeamessage": "Envoyer un message...", "unarchive": "" + }, + "render": { + "conversation_list": "" } }, "notes": { diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js index c5e10d712..365b2431e 100644 --- a/client/src/utils/TemplateConstants.js +++ b/client/src/utils/TemplateConstants.js @@ -2102,6 +2102,17 @@ export const TemplateList = (type, context) => { // }, } : {}), + ...(!type || type === "messaging" + ? { + conversation_list: { + title: i18n.t("messaging.render.conversation_list"), + description: "", + subject: i18n.t("messaging.render.conversation_list"), + key: "conversation_list", + disabled: false, + }, + } + : {}), ...(!type || type === "vendor" ? { purchases_by_vendor_detailed: { From 1e7f43fe3df295e57ce57eafb9cbeb4371eb42b6 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 21 Dec 2023 18:32:37 -0800 Subject: [PATCH 9/9] IO-2501 Correct for missing query variables --- .../scoreboard-timetickets/scoreboard-timetickets.component.jsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/src/components/scoreboard-timetickets/scoreboard-timetickets.component.jsx b/client/src/components/scoreboard-timetickets/scoreboard-timetickets.component.jsx index 0fc84af6d..9fdb384d1 100644 --- a/client/src/components/scoreboard-timetickets/scoreboard-timetickets.component.jsx +++ b/client/src/components/scoreboard-timetickets/scoreboard-timetickets.component.jsx @@ -65,6 +65,8 @@ export default function ScoreboardTimeTickets() { end: endDate.format("YYYY-MM-DD"), fixedStart: fixedPeriods.start.format("YYYY-MM-DD"), fixedEnd: fixedPeriods.end.format("YYYY-MM-DD"), + jobStart: startDate, + jobEnd: endDate, }, fetchPolicy: "network-only", nextFetchPolicy: "network-only",