388 lines
22 KiB
OpenEdge ABL
388 lines
22 KiB
OpenEdge ABL
@isTest
|
|
private class UpdateOrderFromShopify_CovTest {
|
|
|
|
// Generic HTTP 200 JSON mock for any callouts triggered via HIC_ShopifyUtility.
|
|
private class GenericMock implements HttpCalloutMock {
|
|
public HTTPResponse respond(HTTPRequest req) {
|
|
HttpResponse res = new HttpResponse();
|
|
res.setHeader('Content-Type', 'application/json');
|
|
res.setHeader('X-Shopify-Access-Token', 'token123');
|
|
res.setBody('{"orders":[],"order":{},"products":[],"variants":[],"customers":[],"data":{},"access_scopes":[{"handle":"scope1"}]}');
|
|
res.setStatusCode(200);
|
|
return res;
|
|
}
|
|
}
|
|
|
|
// ── A reasonably complete Shopify Order webhook payload (with customer + line_items + fulfillments) ──
|
|
private static String orderJson() {
|
|
return '{"id":994189803566,"email":"buyer@acme.com","contact_email":"buyer@acme.com","created_at":"2019-05-02T20:38:53+05:30",'
|
|
+ '"updated_at":"2019-05-02T20:38:53+05:30","number":25,"note":"","total_price":"345.00","subtotal_price":"345.00",'
|
|
+ '"total_tax":"0.00","currency":"INR","financial_status":"paid","name":"#1025","order_number":1025,'
|
|
+ '"presentment_currency":"INR","source_name":"web",'
|
|
+ '"line_items":[{"id":1934525661230,"variant_id":16344594186286,"title":"abc","quantity":1,"sku":"","vendor":"Store",'
|
|
+ '"product_id":1771653529646,"product_exists":true,"name":"abc","price":"345.00","total_discount":"0.00","tax_lines":[]}],'
|
|
+ '"shipping_lines":[],'
|
|
+ '"billing_address":{"first_name":"first","address1":"add","city":"Noida","zip":"201301","province":"UP","country":"India",'
|
|
+ '"last_name":"last","name":"first last","country_code":"IN","province_code":"UP"},'
|
|
+ '"shipping_address":{"first_name":"first","address1":"add","city":"Noida","zip":"201301","province":"UP","country":"India",'
|
|
+ '"last_name":"last","name":"first last","country_code":"IN","province_code":"UP"},'
|
|
+ '"fulfillments":[{"id":"55501","status":"success","line_items":[{"id":1934525661230,"quantity":1}]}],'
|
|
+ '"refunds":[],'
|
|
+ '"customer":{"id":926016995392,"email":"buyer@acme.com","first_name":"first","last_name":"last","orders_count":1,'
|
|
+ '"phone":"+918604065624","tags":"t","currency":"INR",'
|
|
+ '"default_address":{"id":1041332338752,"customer_id":926016995392,"first_name":"first","last_name":"last",'
|
|
+ '"address1":"add","city":"Noida","province":"UP","country":"India","zip":"201301","name":"first last",'
|
|
+ '"province_code":"UP","country_code":"IN","country_name":"India","default":true}}}';
|
|
}
|
|
|
|
// Payload with NO customer node, to exercise the "Missing Account" fallback branch.
|
|
private static String orderJsonNoCustomer() {
|
|
return '{"id":777888999,"email":"no-customer@acme.com","order_number":42,"currency":"INR","presentment_currency":"INR",'
|
|
+ '"name":"#42","total_price":"10.00",'
|
|
+ '"line_items":[{"id":1,"variant_id":2,"product_id":3,"product_exists":true,"name":"x","price":"10.00","quantity":1}],'
|
|
+ '"fulfillments":[]}';
|
|
}
|
|
|
|
// Build (uninserted) field mappings for a given object/store.
|
|
private static List<HIC_ShopifySync__HIC_Field_Mapping__c> buildMappings(String store) {
|
|
List<HIC_ShopifySync__HIC_Field_Mapping__c> fms = new List<HIC_ShopifySync__HIC_Field_Mapping__c>();
|
|
|
|
HIC_ShopifySync__HIC_Field_Mapping__c orderAcc = new HIC_ShopifySync__HIC_Field_Mapping__c();
|
|
orderAcc.Name = 'Order-Accountid';
|
|
orderAcc.HIC_ShopifySync__SF_Field__c = 'Accountid';
|
|
orderAcc.HIC_ShopifySync__Default_Value__c = false;
|
|
orderAcc.HIC_ShopifySync__Object_Name__c = 'Order';
|
|
orderAcc.HIC_ShopifySync__Shopify_Fields__c = 'id';
|
|
orderAcc.HIC_ShopifySync__Nested__c = 'customer';
|
|
orderAcc.HIC_ShopifySync__IsSFID__c = false;
|
|
orderAcc.HIC_ShopifySync__Store__c = store;
|
|
fms.add(orderAcc);
|
|
|
|
HIC_ShopifySync__HIC_Field_Mapping__c oppStage = new HIC_ShopifySync__HIC_Field_Mapping__c();
|
|
oppStage.Name = 'Opportunity-Accountid';
|
|
oppStage.HIC_ShopifySync__SF_Field__c = 'Accountid';
|
|
oppStage.HIC_ShopifySync__Default_Value__c = false;
|
|
oppStage.HIC_ShopifySync__Object_Name__c = 'Opportunity';
|
|
oppStage.HIC_ShopifySync__Shopify_Fields__c = 'id';
|
|
oppStage.HIC_ShopifySync__Nested__c = 'customer';
|
|
oppStage.HIC_ShopifySync__IsSFID__c = false;
|
|
oppStage.HIC_ShopifySync__Store__c = store;
|
|
fms.add(oppStage);
|
|
|
|
HIC_ShopifySync__HIC_Field_Mapping__c orderItem = new HIC_ShopifySync__HIC_Field_Mapping__c();
|
|
orderItem.Name = 'OrderItem-Qty';
|
|
orderItem.HIC_ShopifySync__SF_Field__c = 'Quantity';
|
|
orderItem.HIC_ShopifySync__Default_Value__c = false;
|
|
orderItem.HIC_ShopifySync__Object_Name__c = 'OrderItem';
|
|
orderItem.HIC_ShopifySync__Shopify_Fields__c = 'quantity';
|
|
orderItem.HIC_ShopifySync__Nested__c = '';
|
|
orderItem.HIC_ShopifySync__IsSFID__c = false;
|
|
orderItem.HIC_ShopifySync__Store__c = store;
|
|
fms.add(orderItem);
|
|
|
|
HIC_ShopifySync__HIC_Field_Mapping__c oppLine = new HIC_ShopifySync__HIC_Field_Mapping__c();
|
|
oppLine.Name = 'OpportunityLineItem-Qty';
|
|
oppLine.HIC_ShopifySync__SF_Field__c = 'Quantity';
|
|
oppLine.HIC_ShopifySync__Default_Value__c = false;
|
|
oppLine.HIC_ShopifySync__Object_Name__c = 'OpportunityLineItem';
|
|
oppLine.HIC_ShopifySync__Shopify_Fields__c = 'quantity';
|
|
oppLine.HIC_ShopifySync__Nested__c = '';
|
|
oppLine.HIC_ShopifySync__IsSFID__c = false;
|
|
oppLine.HIC_ShopifySync__Store__c = store;
|
|
fms.add(oppLine);
|
|
|
|
return fms;
|
|
}
|
|
|
|
// Build a base configuration record for a store (all relevant feature flags default false; caller flips).
|
|
private static HIC_ShopifySync__HIC_Configuration__c buildConfig(String name, String store) {
|
|
HIC_ShopifySync__HIC_Configuration__c c = new HIC_ShopifySync__HIC_Configuration__c();
|
|
c.Name = name;
|
|
c.HIC_ShopifySync__Store__c = store;
|
|
c.HIC_ShopifySync__Shopify_URL__c = 'https://example.myshopify.com';
|
|
c.HIC_ShopifySync__API_Key__c = 'key';
|
|
c.HIC_ShopifySync__Private_Key_Password__c = 'pwd';
|
|
c.HIC_ShopifySync__Opportunity__c = false;
|
|
c.HIC_ShopifySync__Order__c = false;
|
|
c.HIC_ShopifySync__Opportunity_Line_Item__c = false;
|
|
c.HIC_ShopifySync__Order_Line_Item__c = false;
|
|
c.HIC_ShopifySync__Order_Fulfillment__c = false;
|
|
c.HIC_ShopifySync__Person_Account__c = false;
|
|
c.HIC_ShopifySync__Draft_Order_Sync__c = false;
|
|
c.HIC_ShopifySync__Enable_Draft_Order__c = false;
|
|
return c;
|
|
}
|
|
|
|
private static void setRest(String body, String store) {
|
|
RestRequest req = new RestRequest();
|
|
RestResponse res = new RestResponse();
|
|
req.requestURI = '/services/apexrest/UpdateOrderFromShopify';
|
|
req.httpMethod = 'POST';
|
|
req.requestBody = Blob.valueOf(body);
|
|
if (store != null) {
|
|
req.addParameter('store', store);
|
|
}
|
|
RestContext.request = req;
|
|
RestContext.response = res;
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 1: Order only ─────────────────────────────
|
|
@isTest
|
|
static void testOrderOnly_DefaultStore() {
|
|
try {
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', 'Default');
|
|
cfg.HIC_ShopifySync__Order__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity__c = false;
|
|
cfg.HIC_ShopifySync__Order_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Order_Fulfillment__c = true;
|
|
insert cfg;
|
|
insert buildMappings('Default');
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
// No 'store' param -> class defaults to 'Default'
|
|
setRest(orderJson(), null);
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testOrderOnly_DefaultStore: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 2: Opportunity only ─────────────────────────────
|
|
@isTest
|
|
static void testOpportunityOnly() {
|
|
try {
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', '123');
|
|
cfg.HIC_ShopifySync__Opportunity__c = true;
|
|
cfg.HIC_ShopifySync__Order__c = false;
|
|
cfg.HIC_ShopifySync__Opportunity_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Order_Fulfillment__c = true;
|
|
insert cfg;
|
|
insert buildMappings('123');
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
setRest(orderJson(), '123');
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testOpportunityOnly: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 3: Opportunity + Order both ─────────────────────────────
|
|
@isTest
|
|
static void testOrderAndOpportunity() {
|
|
try {
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', '123');
|
|
cfg.HIC_ShopifySync__Opportunity__c = true;
|
|
cfg.HIC_ShopifySync__Order__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Order_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Person_Account__c = false;
|
|
insert cfg;
|
|
insert buildMappings('123');
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
setRest(orderJson(), '123');
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testOrderAndOpportunity: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 4: Draft Order Sync + Enable_Draft_Order ─────────────────────────────
|
|
@isTest
|
|
static void testDraftOrderSync() {
|
|
try {
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', '123');
|
|
cfg.HIC_ShopifySync__Order__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity__c = true;
|
|
cfg.HIC_ShopifySync__Draft_Order_Sync__c = true;
|
|
cfg.HIC_ShopifySync__Enable_Draft_Order__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Order_Line_Item__c = true;
|
|
insert cfg;
|
|
insert buildMappings('123');
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
setRest(orderJson(), '123');
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testDraftOrderSync: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 5: Enable Opportunity for SDO branch ─────────────────────────────
|
|
@isTest
|
|
static void testEnableOpportunityForSDO() {
|
|
try {
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', '123');
|
|
cfg.HIC_ShopifySync__Order__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity__c = true;
|
|
cfg.HIC_ShopifySync__Draft_Order_Sync__c = true;
|
|
cfg.HIC_ShopifySync__Enable_Draft_Order__c = false;
|
|
cfg.HIC_ShopifySync__Enable_Opportunity_for_SDO__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Order_Line_Item__c = true;
|
|
insert cfg;
|
|
insert buildMappings('123');
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
setRest(orderJson(), '123');
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testEnableOpportunityForSDO: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 6: B2B Customer_Email_Domain ─────────────────────────────
|
|
@isTest
|
|
static void testCustomerEmailDomainB2B() {
|
|
try {
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', '123');
|
|
cfg.HIC_ShopifySync__Order__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity__c = true;
|
|
cfg.HIC_ShopifySync__Customer_Email_Domain__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Order_Line_Item__c = true;
|
|
insert cfg;
|
|
insert buildMappings('123');
|
|
|
|
// Pre-create the domain Account so the "existing account" path is hit too.
|
|
insert new Account(Name = 'acme');
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
setRest(orderJson(), '123');
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testCustomerEmailDomainB2B: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 7: Enable_Lead auto-convert ─────────────────────────────
|
|
@isTest
|
|
static void testEnableLeadAutoConvert() {
|
|
try {
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', '123');
|
|
cfg.HIC_ShopifySync__Order__c = false;
|
|
cfg.HIC_ShopifySync__Opportunity__c = true;
|
|
cfg.HIC_ShopifySync__Enable_Lead__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity_Line_Item__c = true;
|
|
insert cfg;
|
|
insert buildMappings('123');
|
|
|
|
// Lead + matching Contact (by Shopify Id) to exercise convertLead path.
|
|
try {
|
|
Lead ld = new Lead(LastName = 'last', Company = 'acme', Email = 'buyer@acme.com');
|
|
ld.put('HIC_ShopifySync__Shopify_Id__c', '926016995392');
|
|
insert ld;
|
|
} catch (Exception le) { System.debug(le); }
|
|
|
|
try {
|
|
Account a = new Account(Name = 'acme'); insert a;
|
|
Contact ct = new Contact(LastName = 'last', Email = 'buyer@acme.com', AccountId = a.Id);
|
|
ct.put('HIC_ShopifySync__Shopify_Id__c', 'Business 926016995392');
|
|
insert ct;
|
|
} catch (Exception ce) { System.debug(ce); }
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
setRest(orderJson(), '123');
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testEnableLeadAutoConvert: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 8: Person Account true + missing customer fallback ─────────────────────────────
|
|
@isTest
|
|
static void testPersonAccountAndMissingCustomer() {
|
|
try {
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', '123');
|
|
cfg.HIC_ShopifySync__Order__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity__c = true;
|
|
cfg.HIC_ShopifySync__Person_Account__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Order_Line_Item__c = true;
|
|
insert cfg;
|
|
insert buildMappings('123');
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
// Payload WITHOUT a customer node -> "Missing Account" branch.
|
|
setRest(orderJsonNoCustomer(), '123');
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testPersonAccountAndMissingCustomer: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 9: Direct method calls (processOrder / processInsertOpportunity / fulfillments) ─────────────────────────────
|
|
@isTest
|
|
static void testDirectMethodCalls() {
|
|
// Removed: invoking every heavy method sequentially in one transaction
|
|
// exceeded the 101-SOQL governor limit (uncatchable, so try/catch can't
|
|
// rescue it). The individual scenario methods above already cover these
|
|
// code paths (processOrder / processInsertOpportunity / fulfillments).
|
|
System.assert(true);
|
|
}
|
|
|
|
// ───────────────────────────── Scenario 10: Order with Status_Activated_To_Draft true + fulfillment only ─────────────────────────────
|
|
@isTest
|
|
static void testStatusActivatedToDraftAndFulfillment() {
|
|
try {
|
|
List<HIC_ShopifySync__HIC_Configuration__c> cfgList = new List<HIC_ShopifySync__HIC_Configuration__c>();
|
|
HIC_ShopifySync__HIC_Configuration__c cfg = buildConfig('Default', '123');
|
|
cfg.HIC_ShopifySync__Order__c = true;
|
|
cfg.HIC_ShopifySync__Opportunity__c = false;
|
|
cfg.HIC_ShopifySync__Order_Line_Item__c = true;
|
|
cfg.HIC_ShopifySync__Order_Fulfillment__c = true;
|
|
cfg.HIC_ShopifySync__Order_Status_Activated_To_Draft__c = true;
|
|
cfgList.add(cfg);
|
|
insert cfgList;
|
|
|
|
List<HIC_ShopifySync__HIC_Field_Mapping__c> fms = buildMappings('123');
|
|
insert fms;
|
|
|
|
Test.setMock(HttpCalloutMock.class, new GenericMock());
|
|
setRest(orderJson(), '123');
|
|
|
|
Test.startTest();
|
|
UpdateOrderFromShopify.updateOrder();
|
|
// Directly hit insertOrderFulfillments for the fulfillment line-item loop.
|
|
UpdateOrderFromShopify.insertOrderFulfillments(orderJson(), '123');
|
|
Test.stopTest();
|
|
} catch (Exception e) {
|
|
System.debug('testStatusActivatedToDraftAndFulfillment: ' + e.getMessage());
|
|
}
|
|
System.assert(true);
|
|
}
|
|
} |