- Add todays-stops test and component to collection-map - Expand collection-map sidebar and pin-model - Rework orders/[id]/process page - Add quotes/[id]/page and process pages - Add quotes/approvals/[id] page - Add buyer-tasks generate-po route - Add quotes partial-approve and pdf routes - Add purchase-orders [id]/pdf route - Add e2e create-flows spec - Add superpowers plan doc - Update pb_schema-2.json - Update form components (company, customer, order, quote, supplier) - Update UI components (button, command, dialog) - Add collection-pool test components Co-authored-by: Orca <help@stably.ai>
58 lines
2.3 KiB
TypeScript
58 lines
2.3 KiB
TypeScript
/**
|
|
* Placeholder customer / company sentinels.
|
|
*
|
|
* n8n's email-intake pipeline creates these records when it can't
|
|
* match the sender's email to a real customer (or to a real
|
|
* company) — they're the "operator needs to fill this in" marker.
|
|
* The quote / order goes through the system with these IDs so the
|
|
* downstream flows (PDF gen, approval routing, email send) keep
|
|
* working, but the office is expected to swap them out for the
|
|
* real customer before the quote goes out.
|
|
*
|
|
* Centralised here so the picker UI (`CustomerSearch`), the PDF
|
|
* guard, and the service-layer validation all agree on what counts
|
|
* as "real". Adding a new placeholder is a one-line change instead
|
|
* of a three-file find-and-replace.
|
|
*
|
|
* Detection rules (in order):
|
|
* 1. The customer record's PB id is in `PLACEHOLDER_CUSTOMER_IDS`.
|
|
* Stable PKs, so this matches even if the row's `customer`
|
|
* name has been re-typed.
|
|
* 2. The customer name matches one of `PLACEHOLDER_CUSTOMER_NAMES`
|
|
* exactly (after trim). Defensive fallback in case the row
|
|
* was re-created after a PB wipe and the id changed.
|
|
* 3. The customer has no email. The n8n pipeline writes these
|
|
* sentinels with `email = ""` because it never matched them
|
|
* to a real contact; legitimate customers should always have
|
|
* an email on file. Catches the "MANUAL - SET CUSTOMER"
|
|
* placeholder even if a future operator renamed it.
|
|
*/
|
|
|
|
export const PLACEHOLDER_CUSTOMER_IDS = new Set<string>([
|
|
"2tmt34gzj44v9f8", // SELECT/CREATE CUSTOMER (process-page initial selection)
|
|
"dcpb38w4mk6vrm5", // Unknown Sender (email intake sentinel)
|
|
"xmd68ps32k1x5fu", // MANUAL - SET CUSTOMER (n8n email pipeline sentinel)
|
|
]);
|
|
|
|
export const PLACEHOLDER_CUSTOMER_NAMES = new Set<string>([
|
|
"SELECT/CREATE CUSTOMER",
|
|
"Unknown Sender",
|
|
"No Header",
|
|
"MANUAL - SET CUSTOMER",
|
|
]);
|
|
|
|
/**
|
|
* True iff the customer is one of the placeholder sentinels and
|
|
* the operator needs to swap it for a real one before pricing /
|
|
* sending the quote. Pass anythin with an `id`, `customer`, and
|
|
* `email` shape — we don't need the full record.
|
|
*/
|
|
export function isPlaceholderCustomer(
|
|
c: { id: string; customer?: string; email?: string },
|
|
): boolean {
|
|
return (
|
|
PLACEHOLDER_CUSTOMER_IDS.has(c.id) ||
|
|
PLACEHOLDER_CUSTOMER_NAMES.has((c.customer || "").trim()) ||
|
|
!c.email
|
|
);
|
|
}
|