Merged in release/2022-01-21 (pull request #353)

release/2022-01-21

Approved-by: Patrick Fic
This commit is contained in:
Patrick Fic
2022-01-21 00:20:46 +00:00
4 changed files with 79 additions and 54 deletions

View File

@@ -12,6 +12,7 @@ import ProductionAlert from "../production-list-columns/production-list-columns.
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component"; import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component"; import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
import "./production-board-card.styles.scss"; import "./production-board-card.styles.scss";
import moment from "moment";
export default function ProductionBoardCard( export default function ProductionBoardCard(
technician, technician,
@@ -37,6 +38,15 @@ export default function ProductionBoardCard(
// employee_csr = bodyshop.employees.find((e) => e.id === card.employee_csr); // employee_csr = bodyshop.employees.find((e) => e.id === card.employee_csr);
// } // }
const pastDueAlert =
!!card.scheduled_completion &&
((moment().isSameOrAfter(moment(card.scheduled_completion), "day") &&
"production-completion-past") ||
(moment()
.add(1, "day")
.isSame(moment(card.scheduled_completion), "day") &&
"production-completion-soon"));
return ( return (
<Card <Card
className="react-kanban-card imex-kanban-card" className="react-kanban-card imex-kanban-card"
@@ -145,7 +155,7 @@ export default function ProductionBoardCard(
cardSettings.scheduled_completion && cardSettings.scheduled_completion &&
card.scheduled_completion && ( card.scheduled_completion && (
<Col span={cardSettings && cardSettings.compact ? 24 : 12}> <Col span={cardSettings && cardSettings.compact ? 24 : 12}>
<Space> <Space className={pastDueAlert}>
<CalendarOutlined /> <CalendarOutlined />
<DateTimeFormatter format="MM/DD"> <DateTimeFormatter format="MM/DD">
{card.scheduled_completion} {card.scheduled_completion}

View File

@@ -37,6 +37,7 @@ exports.default = async (req, res) => {
//Query for the List of Bodyshop Clients. //Query for the List of Bodyshop Clients.
logger.log("autohouse-start", "DEBUG", "api", null, null); logger.log("autohouse-start", "DEBUG", "api", null, null);
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS); const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
639;
const allxmlsToUpload = []; const allxmlsToUpload = [];
const allErrors = []; const allErrors = [];
@@ -47,16 +48,19 @@ exports.default = async (req, res) => {
}); });
const erroredJobs = []; const erroredJobs = [];
try { try {
const { jobs } = await client.request(queries.AUTOHOUSE_QUERY, { const { jobs, bodyshops_by_pk } = await client.request(
bodyshopid: bodyshop.id, queries.AUTOHOUSE_QUERY,
start: moment().subtract(3, "days").startOf("day"), {
}); bodyshopid: bodyshop.id,
start: moment().subtract(3, "days").startOf("day"),
}
);
const autoHouseObject = { const autoHouseObject = {
AutoHouseExport: { AutoHouseExport: {
RepairOrder: jobs.map((j) => RepairOrder: jobs.map((j) =>
CreateRepairOrderTag( CreateRepairOrderTag(
{ ...j, bodyshop }, { ...j, bodyshop: bodyshops_by_pk },
function ({ job, error }) { function ({ job, error }) {
erroredJobs.push({ job: job, error: error.toString() }); erroredJobs.push({ job: job, error: error.toString() });
} }
@@ -114,12 +118,12 @@ exports.default = async (req, res) => {
} }
} }
// for (const xmlObj of allxmlsToUpload) { for (const xmlObj of allxmlsToUpload) {
// fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml); fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
// } }
// res.json(allxmlsToUpload); res.json(allxmlsToUpload);
// return; return;
let sftp = new Client(); let sftp = new Client();
sftp.on("error", (errors) => sftp.on("error", (errors) =>
@@ -403,21 +407,23 @@ const CreateRepairOrderTag = (job, errorCallback) => {
// AmountDue: null, // AmountDue: null,
// }, // },
RevisedTotals: { RevisedTotals: {
BodyHours: job.job_totals.rates.lab.hours, BodyHours: job.job_totals.rates.lab.hours.toFixed(2),
BodyRepairHours: job.joblines BodyRepairHours: job.joblines
.filter((line) => repairOpCodes.includes(line.lbr_op)) .filter((line) => repairOpCodes.includes(line.lbr_op))
.reduce((acc, val) => acc + val.mod_lb_hrs, 0), .reduce((acc, val) => acc + val.mod_lb_hrs, 0)
.toFixed(2),
BodyReplaceHours: job.joblines BodyReplaceHours: job.joblines
.filter((line) => replaceOpCodes.includes(line.lbr_op)) .filter((line) => replaceOpCodes.includes(line.lbr_op))
.reduce((acc, val) => acc + val.mod_lb_hrs, 0), .reduce((acc, val) => acc + val.mod_lb_hrs, 0)
RefinishHours: job.job_totals.rates.lar.hours, .toFixed(2),
MechanicalHours: job.job_totals.rates.lam.hours, RefinishHours: job.job_totals.rates.lar.hours.toFixed(2),
StructuralHours: job.job_totals.rates.las.hours, MechanicalHours: job.job_totals.rates.lam.hours.toFixed(2),
StructuralHours: job.job_totals.rates.las.hours.toFixed(2),
ElectricalHours: job.job_totals.rates.lae.hours, ElectricalHours: job.job_totals.rates.lae.hours.toFixed(2),
FrameHours: job.job_totals.rates.laf.hours, FrameHours: job.job_totals.rates.laf.hours.toFixed(2),
GlassHours: job.job_totals.rates.lag.hours, GlassHours: job.job_totals.rates.lag.hours.toFixed(2),
DetailHours: job.job_totals.rates.lad.hours, DetailHours: job.job_totals.rates.lad.hours.toFixed(2),
LaborMiscHours: 0, LaborMiscHours: 0,
PartsTotal: Dinero(job.job_totals.parts.parts.total).toFormat( PartsTotal: Dinero(job.job_totals.parts.parts.total).toFormat(
@@ -508,11 +514,11 @@ const CreateRepairOrderTag = (job, errorCallback) => {
PMTotal: Dinero(job.job_totals.rates.mapa.total).toFormat( PMTotal: Dinero(job.job_totals.rates.mapa.total).toFormat(
AHDineroFormat AHDineroFormat
), ),
PMTotalCost: 0, PMTotalCost: repairCosts.PMTotalCost.toFormat(AHDineroFormat),
BMTotal: Dinero(job.job_totals.rates.mash.total).toFormat( BMTotal: Dinero(job.job_totals.rates.mash.total).toFormat(
AHDineroFormat AHDineroFormat
), ),
BMTotalCost: 0, BMTotalCost: repairCosts.BMTotalCost.toFormat(AHDineroFormat),
MiscTotal: 0, MiscTotal: 0,
MiscTotalCost: 0, MiscTotalCost: 0,
TowingTotal: Dinero(job.job_totals.additional.towing).toFormat( TowingTotal: Dinero(job.job_totals.additional.towing).toFormat(
@@ -729,7 +735,7 @@ const StatusMapping = (status, md_ro_statuses) => {
else if (status === default_delivered) return "DEL"; else if (status === default_delivered) return "DEL";
else if (status === default_invoiced || status === default_exported) else if (status === default_invoiced || status === default_exported)
return "CLO"; return "CLO";
else if (status === default_void) return "CLO"; else if (status === default_void) return "VOID";
else if (md_ro_statuses.production_statuses.includes(status)) return "IPR"; else if (md_ro_statuses.production_statuses.includes(status)) return "IPR";
else return "UNDEFINED"; else return "UNDEFINED";
@@ -739,12 +745,7 @@ const StatusMapping = (status, md_ro_statuses) => {
const GenerateDetailLines = (line, statuses) => { const GenerateDetailLines = (line, statuses) => {
const ret = { const ret = {
BackOrdered: line.status === statuses.default_bo ? "1" : "0", BackOrdered: line.status === statuses.default_bo ? "1" : "0",
Cost: Cost: (line.billlines[0] && line.billlines[0].actual_cost.toFixed(2)) || 0,
(line.billlines[0] &&
(line.billlines[0].actual_cost * line.billlines[0].quantity).toFixed(
2
)) ||
0,
//Critical: null, //Critical: null,
Description: line.line_desc || "", Description: line.line_desc || "",
DiscountMarkup: line.prt_dsmk_m || 0, DiscountMarkup: line.prt_dsmk_m || 0,
@@ -760,17 +761,22 @@ const GenerateDetailLines = (line, statuses) => {
"", "",
OriginalCost: null, OriginalCost: null,
OriginalInvoiceNumber: null, OriginalInvoiceNumber: null,
PriceEach: (line.billlines[0] && line.billlines[0].retail_price) || 0, PriceEach: line.act_price || 0,
PartNumber: _.escape(line.oem_partno), PartNumber: _.escape(line.oem_partno),
ProfitPercent: null, ProfitPercent: null,
PurchaseOrderNumber: null, PurchaseOrderNumber: null,
Qty: line.part_qty || 0, Qty: line.part_qty || 0,
Status: line.status || "", Status: line.status || "",
SupplementNumber: line.line_ind || "", SupplementNumber: line.line_ind ? line.line_ind.replace(/[^\d.-]/g, "") : 0,
Type: line.part_type || "", Type: line.part_type || "",
Vendor: (line.billlines[0] && line.billlines[0].bill.vendor.name) || "", Vendor: (line.billlines[0] && line.billlines[0].bill.vendor.name) || "",
VendorPaid: null, VendorPaid: null,
VendorPrice: (line.billlines[0] && line.billlines[0].actual_price) || 0, VendorPrice:
(line.billlines[0] &&
(line.billlines[0].actual_price * line.billlines[0].quantity).toFixed(
2
)) ||
0,
Deleted: null, Deleted: null,
ExpectedOn: null, ExpectedOn: null,
ReceivedOn: ReceivedOn:
@@ -779,7 +785,7 @@ const GenerateDetailLines = (line, statuses) => {
OrderedBy: null, OrderedBy: null,
ShipVia: null, ShipVia: null,
VendorContact: null, VendorContact: null,
EstimateAmount: line.act_price * line.part_qty || 0, //Rebecca EstimateAmount: (line.act_price * line.part_qty).toFixed(2) || 0, //Rebecca
}; };
return ret; return ret;
}; };

View File

@@ -543,6 +543,23 @@ exports.QUERY_EMPLOYEE_PIN = `query QUERY_EMPLOYEE_PIN($shopId: uuid!, $employee
}`; }`;
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshopid: uuid!) { exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshopid: uuid!) {
bodyshops_by_pk(id: $bodyshopid){
id
shopname
address1
city
state
zip_post
country
phone
md_ro_statuses
md_order_statuses
autohouseid
md_responsibility_centers
jc_hourly_rates
}
jobs(where: {_and: [{converted: {_eq: true}}, {updated_at: {_gt: $start}}, {shopid: {_eq: $bodyshopid}}]}) { jobs(where: {_and: [{converted: {_eq: true}}, {updated_at: {_gt: $start}}, {shopid: {_eq: $bodyshopid}}]}) {
id id
ro_number ro_number
@@ -608,21 +625,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshop
job_totals job_totals
driveable driveable
parts_tax_rates parts_tax_rates
bodyshop {
id
shopname
address1
city
state
zip_post
country
phone
md_ro_statuses
md_order_statuses
autohouseid
md_responsibility_centers
jc_hourly_rates
}
joblines(where: {removed: {_eq: false}}) { joblines(where: {removed: {_eq: false}}) {
id id
line_no line_no

View File

@@ -375,9 +375,11 @@ function GenerateCostingData(job) {
//Is it a DMS Setup? //Is it a DMS Setup?
const selectedDmsAllocationConfig = const selectedDmsAllocationConfig =
job.bodyshop.md_responsibility_centers.dms_defaults.find( (job.bodyshop.md_responsibility_centers.dms_defaults &&
(d) => d.name === job.dms_allocation job.bodyshop.md_responsibility_centers.dms_defaults.find(
) || job.bodyshop.md_responsibility_centers.defaults; (d) => d.name === job.dms_allocation
)) ||
job.bodyshop.md_responsibility_centers.defaults;
const billTotalsByCostCenters = job.bills.reduce((bill_acc, bill_val) => { const billTotalsByCostCenters = job.bills.reduce((bill_acc, bill_val) => {
//At the bill level. //At the bill level.
@@ -466,12 +468,16 @@ function GenerateCostingData(job) {
//At the invoice level. //At the invoice level.
if (job.bodyshop.pbs_serialnumber || job.bodyshop.cdk_dealerid) { if (job.bodyshop.pbs_serialnumber || job.bodyshop.cdk_dealerid) {
if (!ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]]) if (
!ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]]
)
ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]] = ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]] =
Dinero(); Dinero();
ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]] = ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]] =
ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]].add( ticket_acc[
selectedDmsAllocationConfig.costs[ticket_val.ciecacode]
].add(
Dinero({ Dinero({
amount: Math.round((ticket_val.rate || 0) * 100), amount: Math.round((ticket_val.rate || 0) * 100),
}).multiply( }).multiply(