Showing posts with label developer. Show all posts
Showing posts with label developer. Show all posts

Saturday, April 17, 2021

Upload Content Document with custom field populated from a Visualforce page

In a previous post, we looked at how to upload files as attachment without exceeding heap size governor limit. Link to post: https://blog.moothien.me/2017/05/upload-attachment-to-salesforce-without.html

However, most implementation nowadays make use of Content Document to store files since the Spring '16 rollout. 

Here I will show you how to upload file to Salesforce as Content Document attached to a record. At the same time, you will also be able to populate fields (standard and custom) on the Content Version record. 

First of all, let's take a look at the data model for Content Document. 


As you can see in the ERD above, the process of creating a Content Document is a bit different. The object Content Document cannot be created on its own, a Content Version needs to be uploaded first. This process will automatically create the Content Document. Now, to link the Content Document to the your record, a Content Document Link needs to be created which will store the relationship between your record and the uploaded file. 

This requires at least three APIs call to Upload: 

  1. upload a file will create a Content Version and will return the Id of the Content Version
  2. Use this Id to get the Content Document Id which has been auto created
  3. Use the Content Document Id and create a Content Document Link which relates to your record
Luckily for us, Salesforce has a special type of API request named Composite Resources which can execute Dependent Requests in a Single API Call. (Read more about Composite Resources here: https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/using_composite_resources.htm)

Here is how the composite resource body is built and where to populate the custom field.


In the payload, you will notice a key referenceId. It will create a variable with this name and will be populated with the response of the current request, which can then be used to sub request.


Composite resource makes use of the following endpoint '/services/data/v51.0/composite'. A session Id is also required to authenticate the request. 

Here is the full code:



Demo

Upload a file with custom attributes


The result on Salesforce


Resources:


Thursday, October 29, 2020

Getting Started with Salesforce Einstein Vision OCR (tabular model) - Part 2

In the previous Einstein Vision OCR blog post, we took a look at setting up Einstein Vision and viewed a sample usage with Business card. Click here if you missed it. 

In this post, we shall see the other version of the OCR which is reading tabular format image. E.g Balance sheet, excel screen capture, inventory list, etc...

Official Einstein Vision Tabular documentation here: https://metamind.readme.io/docs/detect-text-and-tables

I have created a sample code which will call the tabular model and from the predicted result, I built a html table which is being displayed right away in your Salesforce.

Demo screenshot


Here is a demo video:


Technical details about the prediction result: 

  • the recognized label will contain a cellLocation with rowIndex and colIndex. 
  • use the rowIndex and colIndex to map it on a two dimensional array 
  • then build the html table with tr and td
    • tr - for each row
    • td - for each column

Here are some use cases where it can be useful:
  • You need to digitalize all paper work tabular transaction, just scan it and let Einstein do the rest.
  • scan you sheets and display form for a data entry to validate and correct where necessary. This will save time during data entry


In the next post, we shall talk about the Einstein Vision Retail Execution API. Stay tuned.

Cheers..


Friday, April 24, 2020

Dynamically access any variable in an instance class

In this blog post, I will show you how to access any variable on an instance of an Apex class dynamically.

This is something useful when you want to make dynamic feature which are based on setting, especialy when doing ISV stuffs.

The code is as simple as below:

public class Employee {
    public String employeeId;
    public String firstname;
    public String lastname;
    public String username;
    public String profileUrl;

    public Object getValue(String variableName) {
        String jsonString = toJSON();
        Map<String, Object> untyped_instance;
        untyped_instance = 
            (Map<String, Object>)JSON.deserializeUntyped(jsonString);
        return untyped_instance.get(variableName);
    }
    
    public string toJSON() {
        return JSON.serialize(this);
    }
}

Example:

Employee emp = new Employee();
emp.employeeId = 'test';
emp.firstname = 'kevan';
emp.lastname = 'moothien';
emp.username = 'kevanmoothien';
emp.profileUrl = 'https://picsum.photos/200/300';

system.debug(emp.getValue('firstname')); // returns kevan
system.debug(emp.getValue('lastname')); // returns moothien

Here is a use case where this kind of integration can be used based on the above code.
Suppose you have to develop a custom related list lightning component which would be used on several layout. But on each layout, it has to display different columns.

To achieve this, we would think of different component and hardcoded variable. But, this can be done by simply having a Custom Metadata type to save the setting of each layout and the related list custom component can simply display the columns value dynamically using the above code based on the setting provided in the Lighting app builder.

Hope this is useful to you trailblazers.

Cheers :)

Monday, December 3, 2018

Mock HTTP callouts in a Managed Package


In this blog, I will show you how to mock callout response which is in a managed package.


I found out that many developers are using Test.IsRunningTest() in their Apex classes to avoid writing Mock responses for http callouts and if the callout comes from a Managed Package, they are stuck with this message "Methods defined as TestMethod do not support Web service callouts".

As per Salesforce Documentation, "To mock a callout if the code that performs the callout is in a managed package, call Test.setMock from a test method in the same package with the same namespace."

So to be able to mock callout which is performed in a managed package, the line doing "Test.setMock" should be called from the managed package itself.

So what we did in the SharinPix (ISV) managed package, we added a global class which take a HttpCalloutMock class as parameter and execute the Test.setMock from within the package.

@isTest
global class HttpCalloutSimulator {
    global static void setMock(HttpCalloutMock mock) {
        Test.setMock(HttpCalloutMock.class, mock);
    }
}

By adding the above class in your package and making it global so that it ca be called outside the managed package make it easy to mock code which are doing callout in your package without getting error messages.

You will just need to call it as below:

[namespace].HttpCalloutSimulator.setMock(mock);

Example on how to use it:

sharinpix.HttpCalloutSimulator.setMock(HttpCalloutMock mock);  
//where the variable mock is the instance of your HttpCalloutMock class

Links: 

Saturday, December 1, 2018

What is Remote Action in Salesforce?

In this blog, we will learn how to use Remote Actions in Visualforce Page.

But what is a Remote Action? 


Remote Action is a way to access Apex method using Javascript in your Visualforce page.
It allows you to create pages with complex, dynamic behavior that isn’t possible with the standard Visualforce AJAX components.

Remote action method should always have the @RemoteAction annotation and it should be Static.

Let's take an example where we need to retrieve the first five Cases with Status to New.



Output:

Point to remember:

  • @RemoteAction annotation is mandatory
  • Remote Action methods should always be static
  • If you are using the Visualforce Page inline in a Page Layout, then the method should be declared as global instead of public

Saturday, April 1, 2017

Detect if visualforce is inline on a page layout from its apex controller

This tutorial will explain to you on how to detect if a visualforce page is embedded inside of a detail page layout.

To be able to detect if a VF is being on a page layout in an inline section from a custom apex controller. The following code needs to be implemented. You can tweak around the code to mean your requirement.


Moreover you can use the very same Visualforce to override buttons like "New" and "Edit" so that you can have only one Visualforce page to for different operation like creation of a new record or editing the record.

public class CheckState {
    public String vfMode {get; set;}
    private Map<String, String> urlparams = new Map<String, String>();
    public CheckState(ApexPages.StandardController std){
        urlparams = ApexPages.currentPage().getParameters();
        if (urlparams.get('id') == null){
            vfMode = 'New';
        } else if (urlparams.get('id') != null & urlparams.get('retURL') != null) {
            vfMode = 'Edit';
        } else if (urlparams.get('id') != null & urlparams.get('retURL') == null){
            vfMode = 'View';
        }
    }
}

Sunday, February 12, 2017

Introduction to Apex

Each year we are having struggle training fresh graduate from the University into learning the basic of Salesforce Apex programming language. They mixed up the syntax with what Java would look like.
So we came up with a list of things that would speed up the process of training.

Here's a list of the commonly used syntax in Apex and restrictions:

Hope this tutorial is useful to you.

Cheers!

# Intro to apex

## Basic operation
``` java
//variable declaration
Integer val = 0;
string str = 'Super test'; // apex allow only single quote for string variable
boolean isDeleted = true;

/*Concatenate string*/
string firstname = 'John';
string lastname = 'Doe';
string name = firstname + ' ' +  lastname;
```

## Debug Apex code
``` java
string name = 'Super test';
system.debug('### '+name); // ### Super test

```

## Collection
A collection in apex is either a "List", "Set" or a "Map"

``` java
/**
* List
*/
//Populating method 1
list<string> carList = new list<string>();  //initializing an empty list
/*Populating the list*/
carList.add('Honda');
carList.add('Toyota');
carList.add('Mazda');

//Populating method 2
list<string> carList = new list<string>{'BMW', 'Mercedes', 'Audi'};

/**
* Set
*/
set<string> referenceSet = new set<string>();
referenceSet.add('test');
//or
set<string> referenceSet = new set<string>{'test'};

/**
* Map
* A map consists of a key and value. The key should always be a primitive type (string, integer, id, ...).
*/
map<string, string> countryCodeMap = new map<string, string>(); //initiliazing an empty map
//Populating a map
countryCodeMap.put('Mauritius', 'MU');
countryCodeMap.put('France', 'FR');
//or
map<string, string> countryCodeMap = new map<string, string>{'Mauritius'=>'MU', 'France'=>'FR'};

//accessing a value for a specific key in the map
string franceCode = countryCodeMap.get('France'); //returns FR
```

## sObject
Any standard and custom object in Salesforce is represented as an sObject in Apex.

Example

| Object type | Name     | Api name (as represented in apex) |
| ----------- | ---------- | ----------------------------------- |
| Standard | Account  | Account |
| Standard | Contact | Contact |
| Custom | Car | Car__c |
| Custom | Job | Job__c |

``` java
//Create a new instance of an sObject
Contact con1 = new Contact(); //initializing an instance of a contact
con1.Firstname = 'Jane';
con1.Lastname = 'Doe';

// or
Contact con1 = new Contact(Firstname='Jane', Lastname='Doe');

/*custom object*/
Job__c job = new Job__c();

//creating an instance of an existing record
Account salesFr = new Account(Id='0012400000YwpHM'); //you just need to instantiate with the field "Id"

```

### Note
A lookup or master-detail relationship fields in apex is represented by an Id.

## DML
DML operations consists of:
- insert
- update
- upsert
- delete
- undelete
- merge

### Insert
```java
Account telecom = new Account(Name='Telecom');
insert telecom;
```
### Update
```java
telecom.Name = 'Telecom - Head office';
update telecom;
```
### Upsert
It does an insert if record not found else update if found.
Generally use with an ExternalId (a flag on a field to make it an index)
```java
//account does not exist
Account sbm = new Account(Name='SBM');
upsert sbm; // will create an account with Name = SBM
//account exist
Account sbm = new Account(Id='0012400000YwpHM', Name='SBM - Closed');
upsert sbm; // will update with Name = 'SBM - Closed'

//update a contact based on its external id (here Email is defined as external id)
Contact con1 = new Contact(Email='plop@test.com', Lastname='Plop');
upsert con1 Contact.Email;
```
### Delete and Undelete
Can only delete instance which contains an Id.
```java
Account sbm = new Account(Id='0012400000YwpHM');
delete sbm;

undelete sbm;
```

## SOQL queries
SOQL query will always return the following:
- an sobject
- a list of sobjects
- a list of objects

### Basic query
```java
//Returning only one record
Contact jane = [SELECT Id, Firstname, Lastname FROM Contact WHERE Id = '0032400000GRVvY'];

//returning a list of record
list<Account> accountList = [SELECT Id, Name FROM Account];
```
### Advanced query
```java
// returning a list of contact with their account name
list<Contact> contactList = [SELECT Id,
                                    Firstname,
                                    Lastname,
                                    Account.Name
                            FROM Contact
                            WHERE AccountId != null];

// returning list of account with their children(contacts)
list<Account> accountList = [SELECT Id, Name,
                                (SELECT Id, Firstname, Lastname from Contacts)
                            FROM Account];
```
Notice that the child relationship is in plural.
If a custom object was used here
- parent relationship: objectName**__r**
- child relationship: objectName**s__r**


## Loops
``` java
for(integer i = 0; i < size; i++){
  // code here
}

/*Example*/
list<string> firstnames = new list<string>{'John', 'Jane'};
list<string> lastnames = new list<string>{'Smith', 'Doe'};
list<string> names= new list<string>();
for(integer i = 0; i < firstnames.size(); i++){
  string name = firstnames[i] + ' ' + lastnames[i];
  names.add(name);
}

//or
for(type variable: list<type>){
  //do any operation with variable
}

/*Examples*/
integer total = 0;
list<Account> accountList = [SELECT id, NumberOfEmployees FROM Account];
for(Account acc: accountList){
  if (acc.NumberOfEmployees != null){
    total = total + acc.NumberOfEmployees;
  }
}

```

## Classes and Methods
``` java
public class Employee {
  public string name;
  public integer age;
  public datetime arrivedAt;
  public Employee(){
  }
  public void checkIn(){
    //void just do the action
    arrivedAt = System.now();
  }
  public boolean shouldRetire(){
    integer diff = 65 - age;
    if (diff <= 0){
      return true;
    }
    return false;
  }
  public static integer numEmployees(){
    list<Employee__c> employees = [select id from Employee__c];
    return employees.size();
  }
}

//Creating an instance of employee
Employee emp = new Employee();
emp.name = 'john';
emp.age = 30;
//call checkIn method for the employee
emp.checkIn(); // void method do the action only
retired = emp.shouldRetire(); // non void method should return a value

//Calling static methods
Employee.numEmployees();
```