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
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.
HAS_KUGA_SUB = false → use the standard Amount field as normal (the kuga_sub__* fields don't exist).
- 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.
- When building SOQL queries, reports, or list views for pipeline in a subscription org, select
kuga_sub__Amount__c — not Amount.
Quick example
-- 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:
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:
- SalesOrderTriggerHandler.afterUpdate detects status change, populates
mapNewContractOrders, calls createContract → createSubscription → createRenewalOpportunity
- Contract/Subscription creation updates order line items, which fires ServiceLine and ProductLine afterUpdate triggers
- Line triggers check
mapNewContractOrders — if populated and their counterpart has already fired, they call createContract → createSubscription → createRenewalOpportunity again
- 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)
1---2name: kugamon-full-qtc-submgmt3description: 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.4---56# Kugamon Use Cases:78Full lifecycle skill for Kugamon RevOps for Salesforce910**CPQ Flow:** Opportunity → Quote → Order → (Order Release) → Asset1112Full lifecycle skill for Kugamon Quote to Cash, which is a combination of CPQ and Billing functions1314**Q2C Flow:** Opportunity → Quote → Order → (Order Release) → Asset + Shipment → Invoice → Payment 1516Full lifecycle skill for Kugamon Subscription Management, which is a combination of CPQ and Subscription Management functions1718**SubMgmt Flow:** Opportunity → Quote → Order → (Order Release) → Asset + Contract + Subscription + Renewal Opportunity 1920Full lifecycle skill for Kugamon Subscription Billing, which is combination of all Quote to Cash and Subscription Management functions2122**SB Flow:** Opportunity → Quote → Order → (Order Release) → Asset + Shipment + Contract + Subscription + Renewal Opportunity → Invoice → Payment 23242526## Package Detection2728**FIRST STEP: Always detect which packages are installed.**2930Check if `kuga_sub__Renew__c` exists on `OpportunityLineItem` by describing the object's fields via the connected Salesforce MCP or API.3132- `HAS_KUGA_SUB = true` → kuga_sub package is installed (subscription management, contracts, assets, renewals)33- `HAS_KUGA_SUB = false` → only kugo2p (Q2C only, no subscription lifecycle)3435This flag controls revenue classification, line-item separation, and whether Order Release creates contracts/assets/subscriptions.3637---3839## ⚠️ CRITICAL: Opportunity Pipeline Forecasting Field4041**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.**4243### Why this matters4445The 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.4647`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.4849### Rules50511. **`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.522. **`HAS_KUGA_SUB = false`** → use the standard `Amount` field as normal (the `kuga_sub__*` fields don't exist).533. 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.544. When building SOQL queries, reports, or list views for pipeline in a subscription org, select `kuga_sub__Amount__c` — not `Amount`.5556### Quick example5758```sql59-- CORRECT (HAS_KUGA_SUB = true):60SELECT Id, Name, kuga_sub__Amount__c61FROM Opportunity62WHERE IsClosed = false6364-- WRONG (HAS_KUGA_SUB = true):65SELECT Id, Name, Amount66FROM Opportunity67WHERE IsClosed = false68```6970See **Appendix B: Amount Fields Guide** for detailed field-by-field reference and comparison rules.7172---7374## Org-Specific Setup7576**NEVER hardcode Record Type IDs.** Always query dynamically:7778```sql79SELECT Id, Name, SObjectType, DeveloperName80FROM RecordType81WHERE SObjectType IN (82 'kugo2p__SalesQuote__c', 'kugo2p__SalesOrder__c',83 'kugo2p__Payment_Profile__c', 'kugo2p__Processor_Connection__c',84 'kugo2p__Payment_Method__c', 'Opportunity'85)86AND IsActive = true87ORDER BY SObjectType, Name88```8990Cache results for the session. Map by name: Opportunity "New" → Quote "New" → Order "New", etc.9192---9394## Object Model Overview9596### kugo2p Objects (Kugamon Quote to Cash — ~50 custom objects)9798**Quote Stage:**99- `kugo2p__SalesQuote__c` (~95 fields) — master quote100- `kugo2p__SalesQuoteServiceLine__c` (~89 fields) — recurring service lines101- `kugo2p__SalesQuoteProductLine__c` (~76 fields) — one-time product lines102- `kugo2p__SalesQuoteOptionalLine__c` (~16 fields) — optional upsell lines103- `kugo2p__SalesQuoteAdditionalChargeCredit__c` (~34 fields) — surcharges/discounts104- `kugo2p__QuoteLineGroup__c` (~14 fields) — line grouping105106**Order Stage:**107- `kugo2p__SalesOrder__c` (~110 fields) — master order108- `kugo2p__SalesOrderServiceLine__c` (~108 fields) — recurring service order lines109- `kugo2p__SalesOrderProductLine__c` (~105 fields) — one-time product order lines110- `kugo2p__SalesOrderAdditionalChargeCredit__c` (~39 fields) — surcharges/discounts111- `kugo2p__OrderLineGroup__c` (~13 fields) — line grouping112113**Invoice Stage:**114- `kugo2p__KugamonInvoice__c` (~73 fields) — invoice115- `kugo2p__KugamonInvoiceLine__c` (~47 fields) — invoice line items116- `kugo2p__KugamonInvoiceAdditionalChargeCredit__c` (~39 fields) — invoice adjustments117- `kugo2p__OrderInvoiceRelationship__c` (~15 fields) — order-to-invoice link118- `kugo2p__InvoiceSchedule__c` (~15 fields) — recurring invoice generation119120**Payment Stage:**121- `kugo2p__PaymentX__c` (~71 fields) — payment records122- `kugo2p__AppliedPayment__c` (~22 fields) — payment-to-invoice allocation123- `kugo2p__Processor_Connection__c` (~52 fields) — gateway configs (Stripe, AuthNet, PayPal, eWay)124- `kugo2p__Payment_Method__c` (~32 fields) — payment method definitions125- `kugo2p__Payment_Profile__c` (~57 fields) — customer payment profiles126127**Fulfillment Stage:**128- `kugo2p__Shipment__c` (~31 fields) — shipment records129- `kugo2p__ShipmentLine__c` (~27 fields) — shipment line items130- `kugo2p__ServiceDeliverySchedule__c` (~30 fields) — service delivery tracking131- `kugo2p__Carrier__c` (~11 fields) — shipping carriers132- `kugo2p__Warehouse__c` (~17 fields) — warehouse/inventory locations133134**Product & Pricing:**135- `kugo2p__AdditionalProductDetail__c` (~64 fields) — extended product metadata (Service flag, weight, dimensions, tax, etc.)136- `kugo2p__AccountPricing__c` (~26 fields) — customer-specific pricing overrides137- `kugo2p__TieredPricing__c` (~16 fields) — volume/tiered pricing headers138- `kugo2p__Tier__c` (~12 fields) — individual tier definitions139- `kugo2p__ProductCost__c` (~11 fields) — product cost tracking140- `kugo2p__AdditionalChargeCredit__c` (~29 fields) — reusable charge/credit templates141- `kugo2p__ProductCatalog__c` (~19 fields) — product catalog142- `kugo2p__ProductCategory__c` — product categories143- `kugo2p__ProductCategoryProduct__c` — category-product junction144145**Configuration & Bundles:**146- `kugo2p__ConfigurationGroup__c` (~16 fields) — product configuration groups147- `kugo2p__ConfigurationOption__c` (~27 fields) — configuration options148- `kugo2p__KitBundleMember__c` (~15 fields) — kit/bundle components149150**Tax:**151- `kugo2p__TaxLocation__c` (~15 fields) — US tax jurisdictions152- `kugo2p__TaxRate__c` (~13 fields) — US tax rates153- `kugo2p__VAT__c` (~12 fields) — international VAT definitions154- `kugo2p__VATRate__c` (~15 fields) — VAT rates155156**Account:**157- `kugo2p__AdditionalAccountDetail__c` (~44 fields) — extended account metadata158159**Settings:**160- `kugo2p__KugamonSetting__c` (~78 fields) — master org-wide settings161- `kugo2p__Settings__c` (~19 fields) — additional settings162163**Utility:**164- `kugo2p__Favorite__c`, `kugo2p__FavoriteMember__c`, `kugo2p__FavoriteShare__c`165- `kugo2p__Shopping_Cart_Item__c` (~21 fields)166167### kuga_sub Objects (Kugamon Subscriptions — only when HAS_KUGA_SUB = true)168169**Custom Objects:**170- `kuga_sub__Subscription__c` (34 fields) — the subscription record linking orders to contracts171172**Fields added to standard objects by kuga_sub:**173174On **Product2** (4 fields):175- `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.176- `kuga_sub__RenewalProduct__c` (Lookup Product) — substitute product for renewal quotes177- `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.**178- `kuga_sub__UpliftRenewalPrice__c` (Checkbox) — apply price uplift percentage on renewal179180> **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.181182On **OpportunityLineItem** (18 fields):183- `kuga_sub__Renew__c` (Checkbox) — **CRITICAL**: marks line as recurring vs. one-time184- `kuga_sub__ARR__c`, `kuga_sub__MRR__c`, `kuga_sub__NonRecurringRevenue__c` — calculated revenue185- `kuga_sub__ServiceTerm__c`, `kuga_sub__UnitofTerm__c` — term length and unit186- `kuga_sub__DateServiceEnd__c` — service end date187- `kuga_sub__NetAmount__c`, `kuga_sub__TotalAmount__c`, `kuga_sub__ListAmount__c` — amounts188- `kuga_sub__Service__c` (Formula) — whether line is a service189- `kuga_sub__ARRForecast__c`, `kuga_sub__LineTerm__c` — forecasting190- `kuga_sub__DiscountSalesPrice__c`, `kuga_sub__EffectiveDiscount__c` — discount tracking191- `kuga_sub__NonUpliftSalesPrice__c`, `kuga_sub__UpliftRenewalPrice__c` — renewal pricing192- `kuga_sub__ServiceTermBehavior__c` — term behavior picklist193194On **Opportunity** (19 fields):195- `kuga_sub__MonthlyRecurringRevenue__c` (Roll-Up SUM)196- `kuga_sub__AnnualRecurringRevenueCommitted__c` (Roll-Up SUM)197- `kuga_sub__NonRecurringRevenue__c` (Roll-Up SUM)198- `kuga_sub__AnnualContractValueInitial__c` (Formula: NonRecurring + ARR)199- `kuga_sub__TotalContractValue__c` (Formula)200- `kuga_sub__Amount__c` (Roll-Up SUM)201- `kuga_sub__AnnualRecurringRevenueForecast__c`, `kuga_sub__ExpectedRevenue__c`, `kuga_sub__OpportunityAmount__c` (Formulas)202- `kuga_sub__ContractEndDate__c`, `kuga_sub__ParentContractEndDate__c` (Formula Date)203- `kuga_sub__DateRequired__c` (Roll-Up MIN), `kuga_sub__ServiceDateExpires__c` (Roll-Up MAX)204- `kuga_sub__ParentContract__c` (Lookup Contract), `kuga_sub__ParentOrder__c` (Lookup Order)205- `kuga_sub__AutoEmailRenewalOrder__c` (Checkbox), `kuga_sub__AutoRenewedOrder__c` (Lookup Order)206- `kuga_sub__RenewalOrderAutoCreationDate__c` (Date), `kuga_sub__RenewalPriceUpliftPercent__c` (Percent)207208On **kugo2p__SalesOrder__c** (16 fields — **ORDER RELEASE controls**):209- `kuga_sub__GenerateContract__c` (Checkbox) — create Contract on release210- `kuga_sub__GenerateAsset__c` (Checkbox) — create Assets on release211- `kuga_sub__GenerateSubscription__c` (Checkbox) — create Subscriptions on release212- `kuga_sub__GenerateRenewalOpportunity__c` (Checkbox) — create Renewal Opportunity on release213- `kuga_sub__ContractNumber__c` (Lookup Contract), `kuga_sub__ParentContract__c` (Lookup)214- `kuga_sub__RenewalOpportunity__c` (Lookup Opportunity)215- `kuga_sub__ContractEndDate__c`, `kuga_sub__ParentContractEndDate__c`, `kuga_sub__RenewalEndDate__c` (Formulas)216- `kuga_sub__RenewableProductsCount__c`, `kuga_sub__RenewableServicesCount__c` (Roll-Ups)217- `kuga_sub__TrackableProductsCount__c`, `kuga_sub__TrackableServicesCount__c` (Roll-Ups)218- `kuga_sub__ServiceDateExpires__c` (Roll-Up MAX)219- `kuga_sub__UpdateContractContacts__c` (Multi-Select Picklist)220221On **kugo2p__SalesQuote__c** (2 fields):222- `kuga_sub__ContractEndDate__c` (Formula), `kuga_sub__ContractNumber__c` (Lookup Contract)223224On **kugo2p__SalesOrderServiceLine__c** (2 fields):225- `kuga_sub__Renew__c` (Checkbox) — revenue classification (recurring vs one-time). See Appendix D.226- `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`.227228> Order Service Lines generate **Subscriptions** (via the rule above) but **never Assets**.229230On **kugo2p__SalesOrderProductLine__c** (2 fields):231- `kuga_sub__Renew__c` (Checkbox) — revenue classification (recurring vs one-time)232- `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.233234> 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.235236On **kugo2p__SalesQuoteServiceLine__c** (1 field):237- `kuga_sub__Renew__c` (Checkbox)238239On **kugo2p__SalesQuoteProductLine__c** (1 field):240- `kuga_sub__Renew__c` (Checkbox)241242On **Contract** (21 fields):243- `kuga_sub__AnnualRecurringRevenue__c`, `kuga_sub__MonthlyRecurringRevenue__c` (Roll-Up SUM Subscription)244- `kuga_sub__TotalSubscriptionAmount__c`, `kuga_sub__TotalSubscriptionCount__c`, `kuga_sub__TotalSubscriptionQuantity__c` (Roll-Ups)245- `kuga_sub__SubscriptionStartDate__c` (Roll-Up MIN), `kuga_sub__SubscriptionEndDate__c` (Roll-Up MAX)246- `kuga_sub__AnnualRecurringRevenueForecast__c` (Formula)247- `kuga_sub__Effective__c` (Formula Checkbox) — is contract currently active248- `kuga_sub__Expanded__c` (Checkbox) — has been expanded249- `kuga_sub__ContractRenewalNoticeDate__c` (Formula), `kuga_sub__SendRenewalNoticeToday__c` (Formula)250- `kuga_sub__LastRenewalNoticeSentDate__c` (Date)251- `kuga_sub__AutoEmailRenewalNotice__c`, `kuga_sub__AutoEmailRenewalOrder__c` (Checkboxes)252- `kuga_sub__RenewalOpportunity__c` (Lookup Opportunity), `kuga_sub__RenewalTerm__c` (Number)253- `kuga_sub__Pricebook2Id__c` (Lookup Pricebook)254- `kuga_sub__ContactBuying__c`, `kuga_sub__ContactBilling__c`, `kuga_sub__ContactShipping__c` (Lookups)255256On **Asset** (4 fields):257- `kuga_sub__ContractNumber__c` (Lookup Contract)258- `kuga_sub__ParentSubscription__c` (Lookup Subscription)259- `kuga_sub__ParentLine__c` (Formula)260- `kuga_sub__Renew__c` (Formula Checkbox)261262---263264## Apex Triggers265266### kugo2p Triggers (34)267268| Trigger | Object | Purpose |269|---------|--------|---------|270| SalesQuoteTrigger | SalesQuote__c | Quote lifecycle (status, totals, numbering) |271| SalesQuoteServiceLineTrigger | SalesQuoteServiceLine__c | Service line calculations |272| SalesQuoteProductLineTrigger | SalesQuoteProductLine__c | Product line calculations |273| SalesQuoteOptionalLineTrigger | SalesQuoteOptionalLine__c | Optional line handling |274| SalesQuoteACCTrigger | SalesQuoteAdditionalChargeCredit__c | Quote charge/credit calcs |275| SalesOrderTrigger | SalesOrder__c | Order lifecycle (status, totals, invoice gen) |276| SalesOrderServiceLineTrigger | SalesOrderServiceLine__c | Service order line calcs |277| SalesOrderProductLineTrigger | SalesOrderProductLine__c | Product order line calcs |278| SalesOrderACCTrigger | SalesOrderAdditionalChargeCredit__c | Order charge/credit calcs |279| InvoiceTrigger | KugamonInvoice__c | Invoice lifecycle |280| InvoiceLineTrigger | KugamonInvoiceLine__c | Invoice line calcs |281| InvoiceACCTrigger | KugamonInvoiceAdditionalChargeCredit__c | Invoice charge/credit calcs |282| PaymentXTrigger | PaymentX__c | Payment processing |283| AppliedPaymentTrigger | AppliedPayment__c | Payment-to-invoice allocation |284| PaymentMethodTrigger | Payment_Method__c | Payment method validation |285| PaymentProfileTrigger | Payment_Profile__c | Profile management |286| PaymentSettingTrigger | Settings__c | Payment settings validation |287| ProcessorConnectionTrigger | Processor_Connection__c | Processor connection mgmt |288| ShipmentTrigger | Shipment__c | Shipment lifecycle |289| ShipmentLineTrigger | ShipmentLine__c | Shipment line tracking |290| ServiceDeliveryScheduleTrigger | ServiceDeliverySchedule__c | Service delivery tracking |291| OpportunityTrigger | Opportunity | Opp-to-Kugamon sync |292| AccountTrigger | Account | Account data sync |293| AdditionalAccountDetailTrigger | AdditionalAccountDetail__c | Account metadata sync |294| AdditionalProductDetailTrigger | AdditionalProductDetail__c | Product metadata sync |295| Product2Trigger | Product2 | Product sync to AdditionalProductDetail |296| AccountPricingTrigger | AccountPricing__c | Customer pricing validation |297| ProductCostTrigger | ProductCost__c | Cost tracking |298| ProductCatalogTrigger | ProductCatalog__c | Catalog management |299| ProductCategoryTrigger | ProductCategory__c | Category management |300| ConfigurationGroupTrigger | ConfigurationGroup__c | Product configuration |301| KugamonSettingTrigger | KugamonSetting__c | Settings validation |302| LeadTrigger | Lead | Lead conversion handling |303| TaskTrigger | Task | Task automation |304305### kuga_sub Triggers (14 — only when HAS_KUGA_SUB = true)306307| Trigger | Object | Purpose |308|---------|--------|---------|309| Opportunities | Opportunity | Subscription revenue roll-ups, renewal opp linking |310| Quote | SalesQuote__c | Contract linking on renewal quotes |311| QuoteServiceLine | SalesQuoteServiceLine__c | Renew flag propagation to quote lines |312| QuoteProductLine | SalesQuoteProductLine__c | Renew flag propagation to quote lines |313| Order | SalesOrder__c | Order Release: generates Contract, Asset, Subscription, Renewal Opp |314| OrderServiceLine | SalesOrderServiceLine__c | Renew/Track flag handling, subscription creation |315| OrderProductLine | SalesOrderProductLine__c | Renew/Track flag handling, asset creation |316| Contracts | Contract | Subscription roll-ups, renewal notice scheduling |317| Asset | Asset | Contract/subscription linking |318| Subscription | Subscription__c | Subscription lifecycle management |319| Product | Product2 | Renewable/Track flag sync |320| AdditionalAccountDetail | AdditionalAccountDetail__c | Account subscription data sync |321| KugamonSetting | KugamonSetting__c | Subscription settings sync |322| ShipmentLine | ShipmentLine__c | Asset tracking on shipment |323324---325326## Apex Class Logic327328### kuga_sub Architecture329330All 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()`.331332**Central orchestration class:** `KugamonHelper` — contains all core business logic as static methods. Trigger handlers are thin dispatchers that call into KugamonHelper.333334**Security:** All DML operations use `SecurityUtil.stripInaccessibleFromDML()` for FLS enforcement.335336### Order Release Coordination337338The 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.339340**Static coordination flags on KugamonHelper:**341- `hasRenewableProducts` / `hasRenewableServices` — set by product/service line afterUpdate triggers342- `processedContract` / `processedSubscription` — prevent duplicate processing343- `processedProductLineAfterUpdateTrigger` / `processedServiceLineAfterUpdateTrigger` — track which line triggers have fired344- `mapNewContractOrders` — shared map of orders needing processing, populated by SalesOrderTriggerHandler345346**Execution flow when Order status changes:**3473481. **SalesOrderTriggerHandler.afterUpdate** detects status change, populates `mapNewContractOrders`, calls `createContract` → `createSubscription` → `createRenewalOpportunity`3492. Contract/Subscription creation updates order line items, which fires **ServiceLine** and **ProductLine** afterUpdate triggers3503. Line triggers check `mapNewContractOrders` — if populated and their counterpart has already fired, they call `createContract` → `createSubscription` → `createRenewalOpportunity` again3514. The `processedContract` / `processedSubscription` flags prevent duplicate execution352353**Key setting:** `InitiateOrderSubscriptionManagement__c` on `kuga_sub__SubscriptionSetting__c` controls WHEN Order Release fires:354- `"Approve/Release"` — fires when order status changes to Approved AND Released355- `"Release"` — fires only when order status changes to Released356357### KugamonHelper Key Methods358359#### Order Release Methods360361| Method | Purpose |362|--------|---------|363| `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` |364| `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` |365| `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 |366367#### Cancellation / Un-Release Methods368369| Method | Purpose |370|--------|---------|371| `deActivateOrderContracts(set<Id>)` | When order is cancelled/un-released: deletes generated contracts, expires renewal opportunities (sets stage to "Closed Lost"), deactivates subscriptions |372| `unReleaseUpsellOrders(map<Id, Id>)` | Handles un-release of expansion/upsell orders — reverses quantity changes on parent subscriptions |373| `updateSubscriptionStatus(Set<Id>, String)` | Bulk updates subscription status for a set of order IDs |374375#### Renewal and Pricing Methods376377| Method | Purpose |378|--------|---------|379| `updateRenewalUpliftSalesPrice(map newOpps, map oldOpps)` | When a Renewal opportunity's `RenewalPriceUpliftPercent__c` changes, recalculates UnitPrice on all OLIs by applying uplift to `NonUpliftSalesPrice__c` |380| `updateRenewalOrderContractPriceBook(map newOrders, map oldOrders)` | When Renewal order's pricebook changes, syncs back to parent Contract's `Pricebook2Id__c` |381| `updateContractOpptyServiceTerm(map<Id, decimal>)` | Updates ServiceTerm on opportunity line items when contract renewal term changes |382| `deleteOLISchedule(set<Id>)` | Deletes OpportunityLineItemSchedule records when renewal pricing changes |383384#### Line Item and Flag Propagation Methods385386| Method | Purpose |387|--------|---------|388| `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 |389| `updateExpansionKitMemberServiceEndDate(list<ServiceLine>)` | For Expansion orders: adjusts service end dates on kit member lines to align with the parent kit line's end date |390| `setAssetDetails(list<Asset>)` | beforeInsert on Asset: links asset to Contract and Subscription via `ContractNumber__c` and `ParentSubscription__c` |391| `updateSubscriptionDetails(list<Asset>)` | afterInsert on Asset: updates the parent Subscription's `ParentAsset__c` to point back to the newly created asset |392393#### Matching Utility394395| Method | Purpose |396|--------|---------|397| `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 |398399### Trigger Handler Behaviors400401#### SalesOrderTriggerHandler402- **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 flags403- **afterUpdate**: Detects Order status change → triggers Order Release chain (createContract → createSubscription → createRenewalOpportunity). On cancellation/un-release → calls `deActivateOrderContracts` to reverse all generated records404405#### SalesQuoteTriggerHandler406- **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 Contract407408#### ContractTriggerHandler409- **beforeInsert/Update**: Validates single active contract per account (unless `AllowMultipleActiveContracts__c` = true). Auto-calculates `ContractTerm` from StartDate and EndDate410- **beforeUpdate**: `setContactDetails` syncs billing/shipping addresses from Contact records to Contract address fields. Validates required address fields are populated411- **afterUpdate — Activation**: When contract activates, syncs `IsActive__c` on all child Subscriptions412- **afterUpdate — Cancellation**: When contract is cancelled, cancels all child Subscriptions (sets `Status__c = 'Cancelled'`) and closes the linked Renewal Opportunity (stage → "Closed Lost")413- **afterUpdate**: Syncs `AutoEmailRenewalOrder__c` flag changes to the linked Renewal Opportunity414415#### SubscriptionTriggerHandler416- **beforeInsert/Update**: Syncs `IsActive__c` (editable) with `Active__c` (formula) to keep them aligned417- **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 entirely418419#### OpportunityTriggerHandler420- **beforeUpdate**: Validates currency match for Expansion/Renewal opportunities — the opp's CurrencyIsoCode must match the parent Contract's currency. Prevents currency mismatch errors421- **afterUpdate**: When `RenewalPriceUpliftPercent__c` changes on a Renewal opp, triggers `updateRenewalUpliftSalesPrice` to recalculate all line item prices422423#### AssetTriggerHandler424- **beforeInsert**: Calls `KugamonHelper.setAssetDetails` — links asset to Contract and Subscription425- **afterInsert**: Calls `KugamonHelper.updateSubscriptionDetails` — sets `ParentAsset__c` on the subscription426427#### SalesOrderServiceLineTriggerHandler428- **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`429- **afterUpdate**: Sets `processedServiceLineAfterUpdateTrigger = true`, then conditionally calls Order Release chain if `mapNewContractOrders` is populated430431#### SalesOrderProductLineTriggerHandler432- **beforeInsert**: Same pattern as service line handler. `Track__c` from `AdditionalProductDetail.CreateAsset`. Propagates `Renew__c` from linked quote product line433- **afterUpdate**: Sets `processedProductLineAfterUpdateTrigger = true`, then conditionally calls Order Release chain434435### Scheduled Batch Jobs436437Three scheduleable batch classes handle automated lifecycle operations:438439| Batch Class | Schedule | Purpose |440|-------------|----------|---------|441| `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 |442| `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 |443| `SubscriptionBatcher` | Periodic | Syncs `IsActive__c` (editable checkbox) with `Active__c` (formula) on Subscriptions where they have diverged. Safety net to keep these fields aligned |444445### Key Settings That Drive Behavior446447These fields on `kuga_sub__SubscriptionSetting__c` control critical behavior:448449| Setting Field | Values | Effect |450|---------------|--------|--------|451| `InitiateOrderSubscriptionManagement__c` | "Approve/Release" or "Release" | Controls WHEN Order Release fires — on approval+release or release only |452| `ExtendContractonRenewal__c` | Checkbox | If true, Renewal orders extend existing contract end date instead of creating a new contract |453| `AllowMultipleActiveContracts__c` | Checkbox | If true, allows multiple active contracts per account. If false, ContractTriggerHandler enforces single active contract |454| `ContractRenewalEmailTemplateName__c` | Text | Email template API name for renewal notice emails sent by ContractRenewalNoticeBatcher |455456### Order Release Trigger Map457458Three 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.459460```461SUBSCRIPTION (Order Service Line trigger only)462─────────────463Product2.kuga_sub__Track__c (label: "Create Subscription")464 └─ propagates → OLI / QuoteLine / OrderLine .kuga_sub__Track__c465 └─ on Order Release, when the line is a Service466 (lands on kugo2p__SalesOrderServiceLine__c; APD.Service__c = true):467 └─→ Order Service Line trigger creates a Subscription468 └─ on Order Product Lines: no Subscription, ever469470ASSET (Order Product Line trigger only)471─────472kugo2p__AdditionalProductDetail__c.kugo2p__CreateAsset__c473 └─ on Order Release, when the line is a Product474 (lands on kugo2p__SalesOrderProductLine__c; APD.Service__c = false):475 └─→ Order Product Line trigger creates an Asset476 └─ on Order Service Lines: no Asset, ever477478RENEWAL OPPORTUNITY (any line)479───────────────────480Product2.kuga_sub__Renewable__c481 └─ on Order Release, if true on any line's product (service or product):482 └─→ Renewal Opportunity created483 └─ also drives the "Renewable" prefix on the Product Snapshot LWC484```485486**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.487488### kugo2p Apex Classes489490Below is the architectural overview of key kugo2p Apex classes.491492#### Core Architecture Patterns493494**Kontroller** — Central action router for all Visualforce/LWC button actions. Key design:495- `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 buttons496- `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)497- `ValidateAccountDetails(Id acctId)` — validates billing address and contact exist before quote/order creation. Called by trigger handlers too498- Order status flow: Draft → Sent → Approved → Released → Cancelled. Special statuses: `ApproveOrderandPay` (approve + immediate payment), `Unrelease`, `CancelApproved`, `CancelReleased`499- Quote Won flow: `updateQuoteStatusToWonAndGenerateOrder()` sets quote status to Won, then internally routes to `createSalesOrder` to auto-generate order500501**KugamonSyncService** — Bidirectional sync between Quotes/Orders and OpportunityLineItems. Implements `Queueable` for async processing:502- `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 process503- `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`504- `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 OLI505- `disableOpportunitySync` static boolean — can be set to skip sync entirely506- Lines with "Exclude from Opportunity Sync" flag are skipped (creates a Task notification)507- Lines with Quantity = 0 are skipped (OLI doesn't support zero quantity)508- Lines with inactive PricebookEntry are skipped509510**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 caching511512**SecurityUtil** — All DML operations across the entire package use `SecurityUtil.stripInaccessibleFromDML()` for FLS enforcement. Delete operations check `SecurityUtil.checkObjectIsDeletable()`513514#### Helper Classes515516| Class | Key Methods |517|-------|-------------|518| 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` |519| SalesQuoteHelper | `createSalesQuote`, `fillSalesQuote`, `fillSalesQuoteProductLine`/`fillSalesQuoteServiceLine` (multiple overloads with tiered pricing and kit bundles), `calculateServiceEndDate` (multiple overloads), `fillKitMemberQuoteLines`, `createSalesQuoteLines`, `getDateAvailableToPromise`, `cloneSalesQuote`, `assignPrimaryQuote`, `handleQuoteStatusUpdate`, `syncPriceBook` |520| GroupHelper | Inner classes `LineGroup` and `LineGroupMember`. `processProductOrServiceLine`/`processACCLine`/`processOptionalLine`, `createLine`, `prepareLine`/`prepare`, `upsertGroups`/`upsertLines`, `getDBGroups`, `createLineGroupMap`, `processKitBundleLine`, `assignKitBundleMembersToLines` |521| ProductHelper | `CreateProductDetail`, `MapProductDetail`, inner classes `ProductTileData`/`Tier`/`Subscription`, `createPricebookEntryMap`, `getCurrencyCode`, `buildProductRecords`/`buildAssetRecords`/`buildSubscriptionRecords`, `getAccountIdsByHierarchy`, `setProductAccountPricingFields`, `evaluateAccountPricingFilter`, `getPricebookTieredPricing`/`getProductTieredPrice`, `setProductsInContractPricebook`, `setFavoritedProducts`, `setProductCostFields`, `validateAPD` |522| InvoiceHelper | `createInvoiceSchedule`, `buildInvoices`, `createInvoice`, `updateInvoicedQuantities`, `updateInvoiceLineAmounts`, `fillInvoice`, `handleInvoiceStatusUpdate`, `getInvoicePOKey` |523| PaymentHelper | `createPaymentProfile`, `createInvoicePayment`/`createOrderPayment`/`createAccountPayment`, `matchKugamonPayment`, `applyInvoicePayments`/`applyOrderPayments`, `applyPaymentsToLines`, `deleteInProcessPayments` |524| AccountHelper | `MapAccountDetail` (creates/upserts AdditionalAccountDetail from Account), `updateAccountBalance_Batch`, `isPersonAccount` |525| 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) |526527#### kugo2p Trigger Handler Behaviors528529##### SalesQuoteTriggerHandler530- **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 defaults531- **afterInsert**: Copies OpportunityLineItems to quote lines via `SalesQuoteHelper.createSalesQuoteLines`. Calls `SalesQuoteHelper.assignPrimaryQuote` to set IsPrimary532- **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 exist533- **afterUpdate**: Cascades ContactShipping, Carrier, Warehouse, Opportunity changes to all child lines. Calls `KugamonSyncService.syncOpportunity` for opportunity sync. Calls `SalesQuoteHelper.handleQuoteStatusUpdate` on status changes534535##### SalesQuoteServiceLineTriggerHandler536- **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 quote537- **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 sync538- **beforeDelete**: Prevents deletion of required kit bundle members. Cascade deletes child kit members539540##### SalesQuoteProductLineTriggerHandler541- **beforeInsert**: Assigns SortOrder. Validates pricebook (including kit bundle member validation via APD/KBM queries). If `Kontroller.logicPath == 'trigger'`: fills product line defaults, enforces currency match542- **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`543- **beforeDelete**: Prevents required kit member deletion. Cascade deletes child products AND child services544545**Cross-trigger coordination:** `TriggerHelper.passedPricebookValidation` static flag prevents duplicate pricebook validation when both product and service line triggers fire in the same transaction546547##### SalesOrderTriggerHandler548- **beforeInsert**: Validates pricebook, assigns currency. Generates Onl549550…(truncated)