← back to Sample Followup Sweep

lib/compose.js

58 lines

'use strict';
// Phase 3 — Compose. vendor + follow-up rows -> { to, subject, html }
// Verbatim to the letter Steve approved in the canary.

function esc(s) {
  return String(s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

function compose(vendor, rows) {
  // TK-12320 (Cody): never emit a follow-up letter with no items in it.
  if (!Array.isArray(rows) || rows.length === 0) throw new Error('compose: refusing an empty follow-up letter (0 outstanding items)');
  const account = vendor.account_number || '‹CONFIRM DW ACCOUNT #›';
  // Steve 8/20: fall back to the vendor's main email when no sample email exists.
  const to = vendor.sample_email || vendor.main_email || '‹CONFIRM SAMPLE EMAIL›';
  // Steve 9/01: show the DATE WE ORDERED + the MANUFACTURER # (the vendor's own SKU). NEVER our
  // internal DW reference ("combo sku" / DW###). Two conditional columns appear only when populated:
  //   • Pattern Name  — the item name (used when the Manufacturer # is blank so the item is still IDable)
  //   • Your Ref / Tracking — the vendor's OWN order/confirmation # or shipment tracking # from their reply
  const hasName = rows.some(r => r.name);
  const hasRef = rows.some(r => r.ref);
  const th = (t) => `<th style="padding:5px 18px 5px 0">${t}</th>`;
  const td = (v, bold) => `<td style="padding:5px 18px 5px 0;white-space:nowrap">${bold ? '<strong>' : ''}${esc(v || '—')}${bold ? '</strong>' : ''}</td>`;
  const headHtml = `<tr style="text-align:left;border-bottom:2px solid #333">${th('Date Ordered')}${th('Manufacturer #')}${hasName ? th('Pattern Name') : ''}${hasRef ? th('Your Ref / Tracking') : ''}</tr>`;
  const rowsHtml = rows.map(r => `<tr style="border-bottom:1px solid #eee">${td(r.requested)}${td(r.mfr, true)}${hasName ? td(r.name) : ''}${hasRef ? td(r.ref) : ''}</tr>`).join('\n');

  const subject = `Sample Follow-Up — Outstanding Memos (Acct ${account}) — Designer Wallcoverings`;
  const s = vendor.ship_to;

  const html = `<div style="font-family:Arial,Helvetica,sans-serif;font-size:14px;color:#222;line-height:1.5">
<p>We are following up because we have not received the following samples from 10 days ago.<br>
Hopefully we removed any disco items internally from this list before asking again.</p>
<hr style="border:none;border-top:1px solid #ccc">
<p><strong>Our account number is ${esc(account)}</strong></p>
<p>We ordered 1 memo sample of each item below — please quote the Manufacturer # when you reply about an item.</p>
<table style="border-collapse:collapse;font-size:14px;margin:8px 0">
${headHtml}
${rowsHtml}
</table>
<hr style="border:none;border-top:1px solid #ccc">
<p>Ship to the address below.</p>
<p><strong>Sidemark: Samples ASAP</strong></p>
<p>
${esc(s.name)}<br>
${esc(s.line1)}<br>
${esc(s.city_state_zip)}<br>
${esc(s.phone)}
</p>
<p>We truly appreciate the help.</p>
<p>Best Regards,<br>Showroom Manager</p>
<p style="font-size:11px;color:#666">Designer Wallcoverings · 15442 Ventura Blvd. #102 · Sherman Oaks, CA 91403<br>
To stop receiving sample follow-up emails, <a href="mailto:info@designerwallcoverings.com?subject=Unsubscribe%20from%20sample%20follow-ups">unsubscribe here</a>.</p>
</div>`;

  return { to, subject, html };
}

module.exports = { compose };