Add Finish button handler + intake save API endpoint
- Wizard "Finish" button now submits intake data to the API - New PUT /api/v1/compliance-orders/:id/intake endpoint saves intake data, updates entity, re-dispatches worker, and unpauses batch siblings - Shows success screen with portal link after submission Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3614284a78
commit
7b650179e4
2 changed files with 202 additions and 1 deletions
|
|
@ -1534,6 +1534,139 @@ router.get("/api/v1/compliance-orders/my-orders", async (req, res) => {
|
|||
* Customer confirms they've completed USAC E-File delegation.
|
||||
* Updates order status and notifies the team to begin filing.
|
||||
*/
|
||||
/**
|
||||
* PUT /api/v1/compliance-orders/:id/intake
|
||||
* Save intake data collected from the wizard. Dispatches the worker
|
||||
* to process the filing now that intake is complete.
|
||||
*/
|
||||
router.put("/api/v1/compliance-orders/:id/intake", async (req, res) => {
|
||||
const id = req.params.id;
|
||||
const { intake_data, entity, officers } = req.body ?? {};
|
||||
|
||||
if (!intake_data) {
|
||||
res.status(400).json({ error: "intake_data required" });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Merge new intake data with existing (don't overwrite source/frn)
|
||||
const existing = await pool.query(
|
||||
`SELECT intake_data, batch_id, service_slug, payment_status FROM compliance_orders WHERE order_number = $1`,
|
||||
[id],
|
||||
);
|
||||
if (existing.rows.length === 0) {
|
||||
res.status(404).json({ error: "Order not found" });
|
||||
return;
|
||||
}
|
||||
|
||||
const order = existing.rows[0] as Record<string, unknown>;
|
||||
const oldIntake = (typeof order.intake_data === "string"
|
||||
? JSON.parse(order.intake_data as string)
|
||||
: order.intake_data) || {};
|
||||
const merged = { ...oldIntake, ...intake_data };
|
||||
|
||||
// Update the order with merged intake data
|
||||
await pool.query(
|
||||
`UPDATE compliance_orders
|
||||
SET intake_data = $1,
|
||||
payment_status = CASE WHEN payment_status = 'pending_intake' THEN 'paid' ELSE payment_status END,
|
||||
intake_data_validated = TRUE
|
||||
WHERE order_number = $2`,
|
||||
[JSON.stringify(merged), id],
|
||||
);
|
||||
|
||||
// If entity data was provided, update the telecom_entity too
|
||||
if (entity && entity.frn) {
|
||||
try {
|
||||
await pool.query(
|
||||
`UPDATE telecom_entities SET
|
||||
legal_name = COALESCE(NULLIF($1, ''), legal_name),
|
||||
dba_name = COALESCE(NULLIF($2, ''), dba_name),
|
||||
contact_name = COALESCE(NULLIF($3, ''), contact_name),
|
||||
contact_email = COALESCE(NULLIF($4, ''), contact_email),
|
||||
contact_phone = COALESCE(NULLIF($5, ''), contact_phone),
|
||||
address_street = COALESCE(NULLIF($6, ''), address_street),
|
||||
address_city = COALESCE(NULLIF($7, ''), address_city),
|
||||
address_state = COALESCE(NULLIF($8, ''), address_state),
|
||||
address_zip = COALESCE(NULLIF($9, ''), address_zip)
|
||||
WHERE frn = $10`,
|
||||
[
|
||||
entity.legal_name || "", entity.dba_name || "",
|
||||
entity.contact_name || "", entity.contact_email || "",
|
||||
entity.contact_phone || "",
|
||||
entity.address_street || "", entity.address_city || "",
|
||||
entity.address_state || "", entity.address_zip || "",
|
||||
entity.frn,
|
||||
],
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// Re-dispatch the worker to process this order now that intake is complete
|
||||
const workerUrl = process.env.WORKER_URL || "http://workers:8090";
|
||||
setImmediate(async () => {
|
||||
try {
|
||||
await fetch(`${workerUrl}/jobs`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: "process_compliance_service",
|
||||
order_name: id,
|
||||
order_number: id,
|
||||
service_slug: order.service_slug as string,
|
||||
}),
|
||||
});
|
||||
console.log(`[compliance-orders] Worker re-dispatched after intake: ${id}`);
|
||||
} catch (err) {
|
||||
console.warn(`[compliance-orders] Worker dispatch failed for ${id}:`, err);
|
||||
}
|
||||
});
|
||||
|
||||
// If this is a batch order, check if all orders in the batch have intake
|
||||
// and dispatch any that were also pending
|
||||
if (order.batch_id) {
|
||||
try {
|
||||
const pending = await pool.query(
|
||||
`SELECT order_number, service_slug FROM compliance_orders
|
||||
WHERE batch_id = $1 AND payment_status = 'pending_intake' AND order_number != $2`,
|
||||
[order.batch_id, id],
|
||||
);
|
||||
for (const po of pending.rows as any[]) {
|
||||
// Update their intake data too (same entity info)
|
||||
await pool.query(
|
||||
`UPDATE compliance_orders
|
||||
SET intake_data = jsonb_set(COALESCE(intake_data::jsonb, '{}'::jsonb), '{entity_filled}', 'true'::jsonb),
|
||||
payment_status = 'paid'
|
||||
WHERE order_number = $1 AND payment_status = 'pending_intake'`,
|
||||
[po.order_number],
|
||||
);
|
||||
// Dispatch worker
|
||||
setImmediate(async () => {
|
||||
try {
|
||||
await fetch(`${workerUrl}/jobs`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
action: "process_compliance_service",
|
||||
order_name: po.order_number,
|
||||
order_number: po.order_number,
|
||||
service_slug: po.service_slug,
|
||||
}),
|
||||
});
|
||||
console.log(`[compliance-orders] Batch sibling dispatched: ${po.order_number}`);
|
||||
} catch {}
|
||||
});
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
res.json({ ok: true, order_number: id });
|
||||
} catch (err) {
|
||||
console.error("[compliance-orders] Intake save error:", err);
|
||||
res.status(500).json({ error: "Failed to save intake data" });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/api/v1/compliance-orders/:id/usac-delegation", async (req, res) => {
|
||||
const id = req.params.id;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue