# Design - Order Quote Payment Field Inheritance

Status: binding implementation note
Date: 2026-06-13
Scope: PingCAP downstream L2 pack metadata, restored standard Create Order authority, and final-pack assembly
Related: staging inspection run `27413293553`, case `order-create-field-inheritance-api`, issues `#172`, `#613`, `#1604`, `#2165`

Milestone question: where should Order display, line-item fan-out, and billing-field inheritance from Quote live, and what proves the installable pack carries it?

## 0. Bottom line

The PingCAP payment-field and display-name pieces belong in L2. The standard Create Order action and QuoteLineItem -> OrderItem fan-out are L1 CRM metadata already present in the pinned official app pack, but the downstream overlay was replacing the aggregate action and mapping files and dropping the `createOrder` rows from the final pack.

The fix is therefore two-part:

- restore `createOrder` action/mapping metadata in the downstream overlay so the final pack preserves the official standard action authority
- keep the PingCAP-specific `Payment_Term__c` / `Payment_Type__c` inheritance and Order display-name metadata in L2

Durable read path:

`Quote action -> createOrder standard action -> Std_CreateOrderFromQuote -> createOrder field mappings -> Order + OrderItems`

PingCAP billing-field path:

`createOrder Order create -> L2 before-save flow / L2 createOrder mapping -> Order.Payment_Term__c / Order.Payment_Type__c`

Display-name path:

`Order.OrderNumber autonumber -> L2 Order.Name compound metadata -> runtime compound-name synthesis -> final pack install`

## 1. The issue

The staging inspection cases create a Quote through `actions/standard/createQuote`, patch or enrich the Quote/QLIs, then create an Order from that Quote.

The line-item case showed the parent Order was created, but no OrderItems were created from the source QuoteLineItems. The payment-field case patches the Quote with:

- `Payment_Term__c = "30"`
- `Payment_Type__c = "Pay in Full"`

The previous direct Order create path succeeded, and the resulting Order had the expected Quote, Opportunity, Account, Contract, Pricebook, Currency, and Status values. The remaining failures were:

- no `OrderItem` rows created from source `QuoteLineItem` rows
- `Order.Payment_Term__c` and `Order.Payment_Type__c` read back as `null`

This is not a seed failure. The run artifact shows the Quote patch returned `204`, the Order create returned `201`, and the final query returned one Order row.

The same inspection case also asserts `Order.Name == OrderNumber`. During local validation, the payment-field fix exposed that Order was missing the L2 compound display-name metadata already present on Quote and Contract. That is fixed as the same L2 metadata binding rather than as backend special-case code.

## 2. Current state

| Surface | Current behavior | Owner/source | Runtime reader/writer | Target disposition |
| --- | --- | --- | --- | --- |
| L0/L1 runtime | Supports standard actions, flow execution, field mappings, record-triggered flows, record lookups, and `$Record` assignments. | upstream `NexusCRM` | standard action dispatcher / flow executor | Keep as generic mechanism. |
| Standard Create Order | Pinned official app pack contains `createOrder`, `Std_CreateOrderFromQuote`, and `createOrder` mappings. | `nexuscrm-app-packs` | standard action dispatcher / flow executor | Preserve those rows in the final downstream overlay. |
| PingCAP L2 fields | `Quote` and `Order` both define `Payment_Term__c` and `Payment_Type__c`. | `packs/Salesforce-PingCAP-L2/objects` | metadata install and runtime API | Keep as PingCAP field authority. |
| Order display name | `OrderNumber` is generated, but `Order.Name` did not declare a compound composition from `OrderNumber`. | `packs/Salesforce-PingCAP-L2/objects/Order.json` | metadata install and compound-name synthesis | Match the Quote/Contract generated-name pattern in L2. |
| Field mappings | The L2 aggregate mapping file previously kept `createQuote` mappings but dropped `createOrder` mappings from the official pack. | `packs/Salesforce-PingCAP-L2/field_mappings/standard_field_mappings.json` | standard action metadata | Restore Quote -> Order and QuoteLineItem -> OrderItem `createOrder` rows; add PingCAP payment fields to Quote -> Order. |
| Existing flow pattern | L2 before-save flows already look up related records and stamp fields, for example line-item autofill flows. | `packs/Salesforce-PingCAP-L2/flows` | flow executor | Reuse this pattern for Order create. |
| Final pack | Assembly filters flows through `stack.lock.json` `pack_build.flow_whitelist`. | `scripts/build_pingcap_salesforce_sample_pack.sh` | pack build | Whitelist `Std_CreateOrderFromQuote` and the L2 payment flow, then regenerate. |

## 3. Decision

Restore the standard `createOrder` path in the downstream final pack:

- add `Std_CreateOrderFromQuote` to the flow whitelist
- preserve `createOrder` in `actions/invocable_standard_actions.json`
- add `Quote -> Order` and `QuoteLineItem -> OrderItem` `createOrder` mappings
- remove the legacy Quote `CreateOrder` `NavigateToNewRecord` action so the frontend falls back to the standard action authority

Also add `Order_Quote_Payment_Field_Inheritance` as an L2 `standard_flow`.

The flow:

- runs before-save on `Order` create only
- requires `QuoteId` to be present
- looks up the source `Quote`
- assigns `Payment_Term__c` and `Payment_Type__c` from that Quote onto the new Order

Creation-only scope is intentional. This is inheritance at the Order creation seam, not a durable background synchronization rule. Existing Orders and later Order edits are left alone unless a future product decision asks for backfill or ongoing sync.

Also declare `Order.Name` as a compound name composed from `OrderNumber`, matching the generated-number display pattern used by Quote and Contract without tightening the existing physical column's nullability.

## 4. Authority and non-goals

The flow is PingCAP L2 policy. It must not be implemented as upstream runtime special case logic, because `Order.Payment_Term__c` and `Order.Payment_Type__c` are PingCAP CRM fields and the generic flow substrate is already sufficient.

The standard `createOrder` action remains the durable Order creation path. Do not add a separate direct Order insert child-clone flow; that would create two fan-out authorities and risks duplicate OrderItems when the standard action path is used.

This PR does not backfill existing staging/prod Orders and does not change Quote creation.

## 5. Gates

The implementation is complete only when all of these are true:

- L2 pack contains `flows/Order_Quote_Payment_Field_Inheritance.flow.json`.
- L2 `pack.json` registers the flow.
- `stack.lock.json` whitelists `Std_CreateOrderFromQuote` and the L2 flow so final-pack assembly cannot drop either.
- `packs/NOT-EDIT-final-merged-packs` is regenerated and contains both flows.
- Final pack contains `createOrder` in `actions/invocable_standard_actions.json`.
- Final pack contains `createOrder` `Quote -> Order` and `QuoteLineItem -> OrderItem` mappings.
- Final pack no longer exposes the legacy Quote `CreateOrder` `NavigateToNewRecord` UI action.
- A local metadata test verifies the flow shape in both L2 and final pack.
- A local metadata test and final-pack audit verify `Order.Name` composes from `OrderNumber`.
- Local bootstrap can install the regenerated final pack into a fresh local environment.
- The targeted inspection case can be rerun against the local environment or a deployed branch environment.

## 6. Deferred work

Backfill for historical Orders is deferred. If Sales Ops needs existing Order rows repaired, that should be a separate, idempotent migration or seed-backed operational task with its own verification.

Ongoing Quote-to-Order resync is also deferred. A future design would need to decide conflict semantics for Orders that have already been edited after creation.
