# Kugamon Full Qtc Submgmt

> Manage the full Kugamon Quote-to-Cash lifecycle in Salesforce — opportunities, quotes, orders, invoices, payments, shipments, and assets, which uses the kugo2p namespace (Kugamon Quote to Cash). And optionally Managed the full Kugamon Subscription Billing lifecycle in Salesforce - opportunities, quotes, orders, invoices, payments, shipments, contracts, subscriptions, and assets, which requires the kuga_sub namespace (Kugamon Subscription Management). Detects which packages are installed and adapts accordingly. Use when users request operations on any Kugamon object.

- Skill: `kugamon/kugamon-full-qtc-submgmt` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kugamon/kugamon-full-qtc-submgmt`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kugamon/kugamon-full-qtc-submgmt/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kugamon (https://skillmd.com/u/kugamon)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kugamon/kugamon-full-qtc-submgmt

---


# Kugamon Use Cases:

Full lifecycle skill for Kugamon RevOps for Salesforce

**CPQ Flow:** Opportunity → Quote → Order → (Order Release) → Asset

Full lifecycle skill for Kugamon Quote to Cash, which is a combination of CPQ and Billing functions

**Q2C Flow:** Opportunity → Quote → Order → (Order Release) → Asset + Shipment → Invoice → Payment 

Full lifecycle skill for Kugamon Subscription Management, which is a combination of CPQ and Subscription Management functions

**SubMgmt Flow:** Opportunity → Quote → Order → (Order Release) → Asset + Contract + Subscription + Renewal Opportunity 

Full lifecycle skill for Kugamon Subscription Billing, which is combination of all Quote to Cash and Subscription Management functions

**SB Flow:** Opportunity → Quote → Order → (Order Release) → Asset + Shipment + Contract + Subscription + Renewal Opportunity → Invoice → Payment 



## Package Detection

**FIRST STEP: Always detect which packages are installed.**

Check if `kuga_sub__Renew__c` exists on `OpportunityLineItem` by describing the object's fields via the connected Salesforce MCP or API.

- `HAS_KUGA_SUB = true` → kuga_sub package is installed (subscription management, contracts, assets, renewals)
- `HAS_KUGA_SUB = false` → only kugo2p (Q2C only, no subscription lifecycle)

This flag controls revenue classification, line-item separation, and whether Order Release creates contracts/assets/subscriptions.

---

## ⚠️ CRITICAL: Opportunity Pipeline Forecasting Field

**When `HAS_KUGA_SUB = true` (Kugamon Subscription Management is installed), ALWAYS use `kuga_sub__Amount__c` for Opportunity pipeline forecasting. DO NOT use the standard Salesforce `Amount` field.**

### Why this matters

The standard `Amount` field on Opportunity is unreliable in subscription orgs — it can be configured to display MRR, ACV, TCV, or some other value, and the meaning varies by org and even by opportunity. Using it for forecasting will produce incorrect pipeline numbers.

`kuga_sub__Amount__c` is a Roll-Up SUM field maintained by the Kugamon Subscription Management package. It aggregates the correct revenue values from OpportunityLineItems and is the authoritative figure for pipeline reporting in subscription orgs.

### Rules

1. **`HAS_KUGA_SUB = true`** → use `kuga_sub__Amount__c` for all pipeline forecasts, revenue reports, dashboards, and aggregate opportunity-level reporting. Never substitute the standard `Amount` field.
2. **`HAS_KUGA_SUB = false`** → use the standard `Amount` field as normal (the `kuga_sub__*` fields don't exist).
3. When a user asks about "opportunity amount," "pipeline value," or "forecast" in a subscription org, default to `kuga_sub__Amount__c` and briefly explain why.
4. When building SOQL queries, reports, or list views for pipeline in a subscription org, select `kuga_sub__Amount__c` — not `Amount`.

### Quick example

```sql
-- CORRECT (HAS_KUGA_SUB = true):
SELECT Id, Name, kuga_sub__Amount__c
FROM Opportunity
WHERE IsClosed = false

-- WRONG (HAS_KUGA_SUB = true):
SELECT Id, Name, Amount
FROM Opportunity
WHERE IsClosed = false
```

See **Appendix B: Amount Fields Guide** for detailed field-by-field reference and comparison rules.

---

## Org-Specific Setup

**NEVER hardcode Record Type IDs.** Always query dynamically:

```sql
SELECT Id, Name, SObjectType, DeveloperName
FROM RecordType
WHERE SObjectType IN (
  'kugo2p__SalesQuote__c', 'kugo2p__SalesOrder__c',
  'kugo2p__Payment_Profile__c', 'kugo2p__Processor_Connection__c',
  'kugo2p__Payment_Method__c', 'Opportunity'
)
AND IsActive = true
ORDER BY SObjectType, Name
```

Cache results for the session. Map by name: Opportunity "New" → Quote "New" → Order "New", etc.

---

## Object Model Overview

### kugo2p Objects (Kugamon Quote to Cash — ~50 custom objects)

**Quote Stage:**
- `kugo2p__SalesQuote__c` (~95 fields) — master quote
- `kugo2p__SalesQuoteServiceLine__c` (~89 fields) — recurring service lines
- `kugo2p__SalesQuoteProductLine__c` (~76 fields) — one-time product lines
- `kugo2p__SalesQuoteOptionalLine__c` (~16 fields) — optional upsell lines
- `kugo2p__SalesQuoteAdditionalChargeCredit__c` (~34 fields) — surcharges/discounts
- `kugo2p__QuoteLineGroup__c` (~14 fields) — line grouping

**Order Stage:**
- `kugo2p__SalesOrder__c` (~110 fields) — master order
- `kugo2p__SalesOrderServiceLine__c` (~108 fields) — recurring service order lines
- `kugo2p__SalesOrderProductLine__c` (~105 fields) — one-time product order lines
- `kugo2p__SalesOrderAdditionalChargeCredit__c` (~39 fields) — surcharges/discounts
- `kugo2p__OrderLineGroup__c` (~13 fields) — line grouping

**Invoice Stage:**
- `kugo2p__KugamonInvoice__c` (~73 fields) — invoice
- `kugo2p__KugamonInvoiceLine__c` (~47 fields) — invoice line items
- `kugo2p__KugamonInvoiceAdditionalChargeCredit__c` (~39 fields) — invoice adjustments
- `kugo2p__OrderInvoiceRelationship__c` (~15 fields) — order-to-invoice link
- `kugo2p__InvoiceSchedule__c` (~15 fields) — recurring invoice generation

**Payment Stage:**
- `kugo2p__PaymentX__c` (~71 fields) — payment records
- `kugo2p__AppliedPayment__c` (~22 fields) — payment-to-invoice allocation
- `kugo2p__Processor_Connection__c` (~52 fields) — gateway configs (Stripe, AuthNet, PayPal, eWay)
- `kugo2p__Payment_Method__c` (~32 fields) — payment method definitions
- `kugo2p__Payment_Profile__c` (~57 fields) — customer payment profiles

**Fulfillment Stage:**
- `kugo2p__Shipment__c` (~31 fields) — shipment records
- `kugo2p__ShipmentLine__c` (~27 fields) — shipment line items
- `kugo2p__ServiceDeliverySchedule__c` (~30 fields) — service delivery tracking
- `kugo2p__Carrier__c` (~11 fields) — shipping carriers
- `kugo2p__Warehouse__c` (~17 fields) — warehouse/inventory locations

**Product & Pricing:**
- `kugo2p__AdditionalProductDetail__c` (~64 fields) — extended product metadata (Service flag, weight, dimensions, tax, etc.)
- `kugo2p__AccountPricing__c` (~26 fields) — customer-specific pricing overrides
- `kugo2p__TieredPricing__c` (~16 fields) — volume/tiered pricing headers
- `kugo2p__Tier__c` (~12 fields) — individual tier definitions
- `kugo2p__ProductCost__c` (~11 fields) — product cost tracking
- `kugo2p__AdditionalChargeCredit__c` (~29 fields) — reusable charge/credit templates
- `kugo2p__ProductCatalog__c` (~19 fields) — product catalog
- `kugo2p__ProductCategory__c` — product categories
- `kugo2p__ProductCategoryProduct__c` — category-product junction

**Configuration & Bundles:**
- `kugo2p__ConfigurationGroup__c` (~16 fields) — product configuration groups
- `kugo2p__ConfigurationOption__c` (~27 fields) — configuration options
- `kugo2p__KitBundleMember__c` (~15 fields) — kit/bundle components

**Tax:**
- `kugo2p__TaxLocation__c` (~15 fields) — US tax jurisdictions
- `kugo2p__TaxRate__c` (~13 fields) — US tax rates
- `kugo2p__VAT__c` (~12 fields) — international VAT definitions
- `kugo2p__VATRate__c` (~15 fields) — VAT rates

**Account:**
- `kugo2p__AdditionalAccountDetail__c` (~44 fields) — extended account metadata

**Settings:**
- `kugo2p__KugamonSetting__c` (~78 fields) — master org-wide settings
- `kugo2p__Settings__c` (~19 fields) — additional settings

**Utility:**
- `kugo2p__Favorite__c`, `kugo2p__FavoriteMember__c`, `kugo2p__FavoriteShare__c`
- `kugo2p__Shopping_Cart_Item__c` (~21 fields)

### kuga_sub Objects (Kugamon Subscriptions — only when HAS_KUGA_SUB = true)

**Custom Objects:**
- `kuga_sub__Subscription__c` (34 fields) — the subscription record linking orders to contracts

**Fields added to standard objects by kuga_sub:**

On **Product2** (4 fields):
- `kuga_sub__Renewable__c` (Checkbox) — drives the "Renewable" prefix on Product setup labels (e.g. in the Product Snapshot LWC) **and** triggers Renewal Opportunity creation on Order Release. Does NOT itself create a Subscription.
- `kuga_sub__RenewalProduct__c` (Lookup Product) — substitute product for renewal quotes
- `kuga_sub__Track__c` (Checkbox, **label: "Create Subscription"**) — when `true` AND the line lands on an **Order Service Line** (`kugo2p__SalesOrderServiceLine__c`, i.e. `APD.kugo2p__Service__c = true`), the Order Service Line trigger generates a `kuga_sub__Subscription__c` on Order Release. **Order Product Lines never generate Subscriptions, regardless of this flag.**
- `kuga_sub__UpliftRenewalPrice__c` (Checkbox) — apply price uplift percentage on renewal

> **Asset creation is separate and Product-only.** APD field `kugo2p__AdditionalProductDetail__c.kugo2p__CreateAsset__c` drives Asset creation, and only **Order Product Lines** (`kugo2p__SalesOrderProductLine__c`) generate Assets. Order Service Lines never generate Assets. Note: `kugo2p` namespace, on APD.

On **OpportunityLineItem** (18 fields):
- `kuga_sub__Renew__c` (Checkbox) — **CRITICAL**: marks line as recurring vs. one-time
- `kuga_sub__ARR__c`, `kuga_sub__MRR__c`, `kuga_sub__NonRecurringRevenue__c` — calculated revenue
- `kuga_sub__ServiceTerm__c`, `kuga_sub__UnitofTerm__c` — term length and unit
- `kuga_sub__DateServiceEnd__c` — service end date
- `kuga_sub__NetAmount__c`, `kuga_sub__TotalAmount__c`, `kuga_sub__ListAmount__c` — amounts
- `kuga_sub__Service__c` (Formula) — whether line is a service
- `kuga_sub__ARRForecast__c`, `kuga_sub__LineTerm__c` — forecasting
- `kuga_sub__DiscountSalesPrice__c`, `kuga_sub__EffectiveDiscount__c` — discount tracking
- `kuga_sub__NonUpliftSalesPrice__c`, `kuga_sub__UpliftRenewalPrice__c` — renewal pricing
- `kuga_sub__ServiceTermBehavior__c` — term behavior picklist

On **Opportunity** (19 fields):
- `kuga_sub__MonthlyRecurringRevenue__c` (Roll-Up SUM)
- `kuga_sub__AnnualRecurringRevenueCommitted__c` (Roll-Up SUM)
- `kuga_sub__NonRecurringRevenue__c` (Roll-Up SUM)
- `kuga_sub__AnnualContractValueInitial__c` (Formula: NonRecurring + ARR)
- `kuga_sub__TotalContractValue__c` (Formula)
- `kuga_sub__Amount__c` (Roll-Up SUM)
- `kuga_sub__AnnualRecurringRevenueForecast__c`, `kuga_sub__ExpectedRevenue__c`, `kuga_sub__OpportunityAmount__c` (Formulas)
- `kuga_sub__ContractEndDate__c`, `kuga_sub__ParentContractEndDate__c` (Formula Date)
- `kuga_sub__DateRequired__c` (Roll-Up MIN), `kuga_sub__ServiceDateExpires__c` (Roll-Up MAX)
- `kuga_sub__ParentContract__c` (Lookup Contract), `kuga_sub__ParentOrder__c` (Lookup Order)
- `kuga_sub__AutoEmailRenewalOrder__c` (Checkbox), `kuga_sub__AutoRenewedOrder__c` (Lookup Order)
- `kuga_sub__RenewalOrderAutoCreationDate__c` (Date), `kuga_sub__RenewalPriceUpliftPercent__c` (Percent)

On **kugo2p__SalesOrder__c** (16 fields — **ORDER RELEASE controls**):
- `kuga_sub__GenerateContract__c` (Checkbox) — create Contract on release
- `kuga_sub__GenerateAsset__c` (Checkbox) — create Assets on release
- `kuga_sub__GenerateSubscription__c` (Checkbox) — create Subscriptions on release
- `kuga_sub__GenerateRenewalOpportunity__c` (Checkbox) — create Renewal Opportunity on release
- `kuga_sub__ContractNumber__c` (Lookup Contract), `kuga_sub__ParentContract__c` (Lookup)
- `kuga_sub__RenewalOpportunity__c` (Lookup Opportunity)
- `kuga_sub__ContractEndDate__c`, `kuga_sub__ParentContractEndDate__c`, `kuga_sub__RenewalEndDate__c` (Formulas)
- `kuga_sub__RenewableProductsCount__c`, `kuga_sub__RenewableServicesCount__c` (Roll-Ups)
- `kuga_sub__TrackableProductsCount__c`, `kuga_sub__TrackableServicesCount__c` (Roll-Ups)
- `kuga_sub__ServiceDateExpires__c` (Roll-Up MAX)
- `kuga_sub__UpdateContractContacts__c` (Multi-Select Picklist)

On **kugo2p__SalesQuote__c** (2 fields):
- `kuga_sub__ContractEndDate__c` (Formula), `kuga_sub__ContractNumber__c` (Lookup Contract)

On **kugo2p__SalesOrderServiceLine__c** (2 fields):
- `kuga_sub__Renew__c` (Checkbox) — revenue classification (recurring vs one-time). See Appendix D.
- `kuga_sub__Track__c` (Checkbox, **label: "Create Subscription"**) — when `true` on an Order Service Line, the Order Service Line trigger generates a Subscription on Order Release. Propagated from `Product2.kuga_sub__Track__c`.

> Order Service Lines generate **Subscriptions** (via the rule above) but **never Assets**.

On **kugo2p__SalesOrderProductLine__c** (2 fields):
- `kuga_sub__Renew__c` (Checkbox) — revenue classification (recurring vs one-time)
- `kuga_sub__Track__c` (Checkbox, label: "Create Subscription") — present on product lines but has no effect: Order Product Lines never generate Subscriptions on Order Release.

> Order Product Lines generate **Assets** (when the related `APD.kugo2p__CreateAsset__c = true`) but **never Subscriptions**. Asset creation is driven by the Order Product Line trigger, not the Order Service Line trigger.

On **kugo2p__SalesQuoteServiceLine__c** (1 field):
- `kuga_sub__Renew__c` (Checkbox)

On **kugo2p__SalesQuoteProductLine__c** (1 field):
- `kuga_sub__Renew__c` (Checkbox)

On **Contract** (21 fields):
- `kuga_sub__AnnualRecurringRevenue__c`, `kuga_sub__MonthlyRecurringRevenue__c` (Roll-Up SUM Subscription)
- `kuga_sub__TotalSubscriptionAmount__c`, `kuga_sub__TotalSubscriptionCount__c`, `kuga_sub__TotalSubscriptionQuantity__c` (Roll-Ups)
- `kuga_sub__SubscriptionStartDate__c` (Roll-Up MIN), `kuga_sub__SubscriptionEndDate__c` (Roll-Up MAX)
- `kuga_sub__AnnualRecurringRevenueForecast__c` (Formula)
- `kuga_sub__Effective__c` (Formula Checkbox) — is contract currently active
- `kuga_sub__Expanded__c` (Checkbox) — has been expanded
- `kuga_sub__ContractRenewalNoticeDate__c` (Formula), `kuga_sub__SendRenewalNoticeToday__c` (Formula)
- `kuga_sub__LastRenewalNoticeSentDate__c` (Date)
- `kuga_sub__AutoEmailRenewalNotice__c`, `kuga_sub__AutoEmailRenewalOrder__c` (Checkboxes)
- `kuga_sub__RenewalOpportunity__c` (Lookup Opportunity), `kuga_sub__RenewalTerm__c` (Number)
- `kuga_sub__Pricebook2Id__c` (Lookup Pricebook)
- `kuga_sub__ContactBuying__c`, `kuga_sub__ContactBilling__c`, `kuga_sub__ContactShipping__c` (Lookups)

On **Asset** (4 fields):
- `kuga_sub__ContractNumber__c` (Lookup Contract)
- `kuga_sub__ParentSubscription__c` (Lookup Subscription)
- `kuga_sub__ParentLine__c` (Formula)
- `kuga_sub__Renew__c` (Formula Checkbox)

---

## Apex Triggers

### kugo2p Triggers (34)

| Trigger | Object | Purpose |
|---------|--------|---------|
| SalesQuoteTrigger | SalesQuote__c | Quote lifecycle (status, totals, numbering) |
| SalesQuoteServiceLineTrigger | SalesQuoteServiceLine__c | Service line calculations |
| SalesQuoteProductLineTrigger | SalesQuoteProductLine__c | Product line calculations |
| SalesQuoteOptionalLineTrigger | SalesQuoteOptionalLine__c | Optional line handling |
| SalesQuoteACCTrigger | SalesQuoteAdditionalChargeCredit__c | Quote charge/credit calcs |
| SalesOrderTrigger | SalesOrder__c | Order lifecycle (status, totals, invoice gen) |
| SalesOrderServiceLineTrigger | SalesOrderServiceLine__c | Service order line calcs |
| SalesOrderProductLineTrigger | SalesOrderProductLine__c | Product order line calcs |
| SalesOrderACCTrigger | SalesOrderAdditionalChargeCredit__c | Order charge/credit calcs |
| InvoiceTrigger | KugamonInvoice__c | Invoice lifecycle |
| InvoiceLineTrigger | KugamonInvoiceLine__c | Invoice line calcs |
| InvoiceACCTrigger | KugamonInvoiceAdditionalChargeCredit__c | Invoice charge/credit calcs |
| PaymentXTrigger | PaymentX__c | Payment processing |
| AppliedPaymentTrigger | AppliedPayment__c | Payment-to-invoice allocation |
| PaymentMethodTrigger | Payment_Method__c | Payment method validation |
| PaymentProfileTrigger | Payment_Profile__c | Profile management |
| PaymentSettingTrigger | Settings__c | Payment settings validation |
| ProcessorConnectionTrigger | Processor_Connection__c | Processor connection mgmt |
| ShipmentTrigger | Shipment__c | Shipment lifecycle |
| ShipmentLineTrigger | ShipmentLine__c | Shipment line tracking |
| ServiceDeliveryScheduleTrigger | ServiceDeliverySchedule__c | Service delivery tracking |
| OpportunityTrigger | Opportunity | Opp-to-Kugamon sync |
| AccountTrigger | Account | Account data sync |
| AdditionalAccountDetailTrigger | AdditionalAccountDetail__c | Account metadata sync |
| AdditionalProductDetailTrigger | AdditionalProductDetail__c | Product metadata sync |
| Product2Trigger | Product2 | Product sync to AdditionalProductDetail |
| AccountPricingTrigger | AccountPricing__c | Customer pricing validation |
| ProductCostTrigger | ProductCost__c | Cost tracking |
| ProductCatalogTrigger | ProductCatalog__c | Catalog management |
| ProductCategoryTrigger | ProductCategory__c | Category management |
| ConfigurationGroupTrigger | ConfigurationGroup__c | Product configuration |
| KugamonSettingTrigger | KugamonSetting__c | Settings validation |
| LeadTrigger | Lead | Lead conversion handling |
| TaskTrigger | Task | Task automation |

### kuga_sub Triggers (14 — only when HAS_KUGA_SUB = true)

| Trigger | Object | Purpose |
|---------|--------|---------|
| Opportunities | Opportunity | Subscription revenue roll-ups, renewal opp linking |
| Quote | SalesQuote__c | Contract linking on renewal quotes |
| QuoteServiceLine | SalesQuoteServiceLine__c | Renew flag propagation to quote lines |
| QuoteProductLine | SalesQuoteProductLine__c | Renew flag propagation to quote lines |
| Order | SalesOrder__c | Order Release: generates Contract, Asset, Subscription, Renewal Opp |
| OrderServiceLine | SalesOrderServiceLine__c | Renew/Track flag handling, subscription creation |
| OrderProductLine | SalesOrderProductLine__c | Renew/Track flag handling, asset creation |
| Contracts | Contract | Subscription roll-ups, renewal notice scheduling |
| Asset | Asset | Contract/subscription linking |
| Subscription | Subscription__c | Subscription lifecycle management |
| Product | Product2 | Renewable/Track flag sync |
| AdditionalAccountDetail | AdditionalAccountDetail__c | Account subscription data sync |
| KugamonSetting | KugamonSetting__c | Subscription settings sync |
| ShipmentLine | ShipmentLine__c | Asset tracking on shipment |

---

## Apex Class Logic

### kuga_sub Architecture

All kuga_sub triggers use a **TriggerHandler** base class pattern with overridable methods: `beforeInsert`, `afterInsert`, `beforeUpdate`, `afterUpdate`, `beforeDelete`, `afterDelete`. Each trigger instantiates its handler and calls `handler.run()`.

**Central orchestration class:** `KugamonHelper` — contains all core business logic as static methods. Trigger handlers are thin dispatchers that call into KugamonHelper.

**Security:** All DML operations use `SecurityUtil.stripInaccessibleFromDML()` for FLS enforcement.

### Order Release Coordination

The most critical architectural pattern in kuga_sub. Three triggers (Order, ServiceLine, ProductLine) coordinate via static flags to ensure Order Release operations run exactly once regardless of trigger execution order.

**Static coordination flags on KugamonHelper:**
- `hasRenewableProducts` / `hasRenewableServices` — set by product/service line afterUpdate triggers
- `processedContract` / `processedSubscription` — prevent duplicate processing
- `processedProductLineAfterUpdateTrigger` / `processedServiceLineAfterUpdateTrigger` — track which line triggers have fired
- `mapNewContractOrders` — shared map of orders needing processing, populated by SalesOrderTriggerHandler

**Execution flow when Order status changes:**

1. **SalesOrderTriggerHandler.afterUpdate** detects status change, populates `mapNewContractOrders`, calls `createContract` → `createSubscription` → `createRenewalOpportunity`
2. Contract/Subscription creation updates order line items, which fires **ServiceLine** and **ProductLine** afterUpdate triggers
3. Line triggers check `mapNewContractOrders` — if populated and their counterpart has already fired, they call `createContract` → `createSubscription` → `createRenewalOpportunity` again
4. The `processedContract` / `processedSubscription` flags prevent duplicate execution

**Key setting:** `InitiateOrderSubscriptionManagement__c` on `kuga_sub__SubscriptionSetting__c` controls WHEN Order Release fires:
- `"Approve/Release"` — fires when order status changes to Approved AND Released
- `"Release"` — fires only when order status changes to Released

### KugamonHelper Key Methods

#### Order Release Methods

| Method | Purpose |
|--------|---------|
| `createContract(map<Id, SalesOrder__c>)` | Creates Contract from Order. Sets ContractTerm, StartDate, EndDate from order line dates. Copies contacts per `UpdateContractContacts__c` multi-select. If `ExtendContractonRenewal__c` = true for Renewal orders, extends existing contract instead of creating new one. Links contract back to order via `ContractNumber__c` |
| `createSubscription(map<Id, SalesOrder__c>)` | Creates Subscription records from order lines where `Renew__c = true`. Sets MRR, ARR, NetAmount, TotalAmount, ServiceTerm, dates. Links to Contract, Account, Order, Product. Also creates Assets from lines where `Track__c = true` |
| `createRenewalOpportunity(set<Id> orderIds)` | Creates Renewal Opportunity with matching RecordType. Copies line items from order to new opp as OpportunityLineItems. Sets `ParentContract__c` and `ParentOrder__c` on the renewal opp. Returns `List<OrderRenewalOpportunity>` wrapper |

#### Cancellation / Un-Release Methods

| Method | Purpose |
|--------|---------|
| `deActivateOrderContracts(set<Id>)` | When order is cancelled/un-released: deletes generated contracts, expires renewal opportunities (sets stage to "Closed Lost"), deactivates subscriptions |
| `unReleaseUpsellOrders(map<Id, Id>)` | Handles un-release of expansion/upsell orders — reverses quantity changes on parent subscriptions |
| `updateSubscriptionStatus(Set<Id>, String)` | Bulk updates subscription status for a set of order IDs |

#### Renewal and Pricing Methods

| Method | Purpose |
|--------|---------|
| `updateRenewalUpliftSalesPrice(map newOpps, map oldOpps)` | When a Renewal opportunity's `RenewalPriceUpliftPercent__c` changes, recalculates UnitPrice on all OLIs by applying uplift to `NonUpliftSalesPrice__c` |
| `updateRenewalOrderContractPriceBook(map newOrders, map oldOrders)` | When Renewal order's pricebook changes, syncs back to parent Contract's `Pricebook2Id__c` |
| `updateContractOpptyServiceTerm(map<Id, decimal>)` | Updates ServiceTerm on opportunity line items when contract renewal term changes |
| `deleteOLISchedule(set<Id>)` | Deletes OpportunityLineItemSchedule records when renewal pricing changes |

#### Line Item and Flag Propagation Methods

| Method | Purpose |
|--------|---------|
| `updateRenewandServiceTerm(list<SObject>, boolean isService)` | On order line beforeInsert: propagates `Renew__c` from quote line to order line. Sets ServiceTerm and UnitofTerm. If no quote line link, falls back to Product2's `Renewable__c` flag |
| `updateExpansionKitMemberServiceEndDate(list<ServiceLine>)` | For Expansion orders: adjusts service end dates on kit member lines to align with the parent kit line's end date |
| `setAssetDetails(list<Asset>)` | beforeInsert on Asset: links asset to Contract and Subscription via `ContractNumber__c` and `ParentSubscription__c` |
| `updateSubscriptionDetails(list<Asset>)` | afterInsert on Asset: updates the parent Subscription's `ParentAsset__c` to point back to the newly created asset |

#### Matching Utility

| Method | Purpose |
|--------|---------|
| `getOLIKey(orderId, productId, price, discount, description, configOptionId, startDate)` | Generates a composite key for matching Subscriptions to OpportunityLineItems. Used by SubscriptionTriggerHandler when cancelling subscriptions to find and reduce/delete corresponding renewal OLIs |

### Trigger Handler Behaviors

#### SalesOrderTriggerHandler
- **beforeInsert**: Sets RecordType from linked Quote or Opportunity. For Expansion/Renewal: copies `ContractNumber__c` from Quote. Calls `setOrderDetails` which auto-calculates `GenerateContract__c`, `GenerateAsset__c`, `GenerateSubscription__c`, `GenerateRenewalOpportunity__c` based on whether line items have Renew/Track flags
- **afterUpdate**: Detects Order status change → triggers Order Release chain (createContract → createSubscription → createRenewalOpportunity). On cancellation/un-release → calls `deActivateOrderContracts` to reverse all generated records

#### SalesQuoteTriggerHandler
- **beforeInsert**: Sets RecordType from linked Opportunity's RecordType. For Expansion/Renewal quotes when `ExtendContractonRenewal__c` is enabled: auto-sets `ContractNumber__c` and copies contacts (ContactBilling, ContactBuying, ContactShipping) from the Contract

#### ContractTriggerHandler
- **beforeInsert/Update**: Validates single active contract per account (unless `AllowMultipleActiveContracts__c` = true). Auto-calculates `ContractTerm` from StartDate and EndDate
- **beforeUpdate**: `setContactDetails` syncs billing/shipping addresses from Contact records to Contract address fields. Validates required address fields are populated
- **afterUpdate — Activation**: When contract activates, syncs `IsActive__c` on all child Subscriptions
- **afterUpdate — Cancellation**: When contract is cancelled, cancels all child Subscriptions (sets `Status__c = 'Cancelled'`) and closes the linked Renewal Opportunity (stage → "Closed Lost")
- **afterUpdate**: Syncs `AutoEmailRenewalOrder__c` flag changes to the linked Renewal Opportunity

#### SubscriptionTriggerHandler
- **beforeInsert/Update**: Syncs `IsActive__c` (editable) with `Active__c` (formula) to keep them aligned
- **afterUpdate — Cancellation**: When a subscription is cancelled, finds matching OLIs on the Renewal Opportunity using `getOLIKey`. Reduces quantity on the matching OLI by the subscription's quantity. If resulting quantity ≤ 0, deletes the OLI entirely

#### OpportunityTriggerHandler
- **beforeUpdate**: Validates currency match for Expansion/Renewal opportunities — the opp's CurrencyIsoCode must match the parent Contract's currency. Prevents currency mismatch errors
- **afterUpdate**: When `RenewalPriceUpliftPercent__c` changes on a Renewal opp, triggers `updateRenewalUpliftSalesPrice` to recalculate all line item prices

#### AssetTriggerHandler
- **beforeInsert**: Calls `KugamonHelper.setAssetDetails` — links asset to Contract and Subscription
- **afterInsert**: Calls `KugamonHelper.updateSubscriptionDetails` — sets `ParentAsset__c` on the subscription

#### SalesOrderServiceLineTriggerHandler
- **beforeInsert**: Sets ListPrice from PricebookEntry. Propagates `Track__c` from `AdditionalProductDetail.ReferenceProduct.Track__c`. Propagates `Renew__c` from linked quote service line. Calls `updateRenewandServiceTerm` and `updateExpansionKitMemberServiceEndDate`
- **afterUpdate**: Sets `processedServiceLineAfterUpdateTrigger = true`, then conditionally calls Order Release chain if `mapNewContractOrders` is populated

#### SalesOrderProductLineTriggerHandler
- **beforeInsert**: Same pattern as service line handler. `Track__c` from `AdditionalProductDetail.CreateAsset`. Propagates `Renew__c` from linked quote product line
- **afterUpdate**: Sets `processedProductLineAfterUpdateTrigger = true`, then conditionally calls Order Release chain

### Scheduled Batch Jobs

Three scheduleable batch classes handle automated lifecycle operations:

| Batch Class | Schedule | Purpose |
|-------------|----------|---------|
| `ContractRenewalNoticeBatcher` | Daily recommended | Sends renewal notice emails to contracts where `SendRenewalNoticeToday__c = true`. Uses email template from `SubscriptionSetting__c.ContractRenewalEmailTemplateName__c`. Updates `LastRenewalNoticeSentDate__c` after sending |
| `RenewalOrderBatcher` | Daily recommended | Creates Renewal Orders from Renewal Opportunities where RecordType = 'Renewal' and `RenewalOrderAutoCreationDate__c <= today`. Creates `kugo2p__SalesOrder__c` with Renewal record type, copies contacts from Contract (falls back to AdditionalAccountDetail), splits line items into service/product lines based on `Service__c` flag |
| `SubscriptionBatcher` | Periodic | Syncs `IsActive__c` (editable checkbox) with `Active__c` (formula) on Subscriptions where they have diverged. Safety net to keep these fields aligned |

### Key Settings That Drive Behavior

These fields on `kuga_sub__SubscriptionSetting__c` control critical behavior:

| Setting Field | Values | Effect |
|---------------|--------|--------|
| `InitiateOrderSubscriptionManagement__c` | "Approve/Release" or "Release" | Controls WHEN Order Release fires — on approval+release or release only |
| `ExtendContractonRenewal__c` | Checkbox | If true, Renewal orders extend existing contract end date instead of creating a new contract |
| `AllowMultipleActiveContracts__c` | Checkbox | If true, allows multiple active contracts per account. If false, ContractTriggerHandler enforces single active contract |
| `ContractRenewalEmailTemplateName__c` | Text | Email template API name for renewal notice emails sent by ContractRenewalNoticeBatcher |

### Order Release Trigger Map

Three independent triggers drive what's created on Order Release. Crucially, **Subscriptions only come from Order Service Lines** and **Assets only come from Order Product Lines** — the two are split by line-object, not by flag alone.

```
SUBSCRIPTION  (Order Service Line trigger only)
─────────────
Product2.kuga_sub__Track__c (label: "Create Subscription")
   └─ propagates → OLI / QuoteLine / OrderLine .kuga_sub__Track__c
       └─ on Order Release, when the line is a Service
          (lands on kugo2p__SalesOrderServiceLine__c; APD.Service__c = true):
              └─→ Order Service Line trigger creates a Subscription
       └─ on Order Product Lines: no Subscription, ever

ASSET  (Order Product Line trigger only)
─────
kugo2p__AdditionalProductDetail__c.kugo2p__CreateAsset__c
   └─ on Order Release, when the line is a Product
      (lands on kugo2p__SalesOrderProductLine__c; APD.Service__c = false):
          └─→ Order Product Line trigger creates an Asset
   └─ on Order Service Lines: no Asset, ever

RENEWAL OPPORTUNITY  (any line)
───────────────────
Product2.kuga_sub__Renewable__c
   └─ on Order Release, if true on any line's product (service or product):
       └─→ Renewal Opportunity created
   └─ also drives the "Renewable" prefix on the Product Snapshot LWC
```

**Separate concept — revenue classification, not Subscription creation:** `kuga_sub__Renew__c` on `OpportunityLineItem` / Quote Lines / Order Lines is a different field that classifies revenue as recurring (MRR/ARR) vs one-time (NonRecurringRevenue). It does NOT trigger Subscription creation. See **Appendix D: Renew Field Guide** for the revenue side.

### kugo2p Apex Classes

Below is the architectural overview of key kugo2p Apex classes.

#### Core Architecture Patterns

**Kontroller** — Central action router for all Visualforce/LWC button actions. Key design:
- `Kontroller.logicPath` static variable: `'trigger'` (default) or `'controller'`. When set to `'controller'`, trigger handlers skip auto-fill logic (e.g., SalesQuoteHelper.fillSalesQuote) so the controller can manage field values directly. This prevents double-processing when records are created programmatically via buttons
- `Director()` method routes based on `action` parameter: `createSalesQuote`, `createSalesOrder`, `createInvoice`, `updateQuoteStatus`, `updateOrderStatus`, `updateInvoiceStatus`, `deleteInvoice`, `goToPaymentTerminal`, `attachPDF`, `onlineOrderEmail`, `onlineInvoiceEmail`, `emailPaymentPDF`, `createPaymentPDF`, `emailOrderPDF`, `emailQuotePDF`, `emailInvoicePDF`, `refreshAssets`, `refreshPayment`, `cloneSalesQuote` (from updateQuoteStatus Won flow)
- `ValidateAccountDetails(Id acctId)` — validates billing address and contact exist before quote/order creation. Called by trigger handlers too
- Order status flow: Draft → Sent → Approved → Released → Cancelled. Special statuses: `ApproveOrderandPay` (approve + immediate payment), `Unrelease`, `CancelApproved`, `CancelReleased`
- Quote Won flow: `updateQuoteStatusToWonAndGenerateOrder()` sets quote status to Won, then internally routes to `createSalesOrder` to auto-generate order

**KugamonSyncService** — Bidirectional sync between Quotes/Orders and OpportunityLineItems. Implements `Queueable` for async processing:
- `syncOpportunity(list<SObject>, map oldHeaders, String objType)` — static entry point called from quote/order afterUpdate triggers. Detects changes to IsPrimary, Opportunity, PriceBookName, RecordStatus, DiscountPercent. Only syncs if record is primary (`IsPrimary__c = true`) and linked to an Opportunity. Enqueues a Queueable job to process
- `syncOppLines(list<SObject>, map oldLines, String objType, boolean isService)` — static entry point called from quote/order line afterAll triggers. Detects changes to Quantity, SalesPrice, LineDiscountPercent, ServiceDate, LineDescription, SortOrder, OpportunityLineItemId, ParentProductLine, ParentServiceLine, ConfigurationOption. Also checks "twin fields" (custom mapped fields between line types). If `HAS_KUGA_SUB`, also monitors `kuga_sub__Renew__c`, `DateServiceEnd__c`, `UnitofTerm__c`
- `processKugamonLines()` — core sync method. Creates/upserts OpportunityLineItems from quote/order lines. Maps: Quantity, UnitPrice (calculated via getSalesPrice), Discount, ServiceDate, Description, SortOrder. Copies "twin fields" via `Util.copyFields`. If `HAS_KUGA_SUB`: syncs `Renew__c`, `DateServiceEnd__c`, `ServiceTerm__c`, `ServiceTermBehavior__c`, `UnitofTerm__c` to OLI
- `disableOpportunitySync` static boolean — can be set to skip sync entirely
- Lines with "Exclude from Opportunity Sync" flag are skipped (creates a Task notification)
- Lines with Quantity = 0 are skipped (OLI doesn't support zero quantity)
- Lines with inactive PricebookEntry are skipped

**Kugamon** — Central caching/retrieval layer providing get/clear/refresh patterns for all Q2C objects: Account, Contact, Opportunity, OLI, Product2, ProductDetail, KitBundleMembers, Pricebook, PricebookEntry, SalesQuote (with all child lines), SalesOrder (with all child lines), Shipment, Invoice, Payment, AppliedPayment, ServiceDeliverySchedule, RecordType, TaxRate, VAT, AdditionalChargeCredit, EmailTemplate. This class is the data access layer — all trigger handlers and helpers query through it for caching

**SecurityUtil** — All DML operations across the entire package use `SecurityUtil.stripInaccessibleFromDML()` for FLS enforcement. Delete operations check `SecurityUtil.checkObjectIsDeletable()`

#### Helper Classes

| Class | Key Methods |
|-------|-------------|
| SalesOrderHelper | `createSalesOrder` (7 overloads: from Account, Contact, Opportunity, Quote, Payment), `fillSalesOrder`, `createSalesOrderLines` (from Quote and Opportunity), `calculateServiceEndDate`, `fillKitMemberOrderLines`, `unReleaseOrder`, `cancelReleasedOrder`, `hasOrderInvoice`/`hasOrderInvoicePayments`/`hasOrderInvoicePosted`, `updateShipmentStatus`/`updateServiceDeliveryStatus`/`updateAssetStatus`/`updateOrderInvoiceStatus`/`updateOrderStatus`, `cloneSalesOrder`, `validate`, `assignPrimaryOrder`, `CreateAssets`/`UpdateAssets`/`DeleteAssets`, `handleOrderStatusUpdate`, `syncPriceBook`, `okayToUpdateReleasedOrder`, `checkProductSalesLinesSynced` |
| SalesQuoteHelper | `createSalesQuote`, `fillSalesQuote`, `fillSalesQuoteProductLine`/`fillSalesQuoteServiceLine` (multiple overloads with tiered pricing and kit bundles), `calculateServiceEndDate` (multiple overloads), `fillKitMemberQuoteLines`, `createSalesQuoteLines`, `getDateAvailableToPromise`, `cloneSalesQuote`, `assignPrimaryQuote`, `handleQuoteStatusUpdate`, `syncPriceBook` |
| GroupHelper | Inner classes `LineGroup` and `LineGroupMember`. `processProductOrServiceLine`/`processACCLine`/`processOptionalLine`, `createLine`, `prepareLine`/`prepare`, `upsertGroups`/`upsertLines`, `getDBGroups`, `createLineGroupMap`, `processKitBundleLine`, `assignKitBundleMembersToLines` |
| ProductHelper | `CreateProductDetail`, `MapProductDetail`, inner classes `ProductTileData`/`Tier`/`Subscription`, `createPricebookEntryMap`, `getCurrencyCode`, `buildProductRecords`/`buildAssetRecords`/`buildSubscriptionRecords`, `getAccountIdsByHierarchy`, `setProductAccountPricingFields`, `evaluateAccountPricingFilter`, `getPricebookTieredPricing`/`getProductTieredPrice`, `setProductsInContractPricebook`, `setFavoritedProducts`, `setProductCostFields`, `validateAPD` |
| InvoiceHelper | `createInvoiceSchedule`, `buildInvoices`, `createInvoice`, `updateInvoicedQuantities`, `updateInvoiceLineAmounts`, `fillInvoice`, `handleInvoiceStatusUpdate`, `getInvoicePOKey` |
| PaymentHelper | `createPaymentProfile`, `createInvoicePayment`/`createOrderPayment`/`createAccountPayment`, `matchKugamonPayment`, `applyInvoicePayments`/`applyOrderPayments`, `applyPaymentsToLines`, `deleteInProcessPayments` |
| AccountHelper | `MapAccountDetail` (creates/upserts AdditionalAccountDetail from Account), `updateAccountBalance_Batch`, `isPersonAccount` |
| Util | Type conversion, URL/string processing, record type lookup (`getRecordType`), field copy (`copyFields`), sort, multi-currency helpers, email, error handling, `getTwinFields` (custom field mapping between objects) |

#### kugo2p Trigger Handler Behaviors

##### SalesQuoteTriggerHandler
- **beforeInsert**: Validates pricebook (must have PBE entries matching quote currency). Assigns currency from Pricebook if multi-currency. Generates `OnlineApprovalKey__c` random string. Checks `Kontroller.logicPath` — if `'trigger'` (manual creation), calls `SalesQuoteHelper.fillSalesQuote` to auto-fill defaults
- **afterInsert**: Copies OpportunityLineItems to quote lines via `SalesQuoteHelper.createSalesQuoteLines`. Calls `SalesQuoteHelper.assignPrimaryQuote` to set IsPrimary
- **beforeUpdate**: Contact address sync — when ContactBilling/ContactShipping changes, copies Contact's Mailing address → BillTo fields, Other address → ShipTo fields. Discount cascade — when `DiscountPercent__c` changes, recalculates `LineDiscountAmount__c` on ALL child service and product lines. Currency enforcement — prevents currency change if child lines exist. Pricebook validation — prevents pricebook change if child lines exist
- **afterUpdate**: Cascades ContactShipping, Carrier, Warehouse, Opportunity changes to all child lines. Calls `KugamonSyncService.syncOpportunity` for opportunity sync. Calls `SalesQuoteHelper.handleQuoteStatusUpdate` on status changes

##### SalesQuoteServiceLineTriggerHandler
- **beforeInsert**: Fills kit bundle member details from KitBundleMember records. Assigns auto-incrementing SortOrder via aggregate MAX query. Validates pricebook (checks PBE exists for the product, including kit member validation). If `Kontroller.logicPath == 'trigger'` (manual creation): auto-fills ServiceName from APD, calculates ServiceEndDate from ServiceTerm, applies "% of Unit Price" logic, enforces currency match with parent quote
- **afterAll** (insert/update/delete/undelete): Creates kit bundle member lines (both service and product members from KBM records). Rolls up Tax, Discount, VAT amounts to quote header. Syncs kit header quantity changes to member lines. Calls `KugamonSyncService.syncOppLines` for opportunity sync
- **beforeDelete**: Prevents deletion of required kit bundle members. Cascade deletes child kit members

##### SalesQuoteProductLineTriggerHandler
- **beforeInsert**: Assigns SortOrder. Validates pricebook (including kit bundle member validation via APD/KBM queries). If `Kontroller.logicPath == 'trigger'`: fills product line defaults, enforces currency match
- **afterAll**: Creates kit bundle member lines (can create BOTH product AND service member lines from product header). Tax/Discount/VAT roll-up to quote header. Kit quantity sync. Calls `KugamonSyncService.syncOppLines`
- **beforeDelete**: Prevents required kit member deletion. Cascade deletes child products AND child services

**Cross-trigger coordination:** `TriggerHelper.passedPricebookValidation` static flag prevents duplicate pricebook validation when both product and service line triggers fire in the same transaction

##### SalesOrderTriggerHandler
- **beforeInsert**: Validates pricebook, assigns currency. Generates Onl

…(truncated)
