{record.alt_transport}
@@ -382,7 +411,11 @@ const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
title: i18n.t("production.labels.alert"),
dataIndex: "alert",
key: "alert",
-
+ sorter: (a, b) =>
+ Number(a.production_vars?.alert || false) -
+ Number(b.production_vars?.alert || false),
+ sortOrder:
+ state.sortedInfo.columnKey === "alert" && state.sortedInfo.order,
render: (text, record) =>
,
},
{
diff --git a/client/src/components/production-list-columns/production-list-columns.empassignment.component.jsx b/client/src/components/production-list-columns/production-list-columns.empassignment.component.jsx
index e2ed28896..f3603c666 100644
--- a/client/src/components/production-list-columns/production-list-columns.empassignment.component.jsx
+++ b/client/src/components/production-list-columns/production-list-columns.empassignment.component.jsx
@@ -3,12 +3,12 @@ import { useMutation } from "@apollo/client";
import {
Button,
Col,
- notification,
Popover,
Row,
Select,
Space,
Spin,
+ notification,
} from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
@@ -25,8 +25,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 function ProductionListEmpAssignment({
@@ -55,6 +55,7 @@ export function ProductionListEmpAssignment({
insertAuditTrail({
jobid: record.id,
operation: AuditTrailMapping.jobassignmentchange(empAssignment, name),
+ type: "jobassignmentchange",
});
if (!!result.errors) {
@@ -80,6 +81,7 @@ export function ProductionListEmpAssignment({
insertAuditTrail({
jobid: record.id,
operation: AuditTrailMapping.jobassignmentremoved(empAssignment),
+ type: "jobassignmentremoved",
});
if (!!result.errors) {
diff --git a/client/src/components/production-list-columns/production-list-columns.status.category.jsx b/client/src/components/production-list-columns/production-list-columns.status.category.jsx
index 115b69a3f..d49f1f348 100644
--- a/client/src/components/production-list-columns/production-list-columns.status.category.jsx
+++ b/client/src/components/production-list-columns/production-list-columns.status.category.jsx
@@ -12,8 +12,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 function ProductionListColumnCategory({ record, bodyshop }) {
const [updateJob] = useMutation(UPDATE_JOB);
diff --git a/client/src/components/production-list-columns/production-list-columns.status.component.jsx b/client/src/components/production-list-columns/production-list-columns.status.component.jsx
index e29ffdbeb..b122bd3ae 100644
--- a/client/src/components/production-list-columns/production-list-columns.status.component.jsx
+++ b/client/src/components/production-list-columns/production-list-columns.status.component.jsx
@@ -5,16 +5,16 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
-import { selectBodyshop } from "../../redux/user/user.selectors";
import { insertAuditTrail } from "../../redux/application/application.actions";
+import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
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 function ProductionListColumnStatus({
record,
@@ -40,6 +40,7 @@ export function ProductionListColumnStatus({
insertAuditTrail({
jobid: record.id,
operation: AuditTrailMapping.jobstatuschange(key),
+ type: "jobstatuschange",
});
setLoading(false);
diff --git a/client/src/components/report-center-modal/report-center-modal-filters-sorters-component.jsx b/client/src/components/report-center-modal/report-center-modal-filters-sorters-component.jsx
index 892ce67d5..9a2daff8a 100644
--- a/client/src/components/report-center-modal/report-center-modal-filters-sorters-component.jsx
+++ b/client/src/components/report-center-modal/report-center-modal-filters-sorters-component.jsx
@@ -142,7 +142,8 @@ function FiltersSection({filters, form, bodyshop}) {
return generateInternalReflections({
bodyshop,
upperPath,
- finalPath
+ finalPath,
+ t
});
};
diff --git a/client/src/components/report-center-modal/report-center-modal-utils.js b/client/src/components/report-center-modal/report-center-modal-utils.js
index 97b693a61..d78405cfd 100644
--- a/client/src/components/report-center-modal/report-center-modal-utils.js
+++ b/client/src/components/report-center-modal/report-center-modal-utils.js
@@ -22,7 +22,6 @@ const generateOptionsFromArray = (bodyshop, path) => {
})), 'value');
}
-
/**
* Valid internal reflections
* Note: This is intended for future functionality
@@ -57,10 +56,34 @@ const generateOptionsFromObject = (bodyshop, path, labelPath, valuePath) => {
* Generate special reflections
* @param bodyshop
* @param finalPath
+ * @param t - i18n
* @returns {{label: *, value: *}[]|{label: *, value: *}[]|{label: string, value: *}[]|*[]}
*/
-const generateSpecialReflections = (bodyshop, finalPath) => {
+const generateSpecialReflections = (bodyshop, finalPath, t) => {
switch (finalPath) {
+ case 'payment_payers':
+ return [
+ {
+ label: t("payments.labels.customer"),
+ value: t("payments.labels.customer"),
+ },
+ {
+ label: t("payments.labels.insurance"),
+ value: t("payments.labels.insurance"),
+ },
+ // This is a weird one supposedly only used by one shop and could potentially be
+ // placed behind a SplitSDK
+ {
+ label: t("payments.labels.external"),
+ value: t("payments.labels.external"),
+ }
+ ];
+ case 'payment_types':
+ return generateOptionsFromArray(bodyshop, 'md_payment_types');
+ case 'alt_transports':
+ return generateOptionsFromArray(bodyshop, 'appt_alt_transport');
+ case 'lost_sale_reasons':
+ return generateOptionsFromArray(bodyshop, 'md_lost_sale_reasons');
// Special case because Referral Sources is an Array, not an Object.
case 'referral_source':
return generateOptionsFromArray(bodyshop, 'md_referral_sources');
@@ -121,12 +144,13 @@ const generateBodyshopReflections = (bodyshop, finalPath) => {
* @param bodyshop
* @param upperPath
* @param finalPath
+ * @param t - i18n
* @returns {{label: *, value: *}[]|[]|{label: *, value: *}[]|{label: string, value: *}[]|{label: *, value: *}[]|*[]}
*/
-const generateInternalReflections = ({bodyshop, upperPath, finalPath}) => {
+const generateInternalReflections = ({bodyshop, upperPath, finalPath, t}) => {
switch (upperPath) {
case 'special':
- return generateSpecialReflections(bodyshop, finalPath);
+ return generateSpecialReflections(bodyshop, finalPath, t);
case 'bodyshop':
return generateBodyshopReflections(bodyshop, finalPath);
default:
diff --git a/client/src/components/schedule-job-modal/schedule-job-modal.container.jsx b/client/src/components/schedule-job-modal/schedule-job-modal.container.jsx
index 19d6d4a37..c5a781fc0 100644
--- a/client/src/components/schedule-job-modal/schedule-job-modal.container.jsx
+++ b/client/src/components/schedule-job-modal/schedule-job-modal.container.jsx
@@ -34,8 +34,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("schedule")),
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({ jobid, operation, type }) =>
+ dispatch(insertAuditTrail({ jobid, operation, type })),
});
export function ScheduleJobModalContainer({
@@ -146,6 +146,7 @@ export function ScheduleJobModalContainer({
operation: AuditTrailMapping.appointmentinsert(
DateTimeFormat(values.start)
),
+ type: "appointmentinsert",
});
}
diff --git a/client/src/graphql/audit_trail.queries.js b/client/src/graphql/audit_trail.queries.js
index 793cc0001..29891412c 100644
--- a/client/src/graphql/audit_trail.queries.js
+++ b/client/src/graphql/audit_trail.queries.js
@@ -40,6 +40,7 @@ export const INSERT_AUDIT_TRAIL = gql`
bodyshopid
created
operation
+ type
useremail
}
}
diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js
index 650abc302..1379535e1 100644
--- a/client/src/graphql/jobs.queries.js
+++ b/client/src/graphql/jobs.queries.js
@@ -1862,6 +1862,7 @@ export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
ownr_co_nm
ownr_ph1
ownr_ph2
+ ownerid
plate_no
plate_st
v_vin
diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx
index 9ed0133a9..32d48b55c 100644
--- a/client/src/pages/dms/dms.container.jsx
+++ b/client/src/pages/dms/dms.container.jsx
@@ -40,8 +40,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({ jobid, operation, type }) =>
+ dispatch(insertAuditTrail({ jobid, operation, type })),
});
export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
@@ -127,6 +127,7 @@ export function DmsContainer({
insertAuditTrail({
jobid: payload,
operation: AuditTrailMapping.jobexported(),
+ type: "jobexported",
});
history.push("/manage/accounting/receivables");
});
diff --git a/client/src/pages/export-logs/export-logs.page.component.jsx b/client/src/pages/export-logs/export-logs.page.component.jsx
index 7ae8977cf..8e090a712 100644
--- a/client/src/pages/export-logs/export-logs.page.component.jsx
+++ b/client/src/pages/export-logs/export-logs.page.component.jsx
@@ -12,7 +12,8 @@ import AlertComponent from "../../components/alert/alert.component";
import { QUERY_EXPORT_LOG_PAGINATED } from "../../graphql/accounting.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { DateTimeFormatter } from "../../utils/DateFormatter";
-import {pageLimit} from "../../utils/config";
+import { pageLimit } from "../../utils/config";
+import { alphaSort, dateSort } from "./../../utils/sorters";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -34,11 +35,43 @@ export function ExportLogsPageComponent({ bodyshop }) {
limit: pageLimit,
order: [
{
- [sortcolumn || "created_at"]: sortorder
- ? sortorder === "descend"
- ? "desc"
- : "asc"
- : "desc",
+ ...(sortcolumn === "ro_number"
+ ? {
+ job: {
+ [sortcolumn || "created_at"]: sortorder
+ ? sortorder === "descend"
+ ? "desc"
+ : "asc"
+ : "desc",
+ },
+ }
+ : sortcolumn === "invoice_number"
+ ? {
+ bill: {
+ [sortcolumn || "created_at"]: sortorder
+ ? sortorder === "descend"
+ ? "desc"
+ : "asc"
+ : "desc",
+ },
+ }
+ : sortcolumn === "paymentnum"
+ ? {
+ payment: {
+ [sortcolumn || "created_at"]: sortorder
+ ? sortorder === "descend"
+ ? "desc"
+ : "asc"
+ : "desc",
+ },
+ }
+ : {
+ [sortcolumn || "created_at"]: sortorder
+ ? sortorder === "descend"
+ ? "desc"
+ : "asc"
+ : "desc",
+ }),
},
],
},
@@ -68,6 +101,8 @@ export function ExportLogsPageComponent({ bodyshop }) {
title: t("general.labels.created_at"),
dataIndex: "created_at",
key: "created_at",
+ sorter: (a, b) => dateSort(a.created_at, b.created_at),
+ sortOrder: sortcolumn === "created_at" && sortorder,
render: (text, record) => (
{record.created_at}
),
@@ -81,7 +116,8 @@ export function ExportLogsPageComponent({ bodyshop }) {
title: t("jobs.fields.ro_number"),
dataIndex: "ro_number",
key: "ro_number",
-
+ sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
+ sortOrder: sortcolumn === "ro_number" && sortorder,
render: (text, record) =>
record.job && (
@@ -93,6 +129,8 @@ export function ExportLogsPageComponent({ bodyshop }) {
title: t("bills.fields.invoice_number"),
dataIndex: "invoice_number",
key: "invoice_number",
+ sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
+ sortOrder: sortcolumn === "invoice_number" && sortorder,
render: (text, record) =>
record.bill && (
@@ -104,6 +142,8 @@ export function ExportLogsPageComponent({ bodyshop }) {
title: t("payments.fields.paymentnum"),
dataIndex: "paymentnum",
key: "paymentnum",
+ sorter: (a, b) => alphaSort(a.paymentnum, b.paymentnum),
+ sortOrder: sortcolumn === "paymentnum" && sortorder,
render: (text, record) =>
record.payment && (
Number(a.successful) - Number(b.successful),
+ sortOrder: sortcolumn === "successful" && sortorder,
+ filters: [
+ { text: "True", value: true },
+ { text: "False", value: false },
+ ],
+ onFilter: (value, record) => record.successful === value,
render: (text, record) => (
),
diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx
index b6feb3ff5..b95d72a7d 100644
--- a/client/src/pages/jobs-close/jobs-close.component.jsx
+++ b/client/src/pages/jobs-close/jobs-close.component.jsx
@@ -47,11 +47,11 @@ const mapStateToProps = createStructuredSelector({
});
const mapDispatchToProps = (dispatch) => ({
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({ jobid, operation, type }) =>
+ dispatch(insertAuditTrail({ jobid, operation, type })),
});
-export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, }) {
+export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail }) {
const { t } = useTranslation();
const [form] = Form.useForm();
const client = useApolloClient();
@@ -121,6 +121,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail, })
insertAuditTrail({
jobid: job.id,
operation: AuditTrailMapping.jobinvoiced(),
+ type: "jobinvoiced",
});
// history.push(`/manage/jobs/${job.id}`);
} else {
diff --git a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx
index 89a912242..ec383d6a7 100644
--- a/client/src/pages/jobs-detail/jobs-detail.page.component.jsx
+++ b/client/src/pages/jobs-detail/jobs-detail.page.component.jsx
@@ -29,6 +29,7 @@ import { createStructuredSelector } from "reselect";
import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component";
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
+import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component";
import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container";
import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container";
import JobSyncButton from "../../components/job-sync-button/job-sync-button.component";
@@ -54,7 +55,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import UndefinedToNull from "../../utils/undefinedtonull";
import { DateTimeFormat } from "./../../utils/DateFormatter";
-import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -63,8 +63,8 @@ const mapStateToProps = createStructuredSelector({
const mapDispatchToProps = (dispatch) => ({
setPrintCenterContext: (context) =>
dispatch(setModalContext({ context: context, modal: "printCenter" })),
- insertAuditTrail: ({ jobid, operation }) =>
- dispatch(insertAuditTrail({ jobid, operation })),
+ insertAuditTrail: ({ jobid, operation, type }) =>
+ dispatch(insertAuditTrail({ jobid, operation, type })),
});
export function JobsDetailPage({
bodyshop,
@@ -177,6 +177,7 @@ export function JobsDetailPage({
? DateTimeFormat(changedAuditFields[key])
: changedAuditFields[key]
),
+ type: "jobfieldchange",
});
});
@@ -334,15 +335,23 @@ export function JobsDetailPage({
>
-
{t('menus.jobsdetail.lifecycle')}}
- key="lifecycle"
- >
-
-
+
+
+ {t("menus.jobsdetail.lifecycle")}
+
+ }
+ key="lifecycle"
+ >
+
+
-
diff --git a/client/src/redux/application/application.actions.js b/client/src/redux/application/application.actions.js
index 88e23ad66..40b97e168 100644
--- a/client/src/redux/application/application.actions.js
+++ b/client/src/redux/application/application.actions.js
@@ -54,9 +54,9 @@ export const setOnline = (isOnline) => ({
payload: isOnline,
});
-export const insertAuditTrail = ({ jobid, billid, operation }) => ({
+export const insertAuditTrail = ({ jobid, billid, operation, type }) => ({
type: ApplicationActionTypes.INSERT_AUDIT_TRAIL,
- payload: { jobid, billid, operation },
+ payload: { jobid, billid, operation, type },
});
export const setProblemJobs = (problemJobs) => ({
type: ApplicationActionTypes.SET_PROBLEM_JOBS,
diff --git a/client/src/redux/application/application.sagas.js b/client/src/redux/application/application.sagas.js
index fed628415..dc907da74 100644
--- a/client/src/redux/application/application.sagas.js
+++ b/client/src/redux/application/application.sagas.js
@@ -266,7 +266,7 @@ export function* onInsertAuditTrail() {
}
export function* insertAuditTrailSaga({
- payload: { jobid, billid, operation },
+ payload: { jobid, billid, operation, type },
}) {
const state = yield select();
const bodyshop = state.user.bodyshop;
@@ -278,6 +278,7 @@ export function* insertAuditTrailSaga({
jobid,
billid,
operation,
+ type,
useremail: currentUser.email,
},
};
diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml
index 17ccc52a9..587fa8ac3 100644
--- a/hasura/metadata/tables.yaml
+++ b/hasura/metadata/tables.yaml
@@ -259,28 +259,30 @@
- active:
_eq: true
columns:
- - id
+ - billid
+ - bodyshopid
- created
- - operation
+ - id
+ - jobid
- new_val
- old_val
+ - operation
+ - type
- useremail
- - bodyshopid
- - jobid
- - billid
select_permissions:
- role: user
permission:
columns:
+ - billid
+ - bodyshopid
+ - created
- id
+ - jobid
- new_val
- old_val
- operation
+ - type
- useremail
- - created
- - billid
- - bodyshopid
- - jobid
filter:
bodyshop:
associations:
diff --git a/hasura/migrations/1709671738458_alter_table_public_audit_trail_add_column_type/down.sql b/hasura/migrations/1709671738458_alter_table_public_audit_trail_add_column_type/down.sql
new file mode 100644
index 000000000..cc828330e
--- /dev/null
+++ b/hasura/migrations/1709671738458_alter_table_public_audit_trail_add_column_type/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"."audit_trail" add column "type" text
+-- null;
diff --git a/hasura/migrations/1709671738458_alter_table_public_audit_trail_add_column_type/up.sql b/hasura/migrations/1709671738458_alter_table_public_audit_trail_add_column_type/up.sql
new file mode 100644
index 000000000..6653b7b7f
--- /dev/null
+++ b/hasura/migrations/1709671738458_alter_table_public_audit_trail_add_column_type/up.sql
@@ -0,0 +1,2 @@
+alter table "public"."audit_trail" add column "type" text
+ null;