Skip to content

Commit

Permalink
updated rest service to get initial orders when order amendment is pa…
Browse files Browse the repository at this point in the history
…ssed in (#833)

* updated rest service to get initial orders when order amendment passed in

* update for failing test in non cpq environment

* added tracking for invalidated objects

* cop

* added test

* dont cache for accounts

* some ruby test changes

* update for order Amendment fetching per sync with brenen

Co-authored-by: Brennen Ryder <[email protected]>
  • Loading branch information
arnoldezeolisa and brennen-stripe authored Oct 10, 2022
1 parent 4009c32 commit 490651d
Show file tree
Hide file tree
Showing 7 changed files with 721 additions and 281 deletions.
22 changes: 18 additions & 4 deletions lib/stripe-force/cache_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class CacheService
def initialize(user)
@user = user
@cache = {}
@previously_invalidated = []
end

sig { params(sf_object: Restforce::SObject).void }
Expand All @@ -33,8 +34,11 @@ def cache_for_object(sf_object)
end

def invalidate_cache_object(sf_object_id)
log.info("Invalidating cached object", sf_object_id: sf_object_id)
@cache[StripeForce::Utilities::SalesforceUtil.salesforce_type_from_id(@user, sf_object_id)] ||= {}
@cache[StripeForce::Utilities::SalesforceUtil.salesforce_type_from_id(@user, sf_object_id)].delete(sf_object_id)

@previously_invalidated.append(sf_object_id)
end

# ie
Expand Down Expand Up @@ -162,7 +166,7 @@ def get_record_from_cache(sf_record_type, sf_record_id)
sf_record_id: sf_record_id,
}
message = "Missed cache for SF Object, but found when reaching out to Salesforce API"
report_missing_cache(message, metadata)
report_missing_cache(message, metadata, missing_record_ids: [sf_record_id])
@cache[sf_record_type][sf_record_id] = missed_object
end

Expand Down Expand Up @@ -209,11 +213,21 @@ def get_record_from_cache(sf_record_type, sf_record_id)
response.body
end

private def report_missing_cache(message, metadata)
private def previously_invalidated?(sf_object_ids)
sf_object_ids.each do |id|
if @previously_invalidated.include? id
return true
end
end
false
end


private def report_missing_cache(message, metadata, missing_record_ids: [])
Integrations::ErrorContext.report_edge_case(message, metadata: metadata)

# Error out in tests, provide the meatdata for alerting us to what exactly is missing.
if ENV['CI'] || Rails.env.test?
if (ENV['CI'] || Rails.env.test?) && !previously_invalidated?(missing_record_ids)
raise Integrations::Errors::TranslatorError.new(message, metadata: metadata)
end
end
Expand Down Expand Up @@ -245,7 +259,7 @@ def get_record_from_cache(sf_record_type, sf_record_id)
root_object_id: foreign_key_sf_object_id,
}
message = "Missed cache for relational objects, but found when reaching out to Salesforce API"
report_missing_cache(message, metadata)
report_missing_cache(message, metadata, missing_record_ids: record_list.map(&:Id))
end

record_list
Expand Down
9 changes: 6 additions & 3 deletions lib/stripe-force/translate/translate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,19 @@ def cache_service
def translate(sf_object)
set_error_context(user: @user, integration_record: sf_object)

# Cache Related Objects
cache_service.cache_for_object(sf_object)

catch_errors_with_salesforce_context(primary: sf_object) do
case sf_object.sobject_type
when SF_ORDER
# Cache Related Objects
cache_service.cache_for_object(sf_object)
translate_order(sf_object)
when SF_PRODUCT
# Cache Related Objects
cache_service.cache_for_object(sf_object)
translate_product(sf_object)
when SF_PRICEBOOK_ENTRY
# Cache Related Objects
cache_service.cache_for_object(sf_object)
translate_pricebook(sf_object)
when SF_ACCOUNT
translate_account(sf_object)
Expand Down
172 changes: 85 additions & 87 deletions sfdx/force-app/main/default/classes/restService.cls
Original file line number Diff line number Diff line change
Expand Up @@ -286,17 +286,17 @@ global with sharing class restService {
Set<String> listOfInitialOrderRecordAmmendedContractId = new Set<String>();
if(listOfOrderFields.contains(cpqQuoteObjectApiName)) {
Set<String> listOfAllOrderRelatedOpportunityQuoteIds = buildListOfAllOpportunityQuoteIds(listOfOrderRecordMapRecords);

String initialOrderQuery = 'SELECT ' + String.join(((Iterable<String>)listOfOrderFields), ',') + ' FROM Order WHERE SBQQ__Quote__c IN :listOfAllOrderRelatedOpportunityQuoteIds AND Id NOT IN :listOfOrderIds WITH SECURITY_ENFORCED';
List<SObject> listOfInitialOrderRecords = Database.query(initialOrderQuery);

Map<String,Object> updatedInitalOrderAndQouteListMap = addInitialOrderToPayload(listOfInitialOrderRecords, listOfOrderRecordMapRecords, listOfInitialOrderRecordQuoteId, listOfOrderIds);
listOfOrderRecordMapRecords = (Set<Map<String, Object>>)updatedInitalOrderAndQouteListMap.get('listOfOrderRecordMapRecords');
listOfInitialOrderRecordQuoteId = (Set<String>)updatedInitalOrderAndQouteListMap.get('listOfInitialOrderRecordQuoteId');
listOfOrderIds = (Set<String>)updatedInitalOrderAndQouteListMap.get('listOfOrderIds');

Set<String> listOfRelatetedContractOrderRecordIds = buildListOfRelatedContractIds(listOfOrderRecordMapRecords);
String amendedOrderQuery = 'SELECT ' + String.join(((Iterable<String>)listOfOrderFields), ',') + ' FROM Order WHERE ContractId IN :listOfRelatetedContractOrderRecordIds AND Id NOT IN :listOfOrderIds WITH SECURITY_ENFORCED';
Set<String> listOfRelatetedContractOrderRecordIds = buildListOfRelatedContractIds(listOfOrderIds, listOfOrderRecordQuoteId);

String amendedOrderQuery = 'SELECT ' + String.join(((Iterable<String>)listOfOrderFields), ',') + ' FROM Order WHERE Opportunity.SBQQ__AmendedContract__c IN :listOfRelatetedContractOrderRecordIds AND Id NOT IN :listOfOrderIds WITH SECURITY_ENFORCED';
List<SObject> listOfamendedOrderRecords = Database.query(amendedOrderQuery);

Map<String,Object> updatedAmendedOrderAndQouteListMap = addOrderAmendmentsToPayload(listOfamendedOrderRecords, listOfOrderRecordMapRecords, listOfInitialOrderRecordAmmendedContractId, listOfOrderIds);
Expand Down Expand Up @@ -326,6 +326,11 @@ global with sharing class restService {
relatedQuoteRecordIdList.add(quoteRecordMap.get('Id'));
}
}

if (relatedQuoteRecordIdList.isEmpty()) {
continue;
}

//adds list of the related quote ID to orderRecords
orderRecordMap.put('Quotes',(Object)relatedQuoteRecordIdList);
}
Expand Down Expand Up @@ -402,7 +407,6 @@ global with sharing class restService {
//get all related order items based on the orders contained in list
listOfOrderRecordMapRecords = getRelatedOrderItemRecordsById(listOfOrderRecordMapRecords,listOfOrderItemFields, listOfOrderIds, isCpqInstalled);
}

//gets related account records based on the accounts any order in our list looks up to
if(listOfOrderFields.contains('AccountId')) {
listOfOrderRecordMapRecords = addRelatedRecordToPayload(listOfOrderRecordMapRecords,'Account','AccountId');
Expand All @@ -419,7 +423,6 @@ global with sharing class restService {
if(listOfOrderFields.contains('Pricebook2Id')) {
listOfOrderRecordMapRecords = addRelatedRecordToPayload(listOfOrderRecordMapRecords,'Pricebook2','Pricebook2Id');
}


return listOfOrderRecordMapRecords;
}
Expand All @@ -430,47 +433,43 @@ global with sharing class restService {
if (orderRecordMapRecord.get('Opportunity') == null) {
return listOfAllOrderRelatedOpportunityQuoteIds;
}
Map<String,Object> relatatedOrderOppertunityMap = (Map<String,Object>)orderRecordMapRecord.get('Opportunity');

Map<String,Object> relatatedOrderOppertunityMap = (Map<String,Object>)orderRecordMapRecord.get('Opportunity');
Set<String> listOfInitialOrderIds = new Set<String>();

if (relatatedOrderOppertunityMap.get('SBQQ__AmendedContract__r') == null) {
return listOfAllOrderRelatedOpportunityQuoteIds;
}
Map<String,Object> relatatedOrderContractMap = (Map<String,Object>)relatatedOrderOppertunityMap.get('SBQQ__AmendedContract__r');

if (relatatedOrderContractMap.get('SBQQ__Quote__c') != null) {
if (relatatedOrderContractMap.get('SBQQ__Quote__c') == null) {
return listOfAllOrderRelatedOpportunityQuoteIds;
}
listOfAllOrderRelatedOpportunityQuoteIds.add(String.valueOf(relatatedOrderContractMap.get('SBQQ__Quote__c')));
}
return listOfAllOrderRelatedOpportunityQuoteIds;
}

private static Set<String> buildListOfRelatedContractIds(Set<Map<String, Object>> listOfOrderRecordMapRecords) {
private static Set<String> buildListOfRelatedContractIds(Set<String> listOfOrderIds, Set<String> listOfOrderRecordQuoteId) {
Set<String> listOfRelatetedContractOrderRecordIds = new Set<String>();
for (Map<String, Object> orderRecordMapRecord : listOfOrderRecordMapRecords) {

if (orderRecordMapRecord.get('Opportunity') == null) {
continue;
}
Map<String,Object> relatatedOrderOppertunityMap = (Map<String,Object>)orderRecordMapRecord.get('Opportunity');
String relatedContractQuery = 'SELECT ID, SBQQ__Quote__c FROM Contract WHERE SBQQ__Quote__c IN :listOfOrderRecordQuoteId AND Id NOT IN :listOfOrderIds WITH SECURITY_ENFORCED';
List<SObject> listOfAmendedOrderContractRecords = Database.query(relatedContractQuery);

if (relatatedOrderOppertunityMap.get('SBQQ__AmendedContract__r') == null) {
if (listOfAmendedOrderContractRecords.isEmpty()) {
return listOfRelatetedContractOrderRecordIds;
}
for (SObject relatedContractRecord : listOfAmendedOrderContractRecords) {
Map<String, Object> relatedContractRecordMap = (Map<String, Object>) JSON.deserializeUntyped(JSON.serialize(relatedContractRecord));
if (relatedContractRecord.get('SBQQ__Quote__c') == null) {
continue;
}
Map<String,Object> relatatedOrderAmendedContractMap = (Map<String,Object>)relatatedOrderOppertunityMap.get('SBQQ__AmendedContract__r');

if (relatatedOrderAmendedContractMap.get('Id') == null) {
continue;
}
listOfRelatetedContractOrderRecordIds.add(String.valueOf(relatatedOrderAmendedContractMap.get('Id')));

listOfRelatetedContractOrderRecordIds.add((String)relatedContractRecord.get('Id'));
}
return listOfRelatetedContractOrderRecordIds;
}

private static Map<String,Object> addInitialOrderToPayload(List<SObject> listOfInitialOrderRecords, Set<Map<String, Object>> listOfOrderRecordMapRecords, Set<String> listOfInitialOrderRecordQuoteId, Set<String> listOfOrderIds) {
if (!listOfInitialOrderRecords.isEmpty()) {
if (listOfInitialOrderRecords.isEmpty()) {
return new Map<String,Object> {
'listOfOrderRecordMapRecords' => listOfOrderRecordMapRecords,
'listOfInitialOrderRecordQuoteId' => listOfInitialOrderRecordQuoteId,
Expand Down Expand Up @@ -546,10 +545,6 @@ global with sharing class restService {
Set<String> listOfAmendedOrderRecordIds = new Set<String>();

for (SObject amendedOrderRecord : listOfamendedOrderRecords) {
if (relatatedOrderAmendedContractMap.get('Id') != string.valueOf(amendedOrderRecord.get('ContractId'))) {
continue;
}

Map<String, Object> amendedOrderRecordMap = (Map<String, Object>) JSON.deserializeUntyped(JSON.serialize(amendedOrderRecord));
listOfOrderRecordMapRecords.add(amendedOrderRecordMap);

Expand Down Expand Up @@ -761,71 +756,74 @@ global with sharing class restService {
if(orderRecord.get(LookupField) != null)listOfOrderRecordIds.add(string.valueOf(orderRecord.get(LookupField)));
}

if(!listOfOrderRecordIds.isEmpty()) {
//query list of related records based on lookup field and object api name using list of lookup Ids from list of records
String query = 'SELECT '+ String.join(((Iterable<String>)listOfObjectFields), ',') + ' FROM ' + objectApiName +' WHERE Id IN :listOfOrderRecordIds WITH SECURITY_ENFORCED';
List<SObject> listOfRelatedRecordData = Database.query(query);

if(!listOfRelatedRecordData.isEmpty()) {
return listOfOrderRecordMapRecords;
}
if(listOfOrderRecordIds.isEmpty()) {
return listOfOrderRecordMapRecords;
}

/*add each related record to the records json response and add the Id to a list
to add back to parent record map after*/
for(Map<String, Object> orderRecord : listOfOrderRecordMapRecords) {
//list to related record Ids to populate and add per order record
Set<String> listOfRelatedRecordsIds = new Set<String> ();
for(SObject relatedRecord : listOfRelatedRecordData) {
String orderRecordLookupId = (String)orderRecord.get(LookupField);
if(orderRecordLookupId == relatedRecord.get('Id')){
if(relatedRecord != null)responseJsonPayloadRecords.add((Object)relatedRecord);
listOfRelatedRecordsIds.add(string.valueOf(relatedRecord.get('Id')));
}
}
//query list of related records based on lookup field and object api name using list of lookup Ids from list of records
String query = 'SELECT '+ String.join(((Iterable<String>)listOfObjectFields), ',') + ' FROM ' + objectApiName +' WHERE Id IN :listOfOrderRecordIds WITH SECURITY_ENFORCED';
List<SObject> listOfRelatedRecordData = Database.query(query);

if(listOfRelatedRecordData.isEmpty()) {
return listOfOrderRecordMapRecords;
}

if(listOfRelatedRecordsIds.isEmpty()) {
continue;
/*add each related record to the records json response and add the Id to a list
to add back to parent record map after*/
for(Map<String, Object> orderRecord : listOfOrderRecordMapRecords) {
//list to related record Ids to populate and add per order record
Set<String> listOfRelatedRecordsIds = new Set<String> ();
for(SObject relatedRecord : listOfRelatedRecordData) {
String orderRecordLookupId = (String)orderRecord.get(LookupField);
if(orderRecordLookupId == relatedRecord.get('Id')){
Map<String, Object> relatedRecordMap = (Map<String, Object>) JSON.deserializeUntyped(JSON.serialize(relatedRecord));
responseJsonPayloadRecords.add((Object)relatedRecord);
listOfRelatedRecordsIds.add(string.valueOf(relatedRecord.get('Id')));
}
}

/* before adding list of related record Ids to the parent
record switch the objectApiName to the plural object name */
switch on objectApiName {
when 'Pricebook2' {
objectApiName = 'PriceBooks';
}
when 'Account' {
objectApiName = 'Accounts';
}
when 'Opportunity' {
objectApiName = 'Opportunities';
}
when 'Product2' {
objectApiName = 'Products';
}
when 'PricebookEntry' {
objectApiName = 'PricebookEntries';
}
when 'Subscription' {
objectApiName = 'Subscriptions';
}
when 'Contract' {
objectApiName = 'Contracts';
}
when 'Contact' {
objectApiName = 'Contacts';
}
when 'OrderItem' {
objectApiName = 'OrderItems';
}
}
if(listOfRelatedRecordsIds.isEmpty()) {
continue;
}

//add list of child ids to parent record if it is not a direct lookup relationship
Object value = orderRecord.get(objectApiName);
if(value == null) {
orderRecord.put(objectApiName,(Object)listOfRelatedRecordsIds);
/* before adding list of related record Ids to the parent
record switch the objectApiName to the plural object name */
switch on objectApiName {
when 'Pricebook2' {
objectApiName = 'PriceBooks';
}
}
}
when 'Account' {
objectApiName = 'Accounts';
}
when 'Opportunity' {
objectApiName = 'Opportunities';
}
when 'Product2' {
objectApiName = 'Products';
}
when 'PricebookEntry' {
objectApiName = 'PricebookEntries';
}
when 'Subscription' {
objectApiName = 'Subscriptions';
}
when 'Contract' {
objectApiName = 'Contracts';
}
when 'Contact' {
objectApiName = 'Contacts';
}
when 'OrderItem' {
objectApiName = 'OrderItems';
}
}

//add list of child ids to parent record if it is not a direct lookup relationship
Object value = orderRecord.get(objectApiName);
if(value == null) {
orderRecord.put(objectApiName,(Object)listOfRelatedRecordsIds);
}
}
return listOfOrderRecordMapRecords;
}

Expand Down
Loading

0 comments on commit 490651d

Please sign in to comment.