diff --git a/client/src/components/bill-form/bill-form.lines.component.jsx b/client/src/components/bill-form/bill-form.lines.component.jsx index db8afbfe6..9bb65de9c 100644 --- a/client/src/components/bill-form/bill-form.lines.component.jsx +++ b/client/src/components/bill-form/bill-form.lines.component.jsx @@ -1,11 +1,22 @@ -import {DeleteFilled, DollarCircleFilled} from "@ant-design/icons"; -import {useSplitTreatments} from "@splitsoftware/splitio-react"; -import {Button, Checkbox, Form, Input, InputNumber, Select, Space, Switch, Table, Tooltip,} from "antd"; +import { DeleteFilled, DollarCircleFilled } from "@ant-design/icons"; +import { useSplitTreatments } from "@splitsoftware/splitio-react"; +import { + Button, + Checkbox, + Form, + Input, + InputNumber, + Select, + Space, + Switch, + Table, + Tooltip, +} from "antd"; import React from "react"; -import {useTranslation} from "react-i18next"; -import {connect} from "react-redux"; -import {createStructuredSelector} from "reselect"; -import {selectBodyshop} from "../../redux/user/user.selectors"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { selectBodyshop } from "../../redux/user/user.selectors"; import CiecaSelect from "../../utils/Ciecaselect"; import BillLineSearchSelect from "../bill-line-search-select/bill-line-search-select.component"; import BilllineAddInventory from "../billline-add-inventory/billline-add-inventory.component"; @@ -21,25 +32,26 @@ const mapDispatchToProps = (dispatch) => ({ }); export function BillEnterModalLinesComponent({ - bodyshop, - disabled, - lineData, - discount, - form, - responsibilityCenters, - billEdit, - billid, - }) { - const {t} = useTranslation(); - const {setFieldsValue, getFieldsValue, getFieldValue} = form; + bodyshop, + disabled, + lineData, + discount, + form, + responsibilityCenters, + billEdit, + billid, +}) { + const { t } = useTranslation(); + const { setFieldsValue, getFieldsValue, getFieldValue } = form; - const {treatments: {Simple_Inventory, Enhanced_Payroll}} = useSplitTreatments({ + const { + treatments: { Simple_Inventory, Enhanced_Payroll }, + } = useSplitTreatments({ attributes: {}, names: ["Simple_Inventory", "Enhanced_Payroll"], splitKey: bodyshop && bodyshop.imexshopid, }); - const columns = (remove) => { return [ { @@ -76,35 +88,39 @@ export function BillEnterModalLinesComponent({ { setFieldsValue({ - billlines: getFieldsValue(["billlines"]).billlines.map( - (item, idx) => { - if (idx === index) { - return { - ...item, - line_desc: opt.line_desc, - quantity: opt.part_qty || 1, - actual_price: opt.cost, - original_actual_price: opt.cost, - cost_center: opt.part_type - ? bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid - ? opt.part_type !== "PAE" - ? opt.part_type - : null - : responsibilityCenters.defaults && - (responsibilityCenters.defaults.costs[ - opt.part_type - ] || - null) - : null, - }; - } - return item; + billlines: getFieldsValue([ + "billlines", + ]).billlines.map((item, idx) => { + if (idx === index) { + return { + ...item, + line_desc: opt.line_desc, + quantity: opt.part_qty || 1, + actual_price: opt.cost, + original_actual_price: opt.cost, + cost_center: opt.part_type + ? bodyshop.pbs_serialnumber || + bodyshop.cdk_dealerid + ? opt.part_type !== "PAE" + ? opt.part_type + : null + : responsibilityCenters.defaults && + (responsibilityCenters + .defaults.costs[ + opt.part_type + ] || + null) + : null, + }; } - ), + return item; + }), }); }} /> @@ -128,7 +144,7 @@ export function BillEnterModalLinesComponent({ ], }; }, - formInput: (record, index) => , + formInput: (record, index) => , }, { title: t("billlines.fields.quantity"), @@ -145,19 +161,24 @@ export function BillEnterModalLinesComponent({ required: true, //message: t("general.validation.required"), }, - ({getFieldValue}) => ({ + ({ getFieldValue }) => ({ validator(rule, value) { if ( value && - getFieldValue("billlines")[field.fieldKey]?.inventories - ?.length > value + getFieldValue("billlines")[ + field.fieldKey + ]?.inventories?.length > value ) { return Promise.reject( - t("bills.validation.inventoryquantity", { - number: - getFieldValue("billlines")[field.fieldKey] - ?.inventories?.length, - }) + t( + "bills.validation.inventoryquantity", + { + number: getFieldValue( + "billlines" + )[field.fieldKey] + ?.inventories?.length, + } + ) ); } return Promise.resolve(); @@ -167,7 +188,7 @@ export function BillEnterModalLinesComponent({ }; }, formInput: (record, index) => ( - + ), }, { @@ -194,67 +215,87 @@ export function BillEnterModalLinesComponent({ disabled={disabled} onBlur={(e) => { setFieldsValue({ - billlines: getFieldsValue("billlines").billlines.map( - (item, idx) => { - if (idx === index) { - return { - ...item, - actual_cost: !!item.actual_cost - ? item.actual_cost - : Math.round( - (parseFloat(e.target.value) * (1 - discount) + - Number.EPSILON) * - 100 - ) / 100, - }; - } - return item; + billlines: getFieldsValue( + "billlines" + ).billlines.map((item, idx) => { + if (idx === index) { + return { + ...item, + actual_cost: !!item.actual_cost + ? item.actual_cost + : Math.round( + (parseFloat( + e.target.value + ) * + (1 - discount) + + Number.EPSILON) * + 100 + ) / 100, + }; } - ), + return item; + }), }); }} /> ), - additional: (record, index) => ( - InstanceRenderManager({rome: - {() => { - const billLine = getFieldValue(["billlines", record.name]); - const jobLine = lineData.find( - (line) => line.id === billLine?.joblineid - ); + additional: (record, index) => + InstanceRenderManager({ + rome: ( + + {() => { + const billLine = getFieldValue([ + "billlines", + record.name, + ]); + const jobLine = lineData.find( + (line) => + line.id === billLine?.joblineid + ); - if ( - !billEdit && - billLine && - jobLine && - billLine?.actual_price !== jobLine?.act_price - ) { - return ( - - - - - {t("joblines.fields.create_ppc")} - - ); - } else { - return null; - } - }} - - //Do not need to set for promanager as it will default to Rome. - }) - - ), + if ( + !billEdit && + billLine && + jobLine && + billLine?.actual_price !== + jobLine?.act_price + ) { + return ( + + + + + {t( + "joblines.fields.create_ppc" + )} + + ); + } else { + return null; + } + }} + + ), + //Do not need to set for promanager as it will default to Rome. + }), }, { title: t("billlines.fields.actual_cost"), @@ -283,17 +324,30 @@ export function BillEnterModalLinesComponent({ addonAfter={ {() => { - const line = getFieldsValue(["billlines"]).billlines[index]; + const line = getFieldsValue(["billlines"]) + .billlines[index]; if (!!!line) return null; - let lineDiscount = 1 - line.actual_cost / line.actual_price; + let lineDiscount = + 1 - + line.actual_cost / line.actual_price; if (isNaN(lineDiscount)) lineDiscount = 0; return ( - + 0.005 - ? lineDiscount > discount + Math.abs( + lineDiscount - + discount + ) > 0.005 + ? lineDiscount > + discount ? "orange" : "red" : "green", @@ -349,40 +403,48 @@ export function BillEnterModalLinesComponent({ }; }, formInput: (record, index) => ( - {bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? CiecaSelect(true, false) : responsibilityCenters.costs.map((item) => ( - {item.name} - ))} + + {item.name} + + ))} ), }, ...(billEdit ? [] : [ - { - title: t("billlines.fields.location"), - dataIndex: "location", - editable: true, - label: t("billlines.fields.location"), - formItemProps: (field) => { - return { - key: `${field.index}location`, - name: [field.name, "location"], - }; - }, - formInput: (record, index) => ( - - ), - }, - ]), + { + title: t("billlines.fields.location"), + dataIndex: "location", + editable: true, + label: t("billlines.fields.location"), + formItemProps: (field) => { + return { + key: `${field.index}location`, + name: [field.name, "location"], + }; + }, + formInput: (record, index) => ( + + ), + }, + ]), { title: t("billlines.labels.deductedfromlbr"), dataIndex: "deductedfromlbr", @@ -394,9 +456,13 @@ export function BillEnterModalLinesComponent({ name: [field.name, "deductedfromlbr"], }; }, - formInput: (record, index) => , + formInput: (record, index) => , additional: (record, index) => ( - + {() => { const price = getFieldValue([ "billlines", @@ -411,91 +477,150 @@ export function BillEnterModalLinesComponent({ "rate", ]); - const billline = getFieldValue(["billlines", record.name]); + const billline = getFieldValue([ + "billlines", + record.name, + ]); const jobline = lineData.find( (line) => line.id === billline?.joblineid ); - const employeeTeamName = bodyshop.employee_teams.find( - (team) => team.id === jobline?.assigned_team - ); + const employeeTeamName = + bodyshop.employee_teams.find( + (team) => team.id === jobline?.assigned_team + ); - if (getFieldValue(["billlines", record.name, "deductedfromlbr"])) + if ( + getFieldValue([ + "billlines", + record.name, + "deductedfromlbr", + ]) + ) return (
- {Enhanced_Payroll.treatment === "on" ? - - {t("joblines.fields.assigned_team", { - name: employeeTeamName?.name, - })} - {`${jobline.mod_lb_hrs} units/${t( - `joblines.fields.lbr_types.${jobline.mod_lbr_ty}` - )}`} - : - null} + {Enhanced_Payroll.treatment === "on" ? ( + + {t( + "joblines.fields.assigned_team", + { + name: employeeTeamName?.name, + } + )} + {`${ + jobline.mod_lb_hrs + } units/${t( + `joblines.fields.lbr_types.${jobline.mod_lbr_ty}` + )}`} + + ) : null} {Enhanced_Payroll.treatment === "on" ? ( ) : ( - + )} {price && adjustmentRate && - `${(price / adjustmentRate).toFixed(1)} hrs`} + `${( + price / adjustmentRate + ).toFixed(1)} hrs`}
); @@ -538,23 +680,32 @@ export function BillEnterModalLinesComponent({ ), }, + ...InstanceRenderManager({ + imex: [ + { + title: t("billlines.fields.federal_tax_applicable"), + dataIndex: "applicable_taxes.federal", + editable: true, - ...InstanceRenderManager({imex: { title: t("billlines.fields.federal_tax_applicable"), - dataIndex: "applicable_taxes.federal", - editable: true, + formItemProps: (field) => { + return { + key: `${field.index}fedtax`, + valuePropName: "checked", + // initialValue: true, + name: [ + field.name, + "applicable_taxes", + "federal", + ], + }; + }, + formInput: (record, index) => ( + + ), + }, + ], + }), - formItemProps: (field) => { - return { - key: `${field.index}fedtax`, - valuePropName: "checked", - // initialValue: true, - name: [field.name, "applicable_taxes", "federal"], - }; - }, - formInput: (record, index) => ,}}) - - - , { title: t("billlines.fields.state_tax_applicable"), dataIndex: "applicable_taxes.state", @@ -567,24 +718,29 @@ export function BillEnterModalLinesComponent({ name: [field.name, "applicable_taxes", "state"], }; }, - formInput: (record, index) => , + formInput: (record, index) => , }, - ...InstanceRenderManager({imex: { - title: t("billlines.fields.local_tax_applicable"), - dataIndex: "applicable_taxes.local", - editable: true, + ...InstanceRenderManager({ + imex: [ + { + title: t("billlines.fields.local_tax_applicable"), + dataIndex: "applicable_taxes.local", + editable: true, - formItemProps: (field) => { - return { - key: `${field.index}localtax`, - valuePropName: "checked", - name: [field.name, "applicable_taxes", "local"], - }; - }, - formInput: (record, index) => , - }}) - , + formItemProps: (field) => { + return { + key: `${field.index}localtax`, + valuePropName: "checked", + name: [field.name, "applicable_taxes", "local"], + }; + }, + formInput: (record, index) => ( + + ), + }, + ], + }), { title: t("general.labels.actions"), @@ -596,12 +752,13 @@ export function BillEnterModalLinesComponent({ {Simple_Inventory.treatment === "on" && ( )} @@ -653,7 +814,7 @@ export function BillEnterModalLinesComponent({ }, ]} > - {(fields, {add, remove, move}) => { + {(fields, { add, remove, move }) => { return ( <> @@ -676,7 +837,7 @@ export function BillEnterModalLinesComponent({ onClick={() => { add(); }} - style={{width: "100%"}} + style={{ width: "100%" }} > {t("billlines.actions.newline")} @@ -694,28 +855,29 @@ export default connect( )(BillEnterModalLinesComponent); const EditableCell = ({ - dataIndex, - title, - inputType, - record, - index, - children, - formInput, - formItemProps, - additional, - wrapper, - ...restProps - }) => { + dataIndex, + title, + inputType, + record, + index, + children, + formInput, + formItemProps, + additional, + wrapper, + ...restProps +}) => { if (additional) return ( @@ -738,7 +901,7 @@ const EditableCell = ({ return (
- {(formInput && formInput(record, record.name)) || children} + {(formInput && formInput(record, record.name)) || + children} {additional && additional(record, record.name)}
@@ -726,11 +888,12 @@ const EditableCell = ({
- {(formInput && formInput(record, record.name)) || children} + {(formInput && formInput(record, record.name)) || + children} diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx index 669b3dd1f..edc9ca63a 100644 --- a/client/src/components/job-detail-lines/job-lines.component.jsx +++ b/client/src/components/job-detail-lines/job-lines.component.jsx @@ -440,18 +440,18 @@ export function JobLinesComponent({ {type: 'divider'}, {key: "LAA", label: t("joblines.fields.lbr_types.LAA")}, {key: "LAB", label: t("joblines.fields.lbr_types.LAB")}, - {key: "LAD", label: t("joblines.fields.part_types.LAD")}, - {key: "LAE", label: t("joblines.fields.part_types.LAE")}, - {key: "LAF", label: t("joblines.fields.part_types.LAF")}, - {key: "LAG", label: t("joblines.fields.part_types.LAG")}, - {key: "LAM", label: t("joblines.fields.part_types.LAM")}, - {key: "LAR", label: t("joblines.fields.part_types.LAR")}, - {key: "LAS", label: t("joblines.fields.part_types.LAS")}, - {key: "LAU", label: t("joblines.fields.part_types.LAU")}, - {key: "LA1", label: t("joblines.fields.part_types.LA1")}, - {key: "LA2", label: t("joblines.fields.part_types.LA2")}, - {key: "LA3", label: t("joblines.fields.part_types.LA3")}, - {key: "LA4", label: t("joblines.fields.part_types.LA4")}, + {key: "LAD", label: t("joblines.fields.lbr_types.LAD")}, + {key: "LAE", label: t("joblines.fields.lbr_types.LAE")}, + {key: "LAF", label: t("joblines.fields.lbr_types.LAF")}, + {key: "LAG", label: t("joblines.fields.lbr_types.LAG")}, + {key: "LAM", label: t("joblines.fields.lbr_types.LAM")}, + {key: "LAR", label: t("joblines.fields.lbr_types.LAR")}, + {key: "LAS", label: t("joblines.fields.lbr_types.LAS")}, + {key: "LAU", label: t("joblines.fields.lbr_types.LAU")}, + {key: "LA1", label: t("joblines.fields.lbr_types.LA1")}, + {key: "LA2", label: t("joblines.fields.lbr_types.LA2")}, + {key: "LA3", label: t("joblines.fields.lbr_types.LA3")}, + {key: "LA4", label: t("joblines.fields.lbr_types.LA4")}, {type: 'divider'}, {key: "clear", label: t("general.labels.clear")}, ] diff --git a/client/src/components/job-profile-data-warning/job-profile-data-warning.component.jsx b/client/src/components/job-profile-data-warning/job-profile-data-warning.component.jsx index 70213d6d8..4c82e4adb 100644 --- a/client/src/components/job-profile-data-warning/job-profile-data-warning.component.jsx +++ b/client/src/components/job-profile-data-warning/job-profile-data-warning.component.jsx @@ -1,18 +1,22 @@ -import {Alert} from "antd"; +import { Alert } from "antd"; import React from "react"; -import {useTranslation} from "react-i18next"; +import { useTranslation } from "react-i18next"; +import InstanceRenderManager from "../../utils/instanceRenderMgr"; -export default function JobProfileDataWarning({job}) { - const {t} = useTranslation(); +export default function JobProfileDataWarning({ job }) { + const { t } = useTranslation(); let missingProfileInfo = Object.keys(job.cieca_pft).length === 0 || Object.keys(job.cieca_pfl).length === 0 || Object.keys(job.materials).length === 0; - if (missingProfileInfo) + if (missingProfileInfo && InstanceRenderManager({ rome: true })) return ( - + ); return null; } diff --git a/client/src/components/shop-info/shop-info.component.jsx b/client/src/components/shop-info/shop-info.component.jsx index 031b10690..aa6793a47 100644 --- a/client/src/components/shop-info/shop-info.component.jsx +++ b/client/src/components/shop-info/shop-info.component.jsx @@ -31,7 +31,7 @@ export function ShopInfoComponent({bodyshop, form, saveLoading}) { const {treatments: {CriticalPartsScanning, EnhancedPayroll}} = useSplitTreatments({ attributes: {}, - names: ["CriticalPartsScanning"], + names: ["CriticalPartsScanning","EnhancedPayroll"], splitKey: bodyshop.imexshopid, }); diff --git a/server/accounting/qb-receivables-lines.js b/server/accounting/qb-receivables-lines.js index 2f7ca987e..6f20fafa8 100644 --- a/server/accounting/qb-receivables-lines.js +++ b/server/accounting/qb-receivables-lines.js @@ -3,7 +3,7 @@ const DineroQbFormat = require("./accounting-constants").DineroQbFormat; const Dinero = require("dinero.js"); const {DiscountNotAlreadyCounted} = require("../job/job-totals"); const logger = require("../utils/logger"); -const InstanceManager = require("../utils/instanceMgr"); +const InstanceManager = require("../utils/instanceMgr").default; exports.default = function ({ bodyshop, diff --git a/server/accounting/qbo/qbo-callback.js b/server/accounting/qbo/qbo-callback.js index 5c49d3a23..815d845ef 100644 --- a/server/accounting/qbo/qbo-callback.js +++ b/server/accounting/qbo/qbo-callback.js @@ -10,7 +10,7 @@ const OAuthClient = require("intuit-oauth"); const client = require("../../graphql-client/graphql-client").client; const queries = require("../../graphql-client/queries"); const {parse, stringify} = require("querystring"); -const InstanceManager = require("../../utils/instanceMgr"); +const InstanceManager = require("../../utils/instanceMgr").default; const oauthClient = new OAuthClient({ clientId: process.env.QBO_CLIENT_ID, diff --git a/server/email/sendemail.js b/server/email/sendemail.js index 3f9405f9d..ba6c76286 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -9,7 +9,7 @@ const axios = require("axios"); let nodemailer = require("nodemailer"); let aws = require("@aws-sdk/client-ses"); let { defaultProvider } = require("@aws-sdk/credential-provider-node"); -const InstanceManager = require("../utils/instanceMgr"); +const InstanceManager = require("../utils/instanceMgr").default; const logger = require("../utils/logger"); const client = require("../graphql-client/graphql-client").client; const queries = require("../graphql-client/queries"); diff --git a/server/job/job-totals-USA.js b/server/job/job-totals-USA.js index a870663fe..2e08d2e0a 100644 --- a/server/job/job-totals-USA.js +++ b/server/job/job-totals-USA.js @@ -26,7 +26,7 @@ exports.totalsSsu = async function (req, res) { const BearerToken = req.BearerToken; const client = req.userGraphQLClient; - logger.log("job-totals-ssu", "DEBUG", req.user.email, id, null); + logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, id, null); try { const job = await client @@ -55,7 +55,7 @@ exports.totalsSsu = async function (req, res) { res.status(200).send(); } catch (error) { - logger.log("job-totals-ssu-error", "ERROR", req.user.email, id, { + logger.log("job-totals-ssu-USA-error", "ERROR", req.user.email, id, { jobid: id, error, }); @@ -78,7 +78,7 @@ async function TotalsServerSide(req, res) { return ret; } catch (error) { - logger.log("job-totals-ssu-error", "ERROR", req.user?.email, job.id, { + logger.log("job-totals-ssu-USA-error", "ERROR", req.user?.email, job.id, { jobid: job.id, error, }); @@ -92,11 +92,11 @@ async function Totals(req, res) { const logger = req.logger; const client = req.userGraphQLClient; - logger.log("job-totals", "DEBUG", req.user.email, job.id, { + logger.log("job-totals-USA", "DEBUG", req.user.email, job.id, { jobid: job.id, }); - logger.log("job-totals-ssu", "DEBUG", req.user.email, id, null); + logger.log("job-totals-ssu-USA", "DEBUG", req.user.email, id, null); await AutoAddAtsIfRequired({job, client}); @@ -110,7 +110,7 @@ async function Totals(req, res) { res.status(200).json(ret); } catch (error) { - logger.log("job-totals-error", "ERROR", req.user.email, job.id, { + logger.log("job-totals-USA-error", "ERROR", req.user.email, job.id, { jobid: job.id, error, }); diff --git a/server/job/job.js b/server/job/job.js index ea01c6b52..7f968c0cd 100644 --- a/server/job/job.js +++ b/server/job/job.js @@ -1,4 +1,4 @@ -const RenderInstanceManager = require("../utils/instanceMgr"); +const RenderInstanceManager = require("../utils/instanceMgr").default; exports.totals = RenderInstanceManager({ imex: require("./job-totals").default, diff --git a/server/sms/receive.js b/server/sms/receive.js index c6423bc63..424e82767 100644 --- a/server/sms/receive.js +++ b/server/sms/receive.js @@ -11,7 +11,7 @@ const queries = require("../graphql-client/queries"); const {phone} = require("phone"); const {admin} = require("../firebase/firebase-handler"); const logger = require("../utils/logger"); -const InstanceRenderManager = require("../../client/src/utils/instanceRenderMgr"); +const InstanceManager = require("../utils/instanceMgr"); exports.receive = async (req, res) => { //Perform request validation @@ -106,7 +106,7 @@ exports.receive = async (req, res) => { topic: `${message.conversation.bodyshop.imexshopid}-messaging`, notification: { title: - InstanceRenderManager({ + InstanceManager({ imex:`ImEX Online Message - ${data.phone_num}` , rome: `Rome Online Message - ${data.phone_num}`, promanager: `Pro Manager Message - ${data.phone_num}` diff --git a/server/utils/instanceMgr.js b/server/utils/instanceMgr.js index 7465f03d2..3ac00e83c 100644 --- a/server/utils/instanceMgr.js +++ b/server/utils/instanceMgr.js @@ -8,7 +8,7 @@ * @property { string | object | function } imex Return this prop if Rome. */ -export default function InstanceManager({ rome, promanager, imex }) { +function InstanceManager({ rome, promanager, imex }) { let propToReturn = null; switch (process.env.INSTANCE) { @@ -32,3 +32,5 @@ export default function InstanceManager({ rome, promanager, imex }) { // } return propToReturn; } + +exports.default = InstanceManager