Showing posts with label admin. Show all posts
Showing posts with label admin. Show all posts

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..


Thursday, August 13, 2020

Passing parameters to Custom Label in Apex

Custom labels enable developers to create multilingual applications by automatically presenting information (for example, help text or error messages) in a user’s native language. Custom labels are custom text values that can be accessed from Apex classes, Visualforce pages, or Lightning components. The values can be translated into any language Salesforce supports. (more here: https://help.salesforce.com/articleView?id=cl_about.htm&type=5)

But what if we want to be able to add dynamic Custom Label in APEX? Instead of concatenating several labels and dynamic variables, this can be achieved using a single Custom Label.

Example: Account Spoon Consulting Ltd has 130 contacts and 300 opportunities.

In the above label, the account name, contact amount and opportunity amount are dynamic values which have been fetched from the Account record. 

Here is how the label will look after adding the merge parameters: 
Account {0} has {1} contacts and {2} opportunities.

Syntax to reference a Custom Label in Apex: 
System.Label.AccountSummary

Below is how we replace the merge fields in the custom labels:
String.format(System.Label.AccountSummary, 
   new List<Object>{ 'Spoon Consulting Ltd', 130, 300 });
Output: 

Using the above method, you can easily add translation to the label and fully customizable in any language without the need to modify the code. 

Hope this article was useful to you. 

Cheers :)

Saturday, March 9, 2019

Converting a DateTime field into a Unix Timestamp with formula field

In this episode, we will show you have you can easily convert a date time field value to an Epoch/Unix Timestamp using Salesforce formula field.

First, you need a field of type DateTime such as CreatedDate, LastModifiedDate or any Custom Field.

In our example, we will use the CreatedDate Field. The formula is as below.

(CreatedDate - DATETIMEVALUE( "1970-01-01 00:00:00" )) * 86400



This can be used to append to a image url to prevent image cache from browser.

Tuesday, November 28, 2017

Customize Salesforce App Navigation Menu to have SObject item on Top

Salesforce mobile App, formerly known as Salesforce1, provides you with limited options regarding customization of the menu item. You can only add the following items:
  • Salesforce productivity items such as Dashboards, Reports, Tasks, ...
  • Smarch Search Items
  • Visualforce tabs
  • Lightning Page tabs
The rest of the menu depends on the tabs you are allowed to interact and view on your Salesforce. Most of them would be Standard and Custom objects. And according to what Application you have opened, the mobile app will have the same menu.


But sometimes we would like some of our Object menu to be on top in the main menu instead in the recent section. Also to be able to interact as if it was the standard view.
This can easily be done with a few lines of code and some configuration. For this example, we shall use the Opportunity object.

First, we need to create a Lightning Component. We shall name it "OpportunityMenu". Below are the code needed. Change the "scope" according to the SObject you want.

Now we need to add a new Lightning Component Tab.

Once the custom tab has been created, we can configure the Salesforce mobile Navigation menu and add the Opportunity menu.

Reload your Salesforce App and voila..


Standard Listview layout appears

Additional Resources:
({ navHome : function (component, event, helper) { var homeEvent = $A.get("e.force:navigateToObjectHome"); homeEvent.setParams({ "scope": "Opportunity" }); <aura:component implements="force:appHostable"> <aura:dependency resource="markup://force:navigateToSObject" type="EVENT"/> <aura:handler name="init" value="{!this}" action="{!c.navHome}"/> </aura:component>

Tuesday, May 16, 2017

Automatic package license assignment to Users

We have been asked by one of our customer at SharinPix if it was possible to assign Licenses to newly created user automatically and removing the license on user upon deactivation. The solution that I was asked to do was a trigger. But this solution requires coding which will require a test class, changeset for deployment, giving user permission to execute the trigger which it quite a lot to do. In case something is wrong with the trigger, we will be required to modify on the customer sandbox and deploying again, which is kind of tedious. 

But recently I did a module on Trailhead about Process Automation which explain how to achieve complex logic without having the need to write a single piece of Apex Code. It is only by configuring Flows and Process Builders. 

Here is the solution for the above requirement

The following objects will be used to automate assigning user license: 

Below are the steps to create a Flow and Process Builder.

Flow


1. Go to Setup, Search Flows from the Quick Find textbox
2. Click on New Flow, the Flow Designer will open. 
On the left sidebar, click on the tab Resources. Create two variables var_UserId of type text and var_isNew which will store the package license id and the user id. See screenshot below. 

Variable User Id

Variable IsNew
Create a third variable of type SObject variable. Name is SharinPixLicense and Object Type is PackageLicense.

SharinPix License sobject variable

3. We now need to retrieve the Id of the license for the SharinPix package. Drag and drop a Record Lookup element to the canvas. Enter a name and insert the following properties: 
  • Look up: PackageLicense
  • Field: NamespacePrefix, Operator: 'equals', Value: 'sharinpix' (The namespace prefix of the package: Setup | Build | Installed Packages)
  • Variable assignment 
    • Field: Id, Variable: '{!SharinPixLicense.Id}'
    • Field: AllowedLicenses, Variable: '{!SharinPixLicense.AllowedLicenses}'
    • Field: UsedLicenses, Variable: '{!SharinPixLicense.UsedLicenses}'





4. Drag and drop the Record Create element to the canvas. Enter a name and insert the following properties: 
  • Create: UserPackageLicense
  • Field: PackageLicenseId, Value: {!SharinPixLicense.Id}
  • Field: UserId, Value: {!var_UserId} 
Assign license to user


Now that we have the create record, we now need to have the delete license equivalent

5. Drag and drop the Record Delete element. Enter a name and the following properties
  • Delete: UserPackageLicense
  • Field: UserId, Value: {!var_UserId} 
  • Field: PackageLicenseId, Value: {!SharinPixLicense.Id}
Remove license from user

6. Let's create the logic and assemble all the component. 
Drag and drop the Decision element on the canvas. Enter a name and create two outcomes
  • Outcome 1 
    • Name: Created
    • Resource: {!var_isNew}, Operator: equals, Value: {!$GlobalConstant.True}
    • Resource: {!SharinPixLicense.UsedLicenses}, Operator: less than, Value: {!SharinPixLicense.AllowedLicenses}
Note: I have added the condition that Used licenses should be less than Allowed Licenses in order for the flow not to crash if all licenses have been used. 
  • Outcome 2
    • Name: Deleted
    • Resource: {!var_isNew}, Operator: equals, Value: {!$GlobalConstant.False}



7. Link the component same as in the image below and set the Record Lookup as the start of the flow (click on the green arrow icon)
Wrap everything

8. Save your Flow with a name, select type Autolaunched Flow and activate it once done. 
Save flow

Process Builder


Now that our flow is completed. We need to trigger the flow and we will use a process builder to do that.

1. Go to Setup | App Setup | Create | Workflows & Approvals | Process Builder
Click on the New button, Enter the Process Name and API Name and click on Save button.
New Process

2. We need to trigger the process on a specific Object. For this, click on Add Object and in the properties, select User and select when a record is created or edited. Click on Save.
Entry criteria

3. Next step is to add the Process Criterias. In our case, we will have two criteria. One will cater for new user and the other one for user which has been deactivated.
  • Let's create the first one. Click on Add Criteria
    • Criteria Name: User is active
    • Select Formula evaluates to true
    • In the formula field, insert the following formula
      • ( ISNEW() && [User].IsActive ) || ( ISCHANGED([User].IsActive) &&  [User].IsActive )
Save the criteria
New user active or update a user to active

  • Let's create the first one. Click on Add Criteria
    • Criteria Name: User is not active
    • Select Formula evaluates to true
    • In the formula field, insert the following formula
      • ( ISCHANGED([User].IsActive) && NOT( [User].IsActive ))
Save the criteria 


4. Now we add the actions for each criteria. 
For the User is active criteria. In the Intermediate Action section, click Add Action with the following properties:
  • Action Type: Flows
  • Action name: Create License
  • Flow: Automatic Package License assignment (Yours may be under a different name)
  • Set Flow Variables
    • Flow Variable: var_UserId, Type: Reference, Value: [User].Id
    • Flow Variable: var_isNew, Type: Boolean, Value: True

5. Let's repeat step 4 for the User is not active criteria. Change the Action Name to Delete License and set the flow variable var_isNew to False.

Your process builder should look like below. 
Finally, Click on Activate to enable it. 



Every new user shall be affected a License to the package and user being deactivated will have their license removed. 

Do not hesitate to contact me in case something is missing or needs improvements. 

Cheers :)

Tuesday, February 14, 2017

Using Salesforce standard modal in a Detail page button - Part 1

Tired of having to use window.open in a detail page button to display a popup? Or using JavaScript libraries to display a modal?
Well, there is a more simple way to display a popup and this without embedding any JavaScript library in the code.

This can be achieved by using Salesforce standard modal and by tweaking the code, many things can be achieved.

To get started, Create a Custom button on the object you want the modal to be used.
Set the properties to:
Display Type: Detail Page Button
Behavior: Execute JavaScript
Content Source: OnClick JavaScript

custom button salesforce

In the JavaScript code editor, add the following code and change the variables inside it accordingly to your specification.

Here is the final result:

Check out part 2. We shall discuss how to integrate Visualforce pages inside the modal.

Cheers! :)
(function() { var width = 700; var height = 200; var title = "Dialog title here"; var box = new SimpleDialog("salesforce" + Math.random(), true); box.setTitle(title); box.displayX = true; box.isMovable = false; box.createDialog(); box.setWidth(width); // set your html content here box.setContentInnerHTML( "<h2>Your html content here</h2>" ); //set the height of the modal box.dialog.children[1].style.height = height + 'px'; box.show(); //if displayX is set to true, then override standard close event by this code box.dialog.getElementsByClassName('dialogClose')[0].onclick = function() { box.hide(); // you can add code to reload the page or redirect to another page }; //optional : add this to close the modal onclick of the overlay background box.background.addEventListener('click', function() { box.hide(); }); })();