(11/05/2019 -11/10/19)
Very Exhaustive & tiring challenge. A lot of concepts to digest, definitely could not make it without trailhead and other google resources.
It took me 5 days with an average of 1+ Hour daily.
I still feel I am far away from where I would want to be with coding. I would love to be in a state where I don’t refer to trailhead or google resources. I guess practice is the only way forward…
1. Automate Record Creation (11/05/2019 5 am to 6 am)
What I Learned
https://trailhead.salesforce.com/en/content/learn/modules/apex_triggers
trigger MaintenanceRequest on Case (before update, after update) {
// call MaintenanceRequestHelper.updateWorkOrders
if (trigger.isAfter){
//if(trigger.isUpdate){
MaintenanceRequestHelper.updateWorkOrders(Trigger.new,Trigger.OldMap);
}
}
public class MaintenanceRequestHelper {
public static void updateWorkOrders(List<Case> ClosedCases,map<id,Case> ClosedCasesOldMap){
// update workorders
for (Case c : ClosedCases){
Case oldCase = ClosedCasesOldMap.get(c.id);
//https://www.sfdc99.com/2014/02/25/comparing-old-and-new-values-in-a-trigger/
Boolean oldCaseisClosed = oldCase.Status.equals('Closed');
System.debug('OldCaseisClosed=' + oldCaseisClosed);
Boolean NewCaseisClosed = C.Status.equals('Closed');
System.debug('NewCaseisClosed=' + NewCaseisClosed);
List<AggregateResult> minMaintananceCyleDays = [SELECT MIN(Maintanance_cycle__c) from Work_Part__C where Maintenance_Request__c =: oldCase.id];
Integer intminMaintananceCyleDays = Integer.valueOf(minMaintananceCyleDays[0].get('expr0'));
System.debug('intminMaintananceCyleDays = ' + intminMaintananceCyleDays);
List <Case> CasetobeCreated = new List<case>();
if(!oldCaseisClosed && NewCaseisClosed ){
if(c.IsClosed == true && (c.Type == 'Repair' || c.Type == 'Routine Maintenance')){
case nc = new case();
nc.Type = 'Routine Maintenance';
nc.Vehicle__c = c.Vehicle__c;
if (c.Equipment__c != null){
nc.Equipment__c = c.Equipment__c;
}
if (c.Subject != null){
nc.Subject = c.Subject;
}
nc.Date_Reported__c = system.today();
if (intminMaintananceCyleDays != null){
nc.Date_Due__c = system.today()+ intminMaintananceCyleDays;
} else
nc.Date_Due__c = system.today();
System.debug('NC: '+ nc);
nc.Status = 'New';
CasetobeCreated.add(nc);
}
insert CasetobeCreated;
}
}
}
}
2. Synchronize Salesforce data with an external system
What I Learned
public with sharing class WarehouseCalloutService {
private static final String WAREHOUSE_URL = 'https://th-superbadge-apex.herokuapp.com/equipment';
// complete this method to make the callout (using @future) to the
// REST endpoint and update equipment on hand.
@Future(callout=true)
public static void runWarehouseEquipmentSync(){
List<Product2> syncprod = new List<Product2>();
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint(WAREHOUSE_URL);
request.setMethod('GET');
HttpResponse response = http.send(request);
if(response.getStatusCode()==200){
List<equipmentjson> results = (List<equipmentjson>) JSON.deserialize(response.getBody(), List<equipmentjson>.class);
for(equipmentjson inst : results){
product2 equip = new product2();
equip.Cost__c = inst.cost;
equip.Lifespan_Months__c = inst.lifespan;
equip.Maintenance_Cycle__c = inst.maintenanceperiod;
equip.Name = inst.name;
equip.Current_Inventory__c = inst.quantity;
equip.Replacement_Part__c = inst.replacement;
equip.Warehouse_SKU__c = inst.sku;
syncprod.add(equip);
}
}
if(syncprod != null && syncprod.size() > 0){
UPSERT syncprod Warehouse_SKU__c;
}
}
private class equipmentjson{
private String id;
private Integer cost;
private Integer lifespan;
private Integer maintenanceperiod;
private String name;
private Integer quantity;
private boolean replacement;
private String sku;
}
}
global class WarehouseSyncSchedule implements schedulable {
// implement scheduled code here
global void execute(SchedulableContext sc){
WarehouseCalloutService.runWarehouseEquipmentSync();
}
}
4. Test automation logic
https://trailhead.salesforce.com/en/content/learn/modules/apex_testing
@isTest
public class TestDataFactory {
public static List<case> createmr(String mrtype, integer noofcases){
List<case> mr = new List <case>();
if(noofcases > 0 && mrtype.length() >0 ){
//create vehicle
Vehicle__c v = new Vehicle__c(Name='Jetta 01', VIN_Number__c='Jetta123');
insert v;
//create Equipments: two with different maintenance cycles
List<Product2> equip = new List<Product2>();
equip.add(new Product2(Name='Testequip 01', Warehouse_SKU__c='001', Lifespan_Months__c=12, Maintenance_Cycle__c=60, Replacement_Part__c=true));
equip.add(new Product2(Name='Testequip 02', Warehouse_SKU__c='002', Lifespan_Months__c=24, Maintenance_Cycle__c=30, Replacement_Part__c=true));
insert equip;
//create maintenance requests
for (integer i = 0; i<noofcases; i++) {
mr.add(new Case(Type = mrtype, Status='New', Origin='Phone', Equipment__c=equip[0].id, Subject='Test Case'));
}
insert mr;
//Add two work parts for each maintenance request created
List<Work_Part__c> wp = new List<Work_Part__c>();
for (Case c: mr) {
wp.add(new Work_Part__c(Equipment__c=equip[0].id, Maintenance_Request__c=c.id, Quantity__c=1));
wp.add(new Work_Part__c(Equipment__c=equip[1].id, Maintenance_Request__c=c.id, Quantity__c=2));
}
insert wp;
}
return mr;
}
}
@IsTest
public class MaintenanceRequestTest {
@IsTest
static void TestPositiveSingle() {
//Test Repair maintance request
testmrcreation('Repair', 1, 'Closed');
//Test Routine Maintenance request
testmrcreation('Routine Maintenance', 1, 'Closed');
}
@IsTest
static void TestNegativeSingle() {
//Test Other maintance request
testmrcreation('Other', 1, 'Closed');
//Test Repair maintance request
testmrcreation('Repair', 1, 'Working');
//Test Routin Maintenance request
testmrcreation('Routine Maintenance', 1, 'Escalated');
}
@IsTest
static void TestPositiveBulk() {
//Test Repair maintance request
testmrcreation('Routine Maintenance', 300, 'Closed');
//Test Repair maintance request
testmrcreation('Repair', 300, 'Closed');
}
@IsTest
static void TestNegativeBulk() {
//Test Other maintance request
testmrcreation('Other', 300, 'Closed');
//Test Repair maintance request
testmrcreation('Repair', 300, 'Working');
//Test Routin Maintenance request
testmrcreation('Routine Maintenance', 300, 'Escalated');
}
private static void testmrcreation(string requestType, integer totalCount, string newStatus) {
//Test Repair maintance request
List<Case> testRequests = TestDataFactory.createmr(requestType, totalCount);
for (Case tr: testRequests) {
tr.Status = newStatus;
}
update testRequests;
List<Case> newmrs = [SELECT id, Type, Status, Vehicle__c, Equipment__c, Subject, Origin, Date_Reported__c, Date_Due__c
FROM Case WHERE ParentId IN: testRequests
AND Status = 'New'];
integer expectedTotal = 0;
if(newStatus == 'Closed' && (requestType =='Repair' || requestType == 'Routine Maintenance')) {
expectedTotal = totalCount;
}
// System.assertEquals(expectedTotal,newFollowupRequests.size());
if (expectedTotal>0) {
for (Case newmr: newmrs) {
System.assertEquals('Routine Maintenance', newmr.Type);
System.assertEquals('System Generated Routine Maintenance', newmr.Subject);
System.assertEquals('System', newmr.Origin);
System.assertEquals(Date.today(), newmr.Date_Reported__c);
System.assertEquals(Date.today().addDays(30), newmr.Date_Due__c);
}
}
}
}
5. Test Call out Logic
global class WarehouseCalloutServiceMock implements HttpCalloutMock {
// implement http mock callout
//Mock responce created to test the call out
global HttpResponse respond(HttpRequest request){
System.assertEquals('https://th-superbadge-apex.herokuapp.com/equipment', request.getEndpoint());
System.assertEquals('GET', request.getMethod());
HttpResponse response = new HttpResponse();
response.setHeader('Content-Type', 'application/json');
response.setBody('[{"_id":"55d66226726b611100aaf741","replacement":false,"quantity":5,"name":"Generator 1000 kW","maintenanceperiod":365,"lifespan":120,"cost":5000,"sku":"100003"}]');
response.setStatusCode(200);
return response;
}
}
@isTest
private class WarehouseCalloutServiceTest {
// implement your mock callout test here
@isTest
static void WarehouseEquipmentSync(){
Test.startTest();
// Set mock callout class
Test.setMock(HttpCalloutMock.class, new WarehouseCalloutServiceMock());
// This causes a fake response to be sent from the class that implements HttpCalloutMock.
WarehouseCalloutService.runWarehouseEquipmentSync();
Test.stopTest();
}
}
6.Test scheduling logic
https://trailhead.salesforce.com/content/learn/modules/asynchronous_apex/async_apex_scheduled
@isTest
public class WarehouseSyncSheduleTest {
@isTest static void WarehousescheduleTest(){
String scheduleTime = '00 00 01 * * ?';
Test.startTest();
Test.setMock(HttpCalloutMock.class, new WarehouseCalloutServiceMock());
String jobID=System.schedule('Warehouse Time To Schedule to Test', scheduleTime, new WarehouseSyncSchedule());
Test.stopTest();
//Contains schedule information for a scheduled job. CronTrigger is similar to a cron job on UNIX systems.
// This object is available in API version 17.0 and later.
CronTrigger a=[SELECT Id FROM CronTrigger where NextFireTime > today];
System.assertEquals(jobID, a.Id,'Schedule ');
}
}