Skip to content

Multi-Connection Organizations & Document Routing

Organizations in Ordermatic can connect to multiple ERP systems or facilities (e.g. multiple Great Plains, Prophet21, or WhereFour instances). This document outlines the data model, routing decision engine, review UX, and feature flag conventions governing multi-connection organizations.

Historically, an organization could hold at most one active ERP connection, enforced by a unique partial index. The multi-connection architecture relaxes this constraint:

  1. Explicit Default (is_default):

    • erp_connections.is_default designates the fallback connection for the organization.
    • Enforced by a partial unique index erp_connections_default_org_unique ensuring at most one active default connection per organization.
    • Deactivating or deleting a default connection is rejected; another active connection must be designated as default first.
    • Resolvers (getOrganizationDefaultERPConnection) query WHERE active = true ORDER BY is_default DESC, created_at DESC.
  2. Short Facility Codes (short_label):

    • erp_connections.short_label holds a 2–4 character uppercase identifier (e.g. OH, TX, DAL) displayed on inbox chips, badges, and pickers.
    • Unique per active connection within an organization via a case-insensitive unique index.
  3. Per-Document Binding & Effective Connection:

    • Document routing is bound on pdf_documents.erp_connection_id.
    • Work items query effective connection via COALESCE(pdf_documents.erp_connection_id, email_aliases.erp_connection_id) so document binding takes precedence over the mailbox alias.

Every routing decision is recorded in erp_routing_decisions:

  • Fields:
    • id: UUID primary key
    • pdf_document_id: Target PDF document (FK)
    • from_connection_id: Source ERP connection (nullable for initial binding)
    • to_connection_id: Destination ERP connection
    • source: Routing reason:
      • upload: Manual upload picker
      • alias: Inbound mailbox alias binding
      • prior_decision: Historical human routing decision for the same sender domain / customer key (Flywheel)
      • rule: Matching intake routing rule (inbox_routing_rules)
      • default: Fallback to organization default connection
      • human: Reviewer confirmed or changed the destination in the review workbench
    • rule_id: FK to inbox_routing_rules (when source = 'rule')
    • sender_domain & customer_key: Extracted signals indexed alongside clerk_organization_id for $O(1)$ flywheel lookups
    • signals: JSONB metadata (extracted customer name, ship-to state, broker flags)
    • actor_id & actor_email: Identity of human router (for manual decisions)

The review-v2 workbench displays ReviewRoutingCard when an organization has multiple active connections:

  • Destination Derivation:
    • Derived from the connections of all matched lines (extracted_order_items.erp_connection_id).
    • If all lines belong to one connection, that connection is the derived destination.
    • If lines belong to multiple connections, split routing is required.
  • Human Confirmation:
    • CSR can confirm the derived destination or choose another facility.
    • Re-picks customer matching if switching destination facilities.
  • Submit Gates:
    • ROUTING_UNCONFIRMED: Blocks submission if an order’s latest decision was from source = 'default' and has not been confirmed by a human router.
    • SPLIT_REQUIRED: Blocks submission if matched line items belong to multiple ERP connections (directs user to Quote Split).
    • Legacy documents without decision rows pass automatically.

Intake Routing Rules & Prior Decision Flywheel

Section titled “Intake Routing Rules & Prior Decision Flywheel”

When erp_connection_routing_rules_v1 is enabled:

  1. Prior Decision Flywheel: Before evaluating rules, intake inspects recent human routing decisions matching (clerk_organization_id, sender_domain, customer_key). If found, routes with source = 'prior_decision'.
  2. Intake Routing Rules: Evaluates active inbox_routing_rules with action_type = 'route_to_connection' ordered by priority:
    • Supports customer_name_match, customer_name_in, and sender_domain_in triggers.
    • If matched, routes with source = 'rule'.

In the review workbench item search modal (ERPSearchModal):

  • Single-connection organizations search only their local catalog.
  • Multi-connection organizations can check “Search all locations”.
  • /api/erp/parts?scope=org queries Typesense using connection_id IN [...], ranking items from the local connection first and labelling foreign items with their facility short label.
  • Selecting an item from another facility prompts for confirmation and binds the line to that facility.
Flag Scope Purpose
erp_multi_connection_v1 Organization (getFlagForOrganization) Gates multiple active connections, inbox chips, connection pickers, and submit gates
erp_connection_routing_rules_v1 Organization (getFlagForOrganization) Gates intake routing sweep (flywheel and route_to_connection rules)
  • Document-bound surfaces (review cards, extraction, matching, pricing, ERP writes) evaluate on the connection identity (getFlagForConnection).
  • Org-level surfaces (inbox list, backlog lists, chips, team, analytics, settings) evaluate on the organization identity (getFlagForOrganization), never on the default connection.
  • Cross-Reference Test: Every conn_* segment in infrastructure/flagsmith/configs/segments.json must have a corresponding org_* sibling segment, enforced by test_flagsmith_config_cross_references.py.