diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 2286ea1c5..d37bdbacf 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -1243,6 +1243,69 @@ messages + + admin_jobmarkexported + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + admin_jobmarkforreexport + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + admin_jobunvoid + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + billposted 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 a20c6ea20..edef81343 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 @@ -6,17 +6,20 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { UPDATE_JOB_STATUS } from "../../graphql/jobs.queries"; +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) => ({ - //setUserLanguage: language => dispatch(setUserLanguage(language)) + insertAuditTrail: ({ jobid, operation }) => + dispatch(insertAuditTrail({ jobid, operation })), }); export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminStatus); -export function JobsAdminStatus({ bodyshop, job }) { +export function JobsAdminStatus({ insertAuditTrail, bodyshop, job }) { const { t } = useTranslation(); const [mutationUpdateJobstatus] = useMutation(UPDATE_JOB_STATUS); @@ -26,6 +29,10 @@ export function JobsAdminStatus({ bodyshop, job }) { }) .then((r) => { notification["success"]({ message: t("jobs.successes.save") }); + insertAuditTrail({ + jobid: job.id, + operation: AuditTrailMapping.admin_jobstatuschange(status), + }); // 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 28cc4595e..309c433cf 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 @@ -7,8 +7,27 @@ import DateTimePicker from "../form-date-time-picker/form-date-time-picker.compo import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import moment from "moment"; import FormDatePicker from "../form-date-picker/form-date-picker.component"; +import AuditTrailMapping from "../../utils/AuditTrailMappings"; -export default function JobsAdminDatesChange({ job }) { +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { insertAuditTrail } from "../../redux/application/application.actions"; + +const mapStateToProps = createStructuredSelector({ + //currentUser: selectCurrentUser +}); + +const mapDispatchToProps = (dispatch) => ({ + insertAuditTrail: ({ jobid, operation }) => + dispatch(insertAuditTrail({ jobid, operation })), +}); + +export default connect( + mapStateToProps, + mapDispatchToProps +)(JobsAdminDatesChange); + +export function JobsAdminDatesChange({ insertAuditTrail, job }) { const { t } = useTranslation(); const [loading, setLoading] = useState(false); const [form] = Form.useForm(); @@ -20,6 +39,23 @@ export default function JobsAdminDatesChange({ job }) { variables: { jobId: job.id, job: values }, }); + const changedAuditFields = form.getFieldsValue( + true, + (meta) => meta && meta.touched + ); + + Object.keys(changedAuditFields).forEach((key) => { + insertAuditTrail({ + jobid: job.id, + operation: AuditTrailMapping.admin_jobfieldchange( + key, + changedAuditFields[key] instanceof moment + ? moment(changedAuditFields[key]).format("MM/DD/YYYY hh:mm a") + : changedAuditFields[key] + ), + }); + }); + if (!!!result.errors) { notification["success"]({ message: t("jobs.successes.save") }); } else { 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 18b624606..929c7f6d5 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 @@ -8,18 +8,21 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import moment from "moment"; +import AuditTrailMapping from "../../utils/AuditTrailMappings"; +import { insertAuditTrail } from "../../redux/application/application.actions"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, }); const mapDispatchToProps = (dispatch) => ({ - //setUserLanguage: language => dispatch(setUserLanguage(language)) + insertAuditTrail: ({ jobid, operation }) => + dispatch(insertAuditTrail({ jobid, operation })), }); export default connect( mapStateToProps, mapDispatchToProps )(JobAdminMarkReexport); -export function JobAdminMarkReexport({ bodyshop, job }) { +export function JobAdminMarkReexport({ insertAuditTrail, bodyshop, job }) { const { t } = useTranslation(); const [loading, setLoading] = useState(false); const [markJobForReexport] = useMutation(gql` @@ -78,6 +81,10 @@ export function JobAdminMarkReexport({ bodyshop, job }) { if (!result.errors) { notification["success"]({ message: t("jobs.successes.save") }); + insertAuditTrail({ + jobid: job.id, + operation: AuditTrailMapping.admin_jobmarkforreexport(), + }); } else { notification["error"]({ message: t("jobs.errors.saving", { @@ -96,6 +103,10 @@ export function JobAdminMarkReexport({ bodyshop, job }) { if (!result.errors) { notification["success"]({ message: t("jobs.successes.save") }); + insertAuditTrail({ + jobid: job.id, + operation: AuditTrailMapping.admin_jobmarkexported(), + }); } else { notification["error"]({ message: t("jobs.errors.saving", { 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 4f36cd850..8682cd406 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 @@ -4,21 +4,29 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; +import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectBodyshop, selectCurrentUser, } from "../../redux/user/user.selectors"; +import AuditTrailMapping from "../../utils/AuditTrailMappings"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, currentUser: selectCurrentUser, }); const mapDispatchToProps = (dispatch) => ({ - //setUserLanguage: language => dispatch(setUserLanguage(language)) + insertAuditTrail: ({ jobid, operation }) => + dispatch(insertAuditTrail({ jobid, operation })), }); export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminUnvoid); -export function JobsAdminUnvoid({ bodyshop, job, currentUser }) { +export function JobsAdminUnvoid({ + insertAuditTrail, + bodyshop, + job, + currentUser, +}) { const { t } = useTranslation(); const [loading, setLoading] = useState(false); const [updateJob] = useMutation(gql` @@ -84,6 +92,11 @@ mutation UNVOID_JOB($jobId: uuid!) { if (!result.errors) { notification["success"]({ message: t("jobs.successes.save") }); + + insertAuditTrail({ + jobid: job.id, + operation: AuditTrailMapping.admin_unvoicejob(), + }); } else { notification["error"]({ message: t("jobs.errors.saving", { diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index e72220789..477f35ffd 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -90,6 +90,9 @@ }, "audit_trail": { "messages": { + "admin_jobmarkexported": "ADMIN: Job marked as exported.", + "admin_jobmarkforreexport": "ADMIN: Job marked for re-export.", + "admin_jobunvoid": "ADMIN: Job has been unvoided.", "billposted": "Bill with invoice number {{invoice_number}} posted.", "billupdated": "Bill with invoice number {{invoice_number}} updated.", "jobassignmentchange": "Employee {{name}} assigned to {{operation}}", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 690f9f7e1..399f2ecde 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -90,6 +90,9 @@ }, "audit_trail": { "messages": { + "admin_jobmarkexported": "", + "admin_jobmarkforreexport": "", + "admin_jobunvoid": "", "billposted": "", "billupdated": "", "jobassignmentchange": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 66aa029d8..126ef607d 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -90,6 +90,9 @@ }, "audit_trail": { "messages": { + "admin_jobmarkexported": "", + "admin_jobmarkforreexport": "", + "admin_jobunvoid": "", "billposted": "", "billupdated": "", "jobassignmentchange": "", diff --git a/client/src/utils/AuditTrailMappings.js b/client/src/utils/AuditTrailMappings.js index e0d43b098..031cab1a0 100644 --- a/client/src/utils/AuditTrailMappings.js +++ b/client/src/utils/AuditTrailMappings.js @@ -3,12 +3,17 @@ import i18n from "i18next"; const AuditTrailMapping = { jobstatuschange: (status) => i18n.t("audit_trail.messages.jobstatuschange", { status }), + admin_jobstatuschange: (status) => + "ADMIN: " + i18n.t("audit_trail.messages.jobstatuschange", { status }), jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"), jobimported: () => i18n.t("audit_trail.messages.jobimported"), jobconverted: (ro_number) => i18n.t("audit_trail.messages.jobconverted", { ro_number }), jobfieldchange: (field, value) => i18n.t("audit_trail.messages.jobfieldchanged", { field, value }), + admin_jobfieldchange: (field, value) => + "ADMIN: " + + i18n.t("audit_trail.messages.jobfieldchanged", { field, value }), jobspartsorder: (order_number) => i18n.t("audit_trail.messages.jobspartsorder", { order_number }), jobspartsreturn: (order_number) => @@ -29,6 +34,11 @@ const AuditTrailMapping = { jobnoteadded: () => i18n.t("audit_trail.messages.jobnoteadded"), jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"), jobnotedeleted: () => i18n.t("audit_trail.messages.jobnotedeleted"), + admin_jobunvoid: () => i18n.t("audit_trail.messages.admin_jobunvoid"), + admin_jobmarkforreexport: () => + i18n.t("audit_trail.messages.admin_jobmarkforreexport"), + admin_jobmarkexported: () => + i18n.t("audit_trail.messages.admin_jobmarkexported"), }; export default AuditTrailMapping;