Compare commits
34 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff33b924b2 | ||
|
|
84bb25985b | ||
|
|
e38a58550f | ||
|
|
25ef4c6228 | ||
|
|
277fbeebc8 | ||
|
|
399df78957 | ||
|
|
294325343b | ||
|
|
ed17eec948 | ||
|
|
f87c95079c | ||
|
|
327149ffc9 | ||
|
|
f81b21b933 | ||
|
|
a559b56983 | ||
|
|
6a9030b653 | ||
|
|
fc7da187f4 | ||
|
|
f593f83ec1 | ||
|
|
5752f123ac | ||
|
|
6396d68584 | ||
|
|
bfd29f25dd | ||
|
|
e75e35e4ee | ||
|
|
d7ddbf7e8d | ||
|
|
1b0198af63 | ||
|
|
ace16ba873 | ||
|
|
f57a4bd948 | ||
|
|
fef4393f9c | ||
|
|
47adb6d40a | ||
|
|
4940b10910 | ||
|
|
9c8e241ef7 | ||
|
|
c3d6b98c89 | ||
|
|
4b49654083 | ||
|
|
78223078f4 | ||
|
|
ca4b78d44c | ||
|
|
d7bfc789e2 | ||
|
|
b54d0ed62a | ||
|
|
8386443cb0 |
@@ -4,7 +4,6 @@ import { useTranslation } from "react-i18next";
|
|||||||
import InstanceRenderMgr from "../../utils/instanceRenderMgr";
|
import InstanceRenderMgr from "../../utils/instanceRenderMgr";
|
||||||
|
|
||||||
//To be used as a form element only.
|
//To be used as a form element only.
|
||||||
const { Option } = Select;
|
|
||||||
const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, ref) => {
|
const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Card, Form, Input, notification, Switch } from "antd";
|
import { Button, Card, Form, Input, notification, Switch } from "antd";
|
||||||
import dayjs from "../../../../utils/day";
|
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -14,6 +13,7 @@ import { UPDATE_OWNER } from "../../../../graphql/owners.queries";
|
|||||||
import { insertAuditTrail } from "../../../../redux/application/application.actions";
|
import { insertAuditTrail } from "../../../../redux/application/application.actions";
|
||||||
import { selectBodyshop, selectCurrentUser } from "../../../../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../../../../redux/user/user.selectors";
|
||||||
import AuditTrailMapping from "../../../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../../../utils/AuditTrailMappings";
|
||||||
|
import dayjs from "../../../../utils/day";
|
||||||
import ConfigFormComponents from "../../../config-form-components/config-form-components.component";
|
import ConfigFormComponents from "../../../config-form-components/config-form-components.component";
|
||||||
import DateTimePicker from "../../../form-date-time-picker/form-date-time-picker.component";
|
import DateTimePicker from "../../../form-date-time-picker/form-date-time-picker.component";
|
||||||
|
|
||||||
@@ -275,7 +275,19 @@ export function JobChecklistForm({ insertAuditTrail, formItems, bodyshop, curren
|
|||||||
>
|
>
|
||||||
<DateTimePicker disabled={readOnly} />
|
<DateTimePicker disabled={readOnly} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="actual_delivery" label={t("jobs.fields.actual_delivery")} disabled={readOnly}>
|
<Form.Item
|
||||||
|
name="actual_delivery"
|
||||||
|
label={t("jobs.fields.actual_delivery")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: bodyshop.deliverchecklist.actual_delivery
|
||||||
|
? bodyshop.deliverchecklist.actual_delivery
|
||||||
|
: false
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
disabled={readOnly}
|
||||||
|
>
|
||||||
<DateTimePicker disabled={readOnly} />
|
<DateTimePicker disabled={readOnly} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button, Space, notification } from "antd";
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { DELETE_DELIVERY_CHECKLIST, DELETE_INTAKE_CHECKLIST } from "../../graphql/jobs.queries";
|
import { DELETE_DELIVERY_CHECKLIST, DELETE_INTAKE_CHECKLIST } from "../../graphql/jobs.queries";
|
||||||
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
|
||||||
export default function JobAdminDeleteIntake({ job }) {
|
export default function JobAdminDeleteIntake({ job }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -47,16 +48,22 @@ export default function JobAdminDeleteIntake({ job }) {
|
|||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
const InstanceRender = InstanceRenderManager({
|
||||||
|
imex: true,
|
||||||
|
rome: "USE_IMEX",
|
||||||
|
promanager: false
|
||||||
|
});
|
||||||
|
|
||||||
|
return InstanceRender ? (
|
||||||
<>
|
<>
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
<Button loading={loading} onClick={handleDelete} disabled={!job.intakechecklist}>
|
<Button loading={loading} onClick={handleDelete} disabled={!job.intakechecklist}>
|
||||||
{t("jobs.labels.deleteintake")}
|
{t("jobs.labels.deleteintake")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button loading={loading} onClick={handleDeleteDelivery} disabled={!job.deliverychecklist}>
|
<Button loading={loading} onClick={handleDeleteDelivery} disabled={!job.deliverchecklist}>
|
||||||
{t("jobs.labels.deletedelivery")}
|
{t("jobs.labels.deletedelivery")}
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</>
|
</>
|
||||||
);
|
) : null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -319,6 +319,18 @@ export default function ShopInfoIntakeChecklistComponent({ form }) {
|
|||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={["deliverchecklist", "actual_delivery"]}
|
||||||
|
label={t("bodyshop.fields.deliver.require_actual_delivery_date")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
</SelectorDiv>
|
</SelectorDiv>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Button, Result, Space, Steps } from "antd";
|
|
||||||
import { PageHeader } from "@ant-design/pro-layout";
|
import { PageHeader } from "@ant-design/pro-layout";
|
||||||
|
import { Button, Result, Space, Steps } from "antd";
|
||||||
|
|
||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -9,7 +9,6 @@ import JobsCreateJobsInfo from "../../components/jobs-create-jobs-info/jobs-crea
|
|||||||
import JobsCreateOwnerInfoContainer from "../../components/jobs-create-owner-info/jobs-create-owner-info.container";
|
import JobsCreateOwnerInfoContainer from "../../components/jobs-create-owner-info/jobs-create-owner-info.container";
|
||||||
import JobsCreateVehicleInfoContainer from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container";
|
import JobsCreateVehicleInfoContainer from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container";
|
||||||
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
|
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
|
||||||
import FormsFieldChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
|
|
||||||
|
|
||||||
export default function JobsCreateComponent({ form }) {
|
export default function JobsCreateComponent({ form }) {
|
||||||
const [pageIndex, setPageIndex] = useState(0);
|
const [pageIndex, setPageIndex] = useState(0);
|
||||||
@@ -41,10 +40,11 @@ export default function JobsCreateComponent({ form }) {
|
|||||||
|
|
||||||
const next = () => {
|
const next = () => {
|
||||||
setPageIndex(pageIndex + 1);
|
setPageIndex(pageIndex + 1);
|
||||||
console.log("NExt");
|
console.log("Next");
|
||||||
};
|
};
|
||||||
const prev = () => {
|
const prev = () => {
|
||||||
setPageIndex(pageIndex - 1);
|
setPageIndex(pageIndex - 1);
|
||||||
|
console.log("Previous");
|
||||||
};
|
};
|
||||||
const { Step } = Steps;
|
const { Step } = Steps;
|
||||||
|
|
||||||
@@ -53,26 +53,26 @@ export default function JobsCreateComponent({ form }) {
|
|||||||
<PageHeader
|
<PageHeader
|
||||||
extra={
|
extra={
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
{pageIndex > 0 && <Button onClick={() => prev()}>Previous</Button>}
|
{pageIndex > 0 && <Button onClick={() => prev()}>{t("general.actions.previous")}</Button>}
|
||||||
{pageIndex < steps.length - 1 && (
|
{pageIndex < steps.length - 1 && (
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
next();
|
next();
|
||||||
// form
|
form
|
||||||
// .validateFields()
|
.validateFields()
|
||||||
// .then((r) => {
|
.then((r) => {
|
||||||
// if (steps[pageIndex].validation) {
|
if (steps[pageIndex].validation) {
|
||||||
// setErrorMessage(null);
|
setErrorMessage(null);
|
||||||
// next();
|
next();
|
||||||
// } else {
|
} else {
|
||||||
// setErrorMessage(steps[pageIndex].error);
|
setErrorMessage(steps[pageIndex].error);
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
// .catch((error) => console.log("error", error));
|
.catch((error) => console.log("error", error));
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Next
|
{t("general.actions.next")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{pageIndex === steps.length - 1 && (
|
{pageIndex === steps.length - 1 && (
|
||||||
@@ -104,17 +104,17 @@ export default function JobsCreateComponent({ form }) {
|
|||||||
}}
|
}}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setPageIndex(idx);
|
setPageIndex(idx);
|
||||||
// form
|
form
|
||||||
// .validateFields()
|
.validateFields()
|
||||||
// .then((r) => {
|
.then((r) => {
|
||||||
// if (steps[pageIndex].validation) {
|
if (steps[pageIndex].validation) {
|
||||||
// setErrorMessage(null);
|
setErrorMessage(null);
|
||||||
// setPageIndex(idx);
|
setPageIndex(idx);
|
||||||
// } else {
|
} else {
|
||||||
// setErrorMessage(steps[pageIndex].error);
|
setErrorMessage(steps[pageIndex].error);
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
// .catch((error) => console.log("error", error));
|
.catch((error) => console.log("error", error));
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
@@ -144,7 +144,7 @@ export default function JobsCreateComponent({ form }) {
|
|||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<ProgressButtons top />
|
<ProgressButtons top />
|
||||||
<FormsFieldChanged form={form} />
|
|
||||||
{errorMessage ? (
|
{errorMessage ? (
|
||||||
<div>
|
<div>
|
||||||
<AlertComponent message={errorMessage} type="error" />
|
<AlertComponent message={errorMessage} type="error" />
|
||||||
|
|||||||
@@ -295,7 +295,8 @@
|
|||||||
"dailypainttarget": "Scoreboard - Daily Paint Target",
|
"dailypainttarget": "Scoreboard - Daily Paint Target",
|
||||||
"default_adjustment_rate": "Default Labor Deduction Adjustment Rate",
|
"default_adjustment_rate": "Default Labor Deduction Adjustment Rate",
|
||||||
"deliver": {
|
"deliver": {
|
||||||
"templates": "Delivery Templates"
|
"templates": "Delivery Templates",
|
||||||
|
"require_actual_delivery_date": "Require Actual Delivery"
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
"apcontrol": "AP Control Number",
|
"apcontrol": "AP Control Number",
|
||||||
@@ -1139,6 +1140,8 @@
|
|||||||
"download": "Download",
|
"download": "Download",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
|
"next": "Next",
|
||||||
|
"previous": "Previous",
|
||||||
"print": "Print",
|
"print": "Print",
|
||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
@@ -2933,6 +2936,8 @@
|
|||||||
"purchases_by_cost_center_summary": "Purchases by Cost Center (Summary)",
|
"purchases_by_cost_center_summary": "Purchases by Cost Center (Summary)",
|
||||||
"purchases_by_date_range_detail": "Purchases by Date - Detail",
|
"purchases_by_date_range_detail": "Purchases by Date - Detail",
|
||||||
"purchases_by_date_range_summary": "Purchases by Date - Summary",
|
"purchases_by_date_range_summary": "Purchases by Date - Summary",
|
||||||
|
"purchases_by_ro_detail_date": "Purchases by RO - Detail",
|
||||||
|
"purchases_by_ro_summary_date": "Purchases by RO - Summary",
|
||||||
"purchases_by_vendor_detailed_date_range": "Purchases By Vendor - Detailed",
|
"purchases_by_vendor_detailed_date_range": "Purchases By Vendor - Detailed",
|
||||||
"purchases_by_vendor_summary_date_range": "Purchases by Vendor - Summary",
|
"purchases_by_vendor_summary_date_range": "Purchases by Vendor - Summary",
|
||||||
"purchases_grouped_by_vendor_detailed": "Purchases Grouped by Vendor - Detailed",
|
"purchases_grouped_by_vendor_detailed": "Purchases Grouped by Vendor - Detailed",
|
||||||
|
|||||||
@@ -295,7 +295,8 @@
|
|||||||
"dailypainttarget": "",
|
"dailypainttarget": "",
|
||||||
"default_adjustment_rate": "",
|
"default_adjustment_rate": "",
|
||||||
"deliver": {
|
"deliver": {
|
||||||
"templates": ""
|
"templates": "",
|
||||||
|
"require_actual_delivery_date": ""
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
"apcontrol": "",
|
"apcontrol": "",
|
||||||
@@ -1139,6 +1140,8 @@
|
|||||||
"download": "",
|
"download": "",
|
||||||
"edit": "Editar",
|
"edit": "Editar",
|
||||||
"login": "",
|
"login": "",
|
||||||
|
"next": "",
|
||||||
|
"previous": "",
|
||||||
"print": "",
|
"print": "",
|
||||||
"refresh": "",
|
"refresh": "",
|
||||||
"remove": "",
|
"remove": "",
|
||||||
@@ -2933,6 +2936,8 @@
|
|||||||
"purchases_by_cost_center_summary": "",
|
"purchases_by_cost_center_summary": "",
|
||||||
"purchases_by_date_range_detail": "",
|
"purchases_by_date_range_detail": "",
|
||||||
"purchases_by_date_range_summary": "",
|
"purchases_by_date_range_summary": "",
|
||||||
|
"purchases_by_ro_detail_date": "",
|
||||||
|
"purchases_by_ro_summary_date": "",
|
||||||
"purchases_by_vendor_detailed_date_range": "",
|
"purchases_by_vendor_detailed_date_range": "",
|
||||||
"purchases_by_vendor_summary_date_range": "",
|
"purchases_by_vendor_summary_date_range": "",
|
||||||
"purchases_grouped_by_vendor_detailed": "",
|
"purchases_grouped_by_vendor_detailed": "",
|
||||||
|
|||||||
@@ -295,7 +295,8 @@
|
|||||||
"dailypainttarget": "",
|
"dailypainttarget": "",
|
||||||
"default_adjustment_rate": "",
|
"default_adjustment_rate": "",
|
||||||
"deliver": {
|
"deliver": {
|
||||||
"templates": ""
|
"templates": "",
|
||||||
|
"require_actual_delivery_date": ""
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
"apcontrol": "",
|
"apcontrol": "",
|
||||||
@@ -1139,6 +1140,8 @@
|
|||||||
"download": "",
|
"download": "",
|
||||||
"edit": "modifier",
|
"edit": "modifier",
|
||||||
"login": "",
|
"login": "",
|
||||||
|
"next": "",
|
||||||
|
"previous": "",
|
||||||
"print": "",
|
"print": "",
|
||||||
"refresh": "",
|
"refresh": "",
|
||||||
"remove": "",
|
"remove": "",
|
||||||
@@ -2933,6 +2936,8 @@
|
|||||||
"purchases_by_cost_center_summary": "",
|
"purchases_by_cost_center_summary": "",
|
||||||
"purchases_by_date_range_detail": "",
|
"purchases_by_date_range_detail": "",
|
||||||
"purchases_by_date_range_summary": "",
|
"purchases_by_date_range_summary": "",
|
||||||
|
"purchases_by_ro_detail_date": "",
|
||||||
|
"purchases_by_ro_summary_date": "",
|
||||||
"purchases_by_vendor_detailed_date_range": "",
|
"purchases_by_vendor_detailed_date_range": "",
|
||||||
"purchases_by_vendor_summary_date_range": "",
|
"purchases_by_vendor_summary_date_range": "",
|
||||||
"purchases_grouped_by_vendor_detailed": "",
|
"purchases_grouped_by_vendor_detailed": "",
|
||||||
|
|||||||
@@ -1081,6 +1081,32 @@ export const TemplateList = (type, context) => {
|
|||||||
},
|
},
|
||||||
group: "purchases"
|
group: "purchases"
|
||||||
},
|
},
|
||||||
|
purchases_by_ro_detail_date: {
|
||||||
|
title: i18n.t("reportcenter.templates.purchases_by_ro_detail_date"),
|
||||||
|
description: "",
|
||||||
|
subject: i18n.t("reportcenter.templates.purchases_by_ro_detail_date"),
|
||||||
|
key: "purchases_by_ro_detail_date",
|
||||||
|
//idtype: "vendor",
|
||||||
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||||
|
field: i18n.t("jobs.fields.date_invoiced")
|
||||||
|
},
|
||||||
|
group: "purchases"
|
||||||
|
},
|
||||||
|
purchases_by_ro_summary_date: {
|
||||||
|
title: i18n.t("reportcenter.templates.purchases_by_ro_summary_date"),
|
||||||
|
description: "",
|
||||||
|
subject: i18n.t("reportcenter.templates.purchases_by_ro_summary_date"),
|
||||||
|
key: "purchases_by_ro_summary_date",
|
||||||
|
//idtype: "vendor",
|
||||||
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||||
|
field: i18n.t("jobs.fields.date_invoiced")
|
||||||
|
},
|
||||||
|
group: "purchases"
|
||||||
|
},
|
||||||
job_costing_ro_date_summary: {
|
job_costing_ro_date_summary: {
|
||||||
title: i18n.t("reportcenter.templates.job_costing_ro_date_summary"),
|
title: i18n.t("reportcenter.templates.job_costing_ro_date_summary"),
|
||||||
description: "",
|
description: "",
|
||||||
|
|||||||
@@ -891,7 +891,11 @@ function checkStateTax(jobline, jobs_by_pk) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isAdditionalCost =
|
const isAdditionalCost =
|
||||||
(jobline.lbr_op === "OP13" || (jobline.db_ref && jobline.db_ref.startsWith("9360"))) && !isPaintOrShopMat;
|
(jobline.lbr_op === "OP13" ||
|
||||||
|
(jobline.lbr_op === "OP14" && jobline.act_price > 0 && jobline.mod_lb_hrs === 0) ||
|
||||||
|
(jobline.db_ref && jobline.db_ref.startsWith("9360")) ||
|
||||||
|
(jobline.db_ref && jobline.db_ref.startsWith("90051"))) &&
|
||||||
|
!isPaintOrShopMat;
|
||||||
|
|
||||||
if (!jobline.part_type && isAdditionalCost) {
|
if (!jobline.part_type && isAdditionalCost) {
|
||||||
if (jobs_by_pk.tax_lbr_rt === 0) {
|
if (jobs_by_pk.tax_lbr_rt === 0) {
|
||||||
@@ -901,18 +905,12 @@ function checkStateTax(jobline, jobs_by_pk) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
jobline.db_ref === "900511" ||
|
|
||||||
jobline.db_ref === "900510" ||
|
|
||||||
(jobline.mod_lb_hrs === 0 && jobline.act_price > 0 && jobline.lbr_op === "OP14")
|
|
||||||
)
|
|
||||||
return true; //Extending IO-1375 as a part of IO-2023
|
|
||||||
|
|
||||||
if (jobline.tax_part === false) {
|
if (jobline.tax_part === false) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (jobline.part_type) {
|
if (jobline.part_type) {
|
||||||
if (
|
if (
|
||||||
|
!jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`] ||
|
||||||
jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_in === false ||
|
jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_in === false ||
|
||||||
jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_rt === 0
|
jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_rt === 0
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -16,403 +16,402 @@ const { DiscountNotAlreadyCounted } = InstanceManager({
|
|||||||
promanager: "USE_ROME"
|
promanager: "USE_ROME"
|
||||||
});
|
});
|
||||||
|
|
||||||
|
exports.defaultRoute = async function (req, res) {
|
||||||
|
try {
|
||||||
|
CdkBase.createLogEvent(req, "DEBUG", `Received request to calculate allocations for ${req.body.jobid}`);
|
||||||
|
const jobData = await QueryJobData(req, req.BearerToken, req.body.jobid);
|
||||||
|
return res.status(200).json({ data: calculateAllocations(req, jobData) });
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
CdkBase.createLogEvent(req, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`);
|
||||||
|
res.status(500).json({ error: `Error encountered in CdkCalculateAllocations. ${error}` });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
exports.default = async function (socket, jobid) {
|
exports.default = async function (socket, jobid) {
|
||||||
try {
|
try {
|
||||||
CdkBase.createLogEvent(socket, "DEBUG", `Received request to calculate allocations for ${jobid}`);
|
const jobData = await QueryJobData(socket, "Bearer " + socket.handshake.auth.token, jobid);
|
||||||
const job = await QueryJobData(socket, jobid);
|
return calculateAllocations(socket, jobData);
|
||||||
const { bodyshop } = job;
|
|
||||||
|
|
||||||
const taxAllocations = InstanceManager({
|
|
||||||
executeFunction: true,
|
|
||||||
deubg: true,
|
|
||||||
args: [],
|
|
||||||
imex: () => ({
|
|
||||||
local: {
|
|
||||||
center: bodyshop.md_responsibility_centers.taxes.local.name,
|
|
||||||
sale: Dinero(job.job_totals.totals.local_tax),
|
|
||||||
cost: Dinero(),
|
|
||||||
profitCenter: bodyshop.md_responsibility_centers.taxes.local,
|
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes.local
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
center: bodyshop.md_responsibility_centers.taxes.state.name,
|
|
||||||
sale: Dinero(job.job_totals.totals.state_tax),
|
|
||||||
cost: Dinero(),
|
|
||||||
profitCenter: bodyshop.md_responsibility_centers.taxes.state,
|
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes.state
|
|
||||||
},
|
|
||||||
federal: {
|
|
||||||
center: bodyshop.md_responsibility_centers.taxes.federal.name,
|
|
||||||
sale: Dinero(job.job_totals.totals.federal_tax),
|
|
||||||
cost: Dinero(),
|
|
||||||
profitCenter: bodyshop.md_responsibility_centers.taxes.federal,
|
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes.federal
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
rome: () => ({
|
|
||||||
tax_ty1: {
|
|
||||||
center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name,
|
|
||||||
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]),
|
|
||||||
cost: Dinero(),
|
|
||||||
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`],
|
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`]
|
|
||||||
},
|
|
||||||
tax_ty2: {
|
|
||||||
center: bodyshop.md_responsibility_centers.taxes[`tax_ty2`].name,
|
|
||||||
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty2Tax`]),
|
|
||||||
cost: Dinero(),
|
|
||||||
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`],
|
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`]
|
|
||||||
},
|
|
||||||
tax_ty3: {
|
|
||||||
center: bodyshop.md_responsibility_centers.taxes[`tax_ty3`].name,
|
|
||||||
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty3Tax`]),
|
|
||||||
cost: Dinero(),
|
|
||||||
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`],
|
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`]
|
|
||||||
},
|
|
||||||
tax_ty4: {
|
|
||||||
center: bodyshop.md_responsibility_centers.taxes[`tax_ty4`].name,
|
|
||||||
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty4Tax`]),
|
|
||||||
cost: Dinero(),
|
|
||||||
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`],
|
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`]
|
|
||||||
},
|
|
||||||
tax_ty5: {
|
|
||||||
center: bodyshop.md_responsibility_centers.taxes[`tax_ty5`].name,
|
|
||||||
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty5Tax`]),
|
|
||||||
cost: Dinero(),
|
|
||||||
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`],
|
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
//Determine if there are MAPA and MASH lines already on the estimate.
|
|
||||||
//If there are, don't do anything extra (mitchell estimate)
|
|
||||||
//Otherwise, calculate them and add them to the default MAPA and MASH centers.
|
|
||||||
let hasMapaLine = false;
|
|
||||||
let hasMashLine = false;
|
|
||||||
|
|
||||||
const profitCenterHash = job.joblines.reduce((acc, val) => {
|
|
||||||
//Check the Parts Assignment
|
|
||||||
if (val.db_ref === "936008") {
|
|
||||||
//If either of these DB REFs change, they also need to change in job-totals/job-costing calculations.
|
|
||||||
hasMapaLine = true;
|
|
||||||
}
|
|
||||||
if (val.db_ref === "936007") {
|
|
||||||
hasMashLine = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val.profitcenter_part) {
|
|
||||||
if (!acc[val.profitcenter_part]) acc[val.profitcenter_part] = Dinero();
|
|
||||||
|
|
||||||
let DineroAmount = Dinero({
|
|
||||||
amount: Math.round(val.act_price * 100)
|
|
||||||
}).multiply(val.part_qty || 1);
|
|
||||||
|
|
||||||
DineroAmount = DineroAmount.add(
|
|
||||||
((val.prt_dsmk_m && val.prt_dsmk_m !== 0) || (val.prt_dsmk_p && val.prt_dsmk_p !== 0)) &&
|
|
||||||
DiscountNotAlreadyCounted(val, job.joblines)
|
|
||||||
? val.prt_dsmk_m
|
|
||||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
|
||||||
: Dinero({
|
|
||||||
amount: Math.round(val.act_price * 100)
|
|
||||||
})
|
|
||||||
.multiply(val.part_qty || 0)
|
|
||||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
|
||||||
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
|
||||||
: Dinero()
|
|
||||||
);
|
|
||||||
|
|
||||||
acc[val.profitcenter_part] = acc[val.profitcenter_part].add(DineroAmount);
|
|
||||||
}
|
|
||||||
if (val.profitcenter_labor && val.mod_lbr_ty) {
|
|
||||||
//Check the Labor Assignment.
|
|
||||||
|
|
||||||
if (!acc[val.profitcenter_labor]) acc[val.profitcenter_labor] = Dinero();
|
|
||||||
|
|
||||||
acc[val.profitcenter_labor] = acc[val.profitcenter_labor].add(
|
|
||||||
Dinero({
|
|
||||||
amount: Math.round(job[`rate_${val.mod_lbr_ty.toLowerCase()}`] * 100)
|
|
||||||
}).multiply(val.mod_lb_hrs)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const selectedDmsAllocationConfig = bodyshop.md_responsibility_centers.dms_defaults.find(
|
|
||||||
(d) => d.name === job.dms_allocation
|
|
||||||
);
|
|
||||||
CdkBase.createLogEvent(
|
|
||||||
socket,
|
|
||||||
"DEBUG",
|
|
||||||
`Using DMS Allocation ${selectedDmsAllocationConfig && selectedDmsAllocationConfig.name} for cost export.`
|
|
||||||
);
|
|
||||||
|
|
||||||
let costCenterHash = {};
|
|
||||||
//Check whether to skip this if PBS and using AP module.
|
|
||||||
const disablebillwip = !!bodyshop?.pbs_configuration?.disablebillwip;
|
|
||||||
|
|
||||||
if (!disablebillwip) {
|
|
||||||
costCenterHash = job.bills.reduce((bill_acc, bill_val) => {
|
|
||||||
bill_val.billlines.map((line_val) => {
|
|
||||||
if (!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]])
|
|
||||||
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = Dinero();
|
|
||||||
|
|
||||||
let lineDinero = Dinero({
|
|
||||||
amount: Math.round((line_val.actual_cost || 0) * 100)
|
|
||||||
})
|
|
||||||
.multiply(line_val.quantity)
|
|
||||||
.multiply(bill_val.is_credit_memo ? -1 : 1);
|
|
||||||
|
|
||||||
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] =
|
|
||||||
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]].add(lineDinero);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
return bill_acc;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
job.timetickets.forEach((ticket) => {
|
|
||||||
//Get the total amount of the ticket.
|
|
||||||
let TicketTotal = Dinero({
|
|
||||||
amount: Math.round(
|
|
||||||
ticket.rate *
|
|
||||||
(ticket.employee && ticket.employee.flat_rate ? ticket.productivehrs || 0 : ticket.actualhrs || 0) *
|
|
||||||
100
|
|
||||||
)
|
|
||||||
});
|
|
||||||
//Add it to the right cost center.
|
|
||||||
if (!costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]])
|
|
||||||
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] = Dinero();
|
|
||||||
|
|
||||||
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] =
|
|
||||||
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]].add(TicketTotal);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!hasMapaLine && job.job_totals.rates.mapa.total.amount > 0) {
|
|
||||||
// console.log("Adding MAPA Line Manually.");
|
|
||||||
const mapaAccountName = selectedDmsAllocationConfig.profits.MAPA;
|
|
||||||
|
|
||||||
const mapaAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mapaAccountName);
|
|
||||||
|
|
||||||
if (mapaAccount) {
|
|
||||||
if (!profitCenterHash[mapaAccountName]) profitCenterHash[mapaAccountName] = Dinero();
|
|
||||||
|
|
||||||
profitCenterHash[mapaAccountName] = profitCenterHash[mapaAccountName].add(
|
|
||||||
Dinero(job.job_totals.rates.mapa.total)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
//console.log("NO MAPA ACCOUNT FOUND!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasMashLine && job.job_totals.rates.mash.total.amount > 0) {
|
|
||||||
// console.log("Adding MASH Line Manually.");
|
|
||||||
|
|
||||||
const mashAccountName = selectedDmsAllocationConfig.profits.MASH;
|
|
||||||
|
|
||||||
const mashAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mashAccountName);
|
|
||||||
|
|
||||||
if (mashAccount) {
|
|
||||||
if (!profitCenterHash[mashAccountName]) profitCenterHash[mashAccountName] = Dinero();
|
|
||||||
|
|
||||||
profitCenterHash[mashAccountName] = profitCenterHash[mashAccountName].add(
|
|
||||||
Dinero(job.job_totals.rates.mash.total)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// console.log("NO MASH ACCOUNT FOUND!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log(
|
|
||||||
Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting),
|
|
||||||
typeof Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting)
|
|
||||||
);
|
|
||||||
if (!!bodyshop?.cdk_configuration?.sendmaterialscosting) {
|
|
||||||
//Manually send the percentage of the costing.
|
|
||||||
|
|
||||||
//Paint Mat
|
|
||||||
const mapaAccountName = selectedDmsAllocationConfig.costs.MAPA;
|
|
||||||
const mapaAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mapaAccountName);
|
|
||||||
if (mapaAccount) {
|
|
||||||
if (!costCenterHash[mapaAccountName])
|
|
||||||
costCenterHash[mapaAccountName] = Dinero();
|
|
||||||
if (job.bodyshop.use_paint_scale_data === true) {
|
|
||||||
if (job.mixdata.length > 0) {
|
|
||||||
costCenterHash[mapaAccountName] = costCenterHash[
|
|
||||||
mapaAccountName
|
|
||||||
].add(
|
|
||||||
Dinero({
|
|
||||||
amount: Math.round(
|
|
||||||
((job.mixdata[0] && job.mixdata[0].totalliquidcost) || 0) *
|
|
||||||
100
|
|
||||||
),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
costCenterHash[mapaAccountName] = costCenterHash[
|
|
||||||
mapaAccountName
|
|
||||||
].add(
|
|
||||||
Dinero(job.job_totals.rates.mapa.total).percentage(
|
|
||||||
bodyshop?.cdk_configuration?.sendmaterialscosting
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add(
|
|
||||||
Dinero(job.job_totals.rates.mapa.total).percentage(
|
|
||||||
bodyshop?.cdk_configuration?.sendmaterialscosting
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//console.log("NO MAPA ACCOUNT FOUND!!");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Shop Mat
|
|
||||||
const mashAccountName = selectedDmsAllocationConfig.costs.MASH;
|
|
||||||
const mashAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mashAccountName);
|
|
||||||
if (mashAccount) {
|
|
||||||
if (!costCenterHash[mashAccountName]) costCenterHash[mashAccountName] = Dinero();
|
|
||||||
costCenterHash[mashAccountName] = costCenterHash[mashAccountName].add(
|
|
||||||
Dinero(job.job_totals.rates.mash.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// console.log("NO MASH ACCOUNT FOUND!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const { ca_bc_pvrt } = job;
|
|
||||||
if (ca_bc_pvrt) {
|
|
||||||
// const pvrtAccount = bodyshop.md_responsibility_centers.profits.find(
|
|
||||||
// (c) => c.name === mashAccountName
|
|
||||||
// );
|
|
||||||
|
|
||||||
taxAllocations.state.sale = taxAllocations.state.sale.add(
|
|
||||||
Dinero({ amount: Math.round((ca_bc_pvrt || 0) * 100) })
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (job.towing_payable && job.towing_payable !== 0) {
|
|
||||||
const towAccountName = selectedDmsAllocationConfig.profits.TOW;
|
|
||||||
|
|
||||||
const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === towAccountName);
|
|
||||||
|
|
||||||
if (towAccount) {
|
|
||||||
if (!profitCenterHash[towAccountName]) profitCenterHash[towAccountName] = Dinero();
|
|
||||||
|
|
||||||
profitCenterHash[towAccountName] = profitCenterHash[towAccountName].add(
|
|
||||||
Dinero({
|
|
||||||
amount: Math.round((job.towing_payable || 0) * 100)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// console.log("NO MASH ACCOUNT FOUND!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (job.storage_payable && job.storage_payable !== 0) {
|
|
||||||
const storageAccountName = selectedDmsAllocationConfig.profits.TOW;
|
|
||||||
|
|
||||||
const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === storageAccountName);
|
|
||||||
|
|
||||||
if (towAccount) {
|
|
||||||
if (!profitCenterHash[storageAccountName]) profitCenterHash[storageAccountName] = Dinero();
|
|
||||||
|
|
||||||
profitCenterHash[storageAccountName] = profitCenterHash[storageAccountName].add(
|
|
||||||
Dinero({
|
|
||||||
amount: Math.round((job.storage_payable || 0) * 100)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// console.log("NO MASH ACCOUNT FOUND!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (job.adjustment_bottom_line && job.adjustment_bottom_line !== 0) {
|
|
||||||
const otherAccountName = selectedDmsAllocationConfig.profits.PAO;
|
|
||||||
|
|
||||||
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === otherAccountName);
|
|
||||||
|
|
||||||
if (otherAccount) {
|
|
||||||
if (!profitCenterHash[otherAccountName]) profitCenterHash[otherAccountName] = Dinero();
|
|
||||||
|
|
||||||
profitCenterHash[otherAccountName] = profitCenterHash[otherAccountName].add(
|
|
||||||
Dinero({
|
|
||||||
amount: Math.round((job.adjustment_bottom_line || 0) * 100)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// console.log("NO MASH ACCOUNT FOUND!!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (InstanceManager({ rome: true })) {
|
|
||||||
//profile level adjustments
|
|
||||||
Object.keys(job.job_totals.parts.adjustments).forEach((key) => {
|
|
||||||
const accountName = selectedDmsAllocationConfig.profits[key];
|
|
||||||
|
|
||||||
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
|
|
||||||
|
|
||||||
if (otherAccount) {
|
|
||||||
if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero();
|
|
||||||
|
|
||||||
profitCenterHash[accountName] = profitCenterHash[accountName].add(
|
|
||||||
Dinero(job.job_totals.parts.adjustments[key])
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
CdkBase.createLogEvent(
|
|
||||||
socket,
|
|
||||||
"ERROR",
|
|
||||||
`Error encountered in CdkCalculateAllocations. Unable to find adjustment account. ${error}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const jobAllocations = _.union(Object.keys(profitCenterHash), Object.keys(costCenterHash)).map((key) => {
|
|
||||||
const profitCenter = bodyshop.md_responsibility_centers.profits.find((c) => c.name === key);
|
|
||||||
const costCenter = bodyshop.md_responsibility_centers.costs.find((c) => c.name === key);
|
|
||||||
|
|
||||||
return {
|
|
||||||
center: key,
|
|
||||||
sale: profitCenterHash[key] ? profitCenterHash[key] : Dinero(),
|
|
||||||
cost: costCenterHash[key] ? costCenterHash[key] : Dinero(),
|
|
||||||
profitCenter,
|
|
||||||
costCenter
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return [
|
|
||||||
...jobAllocations,
|
|
||||||
...Object.keys(taxAllocations)
|
|
||||||
.filter((key) => taxAllocations[key].sale.getAmount() > 0 || taxAllocations[key].cost.getAmount() > 0)
|
|
||||||
.map((key) => {
|
|
||||||
if (
|
|
||||||
key === "federal" &&
|
|
||||||
selectedDmsAllocationConfig.gst_override &&
|
|
||||||
selectedDmsAllocationConfig.gst_override !== ""
|
|
||||||
) {
|
|
||||||
const ret = { ...taxAllocations[key], tax: key };
|
|
||||||
ret.costCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override;
|
|
||||||
ret.profitCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override;
|
|
||||||
return ret;
|
|
||||||
} else {
|
|
||||||
return { ...taxAllocations[key], tax: key };
|
|
||||||
}
|
|
||||||
})
|
|
||||||
];
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
CdkBase.createLogEvent(socket, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`);
|
CdkBase.createLogEvent(socket, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
async function QueryJobData(socket, jobid) {
|
async function QueryJobData(connectionData, token, jobid) {
|
||||||
CdkBase.createLogEvent(socket, "DEBUG", `Querying job data for id ${jobid}`);
|
CdkBase.createLogEvent(connectionData, "DEBUG", `Querying job data for id ${jobid}`);
|
||||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
|
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
|
||||||
const result = await client
|
const result = await client.setHeaders({ Authorization: token }).request(queries.GET_CDK_ALLOCATIONS, { id: jobid });
|
||||||
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
CdkBase.createLogEvent(connectionData, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`);
|
||||||
.request(queries.GET_CDK_ALLOCATIONS, { id: jobid });
|
|
||||||
CdkBase.createLogEvent(socket, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`);
|
|
||||||
return result.jobs_by_pk;
|
return result.jobs_by_pk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function calculateAllocations(connectionData, job) {
|
||||||
|
const { bodyshop } = job;
|
||||||
|
|
||||||
|
const taxAllocations = InstanceManager({
|
||||||
|
executeFunction: true,
|
||||||
|
deubg: true,
|
||||||
|
args: [],
|
||||||
|
imex: () => ({
|
||||||
|
local: {
|
||||||
|
center: bodyshop.md_responsibility_centers.taxes.local.name,
|
||||||
|
sale: Dinero(job.job_totals.totals.local_tax),
|
||||||
|
cost: Dinero(),
|
||||||
|
profitCenter: bodyshop.md_responsibility_centers.taxes.local,
|
||||||
|
costCenter: bodyshop.md_responsibility_centers.taxes.local
|
||||||
|
},
|
||||||
|
state: {
|
||||||
|
center: bodyshop.md_responsibility_centers.taxes.state.name,
|
||||||
|
sale: Dinero(job.job_totals.totals.state_tax),
|
||||||
|
cost: Dinero(),
|
||||||
|
profitCenter: bodyshop.md_responsibility_centers.taxes.state,
|
||||||
|
costCenter: bodyshop.md_responsibility_centers.taxes.state
|
||||||
|
},
|
||||||
|
federal: {
|
||||||
|
center: bodyshop.md_responsibility_centers.taxes.federal.name,
|
||||||
|
sale: Dinero(job.job_totals.totals.federal_tax),
|
||||||
|
cost: Dinero(),
|
||||||
|
profitCenter: bodyshop.md_responsibility_centers.taxes.federal,
|
||||||
|
costCenter: bodyshop.md_responsibility_centers.taxes.federal
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
rome: () => ({
|
||||||
|
tax_ty1: {
|
||||||
|
center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name,
|
||||||
|
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]),
|
||||||
|
cost: Dinero(),
|
||||||
|
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`],
|
||||||
|
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`]
|
||||||
|
},
|
||||||
|
tax_ty2: {
|
||||||
|
center: bodyshop.md_responsibility_centers.taxes[`tax_ty2`].name,
|
||||||
|
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty2Tax`]),
|
||||||
|
cost: Dinero(),
|
||||||
|
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`],
|
||||||
|
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`]
|
||||||
|
},
|
||||||
|
tax_ty3: {
|
||||||
|
center: bodyshop.md_responsibility_centers.taxes[`tax_ty3`].name,
|
||||||
|
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty3Tax`]),
|
||||||
|
cost: Dinero(),
|
||||||
|
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`],
|
||||||
|
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`]
|
||||||
|
},
|
||||||
|
tax_ty4: {
|
||||||
|
center: bodyshop.md_responsibility_centers.taxes[`tax_ty4`].name,
|
||||||
|
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty4Tax`]),
|
||||||
|
cost: Dinero(),
|
||||||
|
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`],
|
||||||
|
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`]
|
||||||
|
},
|
||||||
|
tax_ty5: {
|
||||||
|
center: bodyshop.md_responsibility_centers.taxes[`tax_ty5`].name,
|
||||||
|
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty5Tax`]),
|
||||||
|
cost: Dinero(),
|
||||||
|
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`],
|
||||||
|
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
//Determine if there are MAPA and MASH lines already on the estimate.
|
||||||
|
//If there are, don't do anything extra (mitchell estimate)
|
||||||
|
//Otherwise, calculate them and add them to the default MAPA and MASH centers.
|
||||||
|
let hasMapaLine = false;
|
||||||
|
let hasMashLine = false;
|
||||||
|
|
||||||
|
const profitCenterHash = job.joblines.reduce((acc, val) => {
|
||||||
|
//Check the Parts Assignment
|
||||||
|
if (val.db_ref === "936008") {
|
||||||
|
//If either of these DB REFs change, they also need to change in job-totals/job-costing calculations.
|
||||||
|
hasMapaLine = true;
|
||||||
|
}
|
||||||
|
if (val.db_ref === "936007") {
|
||||||
|
hasMashLine = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val.profitcenter_part) {
|
||||||
|
if (!acc[val.profitcenter_part]) acc[val.profitcenter_part] = Dinero();
|
||||||
|
|
||||||
|
let DineroAmount = Dinero({
|
||||||
|
amount: Math.round(val.act_price * 100)
|
||||||
|
}).multiply(val.part_qty || 1);
|
||||||
|
|
||||||
|
DineroAmount = DineroAmount.add(
|
||||||
|
((val.prt_dsmk_m && val.prt_dsmk_m !== 0) || (val.prt_dsmk_p && val.prt_dsmk_p !== 0)) &&
|
||||||
|
DiscountNotAlreadyCounted(val, job.joblines)
|
||||||
|
? val.prt_dsmk_m
|
||||||
|
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||||
|
: Dinero({
|
||||||
|
amount: Math.round(val.act_price * 100)
|
||||||
|
})
|
||||||
|
.multiply(val.part_qty || 0)
|
||||||
|
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||||
|
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
||||||
|
: Dinero()
|
||||||
|
);
|
||||||
|
|
||||||
|
acc[val.profitcenter_part] = acc[val.profitcenter_part].add(DineroAmount);
|
||||||
|
}
|
||||||
|
if (val.profitcenter_labor && val.mod_lbr_ty) {
|
||||||
|
//Check the Labor Assignment.
|
||||||
|
|
||||||
|
if (!acc[val.profitcenter_labor]) acc[val.profitcenter_labor] = Dinero();
|
||||||
|
|
||||||
|
acc[val.profitcenter_labor] = acc[val.profitcenter_labor].add(
|
||||||
|
Dinero({
|
||||||
|
amount: Math.round(job[`rate_${val.mod_lbr_ty.toLowerCase()}`] * 100)
|
||||||
|
}).multiply(val.mod_lb_hrs)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const selectedDmsAllocationConfig = bodyshop.md_responsibility_centers.dms_defaults.find(
|
||||||
|
(d) => d.name === job.dms_allocation
|
||||||
|
);
|
||||||
|
CdkBase.createLogEvent(
|
||||||
|
connectionData,
|
||||||
|
"DEBUG",
|
||||||
|
`Using DMS Allocation ${selectedDmsAllocationConfig && selectedDmsAllocationConfig.name} for cost export.`
|
||||||
|
);
|
||||||
|
|
||||||
|
let costCenterHash = {};
|
||||||
|
//Check whether to skip this if PBS and using AP module.
|
||||||
|
const disablebillwip = !!bodyshop?.pbs_configuration?.disablebillwip;
|
||||||
|
|
||||||
|
if (!disablebillwip) {
|
||||||
|
costCenterHash = job.bills.reduce((bill_acc, bill_val) => {
|
||||||
|
bill_val.billlines.map((line_val) => {
|
||||||
|
if (!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]])
|
||||||
|
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = Dinero();
|
||||||
|
|
||||||
|
let lineDinero = Dinero({
|
||||||
|
amount: Math.round((line_val.actual_cost || 0) * 100)
|
||||||
|
})
|
||||||
|
.multiply(line_val.quantity)
|
||||||
|
.multiply(bill_val.is_credit_memo ? -1 : 1);
|
||||||
|
|
||||||
|
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] =
|
||||||
|
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]].add(lineDinero);
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
return bill_acc;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
job.timetickets.forEach((ticket) => {
|
||||||
|
//Get the total amount of the ticket.
|
||||||
|
let TicketTotal = Dinero({
|
||||||
|
amount: Math.round(
|
||||||
|
ticket.rate *
|
||||||
|
(ticket.employee && ticket.employee.flat_rate ? ticket.productivehrs || 0 : ticket.actualhrs || 0) *
|
||||||
|
100
|
||||||
|
)
|
||||||
|
});
|
||||||
|
//Add it to the right cost center.
|
||||||
|
if (!costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]])
|
||||||
|
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] = Dinero();
|
||||||
|
|
||||||
|
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] =
|
||||||
|
costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]].add(TicketTotal);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasMapaLine && job.job_totals.rates.mapa.total.amount > 0) {
|
||||||
|
// console.log("Adding MAPA Line Manually.");
|
||||||
|
const mapaAccountName = selectedDmsAllocationConfig.profits.MAPA;
|
||||||
|
|
||||||
|
const mapaAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mapaAccountName);
|
||||||
|
|
||||||
|
if (mapaAccount) {
|
||||||
|
if (!profitCenterHash[mapaAccountName]) profitCenterHash[mapaAccountName] = Dinero();
|
||||||
|
|
||||||
|
profitCenterHash[mapaAccountName] = profitCenterHash[mapaAccountName].add(
|
||||||
|
Dinero(job.job_totals.rates.mapa.total)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
//console.log("NO MAPA ACCOUNT FOUND!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasMashLine && job.job_totals.rates.mash.total.amount > 0) {
|
||||||
|
// console.log("Adding MASH Line Manually.");
|
||||||
|
|
||||||
|
const mashAccountName = selectedDmsAllocationConfig.profits.MASH;
|
||||||
|
|
||||||
|
const mashAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mashAccountName);
|
||||||
|
|
||||||
|
if (mashAccount) {
|
||||||
|
if (!profitCenterHash[mashAccountName]) profitCenterHash[mashAccountName] = Dinero();
|
||||||
|
|
||||||
|
profitCenterHash[mashAccountName] = profitCenterHash[mashAccountName].add(
|
||||||
|
Dinero(job.job_totals.rates.mash.total)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// console.log("NO MASH ACCOUNT FOUND!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log(
|
||||||
|
// Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting),
|
||||||
|
// typeof Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting)
|
||||||
|
// );
|
||||||
|
if (!!bodyshop?.cdk_configuration?.sendmaterialscosting) {
|
||||||
|
//Manually send the percentage of the costing.
|
||||||
|
|
||||||
|
//Paint Mat
|
||||||
|
const mapaAccountName = selectedDmsAllocationConfig.costs.MAPA;
|
||||||
|
const mapaAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mapaAccountName);
|
||||||
|
if (mapaAccount) {
|
||||||
|
if (!costCenterHash[mapaAccountName]) costCenterHash[mapaAccountName] = Dinero();
|
||||||
|
if (job.bodyshop.use_paint_scale_data === true) {
|
||||||
|
if (job.mixdata.length > 0) {
|
||||||
|
costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add(
|
||||||
|
Dinero({
|
||||||
|
amount: Math.round(((job.mixdata[0] && job.mixdata[0].totalliquidcost) || 0) * 100)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add(
|
||||||
|
Dinero(job.job_totals.rates.mapa.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add(
|
||||||
|
Dinero(job.job_totals.rates.mapa.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//console.log("NO MAPA ACCOUNT FOUND!!");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Shop Mat
|
||||||
|
const mashAccountName = selectedDmsAllocationConfig.costs.MASH;
|
||||||
|
const mashAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mashAccountName);
|
||||||
|
if (mashAccount) {
|
||||||
|
if (!costCenterHash[mashAccountName]) costCenterHash[mashAccountName] = Dinero();
|
||||||
|
costCenterHash[mashAccountName] = costCenterHash[mashAccountName].add(
|
||||||
|
Dinero(job.job_totals.rates.mash.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// console.log("NO MASH ACCOUNT FOUND!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { ca_bc_pvrt } = job;
|
||||||
|
if (ca_bc_pvrt) {
|
||||||
|
// const pvrtAccount = bodyshop.md_responsibility_centers.profits.find(
|
||||||
|
// (c) => c.name === mashAccountName
|
||||||
|
// );
|
||||||
|
|
||||||
|
taxAllocations.state.sale = taxAllocations.state.sale.add(Dinero({ amount: Math.round((ca_bc_pvrt || 0) * 100) }));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (job.towing_payable && job.towing_payable !== 0) {
|
||||||
|
const towAccountName = selectedDmsAllocationConfig.profits.TOW;
|
||||||
|
|
||||||
|
const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === towAccountName);
|
||||||
|
|
||||||
|
if (towAccount) {
|
||||||
|
if (!profitCenterHash[towAccountName]) profitCenterHash[towAccountName] = Dinero();
|
||||||
|
|
||||||
|
profitCenterHash[towAccountName] = profitCenterHash[towAccountName].add(
|
||||||
|
Dinero({
|
||||||
|
amount: Math.round((job.towing_payable || 0) * 100)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// console.log("NO MASH ACCOUNT FOUND!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (job.storage_payable && job.storage_payable !== 0) {
|
||||||
|
const storageAccountName = selectedDmsAllocationConfig.profits.TOW;
|
||||||
|
|
||||||
|
const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === storageAccountName);
|
||||||
|
|
||||||
|
if (towAccount) {
|
||||||
|
if (!profitCenterHash[storageAccountName]) profitCenterHash[storageAccountName] = Dinero();
|
||||||
|
|
||||||
|
profitCenterHash[storageAccountName] = profitCenterHash[storageAccountName].add(
|
||||||
|
Dinero({
|
||||||
|
amount: Math.round((job.storage_payable || 0) * 100)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// console.log("NO MASH ACCOUNT FOUND!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (job.adjustment_bottom_line && job.adjustment_bottom_line !== 0) {
|
||||||
|
const otherAccountName = selectedDmsAllocationConfig.profits.PAO;
|
||||||
|
|
||||||
|
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === otherAccountName);
|
||||||
|
|
||||||
|
if (otherAccount) {
|
||||||
|
if (!profitCenterHash[otherAccountName]) profitCenterHash[otherAccountName] = Dinero();
|
||||||
|
|
||||||
|
profitCenterHash[otherAccountName] = profitCenterHash[otherAccountName].add(
|
||||||
|
Dinero({
|
||||||
|
amount: Math.round((job.adjustment_bottom_line || 0) * 100)
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// console.log("NO MASH ACCOUNT FOUND!!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (InstanceManager({ rome: true })) {
|
||||||
|
//profile level adjustments
|
||||||
|
Object.keys(job.job_totals.parts.adjustments).forEach((key) => {
|
||||||
|
const accountName = selectedDmsAllocationConfig.profits[key];
|
||||||
|
|
||||||
|
const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName);
|
||||||
|
|
||||||
|
if (otherAccount) {
|
||||||
|
if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero();
|
||||||
|
|
||||||
|
profitCenterHash[accountName] = profitCenterHash[accountName].add(
|
||||||
|
Dinero(job.job_totals.parts.adjustments[key])
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
CdkBase.createLogEvent(
|
||||||
|
connectionData,
|
||||||
|
"ERROR",
|
||||||
|
`Error encountered in CdkCalculateAllocations. Unable to find adjustment account. ${error}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const jobAllocations = _.union(Object.keys(profitCenterHash), Object.keys(costCenterHash)).map((key) => {
|
||||||
|
const profitCenter = bodyshop.md_responsibility_centers.profits.find((c) => c.name === key);
|
||||||
|
const costCenter = bodyshop.md_responsibility_centers.costs.find((c) => c.name === key);
|
||||||
|
|
||||||
|
return {
|
||||||
|
center: key,
|
||||||
|
sale: profitCenterHash[key] ? profitCenterHash[key] : Dinero(),
|
||||||
|
cost: costCenterHash[key] ? costCenterHash[key] : Dinero(),
|
||||||
|
profitCenter,
|
||||||
|
costCenter
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
...jobAllocations,
|
||||||
|
...Object.keys(taxAllocations)
|
||||||
|
.filter((key) => taxAllocations[key].sale.getAmount() > 0 || taxAllocations[key].cost.getAmount() > 0)
|
||||||
|
.map((key) => {
|
||||||
|
if (
|
||||||
|
key === "federal" &&
|
||||||
|
selectedDmsAllocationConfig.gst_override &&
|
||||||
|
selectedDmsAllocationConfig.gst_override !== ""
|
||||||
|
) {
|
||||||
|
const ret = { ...taxAllocations[key], tax: key };
|
||||||
|
ret.costCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override;
|
||||||
|
ret.profitCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override;
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
return { ...taxAllocations[key], tax: key };
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|||||||
@@ -211,6 +211,8 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const repairCosts = CreateCosts(job);
|
const repairCosts = CreateCosts(job);
|
||||||
|
const jobline = CreateJobLines(job.joblines);
|
||||||
|
const timeticket = CreateTimeTickets(job.timetickets);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ret = {
|
const ret = {
|
||||||
@@ -276,8 +278,11 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
|||||||
DateInvoiced:
|
DateInvoiced:
|
||||||
(job.date_invoiced && moment(job.date_invoiced).tz(job.bodyshop.timezone).format(DateFormat)) || "",
|
(job.date_invoiced && moment(job.date_invoiced).tz(job.bodyshop.timezone).format(DateFormat)) || "",
|
||||||
DateExported:
|
DateExported:
|
||||||
(job.date_exported && moment(job.date_exported).tz(job.bodyshop.timezone).format(DateFormat)) || ""
|
(job.date_exported && moment(job.date_exported).tz(job.bodyshop.timezone).format(DateFormat)) || "",
|
||||||
|
DateVoid: (job.date_void && moment(job.date_void).tz(job.bodyshop.timezone).format(DateFormat)) || ""
|
||||||
},
|
},
|
||||||
|
JobLineDetails: { jobline },
|
||||||
|
TimeTicketDetails: { timeticket },
|
||||||
Sales: {
|
Sales: {
|
||||||
Labour: {
|
Labour: {
|
||||||
Aluminum: Dinero(job.job_totals.rates.laa.total).toFormat(DineroFormat),
|
Aluminum: Dinero(job.job_totals.rates.laa.total).toFormat(DineroFormat),
|
||||||
@@ -625,3 +630,38 @@ const CreateCosts = (job) => {
|
|||||||
}, 0)
|
}, 0)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CreateJobLines = (joblines) => {
|
||||||
|
const repairLines = [];
|
||||||
|
joblines.forEach((jobline) => {
|
||||||
|
repairLines.push({
|
||||||
|
line_description: jobline.line_desc,
|
||||||
|
oem_part_no: jobline.oem_partno,
|
||||||
|
alt_part_no: jobline.alt_partno,
|
||||||
|
op_code_desc: jobline.op_code_desc,
|
||||||
|
part_type: jobline.part_type,
|
||||||
|
part_qty: jobline.part_qty,
|
||||||
|
part_price: jobline.act_price,
|
||||||
|
labor_type: jobline.mod_lbr_ty,
|
||||||
|
labor_hours: jobline.mod_lb_hrs
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return repairLines;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CreateTimeTickets = (timetickets) => {
|
||||||
|
const timeTickets = [];
|
||||||
|
timetickets.forEach((ticket) => {
|
||||||
|
timeTickets.push({
|
||||||
|
date: ticket.date,
|
||||||
|
employee: ticket.employee.employee_number
|
||||||
|
.trim()
|
||||||
|
.concat(" - ", ticket.employee.first_name.trim(), " ", ticket.employee.last_name.trim())
|
||||||
|
.trim(),
|
||||||
|
productive_hrs: ticket.productivehrs,
|
||||||
|
actual_hrs: ticket.actualhrs,
|
||||||
|
cost_center: ticket.cost_center
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return timeTickets;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1113,7 +1113,7 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
|
|||||||
use_paint_scale_data
|
use_paint_scale_data
|
||||||
timezone
|
timezone
|
||||||
}
|
}
|
||||||
jobs(where: {_and: [{updated_at: {_gt: $start}}, {updated_at: {_lte: $end}}, {shopid: {_eq: $bodyshopid}}]}) {
|
jobs(where: {_and: [{updated_at: {_gt: $start}}, {updated_at: {_lte: $end}}, {converted: {_eq: true}}, {shopid: {_eq: $bodyshopid}}]}) {
|
||||||
actual_completion
|
actual_completion
|
||||||
actual_delivery
|
actual_delivery
|
||||||
actual_in
|
actual_in
|
||||||
@@ -1138,6 +1138,7 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
|
|||||||
date_invoiced
|
date_invoiced
|
||||||
date_open
|
date_open
|
||||||
date_repairstarted
|
date_repairstarted
|
||||||
|
date_void
|
||||||
employee_body_rel {
|
employee_body_rel {
|
||||||
first_name
|
first_name
|
||||||
last_name
|
last_name
|
||||||
@@ -1168,6 +1169,7 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
|
|||||||
ins_co_nm
|
ins_co_nm
|
||||||
joblines(where: {removed: {_eq: false}}) {
|
joblines(where: {removed: {_eq: false}}) {
|
||||||
act_price
|
act_price
|
||||||
|
alt_partno
|
||||||
billlines(order_by: {bill: {date: desc_nulls_last}} limit: 1) {
|
billlines(order_by: {bill: {date: desc_nulls_last}} limit: 1) {
|
||||||
actual_cost
|
actual_cost
|
||||||
actual_price
|
actual_price
|
||||||
@@ -1188,6 +1190,8 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
|
|||||||
line_no
|
line_no
|
||||||
mod_lb_hrs
|
mod_lb_hrs
|
||||||
mod_lbr_ty
|
mod_lbr_ty
|
||||||
|
oem_partno
|
||||||
|
op_code_desc
|
||||||
parts_order_lines(order_by: {parts_order: {order_date: desc_nulls_last}} limit: 1){
|
parts_order_lines(order_by: {parts_order: {order_date: desc_nulls_last}} limit: 1){
|
||||||
parts_order{
|
parts_order{
|
||||||
id
|
id
|
||||||
@@ -1200,7 +1204,6 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
|
|||||||
profitcenter_labor
|
profitcenter_labor
|
||||||
prt_dsmk_m
|
prt_dsmk_m
|
||||||
prt_dsmk_p
|
prt_dsmk_p
|
||||||
oem_partno
|
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
job_totals
|
job_totals
|
||||||
@@ -1251,12 +1254,18 @@ exports.KAIZEN_QUERY = `query KAIZEN_EXPORT($start: timestamptz, $bodyshopid: uu
|
|||||||
scheduled_in
|
scheduled_in
|
||||||
status
|
status
|
||||||
timetickets {
|
timetickets {
|
||||||
id
|
|
||||||
rate
|
|
||||||
cost_center
|
|
||||||
actualhrs
|
actualhrs
|
||||||
productivehrs
|
cost_center
|
||||||
|
date
|
||||||
|
employee {
|
||||||
|
employee_number
|
||||||
|
first_name
|
||||||
|
last_name
|
||||||
|
}
|
||||||
flat_rate
|
flat_rate
|
||||||
|
id
|
||||||
|
productivehrs
|
||||||
|
rate
|
||||||
}
|
}
|
||||||
tlos_ind
|
tlos_ind
|
||||||
v_color
|
v_color
|
||||||
@@ -2481,7 +2490,6 @@ query QUERY_TASK_BY_ID($id: uuid!) {
|
|||||||
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
||||||
exports.GET_JOBS_BY_PKS = `query GET_JOBS_BY_PKS($ids: [uuid!]!) {
|
exports.GET_JOBS_BY_PKS = `query GET_JOBS_BY_PKS($ids: [uuid!]!) {
|
||||||
jobs(where: {id: {_in: $ids}}) {
|
jobs(where: {id: {_in: $ids}}) {
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -318,7 +318,9 @@ function GenerateCostingData(job) {
|
|||||||
if (!partsProfitCenter)
|
if (!partsProfitCenter)
|
||||||
console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type);
|
console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type);
|
||||||
const partsAmount = Dinero({
|
const partsAmount = Dinero({
|
||||||
amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) : Math.round(val.act_price * 100)
|
amount: val.act_price_before_ppc
|
||||||
|
? Math.round(val.act_price_before_ppc * 100)
|
||||||
|
: Math.round(val.act_price * 100)
|
||||||
})
|
})
|
||||||
.multiply(val.part_qty || 1)
|
.multiply(val.part_qty || 1)
|
||||||
.add(
|
.add(
|
||||||
@@ -327,7 +329,9 @@ function GenerateCostingData(job) {
|
|||||||
? val.prt_dsmk_m
|
? val.prt_dsmk_m
|
||||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||||
: Dinero({
|
: Dinero({
|
||||||
amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) : Math.round(val.act_price * 100)
|
amount: val.act_price_before_ppc
|
||||||
|
? Math.round(val.act_price_before_ppc * 100)
|
||||||
|
: Math.round(val.act_price * 100)
|
||||||
})
|
})
|
||||||
.multiply(val.part_qty || 0)
|
.multiply(val.part_qty || 0)
|
||||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||||
@@ -368,7 +372,10 @@ function GenerateCostingData(job) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Additional Profit Center
|
//Additional Profit Center
|
||||||
if ((!val.part_type && !val.mod_lbr_ty) || (!val.part_type && val.mod_lbr_ty)) {
|
if (
|
||||||
|
(!val.part_type && !val.mod_lbr_ty) ||
|
||||||
|
(!val.part_type && val.mod_lbr_ty && val.act_price > 0 && val.lbr_op !== "OP14")
|
||||||
|
) {
|
||||||
//Does it already have a defined profit center?
|
//Does it already have a defined profit center?
|
||||||
//If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate.
|
//If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate.
|
||||||
const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown";
|
const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown";
|
||||||
|
|||||||
@@ -643,7 +643,7 @@ function CalculateAdditional(job) {
|
|||||||
additionalCosts: null,
|
additionalCosts: null,
|
||||||
additionalCostItems: [],
|
additionalCostItems: [],
|
||||||
adjustments: null,
|
adjustments: null,
|
||||||
towing: null,
|
towing: Dinero(),
|
||||||
shipping: Dinero(),
|
shipping: Dinero(),
|
||||||
storage: null,
|
storage: null,
|
||||||
pvrt: null,
|
pvrt: null,
|
||||||
@@ -668,7 +668,7 @@ function CalculateAdditional(job) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (val.line_desc.toLowerCase().includes("towing")) {
|
if (val.line_desc.toLowerCase().includes("towing")) {
|
||||||
ret.towing = lineValue;
|
ret.towing = ret.towing.add(lineValue);
|
||||||
return acc;
|
return acc;
|
||||||
} else {
|
} else {
|
||||||
ret.additionalCostItems.push({ key: val.line_desc, total: lineValue });
|
ret.additionalCostItems.push({ key: val.line_desc, total: lineValue });
|
||||||
@@ -909,6 +909,25 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (job.adjustment_bottom_line) {
|
||||||
|
const subtotal_before_adjustment = subtotal.add(Dinero({ amount: Math.round(job.adjustment_bottom_line * -100) }));
|
||||||
|
const percent_of_adjustment =
|
||||||
|
Math.round(
|
||||||
|
subtotal_before_adjustment.toUnit() /
|
||||||
|
(job.adjustment_bottom_line > 0 ? job.adjustment_bottom_line : job.adjustment_bottom_line * -1)
|
||||||
|
) / 100;
|
||||||
|
|
||||||
|
Object.keys(taxableAmountsByTier).forEach((taxTierKey) => {
|
||||||
|
taxable_adjustment = taxableAmountsByTier[taxTierKey].multiply(percent_of_adjustment);
|
||||||
|
console.log("🚀 ~ taxableAmountsByTier ~ taxable_adjustment:", taxable_adjustment);
|
||||||
|
if (job.adjustment_bottom_line > 0) {
|
||||||
|
taxableAmountsByTier[taxTierKey] = taxableAmountsByTier[taxTierKey].add(taxable_adjustment);
|
||||||
|
} else {
|
||||||
|
taxableAmountsByTier[taxTierKey] = taxableAmountsByTier[taxTierKey].subtract(taxable_adjustment);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const remainingTaxableAmounts = taxableAmountsByTier;
|
const remainingTaxableAmounts = taxableAmountsByTier;
|
||||||
console.log("*** Taxable Amounts by Tier***");
|
console.log("*** Taxable Amounts by Tier***");
|
||||||
console.table(JSON.parse(JSON.stringify(taxableAmountsByTier)));
|
console.table(JSON.parse(JSON.stringify(taxableAmountsByTier)));
|
||||||
|
|||||||
@@ -489,7 +489,7 @@ function CalculateAdditional(job) {
|
|||||||
additionalCosts: null,
|
additionalCosts: null,
|
||||||
additionalCostItems: [],
|
additionalCostItems: [],
|
||||||
adjustments: null,
|
adjustments: null,
|
||||||
towing: null,
|
towing: Dinero(),
|
||||||
shipping: Dinero(),
|
shipping: Dinero(),
|
||||||
storage: null,
|
storage: null,
|
||||||
pvrt: null,
|
pvrt: null,
|
||||||
@@ -512,7 +512,7 @@ function CalculateAdditional(job) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (val.line_desc.toLowerCase().includes("towing")) {
|
if (val.line_desc.toLowerCase().includes("towing")) {
|
||||||
ret.towing = lineValue;
|
ret.towing = ret.towing.add(lineValue);
|
||||||
return acc;
|
return acc;
|
||||||
} else {
|
} else {
|
||||||
ret.additionalCostItems.push({ key: val.line_desc, total: lineValue });
|
ret.additionalCostItems.push({ key: val.line_desc, total: lineValue });
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const cdkGetMake = require("../cdk/cdk-get-makes");
|
const cdkGetMake = require("../cdk/cdk-get-makes");
|
||||||
|
const cdkCalculateAllocations = require("../cdk/cdk-calculate-allocations");
|
||||||
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
||||||
const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");
|
const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");
|
||||||
|
|
||||||
router.use(validateFirebaseIdTokenMiddleware);
|
router.use(validateFirebaseIdTokenMiddleware);
|
||||||
|
|
||||||
router.post("/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.default);
|
router.post("/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.default);
|
||||||
|
router.post("/calculate-allocations", withUserGraphQLClientMiddleware, cdkCalculateAllocations.defaultRoute);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
Reference in New Issue
Block a user