Class Name: DisablePlaceOrder¶
Last Updated: 2025-10-22 Source Code: https://github.com/AANP-IT/I2C.Salesforce.Metadata/blob/STAGING/force-app/main/default/classes/DisablePlaceOrder.cls
API Name: DisablePlaceOrder Type: Lightning Component Controller (AuraEnabled) Test Coverage: DisablePlaceOrderTest.cls Author: Unknown Created: Unknown
Business Purpose¶
This class implements a critical membership-first business rule that prevents non-members from purchasing community access products without first obtaining membership. It enforces AANP's business model by checking whether users attempting to purchase community products are either existing members or have membership products in their current cart. This ensures proper revenue flow, maintains membership requirements, and prevents invalid purchase combinations that would violate business rules.
Class Overview¶
Scope and Sharing¶
- Sharing Model: with sharing (respects record-level security)
- Access Modifier: public
- Interfaces Implemented: None
Key Responsibilities¶
- Validate user has contact association
- Check account membership status
- Analyze cart contents for community products
- Detect membership products in cart
- Enforce membership-first purchase rule
- Return boolean to control Place Order button enablement
- Support cacheable Lightning component integration
Public Methods¶
getWebCart¶
Purpose: Determines whether the Place Order button should be disabled for a user attempting to purchase community products without proper membership. Returns true to disable (prevent order), false to allow order.
Parameters:
- userId (Id): Salesforce User ID to check
- refreshKey (Integer): Cache-busting parameter to force re-evaluation (not used in logic)
Returns:
- Boolean:
- true = Disable Place Order (non-member buying community without membership in cart)
- false = Allow Place Order (member, no community products, or has membership in cart)
Throws: - QueryException: If any SOQL queries fail (not handled) - NullPointerException: If account query returns no results (not handled)
Usage Example:
// Called from Lightning Web Component
import getWebCart from '@salesforce/apex/DisablePlaceOrder.getWebCart';
// In LWC JavaScript
getWebCart({ userId: this.userId, refreshKey: Date.now() })
.then(result => {
this.disablePlaceOrder = result;
})
.catch(error => {
console.error('Error:', error);
});
Business Logic:
- Query User Contact:
- Gets user's associated contact ID
-
LIMIT 1 for governor limit safety
-
Validate ContactId:
-
If no contact, allow order (permissive fallback)
-
Query Account by PersonContactId:
- Finds person account via contact
-
Gets membership status
-
Query WebCarts with Community Products:
- Finds checkout carts containing community products
-
Uses subquery for efficient filtering
-
Query WebCarts with Membership Products:
-
Checks if cart contains membership products
-
Apply Business Rule:
- Returns TRUE (disable order) when ALL conditions met:
- Cart contains community products (webCarts not empty)
- Account is not a member (Is_Member__c = false)
- Cart does NOT contain membership products (webCartsWithMembershipCartItem empty)
- Otherwise returns FALSE (allow order)
Business Rule Truth Table: | Has Community Products | Is Member | Has Membership in Cart | Result | Meaning | |------------------------|-----------|------------------------|--------|---------| | Yes | No | No | TRUE | Disable - Must add membership | | Yes | No | Yes | FALSE | Allow - Membership in cart | | Yes | Yes | No | FALSE | Allow - Already member | | Yes | Yes | Yes | FALSE | Allow - Member buying more | | No | No | No | FALSE | Allow - No community products | | No | Yes | No | FALSE | Allow - Member buying other products |
Private/Helper Methods¶
None - All logic in single method. Could benefit from extraction:
- getUserContact(userId)
- getAccountByContact(contactId)
- hasProductFamily(accountId, productFamily)
- shouldDisablePlaceOrder(hasC ommunity, isMember, hasMembership)
Dependencies¶
Apex Classes¶
- None - Standalone controller
Salesforce Objects¶
User (Standard) - Fields accessed: Id, ContactId - Purpose: Link user to contact
Account (Standard - Person Account) - Fields accessed: Id, Is_Member__c, PersonContactId - Purpose: Check membership status
WebCart (Commerce Cloud) - Fields accessed: Id, AccountId, Status - Purpose: Identify checkout carts
CartItem (Commerce Cloud) - Fields accessed: CartId, product2.Family - Purpose: Identify products in cart
Product2 (Standard) - Fields accessed: Family (via relationship) - Product Families used: - 'Communities': Community access products - 'Membership': Membership products
Custom Settings/Metadata¶
- None identified - Consider adding:
- Cart_Business_Rules__mdt: Configurable product families and rules
- Membership_Settings__mdt: Enable/disable rule enforcement
External Services¶
- None - Pure internal Salesforce processing
Design Patterns¶
- Controller Pattern: AuraEnabled for Lightning component integration
- Business Rule Pattern: Encapsulates complex business logic
- Query Pattern: Multiple queries to gather decision data
- Guard Clause Pattern: Early return for null contact
Why These Patterns: - Controller pattern enables LWC integration - Business rule pattern centralizes membership validation - Query pattern gathers all necessary data - Guard clause handles edge cases early
Governor Limits Considerations¶
SOQL Queries: 3 (User, Account, 2x WebCart queries) DML Operations: 0 (read-only) CPU Time: Low (simple logic) Heap Size: Low (small result sets)
Bulkification: N/A (single user per call) Async Processing: No (synchronous)
Governor Limit Risks: - LOW: 3 SOQL queries well within 100 limit - LOW: No DML operations - MEDIUM: Subqueries in WebCart queries could be optimized - LOW: Cacheable attribute helps reduce repeated calls
Performance Considerations: - Called on every cart page refresh/update - Cacheable reduces server load but may show stale data - refreshKey parameter suggests need for cache busting - Could combine WebCart queries into single query with OR condition
Recommendations: - Combine WebCart queries into one with OR logic - Add query result caching if called frequently - Monitor query performance with cart analytics
Error Handling¶
Strategy: No explicit error handling - relies on system exceptions
Logging: - None - No logging of rule enforcement - No tracking of disabled orders - No business analytics on rule triggers
User Notifications: - None from this class - UI must handle - No error messages to explain why order disabled - No guidance on how to fix (add membership)
Null Handling: - Returns false if ContactId null (permissive) - No null check for account (could throw exception) - Assumes WebCart queries always safe
Recommended Improvements: - Add try-catch around queries - Log when orders are disabled for analytics - Return structured data with reason for disability - Add null check for account query - Provide user-friendly error message
Security Considerations¶
Sharing Rules: RESPECTED - Uses 'with sharing' - User can only check their own cart - Record-level security enforced - Appropriate for user-facing function
Field-Level Security: RESPECTED - FLS enforced on all queries - User must have read access to all queried fields
CRUD Permissions: RESPECTED - User must have read permission on objects - Appropriate for business rule checking
Input Validation: MINIMAL - Validates ContactId not null - No validation of userId parameter - Assumes userId is current user
Security Risks: - LOW: with sharing appropriate - LOW: Read-only queries - MEDIUM: Could check any user's cart if userId manipulated (validate userId = UserInfo.getUserId())
Business Impact: - Prevents invalid purchases - Enforces membership revenue model - Could impact conversion if too restrictive
Mitigation Recommendations: 1. Validate userId matches current user 2. Add audit logging for compliance 3. Monitor for circumvention attempts 4. Regular review of business rule effectiveness
Test Class¶
Test Class: DisablePlaceOrderTest.cls Coverage: To be determined
Test Scenarios That Should Be Covered: - ✓ Non-member with community products (no membership in cart) = true - ✓ Non-member with community products (with membership in cart) = false - ✓ Member with community products = false - ✓ Non-member without community products = false - ✓ User with null ContactId = false - ✓ Account not found for contact (error handling) - ✓ Multiple WebCarts in Checkout status - ✓ WebCart with mixed product families - ✓ WebCart in non-Checkout status (should not affect result) - ✓ Different product families - ✓ Cacheable behavior (same result on repeat calls)
Testing Challenges: - Must create Person Accounts (special setup) - Requires Commerce Cloud test data (WebCart, CartItem) - Product2 Family values must be configured - Is_Member__c custom field must exist - Cacheable testing requires multiple calls
Test Data Requirements: - User records with ContactId - Person Account records with Is_Member__c - Product2 records with Family = 'Communities' and 'Membership' - WebCart records in 'Checkout' status - CartItem records linking to products
Changes & History¶
- Created: Unknown (check git history)
- Author: Unknown (check git annotations)
- Purpose: Enforce membership-first business rule
- Related to: Commerce Cloud checkout implementation
⚠️ Pre-Go-Live Concerns¶
CRITICAL - Fix Before Go-Live¶
- No Error Handling on Queries: Three queries without try-catch - will break UI with cryptic errors if queries fail.
- No Account Null Check: Account query assumed to return result - will throw NullPointerException if account not found for contact.
- User ID Validation Missing: No check that userId parameter matches current user - security risk if manipulated.
- Hardcoded Product Families: 'Communities' and 'Membership' hardcoded - breaks if product structure changes.
HIGH - Address Soon After Go-Live¶
- No User Feedback: Users see disabled button with no explanation of why or how to fix.
- Performance: Three separate queries could be optimized to one or two.
- No Logging: No analytics on how often rule triggers - can't measure business impact.
- Cache Staleness: Cacheable attribute may show stale data if cart changes - refreshKey not actually used in logic.
MEDIUM - Future Enhancement¶
- Membership Expiration: Only checks Is_Member__c flag - doesn't validate membership is current/not expired.
- Partial Implementation: Method name 'getWebCart' doesn't describe what it returns.
- Limited Product Logic: Only handles Communities and Membership families - what about other restricted products?
- No Configuration: Business rules hardcoded - requires code deployment to change.
LOW - Monitor¶
- RefreshKey Parameter: Declared but never used in logic - implement or remove.
- Method Naming: 'getWebCart' misleading - actually returns boolean for place order enablement.
- Code Organization: Could extract helper methods for better readability.
- Return Value Documentation: Boolean return meaning not obvious from method name.
Maintenance Notes¶
Complexity: Medium (multiple queries + business logic) Recommended Review Schedule: Quarterly (business rule changes)
Key Maintainer Notes:
🛒 BUSINESS CRITICALITY: - This class enforces CORE membership business model - Failures could allow invalid purchases or block valid ones - Directly impacts conversion rate and revenue - Changes require business stakeholder approval - Test extensively before deployment
📋 Usage Patterns: - Called from LWC on cart/checkout pages - Runs on every page load/refresh - Cacheable reduces load but may be stale - Critical path for checkout flow
🧪 Testing Requirements: - Test all combinations in truth table - Test with person accounts and business accounts - Test edge cases (no contact, no account) - Test with multiple products in cart - Test performance with large carts - Verify membership flag accuracy
🔧 Product Configuration: - CRITICAL: Product2.Family must be set correctly - 'Communities' for community access - 'Membership' for membership products - CRITICAL: Account.Is_Member__c must be maintained accurately - Misconfigurations break business rule
⚠️ Gotchas and Warnings: - Only checks Is_Member__c flag - doesn't validate membership dates - Cacheable may show stale data after cart changes - Returns false (allow) if ContactId null - permissive fallback - Product Family values are case-sensitive - Only checks WebCarts in 'Checkout' status - Could have multiple WebCarts per account
📅 When to Review This Class: - When membership rules change - When adding new product types - If conversion rate drops unexpectedly - During Commerce Cloud upgrades - When membership flag logic changes - If customer complaints about blocked checkout
🛑 Emergency Deactivation:
// Add at start of method:
Commerce_Settings__mdt settings = Commerce_Settings__mdt.getInstance('PlaceOrderRules');
if (settings != null && !settings.Enforce_Membership_Rule__c) {
return false; // Always allow orders
}
🔍 Debugging Tips: - Enable debug logs for user - Check User.ContactId populated - Verify Account.Is_Member__c value - Query WebCarts directly to see what's in Checkout status - Check Product2.Family values on cart items - Test with different user/account combinations
📊 Monitoring Checklist: - Daily: How often rule triggers (disabled orders) - Weekly: Conversion impact (disabled vs completed orders) - Monthly: Membership attachment rate for community purchases - Monitor: False positives (valid orders disabled) - Alert: Spike in disabled orders (potential bug)
🔗 Related Components: - LWC Place Order Button: Consumes this method - WebCart/CartItem: Data source - Product2: Family configuration - Account: Membership status - Membership management system: Maintains Is_Member__c
Business Owner¶
Primary: Membership Operations / Business Rules Team Secondary: E-Commerce / Product Management Stakeholders: Finance, Marketing, Customer Service, Development Team