diff --git a/client/src/components/card-payment-modal/card-payment-modal.component..jsx b/client/src/components/card-payment-modal/card-payment-modal.component..jsx index 2142c8efc..e5059d14a 100644 --- a/client/src/components/card-payment-modal/card-payment-modal.component..jsx +++ b/client/src/components/card-payment-modal/card-payment-modal.component..jsx @@ -14,10 +14,12 @@ import { selectBodyshop } from "../../redux/user/user.selectors"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component"; import JobSearchSelectComponent from "../job-search-select/job-search-select.component"; +import { getCurrentUser } from "../../firebase/firebase.utils"; const mapStateToProps = createStructuredSelector({ cardPaymentModal: selectCardPayment, - bodyshop: selectBodyshop + bodyshop: selectBodyshop, + currentUser: getCurrentUser }); const mapDispatchToProps = (dispatch) => ({ @@ -25,7 +27,13 @@ const mapDispatchToProps = (dispatch) => ({ toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment")) }); -const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisible, insertAuditTrail }) => { +const CardPaymentModalComponent = ({ + bodyshop, + currentUser, + cardPaymentModal, + toggleModalVisible, + insertAuditTrail +}) => { const { context, actions } = cardPaymentModal; const [form] = Form.useForm(); @@ -142,7 +150,7 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi return acc + (val?.amount || 0); }, 0), account: payments && data && data.jobs.length > 0 ? data.jobs.map((j) => j.ro_number).join(", ") : null, - comment: btoa(JSON.stringify(payments)), + comment: btoa(JSON.stringify({ payments, userEmail: currentUser.email })), paymentSplitMeta: form.getFieldsValue() }); if (response.data) { diff --git a/client/src/components/payments-generate-link/payments-generate-link.component.jsx b/client/src/components/payments-generate-link/payments-generate-link.component.jsx index 5ecd72514..5d19556c8 100644 --- a/client/src/components/payments-generate-link/payments-generate-link.component.jsx +++ b/client/src/components/payments-generate-link/payments-generate-link.component.jsx @@ -8,11 +8,12 @@ import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions"; -import { selectBodyshop } from "../../redux/user/user.selectors"; +import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component"; const mapStateToProps = createStructuredSelector({ - bodyshop: selectBodyshop + bodyshop: selectBodyshop, + currentUser: selectCurrentUser }); const mapDispatchToProps = (dispatch) => ({ openChatByPhone: (phone) => dispatch(openChatByPhone(phone)), @@ -20,7 +21,7 @@ const mapDispatchToProps = (dispatch) => ({ }); export default connect(mapStateToProps, mapDispatchToProps)(PaymentsGenerateLink); -export function PaymentsGenerateLink({ bodyshop, callback, job, openChatByPhone, setMessage }) { +export function PaymentsGenerateLink({ bodyshop, currentUser, callback, job, openChatByPhone, setMessage }) { const { t } = useTranslation(); const [form] = Form.useForm(); @@ -41,7 +42,7 @@ export function PaymentsGenerateLink({ bodyshop, callback, job, openChatByPhone, bodyshop, amount: amount, account: job.ro_number, - invoice: job.id + comment: btoa(JSON.stringify({ payments: [{ jobid: job.id, amount }], userEmail: currentUser.email })) }); setLoading(false); setPaymentLink(response.data.shorUrl); diff --git a/server/email/sendemail.js b/server/email/sendemail.js index 85534b815..3a07486b7 100644 --- a/server/email/sendemail.js +++ b/server/email/sendemail.js @@ -96,7 +96,7 @@ const sendServerEmail = async ({ subject, text }) => { } }; -const sendTaskEmail = async ({ to, subject, text, attachments }) => { +const sendTaskEmail = async ({ to, subject, type = "text", html, text, attachments }) => { try { transporter.sendMail( { @@ -107,7 +107,7 @@ const sendTaskEmail = async ({ to, subject, text, attachments }) => { }), to: to, subject: subject, - text: text, + ...(type === "text" ? { text } : { html }), attachments: attachments || null }, (err, info) => { diff --git a/server/email/tasksEmails.js b/server/email/tasksEmails.js index aac9ebf4f..292d7c92e 100644 --- a/server/email/tasksEmails.js +++ b/server/email/tasksEmails.js @@ -94,7 +94,8 @@ const formatPriority = (priority) => { * @param taskId * @returns {{header, body: string, subHeader: string}} */ -const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId) => { + +function getEndpoints() { const endPoints = InstanceManager({ imex: process.env?.NODE_ENV === "test" ? "https://test.imex.online" : "https://imex.online", rome: @@ -106,6 +107,10 @@ const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, j ? "https//test.romeonline.io" : "https://romeonline.io" }); + return endPoints; +} +const generateTemplateArgs = (title, priority, description, dueDate, bodyshop, job, taskId) => { + const endPoints = getEndpoints(); return { header: title, subHeader: `Body Shop: ${bodyshop.shopname} | Priority: ${formatPriority(priority)} ${formatDate(dueDate)}`, @@ -333,5 +338,6 @@ const tasksRemindEmail = async (req, res) => { module.exports = { taskAssignedEmail, - tasksRemindEmail + tasksRemindEmail, + getEndpoints }; diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index 65cbef473..3ce8e5b09 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -2502,6 +2502,13 @@ exports.GET_JOBS_BY_PKS = `query GET_JOBS_BY_PKS($ids: [uuid!]!) { jobs(where: {id: {_in: $ids}}) { id shopid + ro_number + ownr_co_nm + ownr_fn + ownr_ln + v_make_desc + v_model_yr + v_model_desc } } `; diff --git a/server/intellipay/intellipay.js b/server/intellipay/intellipay.js index 3682e549b..831ade65c 100644 --- a/server/intellipay/intellipay.js +++ b/server/intellipay/intellipay.js @@ -7,7 +7,9 @@ const axios = require("axios"); const moment = require("moment"); const logger = require("../utils/logger"); const InstanceManager = require("../utils/instanceMgr").default; - +const { sendTaskEmail } = require("../email/sendemail"); +const generateEmailTemplate = require("../email/generateTemplate"); +const { getEndpoints } = require("../email/tasksEmails"); require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) }); @@ -166,7 +168,16 @@ exports.postback = async (req, res) => { if (comment) { //Shifted the order to have this first to retain backwards compatibility for the old style of short link. //This has been triggered by IO and may have multiple jobs. - const partialPayments = JSON.parse(comment); + const parsedComment = JSON.parse(comment); + + //Adding in the user email to the short pay email. + //Need to check this to ensure backwards compatibility for clients that don't update. + let partialPayments; + if (!Array.isArray(parsedComment)) { + partialPayments = parsedComment.payments; + } else { + partialPayments = parsedComment; + } const jobs = await gqlClient.request(queries.GET_JOBS_BY_PKS, { ids: partialPayments.map((p) => p.jobid) }); @@ -197,6 +208,25 @@ exports.postback = async (req, res) => { paymentResult }); res.sendStatus(200); + if (values.origin === "OneLink" && parsedComment.userEmail) { + //Send an email, it was a text to pay link. + const endPoints = getEndpoints(); + sendTaskEmail({ + to: parsedComment.userEmail, + subject: `New Payment(s) Received - RO ${jobs.jobs.map((j) => j.ro_number).join(", ")}`, + type: "html", + html: generateEmailTemplate({ + header: "New Payment(s) Received", + subHeader: "", + body: jobs.jobs + .map( + (job) => + `Reference: ${job.ro_number || "N/A"} | ${job.ownr_co_nm ? job.ownr_co_nm : `${job.ownr_fn || ""} ${job.ownr_ln || ""}`.trim()} | ${`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${job.v_model_desc || ""}`.trim()} | $${partialPayments.find((p) => p.jobid === job.id).amount}` + ) + .join("
") + }) + }); + } } else if (values.invoice) { //This is a link email that's been sent out. const job = await gqlClient.request(queries.GET_JOB_BY_PK, {