Merged in feature/IO-1366-Audit-Logging (pull request #1311)
Feature/IO-1366 Audit Logging Approved-by: Dave Richer
This commit is contained in:
@@ -3,10 +3,22 @@ import { useMutation } from "@apollo/client";
|
||||
import { Button, notification, Popconfirm } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { DELETE_BILL } from "../../graphql/bills.queries";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||
|
||||
export default function BillDeleteButton({ bill, callback }) {
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
insertAuditTrail: ({ jobid, operation }) =>
|
||||
dispatch(insertAuditTrail({ jobid, operation })),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(BillDeleteButton);
|
||||
|
||||
export function BillDeleteButton({ bill, jobid, callback, insertAuditTrail }) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const [deleteBill] = useMutation(DELETE_BILL);
|
||||
@@ -36,6 +48,10 @@ export default function BillDeleteButton({ bill, callback }) {
|
||||
|
||||
if (!!!result.errors) {
|
||||
notification["success"]({ message: t("bills.successes.deleted") });
|
||||
insertAuditTrail({
|
||||
jobid: jobid,
|
||||
operation: AuditTrailMapping.billdeleted(bill.invoice_number),
|
||||
});
|
||||
|
||||
if (callback && typeof callback === "function") callback(bill.id);
|
||||
} else {
|
||||
|
||||
@@ -9,8 +9,8 @@ import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import BillDeleteButton from "../bill-delete-button/bill-delete-button.component";
|
||||
import BillDetailEditReturnComponent from "../bill-detail-edit/bill-detail-edit-return.component";
|
||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||
@@ -58,7 +58,7 @@ export function BillsListTableComponent({
|
||||
<EditFilled />
|
||||
</Button>
|
||||
)}
|
||||
<BillDeleteButton bill={record} />
|
||||
<BillDeleteButton bill={record} jobid={job.id} />
|
||||
<BillDetailEditReturnComponent
|
||||
data={{ bills_by_pk: { ...record, jobid: job.id } }}
|
||||
disabled={
|
||||
|
||||
@@ -9,10 +9,12 @@ import { createStructuredSelector } from "reselect";
|
||||
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import client from "../../utils/GraphQLClient";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -20,6 +22,11 @@ const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
insertAuditTrail: ({ jobid, operation }) =>
|
||||
dispatch(insertAuditTrail({ jobid, operation })),
|
||||
});
|
||||
|
||||
function updateJobCache(items) {
|
||||
client.cache.modify({
|
||||
id: "ROOT_QUERY",
|
||||
@@ -40,6 +47,7 @@ export function JobsCloseExportButton({
|
||||
disabled,
|
||||
setSelectedJobs,
|
||||
refetch,
|
||||
insertAuditTrail,
|
||||
}) {
|
||||
const history = useHistory();
|
||||
const { t } = useTranslation();
|
||||
@@ -181,6 +189,10 @@ export function JobsCloseExportButton({
|
||||
key: "jobsuccessexport",
|
||||
message: t("jobs.successes.exported"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: jobId,
|
||||
operation: AuditTrailMapping.jobexported(),
|
||||
});
|
||||
updateJobCache(
|
||||
jobUpdateResponse.data.update_jobs.returning.map((job) => job.id)
|
||||
);
|
||||
@@ -192,12 +204,20 @@ export function JobsCloseExportButton({
|
||||
});
|
||||
}
|
||||
}
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
||||
if (
|
||||
bodyshop.accountingconfig &&
|
||||
bodyshop.accountingconfig.qbo &&
|
||||
successfulTransactions.length > 0
|
||||
) {
|
||||
notification.open({
|
||||
type: "success",
|
||||
key: "jobsuccessexport",
|
||||
message: t("jobs.successes.exported"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: jobId,
|
||||
operation: AuditTrailMapping.jobexported(),
|
||||
});
|
||||
updateJobCache([
|
||||
...new Set(
|
||||
successfulTransactions.map(
|
||||
@@ -227,4 +247,7 @@ export function JobsCloseExportButton({
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(JobsCloseExportButton);
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsCloseExportButton);
|
||||
|
||||
@@ -129,6 +129,12 @@ export function JobsDetailHeaderActions({
|
||||
},
|
||||
},
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobsuspend(
|
||||
!!job.suspended ? !job.suspended : true
|
||||
),
|
||||
});
|
||||
};
|
||||
|
||||
const statusmenu = (
|
||||
@@ -540,6 +546,10 @@ export function JobsDetailHeaderActions({
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.voided"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobvoid(),
|
||||
});
|
||||
//go back to jobs list.
|
||||
history.push(`/manage/`);
|
||||
} else {
|
||||
|
||||
@@ -9,10 +9,12 @@ import { createStructuredSelector } from "reselect";
|
||||
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||
import { UPDATE_JOBS } from "../../graphql/jobs.queries";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import client from "../../utils/GraphQLClient";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -20,6 +22,11 @@ const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
insertAuditTrail: ({ jobid, operation }) =>
|
||||
dispatch(insertAuditTrail({ jobid, operation })),
|
||||
});
|
||||
|
||||
function updateJobCache(items) {
|
||||
client.cache.modify({
|
||||
id: "ROOT_QUERY",
|
||||
@@ -41,6 +48,7 @@ export function JobsExportAllButton({
|
||||
loadingCallback,
|
||||
completedCallback,
|
||||
refetch,
|
||||
insertAuditTrail,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [updateJob] = useMutation(UPDATE_JOBS);
|
||||
@@ -177,6 +185,12 @@ export function JobsExportAllButton({
|
||||
key: "jobsuccessexport",
|
||||
message: t("jobs.successes.exported"),
|
||||
});
|
||||
jobUpdateResponse.data.update_jobs.returning.forEach((job) => {
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobexported(),
|
||||
});
|
||||
});
|
||||
updateJobCache(
|
||||
jobUpdateResponse.data.update_jobs.returning.map(
|
||||
(job) => job.id
|
||||
@@ -190,13 +204,17 @@ export function JobsExportAllButton({
|
||||
});
|
||||
}
|
||||
}
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
||||
if (
|
||||
bodyshop.accountingconfig &&
|
||||
bodyshop.accountingconfig.qbo &&
|
||||
successfulTransactions.length > 0
|
||||
) {
|
||||
notification.open({
|
||||
type: "success",
|
||||
key: "jobsuccessexport",
|
||||
message: t("jobs.successes.exported"),
|
||||
});
|
||||
updateJobCache([
|
||||
const successfulTransactionsSet = [
|
||||
...new Set(
|
||||
successfulTransactions.map(
|
||||
(st) =>
|
||||
@@ -207,7 +225,14 @@ export function JobsExportAllButton({
|
||||
]
|
||||
)
|
||||
),
|
||||
]);
|
||||
];
|
||||
if (successfulTransactionsSet.length > 0) {
|
||||
insertAuditTrail({
|
||||
jobid: successfulTransactionsSet[0],
|
||||
operation: AuditTrailMapping.jobexported(),
|
||||
});
|
||||
}
|
||||
updateJobCache(successfulTransactionsSet);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -225,4 +250,7 @@ export function JobsExportAllButton({
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(JobsExportAllButton);
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsExportAllButton);
|
||||
|
||||
@@ -26,10 +26,12 @@ import { OwnerNameDisplayFunction } from "../../components/owner-name-display/ow
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
import { QUERY_JOB_EXPORT_DMS } from "../../graphql/jobs.queries";
|
||||
import {
|
||||
insertAuditTrail,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
} from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -38,6 +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 })),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
|
||||
@@ -46,7 +50,7 @@ export const socket = SocketIO(
|
||||
process.env.NODE_ENV === "production"
|
||||
? process.env.REACT_APP_AXIOS_BASE_API_URL
|
||||
: window.location.origin,
|
||||
// "http://localhost:4000", // for dev testing,
|
||||
// "http://localhost:4000", // for dev testing,
|
||||
{
|
||||
path: "/ws",
|
||||
withCredentials: true,
|
||||
@@ -57,7 +61,12 @@ export const socket = SocketIO(
|
||||
}
|
||||
);
|
||||
|
||||
export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
export function DmsContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
insertAuditTrail,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [logLevel, setLogLevel] = useState("DEBUG");
|
||||
const history = useHistory();
|
||||
@@ -115,6 +124,10 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
notification.success({
|
||||
message: t("jobs.successes.exported"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: payload,
|
||||
operation: AuditTrailMapping.jobexported(),
|
||||
});
|
||||
history.push("/manage/accounting/receivables");
|
||||
});
|
||||
|
||||
|
||||
@@ -289,7 +289,7 @@ export function* insertAuditTrailSaga({
|
||||
fields: {
|
||||
audit_trail(existingAuditTrail, { readField }) {
|
||||
const newAuditTrail = cache.writeQuery({
|
||||
data: data.insert_audit_trail_one,
|
||||
data: data,
|
||||
query: INSERT_AUDIT_TRAIL,
|
||||
variables,
|
||||
});
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"alerttoggle": "Alert Toggle set to {{status}}",
|
||||
"appointmentcancel": "Appointment canceled. Lost Reason: {{lost_sale_reason}}.",
|
||||
"appointmentinsert": "Appointment created. Appointment Date: {{start}}.",
|
||||
"billdeleted": "Bill with invoice number {{invoice_number}} deleted.",
|
||||
"billposted": "Bill with invoice number {{invoice_number}} posted.",
|
||||
"billupdated": "Bill with invoice number {{invoice_number}} updated.",
|
||||
"failedpayment": "Failed payment",
|
||||
@@ -114,6 +115,7 @@
|
||||
"jobassignmentremoved": "Employee assignment removed for {{operation}}",
|
||||
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
|
||||
"jobconverted": "Job converted and assigned number {{ro_number}}.",
|
||||
"jobexported": "Job has been exported.",
|
||||
"jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.",
|
||||
"jobimported": "Job imported.",
|
||||
"jobinproductionchange": "Job production status set to {{inproduction}}",
|
||||
@@ -126,7 +128,9 @@
|
||||
"jobspartsorder": "Parts order {{order_number}} added to Job.",
|
||||
"jobspartsreturn": "Parts return {{order_number}} added to Job.",
|
||||
"jobstatuschange": "Job status changed to {{status}}.",
|
||||
"jobsupplement": "Job supplement imported."
|
||||
"jobsupplement": "Job supplement imported.",
|
||||
"jobsuspend": "Suspend Toggle set to {{status}}",
|
||||
"jobvoid": "Job has been voided."
|
||||
}
|
||||
},
|
||||
"billlines": {
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"alerttoggle": "",
|
||||
"appointmentcancel": "",
|
||||
"appointmentinsert": "",
|
||||
"billdeleted": "",
|
||||
"billposted": "",
|
||||
"billupdated": "",
|
||||
"failedpayment": "",
|
||||
@@ -114,6 +115,7 @@
|
||||
"jobassignmentremoved": "",
|
||||
"jobchecklist": "",
|
||||
"jobconverted": "",
|
||||
"jobexported": "",
|
||||
"jobfieldchanged": "",
|
||||
"jobimported": "",
|
||||
"jobinproductionchange": "",
|
||||
@@ -126,7 +128,9 @@
|
||||
"jobspartsorder": "",
|
||||
"jobspartsreturn": "",
|
||||
"jobstatuschange": "",
|
||||
"jobsupplement": ""
|
||||
"jobsupplement": "",
|
||||
"jobsuspend": "",
|
||||
"jobvoid": ""
|
||||
}
|
||||
},
|
||||
"billlines": {
|
||||
|
||||
@@ -107,6 +107,7 @@
|
||||
"alerttoggle": "",
|
||||
"appointmentcancel": "",
|
||||
"appointmentinsert": "",
|
||||
"billdeleted": "",
|
||||
"billposted": "",
|
||||
"billupdated": "",
|
||||
"failedpayment": "",
|
||||
@@ -114,6 +115,7 @@
|
||||
"jobassignmentremoved": "",
|
||||
"jobchecklist": "",
|
||||
"jobconverted": "",
|
||||
"jobexported": "",
|
||||
"jobfieldchanged": "",
|
||||
"jobimported": "",
|
||||
"jobinproductionchange": "",
|
||||
@@ -126,7 +128,9 @@
|
||||
"jobspartsorder": "",
|
||||
"jobspartsreturn": "",
|
||||
"jobstatuschange": "",
|
||||
"jobsupplement": ""
|
||||
"jobsupplement": "",
|
||||
"jobsuspend": "",
|
||||
"jobvoid": ""
|
||||
}
|
||||
},
|
||||
"billlines": {
|
||||
|
||||
@@ -20,6 +20,8 @@ const AuditTrailMapping = {
|
||||
i18n.t("audit_trail.messages.appointmentcancel", { lost_sale_reason }),
|
||||
appointmentinsert: (start) =>
|
||||
i18n.t("audit_trail.messages.appointmentinsert", { start }),
|
||||
billdeleted: (invoice_number) =>
|
||||
i18n.t("audit_trail.messages.billdeleted", { invoice_number }),
|
||||
billposted: (invoice_number) =>
|
||||
i18n.t("audit_trail.messages.billposted", { invoice_number }),
|
||||
billupdated: (invoice_number) =>
|
||||
@@ -33,6 +35,7 @@ const AuditTrailMapping = {
|
||||
i18n.t("audit_trail.messages.jobchecklist", { type, inproduction, status }),
|
||||
jobconverted: (ro_number) =>
|
||||
i18n.t("audit_trail.messages.jobconverted", { ro_number }),
|
||||
jobexported: () => i18n.t("audit_trail.messages.jobexported"),
|
||||
jobfieldchange: (field, value) =>
|
||||
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
|
||||
jobimported: () => i18n.t("audit_trail.messages.jobimported"),
|
||||
@@ -51,6 +54,8 @@ const AuditTrailMapping = {
|
||||
jobstatuschange: (status) =>
|
||||
i18n.t("audit_trail.messages.jobstatuschange", { status }),
|
||||
jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"),
|
||||
jobsuspend: (status) => i18n.t("audit_trail.messages.jobsuspend", { status }),
|
||||
jobvoid: () => i18n.t("audit_trail.messages.jobvoid"),
|
||||
};
|
||||
|
||||
export default AuditTrailMapping;
|
||||
|
||||
Reference in New Issue
Block a user