From 7aeac03b2c8c715e0884872b2119544cf2337f9e Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Fri, 23 Sep 2022 13:35:33 -0700 Subject: [PATCH 1/9] update formatting of bounced emails. --- server/email/sendemail.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/server/email/sendemail.js b/server/email/sendemail.js index c585b4815..802d61e0f 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -240,14 +240,13 @@ exports.emailBounce = async function (req, res, next) { to: "patrick@snapt.ca", // replyTo, bcc: "patrick@snapt.ca", subject: `ImEX Online Bounced Email - RE: ${subject}`, - text: ` - ImEX Online has tried to deliver an email with the subject: ${subject} to the intended recipients but encountered an error. + text: `ImEX Online has tried to deliver an email with the subject: ${subject} to the intended recipients but encountered an error. - ${message.bounce?.bouncedRecipients.map( - (r) => - `Recipient: ${r.emailAddress} | Status: ${r.action} | Code: ${r.diagnosticCode} +${message.bounce?.bouncedRecipients.map( + (r) => + `Recipient: ${r.emailAddress} | Status: ${r.action} | Code: ${r.diagnosticCode} ` - )} +)} `, }, (err, info) => { From 39efb52497e42f75733c5758ae8ebffdbfca2deb Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 23 Sep 2022 13:48:45 -0700 Subject: [PATCH 2/9] Update SNS handling --- server/email/sendemail.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/server/email/sendemail.js b/server/email/sendemail.js index 802d61e0f..dc2387b1f 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -209,11 +209,9 @@ async function logEmail(req, email) { exports.emailBounce = async function (req, res, next) { try { const body = JSON.parse(req.body); - if (body.type === "SubscriptionConfirmation") { - logger.log("SNS-confirmation", "DEBUG", "api", null, { - message: body.message, - url: body.SubscribeUrl, - body: body, + if (body.type !== "Notification") { + logger.log("SNS-message", "DEBUG", "api", null, { + body: req.body, }); } if (body.Type === "Notification") { From ac270a608f86a17d5f251c0dddad17e8a7c30100 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 23 Sep 2022 13:59:58 -0700 Subject: [PATCH 3/9] Updates to bounced email tracker. --- server/email/sendemail.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/server/email/sendemail.js b/server/email/sendemail.js index dc2387b1f..277915d17 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -209,15 +209,15 @@ async function logEmail(req, email) { exports.emailBounce = async function (req, res, next) { try { const body = JSON.parse(req.body); - if (body.type !== "Notification") { + if (body.Type === "SubscriptionConfirmation") { logger.log("SNS-message", "DEBUG", "api", null, { body: req.body, }); } - if (body.Type === "Notification") { - const message = JSON.parse(body.Message); + if (body.notificationType === "Bounce") { + // const message = JSON.parse(body.Message); let replyTo, subject, messageId; - message.mail.headers.forEach((header) => { + body.mail.headers.forEach((header) => { if (header.name === "Reply-To") { replyTo = header.value; } else if (header.name === "Subject") { @@ -230,7 +230,7 @@ exports.emailBounce = async function (req, res, next) { const result = await client.request(queries.UPDATE_EMAIL_AUDIT, { sesid: messageId, status: "Bounced", - context: message.bounce?.bouncedRecipients, + context: body.bounce?.bouncedRecipients, }); transporter.sendMail( { @@ -240,7 +240,7 @@ exports.emailBounce = async function (req, res, next) { subject: `ImEX Online Bounced Email - RE: ${subject}`, text: `ImEX Online has tried to deliver an email with the subject: ${subject} to the intended recipients but encountered an error. -${message.bounce?.bouncedRecipients.map( +${body.bounce?.bouncedRecipients.map( (r) => `Recipient: ${r.emailAddress} | Status: ${r.action} | Code: ${r.diagnosticCode} ` From 4b6eea41c27e22f81e33356c1cf44fe4f2669444 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 23 Sep 2022 14:08:45 -0700 Subject: [PATCH 4/9] Updated recipieint for bounced emails since testing confirmed. --- server/email/sendemail.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/email/sendemail.js b/server/email/sendemail.js index 277915d17..b00b3577b 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -215,7 +215,7 @@ exports.emailBounce = async function (req, res, next) { }); } if (body.notificationType === "Bounce") { - // const message = JSON.parse(body.Message); + // const message = JSON.parse(body.Message); let replyTo, subject, messageId; body.mail.headers.forEach((header) => { if (header.name === "Reply-To") { @@ -235,7 +235,7 @@ exports.emailBounce = async function (req, res, next) { transporter.sendMail( { from: `ImEX Online `, - to: "patrick@snapt.ca", // replyTo, + to: replyTo, bcc: "patrick@snapt.ca", subject: `ImEX Online Bounced Email - RE: ${subject}`, text: `ImEX Online has tried to deliver an email with the subject: ${subject} to the intended recipients but encountered an error. From 9249222fabd5593ac189a6243d757727b9f8fe4b Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 23 Sep 2022 14:10:16 -0700 Subject: [PATCH 5/9] Add missing query field. --- client/src/graphql/audit_trail.queries.js | 1 + 1 file changed, 1 insertion(+) diff --git a/client/src/graphql/audit_trail.queries.js b/client/src/graphql/audit_trail.queries.js index b0c0b3f40..793cc0001 100644 --- a/client/src/graphql/audit_trail.queries.js +++ b/client/src/graphql/audit_trail.queries.js @@ -26,6 +26,7 @@ export const QUERY_AUDIT_TRAIL = gql` subject to useremail + status } } `; From 0fee89623c4d46b81a86886233cf5a2b84188e16 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Sat, 24 Sep 2022 11:04:08 -0700 Subject: [PATCH 6/9] Prevent no reply loop --- server/email/sendemail.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/server/email/sendemail.js b/server/email/sendemail.js index b00b3577b..e3565d3e0 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -226,6 +226,11 @@ exports.emailBounce = async function (req, res, next) { messageId = header.value; } }); + + if (replyTo === "noreply@imex.online") { + res.sendStatus(200); + return; + } //If it's bounced, log it as bounced in audit log. Send an email to the user. const result = await client.request(queries.UPDATE_EMAIL_AUDIT, { sesid: messageId, From acd3f545b3f500c2caca29824476050a00411df0 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Mon, 26 Sep 2022 11:33:58 -0700 Subject: [PATCH 7/9] IO-2054 RO Splitting for QBO --- bodyshop_translations.babel | 42 +++++++++ .../pages/jobs-close/jobs-close.component.jsx | 87 +++++++++++++++++-- client/src/translations/en_us/common.json | 2 + client/src/translations/es/common.json | 2 + client/src/translations/fr/common.json | 2 + server/accounting/qbo/qbo-receivables.js | 23 ++++- 6 files changed, 149 insertions(+), 9 deletions(-) diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 8d18dce03..c905978c4 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -26084,6 +26084,27 @@ + + additionalpayeroverallocation + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + additionaltotal false @@ -28062,6 +28083,27 @@ + + multipayers + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + net_repairs false diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx index b8f73c144..3df8aafc6 100644 --- a/client/src/pages/jobs-close/jobs-close.component.jsx +++ b/client/src/pages/jobs-close/jobs-close.component.jsx @@ -12,7 +12,9 @@ import { Popconfirm, Select, Space, + Statistic, Switch, + Typography, } from "antd"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; @@ -33,7 +35,7 @@ import { generateJobLinesUpdatesForInvoicing } from "../../graphql/jobs-lines.qu import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; - +import Dinero from "dinero.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, jobRO: selectJobReadOnly, @@ -325,9 +327,41 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) { )} + {t("jobs.labels.multipayers")} {Qb_Multi_Ar.treatment === "on" && ( - <> - + + ({ + validator(_, value) { + let totalAllocated = Dinero(); + + const payers = form.getFieldValue("qb_multiple_payers"); + payers && + payers.forEach((payer) => { + totalAllocated = totalAllocated.add( + Dinero({ + amount: Math.round((payer?.amount || 0) * 100), + }) + ); + }); + const discrep = job.job_totals + ? Dinero(job.job_totals.totals.total_repairs).subtract( + totalAllocated + ) + : Dinero(); + return discrep.getAmount() > 0 + ? Promise.resolve() + : Promise.reject( + new Error( + t("jobs.labels.additionalpayeroverallocation") + ) + ); + }, + }), + ]} + > {(fields, { add, remove }) => { return (
@@ -382,7 +416,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
}> - - - - + {Qb_Multi_Ar.treatment === "on" && ( + Multiple Payers Item}> + + + + + )} {t("bodyshop.labels.responsibilitycenters.sales_tax_codes")} From c154e7be2ef8b707a9bc2450652d8e3c5df5eebc Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Sep 2022 08:41:45 -0700 Subject: [PATCH 9/9] IO-223 ARMS bug fixes. --- server/data/arms.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/server/data/arms.js b/server/data/arms.js index 7e3cd9643..959c13382 100644 --- a/server/data/arms.js +++ b/server/data/arms.js @@ -205,8 +205,8 @@ exports.default = async (req, res) => { Party: { PersonInfo: { PersonName: { - FirstName: job.ownr_fn, - LastName: job.ownr_ln, + FirstName: job.ownr_co_nm ? "" : job.ownr_fn, + LastName: job.ownr_co_nm ? job.ownr_co_nm : job.ownr_ln, }, // Communications: [ // { @@ -336,7 +336,7 @@ exports.default = async (req, res) => { LossDateTime: job.loss_date && moment(job.loss_date) - .tz(bodyshop.timezone) + //.tz(bodyshop.timezone) .format(momentFormat), LossDescCode: "Collision", PrimaryPOI: { @@ -515,8 +515,11 @@ exports.default = async (req, res) => { { TotalType: "LAB", TotalTypeDesc: "Body Labor", - TotalHours: job.job_totals.rates.lab.hours, - TotalAmt: Dinero(job.job_totals.rates.lab.total).toFormat("0.00"), + TotalHours: + job.job_totals.rates.lab.hours + job.job_totals.rates.la1.hours, + TotalAmt: Dinero(job.job_totals.rates.lab.total) + .add(Dinero(job.job_totals.rates.la1.total)) + .toFormat("0.00"), }, { TotalType: "LAF", @@ -635,9 +638,9 @@ exports.default = async (req, res) => { { TotalType: "OTAC", TotalTypeDesc: "Additional Charges", - TotalAmt: Dinero( - job.job_totals.additional.additionalCosts - ).toFormat("0.00"), + TotalAmt: Dinero(job.job_totals.additional.additionalCosts) + .add(Dinero(job.job_totals.additional.pvrt)) + .toFormat("0.00"), }, ], SummaryTotalsInfo: [