Add engagement authorization, remove price headers from intake pages, fix duplicate emails
- Add clickwrap authorization checkbox to fcc-compliance, state-puc, neca-ocn order pages - Store engagement_accepted_at/ip/version in compliance_orders (migration 074) - Add 499-A past-due/multi-year eSign engagement letter generator - Gate 499-A handler on engagement signature for past-due/multi-year orders - Remove price/tax/fee headers from all 19 intake pages (post-payment only) - Fix duplicate confirmation email for compliance_batch orders - Add USAC past-due fee negotiation research doc Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6171c64b90
commit
cbfb8d6091
29 changed files with 602 additions and 52 deletions
12
api/migrations/074_engagement_columns.sql
Normal file
12
api/migrations/074_engagement_columns.sql
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
-- 074_engagement_columns.sql
|
||||
-- Store client engagement authorization consent for compliance orders.
|
||||
-- Part 1: clickwrap checkbox consent for all orders.
|
||||
-- Part 2: eSign engagement letter for 499-A past-due/multi-year refiling.
|
||||
|
||||
ALTER TABLE compliance_orders
|
||||
ADD COLUMN IF NOT EXISTS engagement_accepted_at TIMESTAMPTZ,
|
||||
ADD COLUMN IF NOT EXISTS engagement_accepted_ip TEXT,
|
||||
ADD COLUMN IF NOT EXISTS engagement_version TEXT,
|
||||
ADD COLUMN IF NOT EXISTS engagement_esign_required BOOLEAN DEFAULT FALSE,
|
||||
ADD COLUMN IF NOT EXISTS engagement_esign_signed_at TIMESTAMPTZ,
|
||||
ADD COLUMN IF NOT EXISTS engagement_letter_minio_key TEXT;
|
||||
|
|
@ -1462,7 +1462,11 @@ export async function handlePaymentComplete(
|
|||
}
|
||||
|
||||
// ── Send order confirmation email ──────────────────────────────────────
|
||||
try {
|
||||
// Skip for compliance_batch — sendComplianceIntakeEmail already sent
|
||||
// a combined confirmation + intake email above.
|
||||
if (order_type === "compliance_batch") {
|
||||
console.log(`[checkout] Skipping generic confirmation for ${order_id} — intake email already sent`);
|
||||
} else try {
|
||||
await sendOrderConfirmationEmail({
|
||||
order_id,
|
||||
order_type,
|
||||
|
|
|
|||
|
|
@ -701,6 +701,8 @@ router.post("/api/v1/compliance-orders", async (req, res) => {
|
|||
// Multi-year catch-up (migration 060) — array of reporting years.
|
||||
// 2+ years gets the 15% multi-year discount.
|
||||
multi_year_filings,
|
||||
// Engagement authorization (migration 074)
|
||||
engagement_accepted,
|
||||
} = req.body ?? {};
|
||||
|
||||
if (!service_slug || !customer_email || !customer_name) {
|
||||
|
|
@ -844,8 +846,9 @@ router.post("/api/v1/compliance-orders", async (req, res) => {
|
|||
discount_code, discount_cents, notes, intake_data,
|
||||
filing_mode, form_year_override, revises_order_number, revised_reason,
|
||||
waive_deminimis_exemption, waive_deminimis_reason,
|
||||
multi_year_filings, multi_year_discount_pct
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22)
|
||||
multi_year_filings, multi_year_discount_pct,
|
||||
engagement_accepted_at, engagement_accepted_ip, engagement_version
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25)
|
||||
RETURNING *`,
|
||||
[
|
||||
order_number,
|
||||
|
|
@ -870,6 +873,9 @@ router.post("/api/v1/compliance-orders", async (req, res) => {
|
|||
waive_deminimis_reason || null,
|
||||
myf && myf.length > 0 ? myf : null,
|
||||
multi_year_discount_pct || null,
|
||||
engagement_accepted ? new Date().toISOString() : null,
|
||||
engagement_accepted ? (req.ip || req.headers["x-forwarded-for"] || null) : null,
|
||||
engagement_accepted ? "v1-2026-04" : null,
|
||||
],
|
||||
);
|
||||
|
||||
|
|
@ -898,6 +904,7 @@ router.post("/api/v1/compliance-orders/batch", async (req, res) => {
|
|||
customer_phone,
|
||||
discount_code,
|
||||
intake_data,
|
||||
engagement_accepted,
|
||||
} = req.body ?? {};
|
||||
|
||||
if (!rawServices || !Array.isArray(rawServices) || rawServices.length === 0) {
|
||||
|
|
@ -997,8 +1004,9 @@ router.post("/api/v1/compliance-orders/batch", async (req, res) => {
|
|||
order_number, batch_id, service_slug, service_name, service_fee_cents,
|
||||
gov_fee_cents, gov_fee_label,
|
||||
customer_email, customer_name, customer_phone,
|
||||
discount_code, discount_cents, intake_data
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13)
|
||||
discount_code, discount_cents, intake_data,
|
||||
engagement_accepted_at, engagement_accepted_ip, engagement_version
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)
|
||||
RETURNING *`,
|
||||
[
|
||||
orderNumber,
|
||||
|
|
@ -1014,6 +1022,9 @@ router.post("/api/v1/compliance-orders/batch", async (req, res) => {
|
|||
discount_code || null,
|
||||
svcDiscount,
|
||||
intake_data ? JSON.stringify(intake_data) : "{}",
|
||||
engagement_accepted ? new Date().toISOString() : null,
|
||||
engagement_accepted ? (req.ip || req.headers["x-forwarded-for"] || null) : null,
|
||||
engagement_accepted ? "v1-2026-04" : null,
|
||||
],
|
||||
);
|
||||
orders.push(result.rows[0]);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue