Skip to main content

Out-of-territory (OOT) quote registration

Audience: developers & AI agents · Scope: the OOT form, the oot_status lifecycle, where OOT data surfaces, and the Pipedrive Is-OOT flag · Last reviewed: 2026-08-25

TL;DR — An agent whose project lies outside their territory registers it from the quote view: a modal (views/bcootform) collects project location, market sector and specifier details, sets quotes.oot_status = 'registered' plus seven oot_* detail columns, emails sales@betacalco.com, and schedules a Pipedrive export. From there the lifecycle is manual: quote makers move the status in the console (registered → processing → approved — no cron, no webhook, no admin screen does it), and only approved flips the deal's Is-OOT custom field to Yes. Live currently runs with the Is-OOT field key blank, so the flag never reaches Pipedrive there.

The flow

  1. Register — the Register out-of-territory quote button appears on the agent quote view only while oot_status = 'not_oot' (views/bcquote/tmpl/default.php). It opens the bcootform modal: project state/city (hard-coded Canada+US state list), market sector (hard-coded list — see docs/_known-issues.md #35), specifier type/name/city/state. The agency contact name/e-mail shown are read-only display; they are not stored.
  2. SaveConfigboxControllerBcootform::submitOotForm()ConfigboxModelBcquotes::saveOotFormData(): one UPDATE writing oot_status = 'registered' + the seven oot_* columns (added by 0.5.38; the enum is not_oot | registered | processing | approved). A deal update is scheduled and two notification e-mails go out — to sales@betacalco.com (hard-coded) and an acknowledgement to the agent.
  3. Review — a quote maker opens the console's OOT Registration Details block (views/bcqmquotedetails) and edits the fields / moves oot_status; the save goes through editQuote()'s allowlist and schedules the export. This is the only place the status moves after registration. (The console block renders read-only for a not_oot quote, so a quote maker cannot initiate an OOT registration.)
  4. Approved — the export sends the deal's Is-OOT custom field as Yes only for approved; every other status sends No (updatePipedriveDeal(); the change log records the flip).

Where it surfaces

SurfaceWhat shows
Agent quote viewafter registration: a collapsible read-only summary with a status badge (amber registered / blue processing / green approved); no re-edit, no withdraw
Quote Console detailthe editable OOT Registration Details block — status select + the seven fields (free text there)
Pipedrive dealthe Is-OOT custom field, Yes only when approved, and only when the field key is configured
Nothing elsenot on the quote PDF, spec sheets, commission reports or exports — OOT has no priced/commission effect in code; routing on it happens outside the system

Admin settings

Three Pipedrive settings (Settings → Pipedrive Integration, external table): the Is-OOT field key (pipedrive_field_name_is_oot — blank = the field is simply skipped, which is live's current state) and the two option ids (pipedrive_oot_option_yes / _no). The Is-OOT field is not part of the provisioning manifest — see pipedrive/field-registry.md.

Testing

tests/specs/agent/submit-oot-form.spec.ts covers the registration path (status registered, deal update scheduled, Is-OOT still No). The console transitions and the e-mails are untested.

Known defects in this area (authorization, the promised-but-unsent approval e-mail) are tracked in docs/_known-issues.md #44/#45 — not here.

  • quotes/lifecycle-and-pricing.md — OOT as one of the quote's four status axes
  • pipedrive/deal-updates.md — where Is-OOT sits in the payload
  • Operator view: admin-guide/sales-agent/create-a-quote.md (the button), admin-guide/quotes-sales/use-the-quote-console.md (the review block)