Skip to content

JobServiceSampleTransferProductsToNewStoreJob

smehta-veeva edited this page Sep 1, 2020 · 1 revision

The JobServiceSampleTransferProductsToNewStoreJob class implements the Job Interface and is the custom job code that finds all the inventory of the existing bicycle store and transfers it to the new store.

Init method

The init method is used to initialize the custom job and set the job input values that will be used when processing.

Firstly, we fetch the job parameters set by the trigger when the custom job processor was execute.

String existingBicycleStore = jobInitContext.getJobParameter("existingBicycleStore", JobParamValueType.STRING);
String newBicycleStore = jobInitContext.getJobParameter("newBicycleStore", JobParamValueType.STRING);

Next, a list must be created to store the job items that will be processed.

List<JobItem> jobItems = VaultCollections.newList();

Next, to find the id of the new store, a VQL query must be run.

String newStoreQuery = "SELECT id FROM bicycle_store__c WHERE name__v='" + newBicycleStore +"' LIMIT 1";

QueryResponse storeQueryResponse = queryService.query(newStoreQuery);
List<String> newStoreIds = VaultCollections.newList();
if(storeQueryResponse.getResultCount() > 0) {
   storeQueryResponse.streamResults().forEach(queryResult -> {
         newStoreIds.add(queryResult.getValue("id", ValueType.STRING));
   });
}

A VQL query must also be run to find all the accessories sold by the old store.

String bicycleAccessoryQuery = "SELECT id, name__v, price__c, quantity__c FROM bicycle_accessory__c WHERE bicycle_store__cr.name__v='" + existingBicycleStore +"' LIMIT 1";

QueryResponse accessoryQueryResponse = queryService.query(bicycleAccessoryQuery);

Next, the result of the query must be used to get the id, name, price, and quantity of the accessories. The Ids will be used to delete these accessory records while the name, price and quantity information will be used to create the new records. These values will be set as job input items to be used by the process method.

if(accessoryQueryResponse.getResultCount() > 0 && newStoreIds.size() > 0) {
            accessoryQueryResponse.streamResults().forEach(queryResult -> {
                JobItem bicycleAccessoryItem = jobInitContext.newJobItem();

                String bicycleAccessoryId = queryResult.getValue("id", ValueType.STRING);
                String bicycleAccessoryName = queryResult.getValue("name__v", ValueType.STRING);
                BigDecimal bicycleAccessoryPrice = queryResult.getValue("price__c", ValueType.NUMBER);
                BigDecimal bicycleAccessoryQuantity = queryResult.getValue("quantity__c", ValueType.NUMBER);

                String newStoreId = newStoreIds.get(0);

                bicycleAccessoryItem.setValue("bicycleAccessoryId", bicycleAccessoryId);
                bicycleAccessoryItem.setValue("bicycleAccessoryName", bicycleAccessoryName);
                bicycleAccessoryItem.setValue("bicycleAccessoryPrice", bicycleAccessoryPrice);
                bicycleAccessoryItem.setValue("bicycleAccessoryQuantity", bicycleAccessoryQuantity);
                bicycleAccessoryItem.setValue("newBicycleStoreId", newStoreId);

                jobItems.add(bicycleAccessoryItem);
            }
            return jobInitContext.newJobInput(jobItems);
        }

Process method

The process method processes the job items and sets the task output statuses.

Firstly, the Record Service must be located. This will be later used to create the clone records and delete the old records.

RecordService recordService = ServiceLocator.locate(RecordService.class);

Next, the Job Items set by the Init method must be fetched. Additionally, lists to hold the new and old records must be created. The Suppress Warnings annotation is used to suppress compiler warnings. In this case, the unchecked safety warning is suppressed, which needs to be done as List is a generic type.

List<JobItem> bicycleAccessoryItems = jobProcessContext.getCurrentTask().getItems();

@SuppressWarnings("unchecked")
List<Record> deletedBicycleAccessoryRecords = VaultCollections.newList();

@SuppressWarnings("unchecked")
List<Record> clonedBicycleAccessoryRecords = VaultCollections.newList();

Next, the job items set by the Init method are iterated over to add to the list of new and old accessory records. This requires fetching the bicycle accessory id and the new store id from the job item and checking if they both are non-null.

for (JobItem bicycleAccessoryItem : bicycleAccessoryItems) {

    String bicycleAccessoryId = bicycleAccessoryItem.getValue("bicycleAccessoryId", JobValueType.STRING);
    String newBicycleStoreId = bicycleAccessoryItem.getValue("newBicycleStoreId", JobValueType.STRING);

    if(bicycleAccessoryId != null && newBicycleStoreId != null) {

...

Next, the new records are created using the values from the job items. Once these values are set on the new records, they are added to the cloned records list. Additionally, the old records are added to the list of records to be deleted.

       Record oldBicycleAccessoryRecord = recordService.newRecordWithId("bicycle_accessory__c", bicycleAccessoryId);

       Record cloneBicycleAccessoryRecord = recordService.newRecord("bicycle_accessory__c");

       cloneBicycleAccessoryRecord.setValue("bicycle_store__c", newBicycleStoreId);

       String bicycleAccessoryName = bicycleAccessoryItem.getValue("bicycleAccessoryName", JobValueType.STRING);
       
       BigDecimal bicycleAccessoryPrice = bicycleAccessoryItem.getValue("bicycleAccessoryPrice", JobValueType.NUMBER);
                
       BigDecimal bicycleAccessoryQuantity = bicycleAccessoryItem.getValue("bicycleAccessoryQuantity", JobValueType.NUMBER);

       cloneBicycleAccessoryRecord.setValue("name__v", bicycleAccessoryName);
       cloneBicycleAccessoryRecord.setValue("price__c", bicycleAccessoryPrice);
       cloneBicycleAccessoryRecord.setValue("quantity__c", bicycleAccessoryQuantity);

        clonedBicycleAccessoryRecords.add(cloneBicycleAccessoryRecord);
        deletedBicycleAccessoryRecords.add(oldBicycleAccessoryRecord);
     }
}

Lastly, the batchSaveRecords and the batchDeleteRecords method is used to save the new records and delete the bulk records in bulk. Then the job task output status is set. In case of an error, the Job Logger is used to log the reason for the failure.

JobTask task = jobProcessContext.getCurrentTask();
TaskOutput taskOutput = task.getTaskOutput();

BatchOperation<PositionalRecordId, BatchOperationError> batchSaveResult = recordService.batchSaveRecords(clonedBicycleAccessoryRecords);

BatchOperation<PositionalRecordId, BatchOperationError> batchDeleteResult = recordService.batchDeleteRecords(deletedBicycleAccessoryRecords);

batchSaveResult.onSuccesses(positionalRecordIds -> {
 taskOutput.setState(TaskState.SUCCESS);
 logger.log("Clone Record Save successful");
});

batchDeleteResult.onSuccesses(positionalRecordIds -> {
  taskOutput.setState(TaskState.SUCCESS);
  logger.log("Old Record Delete successful");
});

batchSaveResult.onErrors( batchOperationErrors -> {
  taskOutput.setState(TaskState.ERRORS_ENCOUNTERED);
  taskOutput.setValue("firstError", batchOperationErrors.get(0).getError().getMessage());
  logger.log("Clone Record Save unsuccessful due to: " + batchOperationErrors.get(0).getError().getMessage());
        });

batchDeleteResult.onErrors( batchOperationErrors -> {
   taskOutput.setState(TaskState.ERRORS_ENCOUNTERED);
   taskOutput.setValue("firstError", batchOperationErrors.get(0).getError().getMessage());
   logger.log("Old Record Delete unsuccessful due to: " + batchOperationErrors.get(0).getError().getMessage());
});

batchSaveResult.execute();
batchDeleteResult.execute();