Files
bodyshop/server/accounting/qb-receivables-lines.js
2024-03-19 10:54:25 -07:00

1000 lines
38 KiB
JavaScript

const DineroQbFormat = require("./accounting-constants").DineroQbFormat;
const Dinero = require("dinero.js");
const {DiscountNotAlreadyCounted} = require("../job/job-totals");
const logger = require("../utils/logger");
const InstanceManager = require("../utils/instanceMgr").default;
exports.default = function ({
bodyshop,
jobs_by_pk,
qbo = false,
items,
taxCodes,
classes,
}) {
const InvoiceLineAdd = [];
const responsibilityCenters = bodyshop.md_responsibility_centers;
const invoiceLineHash = {}; //The hash of cost and profit centers based on the center name.
//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;
//Create the invoice lines mapping.
jobs_by_pk.joblines.map((jobline) => {
if (jobline.db_ref === "936008") {
//If either of these DB REFs change, they also need to change in job-totals/job-costing calculations.
hasMapaLine = true;
}
if (jobline.db_ref === "936007") {
hasMashLine = true;
}
//Parts Lines Mappings.
if (jobline.profitcenter_part) {
//TODO:AIO This appears to be a net 0 change exept for default quantity as 0 instead of 1 for imex. Need to verify.
const discountAmount =
((jobline.prt_dsmk_m && jobline.prt_dsmk_m !== 0) ||
(jobline.prt_dsmk_p && jobline.prt_dsmk_p !== 0)) &&
DiscountNotAlreadyCounted(jobline, jobs_by_pk.joblines)
? jobline.prt_dsmk_m
? Dinero({amount: Math.round(jobline.prt_dsmk_m * 100)})
: Dinero({
amount: Math.round(jobline.act_price * 100),
})
.multiply(jobline.part_qty || 0)
.percentage(Math.abs(jobline.prt_dsmk_p || 0))
.multiply(jobline.prt_dsmk_p > 0 ? 1 : -1)
: Dinero();
let DineroAmount = Dinero({
amount: Math.round((jobline.act_price || 0) * 100),
})
.multiply(jobline.part_qty || 0)
.add(discountAmount);
const account = responsibilityCenters.profits.find(
(i) => jobline.profitcenter_part.toLowerCase() === i.name.toLowerCase()
);
if (!account) {
logger.log(
"qbxml-receivables-no-account",
"warn",
null,
jobline.id,
null
);
throw new Error(
`A matching account does not exist for the part allocation. Center: ${jobline.profitcenter_part}`
);
}
if (qbo) {
//Do the mapping as per QBO.
//Determine the Tax code grouping.
//Going to always assume that we need to apply GST.
const taxAccountCode = findTaxCode(
{
local: false,
federal: InstanceManager({imex: true, rome: false}),
state:
jobs_by_pk.state_tax_rate === 0
? false
: jobline.db_ref === "900511" ||
jobline.db_ref === "900510" ||
(jobline.mod_lb_hrs === 0 && //Extending IO-1375 as a part of IO-2023
jobline.act_price > 0 &&
jobline.lbr_op === "OP14")
? true
: jobline.tax_part,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const QboTaxId = InstanceManager({imex:taxCodes[taxAccountCode], rome: CheckQBOUSATaxID({
jobline: jobline,
type: "part",
job: jobs_by_pk,
}) })
if (!invoiceLineHash[account.name]) invoiceLineHash[account.name] = {};
if (!invoiceLineHash[account.name][QboTaxId]) {
invoiceLineHash[account.name][QboTaxId] = {
DetailType: "SalesItemLineDetail",
Amount: DineroAmount,
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value: items[account.accountitem],
},
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
};
} else {
invoiceLineHash[account.name][QboTaxId].Amount =
invoiceLineHash[account.name][QboTaxId].Amount.add(DineroAmount);
}
} else {
if (!invoiceLineHash[account.name]) {
invoiceLineHash[account.name] = {
ItemRef: {FullName: account.accountitem},
Desc: account.accountdesc,
Quantity: 1, //jobline.part_qty,
Amount: DineroAmount, //.toFormat(DineroQbFormat),
SalesTaxCodeRef:
InstanceManager({imex: {
FullName: "E",
}, rome:{
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode ||
"NON",
} })
,
};
} else {
invoiceLineHash[account.name].Amount =
invoiceLineHash[account.name].Amount.add(DineroAmount);
}
}
}
//End Parts line mappings.
// Labor Lines
if (jobline.profitcenter_labor && jobline.mod_lb_hrs) {
const DineroAmount = Dinero({
amount: Math.round(
jobs_by_pk[`rate_${jobline.mod_lbr_ty.toLowerCase()}`] * 100
),
}).multiply(jobline.mod_lb_hrs);
const account = responsibilityCenters.profits.find(
(i) => jobline.profitcenter_labor.toLowerCase() === i.name.toLowerCase()
);
if (!account) {
throw new Error(
`A matching account does not exist for the labor allocation. Center: ${jobline.profitcenter_labor}`
);
}
if (qbo) {
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: InstanceManager({imex: true, rome: false}),
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const QboTaxId = InstanceManager({imex: taxCodes[taxAccountCode], rome: CheckQBOUSATaxID({jobline: jobline, type: "labor"})})
if (!invoiceLineHash[account.name]) invoiceLineHash[account.name] = {};
if (!invoiceLineHash[account.name][QboTaxId]) {
invoiceLineHash[account.name][QboTaxId] = {
DetailType: "SalesItemLineDetail",
Amount: DineroAmount,
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value: items[account.accountitem],
},
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
};
} else {
invoiceLineHash[account.name][QboTaxId].Amount =
invoiceLineHash[account.name][QboTaxId].Amount.add(DineroAmount);
}
} else {
if (!invoiceLineHash[account.name]) {
invoiceLineHash[account.name] = {
ItemRef: {FullName: account.accountitem},
Desc: account.accountdesc,
Quantity: 1, // jobline.mod_lb_hrs,
Amount: DineroAmount,
//Amount: DineroAmount.toFormat(DineroQbFormat),
SalesTaxCodeRef:
InstanceManager({imex: {
FullName:"E"
},
rome: {
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode ||
"NON",
}
})
,
};
} else {
invoiceLineHash[account.name].Amount =
invoiceLineHash[account.name].Amount.add(DineroAmount);
}
}
}
});
if (!hasMapaLine && jobs_by_pk.job_totals.rates.mapa.total.amount > 0) {
// console.log("Adding MAPA Line Manually.");
const mapaAccountName = responsibilityCenters.defaults.profits.MAPA;
const mapaAccount = responsibilityCenters.profits.find(
(c) => c.name === mapaAccountName
);
if (mapaAccount) {
if (qbo) {
//Add QBO MAPA
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: InstanceManager({imex: true, rome: false}),
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const QboTaxId = InstanceManager({imex:taxCodes[taxAccountCode] , rome: CheckQBOUSATaxID({
// jobline: jobline,
job: jobs_by_pk,
type: "materials",
})});
if (!invoiceLineHash[mapaAccount.name])
invoiceLineHash[mapaAccount.name] = {};
if (!invoiceLineHash[mapaAccount.name][QboTaxId]) {
invoiceLineHash[mapaAccount.name][QboTaxId] = {
DetailType: "SalesItemLineDetail",
Amount: Dinero(jobs_by_pk.job_totals.rates.mapa.total),
SalesItemLineDetail: {
ItemRef: {
value: items[mapaAccount.accountitem],
},
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
};
} else {
invoiceLineHash[mapaAccount.name][QboTaxId].Amount = invoiceLineHash[
mapaAccount.name
][QboTaxId].Amount.add(
Dinero(jobs_by_pk.job_totals.rates.mapa.total)
);
}
} else {
InvoiceLineAdd.push({
ItemRef: {FullName: mapaAccount.accountitem},
Desc: mapaAccount.accountdesc,
Quantity: 1,
Amount: Dinero(jobs_by_pk.job_totals.rates.mapa.total).toFormat(
DineroQbFormat
),
SalesTaxCodeRef:
InstanceManager({imex: {
FullName: "E",
},
rome: {
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON",
}
})
,
});
}
} else {
//console.log("NO MAPA ACCOUNT FOUND!!");
}
}
if (!hasMashLine && jobs_by_pk.job_totals.rates.mash.total.amount > 0) {
// console.log("Adding MASH Line Manually.");
const mashAccountName = responsibilityCenters.defaults.profits.MASH;
const mashAccount = responsibilityCenters.profits.find(
(c) => c.name === mashAccountName
);
if (mashAccount) {
if (qbo) {
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: InstanceManager({imex: true, rome: false}),
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const QboTaxId = InstanceManager({imex:taxCodes[taxAccountCode], rome: CheckQBOUSATaxID({
// jobline: jobline,
job: jobs_by_pk,
type: "materials",
})});
if (!invoiceLineHash[mashAccount.name])
invoiceLineHash[mashAccount.name] = {};
if (!invoiceLineHash[mashAccount.name][QboTaxId]) {
invoiceLineHash[mashAccount.name][QboTaxId] = {
DetailType: "SalesItemLineDetail",
Amount: Dinero(jobs_by_pk.job_totals.rates.mash.total),
SalesItemLineDetail: {
ItemRef: {
value: items[mashAccount.accountitem],
},
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
};
} else {
invoiceLineHash[mashAccount.name][QboTaxId].Amount = invoiceLineHash[
mashAccount.name
][QboTaxId].Amount.add(
Dinero(jobs_by_pk.job_totals.rates.mash.total)
);
}
} else {
InvoiceLineAdd.push({
ItemRef: {FullName: mashAccount.accountitem},
Desc: mashAccount.accountdesc,
Quantity: 1,
Amount: Dinero(jobs_by_pk.job_totals.rates.mash.total).toFormat(
DineroQbFormat
),
SalesTaxCodeRef:
InstanceManager({imex:
{
FullName: "E",
},
rome: {
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON",
}
})
,
});
}
} else {
// console.log("NO MASH ACCOUNT FOUND!!");
}
}
if (qbo) {
Object.keys(invoiceLineHash).forEach((key) => {
Object.keys(invoiceLineHash[key]).forEach((key2) => {
const account = responsibilityCenters.profits.find(
(p) => p.name === key
);
InvoiceLineAdd.push({
...invoiceLineHash[key][key2],
...(account ? {Description: account.accountdesc} : {}),
Amount: invoiceLineHash[key][key2].Amount.toFormat(DineroQbFormat),
});
});
});
} else {
Object.keys(invoiceLineHash).forEach((key) => {
InvoiceLineAdd.push({
...invoiceLineHash[key],
Amount: invoiceLineHash[key].Amount.toFormat(DineroQbFormat),
});
});
}
//Convert the hash to an array.
//Add Towing, storage and adjustment lines.
///TODO:AIO Check if this towing check works for imex and not just Rome.
if (jobs_by_pk.job_totals.additional.towing.amount > 0) {
if (qbo) {
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: InstanceManager({imex:true, rome:false}) ,
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const account = responsibilityCenters.profits.find(
(c) => c.name === responsibilityCenters.defaults.profits["TOW"]
);
const QboTaxId = InstanceManager({imex:taxCodes[taxAccountCode], rome: CheckQBOUSATaxID({
// jobline: jobline,
job: jobs_by_pk,
type: "towing",
}) })
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
///TODO:AIO Check if this towing check works for imex and not just Rome.
Amount: Dinero(jobs_by_pk.job_totals.additional.towing).toFormat(
DineroQbFormat
),
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value: items[account.accountitem],
},
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: responsibilityCenters.profits.find(
(c) => c.name === responsibilityCenters.defaults.profits["TOW"]
).accountitem,
},
Desc: "Towing",
Quantity: 1,
///TODO:AIO Check if this towing check works for imex and not just Rome.
Amount: Dinero(jobs_by_pk.job_totals.additional.towing).toFormat(
DineroQbFormat
),
SalesTaxCodeRef:
InstanceManager({imex: {
FullName: "E",
},
rome: {
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON",
}}),
});
}
}
///TODO:AIO Check if this storage check works for imex and not just Rome.
if (jobs_by_pk.job_totals.additional.storage.amount > 0) {
if (qbo) {
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: InstanceManager({imex: true, rome:false }) ,
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const account = responsibilityCenters.profits.find(
(c) => c.name === responsibilityCenters.defaults.profits["TOW"]
);
const QboTaxId = InstanceManager({imex:taxCodes[taxAccountCode], rome: CheckQBOUSATaxID({
// jobline: jobline,
job: jobs_by_pk,
type: "storage",
}) })
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
///TODO:AIO Check if this storage check works for imex and not just Rome.
Amount: Dinero(
jobs_by_pk.job_totals.additional.storage.amount
).toFormat(DineroQbFormat),
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value: items[account.accountitem],
},
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: responsibilityCenters.profits.find(
(c) => c.name === responsibilityCenters.defaults.profits["TOW"]
).accountitem,
},
Desc: "Storage",
Quantity: 1,
///TODO:AIO Check if this storage check works for imex and not just Rome.
Amount: Dinero(
jobs_by_pk.job_totals.additional.storage.amount
).toFormat(DineroQbFormat),
SalesTaxCodeRef:
InstanceManager({imex:{
FullName: "E",
}, rome: {
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON",
} })
,
});
}
}
if (
jobs_by_pk.adjustment_bottom_line &&
jobs_by_pk.adjustment_bottom_line !== 0
) {
if (qbo) {
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: InstanceManager({imex: true, rome: false}) ,
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const QboTaxId = InstanceManager({imex: taxCodes[taxAccountCode], rome: CheckQBOUSATaxID({
// jobline: jobline,
type: "adjustment",
job: jobs_by_pk,
})})
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: Dinero({
amount: Math.round((jobs_by_pk.adjustment_bottom_line || 0) * 100),
}).toFormat(DineroQbFormat),
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value: items[responsibilityCenters.refund.accountitem],
},
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: responsibilityCenters.refund.accountitem,
},
Desc: "Adjustment",
Quantity: 1,
Amount: Dinero({
amount: Math.round((jobs_by_pk.adjustment_bottom_line || 0) * 100),
}).toFormat(DineroQbFormat),
SalesTaxCodeRef:
InstanceManager({imex:{
FullName: "E",
},
rome: {
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON",
}
})
,
});
}
}
//Add tax lines
const job_totals = jobs_by_pk.job_totals;
const federal_tax = Dinero(job_totals.totals.federal_tax);
const state_tax = Dinero(job_totals.totals.state_tax);
const local_tax = Dinero(job_totals.totals.local_tax);
const RulesetToUse = InstanceManager({ imex: 'CANADA', rome: 'US', promanager: 'US' });
if(RulesetToUse === "CANADA"){
if (federal_tax.getAmount() > 0) {
if (qbo) {
// do qbo
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName:
bodyshop.md_responsibility_centers.taxes.federal.accountitem,
},
Desc: bodyshop.md_responsibility_centers.taxes.federal.accountdesc,
Amount: federal_tax.toFormat(DineroQbFormat),
});
}
}
if (state_tax.getAmount() > 0) {
if (qbo) {
// do qbo
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: bodyshop.md_responsibility_centers.taxes.state.accountitem,
},
Desc: bodyshop.md_responsibility_centers.taxes.state.accountdesc,
Amount: state_tax.toFormat(DineroQbFormat),
});
}
}
if (local_tax.getAmount() > 0) {
if (qbo) {
// do qbo
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: bodyshop.md_responsibility_centers.taxes.local.accountitem,
},
Desc: bodyshop.md_responsibility_centers.taxes.local.accountdesc,
Amount: local_tax.toFormat(DineroQbFormat),
});
}
}
//Region Specific
const {ca_bc_pvrt} = jobs_by_pk;
if (ca_bc_pvrt) {
if (qbo) {
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: Dinero({amount: (ca_bc_pvrt || 0) * 100}).toFormat(
DineroQbFormat
),
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value: items["PVRT"],
},
Qty: 1,
TaxCodeRef: {
value:
taxCodes[
findTaxCode(
{
local: false,
federal: true,
state: false,
},
bodyshop.md_responsibility_centers.sales_tax_codes
)
],
},
},
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: bodyshop.md_responsibility_centers.taxes.state.accountitem,
},
Desc: "PVRT",
Amount: Dinero({amount: (ca_bc_pvrt || 0) * 100}).toFormat(
DineroQbFormat
),
});
}
}
//QB USA with GST
//This was required for the No. 1 Collision Group.
if (
bodyshop.accountingconfig &&
bodyshop.accountingconfig.qbo &&
bodyshop.accountingconfig.qbo_usa &&
bodyshop.region_config.includes("CA_")
) {
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: Dinero(jobs_by_pk.job_totals.totals.federal_tax).toFormat(
DineroQbFormat
),
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value:
items[bodyshop.md_responsibility_centers.taxes.federal.accountitem],
},
Qty: 1,
},
});
}
}
else{
//Handle insurance profile adjustments
Object.keys(job_totals.parts.adjustments).forEach((key) => {
if (qbo) {
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: process.env.COUNTRY === "USA" ? false : true,
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const account = responsibilityCenters.profits.find(
(c) => c.name === responsibilityCenters.defaults.profits[key]
);
const QboTaxId =
process.env.COUNTRY === "USA"
? CheckQBOUSATaxID({
// jobline: jobline,
job: jobs_by_pk,
type: "storage",
})
: taxCodes[taxAccountCode];
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: Dinero(job_totals.parts.adjustments[key]).toFormat(
DineroQbFormat
),
Description: `${account.accountdesc} - Adjustment`,
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value: items[account.accountitem],
},
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: responsibilityCenters.profits.find(
(c) => c.name === responsibilityCenters.defaults.profits[key]
).accountitem,
},
Desc: "Storage",
Quantity: 1,
Amount: Dinero(job_totals.parts.adjustments[key]).toFormat(
DineroQbFormat
),
SalesTaxCodeRef: {
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON",
},
});
}
});
const QboTaxId =
process.env.COUNTRY === "USA"
? CheckQBOUSATaxID({
// jobline: jobline,
type: "adjustment",
job: jobs_by_pk,
})
: taxCodes[taxAccountCode];
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
const taxAmount = Dinero(
job_totals.totals.us_sales_tax_breakdown[`ty${tyCounter}Tax`]
);
console.log(`Tax ${tyCounter}`, taxAmount.toFormat());
if (taxAmount.getAmount() > 0) {
if (qbo) {
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: taxAmount.toFormat(DineroQbFormat),
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value:
items[
responsibilityCenters.taxes[`tax_ty${tyCounter}`].accountitem
],
},
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName:
bodyshop.md_responsibility_centers.taxes[`tax_ty${tyCounter}`]
.accountitem,
},
Desc: bodyshop.md_responsibility_centers.taxes[`tax_ty${tyCounter}`]
.accountdesc,
Amount: taxAmount.toFormat(DineroQbFormat),
});
}
}
}
}
if (!qbo && InvoiceLineAdd.length === 0) {
//Handle the scenario where there is a $0 sale invoice.
InvoiceLineAdd.push({
Desc: "No estimate lines.",
});
}
//Check if there are multiple payers. If there are, add a deduction line and make sure we create new invoices.
if (
jobs_by_pk.qb_multiple_payers &&
jobs_by_pk.qb_multiple_payers.length > 0
) {
jobs_by_pk.qb_multiple_payers.forEach((payer) => {
if (qbo) {
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: Dinero({
amount: Math.round((payer.amount || 0) * 100) * -1,
}).toFormat(DineroQbFormat),
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value:
items[responsibilityCenters.qb_multiple_payers?.accountitem],
},
Qty: 1,
TaxCodeRef: {
value:
taxCodes[
findTaxCode(
{
local: false,
federal: false,
state: false,
},
bodyshop.md_responsibility_centers.sales_tax_codes
)
],
},
},
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: responsibilityCenters.qb_multiple_payers?.accountitem,
},
Desc: `${payer.name} Liability`,
Amount: Dinero({
amount: Math.round((payer.amount || 0) * 100) * -1,
}).toFormat(DineroQbFormat),
});
}
});
}
return InvoiceLineAdd;
};
const findTaxCode = ({local, state, federal}, taxcode) => {
const t = taxcode.filter(
(t) =>
!!t.local === !!local &&
!!t.state === !!state &&
!!t.federal === !!federal
);
if (t.length === 1) {
return t[0].code;
} else if (t.length > 1) {
return "Multiple Tax Codes Match";
} else {
return "";
}
};
exports.findTaxCode = findTaxCode;
exports.createMultiQbPayerLines = function ({
bodyshop,
jobs_by_pk,
qbo = false,
items,
taxCodes,
classes,
payer,
}) {
const InvoiceLineAdd = [];
const responsibilityCenters = bodyshop.md_responsibility_centers;
const invoiceLineHash = {}; //The hash of cost and profit centers based on the center name.
if (qbo) {
//Going to always assume that we need to apply GST and PST for labor.
const taxAccountCode = findTaxCode(
{
local: false,
federal: false,
state: false,
},
bodyshop.md_responsibility_centers.sales_tax_codes
);
const QboTaxId = taxCodes[taxAccountCode];
InvoiceLineAdd.push({
DetailType: "SalesItemLineDetail",
Amount: Dinero({
amount: Math.round((payer.amount || 0) * 100),
}).toFormat(DineroQbFormat),
SalesItemLineDetail: {
...(jobs_by_pk.class
? {ClassRef: {value: classes[jobs_by_pk.class]}}
: {}),
ItemRef: {
value: items[responsibilityCenters.qb_multiple_payers?.accountitem],
},
TaxCodeRef: {
value: QboTaxId,
},
Qty: 1,
},
});
} else {
InvoiceLineAdd.push({
ItemRef: {
FullName: responsibilityCenters.qb_multiple_payers?.accountitem,
},
Desc: `${payer.name} Liability`,
Quantity: 1,
Amount: Dinero({
amount: Math.round((payer.amount || 0) * 100),
}).toFormat(DineroQbFormat),
SalesTaxCodeRef:
InstanceManager({imex: {
FullName: "E",
}, rome:{
FullName:
bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON",
} })
});
}
return InvoiceLineAdd;
};
function CheckQBOUSATaxID({jobline, job, type}) {
//Replacing this to be all non-taxable items with the refactor of parts tax rates.
return "NON";
// if (type === "labor") {
// return jobline.lbr_tax ? "TAX" : "NON";
// } else if (type === "part") {
// return jobline.tax_part ? "TAX" : "NON";
// } else if (type === "materials") {
// return job.tax_paint_mat_rt > 0 ? "TAX" : "NON";
// } else if (type === " towing") {
// return true ? "TAX" : "NON";
// } else if (type === "adjustment") {
// return false ? "TAX" : "NON";
// } else {
// throw new Error(`Unknown type to calculate tax id: ${type} `);
// }
}