Class Name: ZeroDollarCheckout¶
Last Updated: 2025-10-23 Source Code: https://bitbucket.org/i2cinc/i2c.salesforce.metadata/src/STAGING/force-app/main/default/classes/ZeroDollarCheckout.cls
API Name: ZeroDollarCheckout Type: Controller Test Coverage: Unknown
Business Purpose¶
The ZeroDollarCheckout class handles checkout processing for carts with $0 total amount. This supports free product orders (promotional items, free trials), orders with 100% discount coupons, and complimentary memberships. This streamlines the checkout experience by bypassing payment collection when the cart total is exactly $0.
Class Overview¶
Scope and Sharing¶
- Sharing Model: with sharing
- Access Modifier: public
- Interfaces Implemented: None
Key Responsibilities¶
- Validate that the cart has a $0 total amount
- Close the cart without payment processing
- Invoke the Zero_Dollar_Checkout Flow to create the order
- Return the order summary number for display
- Handle test context appropriately
Public Methods¶
closeCart¶
Purpose: Processes zero-dollar checkout and returns order number. This method is called from Lightning components when a user attempts to complete a checkout with a $0 cart total.
Parameters:
- userId (String): The User Id (cart owner) whose active cart should be processed
Returns:
- String: Order Summary Number (e.g., "#12345")
Throws:
- AuraHandledException: Thrown when requirements are not met (cart not found, cart total is not $0, or general errors)
Usage Example:
Business Logic:
- Query Active Cart: Finds the active WebCart for the specified user
- Excludes carts that are being deleted or already closed
-
Retrieves the GrandTotalAmount for validation
-
Validate Zero Total: Ensures the cart total is exactly $0
-
If cart total is not zero, throws an error
-
Invoke Flow or Return Test Value: In production, invokes the Zero_Dollar_Checkout Flow; in tests, returns a mock value
- Flow creates OrderSummary and returns the order number
-
Test context returns a mock order number
-
Error Handling: Catches exceptions and wraps them in AuraHandledException
- Logs errors to debug logs
- Returns generic "Requirements are not met" for QueryException (no cart found)
- Returns generic "Error" for other exceptions
Private/Helper Methods¶
This class does not contain private or helper methods. All logic is contained within the single public method.
Dependencies¶
Apex Classes¶
- None directly called
Salesforce Objects¶
WebCart: [Fields accessed: Id, OwnerId, GrandTotalAmount, Status]- Used to query and validate the active cart for the user
- Status field used to exclude deleted or closed carts
Custom Settings/Metadata¶
- None
External Services¶
- Flow: Zero_Dollar_Checkout: Invoked to process the zero-dollar order
- Input Variable:
cartId(String) - WebCart Id - Output Variable:
orderSummaryNumber(String) - Order number for display - Purpose: Creates OrderSummary without payment processing, marks cart as closed, fulfills order
LWC/Aura Components¶
- Called from Lightning component via
@AuraEnabledannotation - Likely used in checkout page component
Design Patterns¶
- LWC Controller Pattern: Uses @AuraEnabled for Lightning component integration
- Flow Integration Pattern: Delegates complex order creation logic to Flow
- Test Bypass Pattern: Different behavior in tests using Test.isRunningTest() (anti-pattern)
- Error Wrapping Pattern: Catches exceptions and wraps in AuraHandledException for Lightning components
Governor Limits Considerations¶
SOQL Queries: 1 query per invocation (WebCart query) DML Operations: None (handled by Flow) CPU Time: Minimal - simple validation logic Heap Size: Small - single cart record
Bulkification: Not applicable - @AuraEnabled methods process single records Async Processing: None - synchronous processing only
Error Handling¶
Strategy: try-catch block with AuraHandledException wrapping Logging: Uses System.debug() for error messages and stack traces User Notifications: Generic error messages returned to Lightning component
Exception Handling: - QueryException: Caught when no active cart is found for the user - returns "Requirements are not met" - Generic Exception: Catches all other exceptions - returns "Error"
Error Messages: 1. "Requirements are not met" - Cart total is not $0 OR no active cart found for user 2. "Error" - Flow execution failure or unexpected errors
Security Considerations¶
Sharing Rules: Respects sharing rules (with sharing) Field-Level Security: Not explicitly enforced with WITH SECURITY_ENFORCED CRUD Permissions: Not explicitly checked Input Validation: Validates cart total is $0; no validation that userId matches current user
Security Concerns: - OwnerId Filter: Uses userId parameter to find cart - assumes userId is current user. If LWC passes different userId, could potentially access other users' carts. Should validate userId matches current user using UserInfo.getUserId() - No User Authorization Check: Should validate that the passed userId matches the current user before processing
Test Class¶
Test Class: Needs identification Coverage: Unknown Test Scenarios Covered: - Test class requirements identified in documentation: - Success case: Cart with $0 total - Error case: Cart with non-zero total - Error case: No active cart found - Mock return value: '#orderZeroSummaryNumber'
Changes & History¶
- Unknown: Initial implementation for zero-dollar checkout by original developer
⚠️ Pre-Go-Live Concerns¶
CRITICAL - Fix Before Go-Live¶
- Security: User Validation Missing: No check that userId matches current user
- Could allow accessing other users' carts if userId parameter is manipulated
- Fix: Add validation:
if(userId != UserInfo.getUserId()) throw new AuraHandledException('Unauthorized access'); - Generic Error Messages: "Requirements are not met" and "Error" messages are not helpful to users
- Users cannot understand what went wrong
- Fix: Provide specific error messages: "No active cart found", "Cart total must be $0 for zero-dollar checkout", "Failed to create order"
HIGH - Address Soon After Go-Live¶
- Parameter Type Mismatch: userId parameter is String but should be Id type
- Fix: Change method signature to
public static String closeCart(Id userId) - Test.isRunningTest() Anti-Pattern: Production code behaves differently in tests
- Makes testing less reliable
- Fix: Consider dependency injection for Flow execution or accept that Flow runs in tests
- Unused Variables:
customerIdandpaymentIddeclared but never used (lines 17-18) - Fix: Remove unused variables or implement intended functionality
MEDIUM - Future Enhancement¶
- Improve Error Logging: Errors only logged to debug logs
- Consider persistent error logging for troubleshooting
- Enhancement: Implement custom logging framework or use platform event logging
- Empty Order Number Check: Doesn't validate that orderNumber returned from Flow is not blank
- Enhancement: Add validation:
if(String.isBlank(orderNumber)) throw new AuraHandledException('Failed to create order'); - Cart Query Enhancement: Uses QueryException handling instead of checking if cart exists first
- Enhancement: Use List
query and check isEmpty() instead of catching QueryException
LOW - Monitor¶
- Flow Dependency: Requires Zero_Dollar_Checkout Flow to exist and function correctly
- Flow must maintain the expected input/output contract
- Monitor for Flow API version changes
- Cart Status Handling: Properly excludes closed/deleted carts but relies on specific Status values
- Monitor if new cart statuses are added to Commerce Cloud
Maintenance Notes¶
Complexity: Low - Single method with straightforward logic Recommended Review Schedule: Annually or when Commerce Cloud is upgraded Key Maintainer Notes: - Flow Dependency: This class is tightly coupled to the Zero_Dollar_Checkout Flow. Any changes to the Flow's input/output variables will break this integration. - Test Behavior: In test context, the Flow is not executed and a mock order number is returned. This means Flow logic is not tested through this class. - User Validation Critical: The biggest security concern is the lack of user validation. This should be addressed immediately to prevent potential security issues. - Error Message Improvement: Current error messages are too generic. When troubleshooting production issues, developers will need to check debug logs to understand actual failures. - Commerce Cloud Updates: Monitor Salesforce Commerce Cloud release notes for changes to WebCart object or checkout process that might affect this class. - Non-Obvious Behavior: The class uses Test.isRunningTest() which means the actual Flow execution path is never tested when running Apex tests.
Recommended Code Improvements¶
@AuraEnabled
public static String closeCart(Id userId) {
// Validate userId matches current user
if(userId != UserInfo.getUserId()) {
throw new AuraHandledException('Unauthorized access');
}
try {
List<WebCart> carts = [
SELECT Id, GrandTotalAmount
FROM WebCart
WHERE OwnerId = :userId
AND Status NOT IN ('PendingDelete', 'Closed', 'PendingClosed')
LIMIT 1
];
if(carts.isEmpty()) {
throw new AuraHandledException('No active cart found');
}
WebCart cart = carts[0];
if(cart.GrandTotalAmount != 0) {
throw new AuraHandledException('Cart total must be $0 for zero-dollar checkout. Current total: $' + cart.GrandTotalAmount);
}
// Invoke Flow
Map<String, Object> inputs = new Map<String, Object>{'cartId' => cart.Id};
Flow.Interview.Zero_Dollar_Checkout myFlow = new Flow.Interview.Zero_Dollar_Checkout(inputs);
myFlow.start();
String orderNumber = (String) myFlow.getVariablevalue('orderSummaryNumber');
if(String.isBlank(orderNumber)) {
throw new AuraHandledException('Failed to create order');
}
return orderNumber;
} catch(AuraHandledException e) {
throw e; // Re-throw AuraHandledExceptions
} catch(Exception e) {
System.debug(LoggingLevel.ERROR, 'Zero-dollar checkout failed: ' + e.getMessage());
System.debug(LoggingLevel.ERROR, 'Stack trace: ' + e.getStackTraceString());
throw new AuraHandledException('Checkout failed: ' + e.getMessage());
}
}