Focus mode active/Press Alt+Shift+R to toggle/Esc to exit
Final StretchOrdered learning track

End-to-End Quote-to-Cash Data Flow Case Study

Case study data flow end-to-end dari quote creation, pricing, approval, acceptance, quote-to-order conversion, order decomposition, fulfillment, product inventory, billing charge, invoice, payment, reconciliation, and support traceability untuk enterprise CPQ/Quote/Order/Billing systems.

10 min read1830 words
PrevNext
Lesson 7282 lesson track69–82 Final Stretch
#enterprise-data-modelling#quote-to-cash#cpq#order-management+6 more

End-to-End Quote-to-Cash Data Flow Case Study

1. Core Idea

Setelah memahami puluhan building blocks data modelling, kita perlu melihat semuanya sebagai satu flow.

Quote-to-cash bukan satu entity. Ia adalah rangkaian model:

Customer/Account
  -> Catalog/Product Offering
  -> Quote
  -> Quote Item
  -> Pricing
  -> Approval
  -> Accepted Quote Snapshot
  -> Product Order
  -> Order Item
  -> Decomposition
  -> Fulfillment Task
  -> Product/Service/Resource Inventory
  -> Subscription/Charge
  -> Invoice
  -> Payment
  -> Reconciliation
  -> Reporting

Mental model:

End-to-end correctness depends on preserving intent, snapshot, lineage, state, idempotency, and reconciliation across every boundary.

Case study ini bersifat generic enterprise CPQ/order/billing. Detail internal CSG/team harus diverifikasi pada sistem nyata.


2. Case Scenario

Scenario:

Enterprise customer requests a new connectivity service for a site.
Sales creates quote.
Quote is configured and priced.
Discount requires approval.
Customer accepts quote.
System converts accepted quote into product order.
Order decomposes into fulfillment tasks.
Service is activated.
Product inventory is created.
Recurring charge starts.
Invoice is generated.
Payment is received.

Entities involved:

  • customer,
  • account,
  • billing account,
  • site/address,
  • product offering,
  • product specification,
  • quote,
  • quote item,
  • approval request,
  • product order,
  • order item,
  • fulfillment task,
  • product instance,
  • service instance,
  • resource instance,
  • subscription,
  • recurring charge,
  • invoice,
  • payment.

3. High-Level Flow

flowchart TD A["Customer / Account"] --> B["Quote"] C["Catalog / Product Offering"] --> B B --> D["Quote Item"] D --> E["Pricing Snapshot"] E --> F["Approval Request"] F --> G["Accepted Quote"] G --> H["Product Order"] H --> I["Order Item"] I --> J["Order Decomposition"] J --> K["Fulfillment Task"] K --> L["Product / Service / Resource Inventory"] L --> M["Subscription / Charge"] M --> N["Invoice"] N --> O["Payment"] H --> P["Reporting / Reconciliation"] L --> P M --> P N --> P

Every arrow should preserve reference/lineage.


4. Step 1 — Customer and Account Context

Quote starts with customer/account context.

Important data:

customer_id
account_id
billing_account_id
related_party roles
contact
site/location
currency
sales channel
tenant/environment

Key modelling questions:

  • Is customer/account source-of-truth internal or external?
  • Is billing account selected now or later?
  • Is billing account active?
  • Is site serviceable?
  • Which organization hierarchy applies?
  • Which currency and price list apply?
  • What access scope does sales user have?

Common mistake:

Only store customer name on quote and lose customer/account ID.

Better:

Store reference IDs + required snapshots.

5. Step 2 — Catalog Selection

Sales selects product offering.

Important data:

product_offering_id
product_offering_version
product_specification_id
catalog_version
price_list_id
characteristic selections
bundle parent/child
eligibility/serviceability result

Why version matters:

Order must reflect what customer accepted at quote time, not what catalog says today.

Store:

  • offering reference,
  • offering version,
  • configuration snapshot,
  • price snapshot,
  • serviceability evidence if needed.

6. Step 3 — Quote Item Configuration

Quote item captures commercial intent.

Quote item should model:

  • action: add/modify/disconnect,
  • product offering/spec,
  • quantity,
  • site/location,
  • characteristics,
  • parent/child bundle,
  • target product instance for modify/disconnect,
  • validation result,
  • price snapshot.

Example:

quote_item.action = ADD
quote_item.product_offering_id = INTERNET_500_MBPS
quote_item.site_id = SITE-1
quote_item.bandwidth = 500 Mbps

Invariants:

  • required characteristics present,
  • site serviceable,
  • quantity valid,
  • bundle dependencies valid,
  • target product required for modify/disconnect.

7. Step 4 — Pricing Snapshot

Pricing generates quote price.

Important fields:

list_price
discount_amount
discount_percent
net_price
currency
tax_estimate
price_rule_version
price_list_version
effective_date
calculated_at

Quote should store accepted price snapshot.

Do not recompute old accepted quote price from current price rules during order creation.

Lineage:

quote_item_price <- price_rule_version + product_offering_version + discount decision

8. Step 5 — Approval

Discount or non-standard terms may require approval.

Approval data:

approval_request_id
target_quote_id
target_quote_version
approval_type
step
approver
decision
decision_reason
decision_evidence
decision_at

Critical invariant:

Approval applies to a specific quote version and commercial snapshot.

If quote materially changes after approval, approval may need invalidation.


9. Step 6 — Quote Acceptance

Quote acceptance is commitment boundary.

At acceptance:

  • quote version becomes immutable,
  • accepted snapshot is frozen,
  • acceptance evidence captured,
  • status history written,
  • audit written,
  • outbox event written,
  • conversion status initiated or pending.

Example transaction:

Begin transaction
  quote.status = ACCEPTED
  quote.accepted_at = now
  insert quote_status_history
  insert quote_acceptance_evidence
  insert outbox_event QuoteAccepted
Commit

Important:

  • idempotency key for accept command,
  • expected quote version,
  • validUntil guard,
  • approval still valid,
  • pricing snapshot still valid.

10. Step 7 — Quote-to-Order Conversion

Accepted quote becomes product order.

Mapping:

QuoteOrder
quote.id/versionorder.source_quote_id/version
quote.customer/accountorder.customer/account snapshot/reference
quote.billing_accountorder.billing_account
quote itemorder item
quote item actionorder item action
quote price snapshotorder item commercial snapshot
quote siteorder item site
quote configurationorder item configuration snapshot

Conversion must be idempotent.

Unique rule:

one order per accepted quote version

If retry happens, return existing order.


11. Step 8 — Product Order

Order is executable transaction.

Order fields:

order_id
order_number
source_quote_id
source_quote_version
customer_id
account_id
billing_account_id
status
fulfillment_status
billing_status
requested_completion_date
correlation_id
idempotency_key

Order status should not mean everything.

Suggested separation:

lifecycle_status
fulfillment_status
billing_status
reconciliation_status

Order is now operational, not just commercial proposal.


12. Step 9 — Order Items

Each quote item maps to order item.

Order item fields:

order_item_id
source_quote_item_id
action
product_offering_id/version
product_spec_id
target_product_instance_id
site_id
quantity
configuration_snapshot
commercial_snapshot
status
dependency

Order item drives downstream work.

Examples:

  • ADD -> create product/service/resource,
  • MODIFY -> update existing product/service/resource,
  • DISCONNECT -> terminate product/service/resource and charges.

13. Step 10 — Decomposition

Order decomposition turns commercial order into executable tasks.

Outputs:

  • service order,
  • resource order,
  • fulfillment task,
  • billing instruction,
  • inventory update plan,
  • dependency graph.

Lineage:

decomposition_output.source_order_item_id
decomposition_output.rule_version
decomposition_output.workflow_template_version

Why important:

If fulfillment task is wrong, engineer needs to know which order item and decomposition rule created it.


14. Step 11 — Fulfillment

Fulfillment tasks execute work.

Task data:

fulfillment_task_id
order_item_id
task_type
target_system
status
external_request_id
retry_count
fallout_reason_code
completion_proof

Task states:

CREATED
READY
SENT
ACKNOWLEDGED
IN_PROGRESS
COMPLETED
FALLOUT
RETRY_PENDING
MANUAL_INTERVENTION
CANCELLED

Fulfillment completion should not blindly complete order. It should update the relevant item/task and trigger inventory update where appropriate.


15. Step 12 — Product, Service, and Resource Inventory

On successful fulfillment:

product_instance created/updated
service_instance created/updated
resource_instance reserved/assigned/activated

Product instance fields:

product_instance_id
source_order_id
source_order_item_id
customer_id
account_id
product_offering_id/version
status
activation_date
billing_account_id
subscription_id

Service/resource realizes product.

Lineage:

product_instance <- order_item <- quote_item <- product_offering_version

This lineage supports future modify/disconnect.


16. Step 13 — Subscription and Charge Activation

For recurring product:

subscription created/activated
recurring_charge created/activated
billing schedule created

Charge fields:

charge_id
product_instance_id
subscription_item_id
billing_account_id
charge_type
amount
currency
effective_from
effective_to
status
source_order_item_id

Billing readiness guard:

  • product active,
  • billing account active,
  • charge snapshot exists,
  • no duplicate active charge,
  • effective date valid,
  • billing profile complete.

17. Step 14 — Invoice

Billing system generates invoice/invoice lines.

Invoice line should trace to:

  • charge,
  • product instance,
  • order item,
  • billing account,
  • service period.

Important:

invoice_line.charge_id
invoice_line.product_instance_id
invoice_line.order_item_id
billing_period_start/end
amount
tax_amount
currency

Invoice is usually immutable once issued. Corrections should use adjustment/credit/debit according to policy.


18. Step 15 — Payment

Payment may be external.

Payment data:

payment_id
invoice_id
payment_provider_reference
amount
currency
status
paid_at
payment_method_reference

Do not store raw payment secret/card data unless explicitly compliant and required.

Payment status should reconcile to invoice status.


19. End-to-End Identity and Lineage

Critical references:

quote.id/version
quote_item.id
order.id
order_item.id
fulfillment_task.id
product_instance.id
service_instance.id
resource_instance.id
subscription.id
charge.id
invoice.id
invoice_line.id
payment.id

A support/engineer should trace:

invoice line -> charge -> product instance -> order item -> quote item -> quote

If this trace is impossible, the model is not enterprise-grade.


20. End-to-End Events

Possible event chain:

QuoteCreated
QuotePriced
ApprovalRequested
ApprovalApproved
QuoteAccepted
QuoteConversionRequested
ProductOrderCreated
ProductOrderSubmitted
OrderDecomposed
FulfillmentTaskCreated
FulfillmentTaskCompleted
ProductActivated
ChargeActivated
InvoiceIssued
PaymentReceived

Event metadata:

event_id
event_type
event_version
aggregate_id
aggregate_version
tenant_id
correlation_id
causation_id
occurred_at

Events should be minimal, versioned, and idempotent.


21. End-to-End Correlation

A single correlation ID should connect:

  • API request,
  • quote acceptance,
  • order conversion,
  • outbox events,
  • workflow process,
  • fulfillment integration,
  • billing trigger,
  • inventory update,
  • support timeline.

Example:

correlation_id = corr-quote-accept-123

This lets support reconstruct the full flow.


22. End-to-End Idempotency

Idempotency boundaries:

ActionKey
Accept quotequote_id + quote_version + accept request
Convert quote to orderquote_id + quote_version
Create order itemorder_id + source_quote_item_id
Create fulfillment taskorder_item_id + task_type + decomposition_run
Activate productorder_item_id + product_spec/resource key
Activate chargeproduct_instance_id + charge_type + effective_from
Create invoice linecharge_id + billing_period
Process payment callbackprovider + transaction_id

Idempotency should be enforced by persistence, not only memory/cache.


23. End-to-End Reconciliation

Important reconciliation rules:

Accepted quote should have order.
Order item fulfilled should have product instance.
Active product should have active charge if billable.
Terminated product should not have active charge beyond end date.
Charge should appear on invoice line when billed.
Invoice paid status should match payment.
Product inventory should match service/resource inventory where applicable.
Outbox published events should be consumed by required consumers.

Reconciliation closes the gap between distributed steps.


24. Support Timeline Example

Support timeline for this case:

10:00 Quote created
10:05 Quote priced
10:07 Approval requested
10:30 Approval approved
10:45 Quote accepted
10:45 QuoteAccepted event published
10:46 Order created
10:47 Order decomposed
10:49 Fulfillment task sent to OSS
11:10 Fulfillment completed
11:11 Product instance activated
11:12 Charge activated
Next cycle Invoice issued
Payment received

Timeline should include failures, retries, and manual repairs if any.


25. Failure Scenario A — Accepted Quote but No Order

Symptoms:

  • quote accepted,
  • customer expects order,
  • no order exists.

Likely causes:

  • outbox event stuck,
  • order consumer failed,
  • idempotency conflict,
  • conversion validation error,
  • workflow issue.

Detection:

Accepted quote older than threshold with no order.

Repair:

  • inspect quote conversion status,
  • check outbox/inbox,
  • retry conversion using same idempotency key,
  • avoid duplicate order,
  • record repair.

26. Failure Scenario B — Product Active but Not Billed

Symptoms:

  • service delivered,
  • product inventory active,
  • no recurring charge.

Likely causes:

  • billing trigger failed,
  • billing account invalid,
  • charge creation duplicate conflict,
  • event lost,
  • product not marked billable,
  • mapping missing.

Detection:

Active billable product without active recurring charge.

Repair:

  • verify billing readiness,
  • create/retry charge idempotently,
  • reconcile with billing system,
  • audit financial impact.

This is revenue leakage risk.


27. Failure Scenario C — Billing Active but Service Not Active

Symptoms:

  • customer billed,
  • service not delivered.

Likely causes:

  • billing triggered before fulfillment proof,
  • service activation failed after charge activation,
  • state regression,
  • integration mismatch.

Detection:

Active charge but product/service not active.

Repair:

  • suspend/stop billing or issue credit,
  • fix fulfillment,
  • create compensation,
  • link incident.

This is customer trust risk.


28. Failure Scenario D — Modify Order Loses Product Lineage

Symptoms:

  • customer wants modify existing product,
  • system cannot find installed product/source order,
  • wrong product modified.

Likely causes:

  • product instance missing source order item,
  • external ID mapping ambiguous,
  • quote item target product not captured,
  • migration lost lineage.

Prevention:

modify quote/order item must reference target_product_instance_id
product instance must preserve source_order_item_id
external_reference must map OSS/billing IDs

29. Failure Scenario E — Reporting Dispute

Symptoms:

  • sales dashboard says booking amount X,
  • billing dashboard says revenue Y,
  • finance says recognized revenue Z.

Cause:

  • different metrics:
    • quoted,
    • booked,
    • billed,
    • collected,
    • recognized.

Prevention:

  • metric definitions,
  • fact grain,
  • source lineage,
  • time basis,
  • revenue stage separation.

Do not force one number to mean all financial states.


30. PostgreSQL Traceability Query Examples

Trace invoice line back to quote:

select
  il.id as invoice_line_id,
  c.id as charge_id,
  pi.id as product_instance_id,
  oi.id as order_item_id,
  qi.id as quote_item_id,
  q.id as quote_id,
  q.quote_number
from invoice_line il
join charge c on c.id = il.charge_id
join product_instance pi on pi.id = c.product_instance_id
join product_order_item oi on oi.id = pi.source_order_item_id
join quote_item qi on qi.id = oi.source_quote_item_id
join quote q on q.id = qi.quote_id
where il.id = :invoice_line_id;

Actual schema may differ. The pattern matters: preserve links.

Find accepted quotes without order:

select q.id, q.quote_number, q.version, q.accepted_at
from quote q
left join product_order o
  on o.source_quote_id = q.id
 and o.source_quote_version = q.version
where q.status = 'ACCEPTED'
  and q.accepted_at < now() - interval '15 minutes'
  and o.id is null;

Find active billable products without charge:

select pi.id, pi.product_instance_number, pi.customer_id
from product_instance pi
left join recurring_charge rc
  on rc.product_instance_id = pi.id
 and rc.status = 'ACTIVE'
where pi.status = 'ACTIVE'
  and pi.billable = true
  and rc.id is null;

31. Java/JAX-RS Service Boundary View

Possible services:

QuoteService
ApprovalService
OrderService
FulfillmentService
InventoryService
BillingIntegrationService
InvoiceService
PaymentIntegrationService
ReconciliationService
ReportingProjectionService

Important:

  • each service owns its data,
  • commands enforce invariants,
  • events propagate facts,
  • projections support reads,
  • reconciliation verifies cross-service truth,
  • support timeline joins operational evidence.

Avoid one service directly mutating all tables.


32. Case Study PR Review Checklist

For quote-to-cash flow changes, ask:

  • Is quote snapshot preserved?
  • Is quote version used?
  • Is quote-to-order idempotent?
  • Is source quote item mapped to order item?
  • Is order item action explicit?
  • Is fulfillment output linked to order item?
  • Is product instance linked to order item?
  • Is charge linked to product instance/order item?
  • Is invoice line linked to charge?
  • Are billing readiness guards defined?
  • Are events versioned and correlated?
  • Are reconciliation rules updated?
  • Are support timeline entries available?
  • Are reporting metric definitions affected?
  • Are external IDs/mappings preserved?
  • Are privacy/security classifications respected?

33. Internal Verification Checklist

Verify these in the internal CSG/team context:

  • Actual source-of-truth for quote/order/billing/product inventory.
  • Whether quote-to-order conversion stores quote version.
  • Whether order items map to quote items.
  • Whether product instances map to order items.
  • Whether billing charges map to product instances/order items.
  • Whether invoice lines map to charges.
  • Whether fulfillment/service/resource inventory mapping exists.
  • Whether end-to-end correlation ID is propagated.
  • Whether support can trace invoice line back to quote/order.
  • Whether accepted quote without order reconciliation exists.
  • Whether active product without charge reconciliation exists.
  • Whether billing active but service inactive reconciliation exists.
  • Whether CSG-specific extensions to TMF APIs affect this flow.

34. Summary

End-to-end quote-to-cash modelling is about preserving business intent through execution.

A strong flow must preserve:

  • customer/account context,
  • catalog version,
  • quote item configuration,
  • pricing snapshot,
  • approval evidence,
  • quote acceptance immutability,
  • quote-to-order mapping,
  • order item actions,
  • decomposition lineage,
  • fulfillment evidence,
  • product/service/resource inventory,
  • subscription/charge linkage,
  • invoice/payment traceability,
  • correlation/causation,
  • idempotency,
  • reconciliation,
  • support timeline,
  • reporting source definitions.

The key principle:

Quote-to-cash correctness is not a single status or table. It is a chain of snapshots, references, events, states, and reconciliations that must remain traceable from customer promise to cash collection.

Lesson Recap

You just completed lesson 72 in final stretch. Use the series map if you want to review the broader track, or continue directly into the next lesson while the context is still warm.

Continue The Track

Keep the momentum while the lesson is still fresh. Move backward for review or continue forward into the next concept.