Portal login + forgot-password read the Postgres customers table (bcrypt), NOT ERPNext. ensureCompliancePortalUser (the common path for Stripe/PayPal/crypto via handlePaymentComplete) only provisioned the ERPNext customer/website-user and never created the customers row -- so customers (notably PayPal, who reach this path directly) had no account to log into or reset a password against. Now upserts the customers row (no password; ON CONFLICT keeps any existing hash) with name + company so they can register/reset and log in immediately. Also: narrowed the placeholder-email skip from 'any synthetic@ or pipeline.com' to exactly 'synthetic@pipeline.com' (the FMCSA-census placeholder) so real customers on those real consumer domains aren't wrongly skipped -- which is what bit Paul Wilson. Added cc support to sendEmail. e2e-paypal-portal-fix.mjs is the regression test (seeds a compliance order, runs handlePaymentComplete, asserts the customers row is created). Rescue scripts for the affected customer included.
69 lines
3.9 KiB
JavaScript
69 lines
3.9 KiB
JavaScript
/**
|
|
* Correction email for Paul Wilson - the earlier "next steps" email wrongly said
|
|
* "no action is required." His MCS-150 and UCR DO require him to complete the
|
|
* intake form (and the MCS-150 needs his signature, since it's a perjury
|
|
* certification we never auto-submit). This sends the correct intake links.
|
|
* CC justin@performancewest.net.
|
|
*
|
|
* Run: docker exec performancewest-api-1 node /app/scripts/rescue-paul-correct.mjs
|
|
*/
|
|
import pg from "pg";
|
|
import nodemailer from "nodemailer";
|
|
|
|
const EMAIL = "synthetic@pipeline.com";
|
|
const CC = "justin@performancewest.net";
|
|
const NAME = "Paul Wilson";
|
|
const COMPANY = "Compound Technologies, Inc";
|
|
const SITE = process.env.DOMAIN ? `https://${process.env.DOMAIN}` : "https://performancewest.net";
|
|
|
|
const pool = new pg.Pool({ connectionString: process.env.DATABASE_URL });
|
|
const mailer = nodemailer.createTransport({
|
|
host: process.env.SMTP_HOST || "co.carrierone.com",
|
|
port: parseInt(process.env.SMTP_PORT || "587", 10),
|
|
secure: false,
|
|
auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
|
|
});
|
|
const FROM = process.env.SMTP_FROM || "Performance West <noreply@performancewest.net>";
|
|
const firstName = NAME.split(" ")[0];
|
|
|
|
const { rows } = await pool.query(
|
|
`SELECT order_number, service_name, service_slug, COALESCE(intake_data_validated,false) AS done
|
|
FROM compliance_orders WHERE customer_email=$1 ORDER BY created_at`,
|
|
[EMAIL],
|
|
);
|
|
|
|
const items = rows.map(o => {
|
|
const url = `${SITE}/order/${o.service_slug}?order=${o.order_number}`;
|
|
const note = o.service_slug === "mcs150-update"
|
|
? " (we will prepare the filing from your intake, then send it to you to sign before we submit to FMCSA)"
|
|
: "";
|
|
return `<li style="margin:8px 0;font-size:14px;color:#374151">
|
|
<a href="${url}" style="color:#1e40af;font-weight:600;text-decoration:underline">${o.service_name}</a>
|
|
<span style="color:#888;font-family:monospace">(${o.order_number})</span>${note}
|
|
</li>`;
|
|
}).join("");
|
|
|
|
await mailer.sendMail({
|
|
from: FROM, to: EMAIL, cc: CC,
|
|
subject: "Correction: please complete your intake forms to start your filings",
|
|
html: `<div style="font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:24px;color:#222">
|
|
<h2 style="color:#1a2744;margin:0 0 8px">Quick correction - one step needed from you</h2>
|
|
<p>Hi ${firstName}, apologies - my previous email said no action was needed. That was not
|
|
correct. To begin your filings for ${COMPANY}, please complete the short intake form for
|
|
each service below (about 2-5 minutes each). We cannot start a filing until its intake is done.</p>
|
|
<ul style="padding-left:18px">${items}</ul>
|
|
<p style="font-size:14px;color:#374151">For the <strong>MCS-150 Biennial Update</strong>, after you
|
|
complete intake we prepare the update and send it to you to review and sign - we never submit a
|
|
certification to FMCSA without your signature. The <strong>Drug & Alcohol program binder</strong>
|
|
is delivered to you to review and adopt once its intake is complete.</p>
|
|
<p style="font-size:13px;color:#666">If you have not set your portal password yet, use the link in the
|
|
separate "Set your password" email so you can log in and track everything. Questions? Reply here or
|
|
call 1-888-411-0383.</p>
|
|
<p style="font-size:12px;color:#9ca3af">Performance West Inc. · performancewest.net · 1-888-411-0383</p>
|
|
</div>`,
|
|
text: `Hi ${firstName}, correction: my earlier email wrongly said no action was needed. Please complete the intake form for each service to start your filings:\n` +
|
|
rows.map(o => `- ${o.service_name} (${o.order_number}): ${SITE}/order/${o.service_slug}?order=${o.order_number}`).join("\n") +
|
|
`\nThe MCS-150 will be sent to you to sign before we submit to FMCSA. Questions? 1-888-411-0383.`,
|
|
});
|
|
console.log(`[correct] sent correction with intake links to ${EMAIL} (cc ${CC}) for ${rows.length} orders`);
|
|
await pool.end();
|