Sales Management

Why this is a runtime problem, not a CRUD problem

Sales execution spans four departments in sequence: the sales rep closes the deal, the warehouse ships, finance collects, and customer service handles returns. Each handoff — quotation accepted, order approved, shipment confirmed, RMA authorized — is a contract that must be permissioned, audited, and survive mid-flight changes such as currency rate shifts, partial shipments, or order amendments.

The CRM use case ends at opportunity.won. The Sales plugin picks up exactly there: the sl:convert_quotation_to_order command on an accepted quotation (sl_sales_quotation) produces a sales order (sl_sales_order) and carries the source-quote reference forward. Everything downstream — shipment, payment collection, RMA, credit memo — is orchestrated through the same command pipeline that enforces five-layer permissions, emits audit events, and remains reachable from automation rules and AI agents.

Data model summary

The Sales plugin ships 17 models. The core ones:

  • sl_sales_quotation + sl_sales_quotation_line — Formal quote with revision control, validity date, discount, margin; states draft → sent → accepted | rejected | expired. Code auto-generated as SQ-{yyyyMMdd}-{seq}.
  • sl_sales_order + sl_sales_order_line — Core sales document with multi-currency totals (transaction + base), ATP date, IPC traceability class; states draft → pending → approved → delivering → completed | cancelled. Code: SO-{yyyyMMdd}-{seq}.
  • sl_shipment + sl_shipment_line — Warehouse fulfillment linked to a sales order; states draft → confirmed | cancelled. Code: SH-{yyyyMMdd}-{seq}.
  • sl_packing + sl_packing_line — Nested container (carton/pallet) with serial number tracking; linked to a shipment.
  • sl_sales_collection — Payment collection record tracking received amounts and payment method; aggregates payment status back to the order.
  • sl_sales_return + sl_sales_return_line — Return order with fault attribution and inspection workflow.
  • sl_rma — Return Merchandise Authorization with inspection result, disposition decision (repair / replace / refund / scrap), and credit memo linkage; states authorized → received → inspected → disposition_decided → closed.
  • sl_credit_memo — Financial credit document generated from RMA; states draft → approved → applied | cancelled.
  • sl_order_change — Formal order change request with old-vs-new impact assessment and manager approval.
  • sl_price_list + sl_price_list_item — Effective-dated price list with currency, priority tier, and per-product line items.
  • sl_discount_rule — Configurable discount: percentage, fixed amount, or tiered by quantity.

The plugin declares dependencies on crm (account data), product-catalog (product master), inventory (warehouse stock), and finance (exchange rates). Importing Sales without CRM is rejected at resolution time.

Key commands

The Sales plugin defines 82 commands. Six representative ones:

CommandShapeRiskIdempotentWhy it matters
sl:convert_quotation_to_orderActionwritetrueOne-step accepted-quote → sales order; sets sl_so_source_quote_id
sales.order.confirmStateTransitionwritetruedraft → pending; gates on required fields before entering approval queue
sl:approve_sales_orderStateTransitionwritetruepending → approved; handler checks customer credit limit
sl:confirm_shipmentStateTransitionwritetrueCommits shipment; updates order fulfillment progress
sales.rma.approveStateTransitionwritetrueAuthorizes return; triggers goods-receipt workflow
sl:apply_credit_memoStateTransitionwritetrueapproved → applied; offsets against AR; irreversible once applied

A "Approve" button on the order detail page is wired to sl:approve_sales_order — not to a raw PUT /api/sl_sales_order. The same command is reachable from automation rules ("auto-approve orders under threshold") and from AI agents that carry the agentHint: "Use only after credit-limit check has passed" guard.

Process flow

Quotation         Order              Fulfillment         Post-sale
---------         -----              -----------         ---------

sl_sales_         sl_sales_order     sl_shipment         sl_rma
quotation         (draft)            (draft)             (authorized)
  |                 |                   |                    |
sent              pending            confirmed            received
  |                 |                                        |
accepted          approved    -----> sl_sales_           inspected
  |                 |                collection              |
  +--convert-->  delivering    (payment collected)    disposition_decided
                    |                                        |
                 completed                             sl_credit_memo
                                                        (applied) <--+

Permission example

A realistic Sales configuration across all five layers:

  • Layer 1 RBAC: Sales rep holds sl.sales.manage and sl.sales.read; not sl.financial.credit_memo (Finance team only) or sl.rma.manage (Customer Service).
  • Layer 2 Org scope: data visibility limited to the rep's own org subtree (org-and-descendants on sl_so_assigned_to). A rep in APAC cannot list EMEA orders even by guessed ID — the row filter is appended at the SQL layer.
  • Layer 3 Org scope — own orders: sales rep sees only orders where sl_so_assigned_to is in their own org subtree. Cross-region visibility requires an explicit manager grant.
  • Layer 4 ABAC — RMA approval gated by amount: sales.rma.approve is available only when sl_rma_authorized_amount ≤ 10_000; above that the platform routes to a manager-approval BPM step before the transition fires.
  • Layer 5 Field-level masking: the sl_so_credit_limit and customer credit-score fields are masked from operations staff — invisible on form, omitted from API responses, stripped from CSV export. Finance staff sees them; operations does not.

All five layers are evaluated in order. No custom controller code needed.

Process orchestration

The quote-to-cash flow is a BPM process where each task resolves to a command:

                ┌──────────────────────┐
                │ Quotation sent       │  <-  sl:send_sales_quotation
                └──────────┬───────────┘
                           |
              ┌────────────v────────────┐
              │ Customer response       │
              └──┬────────────────────┬─┘
                 | accepted           | rejected/expired
       ┌─────────v──────────┐    ┌────v──────────────┐
       │ Convert to order   │    │ Archive quotation  │
       └─────────┬──────────┘    └───────────────────┘
                 |  <-  sl:convert_quotation_to_order
       ┌─────────v──────────┐
       │ Submit + approve   │  <-  sales.order.confirm, sl:approve_sales_order
       └─────────┬──────────┘
                 |
       ┌─────────v──────────┐
       │ Shipment + packing │  <-  sl:create_shipment, sl:confirm_shipment
       └─────────┬──────────┘
                 |
       ┌─────────v──────────┐
       │ Collection         │  <-  sl:create_sales_collection (auto-aggregates to order)
       └─────────┬──────────┘
                 |
       ┌─────────v──────────┐
       │ RMA loop (if any)  │  <-  sales.rma.approve, sl:inspect_rma,
       │                    │      sl:decide_rma_disposition, sl:apply_credit_memo
       └────────────────────┘

Order change requests mid-flight go through sl_order_change: impact is calculated, submitted for approval, and applied via sl:apply_order_change — the original order line records carry old-vs-new history.

Agent integration

Three command classes are intentionally exposed to AI agents:

  1. Read-and-summarize (sl_sales_order.list_overdue, sales_dashboard.kpi_summary) — read-only, idempotent, low risk. Agents call freely.
  2. Drafting (sl:create_sales_quotation, sl:add_sq_line) — write, idempotent, reversible. Agent drafts a quotation from an RFQ; the sales rep reviews and sends it.
  3. Operational nudges (sl:calculate_atp, sl:check_compliance) — write, idempotent. Agent flags an ATP risk on a pending order; cannot itself approve it.

What is not exposed: sl:apply_credit_memo (irreversible financial), sl:cancel_sales_order in approved state (supply-chain commitment), sl:delete_sales_order. These carry agentHint: "Human-only".

How to get it

  • Community: build it yourself. The DSL, command pipeline, state-machine engine and five-layer permissions are all open-source; the Sales plugin itself is not bundled.
  • Standard: white-label the base platform; build your own sales-shaped plugin on top.
  • Professional: get the Sales solution package — 17 models, 82 commands, 33 pages (including Kanban board and real-time dashboard), pre-wired roles and price-list engine.
  • Enterprise: same package plus dedicated delivery engineering, multi-currency reconciliation design, ERP/WMS integration, and SLA-backed support.

See Pricing for the full edition comparison.

Enterprise note — Marketplace publication of vertical plugin packs, License/Entitlement enforcement on the Command pipeline, cross-tenant Agent Control Plane for multi-region order orchestration, and Observability Pro per-stage trace spans are commercial-only capabilities. The open-core runtime described above is the same in every edition.

Next steps

  • CRM use case — how leads and opportunities flow upstream into sales quotations
  • System overview — how plugins, commands, and the runtime fit together
  • Command pipeline — the execution contract used by every command above
  • Permissions — the five-layer model illustrated by the Sales rep example
  • Plugin manifest — how dependency resolution works across Sales, CRM, Inventory and Finance
  • Agent readiness — designing agentHint and risk fields for safe execution