diff --git a/_reference/reportFiltersAndSorters.md b/_reference/reportFiltersAndSorters.md index 2aea3f11a..0b5b16aaf 100644 --- a/_reference/reportFiltersAndSorters.md +++ b/_reference/reportFiltersAndSorters.md @@ -59,7 +59,7 @@ Filters can make use of reflection to pre-fill select boxes, the following is an "type": "internal", "name": "special.job_statuses" } - }, + } ``` in this example, a reflector with the type 'internal' (all types at the moment require this, and it is used for future functionality), with a name of `special.job_statuses` @@ -74,9 +74,13 @@ The following cases are available - `special.employees` - This will reflect the employees `bodyshop.employees` - `special.first_names` - This will reflect the first names `bodyshop.employees` - `special.last_names` - This will reflect the last names `bodyshop.employees` -- `special.referral_sources` - This will reflect the referral sources `bodyshop.md_referral_sources +- `special.referral_sources` - This will reflect the referral sources `bodyshop.md_referral_sources` - `special.class`- This will reflect the class `bodyshop.md_classes` -- +- `special.lost_sale_reasons` - This will reflect the lost sale reasons `bodyshop.md_lost_sale_reasons` +- `special.alt_transports` - This will reflect the alternative transports `bodyshop.appt_alt_transport` +- `special.payment_types` - This will reflect the payment types `bodyshop.md_payment_types` +- `special.payment_payers` - This is a special case with a key value set of [Customer, Insurance] + ### Path without brackets, multi level `"name": "jobs.joblines.mod_lb_hrs",` @@ -156,6 +160,7 @@ query gendoc_hours_sold_detail_open($starttz: timestamptz!, $endtz: timestamptz! - Do not add the ability to filter things that are already filtered as part of the original query, this would be redundant and could cause issues. - Do not add the ability to filter on things like FK constraints, must like the above example. +- *INHERITANCE CAVEAT* If you have a filters file on a parent report that has a child that you do not want the filters inherited from, you must place a blank filters file (valid json so {}) on the child report level. This will than fetch the child filters, which are empty and move along, versus inheriting the parent filters. ## Sorters diff --git a/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx b/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx index 07d0e9b4a..bb3201fcc 100644 --- a/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx +++ b/client/src/components/accounting-payables-table/accounting-payables-table.component.jsx @@ -1,21 +1,20 @@ -import {Card, Checkbox, Input, Space, Table} from "antd"; +import {Card, Checkbox, Input, Space, Table} from "antd";import queryString from "query-string"; import React, {useState} from "react"; import {useTranslation} from "react-i18next"; +import {connect } from "react-redux"; import {Link} from "react-router-dom"; -import CurrencyFormatter from "../../utils/CurrencyFormatter"; -import {alphaSort, dateSort} from "../../utils/sorters"; -import PayableExportButton from "../payable-export-button/payable-export-button.component"; -import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component"; -import {DateFormatter} from "../../utils/DateFormatter"; -import queryString from "query-string"; +import { createStructuredSelector } from "reselect"; import {logImEXEvent} from "../../firebase/firebase.utils"; -import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component"; -import {connect} from "react-redux"; -import {createStructuredSelector} from "reselect"; -import {selectBodyshop} from "../../redux/user/user.selectors"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import CurrencyFormatter from "../../utils/CurrencyFormatter"; +import {DateFormatter} from "../../utils/DateFormatter"; +import { pageLimit } from "../../utils/config"; +import {alphaSort, dateSort} from "../../utils/sorters"; import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component"; +import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component"; +import PayableExportButton from "../payable-export-button/payable-export-button.component"; import BillMarkSelectedExported from "../payable-mark-selected-exported/payable-mark-selected-exported.component"; -import {pageLimit} from "../../utils/config"; +import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -147,7 +146,7 @@ export function AccountingPayablesTableComponent({ title: t("general.labels.actions"), dataIndex: "actions", key: "actions", - sorter: (a, b) => a.clm_total - b.clm_total, + render: (text, record) => ( alphaSort(a.job.ownr_ln, b.job.ownr_ln), + sorter: (a, b) => + alphaSort( + OwnerNameDisplayFunction(a.job), + OwnerNameDisplayFunction(b.job) + ), sortOrder: state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, render: (text, record) => { @@ -94,7 +100,9 @@ export function AccountingPayablesTableComponent({ title: t("payments.fields.amount"), dataIndex: "amount", key: "amount", - render: (text, record) => ( + sorter: (a, b) => a.amount - b.amount, + sortOrder: + state.sortedInfo.columnKey === "amount" && state.sortedInfo.order,render: (text, record) => ( {record.amount} ), }, @@ -111,19 +119,21 @@ export function AccountingPayablesTableComponent({ { title: t("payments.fields.created_at"), dataIndex: "created_at", - key: "created_at", + key: "created_at",sorter: (a, b) => dateSort(a.created_at, b.created_at), + sortOrder: + state.sortedInfo.columnKey === "created_at" && state.sortedInfo.order, render: (text, record) => ( {record.created_at} ), }, - { - title: t("payments.fields.exportedat"), - dataIndex: "exportedat", - key: "exportedat", - render: (text, record) => ( - {record.exportedat} - ), - }, + //{ + // title: t("payments.fields.exportedat"), + // dataIndex: "exportedat", + // key: "exportedat", + // render: (text, record) => ( + // {record.exportedat} + // ), + //}, { title: t("exportlogs.labels.attempts"), dataIndex: "attempts", @@ -137,7 +147,7 @@ export function AccountingPayablesTableComponent({ title: t("general.labels.actions"), dataIndex: "actions", key: "actions", - sorter: (a, b) => a.clm_total - b.clm_total, + render: (text, record) => ( a.status - b.status, + sorter: (a, b) => statusSort(a, b, bodyshop.md_ro_statuses.statuses), sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order, }, @@ -83,7 +85,8 @@ export function AccountingReceivablesTableComponent({ title: t("jobs.fields.owner"), dataIndex: "owner", key: "owner", - sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), + sorter: (a, b) => + alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)), sortOrder: state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, render: (text, record) => { @@ -103,7 +106,15 @@ export function AccountingReceivablesTableComponent({ dataIndex: "vehicle", key: "vehicle", ellipsis: true, - render: (text, record) => { + sorter: (a, b) => + alphaSort( + `${a.v_model_yr || ""} ${a.v_make_desc || ""} ${ + a.v_model_desc || "" + }`, + `${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}` + ), + sortOrder: + state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,render: (text, record) => { return record.vehicleid ? ( {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${ diff --git a/client/src/components/bill-delete-button/bill-delete-button.component.jsx b/client/src/components/bill-delete-button/bill-delete-button.component.jsx index af7748228..13eb94527 100644 --- a/client/src/components/bill-delete-button/bill-delete-button.component.jsx +++ b/client/src/components/bill-delete-button/bill-delete-button.component.jsx @@ -12,8 +12,8 @@ import { createStructuredSelector } from "reselect"; const mapStateToProps = createStructuredSelector({}); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({ jobid, operation }) => - dispatch(insertAuditTrail({ jobid, operation })), + insertAuditTrail: ({ jobid, operation, type }) => + dispatch(insertAuditTrail({ jobid, operation, type })), }); export default connect(mapStateToProps, mapDispatchToProps)(BillDeleteButton); @@ -51,7 +51,8 @@ export function BillDeleteButton({ bill, jobid, callback, insertAuditTrail }) { insertAuditTrail({ jobid: jobid, operation: AuditTrailMapping.billdeleted(bill.invoice_number), - }); + type: "billdeleted", + }); if (callback && typeof callback === "function") callback(bill.id); } else { 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 fd3f5ecbe..30c2b49d2 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 @@ -30,8 +30,8 @@ const mapStateToProps = createStructuredSelector({ const mapDispatchToProps = (dispatch) => ({ setPartsOrderContext: (context) => dispatch(setModalContext({context: context, modal: "partsOrder"})), - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect( @@ -145,7 +145,8 @@ export function BillDetailEditcontainer({setPartsOrderContext, insertAuditTrail, jobid: bill.jobid, billid: search.billid, operation: AuditTrailMapping.billupdated(bill.invoice_number), - }); + type: "billupdated", + }); await refetch(); form.setFieldsValue(transformData(data)); diff --git a/client/src/components/bill-detail-edit/bill-detail-edit-return.component.jsx b/client/src/components/bill-detail-edit/bill-detail-edit-return.component.jsx index 6d9961ebf..5ef1993dc 100644 --- a/client/src/components/bill-detail-edit/bill-detail-edit-return.component.jsx +++ b/client/src/components/bill-detail-edit/bill-detail-edit-return.component.jsx @@ -16,8 +16,8 @@ const mapStateToProps = createStructuredSelector({ const mapDispatchToProps = (dispatch) => ({ setPartsOrderContext: (context) => dispatch(setModalContext({context: context, modal: "partsOrder"})), - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect( 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 4838c4827..31dd371b5 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 @@ -31,8 +31,8 @@ const mapStateToProps = createStructuredSelector({ }); const mapDispatchToProps = (dispatch) => ({ toggleModalVisible: () => dispatch(toggleModalVisible("billEnter")), - insertAuditTrail: ({jobid, billid, operation}) => - dispatch(insertAuditTrail({jobid, billid, operation})), + insertAuditTrail: ({jobid, billid, operation, type}) => + dispatch(insertAuditTrail({jobid, billid, operation, type })), }); const Templates = TemplateList("job_special"); @@ -165,7 +165,7 @@ function BillEnterModalContainer({ mod_lbr_ty: key, hours: adjustmentsToInsert[key].toFixed(1), }), - }); + type: "jobmodifylbradj",}); }); const jobUpdate = client.mutate({ @@ -314,7 +314,8 @@ function BillEnterModalContainer({ operation: AuditTrailMapping.billposted( r1.data.insert_bills.returning[0].invoice_number ), - }); + type: "billposted", + }); if (enterAgain) { form.resetFields(); diff --git a/client/src/components/card-payment-modal/card-payment-modal.component..jsx b/client/src/components/card-payment-modal/card-payment-modal.component..jsx index 6927bbf2f..581fe7334 100644 --- a/client/src/components/card-payment-modal/card-payment-modal.component..jsx +++ b/client/src/components/card-payment-modal/card-payment-modal.component..jsx @@ -23,8 +23,8 @@ const mapStateToProps = createStructuredSelector({ }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type})), toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment")), }); @@ -88,7 +88,7 @@ const CardPaymentModalComponent = ({ insertAuditTrail({ jobid: payment.jobid, operation: AuditTrailMapping.failedpayment(), - }) + type: "failedpayment",}) ); }); }; diff --git a/client/src/components/dashboard-components/scheduled-in-today/scheduled-in-today.component.jsx b/client/src/components/dashboard-components/scheduled-in-today/scheduled-in-today.component.jsx index 5277ca0ec..5d24bb606 100644 --- a/client/src/components/dashboard-components/scheduled-in-today/scheduled-in-today.component.jsx +++ b/client/src/components/dashboard-components/scheduled-in-today/scheduled-in-today.component.jsx @@ -4,7 +4,7 @@ import { PauseCircleOutlined, } from "@ant-design/icons"; import { Card, Space, Switch, Table, Tooltip, Typography } from "antd"; -import moment from "moment"; +import dayjs from "../../../utils/day"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; @@ -74,7 +74,7 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) { } }); appt.sort(function (a, b) { - return new moment(a.start) - new moment(b.start); + return dayjs(a.start) - dayjs(b.start); }); const tvFontSize = 16; @@ -419,7 +419,7 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) { return ( @@ -449,9 +449,9 @@ export default function DashboardScheduledInToday({ data, ...cardProps }) { } export const DashboardScheduledInTodayGql = ` - scheduled_in_today: appointments(where: {start: {_gte: "${moment() + scheduled_in_today: appointments(where: {start: {_gte: "${dayjs() .startOf("day") - .toISOString()}", _lte: "${moment() + .toISOString()}", _lte: "${dayjs() .endOf("day") .toISOString()}"}, canceled: {_eq: false}, block: {_neq: true}}) { canceled diff --git a/client/src/components/job-at-change/schedule-event.container.jsx b/client/src/components/job-at-change/schedule-event.container.jsx index 755520627..fcc85cecc 100644 --- a/client/src/components/job-at-change/schedule-event.container.jsx +++ b/client/src/components/job-at-change/schedule-event.container.jsx @@ -53,7 +53,7 @@ export default function ScheduleEventContainer({bodyshop, event, refetch}) { insertAuditTrail({ jobid: event.job.id, operation: AuditTrailMapping.appointmentcancel(lost_sale_reason), - }) + type: "appointmentcancel",}) ); } if (!!jobUpdate.errors) { diff --git a/client/src/components/job-checklist/components/job-checklist-form/job-checklist-form.component.jsx b/client/src/components/job-checklist/components/job-checklist-form/job-checklist-form.component.jsx index f169736f9..cf45c4356 100644 --- a/client/src/components/job-checklist/components/job-checklist-form/job-checklist-form.component.jsx +++ b/client/src/components/job-checklist/components/job-checklist-form/job-checklist-form.component.jsx @@ -28,8 +28,8 @@ const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export function JobChecklistForm({ @@ -183,7 +183,7 @@ export function JobChecklistForm({ (type === "intake" && bodyshop.md_ro_statuses.default_arrived) || (type === "deliver" && bodyshop.md_ro_statuses.default_delivered) ), - }); + type: "jobchecklist",}); } else { notification["error"]({ message: t("checklist.errors.complete", { diff --git a/client/src/components/job-employee-assignments/job-employee-assignments.container.jsx b/client/src/components/job-employee-assignments/job-employee-assignments.container.jsx index f81e60819..b36345ed3 100644 --- a/client/src/components/job-employee-assignments/job-employee-assignments.container.jsx +++ b/client/src/components/job-employee-assignments/job-employee-assignments.container.jsx @@ -15,8 +15,8 @@ const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect( mapStateToProps, @@ -47,7 +47,8 @@ export function JobEmployeeAssignmentsContainer({ insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.jobassignmentchange(operation, name), - }); + type: "jobassignmentchange", + }); if (!!result.errors) { notification["error"]({ @@ -77,7 +78,7 @@ export function JobEmployeeAssignmentsContainer({ insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.jobassignmentremoved(operation), - }); + type: "jobassignmentremoved",}); setLoading(false); }; diff --git a/client/src/components/job-line-convert-to-labor/job-line-convert-to-labor.component.jsx b/client/src/components/job-line-convert-to-labor/job-line-convert-to-labor.component.jsx index d1062ce92..b27f250bd 100644 --- a/client/src/components/job-line-convert-to-labor/job-line-convert-to-labor.component.jsx +++ b/client/src/components/job-line-convert-to-labor/job-line-convert-to-labor.component.jsx @@ -17,8 +17,8 @@ const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect( mapStateToProps, @@ -102,7 +102,7 @@ export function JobLineConvertToLabor({ hours: calculateAdjustment({mod_lbr_ty, job, jobline}).toFixed(1), mod_lbr_ty, }), - }); + type: "jobmodifylbradj",}); setLoading(false); setVisibility(false); }; diff --git a/client/src/components/jobs-admin-change-status/jobs-admin-change.status.component.jsx b/client/src/components/jobs-admin-change-status/jobs-admin-change.status.component.jsx index 9b8625eb2..325f58e4e 100644 --- a/client/src/components/jobs-admin-change-status/jobs-admin-change.status.component.jsx +++ b/client/src/components/jobs-admin-change-status/jobs-admin-change.status.component.jsx @@ -14,8 +14,8 @@ const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminStatus); @@ -32,7 +32,7 @@ export function JobsAdminStatus({insertAuditTrail, bodyshop, job}) { insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.admin_jobstatuschange(status), - }); + type: "admin_jobstatuschange",}); // refetch(); }) .catch((error) => { diff --git a/client/src/components/jobs-admin-dates/jobs-admin-dates.component.jsx b/client/src/components/jobs-admin-dates/jobs-admin-dates.component.jsx index 200a24975..23375fac8 100644 --- a/client/src/components/jobs-admin-dates/jobs-admin-dates.component.jsx +++ b/client/src/components/jobs-admin-dates/jobs-admin-dates.component.jsx @@ -20,8 +20,8 @@ const mapStateToProps = createStructuredSelector({ }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect( @@ -57,7 +57,7 @@ export function JobsAdminDatesChange({insertAuditTrail, job}) { ? DateTimeFormat(changedAuditFields[key]) : changedAuditFields[key] ), - }); + type: "admin_jobfieldchange",}); }); if (!!!result.errors) { diff --git a/client/src/components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component.jsx b/client/src/components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component.jsx index b55208e94..b947a7a5c 100644 --- a/client/src/components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component.jsx +++ b/client/src/components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component.jsx @@ -24,8 +24,8 @@ const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect( mapStateToProps, @@ -60,7 +60,7 @@ export function JobAdminMarkReexport({ insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.admin_jobmarkforreexport(), - }); + type: "admin_jobmarkforreexport",}); } else { notification["error"]({ message: t("jobs.errors.saving", { @@ -100,7 +100,7 @@ export function JobAdminMarkReexport({ insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.admin_jobmarkexported(), - }); + type: "admin_jobmarkexported",}); } else { notification["error"]({ message: t("jobs.errors.saving", { @@ -125,7 +125,7 @@ export function JobAdminMarkReexport({ insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.admin_jobuninvoice(), - }); + type: "admin_jobuninvoice",}); } else { notification["error"]({ message: t("jobs.errors.saving", { diff --git a/client/src/components/jobs-admin-remove-ar/jobs-admin-remove-ar.component.jsx b/client/src/components/jobs-admin-remove-ar/jobs-admin-remove-ar.component.jsx index 22970400e..ce5a1535b 100644 --- a/client/src/components/jobs-admin-remove-ar/jobs-admin-remove-ar.component.jsx +++ b/client/src/components/jobs-admin-remove-ar/jobs-admin-remove-ar.component.jsx @@ -10,8 +10,8 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings"; const mapStateToProps = createStructuredSelector({}); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminRemoveAR); @@ -34,7 +34,7 @@ export function JobsAdminRemoveAR({insertAuditTrail, job}) { insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.admin_job_remove_from_ar(value), - }); + type: "admin_job_remove_from_ar",}); setSwitchValue(value); } else { notification["error"]({ diff --git a/client/src/components/jobs-admin-unvoid/jobs-admin-unvoid.component.jsx b/client/src/components/jobs-admin-unvoid/jobs-admin-unvoid.component.jsx index d9735f2d6..7dfa41bb8 100644 --- a/client/src/components/jobs-admin-unvoid/jobs-admin-unvoid.component.jsx +++ b/client/src/components/jobs-admin-unvoid/jobs-admin-unvoid.component.jsx @@ -14,8 +14,8 @@ const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminUnvoid); @@ -46,7 +46,7 @@ export function JobsAdminUnvoid({ insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.admin_jobunvoid(), - }); + type: "admin_jobunvoid",}); } else { notification["error"]({ message: t("jobs.errors.saving", { diff --git a/client/src/components/jobs-available-table/jobs-available-table.container.jsx b/client/src/components/jobs-available-table/jobs-available-table.container.jsx index 92bacbcd5..1feb83846 100644 --- a/client/src/components/jobs-available-table/jobs-available-table.container.jsx +++ b/client/src/components/jobs-available-table/jobs-available-table.container.jsx @@ -38,8 +38,8 @@ const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({ jobid, operation, type }) => + dispatch(insertAuditTrail({ jobid, operation, type })), }); export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail,}) { @@ -177,10 +177,11 @@ export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail, }); //Job has been inserted. Clean up the available jobs record. - insertAuditTrail({ - jobid: r.data.insert_jobs.returning[0].id, - operation: AuditTrailMapping.jobimported(), - }); + insertAuditTrail({ + jobid: r.data.insert_jobs.returning[0].id, + operation: AuditTrailMapping.jobimported(), + type: "jobimported", + }); deleteJob({ variables: {id: estData.id}, @@ -325,24 +326,25 @@ export function JobsAvailableContainer({bodyshop, currentUser, insertAuditTrail, setInsertLoading(false); }); - await insertNote({ - variables: { - noteInput: [ - { - jobid: selectedJob, - created_by: currentUser.email, - audit: true, - text: t("jobs.labels.supplementnote"), - }, - ], - }, - }); - insertAuditTrail({ - jobid: selectedJob, - operation: AuditTrailMapping.jobsupplement(), - }); - } - }; + await insertNote({ + variables: { + noteInput: [ + { + jobid: selectedJob, + created_by: currentUser.email, + audit: true, + text: t("jobs.labels.supplementnote"), + }, + ], + }, + }); + insertAuditTrail({ + jobid: selectedJob, + operation: AuditTrailMapping.jobsupplement(), + type: "jobsupplement", + }); + } + }; const owner = estDataRaw.data && diff --git a/client/src/components/jobs-change-status/jobs-change-status.component.jsx b/client/src/components/jobs-change-status/jobs-change-status.component.jsx index daf384d9d..796283f94 100644 --- a/client/src/components/jobs-change-status/jobs-change-status.component.jsx +++ b/client/src/components/jobs-change-status/jobs-change-status.component.jsx @@ -16,8 +16,8 @@ const mapStateToProps = createStructuredSelector({ jobRO: selectJobReadOnly, }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export function JobsChangeStatus({job, bodyshop, jobRO, insertAuditTrail}) { @@ -35,7 +35,7 @@ export function JobsChangeStatus({job, bodyshop, jobRO, insertAuditTrail}) { insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.jobstatuschange(status), - }); + type: "jobstatuschange",}); // refetch(); }) .catch((error) => { diff --git a/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx b/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx index ffc921a00..52b7cbbd3 100644 --- a/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx +++ b/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx @@ -23,8 +23,8 @@ const mapStateToProps = createStructuredSelector({ }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({ jobid, operation }) => - dispatch(insertAuditTrail({ jobid, operation })), + insertAuditTrail: ({ jobid, operation, type }) => + dispatch(insertAuditTrail({ jobid, operation, type })), }); function updateJobCache(items) { @@ -192,7 +192,7 @@ export function JobsCloseExportButton({ insertAuditTrail({ jobid: jobId, operation: AuditTrailMapping.jobexported(), - }); + type: "jobexported",}); updateJobCache( jobUpdateResponse.data.update_jobs.returning.map((job) => job.id) ); @@ -216,7 +216,7 @@ export function JobsCloseExportButton({ }); insertAuditTrail({ jobid: jobId, - operation: AuditTrailMapping.jobexported(), + operation: AuditTrailMapping.jobexported(),type: "jobexported", }); updateJobCache([ ...new Set( diff --git a/client/src/components/jobs-convert-button/jobs-convert-button.component.jsx b/client/src/components/jobs-convert-button/jobs-convert-button.component.jsx index 3c54e0fad..0afed461d 100644 --- a/client/src/components/jobs-convert-button/jobs-convert-button.component.jsx +++ b/client/src/components/jobs-convert-button/jobs-convert-button.component.jsx @@ -17,8 +17,8 @@ const mapStateToProps = createStructuredSelector({ jobRO: selectJobReadOnly, }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export function JobsConvertButton({ @@ -70,7 +70,8 @@ export function JobsConvertButton({ operation: AuditTrailMapping.jobconverted( res.data.update_jobs.returning[0].ro_number ), - }); + type: "jobconverted", + }); setOpen(false); } diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addtoproduction.util.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addtoproduction.util.jsx index 4dd9a6788..641bf1bba 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addtoproduction.util.jsx +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.addtoproduction.util.jsx @@ -29,6 +29,7 @@ export default function AddToProduction( insertAuditTrail({ jobid: jobId, operation: AuditTrailMapping.jobinproductionchange(!remove), + type: "jobinproductionchange", }) ); if (completionCallback) completionCallback(); @@ -40,8 +41,4 @@ export default function AddToProduction( }), }); }); - - //insert the new job. call the callback with the returned ID when done. - - return; } 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 3e7fd50e8..1eeaf68fe 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 @@ -48,8 +48,8 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(setModalContext({context: context, modal: "timeTicket"})), setCardPaymentContext: (context) => dispatch(setModalContext({context: context, modal: "cardPayment"})), - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({ jobid, operation, type }) => + dispatch(insertAuditTrail({ jobid, operation, type })), setEmailOptions: (e) => dispatch(setEmailOptions(e)), openChatByPhone: (phone) => dispatch(openChatByPhone(phone)), setMessage: (text) => dispatch(setMessage(text)), @@ -240,6 +240,7 @@ export function JobsDetailHeaderActions({ insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.jobvoid(), + type: "jobvoid", }); return; } @@ -461,6 +462,7 @@ export function JobsDetailHeaderActions({ ? !job.production_vars.alert : true, }, + type: "alertToggle", }, }, }); @@ -490,6 +492,7 @@ export function JobsDetailHeaderActions({ operation: AuditTrailMapping.jobsuspend( !!job.suspended ? !job.suspended : true ), + type: "jobsuspend", }); }; @@ -521,6 +524,7 @@ export function JobsDetailHeaderActions({ jobid: job.id, operation: AuditTrailMapping.appointmentcancel(lost_sale_reason), + type: "appointmentcancel", }); } diff --git a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx index 03f4ed6a0..80580a425 100644 --- a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx +++ b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx @@ -23,8 +23,8 @@ const mapStateToProps = createStructuredSelector({ }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({ jobid, operation }) => - dispatch(insertAuditTrail({ jobid, operation })), + insertAuditTrail: ({ jobid, operation, type }) => + dispatch(insertAuditTrail({ jobid, operation, type })), }); function updateJobCache(items) { @@ -189,6 +189,7 @@ export function JobsExportAllButton({ insertAuditTrail({ jobid: job.id, operation: AuditTrailMapping.jobexported(), + type: "jobexported", }); }); updateJobCache( @@ -230,6 +231,7 @@ export function JobsExportAllButton({ insertAuditTrail({ jobid: successfulTransactionsSet[0], operation: AuditTrailMapping.jobexported(), + type: "jobexported", }); } updateJobCache(successfulTransactionsSet); diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx index e5b708fed..f997312c5 100644 --- a/client/src/components/jobs-list/jobs-list.component.jsx +++ b/client/src/components/jobs-list/jobs-list.component.jsx @@ -16,6 +16,7 @@ import useLocalStorage from "../../utils/useLocalStorage"; import AlertComponent from "../alert/alert.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; +import { OwnerNameDisplayFunction } from "./../owner-name-display/owner-name-display.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -142,7 +143,8 @@ export function JobsList({bodyshop}) { ellipsis: true, responsive: ["md"], - sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), + sorter: (a, b) => + alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)), sortOrder: state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, render: (text, record) => { @@ -187,7 +189,8 @@ export function JobsList({bodyshop}) { key: "status", ellipsis: true, - sorter: (a, b) => alphaSort(a.status, b.status), + sorter: (a, b) => + statusSort(a.status, b.status, bodyshop.md_ro_statuses.active_statuses), sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order, filteredValue: filter?.status || null, @@ -218,7 +221,15 @@ export function JobsList({bodyshop}) { dataIndex: "vehicle", key: "vehicle", ellipsis: true, - render: (text, record) => { + sorter: (a, b) => + alphaSort( + `${a.v_model_yr || ""} ${a.v_make_desc || ""} ${ + a.v_model_desc || "" + }`, + `${b.v_model_yr || ""} ${b.v_make_desc || ""} ${b.v_model_desc || ""}` + ), + sortOrder: + state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,render: (text, record) => { return record.vehicleid ? ( alphaSort(a.ins_co_nm, b.ins_co_nm), + sortOrder: + state.sortedInfo.columnKey === "ins_co_nm" && state.sortedInfo.order,filteredValue: filter?.ins_co_nm || null, filters: (jobs && jobs @@ -301,7 +314,13 @@ export function JobsList({bodyshop}) { dataIndex: "jobs.labels.estimator", key: "jobs.labels.estimator", ellipsis: true, - responsive: ["xl"], + responsive: ["xl"],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, filterSearch: true, filteredValue: filter?.estimator || null, filters: diff --git a/client/src/components/jobs-notes/jobs-notes.container.jsx b/client/src/components/jobs-notes/jobs-notes.container.jsx index 763f869ff..e45385854 100644 --- a/client/src/components/jobs-notes/jobs-notes.container.jsx +++ b/client/src/components/jobs-notes/jobs-notes.container.jsx @@ -16,8 +16,8 @@ const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect(mapStateToProps, mapDispatchToProps)(JobNotesContainer); @@ -46,7 +46,7 @@ export function JobNotesContainer({jobId, insertAuditTrail}) { insertAuditTrail({ jobid: jobId, operation: AuditTrailMapping.jobnotedeleted(), - }); + type: "jobnotedeleted",}); }); setDeleteLoading(false); }; diff --git a/client/src/components/labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component.jsx b/client/src/components/labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component.jsx index 6e7808267..0df6acb17 100644 --- a/client/src/components/labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component.jsx +++ b/client/src/components/labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component.jsx @@ -21,8 +21,8 @@ const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export default connect( mapStateToProps, @@ -77,7 +77,7 @@ export function LaborAllocationsAdjustmentEdit({ values.hours - ((adjustments && adjustments[mod_lbr_ty]) || 0).toFixed(1), }), - }); + type: "jobmodifylbradj",}); } setLoading(false); setOpen(false); diff --git a/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx b/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx index b071156c2..fbc5fa7db 100644 --- a/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx +++ b/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx @@ -19,8 +19,8 @@ const mapStateToProps = createStructuredSelector({ }); const mapDispatchToProps = (dispatch) => ({ toggleModalVisible: () => dispatch(toggleModalVisible("noteUpsert")), - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export function NoteUpsertModalContainer({ @@ -70,7 +70,7 @@ export function NoteUpsertModalContainer({ insertAuditTrail({ jobid: context.jobId, operation: AuditTrailMapping.jobnoteupdated(), - }); + type: "jobnoteupdated",}); }); if (refetch) refetch(); toggleModalVisible(); @@ -102,7 +102,7 @@ export function NoteUpsertModalContainer({ insertAuditTrail({ jobid: newJobId, operation: AuditTrailMapping.jobnoteadded(), - }); + type: "jobnoteadded",}); }); } @@ -115,7 +115,7 @@ export function NoteUpsertModalContainer({ insertAuditTrail({ jobid: context.jobId, operation: AuditTrailMapping.jobnoteadded(), - }); + type: "jobnoteadded",}); } }; diff --git a/client/src/components/parts-order-modal/parts-order-modal.container.jsx b/client/src/components/parts-order-modal/parts-order-modal.container.jsx index 35f6db84d..5f9b41180 100644 --- a/client/src/components/parts-order-modal/parts-order-modal.container.jsx +++ b/client/src/components/parts-order-modal/parts-order-modal.container.jsx @@ -1,19 +1,28 @@ -import {useApolloClient, useMutation, useQuery} from "@apollo/client"; -import {Form, Modal, notification} from "antd"; -import dayjs from "../../utils/day"; -import React, {useEffect, useState} from "react"; -import {useTranslation} from "react-i18next"; -import {connect} from "react-redux"; -import {createStructuredSelector} from "reselect"; -import {auth, logImEXEvent} from "../../firebase/firebase.utils"; -import {UPDATE_JOB_LINE_STATUS} from "../../graphql/jobs-lines.queries"; -import {INSERT_NEW_PARTS_ORDERS, QUERY_PARTS_ORDER_OEC,} from "../../graphql/parts-orders.queries"; -import {QUERY_ALL_VENDORS_FOR_ORDER} from "../../graphql/vendors.queries"; -import {insertAuditTrail} from "../../redux/application/application.actions"; -import {setEmailOptions} from "../../redux/email/email.actions"; -import {setModalContext, toggleModalVisible,} from "../../redux/modals/modals.actions"; -import {selectPartsOrder} from "../../redux/modals/modals.selectors"; -import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors"; +import { useMutation, useQuery, useApolloClient } from "@apollo/client"; +import { Form, Modal, notification } from "antd"; +import dayjs from '../../utils/day'; +import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { logImEXEvent, auth } from "../../firebase/firebase.utils"; +import { UPDATE_JOB_LINE_STATUS } from "../../graphql/jobs-lines.queries"; +import { + INSERT_NEW_PARTS_ORDERS, + QUERY_PARTS_ORDER_OEC, +} from "../../graphql/parts-orders.queries"; +import { QUERY_ALL_VENDORS_FOR_ORDER } from "../../graphql/vendors.queries"; +import { insertAuditTrail } from "../../redux/application/application.actions"; +import { setEmailOptions } from "../../redux/email/email.actions"; +import { + setModalContext, + toggleModalVisible, +} from "../../redux/modals/modals.actions"; +import { selectPartsOrder } from "../../redux/modals/modals.selectors"; +import { + selectBodyshop, + selectCurrentUser, +} from "../../redux/user/user.selectors"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; import {GenerateDocument} from "../../utils/RenderTemplate"; import {TemplateList} from "../../utils/TemplateConstants"; @@ -36,8 +45,8 @@ const mapDispatchToProps = (dispatch) => ({ toggleModalVisible: () => dispatch(toggleModalVisible("partsOrder")), setBillEnterContext: (context) => dispatch(setModalContext({context: context, modal: "billEnter"})), - insertAuditTrail: ({jobid, operation}) => - dispatch(insertAuditTrail({jobid, operation})), + insertAuditTrail: ({jobid, operation, type}) => + dispatch(insertAuditTrail({jobid, operation, type })), }); export function PartsOrderModalContainer({ @@ -135,7 +144,8 @@ export function PartsOrderModalContainer({ : AuditTrailMapping.jobspartsorder( insertResult.data.insert_parts_orders.returning[0].order_number ), - }); + type: isReturn ? "jobspartsreturn" : "jobspartsorder", + }); const jobLinesResult = await updateJobLines({ variables: { diff --git a/client/src/components/phonebook-form/phonebook-form.component.jsx b/client/src/components/phonebook-form/phonebook-form.component.jsx index 4df793c0a..aef4d1ab3 100644 --- a/client/src/components/phonebook-form/phonebook-form.component.jsx +++ b/client/src/components/phonebook-form/phonebook-form.component.jsx @@ -2,14 +2,17 @@ import {Button, Form, Input, Space} from "antd"; import {PageHeader} from "@ant-design/pro-layout"; import React from "react"; import {useTranslation} from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { + selectAuthLevel, + selectBodyshop, +} from "../../redux/user/user.selectors"; import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component"; import FormItemEmail from "../form-items-formatted/email-form-item.component"; import PhoneFormItem, {PhoneItemFormatterValidation,} from "../form-items-formatted/phone-form-item.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component"; -import {connect} from "react-redux"; -import {createStructuredSelector} from "reselect"; -import {selectAuthLevel, selectBodyshop,} from "../../redux/user/user.selectors"; const mapStateToProps = createStructuredSelector({ authLevel: selectAuthLevel, @@ -43,13 +46,16 @@ export function PhonebookFormComponent({ return (
+ {() =>`${form.getFieldValue("firstname") || ""} ${ form.getFieldValue("lastname") || "" }${ form.getFieldValue("company") ? ` - ${form.getFieldValue("company")}` - : "" - }`} + : ""}` + } + + } extra={