### Integration Test for applyDiscounts Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Integration test for OpportunitiesService.applyDiscounts. This test requires data setup and runs as a standard user with a specific permission set to verify the discount application in a near-production environment. ```apex // --- Integration test (runs as user with permission set for USER_MODE) --- @IsTest private static void applyDiscountsIntegrationTest() { // Data setup in system context (PricebookEntry insert requires admin privileges) Opportunity opp = new Opportunity(Name='Test', StageName='Open', CloseDate=System.today()); insert opp; Product2 prod = new Product2(Name='Widget'); insert prod; PricebookEntry pbe = new PricebookEntry( UnitPrice=100, IsActive=true, UseStandardPrice=false, Pricebook2Id=Test.getStandardPricebookId(), Product2Id=prod.Id); insert pbe; insert new OpportunityLineItem( OpportunityId=opp.Id, PricebookEntryId=pbe.Id, Quantity=1, TotalPrice=100); // Act as standard user with ApexEnterprisePatternsSampleApp permission set System.runAs(TestDataFactory.getRunAsUser()) { Test.startTest(); OpportunitiesService.applyDiscounts(new Set{ opp.Id }, 10); Test.stopTest(); } System.assertEquals(90, [SELECT Amount FROM Opportunity WHERE Id = :opp.Id].Amount); } ``` -------------------------------- ### Opportunity Trigger Handling with fflib_SObjectDomain Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Handles Opportunity trigger events by extending `fflib_SObjectDomain`. Applies default discounts, validates account association for 'Existing' types, and prevents Opportunity type changes. Requires `fflib_SObjectDomain` and `AccountsService`. ```apex // Opportunity.trigger (single-line dispatch — all logic in the domain class) trigger Opportunities on Opportunity ( before insert, before update, after insert, after update, after delete, after undelete) { fflib_SObjectDomain.triggerHandler(OpportunitiesTriggerHandler.class); } ``` ```apex // Domain handler hooks public class OpportunitiesTriggerHandler extends fflib_SObjectDomain { public OpportunitiesTriggerHandler(List sObjectList) { super(sObjectList); } public override void onApplyDefaults() { for (Opportunity opp : (List) this.records) opp.DiscountType__c = OpportunitySettings__c.getInstance().DiscountType__c; } public override void onValidate() { for (Opportunity opp : (List) this.records) if (opp.Type != null && opp.Type.startsWith('Existing') && opp.AccountId == null) opp.AccountId.addError( error('You must provide an Account for existing Customers.', opp, Opportunity.AccountId)); } public override void onValidate(Map existingRecords) { for (Opportunity opp : (List) this.records) { Opportunity existing = (Opportunity) existingRecords.get(opp.Id); if (opp.Type != existing.Type) opp.Type.addError( error('You cannot change the Opportunity type once it has been created.', opp, Opportunity.Type)); } } public override void onAfterInsert() { Set accountIds = Opportunities.newInstance(this.records).getAccountIds(); if (!accountIds.isEmpty()) AccountsService.updateOpportunityActivity(accountIds); } } ``` -------------------------------- ### Create Invoices from Opportunities in Apex Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Use this method to create Invoice__c and InvoiceLine__c records from closed Opportunities. Optionally apply a discount percentage before invoice creation. All DML is batched through one Unit of Work and committed atomically. Returns the Set of generated Invoice IDs. ```apex // --- Production usage --- Set oppIds = new Set{ '006000000000001AAA' }; // Create invoices without any discount Set invoiceIds = OpportunitiesService.createInvoices(oppIds, null); // Create invoices after applying a 15 % discount Set invoiceIdsWithDiscount = OpportunitiesService.createInvoices(oppIds, 15); ``` ```apex // --- Service implementation detail (OpportunitiesServiceImpl) --- public Set createInvoices(Set opportunityIds, Decimal discountPercentage) { fflib_ISObjectUnitOfWork uow = Application.UnitOfWork.newInstance(); IOpportunities opps = Opportunities.newInstance( OpportunitiesSelector.newInstance().selectByIdWithProducts(opportunityIds)); if (discountPercentage != null && discountPercentage > 0) opps.applyDiscount(discountPercentage, uow); List invoices = new List(); for (Opportunity opp : (List) opps.getRecords()) { Invoice__c invoice = new Invoice__c(); invoice.Account__c = opp.AccountId; invoice.Description__c = opp.Description; invoice.InvoiceDate__c = opp.CloseDate; invoice.Opportunity__c = opp.Id; uow.registerNew(invoice); for (OpportunityLineItem li : opp.OpportunityLineItems) { InvoiceLine__c line = new InvoiceLine__c(); line.Description__c = li.Description; line.Product__c = li.PricebookEntry.Product2Id; line.UnitPrice__c = li.UnitPrice; line.Quantity__c = li.Quantity; uow.registerNew(line, InvoiceLine__c.Invoice__c, invoice); } invoices.add(invoice); } uow.commitWork(); Set invoiceIds = new Set(); for (SObject inv : invoices) invoiceIds.add((Id) inv.get('Id')); return invoiceIds; } ``` -------------------------------- ### Apply Discount to Opportunity (REST API) Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt This snippet shows how to apply a discount to a specific opportunity using a REST API endpoint. It includes the cURL command for making the request and the Apex implementation of the REST resource. ```APIDOC ## POST /services/apexrest/opportunities/:opportunityId/applydiscount ### Description Applies a specified discount percentage to an opportunity. ### Method POST ### Endpoint /services/apexrest/opportunities/:opportunityId/applydiscount?discount= ### Parameters #### Query Parameters - **discount** (Decimal) - Required - The percentage of discount to apply. ### Request Example ```bash curl -X POST \ "https://.salesforce.com/services/apexrest/opportunities/006b0000003u4Ln/applydiscount?discount=10" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" ``` ### Response #### Success Response (200) An empty body is returned on success. #### Error Response (500) Salesforce error JSON is returned on error. ``` ```APIDOC ## OpportunitiesResource (Apex Class) ### Description Implements the REST endpoint for applying discounts to opportunities. ### Method `HttpPost` ### Endpoint Mapping `@RestResource(UrlMapping='/opportunities/*/applydiscount')` ### Logic Parses the opportunity ID from the URI and the discount percentage from query parameters. Calls `OpportunitiesService.applyDiscounts` to perform the operation. ``` -------------------------------- ### OpportunityApplyDiscountController (Visualforce) Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt This controller backs Visualforce pages for applying discounts to single opportunities or multiple opportunities selected in a list view. It handles user input for the discount percentage and delegates the actual discount application to the OpportunitiesService. ```APIDOC ## OpportunityApplyDiscountController (Apex Class) ### Description Controller for Visualforce pages to apply discounts to Opportunities. Supports single record and list view operations. ### Properties - **DiscountPercentage** (Decimal) - Property to hold the discount percentage entered by the user. ### Constructors - `OpportunityApplyDiscountController(ApexPages.StandardController sc)`: Constructor for single-record pages. - `OpportunityApplyDiscountController(ApexPages.StandardSetController ssc)`: Constructor for list view pages. ### Methods - **applyDiscount()** (PageReference): Called from a single-record VF page button. Applies discount to the current opportunity and returns to the record view or null if errors occur. - **applyDiscounts()** (PageReference): Called from a list view VF page button. Applies discount to all selected opportunities and adds an informational message. ``` -------------------------------- ### Querying Opportunities with FLS Enforcement Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Demonstrates querying Opportunity data using `fflib_SObjectSelector` with `DataAccess.USER_MODE` to enforce Field-Level Security. Includes methods for selecting by ID, with line items, lightweight DTOs, and a `QueryLocator` for batch processing. ```apex // Instantiate via factory (respects mock substitution in tests) IOpportunitiesSelector sel = OpportunitiesSelector.newInstance(); // Basic select by ID List opps = sel.selectById(new Set{ oppId }); // Select with products, pricebook entries, and pricebooks (sub-selects) List oppsWithLines = sel.selectByIdWithProducts(new Set{ oppId }); for (OpportunityLineItem li : oppsWithLines[0].OpportunityLineItems) { System.debug(li.UnitPrice + ' x ' + li.Quantity); } // Lightweight DTO projection for console views List infos = sel.selectOpportunityInfo(new Set{ oppId }); System.debug(infos[0].AccountName + ' | ' + infos[0].Stage + ' | ' + infos[0].Amount); // Query locator for Batch Apex (Opportunities ready to invoice) Database.QueryLocator ql = new OpportunitiesSelector().queryLocatorReadyToInvoice(); // Equivalent SOQL: SELECT ... FROM Opportunity WHERE InvoicedStatus__c = 'Ready' ``` -------------------------------- ### OpportunityApplyDiscountController for Visualforce Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt This Apex controller backs Visualforce pages for applying discounts to single opportunities or multiple selected opportunities. It handles user input for the discount percentage and calls the service layer. ```apex // Standard controller usage (single record custom button page) public with sharing class OpportunityApplyDiscountController { public Decimal DiscountPercentage { get; set; } private ApexPages.StandardController standardController; private ApexPages.StandardSetController standardSetController; public OpportunityApplyDiscountController(ApexPages.StandardController sc) { standardController = sc; } public OpportunityApplyDiscountController(ApexPages.StandardSetController ssc) { standardSetController = ssc; } // Called from a single-record VF page button public PageReference applyDiscount() { try { OpportunitiesService.applyDiscounts( new Set{ standardController.getId() }, DiscountPercentage); } catch (Exception e) { ApexPages.addMessages(e); } return ApexPages.hasMessages() ? null : standardController.view(); } // Called from a list view VF page button public PageReference applyDiscounts() { try { Set selected = new Map(standardSetController.getSelected()).keySet(); OpportunitiesService.applyDiscounts(selected, DiscountPercentage); ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'Opportunities updated.')); } catch (Exception e) { ApexPages.addMessages(e); } return null; } } ``` -------------------------------- ### Application DI Container and Factory Singletons Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt The `Application.cls` class acts as the central dependency injection container, wiring together Unit of Work, Service, Selector, and Domain factories. It configures commit ordering, maps interfaces to implementations, and registers SObject types with their respective classes. The inner `UserModeUnitOfWorkFactory` ensures all DML operations respect FLS by using `UserModeDML`. ```apex public class Application { // UoW commit order; uses UserModeDML for FLS enforcement public static final fflib_Application.UnitOfWorkFactory UnitOfWork = new UserModeUnitOfWorkFactory( new List { Account.SObjectType, Invoice__c.SObjectType, InvoiceLine__c.SObjectType, Opportunity.SObjectType, Product2.SObjectType, PricebookEntry.SObjectType, OpportunityLineItem.SObjectType, WorkOrder__c.SObjectType, DeveloperWorkItem__c.SObjectType, TrainingWorkItem__c.SObjectType, DesignWorkItem__c.SObjectType }); // Interface-to-implementation map for the Service layer public static final fflib_Application.ServiceFactory Service = new fflib_Application.ServiceFactory( new Map { IAccountsService.class => AccountsServiceImpl.class, IOpportunitiesService.class => OpportunitiesServiceImpl.class, IInvoicingService.class => InvoicingServiceImpl.class }); // SObjectType-to-Selector class map public static final fflib_Application.SelectorFactory Selector = new fflib_Application.SelectorFactory( new Map { Account.SObjectType => AccountsSelector.class, Opportunity.SObjectType => OpportunitiesSelector.class, OpportunityLineItem.SObjectType => OpportunityLineItemsSelector.class, PricebookEntry.SObjectType => PricebookEntriesSelector.class, Pricebook2.SObjectType => PricebooksSelector.class, Product2.SObjectType => ProductsSelector.class, User.sObjectType => UsersSelector.class }); // SObjectType-to-Domain constructor map public static final fflib_Application.DomainFactory Domain = new fflib_Application.DomainFactory( Application.Selector, new Map { Opportunity.SObjectType => Opportunities.Constructor.class, OpportunityLineItem.SObjectType => OpportunityLineItems.Constructor.class, Account.SObjectType => Accounts.Constructor.class, DeveloperWorkItem__c.SObjectType => DeveloperWorkItems.class }); // Factory override — forces UserModeDML on every UoW instance private class UserModeUnitOfWorkFactory extends fflib_Application.UnitOfWorkFactory { public UserModeUnitOfWorkFactory(List objectTypes) { super(objectTypes); } public override fflib_ISObjectUnitOfWork newInstance() { if (m_mockUow != null) return m_mockUow; return new fflib_SObjectUnitOfWork(m_objectTypes, new fflib_SObjectUnitOfWork.UserModeDML()); } } } ``` -------------------------------- ### OpportunitiesResource Apex Class for Applying Discounts Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt This Apex class implements the REST endpoint for applying discounts to opportunities. It parses the opportunity ID from the URL and the discount percentage from query parameters. ```apex // OpportunitiesResource implementation @RestResource(UrlMapping='/opportunities/*/applydiscount') global with sharing class OpportunitiesResource { @HttpPost global static void applyDiscount() { RestRequest req = RestContext.request; String[] uriParts = req.requestURI.split('/'); Id opportunityId = uriParts[2]; String discountParam = req.params.get('discount'); Decimal discountPercent = discountParam != null ? Decimal.valueOf(discountParam) : 0; OpportunitiesService.applyDiscounts(new Set{ opportunityId }, discountPercent); } } ``` -------------------------------- ### TestDataFactory for USER_MODE Tests Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Utility class to create a Standard User with a specific permission set for tests requiring USER_MODE execution context. Use `createUserWithSampleAppPermissions()` in `@TestSetup` and `getRunAsUser()` within `System.runAs()` blocks. ```apex @IsTest private class MyServiceTest { @TestSetup static void setup() { TestDataFactory.createUserWithSampleAppPermissions(); } @IsTest private static void myTest() { // Data setup (system context — admin privileges for PricebookEntry, etc.) Opportunity opp = new Opportunity(Name='Test', StageName='Open', CloseDate=System.today()); insert opp; // Service call under USER_MODE (requires permission set for FLS) System.runAs(TestDataFactory.getRunAsUser()) { Test.startTest(); OpportunitiesService.applyDiscounts(new Set{ opp.Id }, 5); Test.stopTest(); } System.assertNotEquals(null, [SELECT Amount FROM Opportunity WHERE Id = :opp.Id].Amount); } } ``` -------------------------------- ### Apply 10% Discount to Opportunity via REST API Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Use this cURL command to apply a discount to a specific opportunity via the REST API. Ensure you replace placeholders with your actual instance URL, session ID, and opportunity ID. ```shell curl -X POST \ "https://.salesforce.com/services/apexrest/opportunities/006b0000003u4Ln/applydiscount?discount=10" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" ``` -------------------------------- ### Apply Discount to Opportunity via REST API Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Exposes a REST endpoint for applying a percentage discount to an Opportunity. The controller is a thin wrapper around OpportunitiesService.applyDiscounts. -------------------------------- ### Apply Discount via JavaScript Remoting Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Exposes an Apex method for direct JavaScript calls from Visualforce or Salesforce Console to apply discounts to opportunities. Ensure the `escape` option is set to `true` for security. ```apex public with sharing class OpportunityConsoleController { @RemoteAction public static void applyDiscount(Id opportunityId, Decimal discountPercent) { OpportunitiesService.applyDiscounts(new Set{ opportunityId }, discountPercent); } } ``` ```javascript // Call from a Visualforce page JavaScript block OpportunityConsoleController.applyDiscount( '{!Opportunity.Id}', 10, function(result, event) { if (event.status) { console.log('Discount applied successfully'); } else { console.error('Error: ' + event.message); } }, { escape: true } ); ``` -------------------------------- ### OpportunitiesService.applyDiscounts Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Applies a percentage discount to one or more Opportunities. This method queries Opportunities with their line items, wraps them in the Opportunities domain class, applies the discount, and commits the changes via a Unit of Work. ```APIDOC ## OpportunitiesService.applyDiscounts(Set oppIds, Decimal discountPercentage) ### Description Applies a specified percentage discount to a set of Opportunities. This operation is handled transactionally using a Unit of Work. ### Method Signature `OpportunitiesService.applyDiscounts(Set oppIds, Decimal discountPercentage)` ### Parameters #### Path Parameters - None #### Query Parameters - None #### Request Body - None ### Parameters - **oppIds** (Set) - Required - A set of Opportunity IDs to which the discount will be applied. - **discountPercentage** (Decimal) - Required - The percentage discount to apply (e.g., 10 for 10%). ### Request Example ```apex Set opportunityIds = new Set{ '006000000000001AAA', '006000000000002AAA' }; OpportunitiesService.applyDiscounts(opportunityIds, 10); ``` ### Response #### Success Response This method does not return a value but performs DML operations to update the Opportunities. #### Response Example N/A ``` -------------------------------- ### Generic Invoice Generation via Domain Interface Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Generates invoices for any domain that implements InvoicingService.ISupportInvoicing. Throws ApplicationException if the domain does not support invoicing. ```apex // Generate invoices for any domain that implements ISupportInvoicing List invoiceIds = InvoicingService.generate(new List{ oppId1, oppId2 }); System.debug('Generated ' + invoiceIds.size() + ' invoices'); ``` ```apex // --- Implementing ISupportInvoicing on a Domain class --- public class Opportunities extends fflib_SObjects implements IOpportunities, InvoicingService.ISupportInvoicing { public void generate(InvoicingService.InvoiceFactory invoiceFactory) { for (Opportunity opp : (List) getRecords()) { InvoicingService.Invoice invoice = new InvoicingService.Invoice(); invoice.Account = opp.AccountId; invoice.Description = opp.Description; invoice.InvoiceDate = opp.CloseDate.addDays(14); // net-14 terms invoice.Lines = new List(); for (OpportunityLineItem li : opp.OpportunityLineItems) { InvoicingService.InvoiceLine line = new InvoicingService.InvoiceLine(); line.Description = li.Description; line.Product = li.PricebookEntry.Product2Id; line.UnitPrice = li.UnitPrice; line.Quantity = li.Quantity; invoice.Lines.add(line); } invoiceFactory.add(invoice); // registers Invoice__c + InvoiceLine__c with UoW } } } ``` ```apex // --- Integration test --- @IsTest private static void testInvoicingService() { // Setup in system context fflib_ISObjectUnitOfWork uow = Application.UnitOfWork.newInstance(); Opportunity opp = new Opportunity(Name='Opp', StageName='Open', CloseDate=System.today()); uow.registerNew(opp); for (Integer i = 0; i < 5; i++) { Product2 prod = new Product2(Name='Prod ' + i); uow.registerNew(prod); PricebookEntry pbe = new PricebookEntry( UnitPrice=10, IsActive=true, UseStandardPrice=false, Pricebook2Id=Test.getStandardPricebookId()); uow.registerNew(pbe, PricebookEntry.Product2Id, prod); OpportunityLineItem oli = new OpportunityLineItem(Quantity=1, TotalPrice=10); uow.registerRelationship(oli, OpportunityLineItem.PricebookEntryId, pbe); uow.registerNew(oli, OpportunityLineItem.OpportunityId, opp); } uow.commitWork(); System.runAs(TestDataFactory.getRunAsUser()) { List invoiceIds = InvoicingService.generate(new List{ opp.Id }); System.assertEquals(1, invoiceIds.size()); } } ``` -------------------------------- ### Apply Percentage Discount to Opportunities Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Applies a percentage discount to Opportunities. Use this method from controllers or REST endpoints. Ensure the correct IDs and discount percentage are provided. ```apex // --- Production call (e.g., from a controller or REST endpoint) --- Set oppIds = new Set{ '006000000000001AAA', '006000000000002AAA' }; OpportunitiesService.applyDiscounts(oppIds, 10); // apply 10 % discount ``` -------------------------------- ### OpportunitiesResource.applyDiscount Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Applies a specified percentage discount to an Opportunity. ```APIDOC ## OpportunitiesResource — REST API: Apply Discount `OpportunitiesResource` exposes a `@RestResource` endpoint at `/services/apexrest/opportunities/*/applydiscount`. An HTTP POST with a `discount` query parameter applies that percentage discount to the Opportunity whose ID appears in the URL path. The controller is a thin wrapper around `OpportunitiesService.applyDiscounts`. ### Method POST ### Endpoint `/services/apexrest/opportunities/{opportunityId}/applydiscount` ### Query Parameters * **discount** (Decimal) - Required - The percentage discount to apply. ### Request Example (Bash) ```bash curl \ --request POST \ --url "https://yourinstance.salesforce.com/services/apexrest/opportunities/006XXXXXXXXXXXX/applydiscount?discount=10" \ --header "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` ### Description This endpoint applies a given percentage discount to a specific Opportunity. The Opportunity ID is part of the URL, and the discount percentage is provided as a query parameter. This operation is a wrapper around the `OpportunitiesService.applyDiscounts` method. ``` -------------------------------- ### OpportunitiesService.createInvoices Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Creates Invoice__c and InvoiceLine__c records from closed Opportunities. Optionally applies a discount and uses Unit of Work for atomic DML operations. Returns the Set of generated Invoice IDs. ```APIDOC ## OpportunitiesService.createInvoices — Create Invoices from Opportunities ### Description Creates `Invoice__c` and `InvoiceLine__c` records from closed Opportunities, optionally applying a discount first. All DML is batched through one Unit of Work and committed atomically. Returns the Set of generated Invoice IDs. ### Method Signature `OpportunitiesService.createInvoices(Set opportunityIds, Decimal discountPercentage)` ### Parameters #### Path Parameters - **opportunityIds** (Set) - Required - A set of Opportunity IDs to create invoices from. - **discountPercentage** (Decimal) - Optional - The percentage discount to apply before creating invoices. If null or 0, no discount is applied. ### Request Example ```apex // Create invoices without any discount Set oppIds = new Set{ '006000000000001AAA' }; Set invoiceIds = OpportunitiesService.createInvoices(oppIds, null); // Create invoices after applying a 15 % discount Set invoiceIdsWithDiscount = OpportunitiesService.createInvoices(oppIds, 15); ``` ### Response #### Success Response - **Set** - A set containing the IDs of the newly created Invoice__c records. ``` -------------------------------- ### OpportunityCreateInvoiceController (Visualforce) Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt This controller is used for Visualforce pages that create invoices for opportunities. It supports both single opportunity invoice creation (redirecting to the new invoice record) and bulk invoice creation for selected opportunities (staying on the page with a confirmation message). ```APIDOC ## OpportunityCreateInvoiceController (Apex Class) ### Description Controller for Visualforce pages to create invoices for Opportunities. Supports single record and list view operations. ### Methods - **createInvoice()** (PageReference): Creates a single invoice for the current opportunity and redirects to the newly created Invoice__c record. Handles exceptions by adding messages. - **createInvoices()** (PageReference): Creates invoices for all selected opportunities from a list view. Adds a confirmation message upon successful creation. Handles exceptions by adding messages. ``` -------------------------------- ### AbstractChargeable Domain Base Class Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Abstract base class for domain objects that automatically compute a cost field based on hours worked. Subclasses must implement methods to define the target cost field and how to calculate hours worked. ```apex public abstract class AbstractChargeable extends fflib_SObjectDomain implements IChargeable { public abstract Schema.SObjectField getCostOfHoursWorkedField(); public abstract List calculateHoursWorked(); public override void onBeforeInsert() { updateCostOfHoursWorked(); } public override void onBeforeUpdate(Map existing) { updateCostOfHoursWorked(); } public void updateCostOfHoursWorked() { List hours = calculateHoursWorked(); Schema.SObjectField costField = getCostOfHoursWorkedField(); Integer idx = 0; for (SObject rec : this.records) rec.put(costField, hours[idx++] * 100); // cost = hours × 100 } } ``` ```apex public class DeveloperWorkItems extends AbstractChargeable implements IDeveloperWorkItems { public override Schema.SObjectField getCostOfHoursWorkedField() { return DeveloperWorkItem__c.DeveloperCost__c; } public override List calculateHoursWorked() { List result = new List(); for (DeveloperWorkItem__c wi : (List) this.records) result.add((Integer)(wi.CodingHours__c + wi.CodeReviewingHours__c + wi.TechnicalDesignHours__c)); return result; } } ``` ```apex DeveloperWorkItem__c item = new DeveloperWorkItem__c( CodingHours__c=8, CodeReviewingHours__c=2, TechnicalDesignHours__c=4); insert item; // DeveloperCost__c is set to (8+2+4)*100 = 1400 automatically ``` -------------------------------- ### Submit Batch Invoice Creation Job in Apex Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Enqueues the CreateInvoicesJob as a Batch Apex job to process Opportunities ready for invoicing. Errors are captured and emailed to the submitting user upon job completion. The job can also be scheduled using System.schedule. ```apex // Submit the batch job (returns the AsyncApexJob Id) Id jobId = OpportunitiesService.submitInvoicingJob(); System.debug('Batch job submitted: ' + jobId); ``` ```apex // The job can also be scheduled System.schedule('Nightly Invoice Run', '0 0 2 * * ?', new CreateInvoicesJob()); ``` ```apex // CreateInvoicesJob — core methods public class CreateInvoicesJob implements System.Schedulable, Database.Batchable, Database.Stateful { private List jobErrors = new List(); public void execute(SchedulableContext sc) { Database.executeBatch(new CreateInvoicesJob()); } public Database.QueryLocator start(Database.BatchableContext ctx) { // Delegates scope query entirely to the Selector layer return new OpportunitiesSelector().queryLocatorReadyToInvoice(); } public void execute(Database.BatchableContext ctx, List opps) { try { OpportunitiesService.createInvoices(new Map(opps).keySet(), 0); } catch (Exception e) { JobError err = new JobError(); err.records = opps; err.message = e.getMessage(); jobErrors.add(err); } } public void finish(Database.BatchableContext ctx) { if (jobErrors.isEmpty()) return; Map emails = new UsersSelector().getUsersEmail(new Set{ UserInfo.getUserId() }); Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); mail.setToAddresses(new String[]{ emails.get(UserInfo.getUserId()) }); mail.setSubject('Create Invoice Job Failures'); String body = ''; for (JobError e : jobErrors) body += '

' + e.message + '

'; mail.setHtmlBody(body); Messaging.sendEmail(new Messaging.SingleEmailMessage[]{ mail }); } } ``` -------------------------------- ### Unit Test for applyDiscounts with Mocks Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Unit test for OpportunitiesService.applyDiscounts using fflib_ApexMocks. This test verifies the interactions with the domain, selector, and unit of work without performing DML operations. ```apex // --- Unit test with mocks (no DML required) --- @IsTest private static void applyDiscountsMockTest() { fflib_ApexMocks mocks = new fflib_ApexMocks(); fflib_ISObjectUnitOfWork uowMock = (fflib_ISObjectUnitOfWork) mocks.mock(fflib_ISObjectUnitOfWork.class); IOpportunities domainMock = (IOpportunities) mocks.mock(IOpportunities.class); IOpportunitiesSelector selectorMock = (IOpportunitiesSelector) mocks.mock(IOpportunitiesSelector.class); mocks.startStubbing(); List stubOpps = new List{ new Opportunity( Id = fflib_IDGenerator.generate(Opportunity.SObjectType), Name = 'Test Opp', StageName = 'Open', Amount = 1000, CloseDate = System.today()) }; Set oppIds = new Map(stubOpps).keySet(); mocks.when(domainMock.getType()).thenReturn(Opportunity.SObjectType); mocks.when(selectorMock.sObjectType()).thenReturn(Opportunity.SObjectType); mocks.when(selectorMock.selectByIdWithProducts(oppIds)).thenReturn(stubOpps); mocks.stopStubbing(); Application.UnitOfWork.setMock(uowMock); Application.Domain.setMock(domainMock); Application.Selector.setMock(selectorMock); OpportunitiesService.applyDiscounts(oppIds, 10); ((IOpportunitiesSelector) mocks.verify(selectorMock)).selectByIdWithProducts(oppIds); ((IOpportunities) mocks.verify(domainMock)).applyDiscount(10, uowMock); ((fflib_ISObjectUnitOfWork) mocks.verify(uowMock, 1)).commitWork(); } ``` -------------------------------- ### OpportunitiesService.submitInvoicingJob Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Enqueues the CreateInvoicesJob as a Batch Apex job to process Opportunities ready for invoicing. Errors are captured and emailed to the submitting user upon job completion. ```APIDOC ## OpportunitiesService.submitInvoicingJob — Kick Off Batch Invoice Creation ### Description Enqueues `CreateInvoicesJob` as a Batch Apex job. The job uses `OpportunitiesSelector.queryLocatorReadyToInvoice()` to find all Opportunities with `InvoicedStatus__c = 'Ready'` and calls `OpportunitiesService.createInvoices` per batch. Errors are captured and emailed to the submitting user upon job completion. ### Method Signature `OpportunitiesService.submitInvoicingJob()` ### Parameters This method does not accept any parameters. ### Request Example ```apex // Submit the batch job (returns the AsyncApexJob Id) Id jobId = OpportunitiesService.submitInvoicingJob(); System.debug('Batch job submitted: ' + jobId); // The job can also be scheduled System.schedule('Nightly Invoice Run', '0 0 2 * * ?', new CreateInvoicesJob()); ``` ### Response #### Success Response - **Id** - The ID of the submitted asynchronous Apex job (AsyncApexJob). ### Related Classes `CreateInvoicesJob` implements `System.Schedulable`, `Database.Batchable`, and `Database.Stateful` to handle the batch processing of invoices. ``` -------------------------------- ### OpportunityCreateInvoiceController for Visualforce Invoice Creation Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt This Apex controller manages the creation of invoices from Visualforce pages. It supports both single opportunity invoice creation with redirection and bulk invoice creation for selected opportunities. ```apex // Single-record controller — creates one invoice and redirects to it public PageReference createInvoice() { try { Set invoiceIds = OpportunitiesService.createInvoices( new Set{ standardController.getId() }, DiscountPercentage); return new PageReference('/' + new List(invoiceIds)[0]); // redirect to Invoice record } catch (Exception e) { ApexPages.addMessages(e); } return ApexPages.hasMessages() ? null : standardController.view(); } // Bulk list-view controller — creates invoices for all selected Opportunities public PageReference createInvoices() { try { Set selectedIds = new Map(standardSetController.getSelected()).keySet(); OpportunitiesService.createInvoices(selectedIds, DiscountPercentage); ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.INFO, 'Invoices created.')); } catch (Exception e) { ApexPages.addMessages(e); } return null; } ``` -------------------------------- ### InvoicingService.generate Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt A polymorphic invoice generator that resolves the SObject type of the provided IDs, constructs the appropriate domain class, and calls generate(InvoiceFactory) on it. ```APIDOC ## InvoicingService.generate — Generic Invoice Generation via Domain Interface `InvoicingService.generate(List)` is a polymorphic invoice generator. It resolves the SObject type of the provided IDs, constructs the appropriate domain class, and calls `generate(InvoiceFactory)` on it — as long as the domain implements `InvoicingService.ISupportInvoicing`. `Opportunities` is the sample domain that implements this interface. Throws `ApplicationException` if the domain does not support invoicing. ### Method Signature `InvoicingService.generate(List recordIds)` ### Parameters * **recordIds** (List) - A list of IDs for which to generate invoices. ### Returns * (List) - A list of generated invoice IDs. ### Request Example (Apex) ```apex List invoiceIds = InvoicingService.generate(new List{ oppId1, oppId2 }); System.debug('Generated ' + invoiceIds.size() + ' invoices'); ``` ### Domain Implementation Example (Apex) ```apex public class Opportunities extends fflib_SObjects implements IOpportunities, InvoicingService.ISupportInvoicing { public void generate(InvoicingService.InvoiceFactory invoiceFactory) { for (Opportunity opp : (List) getRecords()) { InvoicingService.Invoice invoice = new InvoicingService.Invoice(); invoice.Account = opp.AccountId; invoice.Description = opp.Description; invoice.InvoiceDate = opp.CloseDate.addDays(14); // net-14 terms invoice.Lines = new List(); for (OpportunityLineItem li : opp.OpportunityLineItems) { InvoicingService.InvoiceLine line = new InvoicingService.InvoiceLine(); line.Description = li.Description; line.Product = li.PricebookEntry.Product2Id; line.UnitPrice = li.UnitPrice; line.Quantity = li.Quantity; invoice.Lines.add(line); } invoiceFactory.add(invoice); // registers Invoice__c + InvoiceLine__c with UoW } } } ``` ### Integration Test Example (Apex) ```apex @IsTest private static void testInvoicingService() { // Setup in system context fflib_ISObjectUnitOfWork uow = Application.UnitOfWork.newInstance(); Opportunity opp = new Opportunity(Name='Opp', StageName='Open', CloseDate=System.today()); uow.registerNew(opp); for (Integer i = 0; i < 5; i++) { Product2 prod = new Product2(Name='Prod ' + i); uow.registerNew(prod); PricebookEntry pbe = new PricebookEntry( UnitPrice=10, IsActive=true, UseStandardPrice=false, Pricebook2Id=Test.getStandardPricebookId()); uow.registerNew(pbe, PricebookEntry.Product2Id, prod); OpportunityLineItem oli = new OpportunityLineItem(Quantity=1, TotalPrice=10); uow.registerRelationship(oli, OpportunityLineItem.PricebookEntryId, pbe); uow.registerNew(oli, OpportunityLineItem.OpportunityId, opp); } uow.commitWork(); System.runAs(TestDataFactory.getRunAsUser()) { List invoiceIds = InvoicingService.generate(new List{ opp.Id }); System.assertEquals(1, invoiceIds.size()); } } ``` ``` -------------------------------- ### Update Opportunity Activity on Accounts Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Automatically updates the Description field on related Account records to reflect recent opportunity activity. Triggered from OpportunitiesTriggerHandler.onAfterInsert(). ```apex // --- Direct service call --- Set accountIds = new Set{ '001000000000001AAA' }; AccountsService.updateOpportunityActivity(accountIds); // Result: Account.Description = 'Last Opportunity Raised ' ``` ```apex // --- AccountsServiceImpl internals --- public void updateOpportunityActivity(Set accountIds) { fflib_ISObjectUnitOfWork uow = Application.UnitOfWork.newInstance(); IAccounts accounts = (IAccounts) Application.Domain.newInstance(accountIds); accounts.updateOpportunityActivity(); // sets Description on each record uow.registerDirty(accounts.getRecords()); uow.commitWork(); } ``` ```apex // --- Trigger handler fires the service automatically on insert --- public class OpportunitiesTriggerHandler extends fflib_SObjectDomain { public override void onAfterInsert() { Set accountIds = Opportunities.newInstance(this.records).getAccountIds(); if (!accountIds.isEmpty()) AccountsService.updateOpportunityActivity(accountIds); } } ``` -------------------------------- ### AccountsService.updateOpportunityActivity Source: https://context7.com/apex-enterprise-patterns/fflib-apex-common-samplecode/llms.txt Updates the Description field on related Account records to reflect recent opportunity activity. This is automatically triggered from OpportunitiesTriggerHandler.onAfterInsert(). ```APIDOC ## AccountsService.updateOpportunityActivity — Propagate Opportunity Activity to Accounts `AccountsService.updateOpportunityActivity(Set)` updates the `Description` field on related Account records to reflect recent opportunity activity. It is automatically triggered from `OpportunitiesTriggerHandler.onAfterInsert()` whenever new Opportunities are inserted, ensuring Account records stay current without any manual intervention. ### Method Signature `AccountsService.updateOpportunityActivity(Set accountIds)` ### Parameters * **accountIds** (Set) - A set of Account IDs to update. ### Request Example (Apex) ```apex Set accountIds = new Set{ '001000000000001AAA' }; AccountsService.updateOpportunityActivity(accountIds); // Result: Account.Description = 'Last Opportunity Raised ' ``` ### Internal Implementation (Apex) ```apex public void updateOpportunityActivity(Set accountIds) { fflib_ISObjectUnitOfWork uow = Application.UnitOfWork.newInstance(); IAccounts accounts = (IAccounts) Application.Domain.newInstance(accountIds); accounts.updateOpportunityActivity(); // sets Description on each record uow.registerDirty(accounts.getRecords()); uow.commitWork(); } ``` ### Trigger Integration (Apex) ```apex public class OpportunitiesTriggerHandler extends fflib_SObjectDomain { public override void onAfterInsert() { Set accountIds = Opportunities.newInstance(this.records).getAccountIds(); if (!accountIds.isEmpty()) AccountsService.updateOpportunityActivity(accountIds); } } ``` ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.