Browse Source

Initial commit

master
Matt Comer 3 months ago
commit
8ca00b4ea5
15 changed files with 672 additions and 0 deletions
  1. +15
    -0
      .eslintignore
  2. +12
    -0
      .forceignore
  3. +38
    -0
      .gitignore
  4. +9
    -0
      .prettierignore
  5. +13
    -0
      .prettierrc
  6. +58
    -0
      README.md
  7. +18
    -0
      config/project-scratch-def.json
  8. +189
    -0
      force-app/main/default/classes/MassTransactorAction.cls
  9. +5
    -0
      force-app/main/default/classes/MassTransactorAction.cls-meta.xml
  10. +134
    -0
      force-app/main/default/classes/MassTransactorActionTest.cls
  11. +5
    -0
      force-app/main/default/classes/MassTransactorActionTest.cls-meta.xml
  12. +119
    -0
      force-app/main/default/classes/MassTransactorBatchHelper.cls
  13. +5
    -0
      force-app/main/default/classes/MassTransactorBatchHelper.cls-meta.xml
  14. +41
    -0
      package.json
  15. +11
    -0
      sfdx-project.json

+ 15
- 0
.eslintignore View File

@@ -0,0 +1,15 @@
**/lwc/**/*.css
**/lwc/**/*.html
**/lwc/**/*.json
**/lwc/**/*.svg
**/lwc/**/*.xml
**/aura/**/*.auradoc
**/aura/**/*.cmp
**/aura/**/*.css
**/aura/**/*.design
**/aura/**/*.evt
**/aura/**/*.json
**/aura/**/*.svg
**/aura/**/*.tokens
**/aura/**/*.xml
.sfdx

+ 12
- 0
.forceignore View File

@@ -0,0 +1,12 @@
# List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status
# More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm
#

package.xml

# LWC configuration files
**/jsconfig.json
**/.eslintrc.json

# LWC Jest
**/__tests__/**

+ 38
- 0
.gitignore View File

@@ -0,0 +1,38 @@
# This file is used for Git repositories to specify intentionally untracked files that Git should ignore.
# If you are not using git, you can delete this file. For more information see: https://git-scm.com/docs/gitignore
# For useful gitignore templates see: https://github.com/github/gitignore

# Salesforce cache
.sfdx/
.localdevserver/

# VS Code config
.vscode/

# LWC VSCode autocomplete
**/lwc/jsconfig.json

# LWC Jest coverage reports
coverage/

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Dependency directories
node_modules/

# Eslint cache
.eslintcache

# MacOS system files
.DS_Store

# Windows system files
Thumbs.db
ehthumbs.db
[Dd]esktop.ini
$RECYCLE.BIN/

+ 9
- 0
.prettierignore View File

@@ -0,0 +1,9 @@
# List files or directories below to ignore them when running prettier
# More information: https://prettier.io/docs/en/ignore.html
#

**/staticresources/**
.localdevserver
.sfdx

coverage/

+ 13
- 0
.prettierrc View File

@@ -0,0 +1,13 @@
{
"trailingComma": "none",
"overrides": [
{
"files": "**/lwc/**/*.html",
"options": { "parser": "lwc" }
},
{
"files": "*.{cmp,page,component}",
"options": { "parser": "html" }
}
]
}

+ 58
- 0
README.md View File

@@ -0,0 +1,58 @@
# Salesforce App

This guide helps Salesforce developers who are new to Visual Studio Code go from zero to a deployed app using Salesforce Extensions for VS Code and Salesforce CLI.

## Part 1: Choosing a Development Model

There are two types of developer processes or models supported in Salesforce Extensions for VS Code and Salesforce CLI. These models are explained below. Each model offers pros and cons and is fully supported.

### Package Development Model

The package development model allows you to create self-contained applications or libraries that are deployed to your org as a single package. These packages are typically developed against source-tracked orgs called scratch orgs. This development model is geared toward a more modern type of software development process that uses org source tracking, source control, and continuous integration and deployment.

If you are starting a new project, we recommend that you consider the package development model. To start developing with this model in Visual Studio Code, see [Package Development Model with VS Code](https://forcedotcom.github.io/salesforcedx-vscode/articles/user-guide/package-development-model). For details about the model, see the [Package Development Model](https://trailhead.salesforce.com/en/content/learn/modules/sfdx_dev_model) Trailhead module.

If you are developing against scratch orgs, use the command `SFDX: Create Project` (VS Code) or `sfdx force:project:create` (Salesforce CLI) to create your project. If you used another command, you might want to start over with that command.

When working with source-tracked orgs, use the commands `SFDX: Push Source to Org` (VS Code) or `sfdx force:source:push` (Salesforce CLI) and `SFDX: Pull Source from Org` (VS Code) or `sfdx force:source:pull` (Salesforce CLI). Do not use the `Retrieve` and `Deploy` commands with scratch orgs.

### Org Development Model

The org development model allows you to connect directly to a non-source-tracked org (sandbox, Developer Edition (DE) org, Trailhead Playground, or even a production org) to retrieve and deploy code directly. This model is similar to the type of development you have done in the past using tools such as Force.com IDE or MavensMate.

To start developing with this model in Visual Studio Code, see [Org Development Model with VS Code](https://forcedotcom.github.io/salesforcedx-vscode/articles/user-guide/org-development-model). For details about the model, see the [Org Development Model](https://trailhead.salesforce.com/content/learn/modules/org-development-model) Trailhead module.

If you are developing against non-source-tracked orgs, use the command `SFDX: Create Project with Manifest` (VS Code) or `sfdx force:project:create --manifest` (Salesforce CLI) to create your project. If you used another command, you might want to start over with this command to create a Salesforce DX project.

When working with non-source-tracked orgs, use the commands `SFDX: Deploy Source to Org` (VS Code) or `sfdx force:source:deploy` (Salesforce CLI) and `SFDX: Retrieve Source from Org` (VS Code) or `sfdx force:source:retrieve` (Salesforce CLI). The `Push` and `Pull` commands work only on orgs with source tracking (scratch orgs).

## The `sfdx-project.json` File

The `sfdx-project.json` file contains useful configuration information for your project. See [Salesforce DX Project Configuration](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_config.htm) in the _Salesforce DX Developer Guide_ for details about this file.

The most important parts of this file for getting started are the `sfdcLoginUrl` and `packageDirectories` properties.

The `sfdcLoginUrl` specifies the default login URL to use when authorizing an org.

The `packageDirectories` filepath tells VS Code and Salesforce CLI where the metadata files for your project are stored. You need at least one package directory set in your file. The default setting is shown below. If you set the value of the `packageDirectories` property called `path` to `force-app`, by default your metadata goes in the `force-app` directory. If you want to change that directory to something like `src`, simply change the `path` value and make sure the directory you’re pointing to exists.

```json
"packageDirectories" : [
{
"path": "force-app",
"default": true
}
]
```

## Part 2: Working with Source

For details about developing against scratch orgs, see the [Package Development Model](https://trailhead.salesforce.com/en/content/learn/modules/sfdx_dev_model) module on Trailhead or [Package Development Model with VS Code](https://forcedotcom.github.io/salesforcedx-vscode/articles/user-guide/package-development-model).

For details about developing against orgs that don’t have source tracking, see the [Org Development Model](https://trailhead.salesforce.com/content/learn/modules/org-development-model) module on Trailhead or [Org Development Model with VS Code](https://forcedotcom.github.io/salesforcedx-vscode/articles/user-guide/org-development-model).

## Part 3: Deploying to Production

Don’t deploy your code to production directly from Visual Studio Code. The deploy and retrieve commands do not support transactional operations, which means that a deployment can fail in a partial state. Also, the deploy and retrieve commands don’t run the tests needed for production deployments. The push and pull commands are disabled for orgs that don’t have source tracking, including production orgs.

Deploy your changes to production using [packaging](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_dev2gp.htm) or by [converting your source](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_force_source.htm#cli_reference_convert) into metadata format and using the [metadata deploy command](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_force_mdapi.htm#cli_reference_deploy).

+ 18
- 0
config/project-scratch-def.json View File

@@ -0,0 +1,18 @@
{
"orgName": "matt company",
"edition": "Developer",
"features": [],
"settings": {
"lightningExperienceSettings": {
"enableS1DesktopEnabled": true
},
"securitySettings": {
"passwordPolicies": {
"enableSetPasswordInApi": true
}
},
"mobileSettings": {
"enableS1EncryptedStoragePref2": false
}
}
}

+ 189
- 0
force-app/main/default/classes/MassTransactorAction.cls View File

@@ -0,0 +1,189 @@
/**
* @description : Invocable for doing large batch DML from Flow and specifies a batch
* @author : Matt Comer, Kyle Kim, Ward Wood, Adam White
* @group :
* @last modified on :
* @last modified by :
* Modifications Log
* Ver Date Author Modification
* 1.0 08-06-2020 Matt Comer, Kyle Kim, Ward Wood Initial Version
* 1.1 08-20-2020 Adan White Added email inputs / send on complete

**/
global with sharing class MassTransactorAction {
public static Integer MAX_BATCH_SIZE = 2000;
// If no Batch size is specified from the flow - batch size defaults to DEFAULT_BATCH_SIZE
public static Integer DEFAULT_BATCH_SIZE = 200;


//Main Method to acting as an orchestration layer.
@InvocableMethod (label='DML Records Asynchronously')
public static List<InvocableApexAsyncBatchResponse> InvocableApexCreateAsyncController(List<InvocableApexAsyncBatchRequest> RequestList){
InvocableApexAsyncBatchRequest request = RequestList[0];
ValidationObject vo = ValidateRequestObject(request);

InvocableApexAsyncBatchResponse response = new InvocableApexAsyncBatchResponse();
List<InvocableApexAsyncBatchResponse> result = new List<InvocableApexAsyncBatchResponse>();
result.add(response);

if (vo.Validity) {
Integer batchSize = request.BatchSizeIsNull() ? DEFAULT_BATCH_SIZE : request.BatchSize;
MassTransactorBatchHelper bh = new MassTransactorBatchHelper(request.RequestList,
request.OperationType,
request.EmailToAddress,
request.EmailBody,
request.EmailSubject);
response.jobId = Database.executeBatch(bh, batchSize);
response.success = true;
} else {
response.success = false;
response.errorMessage = vo.ResponseMessage;
}

return result;
}

//Method & Main controller for Error handling. utlizes two different methods.
public static ValidationObject ValidateRequestObject(InvocableApexAsyncBatchRequest RequestPayload){
ValidationObject MasterValidationObject = new ValidationObject();
ValidatePayloadSize(RequestPayload, MasterValidationObject);
if (MasterValidationObject.Validity == false){
return MasterValidationObject;
}
else{
//run another check on items if math is good then we can return it and let the controller do it's magic
ValidatePayloadItems(RequestPayload, MasterValidationObject);
return MasterValidationObject;

}
}

//Method scans the payload and ensure that the items in the batch are okay
//We need to ensure Deletes are parsed as [{ids}]
//Everything else [{any fields in there. map it correctly when assigning it though..}]
public static void ValidatePayloadItems (InvocableApexAsyncBatchRequest RequestPayload, ValidationObject MasterValidationObject){

//Variables to establish Constants ()
Schema.sObjectType ObjectType = RequestPayload.RequestList.get(0).getSObjectType();

//Parse out all IDs into a set(de-dup if someone did something silly).
Set <Id> IDSet = new Set <ID>();
for(sObject cursor : RequestPayload.RequestList){
if(cursor.Id != null || cursor.Id != ''){
IDSet.add(cursor.Id);
}
}

String queryString = 'Select ID from ' + String.valueOf(ObjectType) + ' where ID in :IDSet';
List <sObject> ValidationList = Database.query(queryString);

//based on the operation type
switch on RequestPayload.OperationType.toUpperCase(){
//Make sure IDs do not exist.
when 'CREATE'{
if(ValidationList.size() > 0) {
MasterValidationObject.Validity = false;
MasterValidationObject.ResponseMessage = 'There are IDs that exis. Cannot create records with existing Ids.';
MasterValidationObject.ResponseCode = 403;
}
}
//update and delete, make sure all Ids Exist.
when else {
if(ValidationList.size() != RequestPayload.RequestList.size()){
MasterValidationObject.Validity = false;
MasterValidationObject.ResponseMessage = 'There are records in this collection with IDs that do not exist. Cannot execute delete or updates on Ids that do not exist';
MasterValidationObject.ResponseCode = 405;
}
}
}
if(MasterValidationObject.Validity != false){
MasterValidationObject.Validity = true;
MasterValidationObject.ResponseMessage = 'Valid Payload';
MasterValidationObject.ResponseCode = 200;
}
}
// Method scans the payload, and ensures that the batch size is okay
public static void ValidatePayloadSize (InvocableApexAsyncBatchRequest RequestPayload, ValidationObject MasterValidationObject){
if(RequestPayload.RequestList.size() == 0 || RequestPayload.RequestList == null) {
MasterValidationObject.Validity = false;
MasterValidationObject.ResponseMessage = 'There are no records to process.';
MasterValidationObject.ResponseCode = 66;
}
else {
//If there is no batchsize set it to the max
Integer BatchSize = RequestPayload.BatchSize = RequestPayload.BatchSizeIsNull() ? DEFAULT_BATCH_SIZE : RequestPayload.BatchSize;
//check if batch size reaches limit || Check if too many batches || Check if no batches...
if(BatchSize > MAX_BATCH_SIZE || BatchSize <= 0){
MasterValidationObject.Validity = false;
MasterValidationObject.ResponseCode = 401;
MasterValidationObject.ResponseMessage = 'Batch size needs to be between 0 and 2000';
}
else {
MasterValidationObject.Validity = true;
MasterValidationObject.ResponseCode = 200;
MasterValidationObject.ResponseMessage = 'Success';
}
}
}

//Request and Response Objects.
public class InvocableApexAsyncBatchRequest{
@InvocableVariable(label='Operation Type' description='CUD operation Create Delete Update' required=true)
public String OperationType;
@InvocableVariable(label='Records for Input' description='Flexible List to pass objects' required=true)
public List<sObject> RequestList;

@InvocableVariable(label='Batch Size' description='Size of Batch for each job' required=false)
public Integer BatchSize;
@InvocableVariable(label='Finish Notification Email' description='A single email address to send the finish email to')
public String EmailToAddress;
@InvocableVariable(label='Body of the email' description='What the email will contain upon completion')
public String EmailBody;
@InvocableVariable(label='Subject of the email' description='Subject of the email upon completion')
public String EmailSubject;
//Boolean to check if this is null or empty.
public Boolean BatchSizeIsNull(){
if(this.BatchSize == null || this.BatchSize == 0){
return true;
}
else{
return false;
}
}

}

//Response object - not sure if we need this
public class InvocableApexAsyncBatchResponse {
@InvocableVariable(label='Submission Results' description='True if the batch was succesfully submitted, false if not')
public Boolean success;

@InvocableVariable(label='JobId' description='The jobId of the batch processing the DML')
public String jobId;

@InvocableVariable(label='Error message' description='If success is false, the validation error which occured')
public String errorMessage;
}

public class ValidationObject {
public boolean Validity;
public String ResponseMessage;
public Integer ResponseCode;
}

}

+ 5
- 0
force-app/main/default/classes/MassTransactorAction.cls-meta.xml View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>49.0</apiVersion>
<status>Active</status>
</ApexClass>

+ 134
- 0
force-app/main/default/classes/MassTransactorActionTest.cls View File

@@ -0,0 +1,134 @@
/**
* @description :
* @author : Adam White, CapTech Consulting
* @group :
* @last modified on : 08-18-2020
* @last modified by : Adam White, CapTech Consulting
* Modifications Log
* Ver Date Author Modification
* 1.0 08-18-2020 Adam White, CapTech Consulting Initial Version
**/
@IsTest
global with sharing class MassTransactorActionTest{

@TestSetup
static void makeData(){
List<Account> accounts = new List<Account>();
// insert 10 accounts
for (Integer i=0;i<10;i++) {
accounts.add(new Account(name='Account '+i,
billingcity='New York',
billingcountry='USA',
billingState = 'Virginia',
billingPostalCode = '23113',
BillingStreet = '12345 Hello Lane'));
}
insert accounts;
}
@IsTest
static void createRecords(){
List<Account> accounts = new List<Account>();
// insert 10 accounts
for (Integer i=0;i<10;i++) {
accounts.add(new Account(name='Account '+i,
billingcity='New York',
billingcountry='USA',
billingState = 'Virginia',
billingPostalCode = '23113',
BillingStreet = '12345 Hello Lane'));
}
List<MassTransactorAction.InvocableApexAsyncBatchRequest> flowRequests = new List<MassTransactorAction.InvocableApexAsyncBatchRequest>();
MassTransactorAction.InvocableApexAsyncBatchRequest flowRequest = new MassTransactorAction.InvocableApexAsyncBatchRequest();
flowRequest.BatchSize = 220;
flowRequest.OperationType = 'Create';
flowRequest.RequestList = accounts;
flowRequests.add(flowRequest);
Test.startTest();
MassTransactorAction.InvocableApexCreateAsyncController(flowRequests);
Test.stopTest();
}
@IsTest
static void deleteRecords(){
List<Account> accounts = [SELECT Id from Account Where Name like '%Account%'];
List<MassTransactorAction.InvocableApexAsyncBatchRequest> flowRequests = new List<MassTransactorAction.InvocableApexAsyncBatchRequest>();
MassTransactorAction.InvocableApexAsyncBatchRequest flowRequest = new MassTransactorAction.InvocableApexAsyncBatchRequest();
flowRequest.BatchSize = 220;
flowRequest.OperationType = 'Delete';
flowRequest.RequestList = accounts;
flowRequests.add(flowRequest);
Test.startTest();
MassTransactorAction.InvocableApexCreateAsyncController(flowRequests);
Test.stopTest();
}
@IsTest
static void testBatchLimit(){
List<Account> accounts = [SELECT Id from Account Where Name like '%Account%'];
List<MassTransactorAction.InvocableApexAsyncBatchRequest> flowRequests = new List<MassTransactorAction.InvocableApexAsyncBatchRequest>();
MassTransactorAction.InvocableApexAsyncBatchRequest flowRequest = new MassTransactorAction.InvocableApexAsyncBatchRequest();
flowRequest.BatchSize = 2220;
flowRequest.OperationType = 'Delete';
flowRequest.RequestList = accounts;
flowRequests.add(flowRequest);
Test.startTest();
MassTransactorAction.InvocableApexCreateAsyncController(flowRequests);
Test.stopTest();
}
@IsTest
// Test creating some records where records already exist
static void testBatchWrongDMLCreate(){
List<Account> accounts = [SELECT Id from Account Where Name like '%Account%'];
List<MassTransactorAction.InvocableApexAsyncBatchRequest> flowRequests = new List<MassTransactorAction.InvocableApexAsyncBatchRequest>();
MassTransactorAction.InvocableApexAsyncBatchRequest flowRequest = new MassTransactorAction.InvocableApexAsyncBatchRequest();
flowRequest.BatchSize = 200;
flowRequest.OperationType = 'Create';
flowRequest.RequestList = accounts;
flowRequests.add(flowRequest);
Test.startTest();
MassTransactorAction.InvocableApexCreateAsyncController(flowRequests);
Test.stopTest();
}
@IsTest
// Test creating some records where records dont exist
static void testBatchWrongDMLDelete(){
List<Account> accounts = new List<Account>();
// insert 10 accounts
for (Integer i=0;i<10;i++) {
accounts.add(new Account(name='Account '+i,
billingcity='New York',
billingcountry='USA',
billingState = 'Virginia',
billingPostalCode = '23113',
BillingStreet = '12345 Hello Lane'));
}
List<MassTransactorAction.InvocableApexAsyncBatchRequest> flowRequests = new List<MassTransactorAction.InvocableApexAsyncBatchRequest>();
MassTransactorAction.InvocableApexAsyncBatchRequest flowRequest = new MassTransactorAction.InvocableApexAsyncBatchRequest();
flowRequest.BatchSize = 200;
flowRequest.OperationType = 'Delete';
flowRequest.RequestList = accounts;
flowRequests.add(flowRequest);
Test.startTest();
MassTransactorAction.InvocableApexCreateAsyncController(flowRequests);
Test.stopTest();
}

@IsTest
// Test creating some records where records dont exist
static void testBatchNull(){
List<Account> accounts = new List<Account>();
List<MassTransactorAction.InvocableApexAsyncBatchRequest> flowRequests = new List<MassTransactorAction.InvocableApexAsyncBatchRequest>();
MassTransactorAction.InvocableApexAsyncBatchRequest flowRequest = new MassTransactorAction.InvocableApexAsyncBatchRequest();
flowRequest.BatchSize = 200;
flowRequest.OperationType = 'Delete';
flowRequest.RequestList = accounts;
flowRequests.add(flowRequest);
Test.startTest();
MassTransactorAction.InvocableApexCreateAsyncController(flowRequests);
Test.stopTest();
}
}

+ 5
- 0
force-app/main/default/classes/MassTransactorActionTest.cls-meta.xml View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>49.0</apiVersion>
<status>Active</status>
</ApexClass>

+ 119
- 0
force-app/main/default/classes/MassTransactorBatchHelper.cls View File

@@ -0,0 +1,119 @@
/**
* @description : Invocable for doing large batch DML from Flow and specifies a batch. Use the MassTransactorActionTest class to test this
* @author : Matt Comer, CapTech Consulting
* @group :
* @last modified on :
* @last modified by :
* Modifications Log
* Ver Date Author Modification
* 1.0 08-19-2020 Matt Comer Initial Version
* 1.1 08-20-2020 Adan White Added email inputs / send on complete
**/
public with sharing class MassTransactorBatchHelper implements Database.Batchable<SObject>, Database.Stateful {
public enum OperationType {DO_INSERT, DO_UPDATE, DO_UPSERT, DO_DELETE}
private List<SObject> records;
private OperationType action;
private String emailTo;
private String subject;
private String body;
public class ListIterator implements Iterator<SObject> {
private List<SObject> records;
Integer index;
public ListIterator(List<SObject> records) {
this.records = records;
index = 0;
}
public boolean hasNext() {
return (index < records.size());
}
public SObject next() {
if (index == records.size()) {return null;}
index++;
return records[index - 1];
}
}

public class ListIterable implements Iterable<SObject> {
private List<SObject> records;
public ListIterable(List<SObject> records) {
this.records = records;
}
public Iterator<SObject> Iterator(){
return new ListIterator(records);
}
}
public MassTransactorBatchHelper(List<SObject> records, OperationType action) {
this.records = records;
this.action = action;
}

public MassTransactorBatchHelper(List<SObject> records, String actionIn, String emailTo, String subj, String bod) {
this.records = records;
String a = actionIn.toUpperCase();
this.emailTo = emailto;
this.subject = subj;
this.body = bod;

if (a == 'CREATE') {
this.action = OperationType.DO_INSERT;
} else if (a == 'UPDATE') {
this.action = OperationType.DO_UPDATE;
} else if (a == 'UPSERT') {
this.action = OperationType.DO_UPSERT;
} else if (a == 'DELETE') {
this.action = OperationType.DO_DELETE;
}
}

public System.Iterable<SObject> start(Database.BatchableContext ctx) {
return new ListIterable(records);
}
public void execute(Database.BatchableContext ctx, List<SObject> records) {
// fix problem with picklist field values which can occur in async context (seems to be due to serialization / storage of state)
if (action != OperationType.DO_DELETE) {
Map<String, Schema.SObjectField> sObjectFieldsMap = Schema.describeSObjects(new List<String> { records[0].getSObjectType().getDescribe().getName() })[0].fields.getMap();
for (SObject o: records) {
for (String fieldName : o.getPopulatedFieldsAsMap().keySet()) {
Schema.DisplayType dt = sObjectFieldsMap.get(fieldName).getDescribe().getType();
if ((dt == Schema.DisplayType.PICKLIST || dt == Schema.DisplayType.MULTIPICKLIST) &&
String.valueOf(o.get(fieldName)) != null ) {
o.put(fieldName, String.valueOf(o.get(fieldName)).replace('[', '').replace(']', ''));
}
}
}
}
switch on action {
when DO_INSERT {
Database.insert(records, false);
}
when DO_UPDATE {
Database.update(records, false);
}
when DO_UPSERT {
Database.upsert(records, false);
}
when DO_DELETE {
Database.delete(records, false);
}
}
}

public void finish(Database.BatchableContext ctx) {
If(this.emailTo != null && this.subject != null && this.body != null) {
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new List<String>();
toAddresses.add(this.emailTo);
mail.setToAddresses(toAddresses);
mail.setSubject(this.subject);
mail.setPlainTextBody(this.body);

Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
}

+ 5
- 0
force-app/main/default/classes/MassTransactorBatchHelper.cls-meta.xml View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>49.0</apiVersion>
<status>Active</status>
</ApexClass>

+ 41
- 0
package.json View File

@@ -0,0 +1,41 @@
{
"name": "salesforce-app",
"private": true,
"version": "1.0.0",
"description": "Salesforce App",
"scripts": {
"lint": "npm run lint:lwc && npm run lint:aura",
"lint:aura": "eslint **/aura/**",
"lint:lwc": "eslint **/lwc/**",
"test": "npm run test:unit",
"test:unit": "sfdx-lwc-jest",
"test:unit:watch": "sfdx-lwc-jest --watch",
"test:unit:debug": "sfdx-lwc-jest --debug",
"test:unit:coverage": "sfdx-lwc-jest --coverage",
"prettier": "prettier --write \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
"prettier:verify": "prettier --list-different \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\""
},
"devDependencies": {
"@prettier/plugin-xml": "^0.10.0",
"@salesforce/eslint-config-lwc": "^0.7.0",
"@salesforce/eslint-plugin-aura": "^1.4.0",
"@salesforce/sfdx-lwc-jest": "^0.9.2",
"eslint": "^7.6.0",
"eslint-config-prettier": "^6.11.0",
"husky": "^4.2.1",
"lint-staged": "^10.0.7",
"prettier": "^2.0.5",
"prettier-plugin-apex": "^1.6.0"
},
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}": [
"prettier --write"
],
"**/{aura|lwc}/**": ["eslint"]
}
}

+ 11
- 0
sfdx-project.json View File

@@ -0,0 +1,11 @@
{
"packageDirectories": [
{
"path": "force-app",
"default": true
}
],
"namespace": "",
"sfdcLoginUrl": "https://login.salesforce.com",
"sourceApiVersion": "49.0"
}

Loading…
Cancel
Save