Out-of-territory (OOT) quote registration
Audience: developers & AI agents · Scope: the OOT form, the
oot_statuslifecycle, 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
- 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 thebcootformmodal: project state/city (hard-coded Canada+US state list), market sector (hard-coded list — seedocs/_known-issues.md#35), specifier type/name/city/state. The agency contact name/e-mail shown are read-only display; they are not stored. - Save —
ConfigboxControllerBcootform::submitOotForm()→ConfigboxModelBcquotes::saveOotFormData(): one UPDATE writingoot_status = 'registered'+ the sevenoot_*columns (added by0.5.38; the enum isnot_oot | registered | processing | approved). A deal update is scheduled and two notification e-mails go out — tosales@betacalco.com(hard-coded) and an acknowledgement to the agent. - Review — a quote maker opens the console's OOT Registration Details block
(
views/bcqmquotedetails) and edits the fields / movesoot_status; the save goes througheditQuote()'s allowlist and schedules the export. This is the only place the status moves after registration. (The console block renders read-only for anot_ootquote, so a quote maker cannot initiate an OOT registration.) - 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
| Surface | What shows |
|---|---|
| Agent quote view | after registration: a collapsible read-only summary with a status badge (amber registered / blue processing / green approved); no re-edit, no withdraw |
| Quote Console detail | the editable OOT Registration Details block — status select + the seven fields (free text there) |
| Pipedrive deal | the Is-OOT custom field, Yes only when approved, and only when the field key is configured |
| Nothing else | not 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.
Related docs
- 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)