diff --git a/client/src/components/bill-form/bill-form.component.jsx b/client/src/components/bill-form/bill-form.component.jsx
index 4067bef7f..f5849c6a4 100644
--- a/client/src/components/bill-form/bill-form.component.jsx
+++ b/client/src/components/bill-form/bill-form.component.jsx
@@ -53,9 +53,23 @@ export function BillFormComponent({bodyshop, disabled, form, vendorAutoCompleteO
});
};
- useEffect(() => {
- if (job) form.validateFields(["is_credit_memo"]);
- }, [job, form]);
+ const handleFederalTaxExemptSwitchToggle = (checked) => {
+ // 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(() => {
+ if (job) form.validateFields(["is_credit_memo"]);
+ }, [job, form]);
useEffect(() => {
const vendorId = form.getFieldValue("vendorid");
@@ -308,134 +322,143 @@ export function BillFormComponent({bodyshop, disabled, form, vendorAutoCompleteO
return Promise.reject(t("bills.labels.onlycmforinvoiced"));
}
- return Promise.resolve();
- },
- }),
- ]}
- >
-
-
-
-
-
- {!billEdit && (
-
-
-
- )}
-
-
-
-
-
-
-
-
-
-
-
-
- {() => {
- const values = form.getFieldsValue([
- "billlines",
- "total",
- "federal_tax_rate",
- "state_tax_rate",
- "local_tax_rate",
- ]);
- let totals;
- if (
- !!values.total &&
- !!values.billlines &&
- values.billlines.length > 0
- )
- totals = CalculateBillTotal(values);
- if (!!totals)
- return (
-
-
-
-
-
-
-
-
-
-
- {form.getFieldValue("is_credit_memo") ? (
-
- ) : null}
-
- );
- return null;
- }}
-
-
- {t("bills.labels.bill_lines")}
+ return Promise.resolve();
+ },
+ }),
+ ]}
+ >
+
+
+
+
+
+ {!billEdit && (
+
+
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+ {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
+
+
+
+ ) : null}
+
+ {() => {
+ const values = form.getFieldsValue([
+ "billlines",
+ "total",
+ "federal_tax_rate",
+ "state_tax_rate",
+ "local_tax_rate",
+ ]);
+ let totals;
+ if (
+ !!values.total &&
+ !!values.billlines &&
+ values.billlines.length > 0
+ )
+ totals = CalculateBillTotal(values);
+ if (!!totals)
+ return (
+
+
+
+
+
+
+
+
+
+
+ {form.getFieldValue("is_credit_memo") ? (
+
+ ) : null}
+
+ );
+ return null;
+ }}
+
+
+ {t("bills.labels.bill_lines")}
{Extended_Bill_Posting.treatment === "on" ? (
+
({
+ setEmailOptions: (e) => dispatch(setEmailOptions(e)),
+});
+
+export function ChatPrintButton({ conversation }) {
+ const [loading, setLoading] = useState(false);
+
+ const generateDocument = (type) => {
+ setLoading(true);
+ GenerateDocument(
+ {
+ name: TemplateList("messaging").conversation_list.key,
+ variables: { id: conversation.id },
+ },
+ {
+ subject: TemplateList("messaging").conversation_list.subject,
+ },
+ type,
+ conversation.id
+ ).catch(e => {
+ console.warn('Something went wrong generating a document.');
+ });
+ setLoading(false);
+ }
+
+ return (
+
+ generateDocument('p')}/>
+ generateDocument('e')}/>
+ {loading && }
+
+ );
+}
+export default connect(mapStateToProps, mapDispatchToProps)(ChatPrintButton);
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 bccff8507..8b96ecdb5 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/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 7282a2e90..9158707b2 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/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx b/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx
index 10f3a669b..8d3171fde 100644
--- a/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx
+++ b/client/src/components/scoreboard-timetickets-stats/scoreboard-timetickets.component.jsx
@@ -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,24 @@ 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 +371,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/components/shop-info/shop-info.rbac.component.jsx b/client/src/components/shop-info/shop-info.rbac.component.jsx
index 1c46e6dde..1ab089a25 100644
--- a/client/src/components/shop-info/shop-info.rbac.component.jsx
+++ b/client/src/components/shop-info/shop-info.rbac.component.jsx
@@ -19,684 +19,694 @@ export default connect(
mapDispatchToProps
)(ShopInfoRbacComponent);
-export function ShopInfoRbacComponent({form, bodyshop}) {
- const {t} = useTranslation();
-
-
+export function ShopInfoRbacComponent({ form, bodyshop }) {
+ const { t } = useTranslation();
const { treatments: {Simple_Inventory} } = useSplitTreatments({
attributes: {},
names: ["Simple_Inventory"],
splitKey:bodyshop && bodyshop.imexshopid,
});
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {Simple_Inventory.treatment === "on" && (
- <>
-
-
-
-
-
-
- >
- )}
-
-
- );
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {Simple_Inventory.treatment === "on" && (
+ <>
+
+
+
+
+
+
+ >
+ )}
+
+
+ );
}
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/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx
index 7a5c2ceba..38cf70c28 100644
--- a/client/src/pages/jobs-close/jobs-close.component.jsx
+++ b/client/src/pages/jobs-close/jobs-close.component.jsx
@@ -37,14 +37,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();
@@ -107,9 +115,11 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
notification["success"]({
message: t("jobs.successes.closed"),
});
-
- // const navigate = useNavigate();
- // navigate(`/manage/jobs/${job.id}`);
+ insertAuditTrail({
+ jobid: job.id,
+ operation: AuditTrailMapping.jobinvoiced(),
+ });
+ // history.push(`/manage/jobs/${job.id}`);
} else {
setLoading(false);
notification["error"]({
@@ -526,4 +536,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 bbac4cc7b..b96b555db 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.",
@@ -111,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.",
@@ -203,6 +205,7 @@
"entered_total": "Total of Entered Lines",
"enteringcreditmemo": "You are entering a credit memo. Please ensure you are also entering positive values.",
"federal_tax": "Federal Tax",
+ "federal_tax_exempt": "Federal Tax Exempt?",
"generatepartslabel": "Generate Parts Labels after Saving?",
"iouexists": "An IOU exists that is associated to this RO.",
"local_tax": "Local Tax",
@@ -447,6 +450,7 @@
"config": "Shop -> Config",
"dashboard": "Shop -> Dashboard",
"rbac": "Shop -> RBAC",
+ "reportcenter": "Shop -> Report Center",
"templates": "Shop -> Templates",
"vendors": "Shop -> Vendors"
},
@@ -2044,6 +2048,9 @@
"sentby": "Sent by {{by}} at {{time}}",
"typeamessage": "Send a message...",
"unarchive": "Unarchive"
+ },
+ "render": {
+ "conversation_list": "Conversation List"
}
},
"notes": {
@@ -2695,6 +2702,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 +2717,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..f68cf4a41 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": "",
@@ -111,6 +112,7 @@
"jobassignmentchange": "",
"jobassignmentremoved": "",
"jobchecklist": "",
+ "jobinvoiced": "",
"jobconverted": "",
"jobfieldchanged": "",
"jobimported": "",
@@ -203,6 +205,7 @@
"entered_total": "",
"enteringcreditmemo": "",
"federal_tax": "",
+ "federal_tax_exempt": "",
"generatepartslabel": "",
"iouexists": "",
"local_tax": "",
@@ -447,6 +450,7 @@
"config": "",
"dashboard": "",
"rbac": "",
+ "reportcenter": "",
"templates": "",
"vendors": ""
},
@@ -2044,6 +2048,9 @@
"sentby": "",
"typeamessage": "Enviar un mensaje...",
"unarchive": ""
+ },
+ "render": {
+ "conversation_list": ""
}
},
"notes": {
@@ -2695,6 +2702,7 @@
"efficiencyoverperiod": "",
"entries": "",
"jobs": "",
+ "jobscompletednotinvoiced": "",
"lastmonth": "",
"lastweek": "",
"monthlytarget": "",
@@ -2709,6 +2717,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..d0e44b704 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": "",
@@ -111,6 +112,7 @@
"jobassignmentchange": "",
"jobassignmentremoved": "",
"jobchecklist": "",
+ "jobinvoiced": "",
"jobconverted": "",
"jobfieldchanged": "",
"jobimported": "",
@@ -203,6 +205,7 @@
"entered_total": "",
"enteringcreditmemo": "",
"federal_tax": "",
+ "federal_tax_exempt": "",
"generatepartslabel": "",
"iouexists": "",
"local_tax": "",
@@ -447,6 +450,7 @@
"config": "",
"dashboard": "",
"rbac": "",
+ "reportcenter": "",
"templates": "",
"vendors": ""
},
@@ -2044,6 +2048,9 @@
"sentby": "",
"typeamessage": "Envoyer un message...",
"unarchive": ""
+ },
+ "render": {
+ "conversation_list": ""
}
},
"notes": {
@@ -2695,6 +2702,7 @@
"efficiencyoverperiod": "",
"entries": "",
"jobs": "",
+ "jobscompletednotinvoiced": "",
"lastmonth": "",
"lastweek": "",
"monthlytarget": "",
@@ -2709,6 +2717,7 @@
"timetickets": "",
"timeticketsemployee": "",
"todateactual": "",
+ "totalhrs": "",
"totaloverperiod": "",
"weeklyactual": "",
"weeklytarget": "",
diff --git a/client/src/utils/AuditTrailMappings.js b/client/src/utils/AuditTrailMappings.js
index afa0de1e5..d7098fa2d 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) =>
@@ -11,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) =>
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: {
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 }],