diff --git a/server/data/arms.js b/server/data/arms.js index 7124c07ad..2d23ab8d3 100644 --- a/server/data/arms.js +++ b/server/data/arms.js @@ -2,6 +2,7 @@ const path = require("path"); const queries = require("../graphql-client/queries"); const Dinero = require("dinero.js"); const moment = require("moment"); +const fs = require("fs"); const _ = require("lodash"); const logger = require("../utils/logger"); @@ -28,7 +29,6 @@ exports.default = async (req, res) => { 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) { @@ -40,10 +40,12 @@ exports.default = async (req, res) => { const { jobs } = await client.request(queries.ENTEGRAL_EXPORT, { bodyshopid: bodyshop.id, }); - const ret = jobs.map((job) => { + const jobsToPush = []; + + jobs.forEach((job) => { const transId = uuid(); // Can this actually be the job id? - return { + let obj = { RqUID: transId, DocumentInfo: { BMSVer: "4.0.0", @@ -55,16 +57,18 @@ exports.default = async (req, res) => { TransmitDateTime: moment().format(momentFormat), // Omitted from ARMS docs }, EventInfo: { - AssignmentEvent: { - CreateDateTime: - job.asgn_date && moment(job.asgn_date).format(momentFormat), - }, - EstimateEvent: { - UploadDateTime: moment().format(momentFormat), - }, + // AssignmentEvent: { + // CreateDateTime: + // job.asgn_date && moment(job.asgn_date).format(momentFormat), + // }, + // EstimateEvent: { + // UploadDateTime: moment().format(momentFormat), + // }, RepairEvent: { - CreatedDateTime: - job.date_open && moment(job.date_open).format(momentFormat), + CreatedDateTime: (job.date_open + ? moment(job.date_open) + : moment() + ).format(momentFormat), ArrivalDateTime: job.actual_in && moment(job.actual_in).format(momentFormat), ArrivalOdometerReading: job.kmin, @@ -92,35 +96,35 @@ exports.default = async (req, res) => { 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, - }, + // 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: { @@ -141,16 +145,16 @@ exports.default = async (req, res) => { // }, // }, // }, - Insured: { - Party: { - PersonInfo: { - PersonName: { - FirstName: job.insd_fn, - LastName: job.insd_ln, - }, - }, - }, - }, + // Insured: { + // Party: { + // PersonInfo: { + // PersonName: { + // FirstName: job.insd_fn, + // LastName: job.insd_ln, + // }, + // }, + // }, + // }, Owner: { Party: { PersonInfo: { @@ -158,68 +162,70 @@ exports.default = async (req, res) => { FirstName: job.ownr_fn, LastName: job.ownr_ln, }, - Communications: [ - { - CommQualifier: "HA", - Address: { - Address1: job.ownr_addr1, + // 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, - // }, + // 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, + CompanyName: + process.env.NODE_ENV === "production" + ? bodyshop.shopname + : "IMEX Test Shop", IDInfo: { IDQualifierCode: "US", IDNum: bodyshop.entegral_id, @@ -233,7 +239,7 @@ exports.default = async (req, res) => { // VendorCode: "C", // EstimateDocumentID: "1223HJ76", }, - //RepairOrderType: "DRP", + RepairOrderType: "DirectRepairProgram", //Need to get from Entegral //ReferralSourceType: "Yellow Pages", VehicleInfo: { VINInfo: { @@ -241,9 +247,9 @@ exports.default = async (req, res) => { VINNum: job.v_vin, }, }, - License: { - LicensePlateNum: job.plate_no, - }, + // License: { + // LicensePlateNum: job.plate_no, + // }, VehicleDesc: { //ProductionDate: "2009-10", ModelYear: @@ -255,23 +261,23 @@ exports.default = async (req, res) => { MakeDesc: job.v_make_desc, ModelName: job.v_model_desc, }, - Paint: { - Exterior: { - Color: { - ColorName: job.v_color, - // OEMColorCode: "1M3", - }, - }, - }, + // Paint: { + // Exterior: { + // Color: { + // ColorName: job.v_color, + // // OEMColorCode: "1M3", + // }, + // }, + // }, // Body: { // BodyStyle: "2 Door Convertible", // Trim: { // TrimCode: "1B3", // }, // }, - Condition: { - DrivableInd: job.driveable ? "Y" : "N", - }, + // Condition: { + // DrivableInd: job.driveable ? "Y" : "N", + // }, }, ClaimInfo: { ClaimNum: job.clm_no, @@ -296,7 +302,7 @@ exports.default = async (req, res) => { }, }, ProfileInfo: { - //ProfileName: "Shop Standard Rates", + ProfileName: "ImEX", RateInfo: [ { RateType: "PA", @@ -306,7 +312,7 @@ exports.default = async (req, res) => { TaxableInd: true, TaxTierInfo: { TierNum: 1, - Percentage: 0, //TODO Find the best place to take the tax rates for parts. + Percentage: job.parts_tax_rates.PAN.prt_tax_rt * 100, //TODO Find the best place to take the tax rates for parts. }, }, }, @@ -318,7 +324,7 @@ exports.default = async (req, res) => { TaxableInd: true, TaxTierInfo: { TierNum: 1, - Percentage: 0, //TODO Find the best place to take the tax rates for labor. + Percentage: job.parts_tax_rates.PAN.prt_tax_rt * 100, //TODO Find the best place to take the tax rates for labor. }, }, }, @@ -495,56 +501,56 @@ exports.default = async (req, res) => { TotalType: "PAA", TotalTypeDesc: "Aftermarket Parts", TotalAmt: Dinero( - job.job_totals.parts.parts.list.paa && - job.job_totals.parts.parts.list.paa.total + job.job_totals.parts.parts.list.PAA && + job.job_totals.parts.parts.list.PAA.total ).toFormat("0.00"), }, { TotalType: "PAC", TotalTypeDesc: "Re-Chromed Parts", TotalAmt: Dinero( - job.job_totals.parts.parts.list.pac && - job.job_totals.parts.parts.list.pac.total + job.job_totals.parts.parts.list.PAC && + job.job_totals.parts.parts.list.PAC.total ).toFormat("0.00"), }, { TotalType: "PAG", TotalTypeDesc: "Glass Parts", TotalAmt: Dinero( - job.job_totals.parts.parts.list.pag && - job.job_totals.parts.parts.list.pag.total + job.job_totals.parts.parts.list.PAG && + job.job_totals.parts.parts.list.PAG.total ).toFormat("0.00"), }, { TotalType: "PAL", TotalTypeDesc: "LKQ/Used Parts", TotalAmt: Dinero( - job.job_totals.parts.parts.list.pal && - job.job_totals.parts.parts.list.pal.total + job.job_totals.parts.parts.list.PAL && + job.job_totals.parts.parts.list.PAL.total ).toFormat("0.00"), }, { TotalType: "PAM", TotalTypeDesc: "Remanufactured Parts", TotalAmt: Dinero( - job.job_totals.parts.parts.list.pam && - job.job_totals.parts.parts.list.pam.total + job.job_totals.parts.parts.list.PAM && + job.job_totals.parts.parts.list.PAM.total ).toFormat("0.00"), }, { TotalType: "PAN", TotalTypeDesc: "New Parts", TotalAmt: Dinero( - job.job_totals.parts.parts.list.pan && - job.job_totals.parts.parts.list.pan.total + job.job_totals.parts.parts.list.PAN && + job.job_totals.parts.parts.list.PAN.total ).toFormat("0.00"), }, { TotalType: "PAR", TotalTypeDesc: "Recored Parts", TotalAmt: Dinero( - job.job_totals.parts.parts.list.par && - job.job_totals.parts.parts.list.par.total + job.job_totals.parts.parts.list.PAR && + job.job_totals.parts.parts.list.PAR.total ).toFormat("0.00"), }, ], @@ -616,6 +622,14 @@ exports.default = async (req, res) => { "0.00" ), }, + { + TotalType: "TOT", + TotalSubType: "SM", + TotalTypeDesc: "Supplement Total", + TotalAmt: job.cieca_ttl + ? job.cieca_ttl.data.supp_amt + : Dinero().toFormat("0.00"), + }, { TotalType: "TOT", TotalSubType: "F7", @@ -632,12 +646,14 @@ exports.default = async (req, res) => { "0.00" ), }, - // { - // TotalType: "TOT", - // TotalSubType: "SM", - // TotalTypeDesc: "Supplement Total", - // TotalAmt: 0, - // }, + { + TotalType: "TOT", + TotalSubType: "D8", + TotalTypeDesc: "Bottom Line Discount", + TotalAmt: Dinero( + job.job_totals.additional.adjustments + ).toFormat("0.00"), + }, { TotalType: "TOT", TotalSubType: "D2", @@ -658,15 +674,13 @@ exports.default = async (req, res) => { TotalType: "TOT", TotalSubType: "AA", TotalTypeDesc: "Appearance Allowance", - TotalAmt: 0, + TotalAmt: Dinero().toFormat("0.00"), }, { TotalType: "TOT", - TotalSubType: "D8", - TotalTypeDesc: "Bottom Line Discount", - TotalAmt: Dinero( - job.job_totals.additional.adjustments - ).toFormat("0.00"), + TotalSubType: "DEPOSIT", + TotalTypeDesc: "Deposit", + TotalAmt: Dinero().toFormat("0.00"), }, { TotalType: "TOT", @@ -676,12 +690,6 @@ exports.default = async (req, res) => { .subtract(Dinero(job.job_totals.totals.custPayable.total)) .toFormat("0.00"), }, - // { - // TotalType: "TOT", - // TotalSubType: "DEPOSIT", - // TotalTypeDesc: "Deposit", - // TotalAmt: 0, - // }, { TotalType: "TOT", TotalSubType: "CUST", @@ -691,7 +699,7 @@ exports.default = async (req, res) => { ).toFormat("0.00"), }, ], - RepairTotalsType: 1, + // RepairTotalsType: 1, }, // RepairLabor: { // LaborAllocations: { @@ -741,7 +749,7 @@ exports.default = async (req, res) => { // }, ProductionStatus: { ProductionStage: { - ProductionStageCode: GetProductionStageCode(job), + ProductionStageCode: GetProductionStageCode(job, bodyshop), ProductionStageDateTime: moment().format(momentFormat), // ProductionStageStatusComment: // "Going to be painted this afternoon", @@ -777,6 +785,9 @@ exports.default = async (req, res) => { // }, // }, }; + + deleteNullKeys(obj); + jobsToPush.push(obj); }); if (erroredJobs.length > 0) { @@ -784,13 +795,12 @@ exports.default = async (req, res) => { count: erroredJobs.length, jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number)), }); + allErrors = [...allErrors, ...erroredJobs]; } logger.log("arms-end-shop-extract", "DEBUG", "api", bodyshop.id, { shopname: bodyshop.shopname, }); - const abc = ret[1]; - deleteNullKeys(abc); try { const entegralSoapClient = await soap.createClientAsync( @@ -798,7 +808,7 @@ exports.default = async (req, res) => { { ignoredNamespaces: true, wsdl_options: { - useEmptyTag: true, + // useEmptyTag: true, }, wsdl_headers: { Authorization: `Basic ${new Buffer.from( @@ -816,14 +826,20 @@ exports.default = async (req, res) => { ); const entegralResponse = - await entegralSoapClient.RepairOrderFolderAddRqAsync(abc); + await entegralSoapClient.RepairOrderFolderAddRqAsync( + jobsToPush, + function (err, result, rawResponse, soapHeader, rawRequest) { + fs.writeFileSync(`./logs/arms-request.xml`, rawRequest); + fs.writeFileSync(`./logs/arms-response.xml`, rawResponse); + + res.json(err || result); + } + ); const [result, rawResponse, , rawRequest] = entegralResponse; - console.log("🚀 ~ file: arms.js ~ line 806 ~ result", result); - res.json({ result, obj: abc }); } catch (error) { + fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml); console.log(error); - res.json(error); } } catch (error) { //Error at the shop level. @@ -846,15 +862,18 @@ exports.default = async (req, res) => { } } - // res.sendStatus(200); + res.sendStatus(200); } catch (error) { res.status(200).json(error); } }; function GetSupplementNumber(joblines) { - return 0; - return _.max(joblines.map((jl) => jl.line_ind)); + const max = _.max( + joblines.map((jl) => parseInt((jl.line_ind || "0").replace(/[^\d.-]/g, ""))) + ); + + return max || 0; } function GetDocumentstatus(job, bodyshop) { @@ -873,7 +892,9 @@ function GetDocumentstatus(job, bodyshop) { function GetRepairStatusCode(job) { return "25"; } -function GetProductionStageCode(job) { +function GetProductionStageCode(job, bodyshop) { + if (bodyshop.md_ro_statuses.post_production_statuses.includes(job.status)) + return "8D"; return "33"; } diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index e9ba2d511..1393e1b4d 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -783,6 +783,8 @@ query ENTEGRAL_EXPORT($bodyshopid: uuid!) { rate_matd job_totals ded_amt + cieca_ttl + adjustment_bottom_line } } `;