Advertisement
Guest User

Untitled

a guest
Jun 25th, 2019
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.30 KB | None | 0 0
  1. /**
  2. * @author vladimir.romanov
  3. * @description Apex class to illustrate the Clean Code Principles:
  4. * Boy Scout Rule,
  5. * Meaningful naming,
  6. * Using constants instead of hardcoded values,
  7. * Small functions.
  8. *
  9. * The class contains update trigger logic that filters quotes and inserts new QuoteFollowUp__c records
  10. *
  11. * createFollowUps(): public static method that creates an instance of an inner class and launches the logic.
  12. *
  13. * FollowUpCreator: inner class to encapsulate processing details
  14. * FollowUpCreator.createFollowUps(): private instance method that contains the processing logic
  15. *
  16. * Working with an instance of a class instead of a static function gives us
  17. * possibility to reuse instance variables
  18. * instead of passing them every time from one function to another
  19. * thus reducing number of arguments of the functions.
  20. */
  21. public class QuoteFollowUpCreator
  22. {
  23. // CONSTANTS
  24.  
  25. // if tomorrow there will be one more condition for Request__c query the only thing to update is this constant!
  26. // Test classes reference this constant!
  27. @TestVisible
  28. private static final Set<String> REQUEST_CONDITIONS = new Set<String>
  29. {
  30. 'Condition1',
  31. 'Condition2'
  32. };
  33.  
  34. // set up a 120 ruler in your IDE and split longer lines
  35. // to make sure one function is entirely in your field of vision
  36. private static final Id RECORDTYPEID_MY_REQUEST = [SELECT Id FROM RecordType WHERE SobjectType = 'Request__c'
  37. AND DeveloperName = 'MyRequest'].Id;
  38.  
  39. // PUBLIC METHOD
  40.  
  41. public static void createFollowUps(Map<Id, Quote> newQuoteById, Map<Id, Quote> oldQuoteById)
  42. {
  43. FollowUpCreator followUpCreator = new FollowUpCreator(newQuoteById, oldQuoteById);
  44. followUpCreator.createFollowUps();
  45. }
  46.  
  47. // PRIVATE INNER CLASS (encapsulating processing details)
  48.  
  49. private class FollowUpCreator
  50. {
  51. private Map<Id, Quote> quoteToProcessById = new Map<Id, Quote>();
  52.  
  53. public FollowUpCreator(Map<Id, Quote> newQuoteById, Map<Id, Quote> oldQuoteById)
  54. {
  55. this.quoteToProcessById = getQuotesToProcessByIdsMap(newQuoteById, oldQuoteById);
  56. }
  57.  
  58. // In the high level functions we write a human-readable story about what the code is doing!
  59. // We delegate details to the lower-levels functions!
  60. public void createFollowUps()
  61. {
  62. if (quoteToProcessById.isEmpty())
  63. return;
  64. List<Request__c> requests = retrieveRequests();
  65. Map<Id, Request__c> requestByQuoteId = getRequestByQuoteIdMap(requests);
  66. List<QuoteFollowUp__c> quoteFollowUps = getFollowUps(requestByQuoteId);
  67. if (!quoteFollowUps.isEmpty())
  68. insert quoteFollowUps;
  69.  
  70. // Include name of the class, name of the function and name of the variable in the debug message.
  71. // this helps to know the origin of a message in debug log
  72. // You can develop a custom Logger class to avoid hardcoding the class name every time.
  73. System.debug('QuoteFollowUpCreator.FollowUpCreator::createFollowUps()::quoteFollowUps: '
  74. + JSON.serialize(quoteFollowUps));
  75. }
  76.  
  77. private Map<Id, Quote> getQuotesToProcessByIdsMap(Map<Id, Quote> newQuoteById, Map<Id, Quote> oldQuoteById)
  78. {
  79. Map<Id, Quote> quoteToProcessById = new Map<Id, Quote>();
  80. for (Quote newQuote: newQuoteById.values())
  81. {
  82. Quote oldQuote = oldQuoteById.get(newQuote.Id);
  83. if (isFollowUpNeeded(newQuote, oldQuote))
  84. quoteToProcessById.put(newQuote.Id, newQuote);
  85. }
  86. return quoteToProcessById;
  87. }
  88.  
  89. // Encapsulate logical condition into a small function that provides additional information
  90. // about the intention of the condition in the function name
  91. private Boolean isFollowUpNeeded(Quote newQuote, Quote oldQuote)
  92. {
  93. if (newQuote.Is_Acquired__c != true)
  94. return false;
  95. if (oldQuote.Acquired_Date__c == null && newQuote.Acquired_Date__c != null)
  96. return false; // the accuired date is set for the first time - old date null new not null
  97. return true;
  98. }
  99.  
  100. private Map<Id, Request__c> getRequestByQuoteIdMap(List<Request__c> requests)
  101. {
  102. Map<Id, Request__c> requestByQuoteId = new Map<Id, Request__c>();
  103.  
  104. Map<Id, List<Request__c>> requestsByAccountId = getRequestsByAccountIdMap(requests);
  105. requestByQuoteId = getRequestByQuoteIdMapFromRequestsByAccountId(requestsByAccountId);
  106.  
  107. return requestByQuoteId;
  108. }
  109.  
  110. // SOQL query is encapsulated to a small function for better readability and maintainability
  111. private List<Request__c> retrieveRequests()
  112. {
  113. Date earliestOrderDate;
  114. Set<Id> accountIds = new Set<Id>();
  115.  
  116. for (Quote quoteRecord: quoteToProcessById.values())
  117. {
  118. if (earliestOrderDate == null
  119. || quoteRecord.Acquired_Date__c < earliestOrderDate)
  120. earliestOrderDate = quoteRecord.Acquired_Date__c;
  121. accountIds.add(quoteRecord.Account__c);
  122. }
  123.  
  124. System.debug('QuoteFollowUpCreator.FollowUpCreator::retrieveRequests()::earliestOrderDate: ' + earliestOrderDate);
  125. System.debug('QuoteFollowUpCreator.FollowUpCreator::retrieveRequests()::accountIds: ' + accountIds);
  126.  
  127. return
  128. [
  129. SELECT
  130. Id,
  131. Account__c,
  132. Account__r.Name,
  133. ExecutionDate__c,
  134. ExpirationDate__c
  135. FROM Request__c
  136. WHERE Condition__c IN :REQUEST_CONDITIONS
  137. AND ExecutionDate__c <= :earliestOrderDate
  138. AND RecordTypeId != :RECORDTYPEID_MY_REQUEST
  139. AND Account__c IN :accountIds
  140. ORDER BY ExecutionDate__c ASC
  141. ];
  142. }
  143.  
  144. private Map<Id, List<Request__c>> getRequestsByAccountIdMap(List<Request__c> requests)
  145. {
  146. Map<Id, List<Request__c>> requestsByAccountId = new Map<Id, List<Request__c>>();
  147. for (Request__c request: requests)
  148. {
  149. List<Request__c> accountScoringRequests = requestsByAccountId.get(request.Account__c);
  150. if (accountScoringRequests != null)
  151. accountScoringRequests.add(request);
  152. else
  153. requestsByAccountId.put(request.Account__c, new List<Request__c> {request});
  154. }
  155.  
  156. return requestsByAccountId;
  157. }
  158.  
  159. private Map<Id, Request__c> getRequestByQuoteIdMapFromRequestsByAccountId(Map<Id, List<Request__c>> requestsByAccountId)
  160. {
  161. Map<Id, Request__c> requestByQuoteId = new Map<Id, Request__c>();
  162. for (Quote quoteRecord: quoteToProcessById.values())
  163. {
  164. List<Request__c> accountScoringRequests = requestsByAccountId.get(quoteRecord.Account__c);
  165. if (accountScoringRequests == null)
  166. continue; // using the 'continue;' statement to avoid adding unnecessary indentation layer
  167. for (Request__c request: accountScoringRequests)
  168. {
  169. //there should be just one request for each quote, here we'll just take the last one in the list
  170. if (request.ExpirationDate__c >= quoteRecord.Acquired_Date__c)
  171. requestByQuoteId.put(quoteRecord.Id, request);
  172. }
  173. }
  174. return requestByQuoteId;
  175. }
  176.  
  177. private void getFollowUps()
  178. {
  179. List<QuoteFollowUp__c> quoteFollowUps = new List<QuoteFollowUp__c>();
  180. for (Quote quoteRecord: quoteToProcessById.values())
  181. {
  182. Request__c request = requestByQuoteId.get(quoteRecord.Id);
  183. if (request != null)
  184. quoteFollowUps.add(getNewFollowUp(quoteRecord, request));
  185. }
  186. return quoteFollowUps;
  187. }
  188.  
  189. // this function constructs new records to insert, it is doing only one thing, and can be easily reused!
  190. private QuoteFollowUp__c getNewFollowUp(Quote quoteRecord, Request__c request)
  191. {
  192. QuoteFollowUp__c followUp = new QuoteFollowUp__c();
  193. followUp.Quote__c = quoteRecord.Id;
  194. followUp.Request__c = request.Id;
  195. followUp.Total_Investment__c = quoteRecord.Total_Investment__c;
  196. return followUp;
  197. }
  198. }
  199.  
  200. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement