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"); const logger = require("../utils/logger"); require("dotenv").config({ path: path.resolve( process.cwd(), `.env.${process.env.NODE_ENV || "development"}` ), }); const client = require("../graphql-client/graphql-client").client; const uuid = require("uuid").v4; exports.default = async (req, res) => { //Query for the List of Bodyshop Clients. logger.log("arms-start", "DEBUG", "api", null, null); const { bodyshops } = await client.request(queries.GET_ENTEGRAL_SHOPS); const allxmlsToUpload = []; const allErrors = []; try { for (const bodyshop of bodyshops) { logger.log("arms-start-shop-extract", "DEBUG", "api", bodyshop.id, { shopname: bodyshop.shopname, }); const erroredJobs = []; try { const { jobs } = await client.request(queries.ENTEGRAL_EXPORT, { bodyshopid: bodyshop.id, }); const ret = jobs.map((job) => { const transId = uuid(); // Can this actually be the job id? return { RepairOrderFolderAddRq: { RqUID: transId, DocumentInfo: { BMSVer: "4.0.0", DocumentType: "Repair Order", DocumentVerCode: "EM", DocumentVerNum: GetSupplementNumber(job.joblines), //TODO Get Supplement Number DocumentStatus: GetDocumentstatus(job, bodyshop), CreateDateTime: moment().format(), // TransmitDateTime: "2009-03-11T11:58:31.0404914-07:00", Omitted from ARMS docs }, EventInfo: { AssignmentEvent: { CreateDateTime: job.asgn_date && moment(job.asgn_date).format(), }, EstimateEvent: { UploadDateTime: "2009-03-02T17:00:00.0000000-08:00", //TODO Figure out what this actually is. 'Date Estimate was uploaded' }, RepairEvent: { ArrivalDateTime: job.date_open && moment(job.date_open).format(), ArrivalOdometerReading: job.kmin, TargetCompletionDateTime: job.scheduled_completion && moment(job.scheduled_completion).format(), ActualCompletionDateTime: job.actual_completion && moment(job.actual_completion).format(), ActualPickUpDateTime: job.actual_delivery && moment(job.actual_delivery).format(), CloseDateTime: job.date_exported && moment(job.date_exported).format(), }, }, RepairOrderHeader: { AdminInfo: { InsuranceCompany: { Party: { OrgInfo: { CompanyName: job.ins_co_nm, IDInfo: { IDQualifierCode: "US", IDNum: 44, // ** Not sure where to get this entegral ID from? }, Communications: [ { CommQualifier: "WA", Address: { Address1: job.ins_addr1, Address2: job.ins_addr2, City: job.ins_city, StateProvince: job.ins_st, PostalCode: job.ins_zip, CountryCode: job.ins_ctry, }, }, { CommQualifier: "WP", CommPhone: job.ins_ph1, }, { CommQualifier: "WF", CommPhone: job.ins_ph2, }, ], }, ContactInfo: { ContactJobTitle: "Adjuster", ContactName: { FirstName: job.est_ct_fn, LastName: job.est_ct_ln, }, }, }, }, // InsuranceAgent: { // Party: { // OrgInfo: { // CompanyName: "Nationwide Insurance", // Communications: { // CommQualifier: "WP", // CommPhone: "714-5551212", // }, // }, // ContactInfo: { // ContactJobTitle: "Insurance Agent", // ContactName: { // FirstName: "Paul", // LastName: "White", // }, // }, // }, // }, Insured: { Party: { PersonInfo: { PersonName: { FirstName: job.insd_fn, LastName: job.insd_ln, }, }, }, }, Owner: { Party: { PersonInfo: { PersonName: { FirstName: job.ownr_fn, LastName: job.ownr_ln, }, Communications: [ { CommQualifier: "HA", Address: { Address1: job.ownr_addr1, City: job.ownr_city, StateProvince: job.ownr_st, PostalCode: job.ownr_zip, CountryCode: job.ownr_ctry, }, }, { CommQualifier: "HP", CommPhone: job.ownr_ph1, }, { CommQualifier: "WP", CommPhone: job.ownr_ph2, }, { CommQualifier: "CP", CommPhone: job.ownr_ph1, }, { CommQualifier: "EM", CommEmail: job.ownr_ea, }, ], }, }, }, Claimant: { Party: { PersonInfo: { PersonName: { FirstName: job.clm_ct_fn, LastName: job.clm_ct_ln, }, }, }, OwnerInd: true, }, Estimator: { Party: { PersonInfo: { PersonName: { FirstName: job.est_ct_fn, LastName: job.est_ct_ln, }, // IDInfo: { // IDQualifierCode: "US", // IDNum: 2941, // }, }, }, }, RepairFacility: { //This section not in documentation. Party: { OrgInfo: { CompanyName: bodyshop.shopname, IDInfo: { IDQualifierCode: "US", IDNum: bodyshop.entegral_id, }, }, }, }, }, RepairOrderIDs: { RepairOrderNum: job.ro_number, // VendorCode: "C", // EstimateDocumentID: "1223HJ76", }, //RepairOrderType: "DRP", //ReferralSourceType: "Yellow Pages", VehicleInfo: { VINInfo: { VIN: { VINNum: job.v_vin, }, }, License: { LicensePlateNum: job.plate_no, }, VehicleDesc: { //ProductionDate: "2009-10", ModelYear: job.v_model_yr, MakeDesc: job.v_make_desc, ModelName: job.v_model_desc, }, Paint: { Exterior: { Color: { ColorName: job.v_color, // OEMColorCode: "1M3", }, }, }, // Body: { // BodyStyle: "2 Door Convertible", // Trim: { // TrimCode: "1B3", // }, // }, Condition: { DrivableInd: job.driveable ? "Y" : "N", }, }, ClaimInfo: { ClaimNum: job.clm_no, PolicyInfo: { PolicyNum: job.policy_no, }, LossInfo: { Facts: { LossDateTime: job.loss_date && moment(job.loss_date).format(), LossDescCode: "Collision", PrimaryPOI: { POICode: job.area_of_damage.impact1, }, SecondaryPOI: { POICode: job.area_of_damage.impact2, }, }, TotalLossInd: job.tlos_ind, }, }, }, ProfileInfo: { //ProfileName: "Shop Standard Rates", RateInfo: [ { RateType: "PA", RateDesc: "Parts Tax", TaxInfo: { TaxType: "LS", TaxableInd: true, TaxTierInfo: { TierNum: 1, Percentage: 0, //TODO Find the best place to take the tax rates for parts. }, }, }, { RateType: "LA", RateDesc: "Labor Tax", TaxInfo: { TaxType: "LS", TaxableInd: true, TaxTierInfo: { TierNum: 1, Percentage: 0, //TODO Find the best place to take the tax rates for labor. }, }, }, { RateType: "LAB", RateDesc: "Body Labor", RateTierInfo: { TierNum: 1, Rate: job.rate_lab, }, }, { RateType: "LAS", RateDesc: "Structural Labor", RateTierInfo: { TierNum: 1, Rate: job.rate_las, }, }, { RateType: "LAR", RateDesc: "Refinish Labor", RateTierInfo: { TierNum: 1, Rate: job.rate_lar, }, }, { RateType: "LAG", RateDesc: "Glass Labor", RateTierInfo: { TierNum: 1, Rate: job.rate_lag, }, }, { RateType: "LAF", RateDesc: "Frame Labor", RateTierInfo: { TierNum: 1, Rate: job.rate_laf, }, }, { RateType: "LAM", RateDesc: "Mechancial Labor", RateTierInfo: { TierNum: 1, Rate: job.rate_lam, }, }, { RateType: "LAU", RateDesc: "User Defined Labor", RateTierInfo: { TierNum: 1, Rate: job.rate_lau, }, }, { RateType: "MAPA", RateDesc: "Paint Materials", RateTierInfo: { TierNum: 1, Rate: job.rate_mapa, ThresholdAmt: 0, }, MaterialCalcSettings: { CalcMethodCode: 2, CalcMaxAmt: 9999.99, //TODO Find threshold amts. }, }, { RateType: "MASH", RateDesc: "Shop Materials", RateTierInfo: { TierNum: 1, Rate: job.rate_mash, }, MaterialCalcSettings: { CalcMethodCode: 4, CalcMaxAmt: 9999.99, //TODO Find threshold amounts. }, }, { RateType: "MAHW", RateDesc: "Hazardous Wastes Removal", RateTierInfo: { TierNum: 1, Rate: job.rate_mahw, }, MaterialCalcSettings: { //Todo Capture Calc Settings CalcMethodCode: 2, CalcMaxAmt: 10, }, }, { RateType: "MA2S", RateDesc: "Two Stage Paint", RateTierInfo: { TierNum: 1, Rate: job.rate_ma2s, }, MaterialCalcSettings: { CalcMethodCode: 1, CalcMaxAmt: 999999.99, }, }, { RateType: "MA2T", RateDesc: "Two Tone Paint", RateTierInfo: { TierNum: 1, Rate: job.rate_ma2t, }, MaterialCalcSettings: { CalcMethodCode: 1, CalcMaxAmt: 999999.99, }, }, { RateType: "MA3S", RateDesc: "Three Stage Paint", RateTierInfo: { TierNum: 1, Rate: job.rate_ma3s, }, MaterialCalcSettings: { CalcMethodCode: 1, CalcMaxAmt: 999999.99, }, }, ], }, //StorageDuration: 17, RepairTotalsInfo: { LaborTotalsInfo: [ { TotalType: "LAB", TotalTypeDesc: "Body Labor", TotalHours: job.job_totals.rates.lab.hours, TotalAmt: Dinero(job.job_totals.rates.lab.total).toFormat( 0.0 ), }, { TotalType: "LAF", TotalTypeDesc: "Frame Labor", TotalHours: job.job_totals.rates.laf.hours, TotalAmt: Dinero(job.job_totals.rates.laf.total).toFormat( 0.0 ), }, { TotalType: "LAM", TotalTypeDesc: "Mechanical Labor", TotalHours: job.job_totals.rates.lam.hours, TotalAmt: Dinero(job.job_totals.rates.lam.total).toFormat( 0.0 ), }, { TotalType: "LAR", TotalTypeDesc: "Refinish Labor", TotalHours: job.job_totals.rates.lar.hours, TotalAmt: Dinero(job.job_totals.rates.lar.total).toFormat( 0.0 ), }, ], PartsTotalsInfo: [ { TotalType: "PAA", TotalTypeDesc: "Aftermarket Parts", TotalAmt: Dinero( job.job_totals.parts.parts.list.paa && job.job_totals.parts.parts.list.paa.total ).toFormat("0.0"), }, { TotalType: "PAC", TotalTypeDesc: "Re-Chromed Parts", TotalAmt: Dinero( job.job_totals.parts.parts.list.pac && job.job_totals.parts.parts.list.pac.total ).toFormat("0.0"), }, { TotalType: "PAG", TotalTypeDesc: "Glass Parts", TotalAmt: Dinero( job.job_totals.parts.parts.list.pag && job.job_totals.parts.parts.list.pag.total ).toFormat("0.0"), }, { TotalType: "PAL", TotalTypeDesc: "LKQ/Used Parts", TotalAmt: Dinero( job.job_totals.parts.parts.list.pal && job.job_totals.parts.parts.list.pal.total ).toFormat("0.0"), }, { TotalType: "PAM", TotalTypeDesc: "Remanufactured Parts", TotalAmt: Dinero( job.job_totals.parts.parts.list.pam && job.job_totals.parts.parts.list.pam.total ).toFormat("0.0"), }, { TotalType: "PAN", TotalTypeDesc: "New Parts", TotalAmt: Dinero( job.job_totals.parts.parts.list.pan && job.job_totals.parts.parts.list.pan.total ).toFormat("0.0"), }, { TotalType: "PAR", TotalTypeDesc: "Recored Parts", TotalAmt: Dinero( job.job_totals.parts.parts.list.par && job.job_totals.parts.parts.list.par.total ).toFormat("0.0"), }, ], OtherChargesTotalsInfo: [ { TotalType: "OTSL", TotalTypeDesc: "Sublet", TotalAmt: Dinero( job.job_totals.parts.sublets.total ).toFormat("0.0"), }, { TotalType: "MAPA", TotalTypeDesc: "Paint Materials", TotalAmt: Dinero(job.job_totals.rates.mapa.total).toFormat( 0.0 ), }, { TotalType: "MASH", TotalTypeDesc: "Shop Materials", TotalAmt: Dinero(job.job_totals.rates.mash.total).toFormat( 0.0 ), }, // { // TotalType: "MAHW", // TotalTypeDesc: "Hazardous Wastes Removal", // TotalAmt: Dinero(job.job_totals.rates.mahw.total).toFormat( // 0.0 // ), // }, { TotalType: "OTST", TotalTypeDesc: "Storage", TotalAmt: Dinero( job.job_totals.additional.storage ).toFormat("0.0"), }, { TotalType: "OTTW", TotalTypeDesc: "Towing", TotalAmt: Dinero(job.job_totals.additional.towing).toFormat( 0.0 ), }, { TotalType: "OTAC", TotalTypeDesc: "Additional Charges", TotalAmt: Dinero( job.job_totals.additional.additionalCosts ).toFormat("0.0"), }, ], SummaryTotalsInfo: [ { TotalType: "TOT", TotalSubType: "T2", TotalTypeDesc: "Net Total", TotalAmt: Dinero(job.job_totals.totals.subtotal).toFormat( 0.0 ), }, { TotalType: "TOT", TotalSubType: "F7", TotalTypeDesc: "Sales Tax", TotalAmt: Dinero(job.job_totals.totals.state_tax).toFormat( 0.0 ), }, { TotalType: "TOT", TotalSubType: "GST", TotalTypeDesc: "GST Tax", TotalAmt: Dinero( job.job_totals.totals.federal_tax ).toFormat("0.0"), }, { TotalType: "TOT", TotalSubType: "TT", TotalTypeDesc: "Gross Total", TotalAmt: Dinero( job.job_totals.totals.total_repairs ).toFormat("0.0"), }, // { // TotalType: "TOT", // TotalSubType: "SM", // TotalTypeDesc: "Supplement Total", // TotalAmt: 0, // }, { TotalType: "TOT", TotalSubType: "D2", TotalTypeDesc: "Deductible", TotalAmt: Dinero({ amount: Math.round((job.ded_amt || 0) * 100), }).toFormat("0.0"), }, { TotalType: "TOT", TotalSubType: "BTR", TotalTypeDesc: "Betterment", TotalAmt: Dinero( job.job_totals.totals.custPayable.dep_taxes ).toFormat("0.0"), }, { TotalType: "TOT", TotalSubType: "AA", TotalTypeDesc: "Appearance Allowance", TotalAmt: 0, }, { TotalType: "TOT", TotalSubType: "D8", TotalTypeDesc: "Bottom Line Discount", TotalAmt: Dinero( job.job_totals.additional.adjustments ).toFormat("0.0"), }, { TotalType: "TOT", TotalSubType: "INS", TotalTypeDesc: "Insurance Pay", TotalAmt: Dinero(job.job_totals.totals.total_repairs) .subtract(Dinero(job.job_totals.totals.custPayable.total)) .toFormat("0.0"), }, // { // TotalType: "TOT", // TotalSubType: "DEPOSIT", // TotalTypeDesc: "Deposit", // TotalAmt: 0, // }, { TotalType: "TOT", TotalSubType: "CUST", TotalTypeDesc: "Customer Pay", TotalAmt: Dinero( job.job_totals.totals.custPayable.total ).toFormat("0.0"), }, ], RepairTotalsType: 1, }, // RepairLabor: { // LaborAllocations: { // LaborAllocation: [ // { // LaborAllocationUUID: // "426cce3a-efa7-44d9-b76e-50b9102c4198", // LaborType: "LAB", // Technician: { // Employee: { // PersonInfo: { // PersonName: { // FirstName: "Jose", // LastName: "Gonzalez", // }, // IDInfo: { // IDQualifierCode: "US", // IDNum: 2987, // }, // }, // }, // }, // AllocatedHours: 3.5, // }, // { // LaborAllocationUUID: // "426cce3a-efa7-44d9-b76e-50b9102c4199", // LaborType: "LAR", // Technician: { // Employee: { // PersonInfo: { // PersonName: { // FirstName: "Rcardo", // LastName: "Himenez", // }, // IDInfo: { // IDQualifierCode: "US", // IDNum: 2989, // }, // }, // }, // }, // AllocatedHours: 5.5, // }, // ], // }, // }, ProductionStatus: { ProductionStage: { ProductionStageCode: 4, ProductionStageDateTime: "2009-03-11T11:58:32.1898319-07:00", ProductionStageStatusComment: "Going to be painted this afternoon", }, RepairStatus: { RepairStatusCode: 2, RepairStatusDateTime: "2009-03-11T11:58:32.1898319-07:00", RepairStatusMemo: "Waiting on back ordered parts", }, }, // RepairOrderNotes: { // RepairOrderNote: { // LineSequenceNum: 1, // Note: "Revision Requested : approved--but needs est separated.8/22/2008 11:58:53 AM", // CreateDateTime: "2008-08-22T11:58:53", // AuthoredBy: { // FirstName: { // "#text": "Elizabeth/FirstName>", // LastName: "Unis", // }, // }, // RepairOrderNote: { // LineSequenceNum: 2, // Note: "Approved : 8/26/2008 12:21:08 PM", // CreateDateTime: "2008-08-26T12:21:08", // AuthoredBy: { // FirstName: { // "#text": "Elizabeth/FirstName>", // LastName: "Unis", // }, // }, // }, // }, // }, }, }; }); if (erroredJobs.length > 0) { logger.log("arms-failed-jobs", "ERROR", "api", bodyshop.id, { count: erroredJobs.length, jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number)), }); } logger.log("arms-end-shop-extract", "DEBUG", "api", bodyshop.id, { shopname: bodyshop.shopname, }); res.json(ret); } catch (error) { //Error at the shop level. logger.log("arms-error-shop", "ERROR", "api", bodyshop.id, { error, }); allErrors.push({ bodyshopid: bodyshop.id, imexshopid: bodyshop.imexshopid, fatal: true, errors: [error.toString()], }); } finally { allErrors.push({ bodyshopid: bodyshop.id, imexshopid: bodyshop.imexshopid, errors: erroredJobs, }); } } res.sendStatus(200); } catch (error) { res.status(200).json(error); } }; function GetSupplementNumber(joblines) { return _.max(joblines.map((jl) => jl.line_ind)); } function GetDocumentstatus(job, bodyshop) { switch (job.status) { case bodyshop.md_ro_statuses.default_void: return "V"; case bodyshop.md_ro_statuses.default_invoiced: case bodyshop.md_ro_statuses.default_exported: return "V"; default: return "0"; } }