Merged in release/2022-02-11 (pull request #376)

Release/2022 02 11
This commit is contained in:
Patrick Fic
2022-02-09 23:52:27 +00:00
24 changed files with 343 additions and 100 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project be_version="2.7.1" version="1.2">
<babeledit_project version="1.2" be_version="2.7.1">
<!--
BabelEdit project file
@@ -25120,6 +25120,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>cost_Additional</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>cost_labor</name>
<definition_loaded>false</definition_loaded>
@@ -27014,6 +27035,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>sale_additional</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>sale_labor</name>
<definition_loaded>false</definition_loaded>
@@ -32085,6 +32127,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>part_type</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>quantity</name>
<definition_loaded>false</definition_loaded>

View File

@@ -207,6 +207,8 @@ export function BillDetailEditcontainer({
cost: i.actual_cost,
quantity: i.quantity,
joblineid: i.joblineid,
oem_partno: i.jobline && i.jobline.oem_partno,
part_type: i.jobline && i.jobline.part_type,
};
}),
isReturn: true,

View File

@@ -216,7 +216,11 @@ function BillEnterModalContainer({
if (enterAgain) {
form.resetFields();
form.setFieldsValue({ ...form.getFieldsValue(), billlines: [] });
form.resetFields();
form.setFieldsValue({
...formValues,
billlines: [],
});
} else {
toggleModalVisible();
}

View File

@@ -76,6 +76,7 @@ export function BillsListTableComponent({
quantity: i.quantity,
joblineid: i.joblineid,
oem_partno: i.jobline && i.jobline.oem_partno,
part_type: i.jobline && i.jobline.part_type,
};
}),
isReturn: true,

View File

@@ -26,11 +26,6 @@ export function JobCostingModalContainer({
const { visible, context } = jobCostingModal;
const { jobId } = context;
// const { loading, error, data } = useQuery(QUERY_JOB_COSTING_DETAILS, {
// variables: { id: jobId },
// skip: !jobId,
// });
useEffect(() => {
async function getData() {
if (jobId && visible) {
@@ -46,8 +41,14 @@ export function JobCostingModalContainer({
<Modal
visible={visible}
title={t("jobs.labels.jobcosting")}
onOk={() => toggleModalVisible()}
onCancel={() => toggleModalVisible()}
onOk={() => {
toggleModalVisible();
setCostingData(null);
}}
onCancel={() => {
toggleModalVisible();
setCostingData(null);
}}
cancelButtonProps={{ style: { display: "none" } }}
width="90%"
destroyOnClose

View File

@@ -16,6 +16,10 @@ export default function JobCostingStatistics({ summaryData }) {
value={Dinero(summaryData.totalPartsSales).toFormat()}
title={t("jobs.labels.sale_parts")}
/>
<Statistic
value={Dinero(summaryData.totalAdditionalSales).toFormat()}
title={t("jobs.labels.sale_additional")}
/>
<Statistic
value={Dinero(summaryData.totalSales).toFormat()}
title={t("jobs.labels.total_sales")}
@@ -28,6 +32,10 @@ export default function JobCostingStatistics({ summaryData }) {
value={Dinero(summaryData.totalPartsCost).toFormat()}
title={t("jobs.labels.cost_parts")}
/>
<Statistic
value={Dinero(summaryData.totalAdditionalCost).toFormat()}
title={t("jobs.labels.cost_Additional")}
/>
<Statistic
value={Dinero(summaryData.totalCost).toFormat()}
title={t("jobs.labels.total_cost")}

View File

@@ -319,6 +319,15 @@ export function PartsOrderListTableComponent({
},
]
: []),
{
title: t("parts_orders.fields.part_type"),
dataIndex: "part_type",
key: "part_type",
render: (text, record) =>
record.part_type
? t(`joblines.fields.part_types.${record.part_type}`)
: null,
},
{
title: t("parts_orders.fields.oem_partno"),
dataIndex: "oem_partno",

View File

@@ -1,6 +1,15 @@
import { DeleteFilled, WarningFilled } from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react";
import { Divider, Form, Input, InputNumber, Radio, Space, Tag } from "antd";
import {
Divider,
Form,
Input,
InputNumber,
Radio,
Space,
Tag,
Select,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -114,6 +123,45 @@ export function PartsOrderModalComponent({
>
<Input />
</Form.Item>
<Form.Item
label={t("parts_orders.fields.part_type")}
key={`${index}part_type`}
name={[field.name, "part_type"]}
>
<Select>
<Select.Option value="PAA">
{t("joblines.fields.part_types.PAA")}
</Select.Option>
<Select.Option value="PAC">
{t("joblines.fields.part_types.PAC")}
</Select.Option>
<Select.Option value="PAL">
{t("joblines.fields.part_types.PAL")}
</Select.Option>
<Select.Option value="PAG">
{t("joblines.fields.part_types.PAG")}
</Select.Option>
<Select.Option value="PAM">
{t("joblines.fields.part_types.PAM")}
</Select.Option>
<Select.Option value="PAP">
{t("joblines.fields.part_types.PAP")}
</Select.Option>
<Select.Option value="PAN">
{t("joblines.fields.part_types.PAN")}
</Select.Option>
<Select.Option value="PAO">
{t("joblines.fields.part_types.PAO")}
</Select.Option>
<Select.Option value="PAR">
{t("joblines.fields.part_types.PAR")}
</Select.Option>
<Select.Option value="PAS">
{t("joblines.fields.part_types.PAS")}
</Select.Option>
</Select>
</Form.Item>
<Form.Item
label={t("parts_orders.fields.oem_partno")}
key={`${index}oem_partno`}

View File

@@ -77,7 +77,7 @@ export function PartsOrderModalContainer({
const { refetch } = actions;
const [form] = Form.useForm();
const [saving, setSaving] = useState(false);
const sendTypeState = useState("e");
const sendType = sendTypeState[0];
@@ -93,7 +93,7 @@ export function PartsOrderModalContainer({
const handleFinish = async (values) => {
logImEXEvent("parts_order_insert");
setSaving(true);
const insertResult = await insertPartOrder({
variables: {
po: [
@@ -247,8 +247,6 @@ export function PartsOrderModalContainer({
});
}
console.log(partsOrder.data.parts_orders_by_pk);
const oecResponse = await axios.post(
"http://localhost:1337/oec/",
@@ -275,11 +273,11 @@ export function PartsOrderModalContainer({
error: JSON.stringify(error.message),
}),
});
setSaving(false);
return;
}
}
setSaving(false);
toggleModalVisible();
};
@@ -301,6 +299,7 @@ export function PartsOrderModalContainer({
cost: value.cost,
quantity: value.part_qty,
job_line_id: isReturn ? value.joblineid : value.id,
part_type: value.part_type,
});
return acc;
}, [])
@@ -324,6 +323,8 @@ export function PartsOrderModalContainer({
}
onCancel={() => toggleModalVisible()}
onOk={() => form.submit()}
okButtonProps={{ loading: saving }}
cancelButtonProps={{ loading: saving }}
destroyOnClose
width="75%"
forceRender

View File

@@ -84,6 +84,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
line_remarks
quantity
job_line_id
part_type
cost
jobline {
id
@@ -123,6 +124,10 @@ export const QUERY_BILLS_BY_JOBID = gql`
applicable_taxes
deductedfromlbr
lbr_adjustment
jobline{
oem_partno
part_type
}
}
}
}
@@ -159,6 +164,10 @@ export const QUERY_BILL_BY_PK = gql`
cost_center
quantity
joblineid
jobline{
oem_partno
part_type
}
applicable_taxes
deductedfromlbr
lbr_adjustment

View File

@@ -69,6 +69,7 @@ export const QUERY_PARTS_ORDER_OEC = gql`
db_price
line_desc
quantity
part_type
}
job {
bodyshop{

View File

@@ -1486,6 +1486,7 @@
"closejob": "Close Job {{ro_number}}",
"contracts": "CC Contracts",
"cost": "Cost",
"cost_Additional": "Cost - Additional",
"cost_labor": "Cost - Labor",
"cost_parts": "Cost - Parts",
"costs": "Costs",
@@ -1585,6 +1586,7 @@
"relatedros": "Related ROs",
"returntotals": "Return Totals",
"rosaletotal": "RO Parts Total",
"sale_additional": "Sales - Additional",
"sale_labor": "Sales - Labor",
"sale_parts": "Sales - Parts & Sublet",
"sales": "Sales",
@@ -1904,6 +1906,7 @@
"order_date": "Order Date",
"order_number": "Order Number",
"orderedby": "Ordered By",
"part_type": "Type",
"quantity": "Qty.",
"return": "Return",
"status": "Status"

View File

@@ -1486,6 +1486,7 @@
"closejob": "",
"contracts": "",
"cost": "",
"cost_Additional": "",
"cost_labor": "",
"cost_parts": "",
"costs": "",
@@ -1585,6 +1586,7 @@
"relatedros": "",
"returntotals": "",
"rosaletotal": "",
"sale_additional": "",
"sale_labor": "",
"sale_parts": "",
"sales": "",
@@ -1904,6 +1906,7 @@
"order_date": "",
"order_number": "",
"orderedby": "",
"part_type": "",
"quantity": "",
"return": "",
"status": ""

View File

@@ -1486,6 +1486,7 @@
"closejob": "",
"contracts": "",
"cost": "",
"cost_Additional": "",
"cost_labor": "",
"cost_parts": "",
"costs": "",
@@ -1585,6 +1586,7 @@
"relatedros": "",
"returntotals": "",
"rosaletotal": "",
"sale_additional": "",
"sale_labor": "",
"sale_parts": "",
"sales": "",
@@ -1904,6 +1906,7 @@
"order_date": "",
"order_number": "",
"orderedby": "",
"part_type": "",
"quantity": "",
"return": "",
"status": ""

View File

@@ -815,6 +815,7 @@
- email
- enforce_class
- enforce_referral
- entegral_configuration
- entegral_id
- features
- federal_tax_id

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."bodyshops" add column "entegral_configuration" jsonb
-- null default jsonb_build_array();

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "entegral_configuration" jsonb
null default jsonb_build_array();

View File

@@ -0,0 +1 @@
alter table "public"."bodyshops" alter column "entegral_configuration" set default jsonb_build_array();

View File

@@ -0,0 +1 @@
alter table "public"."bodyshops" alter column "entegral_configuration" set default jsonb_build_object();

View File

@@ -0,0 +1 @@
ALTER TABLE "public"."bodyshops" ALTER COLUMN "timezone" drop default;

View File

@@ -0,0 +1 @@
alter table "public"."bodyshops" alter column "timezone" set default 'America/Vancouver';

View File

@@ -123,12 +123,12 @@ exports.default = async (req, res) => {
}
}
// for (const xmlObj of allxmlsToUpload) {
// fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
// }
for (const xmlObj of allxmlsToUpload) {
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
}
// res.json(allxmlsToUpload);
// return;
res.json(allxmlsToUpload);
return;
let sftp = new Client();
sftp.on("error", (errors) =>
@@ -227,7 +227,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
InsuredorClaimantFlag: null,
},
VehicleInformation: {
Year: job.v_model_yr || "",
Year: parseInt(job.v_model_yr.match(/\d/g).join(""), 10) || "",
Make: job.v_make_desc || "",
Model: job.v_model_desc || "",
VIN: job.v_vin || "",
@@ -575,10 +575,12 @@ const CreateRepairOrderTag = (job, errorCallback) => {
.add(Dinero(job.job_totals.totals.federal_tax))
.toFormat(AHDineroFormat),
SalesTaxTotalCost: 0,
GrossTotal: Dinero(job.job_totals.totals.net_repairs).toFormat(
GrossTotal: Dinero(job.job_totals.totals.total_repairs).toFormat(
AHDineroFormat
),
DeductibleTotal: job.ded_amt || 0,
DeductibleTotal: Dinero({
amount: Math.round((job.ded_amt || 0) * 100),
}).toFormat(AHDineroFormat),
DepreciationTotal: Dinero(
job.job_totals.totals.custPayable.dep_taxes
).toFormat(AHDineroFormat),
@@ -588,7 +590,9 @@ const CreateRepairOrderTag = (job, errorCallback) => {
CustomerPay: Dinero(job.job_totals.totals.custPayable.total).toFormat(
AHDineroFormat
),
InsurancePay: 0,
InsurancePay: Dinero(job.job_totals.totals.total_repairs)
.subtract(Dinero(job.job_totals.totals.custPayable))
.toFormat(AHDineroFormat),
Deposit: 0,
AmountDue: 0,
},
@@ -634,7 +638,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
DetailLine:
job.joblines.length > 0
? job.joblines.map((jl) =>
GenerateDetailLines(jl, job.bodyshop.md_order_statuses)
GenerateDetailLines(job, jl, job.bodyshop.md_order_statuses)
)
: [generateNullDetailLine()],
},
@@ -718,7 +722,10 @@ const CreateCosts = (job) => {
return {
PartsTotalCost: Object.keys(billTotalsByCostCenters).reduce((acc, key) => {
return acc.add(billTotalsByCostCenters[key]);
if (key !== defaultCosts.PAS && key !== defaultCosts.PASL)
return acc.add(billTotalsByCostCenters[key]);
return acc;
}, Dinero()),
PartsOemCost: (billTotalsByCostCenters[defaultCosts.PAN] || Dinero()).add(
billTotalsByCostCenters[defaultCosts.PAP] || Dinero()
@@ -728,7 +735,9 @@ const CreateCosts = (job) => {
billTotalsByCostCenters[defaultCosts.PAM] || Dinero(),
PartsRecycledCost: billTotalsByCostCenters[defaultCosts.PAL] || Dinero(),
PartsOtherCost: billTotalsByCostCenters[defaultCosts.PAO] || Dinero(),
SubletTotalCost: billTotalsByCostCenters[defaultCosts.PAS] || Dinero(),
SubletTotalCost:
billTotalsByCostCenters[defaultCosts.PAS] ||
Dinero(billTotalsByCostCenters[defaultCosts.PASL] || Dinero()),
BodyLaborTotalCost: ticketTotalsByCostCenter[defaultCosts.LAB] || Dinero(),
RefinishLaborTotalCost:
ticketTotalsByCostCenter[defaultCosts.LAR] || Dinero(),
@@ -781,10 +790,15 @@ const StatusMapping = (status, md_ro_statuses) => {
// default: return "UNDEFINED"
};
const GenerateDetailLines = (line, statuses) => {
const GenerateDetailLines = (job, line, statuses) => {
const ret = {
BackOrdered: line.status === statuses.default_bo ? "1" : "0",
Cost: (line.billlines[0] && line.billlines[0].actual_cost.toFixed(2)) || 0,
Cost:
(line.billlines[0] &&
(line.billlines[0].actual_cost * line.billlines[0].quantity).toFixed(
2
)) ||
0,
//Critical: null,
Description: line.line_desc || "",
DiscountMarkup: line.prt_dsmk_m || 0,
@@ -811,11 +825,7 @@ const GenerateDetailLines = (line, statuses) => {
Vendor: (line.billlines[0] && line.billlines[0].bill.vendor.name) || "",
VendorPaid: null,
VendorPrice:
(line.billlines[0] &&
(line.billlines[0].actual_price * line.billlines[0].quantity).toFixed(
2
)) ||
0,
(line.billlines[0] && line.billlines[0].actual_price.toFixed(2)) || 0,
Deleted: null,
ExpectedOn: null,
ReceivedOn:

View File

@@ -639,7 +639,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshop
job_totals
driveable
parts_tax_rates
ded_amt
joblines(where: {removed: {_eq: false}}) {
id
line_no

View File

@@ -62,9 +62,11 @@ async function JobCostingMulti(req, res) {
summaryData: {
totalLaborSales: Dinero({ amount: 0 }),
totalPartsSales: Dinero({ amount: 0 }),
totalAdditionalSales: Dinero({ amount: 0 }),
totalSales: Dinero({ amount: 0 }),
totalLaborCost: Dinero({ amount: 0 }),
totalPartsCost: Dinero({ amount: 0 }),
totalAdditionalCost: Dinero({ amount: 0 }),
totalCost: Dinero({ amount: 0 }),
gpdollars: Dinero({ amount: 0 }),
gppercent: null,
@@ -102,12 +104,18 @@ async function JobCostingMulti(req, res) {
sale_parts_dinero: multiSummary.costCenterData[
CostCenterIndex
].sale_parts_dinero.add(c.sale_parts_dinero),
sale_additional_dinero: multiSummary.costCenterData[
CostCenterIndex
].sale_additional_dinero.add(c.sale_additional_dinero),
cost_labor_dinero: multiSummary.costCenterData[
CostCenterIndex
].cost_labor_dinero.add(c.cost_labor_dinero),
cost_parts_dinero: multiSummary.costCenterData[
CostCenterIndex
].cost_parts_dinero.add(c.cost_parts_dinero),
cost_additional_dinero: multiSummary.costCenterData[
CostCenterIndex
].cost_additional_dinero.add(c.cost_additional_dinero),
gpdollars_dinero: multiSummary.costCenterData[
CostCenterIndex
].gpdollars_dinero.add(c.gpdollars_dinero),
@@ -129,6 +137,10 @@ async function JobCostingMulti(req, res) {
multiSummary.summaryData.totalPartsSales.add(
costingData.summaryData.totalPartsSales
);
multiSummary.summaryData.totalAdditionalSales =
multiSummary.summaryData.totalAdditionalSales.add(
costingData.summaryData.totalAdditionalSales
);
multiSummary.summaryData.totalSales =
multiSummary.summaryData.totalSales.add(
costingData.summaryData.totalSales
@@ -145,6 +157,10 @@ async function JobCostingMulti(req, res) {
multiSummary.summaryData.totalPartsCost.add(
costingData.summaryData.totalPartsCost
);
multiSummary.summaryData.totalAdditionalCost =
multiSummary.summaryData.totalAdditionalCost.add(
costingData.summaryData.totalAdditionalCost
);
multiSummary.summaryData.totalCost =
multiSummary.summaryData.totalCost.add(
costingData.summaryData.totalCost
@@ -201,10 +217,14 @@ async function JobCostingMulti(req, res) {
...c,
sale_labor: c.sale_labor_dinero && c.sale_labor_dinero.toFormat(),
sale_parts: c.sale_parts_dinero && c.sale_parts_dinero.toFormat(),
sales: c.sale_labor_dinero.add(c.sale_parts_dinero).toFormat(),
sale_additional:
c.sale_additional_dinero && c.sale_additional_dinero.toFormat(),
sales: c.sales_dinero.toFormat(),
cost_parts: c.cost_parts_dinero && c.cost_parts_dinero.toFormat(),
cost_labor: c.cost_labor_dinero && c.cost_labor_dinero.toFormat(),
costs: c.cost_parts_dinero.add(c.cost_labor_dinero).toFormat(),
cost_additional:
c.cost_additional_dinero && c.cost_additional_dinero.toFormat(),
costs: c.costs_dinero.toFormat(),
gpdollars: c.gpdollars_dinero.toFormat(),
gppercent: formatGpPercent(
(
@@ -340,33 +360,33 @@ function GenerateCostingData(job) {
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
);
if (!acc.parts[partsProfitCenter])
acc.parts[partsProfitCenter] = Dinero();
acc.parts[partsProfitCenter] =
acc.parts[partsProfitCenter].add(partsAmount);
if (!acc.additional[partsProfitCenter])
acc.additional[partsProfitCenter] = Dinero();
acc.additional[partsProfitCenter] =
acc.additional[partsProfitCenter].add(partsAmount);
}
}
return acc;
},
{ parts: {}, labor: {} }
{ parts: {}, labor: {}, additional: {} }
);
if (!hasMapaLine) {
if (!jobLineTotalsByProfitCenter.parts[defaultProfits["MAPA"]])
jobLineTotalsByProfitCenter.parts[defaultProfits["MAPA"]] = Dinero();
jobLineTotalsByProfitCenter.parts[defaultProfits["MAPA"]] =
jobLineTotalsByProfitCenter.parts[defaultProfits["MAPA"]].add(
if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]])
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] = Dinero();
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]] =
jobLineTotalsByProfitCenter.additional[defaultProfits["MAPA"]].add(
Dinero({
amount: Math.round((job.rate_mapa || 0) * 100),
}).multiply(materialsHours.mapaHrs || 0)
);
}
if (!hasMashLine) {
if (!jobLineTotalsByProfitCenter.parts[defaultProfits["MASH"]])
jobLineTotalsByProfitCenter.parts[defaultProfits["MASH"]] = Dinero();
jobLineTotalsByProfitCenter.parts[defaultProfits["MASH"]] =
jobLineTotalsByProfitCenter.parts[defaultProfits["MASH"]].add(
if (!jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]])
jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]] = Dinero();
jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]] =
jobLineTotalsByProfitCenter.additional[defaultProfits["MASH"]].add(
Dinero({
amount: Math.round((job.rate_mash || 0) * 100),
}).multiply(materialsHours.mashHrs || 0)
@@ -381,54 +401,88 @@ function GenerateCostingData(job) {
)) ||
job.bodyshop.md_responsibility_centers.defaults;
const billTotalsByCostCenters = job.bills.reduce((bill_acc, bill_val) => {
//At the bill level.
bill_val.billlines.map((line_val) => {
//At the bill line level.
if (job.bodyshop.pbs_serialnumber || job.bodyshop.cdk_dealerid) {
if (!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]])
const billTotalsByCostCenters = job.bills.reduce(
(bill_acc, bill_val) => {
//At the bill level.
bill_val.billlines.map((line_val) => {
//At the bill line level.
if (job.bodyshop.pbs_serialnumber || job.bodyshop.cdk_dealerid) {
if (
!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]]
)
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] =
Dinero();
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] =
Dinero();
bill_acc[
selectedDmsAllocationConfig.costs[line_val.cost_center]
].add(
Dinero({
amount: Math.round((line_val.actual_cost || 0) * 100),
})
.multiply(line_val.quantity)
.multiply(bill_val.is_credit_memo ? -1 : 1)
);
} else {
const isAdditionalCostCenter =
// line_val.cost_center ===
// job.bodyshop.md_responsibility_centers.defaults.costs.PAS ||
// line_val.cost_center ===
// job.bodyshop.md_responsibility_centers.defaults.costs.PASL ||
line_val.cost_center ===
job.bodyshop.md_responsibility_centers.defaults.costs.TOW ||
line_val.cost_center ===
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA ||
line_val.cost_center ===
job.bodyshop.md_responsibility_centers.defaults.costs.MASH;
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] =
bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]].add(
Dinero({
amount: Math.round((line_val.actual_cost || 0) * 100),
})
.multiply(line_val.quantity)
.multiply(bill_val.is_credit_memo ? -1 : 1)
);
} else {
if (!bill_acc[line_val.cost_center])
bill_acc[line_val.cost_center] = Dinero();
if (isAdditionalCostCenter) {
if (!bill_acc.additionalCosts[line_val.cost_center])
bill_acc.additionalCosts[line_val.cost_center] = Dinero();
bill_acc[line_val.cost_center] = bill_acc[line_val.cost_center].add(
Dinero({
amount: Math.round((line_val.actual_cost || 0) * 100),
})
.multiply(line_val.quantity)
.multiply(bill_val.is_credit_memo ? -1 : 1)
);
}
bill_acc.additionalCosts[line_val.cost_center] =
bill_acc.additionalCosts[line_val.cost_center].add(
Dinero({
amount: Math.round((line_val.actual_cost || 0) * 100),
})
.multiply(line_val.quantity)
.multiply(bill_val.is_credit_memo ? -1 : 1)
);
} else {
if (!bill_acc[line_val.cost_center])
bill_acc[line_val.cost_center] = Dinero();
return null;
});
return bill_acc;
}, {});
bill_acc[line_val.cost_center] = bill_acc[line_val.cost_center].add(
Dinero({
amount: Math.round((line_val.actual_cost || 0) * 100),
})
.multiply(line_val.quantity)
.multiply(bill_val.is_credit_memo ? -1 : 1)
);
}
}
return null;
});
return bill_acc;
},
{ additionalCosts: {} }
);
//If the hourly rates for job costing are set, add them in.
if (job.bodyshop.jc_hourly_rates && job.bodyshop.jc_hourly_rates.mapa) {
if (
!billTotalsByCostCenters[
!billTotalsByCostCenters.additionalCosts[
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA
]
)
billTotalsByCostCenters[
billTotalsByCostCenters.additionalCosts[
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA
] = Dinero();
billTotalsByCostCenters[
billTotalsByCostCenters.additionalCosts[
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA
] = billTotalsByCostCenters[
] = billTotalsByCostCenters.additionalCosts[
job.bodyshop.md_responsibility_centers.defaults.costs.MAPA
].add(
Dinero({
@@ -442,16 +496,16 @@ function GenerateCostingData(job) {
if (job.bodyshop.jc_hourly_rates && job.bodyshop.jc_hourly_rates.mash) {
if (
!billTotalsByCostCenters[
!billTotalsByCostCenters.additionalCosts[
job.bodyshop.md_responsibility_centers.defaults.costs.MASH
]
)
billTotalsByCostCenters[
billTotalsByCostCenters.additionalCosts[
job.bodyshop.md_responsibility_centers.defaults.costs.MASH
] = Dinero();
billTotalsByCostCenters[
billTotalsByCostCenters.additionalCosts[
job.bodyshop.md_responsibility_centers.defaults.costs.MASH
] = billTotalsByCostCenters[
] = billTotalsByCostCenters.additionalCosts[
job.bodyshop.md_responsibility_centers.defaults.costs.MASH
].add(
Dinero({
@@ -511,9 +565,11 @@ function GenerateCostingData(job) {
const summaryData = {
totalLaborSales: Dinero({ amount: 0 }),
totalPartsSales: Dinero({ amount: 0 }),
totalAdditionalSales: Dinero({ amount: 0 }),
totalSales: Dinero({ amount: 0 }),
totalLaborCost: Dinero({ amount: 0 }),
totalPartsCost: Dinero({ amount: 0 }),
totalAdditionalCost: Dinero({ amount: 0 }),
totalCost: Dinero({ amount: 0 }),
totalLaborGp: Dinero({ amount: 0 }),
totalPartsGp: Dinero({ amount: 0 }),
@@ -533,14 +589,16 @@ function GenerateCostingData(job) {
jobLineTotalsByProfitCenter.labor[ccVal] || Dinero({ amount: 0 });
const sale_parts =
jobLineTotalsByProfitCenter.parts[ccVal] || Dinero({ amount: 0 });
const sale_additional =
jobLineTotalsByProfitCenter.additional[ccVal] || Dinero({ amount: 0 });
const cost_labor = ticketTotalsByCostCenter[ccVal] || Dinero({ amount: 0 });
const cost_parts = billTotalsByCostCenters[ccVal] || Dinero({ amount: 0 });
const cost_additional =
billTotalsByCostCenters.additionalCosts[ccVal] || Dinero({ amount: 0 });
const costs = (billTotalsByCostCenters[ccVal] || Dinero({ amount: 0 })).add(
ticketTotalsByCostCenter[ccVal] || Dinero({ amount: 0 })
);
const totalSales = sale_labor.add(sale_parts);
const costs = cost_labor.add(cost_parts).add(cost_additional);
const totalSales = sale_labor.add(sale_parts).add(sale_additional);
const gpdollars = totalSales.subtract(costs);
const gppercent = (
(gpdollars.getAmount() / totalSales.getAmount()) *
@@ -550,11 +608,13 @@ function GenerateCostingData(job) {
//Push summary data to avoid extra loop.
summaryData.totalLaborSales = summaryData.totalLaborSales.add(sale_labor);
summaryData.totalPartsSales = summaryData.totalPartsSales.add(sale_parts);
summaryData.totalSales = summaryData.totalSales
.add(sale_labor)
.add(sale_parts);
summaryData.totalAdditionalSales =
summaryData.totalAdditionalSales.add(sale_additional);
summaryData.totalSales = summaryData.totalSales.add(totalSales);
summaryData.totalLaborCost = summaryData.totalLaborCost.add(cost_labor);
summaryData.totalPartsCost = summaryData.totalPartsCost.add(cost_parts);
summaryData.totalAdditionalCost =
summaryData.totalAdditionalCost.add(cost_additional);
summaryData.totalCost = summaryData.totalCost.add(costs);
return {
@@ -564,14 +624,18 @@ function GenerateCostingData(job) {
sale_labor_dinero: sale_labor,
sale_parts: sale_parts && sale_parts.toFormat(),
sale_parts_dinero: sale_parts,
sales: sale_labor.add(sale_parts).toFormat(),
sales_dinero: sale_labor.add(sale_parts),
sale_additional: sale_additional && sale_additional.toFormat(),
sale_additional_dinero: sale_additional,
sales: totalSales.toFormat(),
sales_dinero: totalSales,
cost_parts: cost_parts && cost_parts.toFormat(),
cost_parts_dinero: cost_parts,
cost_labor: cost_labor && cost_labor.toFormat(),
cost_labor_dinero: cost_labor,
costs: cost_parts.add(cost_labor).toFormat(),
costs_dinero: cost_parts.add(cost_labor),
cost_additional: cost_additional && cost_additional.toFormat(),
cost_additional_dinero: cost_additional,
costs: costs.toFormat(),
costs_dinero: costs,
gpdollars_dinero: gpdollars,
gpdollars: gpdollars.toFormat(),
gppercent: formatGpPercent(gppercent),
@@ -675,6 +739,8 @@ const getAdditionalCostCenter = (jl, profitCenters) => {
return profitCenters["MAPA"];
} else if (lineDesc.includes("ats amount")) {
return profitCenters["ATS"];
} else if (lineDesc.includes("towing")) {
return profitCenters["TOW"];
} else {
return null;
}