const path = require("path"); const queries = require("../graphql-client/queries"); const Dinero = require("dinero.js"); const moment = require("moment"); var builder = require("xmlbuilder2"); const _ = require("lodash"); require("dotenv").config({ path: path.resolve( process.cwd(), `.env.${process.env.NODE_ENV || "development"}` ), }); const client = require("../graphql-client/graphql-client").client; const AHDineroFormat = "0.00"; const AhDateFormat = "MMDDYYYY"; exports.default = async (req, res) => { //Get Client Dataset. const { jobs } = await client.request(queries.AUTOHOUSE_QUERY); const erroredJobs = []; const autoHouseObject = { AutoHouseExport: { RepairOrder: jobs.map((j) => CreateRepairOrderTag(j, (job, error) => { erroredJobs.push({ job, error }); }) ), }, }; console.log("***Number of Failed jobs***: ", erroredJobs.length); var ret = builder .create(autoHouseObject, { version: "1.0", encoding: "UTF-8", }) .end({ pretty: true }); //***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml res.type("application/xml"); //res.sendFile(ret); res.send(ret); }; const CreateRepairOrderTag = (job, errorCallback) => { //Level 2 try { const ret = { RepairOrderInformation: { ShopInternalName: job.bodyshop.autohouseid, ID: job.id, RO: job.ro_number, Est: job.id, //We no longer use estimate id. GUID: job.id, TransType: StatusMapping(job.status, job.bodyshop.md_ro_statuses), ShopName: job.bodyshop.shopname, ShopAddress: job.bodyshop.address1, ShopCity: job.bodyshop.city, ShopState: job.bodyshop.state, ShopZip: job.bodyshop.zip_post, ShopPhone: job.bodyshop.phone, EstimatorID: `${job.est_ct_fn} ${job.est_ct_ln}`, EstimatorName: `${job.est_ct_fn} ${job.est_ct_ln}`, }, CustomerInformation: { FirstName: job.ownr_fn, LastName: job.ownr_ln, Street: job.ownr_addr1, City: job.ownr_city, State: job.ownr_st, Zip: job.ownr_zip, Phone1: job.ownr_ph1, Phone2: null, Phone2Extension: null, Phone3: null, Phone3Extension: null, FileComments: null, Source: null, Email: job.ownr_ea, RetWhsl: null, Cat: null, InsuredorClaimantFlag: null, }, VehicleInformation: { Year: job.v_model_yr, Make: job.v_make_desc, Model: job.v_model_desc, VIN: job.v_vin, License: job.plate_no, MileageIn: job.kmin, Vehiclecolor: job.v_color, VehicleProductionDate: null, VehiclePaintCode: null, VehicleTrimCode: null, VehicleBodyStyle: null, DriveableFlag: job.tlos_ind ? "Y" : "N", }, InsuranceInformation: { InsuranceCo: job.ins_co_nm, CompanyName: job.ins_co_nm, Address: job.ins_addr1, City: job.ins_addr1, State: job.ins_city, Zip: job.ins_zip, Phone: job.ins_ph1, Fax: null, ClaimType: null, LossType: null, Policy: null, Claim: job.clm_no, InsuredLastName: null, InsuredFirstName: null, ClaimantLastName: null, ClaimantFirstName: null, Assignment: null, InsuranceAgentLastName: null, InsuranceAgentFirstName: null, InsAgentPhone: null, InsideAdjuster: null, OutsideAdjuster: null, }, Dates: { DateofLoss: job.loss_date && moment(job.loss_date).format(AhDateFormat), InitialCustomerContactDate: null, FirstFollowUpDate: null, ReferralDate: null, EstimateAppointmentDate: null, SecondFollowUpDate: null, AssignedDate: null, EstComplete: null, CustomerAuthorizationDate: null, InsuranceAuthorizationDate: null, DateOpened: job.date_open && moment(job.date_open).format(AhDateFormat), ScheduledArrivalDate: job.scheduled_in && moment(job.scheduled_in).format(AhDateFormat), CarinShop: job.actual_in && moment(job.actual_in).format(AhDateFormat), InsInspDate: null, StartDate: null, PartsOrder: null, TeardownHold: null, SupplementSubmittedDate: null, SupplementApprovedDate: null, AssntoBody: null, AssntoMech: null, AssntoPaint: null, AssntoDetail: null, PromiseDate: job.scheduled_completion && moment(job.scheduled_completion).format(AhDateFormat), InsuranceTargetOut: null, CarComplete: job.actual_completion && moment(job.actual_completion).format(AhDateFormat), DeliveryAppointmentDate: job.scheduled_delivery && moment(job.scheduled_delivery).format(AhDateFormat), DateClosed: job.date_invoiced && moment(job.date_invoiced).format(AhDateFormat), CustomerPaidInFullDate: null, InsurancePaidInFullDate: null, CustPickup: job.actual_delivery && moment(job.actual_delivery).format(AhDateFormat), AccountPostedDate: job.date_exported && moment(job.date_exported).format(AhDateFormat), CSIProcessedDate: null, ThankYouLetterSent: null, AdditionalFollowUpDate: null, }, Rates: { BodyRate: job.rate_lab, RefinishRate: job.rate_lar, MechanicalRate: job.rate_lam, StructuralRate: job.rate_las, PMRate: job.rate_mapa, BMRate: job.rate_mash, TaxRate: null, StorageRateperDay: null, DaysStored: null, }, EstimateTotals: { BodyHours: null, RefinishHours: null, MechanicalHours: null, StructuralHours: null, PartsTotal: null, PartsOEM: null, PartsAM: null, PartsReconditioned: null, PartsRecycled: null, PartsOther: null, SubletTotal: null, BodyLaborTotal: null, RefinishLaborTotal: null, MechanicalLaborTotal: null, StructuralLaborTotal: null, MiscellaneousChargeTotal: null, PMTotal: null, BMTotal: null, MiscTotal: null, TowingTotal: null, StorageTotal: null, DetailTotal: null, SalesTaxTotal: null, GrossTotal: null, DeductibleTotal: null, DepreciationTotal: null, Discount: null, CustomerPay: null, InsurancePay: null, Deposit: null, AmountDue: null, }, SupplementTotals: { BodyHours: null, RefinishHours: null, MechanicalHours: null, StructuralHours: null, PartsTotal: null, PartsOEM: null, PartsAM: null, PartsReconditioned: null, PartsRecycled: null, PartsOther: null, SubletTotal: null, BodyLaborTotal: null, RefinishLaborTotal: null, MechanicalLaborTotal: null, StructuralLaborTotal: null, MiscellaneousChargeTotal: null, PMTotal: null, BMTotal: null, MiscTotal: null, TowingTotal: null, StorageTotal: null, DetailTotal: null, SalesTaxTotal: null, GrossTotal: null, DeductibleTotal: null, DepreciationTotal: null, Discount: null, CustomerPay: null, InsurancePay: null, Deposit: null, AmountDue: null, }, RevisedTotals: { BodyHours: job.job_totals.rates.lab.hours, RefinishHours: job.job_totals.rates.lar.hours, MechanicalHours: job.job_totals.rates.lam.hours, StructuralHours: job.job_totals.rates.las.hours, PartsTotal: Dinero(job.job_totals.parts.parts.total).toFormat( AHDineroFormat ), PartsTotalCost: 0, PartsOEM: Dinero( job.job_totals.parts.parts.list.PAN && job.job_totals.parts.parts.list.PAN.total ).toFormat(AHDineroFormat), PartsOEMCost: 0, PartsAM: Dinero( job.job_totals.parts.parts.list.PAA && job.job_totals.parts.parts.list.PAA.total ).toFormat(AHDineroFormat), PartsAMCost: 0, PartsReconditioned: null, PartsReconditionedCost: null, PartsRecycled: Dinero( job.job_totals.parts.parts.list.PAR && job.job_totals.parts.parts.list.PAR.total ).toFormat(AHDineroFormat), PartsRecycledCost: null, PartsOther: Dinero( job.job_totals.parts.parts.list.PAO && job.job_totals.parts.parts.list.PAO.total ).toFormat(AHDineroFormat), PartsOtherCost: null, SubletTotal: Dinero(job.job_totals.parts.sublets.total).toFormat( AHDineroFormat ), SubletTotalCost: 0, BodyLaborTotal: Dinero(job.job_totals.rates.lab.total).toFormat( AHDineroFormat ), BodyLaborTotalCost: 0, RefinishLaborTotal: Dinero(job.job_totals.rates.lar.total).toFormat( AHDineroFormat ), RefinishLaborTotalCost: 0, MechanicalLaborTotal: Dinero(job.job_totals.rates.lam.total).toFormat( AHDineroFormat ), MechanicalLaborTotalCost: 0, StructuralLaborTotal: Dinero(job.job_totals.rates.las.total).toFormat( AHDineroFormat ), StructuralLaborTotalCost: null, MiscellaneousChargeTotal: null, MiscellaneousChargeTotalCost: null, PMTotal: Dinero(job.job_totals.rates.mapa.total).toFormat( AHDineroFormat ), PMTotalCost: 0, BMTotal: Dinero(job.job_totals.rates.mash.total).toFormat( AHDineroFormat ), BMTotalCost: 0, MiscTotal: 0, MiscTotalCost: 0, TowingTotal: Dinero(job.job_totals.additional.towing).toFormat( AHDineroFormat ), TowingTotalCost: null, StorageTotal: Dinero(job.job_totals.additional.storage).toFormat( AHDineroFormat ), StorageTotalCost: null, DetailTotal: null, DetailTotalCost: null, SalesTaxTotal: Dinero(job.job_totals.totals.local_tax) .add(Dinero(job.job_totals.totals.state_tax)) .add(Dinero(job.job_totals.totals.federal_tax)) .toFormat(AHDineroFormat), SalesTaxTotalCost: null, GrossTotal: Dinero(job.job_totals.totals.net_repairs).toFormat( AHDineroFormat ), DeductibleTotal: job.ded_amt, DepreciationTotal: Dinero( job.job_totals.totals.custPayable.dep_taxes ).toFormat(AHDineroFormat), Discount: Dinero(job.job_totals.additional.adjustments).toFormat( AHDineroFormat ), CustomerPay: Dinero(job.job_totals.totals.custPayable.total).toFormat( AHDineroFormat ), InsurancePay: 0, Deposit: 0, AmountDue: 0, }, Misc: { ProductionStatus: null, StatusDescription: null, Hub50Comment: null, DateofChange: null, BodyTechName: null, TotalLossYN: null, InsScreenCommentsLine1: null, InsScreenCommentsLine2: null, AssignmentCaller: null, AssignmentDivision: null, LocationofPrimaryImpact: "12", LocationofSecondaryImpact: null, PaintTechID: null, PaintTechName: null, ImportType: null, ImportFile: null, GSTTax: null, RepairDelayStatusCode: null, RepairDelaycomment: null, AgentMktgID: null, AgentCity: null, Picture1: null, Picture2: null, ExtNoteDate: null, RentalOrdDate: null, RentalPUDate: null, RentalDueDate: null, RentalActRetDate: null, RentalCompanyID: null, CSIID: null, InsGroupCode: null, }, DetailLines: { DetailLine: job.joblines.length > 0 ? job.joblines.map((jl) => GenerateDetailLines(jl, job.bodyshop.md_order_statuses) ) : [generateNullDetailLine()], }, }; return ret; } catch (error) { errorCallback(job, error); } }; const StatusMapping = (status, md_ro_statuses) => { //EST, SCH, ARR, IPR, RDY, DEL, CLO, CAN, UNDEFINED. const { default_imported, default_open, default_scheduled, default_arrived, default_completed, default_delivered, default_invoiced, default_exported, default_void, } = md_ro_statuses; if (status === default_open || status === default_imported) return "EST"; else if (status === default_scheduled) return "SCH"; else if (status === default_arrived) return "ARR"; else if (status === default_completed) return "RDY"; else if (status === default_delivered) return "DEL"; else if (status === default_invoiced || status === default_exported) return "CLO"; else if (status === default_void) return "CLO"; else if (md_ro_statuses.production_statuses.includes(status)) return "IPR"; else return "UNDEFINED"; // default: return "UNDEFINED" }; const GenerateDetailLines = (line, statuses) => { const ret = { BackOrdered: line.status === statuses.default_bo ? "1" : "0", Cost: line.billlines[0] && (line.billlines[0].actual_cost * line.billlines[0].quantity).toFixed(2), Critical: null, Description: line.line_desc, DiscountMarkup: null, InvoiceNumber: line.billlines[0] && line.billlines[0].bill.invoice_number, IOUPart: null, LineNumber: line.line_no, MarkUp: null, OrderedOn: null, OriginalCost: null, OriginalInvoiceNumber: null, PriceEach: line.billlines[0] && line.billlines[0].actual_cost, PartNumber: _.escape(line.oem_partno), ProfitPercent: null, PurchaseOrderNumber: null, Qty: line.part_qty, Status: line.status, SupplementNumber: null, Type: line.part_type, Vendor: line.billlines[0] && line.billlines[0].bill.vendor.name, VendorPaid: null, VendorPrice: line.billlines[0] && line.billlines[0].actual_price, Deleted: null, ExpectedOn: null, ReceivedOn: null, OrderedBy: null, ShipVia: null, VendorContact: null, EstimateAmount: line.act_price, }; return ret; }; const generateNullDetailLine = () => { return { BackOrdered: "0", Cost: 0, Critical: null, Description: "No Lines on Estimate", DiscountMarkup: null, InvoiceNumber: null, IOUPart: null, LineNumber: 0, MarkUp: null, OrderedOn: null, OriginalCost: null, OriginalInvoiceNumber: null, PriceEach: 0, PartNumber: 0, ProfitPercent: null, PurchaseOrderNumber: null, Qty: 0, Status: null, SupplementNumber: null, Type: null, Vendor: null, VendorPaid: null, VendorPrice: null, Deleted: null, ExpectedOn: null, ReceivedOn: null, OrderedBy: null, ShipVia: null, VendorContact: null, EstimateAmount: null, }; };