From b97de32a44d46dc1fa90ee35315b5090b161ee32 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 12 Dec 2023 15:41:36 -0800 Subject: [PATCH 01/24] 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 02/24] 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 03/24] 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 04/24] 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 05/24] 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 06/24] 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 07/24] 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 08/24] 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 09/24] 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", From f6a59bdf5512d53321aa6b9163f6f20eee1ff6f2 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Tue, 26 Dec 2023 11:18:39 -0800 Subject: [PATCH 10/24] IO-2511 Bill Label Reprint --- .../bill-detail-edit-component.jsx | 5 ++- .../bill-print-button.component.jsx | 38 +++++++++++++++++++ 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, 44 insertions(+), 2 deletions(-) create mode 100644 client/src/components/bill-print-button/bill-print-button.component.jsx diff --git a/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx b/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx index e92bb175b..12ca80301 100644 --- a/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx +++ b/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx @@ -10,7 +10,7 @@ import { createStructuredSelector } from "reselect"; import { DELETE_BILL_LINE, INSERT_NEW_BILL_LINES, - UPDATE_BILL_LINE + UPDATE_BILL_LINE, } from "../../graphql/bill-lines.queries"; import { QUERY_BILL_BY_PK, UPDATE_BILL } from "../../graphql/bills.queries"; import { insertAuditTrail } from "../../redux/application/application.actions"; @@ -20,6 +20,7 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AlertComponent from "../alert/alert.component"; import BillFormContainer from "../bill-form/bill-form.container"; import BillMarkExportedButton from "../bill-mark-exported-button/bill-mark-exported-button.component"; +import BillPrintButton from "../bill-print-button/bill-print-button.component"; import BillReeportButtonComponent from "../bill-reexport-button/bill-reexport-button.component"; import JobDocumentsGallery from "../jobs-documents-gallery/jobs-documents-gallery.container"; import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-documents-local-gallery.container"; @@ -176,7 +177,7 @@ export function BillDetailEditcontainer({ extra={ - + form.submit()} diff --git a/client/src/components/bill-print-button/bill-print-button.component.jsx b/client/src/components/bill-print-button/bill-print-button.component.jsx new file mode 100644 index 000000000..46e7d2f72 --- /dev/null +++ b/client/src/components/bill-print-button/bill-print-button.component.jsx @@ -0,0 +1,38 @@ +import { Button, Space } from "antd"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { GenerateDocument } from "../../utils/RenderTemplate"; +import { TemplateList } from "../../utils/TemplateConstants"; + +export default function BillPrintButton({ billid }) { + const { t } = useTranslation(); + const [loading, setLoading] = useState(false); + const Templates = TemplateList("job_special"); + + const submitHandler = async () => { + setLoading(true); + try { + await GenerateDocument( + { + name: Templates.parts_invoice_label_single.key, + variables: { + id: billid, + }, + }, + {}, + "p" + ); + } catch (e) { + console.warn("Warning: Error generating a document."); + } + setLoading(false); + }; + + return ( + + + + ); +} diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index b96b555db..48ea29334 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -214,6 +214,7 @@ "new": "New Bill", "noneselected": "No bill selected.", "onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.", + "printlabels": "Print Labels", "retailtotal": "Bills Retail Total", "savewithdiscrepancy": "You are about to save this bill with a discrepancy. The system will continue to use the calculated amount using the bill lines. Press cancel to return to the bill.", "state_tax": "Provincial/State Tax", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index f68cf4a41..5e99b800a 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -214,6 +214,7 @@ "new": "", "noneselected": "", "onlycmforinvoiced": "", + "printlabels": "", "retailtotal": "", "savewithdiscrepancy": "", "state_tax": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index d0e44b704..0c7089e6c 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -214,6 +214,7 @@ "new": "", "noneselected": "", "onlycmforinvoiced": "", + "printlabels": "", "retailtotal": "", "savewithdiscrepancy": "", "state_tax": "", From 2daee84fbf196e5888b87cd0eb443c614e81800d Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 27 Dec 2023 11:07:17 -0800 Subject: [PATCH 11/24] IO-2512 Date Esimated on Manual Created Jobs --- client/src/pages/jobs-create/jobs-create.container.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/src/pages/jobs-create/jobs-create.container.jsx b/client/src/pages/jobs-create/jobs-create.container.jsx index 15af524ed..dfe83358c 100644 --- a/client/src/pages/jobs-create/jobs-create.container.jsx +++ b/client/src/pages/jobs-create/jobs-create.container.jsx @@ -1,6 +1,6 @@ -import _ from "lodash"; import { useLazyQuery, useMutation } from "@apollo/client"; import { Form, notification } from "antd"; +import _ from "lodash"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -90,6 +90,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { {}, values, { date_open: new Date() }, + { date_estimated: new Date() }, { vehicle: state.vehicle.selectedid || state.vehicle.none From 87a01208fbce2d53e1f041fee8c3616111ade9dc Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 27 Dec 2023 13:35:29 -0800 Subject: [PATCH 12/24] IO-2500 Readiness and Fuel Level --- .../contract-cars/contract-cars.component.jsx | 9 ++ .../courtesy-car-form.component.jsx | 7 ++ ...ourtesy-car-readiness-select.component.jsx | 35 ++++++ .../courtesy-cars-list.component.jsx | 50 +++++++++ client/src/graphql/courtesy-car.queries.js | 33 +++--- .../courtesy-car-detail.page.container.jsx | 17 +-- client/src/translations/en_us/common.json | 5 + client/src/translations/es/common.json | 5 + client/src/translations/fr/common.json | 5 + hasura/metadata/tables.yaml | 105 +++++++++--------- .../down.sql | 4 + .../up.sql | 2 + 12 files changed, 203 insertions(+), 74 deletions(-) create mode 100644 client/src/components/courtesy-car-readiness-select/courtesy-car-readiness-select.component.jsx create mode 100644 hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/down.sql create mode 100644 hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/up.sql diff --git a/client/src/components/contract-cars/contract-cars.component.jsx b/client/src/components/contract-cars/contract-cars.component.jsx index 541d6d7c3..6162ae7af 100644 --- a/client/src/components/contract-cars/contract-cars.component.jsx +++ b/client/src/components/contract-cars/contract-cars.component.jsx @@ -35,6 +35,15 @@ export default function ContractsCarsComponent({ state.sortedInfo.columnKey === "status" && state.sortedInfo.order, render: (text, record) =>
{t(record.status)}
, }, + { + title: t("courtesycars.fields.readiness"), + dataIndex: "readiness", + key: "readiness", + sorter: (a, b) => alphaSort(a.readiness, b.readiness), + sortOrder: + state.sortedInfo.columnKey === "readiness" && state.sortedInfo.order, + render: (text, record) => t(record.readiness), + }, { title: t("courtesycars.fields.year"), dataIndex: "year", diff --git a/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx b/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx index d5315ed3a..a64cb8a2a 100644 --- a/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx +++ b/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx @@ -7,6 +7,7 @@ import { useTranslation } from "react-i18next"; import { CHECK_CC_FLEET_NUMBER } from "../../graphql/courtesy-car.queries"; import { DateFormatter } from "../../utils/DateFormatter"; import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component"; +import CourtesyCarReadiness from "../courtesy-car-readiness-select/courtesy-car-readiness-select.component"; import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component"; import FormDatePicker from "../form-date-picker/form-date-picker.component"; //import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; @@ -213,6 +214,12 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) { > + + +
{ + const [option, setOption] = useState(value); + const { t } = useTranslation(); + + useEffect(() => { + if (value !== option && onChange) { + onChange(option); + } + }, [value, option, onChange]); + + return ( + + ); +}; +export default forwardRef(CourtesyCarReadinessComponent); diff --git a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx index ab85f95bc..7c4b25534 100644 --- a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx +++ b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx @@ -91,6 +91,26 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) { ); }, }, + { + title: t("courtesycars.fields.readiness"), + dataIndex: "readiness", + key: "readiness", + sorter: (a, b) => alphaSort(a.readiness, b.readiness), + filters: [ + { + text: t("courtesycars.readiness.ready"), + value: "courtesycars.readiness.ready", + }, + { + text: t("courtesycars.readiness.notready"), + value: "courtesycars.readiness.notready", + }, + ], + onFilter: (value, record) => value.includes(record.readiness), + sortOrder: + state.sortedInfo.columnKey === "readiness" && state.sortedInfo.order, + render: (text, record) => t(record.readiness), + }, { title: t("courtesycars.fields.year"), dataIndex: "year", @@ -131,6 +151,36 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) { sortOrder: state.sortedInfo.columnKey === "plate" && state.sortedInfo.order, }, + { + title: t("courtesycars.fields.fuel"), + dataIndex: "fuel", + key: "fuel", + sorter: (a, b) => alphaSort(a.fuel, b.fuel), + sortOrder: + state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order, + render: (text, record) => { + switch (record.fuel) { + case 100: + return t("courtesycars.labels.fuel.full"); + case 88: + return t("courtesycars.labels.fuel.78"); + case 63: + return t("courtesycars.labels.fuel.58"); + case 50: + return t("courtesycars.labels.fuel.12"); + case 38: + return t("courtesycars.labels.fuel.34"); + case 25: + return t("courtesycars.labels.fuel.14"); + case 13: + return t("courtesycars.labels.fuel.18"); + case 0: + return t("courtesycars.labels.fuel.empty"); + default: + return record.fuel; + } + }, + }, { title: t("courtesycars.labels.outwith"), dataIndex: "outwith", diff --git a/client/src/graphql/courtesy-car.queries.js b/client/src/graphql/courtesy-car.queries.js index a5bcbea55..4f7bcd0ca 100644 --- a/client/src/graphql/courtesy-car.queries.js +++ b/client/src/graphql/courtesy-car.queries.js @@ -30,15 +30,15 @@ export const QUERY_AVAILABLE_CC = gql` fuel id make - model - plate - status - year - dailycost mileage + model notes nextservicekm nextservicedate + plate + readiness + status + year } } `; @@ -68,19 +68,20 @@ export const QUERY_ALL_CC = gql` insuranceexpires leaseenddate make + mileage model nextservicedate nextservicekm notes plate purchasedate + readiness registrationexpires serviceenddate servicestartdate status vin year - mileage cccontracts( where: { status: { _eq: "contracts.status.out" } } order_by: { contract_date: desc } @@ -90,10 +91,10 @@ export const QUERY_ALL_CC = gql` scheduledreturn job { id - ro_number ownr_fn ownr_ln ownr_co_nm + ro_number } } } @@ -119,19 +120,20 @@ export const QUERY_CC_BY_PK = gql` insuranceexpires leaseenddate make + mileage model nextservicedate nextservicekm notes plate purchasedate + readiness registrationexpires serviceenddate servicestartdate status vin year - mileage cccontracts_aggregate { aggregate { count(distinct: true) @@ -139,21 +141,20 @@ export const QUERY_CC_BY_PK = gql` } cccontracts(offset: $offset, limit: $limit, order_by: $order) { agreementnumber + driver_fn + driver_ln id - status - start - scheduledreturn kmstart kmend - driver_ln - driver_fn + scheduledreturn + start + status job { - ro_number - + id ownr_ln ownr_fn ownr_co_nm - id + ro_number } } } diff --git a/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx b/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx index 93bffe97f..bf73b4cc3 100644 --- a/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx +++ b/client/src/pages/courtesy-car-detail/courtesy-car-detail.page.container.jsx @@ -1,11 +1,14 @@ import { useMutation, useQuery } from "@apollo/client"; import { Form, notification } from "antd"; import moment from "moment"; +import queryString from "query-string"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; -import { useParams } from "react-router-dom"; +import { useLocation, useParams } from "react-router-dom"; import AlertComponent from "../../components/alert/alert.component"; +import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; +import NotFound from "../../components/not-found/not-found.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import { QUERY_CC_BY_PK, UPDATE_CC } from "../../graphql/courtesy-car.queries"; import { @@ -13,13 +16,10 @@ import { setBreadcrumbs, setSelectedHeader, } from "../../redux/application/application.actions"; +import { pageLimit } from "../../utils/config"; import { CreateRecentItem } from "../../utils/create-recent-item"; +import UndefinedToNull from "./../../utils/undefinedtonull"; import CourtesyCarDetailPageComponent from "./courtesy-car-detail.page.component"; -import NotFound from "../../components/not-found/not-found.component"; -import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; -import queryString from "query-string"; -import { useLocation } from "react-router-dom"; -import {pageLimit} from "../../utils/config"; const mapDispatchToProps = (dispatch) => ({ setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), @@ -112,7 +112,10 @@ export function CourtesyCarDetailPageContainer({ setSaveLoading(true); const result = await updateCourtesyCar({ - variables: { cc: { ...values }, ccId: ccId }, + variables: { + cc: { ...UndefinedToNull(values, ["readiness"]) }, + ccId: ccId, + }, refetchQueries: ["QUERY_CC_BY_PK"], awaitRefetchQueries: true, }); diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index b96b555db..8410ea08b 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -785,6 +785,7 @@ "notes": "Notes", "plate": "Plate Number", "purchasedate": "Purchase Date", + "readiness": "Readiness", "registrationexpires": "Registration Expires On", "serviceenddate": "Usage End Date", "servicestartdate": "Usage Start Date", @@ -821,6 +822,10 @@ }, "successes": { "saved": "Courtesy Car saved successfully." + }, + "readiness": { + "notready": "Not Ready", + "ready": "Ready" } }, "csi": { diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index f68cf4a41..c759e1ffa 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -785,6 +785,7 @@ "notes": "", "plate": "", "purchasedate": "", + "readiness": "", "registrationexpires": "", "serviceenddate": "", "servicestartdate": "", @@ -821,6 +822,10 @@ }, "successes": { "saved": "" + }, + "readiness": { + "notready": "", + "ready": "" } }, "csi": { diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index d0e44b704..90941e460 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -785,6 +785,7 @@ "notes": "", "plate": "", "purchasedate": "", + "readiness": "", "registrationexpires": "", "serviceenddate": "", "servicestartdate": "", @@ -821,6 +822,10 @@ }, "successes": { "saved": "" + }, + "readiness": { + "notready": "", + "ready": "" } }, "csi": { diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index d94a97af0..216ac8c48 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -1388,60 +1388,62 @@ - active: _eq: true columns: - - id - - created_at - - updated_at - bodyshopid - - make - - model - - year - - plate - color - - vin - - fleetnumber - - purchasedate - - servicestartdate - - serviceenddate - - leaseenddate - - status - - nextservicekm - - nextservicedate - - damage - - notes - - fuel - - registrationexpires - - insuranceexpires + - created_at - dailycost + - damage + - fleetnumber + - fuel + - id + - insuranceexpires + - leaseenddate + - make - mileage + - model + - nextservicedate + - nextservicekm + - notes + - plate + - purchasedate + - readiness + - registrationexpires + - serviceenddate + - servicestartdate + - status + - updated_at + - vin + - year select_permissions: - role: user permission: columns: + - bodyshopid + - color + - created_at + - dailycost + - damage + - fleetnumber + - fuel + - id - insuranceexpires - leaseenddate + - make + - mileage + - model - nextservicedate + - nextservicekm + - notes + - plate - purchasedate + - readiness - registrationexpires - serviceenddate - servicestartdate - - dailycost - - fuel - - mileage - - nextservicekm - - color - - damage - - fleetnumber - - make - - model - - notes - - plate - status + - updated_at - vin - year - - created_at - - updated_at - - bodyshopid - - id filter: bodyshop: associations: @@ -1456,31 +1458,32 @@ - role: user permission: columns: + - bodyshopid + - color + - created_at + - dailycost + - damage + - fleetnumber + - fuel + - id - insuranceexpires - leaseenddate + - make + - mileage + - model - nextservicedate + - nextservicekm + - notes + - plate - purchasedate + - readiness - registrationexpires - serviceenddate - servicestartdate - - dailycost - - fuel - - mileage - - nextservicekm - - color - - damage - - fleetnumber - - make - - model - - notes - - plate - status + - updated_at - vin - year - - created_at - - updated_at - - bodyshopid - - id filter: bodyshop: associations: diff --git a/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/down.sql b/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/down.sql new file mode 100644 index 000000000..5e741dcc7 --- /dev/null +++ b/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."courtesycars" add column "readiness" text +-- null; diff --git a/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/up.sql b/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/up.sql new file mode 100644 index 000000000..4f5339ede --- /dev/null +++ b/hasura/migrations/1703706449547_alter_table_public_courtesycars_add_column_readiness/up.sql @@ -0,0 +1,2 @@ +alter table "public"."courtesycars" add column "readiness" text + null; From bdb2951330277cc2babc3ba6a79d69858f52395e Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 27 Dec 2023 13:55:31 -0800 Subject: [PATCH 13/24] IO-2500 Courtesy Car Readiness --- .../courtesy-car-fuel-select.component.jsx | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/client/src/components/courtesy-car-fuel-select/courtesy-car-fuel-select.component.jsx b/client/src/components/courtesy-car-fuel-select/courtesy-car-fuel-select.component.jsx index 2f9226b83..6b561d12a 100644 --- a/client/src/components/courtesy-car-fuel-select/courtesy-car-fuel-select.component.jsx +++ b/client/src/components/courtesy-car-fuel-select/courtesy-car-fuel-select.component.jsx @@ -34,6 +34,32 @@ const CourtesyCarFuelComponent = (props, ref) => { step={null} style={{ marginLeft: "2rem", marginRight: "2rem" }} {...props} + tooltip={{ + formatter: (value) => { + switch (value) { + case 0: + return t("courtesycars.labels.fuel.empty"); + case 13: + return t("courtesycars.labels.fuel.18"); + case 25: + return t("courtesycars.labels.fuel.14"); + case 38: + return t("courtesycars.labels.fuel.38"); + case 50: + return t("courtesycars.labels.fuel.12"); + case 63: + return t("courtesycars.labels.fuel.58"); + case 75: + return t("courtesycars.labels.fuel.34"); + case 88: + return t("courtesycars.labels.fuel.78"); + case 100: + return t("courtesycars.labels.fuel.full"); + default: + return value; + } + }, + }} /> ); }; From b0d077e104a4c23587ce7ed4528b7493927125b9 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 28 Dec 2023 10:12:59 -0800 Subject: [PATCH 14/24] IO-2514 Production Board Estimators --- .../production-list-columns.data.js | 29 ++++++++++++++++++- client/src/graphql/jobs.queries.js | 2 ++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/client/src/components/production-list-columns/production-list-columns.data.js b/client/src/components/production-list-columns/production-list-columns.data.js index a93e0f3e6..a7f1ead6e 100644 --- a/client/src/components/production-list-columns/production-list-columns.data.js +++ b/client/src/components/production-list-columns/production-list-columns.data.js @@ -1,4 +1,4 @@ -import { PauseCircleOutlined, BranchesOutlined } from "@ant-design/icons"; +import { BranchesOutlined, PauseCircleOutlined } from "@ant-design/icons"; import { Space, Tooltip } from "antd"; import i18n from "i18next"; import moment from "moment"; @@ -536,6 +536,33 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => { ), }, + { + title: i18n.t("jobs.labels.estimator"), + dataIndex: "estimator", + key: "estimator", + sorter: (a, b) => + alphaSort( + `${a.est_ct_fn || ""} ${a.est_ct_ln || ""}`.trim(), + `${b.est_ct_fn || ""} ${b.est_ct_ln || ""}`.trim() + ), + sortOrder: + state.sortedInfo.columnKey === "estimator" && state.sortedInfo.order, + filters: + (bodyshop && + bodyshop.md_estimators.map((s) => { + return { + text: `${s.est_ct_fn || ""} ${s.est_ct_ln || ""}`.trim(), + value: [`${s.est_ct_fn || ""} ${s.est_ct_ln || ""}`.trim()], + }; + })) || + [], + onFilter: (value, record) => + value.includes( + `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim() + ), + render: (text, record) => + `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(), + }, //Added as a place holder for St Claude. Not implemented as it requires another join for a field used by only 1 client. // { diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index b18673de6..fbeb8740d 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -364,6 +364,8 @@ export const QUERY_JOBS_IN_PRODUCTION = gql` employee_refinish employee_prep employee_csr + est_ct_fn + est_ct_ln suspended date_repairstarted joblines_status { From e236d6e9123117f045b009e72276eff622c84633 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 28 Dec 2023 10:57:03 -0800 Subject: [PATCH 15/24] IO-2489 Registration # in Vehicle Info Box --- .../jobs-detail-header/jobs-detail-header.component.jsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx index a5dd99f6f..30bb98560 100644 --- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx +++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx @@ -1,8 +1,8 @@ import { + BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, WarningFilled, - BranchesOutlined, } from "@ant-design/icons"; import { Card, Col, Row, Space, Tag, Tooltip } from "antd"; import React, { useState } from "react"; @@ -222,6 +222,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) { {`${job.v_vin || t("general.labels.na")}`} + + {job.regie_number || t("general.labels.na")} + From 823f07409aca7584a804c3118cf3e695209b58df Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 29 Dec 2023 16:03:40 -0800 Subject: [PATCH 16/24] IO-2517 All Courtesy Car Warning Indicator --- .../courtesy-cars-list/courtesy-cars-list.component.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx index 7c4b25534..3be08fff2 100644 --- a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx +++ b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx @@ -74,10 +74,10 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) { render: (text, record) => { const { nextservicedate, nextservicekm, mileage } = record; - const mileageOver = nextservicekm <= mileage; + const mileageOver = nextservicekm ? nextservicekm <= mileage : false; const dueForService = - nextservicedate && moment(nextservicedate).isBefore(moment()); + nextservicedate && moment(nextservicedate).isSameOrBefore(moment()); return ( From bfe94e3068c06d9b256269439ae275f2c6cb3f90 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 29 Dec 2023 16:17:37 -0800 Subject: [PATCH 17/24] IO-2517 Add same check within C/C form --- .../courtesy-car-form/courtesy-car-form.component.jsx | 10 ++++------ .../courtesy-cars-list.component.jsx | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx b/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx index a64cb8a2a..f9a32dfee 100644 --- a/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx +++ b/client/src/components/courtesy-car-form/courtesy-car-form.component.jsx @@ -214,10 +214,7 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) { > - +
@@ -234,8 +231,9 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) { > {() => { const nextservicekm = form.getFieldValue("nextservicekm"); - const mileageOver = - nextservicekm && nextservicekm <= form.getFieldValue("mileage"); + const mileageOver = nextservicekm + ? nextservicekm <= form.getFieldValue("mileage") + : false; if (mileageOver) return ( diff --git a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx index 3be08fff2..2c992990c 100644 --- a/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx +++ b/client/src/components/courtesy-cars-list/courtesy-cars-list.component.jsx @@ -77,7 +77,8 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) { const mileageOver = nextservicekm ? nextservicekm <= mileage : false; const dueForService = - nextservicedate && moment(nextservicedate).isSameOrBefore(moment()); + nextservicedate && + moment(nextservicedate).endOf("day").isSameOrBefore(moment()); return ( From ded798fdf1fc8d01b99f18958cf4a6fbc5649fbd Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 29 Dec 2023 16:37:34 -0800 Subject: [PATCH 18/24] IO-2518 Dealership Vin Warning --- .../jobs-detail-header/jobs-detail-header.component.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx index 30bb98560..9ae08588d 100644 --- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx +++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx @@ -221,6 +221,11 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) { {`${job.v_vin || t("general.labels.na")}`} + {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? ( + job.v_vin.length !== 17 ? ( + + ) : null + ) : null} {job.regie_number || t("general.labels.na")} From 9d3aca646b2effb73d3269b1b2f46c97af4e246f Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Wed, 3 Jan 2024 10:55:45 -0800 Subject: [PATCH 19/24] IO-2514 Production Board Estimator filter by table data --- .../production-list-columns.add.component.jsx | 7 ++-- .../production-list-columns.data.js | 16 ++++----- ...ction-list-table-view-select.component.jsx | 3 ++ .../production-list-table.component.jsx | 35 +++++++++++++++++-- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/client/src/components/production-list-columns/production-list-columns.add.component.jsx b/client/src/components/production-list-columns/production-list-columns.add.component.jsx index 82f884673..c79e9db7f 100644 --- a/client/src/components/production-list-columns/production-list-columns.add.component.jsx +++ b/client/src/components/production-list-columns/production-list-columns.add.component.jsx @@ -1,7 +1,7 @@ -import React from "react"; import { Button, Dropdown, Menu } from "antd"; -import dataSource from "./production-list-columns.data"; +import React from "react"; import { useTranslation } from "react-i18next"; +import dataSource from "./production-list-columns.data"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -24,6 +24,7 @@ export function ProductionColumnsComponent({ columnState, technician, bodyshop, + data, tableState, }) { const [columns, setColumns] = columnState; @@ -36,6 +37,7 @@ export function ProductionColumnsComponent({ bodyshop, technician, state: tableState, + data: data, activeStatuses: bodyshop.md_ro_statuses.active_statuses, }).filter((i) => i.key === e.key), ]); @@ -46,6 +48,7 @@ export function ProductionColumnsComponent({ technician, state: tableState, activeStatuses: bodyshop.md_ro_statuses.active_statuses, + data: data, }); const menu = ( { +const r = ({ technician, state, activeStatuses, data, bodyshop }) => { return [ { title: i18n.t("jobs.actions.viewdetail"), @@ -548,14 +548,12 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => { sortOrder: state.sortedInfo.columnKey === "estimator" && state.sortedInfo.order, filters: - (bodyshop && - bodyshop.md_estimators.map((s) => { - return { - text: `${s.est_ct_fn || ""} ${s.est_ct_ln || ""}`.trim(), - value: [`${s.est_ct_fn || ""} ${s.est_ct_ln || ""}`.trim()], - }; - })) || - [], + data?.map((s) => { + return { + text: `${s.est_ct_fn || ""} ${s.est_ct_ln || ""}`.trim(), + value: [`${s.est_ct_fn || ""} ${s.est_ct_ln || ""}`.trim()], + }; + }) || [], onFilter: (value, record) => value.includes( `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim() diff --git a/client/src/components/production-list-table/production-list-table-view-select.component.jsx b/client/src/components/production-list-table/production-list-table-view-select.component.jsx index 044c75994..82086ac96 100644 --- a/client/src/components/production-list-table/production-list-table-view-select.component.jsx +++ b/client/src/components/production-list-table/production-list-table-view-select.component.jsx @@ -24,6 +24,7 @@ export function ProductionListTable({ technician, currentUser, state, + data, setColumns, setState, }) { @@ -41,6 +42,7 @@ export function ProductionListTable({ bodyshop, technician, state, + data: data, activeStatuses: bodyshop.md_ro_statuses.active_statuses, }).find((e) => e.key === k.key), width: k.width, @@ -95,6 +97,7 @@ export function ProductionListTable({ ...ProductionListColumns({ technician, state, + data: data, activeStatuses: bodyshop.md_ro_statuses.active_statuses, }).find((e) => e.key === k.key), width: k.width, diff --git a/client/src/components/production-list-table/production-list-table.component.jsx b/client/src/components/production-list-table/production-list-table.component.jsx index 3ea3391d3..5257cea9d 100644 --- a/client/src/components/production-list-table/production-list-table.component.jsx +++ b/client/src/components/production-list-table/production-list-table.component.jsx @@ -10,7 +10,7 @@ import { Statistic, Table, } from "antd"; -import React, { useMemo, useState } from "react"; +import React, { useEffect, useMemo, useState } from "react"; import ReactDragListView from "react-drag-listview"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -79,6 +79,7 @@ export function ProductionListTable({ bodyshop, technician, state, + data: data, activeStatuses: bodyshop.md_ro_statuses.active_statuses, }).find((e) => e.key === k.key), width: k.width ?? 100, @@ -87,6 +88,33 @@ export function ProductionListTable({ [] ); + useEffect(() => { + const newColumns = + (state && + matchingColumnConfig && + matchingColumnConfig.columns.columnKeys.map((k) => { + return { + ...ProductionListColumns({ + bodyshop, + technician, + state, + data: data, + activeStatuses: bodyshop.md_ro_statuses.active_statuses, + }).find((e) => e.key === k.key), + width: k.width ?? 100, + }; + })) || + []; + setColumns(newColumns); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ + //state, + matchingColumnConfig, + bodyshop, + technician, + data, + ]); //State removed from dependency array as it causes race condition when removing columns from table view and is not needed. + const handleTableChange = (pagination, filters, sorter) => { setState({ ...state, @@ -104,7 +132,8 @@ export function ProductionListTable({ const removeColumn = (e) => { const { key } = e; - setColumns(columns.filter((i) => i.key !== key)); + const newColumns = columns.filter((i) => i.key !== key); + setColumns(newColumns); }; const handleResize = @@ -227,6 +256,7 @@ export function ProductionListTable({ Date: Fri, 5 Jan 2024 08:53:17 -0800 Subject: [PATCH 20/24] Minor intellipay change. --- server/intellipay/intellipay.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/intellipay/intellipay.js b/server/intellipay/intellipay.js index 0ece0c69c..60b74c1b5 100644 --- a/server/intellipay/intellipay.js +++ b/server/intellipay/intellipay.js @@ -132,6 +132,7 @@ exports.payment_refund = async (req, res) => { exports.generate_payment_url = async (req, res) => { logger.log("intellipay-payment-url", "DEBUG", req.user?.email, null, null); const shopCredentials = await getShopCredentials(req.body.bodyshop); + try { const options = { method: "POST", @@ -139,7 +140,12 @@ exports.generate_payment_url = async (req, res) => { //TODO: Move these to environment variables/database. data: qs.stringify({ ...shopCredentials, - ...req.body, + //...req.body, + amount: Dinero({ amount: Math.round(req.body.amount * 100) }).toFormat( + "0.00" + ), + account: req.body.account, + invoice: req.body.invoice, createshorturl: true, //The postback URL is set at the CP teller global terminal settings page. }), From 28dc4867dbe41329ebc2428dd1c063f10fe61916 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 5 Jan 2024 09:02:52 -0800 Subject: [PATCH 21/24] Remove unnecessary debug button. --- .../components/bill-enter-modal/bill-enter-modal.container.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/src/components/bill-enter-modal/bill-enter-modal.container.jsx b/client/src/components/bill-enter-modal/bill-enter-modal.container.jsx index 3fc5c966a..90a14a5d1 100644 --- a/client/src/components/bill-enter-modal/bill-enter-modal.container.jsx +++ b/client/src/components/bill-enter-modal/bill-enter-modal.container.jsx @@ -455,9 +455,6 @@ function BillEnterModalContainer({ setEnterAgain(false); }} > - Date: Fri, 5 Jan 2024 10:56:30 -0800 Subject: [PATCH 22/24] IO-2522 Load Level Report App Side --- .../shop-employee-teams.form.component.jsx | 16 ++++++++-- client/src/graphql/employee_teams.queries.js | 29 +++++++++++-------- client/src/translations/en_us/common.json | 2 ++ client/src/translations/es/common.json | 2 ++ client/src/translations/fr/common.json | 2 ++ client/src/utils/TemplateConstants.js | 13 +++++++++ 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/client/src/components/shop-teams/shop-employee-teams.form.component.jsx b/client/src/components/shop-teams/shop-employee-teams.form.component.jsx index d811eb794..928b4286b 100644 --- a/client/src/components/shop-teams/shop-employee-teams.form.component.jsx +++ b/client/src/components/shop-teams/shop-employee-teams.form.component.jsx @@ -2,11 +2,11 @@ import { DeleteFilled } from "@ant-design/icons"; import { useMutation, useQuery } from "@apollo/client"; import { Button, - Space, Card, Form, Input, InputNumber, + Space, Switch, notification, } from "antd"; @@ -157,6 +157,18 @@ export function ShopEmployeeTeamsFormComponent({ bodyshop }) { > + + + {(fields, { add, remove, move }) => { @@ -199,7 +211,7 @@ export function ShopEmployeeTeamsFormComponent({ bodyshop }) { }, ]} > - + { }, group: "customers", }, + load_level: { + title: i18n.t("reportcenter.templates.load_level"), + subject: i18n.t("reportcenter.templates.load_level"), + key: "load_level", + //idtype: "vendor", + disabled: false, + rangeFilter: { + object: i18n.t("reportcenter.labels.objects.jobs"), + field: i18n.t("jobs.fields.date_open"), + }, + group: "jobs", + enhanced_payroll: true, + }, } : {}), ...(!type || type === "courtesycarcontract" From c0dab92d0ef6d0f2f7b51129d556edd2aae9d2c1 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 5 Jan 2024 12:01:47 -0800 Subject: [PATCH 23/24] IO-2522 Load Level Table Change --- hasura/metadata/tables.yaml | 33 ++++++++++--------- .../down.sql | 4 +++ .../up.sql | 2 ++ .../down.sql | 3 ++ .../up.sql | 1 + .../down.sql | 4 +++ .../up.sql | 2 ++ 7 files changed, 34 insertions(+), 15 deletions(-) create mode 100644 hasura/migrations/1704401074280_alter_table_public_employee_team_members_add_column_max_load/down.sql create mode 100644 hasura/migrations/1704401074280_alter_table_public_employee_team_members_add_column_max_load/up.sql create mode 100644 hasura/migrations/1704403786392_alter_table_public_employee_team_members_drop_column_max_load/down.sql create mode 100644 hasura/migrations/1704403786392_alter_table_public_employee_team_members_drop_column_max_load/up.sql create mode 100644 hasura/migrations/1704403846373_alter_table_public_employee_teams_add_column_max_load/down.sql create mode 100644 hasura/migrations/1704403846373_alter_table_public_employee_teams_add_column_max_load/up.sql diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 216ac8c48..9867b3f8e 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -2023,24 +2023,24 @@ - active: _eq: true columns: - - labor_rates - - percentage - created_at - - updated_at - employeeid - id + - labor_rates + - percentage - teamid + - updated_at select_permissions: - role: user permission: columns: - - labor_rates - - percentage - created_at - - updated_at - employeeid - id + - labor_rates + - percentage - teamid + - updated_at filter: employee_team: bodyshop: @@ -2055,13 +2055,13 @@ - role: user permission: columns: - - labor_rates - - percentage - created_at - - updated_at - employeeid - id + - labor_rates + - percentage - teamid + - updated_at filter: employee_team: bodyshop: @@ -2123,21 +2123,23 @@ _eq: true columns: - active - - name - - created_at - - updated_at - bodyshopid + - created_at - id + - max_load + - name + - updated_at select_permissions: - role: user permission: columns: - active - - name - - created_at - - updated_at - bodyshopid + - created_at - id + - max_load + - name + - updated_at filter: bodyshop: associations: @@ -2153,6 +2155,7 @@ columns: - active - bodyshopid + - max_load - name - updated_at filter: diff --git a/hasura/migrations/1704401074280_alter_table_public_employee_team_members_add_column_max_load/down.sql b/hasura/migrations/1704401074280_alter_table_public_employee_team_members_add_column_max_load/down.sql new file mode 100644 index 000000000..8df675f00 --- /dev/null +++ b/hasura/migrations/1704401074280_alter_table_public_employee_team_members_add_column_max_load/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."employee_team_members" add column "max_load" numeric +-- not null default '10000'; diff --git a/hasura/migrations/1704401074280_alter_table_public_employee_team_members_add_column_max_load/up.sql b/hasura/migrations/1704401074280_alter_table_public_employee_team_members_add_column_max_load/up.sql new file mode 100644 index 000000000..7b49a8dcd --- /dev/null +++ b/hasura/migrations/1704401074280_alter_table_public_employee_team_members_add_column_max_load/up.sql @@ -0,0 +1,2 @@ +alter table "public"."employee_team_members" add column "max_load" numeric + not null default '10000'; diff --git a/hasura/migrations/1704403786392_alter_table_public_employee_team_members_drop_column_max_load/down.sql b/hasura/migrations/1704403786392_alter_table_public_employee_team_members_drop_column_max_load/down.sql new file mode 100644 index 000000000..a869e6890 --- /dev/null +++ b/hasura/migrations/1704403786392_alter_table_public_employee_team_members_drop_column_max_load/down.sql @@ -0,0 +1,3 @@ +alter table "public"."employee_team_members" alter column "max_load" set default '10000'::numeric; +alter table "public"."employee_team_members" alter column "max_load" drop not null; +alter table "public"."employee_team_members" add column "max_load" numeric; diff --git a/hasura/migrations/1704403786392_alter_table_public_employee_team_members_drop_column_max_load/up.sql b/hasura/migrations/1704403786392_alter_table_public_employee_team_members_drop_column_max_load/up.sql new file mode 100644 index 000000000..18bf59cf3 --- /dev/null +++ b/hasura/migrations/1704403786392_alter_table_public_employee_team_members_drop_column_max_load/up.sql @@ -0,0 +1 @@ +alter table "public"."employee_team_members" drop column "max_load" cascade; diff --git a/hasura/migrations/1704403846373_alter_table_public_employee_teams_add_column_max_load/down.sql b/hasura/migrations/1704403846373_alter_table_public_employee_teams_add_column_max_load/down.sql new file mode 100644 index 000000000..58a0f9b6d --- /dev/null +++ b/hasura/migrations/1704403846373_alter_table_public_employee_teams_add_column_max_load/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."employee_teams" add column "max_load" numeric +-- not null default '10000'; diff --git a/hasura/migrations/1704403846373_alter_table_public_employee_teams_add_column_max_load/up.sql b/hasura/migrations/1704403846373_alter_table_public_employee_teams_add_column_max_load/up.sql new file mode 100644 index 000000000..c55ba33d0 --- /dev/null +++ b/hasura/migrations/1704403846373_alter_table_public_employee_teams_add_column_max_load/up.sql @@ -0,0 +1,2 @@ +alter table "public"."employee_teams" add column "max_load" numeric + not null default '10000'; From fe3698980d5c81651288ed3aad1807366e5e7fa2 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Fri, 5 Jan 2024 13:09:15 -0800 Subject: [PATCH 24/24] IO-2514 Only Unique items in Menu --- .../production-list-columns.data.js | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/client/src/components/production-list-columns/production-list-columns.data.js b/client/src/components/production-list-columns/production-list-columns.data.js index d43433540..8e584aa2e 100644 --- a/client/src/components/production-list-columns/production-list-columns.data.js +++ b/client/src/components/production-list-columns/production-list-columns.data.js @@ -6,6 +6,7 @@ import { Link } from "react-router-dom"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import { TimeFormatter } from "../../utils/DateFormatter"; import PhoneFormatter from "../../utils/PhoneFormatter"; +import { onlyUnique } from "../../utils/arrayHelper"; import { alphaSort, dateSort, statusSort } from "../../utils/sorters"; import JobAltTransportChange from "../job-at-change/job-at-change.component"; import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component"; @@ -548,12 +549,17 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => { sortOrder: state.sortedInfo.columnKey === "estimator" && state.sortedInfo.order, filters: - data?.map((s) => { - return { - text: `${s.est_ct_fn || ""} ${s.est_ct_ln || ""}`.trim(), - value: [`${s.est_ct_fn || ""} ${s.est_ct_ln || ""}`.trim()], - }; - }) || [], + (data && + data + .map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim()) + .filter(onlyUnique) + .map((s) => { + return { + text: s || "N/A", + value: [s], + }; + })) || + [], onFilter: (value, record) => value.includes( `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()