Skip to content

Commit

Permalink
Merge pull request #152 from jbachelet/fix/issue-134
Browse files Browse the repository at this point in the history
Fixing issue-134 and revamping how Core is getting customer promotions to actually get the promotions from when the customer is authenticated and not as a guest customer
  • Loading branch information
jbachelet authored Mar 30, 2022
2 parents 30798ab + 73b8bf9 commit c259be2
Show file tree
Hide file tree
Showing 18 changed files with 756 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function afterPATCH(customer, customerRegistration) {
* @returns {Status} Returns the status for the OCAPI request
*/
// eslint-disable-next-line no-unused-vars
function modifyPOSTResponse(customer, customerResponse) {
function modifyGETResponse(customer, customerResponse) {
if (!Site.getCurrent().getCustomPreferenceValue('b2ccrm_syncEnhanceOCAPICustomerResponse')) {
return new Status(Status.OK);
}
Expand All @@ -85,4 +85,4 @@ function modifyPOSTResponse(customer, customerResponse) {

module.exports.afterPOST = afterPOST;
module.exports.afterPATCH = afterPATCH;
module.exports.modifyPOSTResponse = modifyPOSTResponse;
module.exports.modifyGETResponse = modifyGETResponse;
2 changes: 1 addition & 1 deletion src/sfcc/cartridges/int_b2ccrmsync/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"script": "./cartridge/scripts/b2ccrmsync/hooks/ocapi/shop.customer"
},
{
"name": "dw.ocapi.shop.customer.auth.modifyPOSTResponse",
"name": "dw.ocapi.shop.customer.modifyGETResponse",
"script": "./cartridge/scripts/b2ccrmsync/hooks/ocapi/shop.customer"
},
{
Expand Down
5 changes: 2 additions & 3 deletions src/sfdc/base/main/default/classes/B2CHttpRequestHelper.cls
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,17 @@ public with sharing class B2CHttpRequestHelper {
* @param customerId {String} Represents the B2C ClientID used to drive this request
* @param clientId {String} Represents the customerId of the customer being authenticated
* @param accessToken {String} Represents the B2C Commerce authToken used for this request
* @param expandParameter {String} Represents the value of the "custom_expand" GET parameter that the B2C cartridge is using to enhance the API response
* @return HttpRequest Returns an http-object pre-configured shop-api site retrieval request
* */
public static HttpRequest getCustomerAuthRequest(
String apiUrl, String siteId, String apiVersion, String customerId, String clientId, String accessToken, String expandParameter
String apiUrl, String siteId, String apiVersion, String customerId, String clientId, String accessToken
) {
return getOCAPIShopAPIHttpRequest(
apiUrl,
siteId,
accessToken,
clientId,
'/customers/' + customerId + '/auth' + (String.isEmpty(expandParameter) ? '' : '?custom_expand=' + expandParameter),
'/customers/' + customerId + '/auth',
apiVersion,
'post',
'{"type" : "credentials"}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public with sharing class B2CIAAuthCustomerClientCredentialsGrant {

// Initialize the authentication request
HttpRequest req = B2CHttpRequestHelper.getCustomerAuthRequest(
b2creq.domain, b2creq.siteId, b2creq.version, b2creq.customerId, b2creq.clientId, b2creq.token, b2creq.expandParameter
b2creq.domain, b2creq.siteId, b2creq.version, b2creq.customerId, b2creq.clientId, b2creq.token
);

// Initialize the http-handler
Expand All @@ -55,7 +55,6 @@ public with sharing class B2CIAAuthCustomerClientCredentialsGrant {

// Check if the statusCode is found in the response and the response was processed successfully
if (accessTokenResult.statusCode == 200) {

// Seed the response object with the access token details
accessTokenResult.accessToken = res.getHeader('authorization');

Expand All @@ -68,22 +67,10 @@ public with sharing class B2CIAAuthCustomerClientCredentialsGrant {
accessTokenResult.accessToken = accessTokenResult.accessToken.replace('Bearer ', '');
accessTokenResult.tokenType = 'Bearer';
}

if (String.isNotEmpty(b2creq.expandParameter)) {
JSONParse responseParsedJSON = new JSONParse(res.getBody());
accessTokenResult.promotionIds = new List<String>();
List<JSONParse> promotionsList = responseParsedJSON.get('c_active_promotions').asList();
for (JsonParse promotionItem : promotionsList) {
accessTokenResult.promotionIds.add(promotionItem.getStringValue());
}
accessTokenResult.totalPromotionsSize = accessTokenResult.promotionIds.size();
}
} else {

// Otherwise, capture the error message
accessTokenResult.errorMessage = B2CConstant.ERRORS_OCAPI_ACCESSTOKENNOTPRESENT;
accessTokenResult.isError = true;

}
// Add the accessToken to the output
outputObj.add(accessTokenResult);
Expand Down
3 changes: 0 additions & 3 deletions src/sfdc/base/main/default/classes/B2CIAAuthCustomerInput.cls
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,4 @@ public with sharing class B2CIAAuthCustomerInput {

@AuraEnabled @InvocableVariable(Required=true)
public String version;

@AuraEnabled @InvocableVariable(Required=false)
public String expandParameter;
}
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ public with sharing class B2CIACustomerResolution_TestHelper {
if (defaultContactModel == 'Person') {

// Update the default recordType for the parent Account
accountRecordTypeDeveloperName = 'PersonAccount';
accountRecordTypeDeveloperName = B2CConfigurationManager.getPersonAccountRecordTypeDeveloperName();

// Retrieve a separate instance of the account (so we can update it)
thisAccountToUpdate = [
Expand Down
64 changes: 64 additions & 0 deletions src/sfdc/base/main/default/classes/B2CIACustomerShopperProfile.cls
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* @author Jordane Bachelet
* @date January 3rd, 2022
*
* @description This class is used to retrieve a customer profile from the OCAPI Shop API from B2C Commerce.
* The goal of using the Shop API is to retrieve custom data based on customer's context
*/
public with sharing class B2CIACustomerShopperProfile {
/**
* @description This class is used to process the collection of inputs used to retrieve a
* customer profile from B2C Commerce. When successful, it returns customer profile data.
*
* @param customerShopperProfileInputList {List<B2CIACustomerShopperProfileInput>} Represents the collection of input
* properties used to request an access token
* @return {List<B2CIACustomerShopperProfileResult>} Returns a result representing the access token
* request response (containing a token or the error
*/
@InvocableMethod(
Label='B2C: Get Customer Shopper Profile'
Description='Retrieve the Shopper Customer Profile from B2C Commerce to get data from the current customer\'s context'
)
public static List<B2CIACustomerShopperProfileResult> getCustomerShopperProfile(
List<B2CIACustomerShopperProfileInput> customerShopperProfileInputList
) {
List<B2CIACustomerShopperProfileResult> outputObj = new List<B2CIACustomerShopperProfileResult>();

for (B2CIACustomerShopperProfileInput b2creq : customerShopperProfileInputList) {
HttpRequest req = B2CHttpRequestHelper.getShopCustomerProfileRequest(
b2creq.domain, b2creq.siteId, b2creq.version, b2creq.customerId, b2creq.clientId, b2creq.token, b2creq.expandParameter
);

Http https = new Http();
HttpResponse res = https.send(req);
B2CIACustomerShopperProfileResult result = new B2CIACustomerShopperProfileResult();

result.status = res.getStatus();
result.statusCode = res.getStatusCode();
result.responseBody = res.getBody();
result.isError = false;

if (result.statusCode == 200) {
JSONParse responseParsedJSON = new JSONParse(res.getBody());
result.promotionIds = new List<String>();
try {
List<JSONParse> promotionsList = responseParsedJSON.get('c_active_promotions').asList();
for (JsonParse promotionItem : promotionsList) {
result.promotionIds.add(promotionItem.getStringValue());
}
} catch (Exception e) {
// No coupons found in the promotion
System.debug('No promotions found for the profile.');
}
result.totalPromotionsSize = result.promotionIds.size();
} else {
result.errorMessage = B2CConstant.ERRORS_B2CCOMMERCE_SHOP_CUSTOMER_RETRIEVAL;
result.isError = true;
}

outputObj.add(result);
}

return outputObj;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<status>Active</status>
</ApexClass>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @author Jordane Bachelet
* @date January 3rd, 2022
* @description This is the input class for customer shopper profile retrieval.
*/
public with sharing class B2CIACustomerShopperProfileInput {
@AuraEnabled @InvocableVariable(Required=true)
public String siteId;

@AuraEnabled @InvocableVariable(Required=true)
public String customerId;

@AuraEnabled @InvocableVariable(Required=true)
public String clientId;

@AuraEnabled @InvocableVariable(Required=true)
public String token;

@AuraEnabled @InvocableVariable(Required=true)
public String domain;

@AuraEnabled @InvocableVariable(Required=true)
public String version;

@AuraEnabled @InvocableVariable(Required=false)
public String expandParameter;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<status>Active</status>
</ApexClass>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @author Jordane Bachelet
* @date January 3rd, 2022
*
* @description This is the wrapper used by the B2CIACustomerShopperProfile class to capture the B2C Commerce API result
*/
public class B2CIACustomerShopperProfileResult {

////////////////////////////////////////////////////////////////
// Include the REST response properties
////////////////////////////////////////////////////////////////
@InvocableVariable
public String status;

@InvocableVariable
public Integer statusCode;

@InvocableVariable
public String responseBody;

////////////////////////////////////////////////////////////////
// Include any error messaging or detail flags
////////////////////////////////////////////////////////////////
@InvocableVariable
public Boolean isError;

@InvocableVariable
public String errorMessage;

////////////////////////////////////////////////////////////////
// Include the deserialized properties from the response
////////////////////////////////////////////////////////////////

@InvocableVariable
public Integer totalPromotionsSize;

@InvocableVariable
public List<String> promotionIds;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<status>Active</status>
</ApexClass>
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* @author Jordane Bachelet
* @date Dec 28, 2021
*
* @description This class exercises the successful and failed process of customer shopper details retrieval.
*/
@IsTest
private class B2CIACustomerShopperProfile_Test {
@IsTest
static void testIsSuccess() {
Test.startTest();
Test.setMock(HttpCalloutMock.class, new B2CHttpTestCalloutMockGenerator('CustomerShopDetailsSuccessWithPromotions'));

// Seed the input arguments
B2CIACustomerShopperProfileInput req = new B2CIACustomerShopperProfileInput();
req.siteId = 'siteId';
req.customerId = 'customerId';
req.clientId = 'clientId';
req.token = 'token';
req.domain = 'domain';
req.version = 'version';
req.expandParameter = 'parameter';

// Request the authToken and validate the results
List<B2CIACustomerShopperProfileResult> resultList = B2CIACustomerShopperProfile.getCustomerShopperProfile(
new List<B2CIACustomerShopperProfileInput>{
req
}
);
Test.stopTest();

// Validate that the request processed successfully
System.assertEquals(resultList.size() > 0, true, 'Expected a result to be processed and returned in the results');
System.assertEquals(resultList[0].statusCode, 200, 'Expected a successful http statusCode to be returned as part of this request');
System.assertEquals(resultList[0].isError, false, 'Expected the isError flag to be false.');
System.assertEquals(resultList[0].totalPromotionsSize, 2, 'Expected two promotions to be returned from the mock response');
System.assertEquals(resultList[0].promotionIds.size(), 2, 'Expected two promotions to be returned from the mock response');
}

@IsTest
static void testIsFailure() {
Test.startTest();
Test.setMock(HttpCalloutMock.class, new B2CHttpTestCalloutMockGenerator('CustomerShopDetailsFailure'));

// Seed the input arguments
B2CIACustomerShopperProfileInput req = new B2CIACustomerShopperProfileInput();
req.siteId = 'siteId';
req.customerId = 'customerId';
req.clientId = 'clientId';
req.token = 'token';
req.domain = 'domain';
req.version = 'version';
req.expandParameter = 'parameter';

// Request the authToken and validate the results
List<B2CIACustomerShopperProfileResult> resultList = B2CIACustomerShopperProfile.getCustomerShopperProfile(
new List<B2CIACustomerShopperProfileInput>{
req
}
);

Test.stopTest();

// Validate that the request processed with a failure
System.assertEquals(resultList.size() > 0, true, 'Expected a result to be processed and returned in the results');
System.assertEquals(resultList[0].statusCode, 400, 'Expected a failed (400) http statusCode to be returned as part of this request');
System.assertEquals(resultList[0].isError, true, 'Expected the isError flag to be true.');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>52.0</apiVersion>
<status>Active</status>
</ApexClass>
11 changes: 0 additions & 11 deletions src/sfdc/base/main/default/classes/B2CIAGetAccessTokenResult.cls
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,4 @@ public class B2CIAGetAccessTokenResult {
@InvocableVariable
public String b2cInstanceAPIUrl;


////////////////////////////////////////////////////////////////
// Include the deserialized properties from the response
////////////////////////////////////////////////////////////////

@InvocableVariable
public Integer totalPromotionsSize;

@InvocableVariable
public List<String> promotionIds;

}
Loading

0 comments on commit c259be2

Please sign in to comment.