Pages

Thursday, December 7, 2023

Understanding complex Salesforce customization

Every Salesforce org is different, and as a Salesforce admin or developer, you may inherit the customization built by a team or consulting company that is no longer engaged, and worse, there is no good documentation available.

Panaya has released an AI-powered solution, helping Salesforce professionals understand complex customization by translating them into simple language.

The tool can also copy the explanation and use it to create documentation. The solution supports the following component types: Apex Code, Validation Rules, Formulas, and Flows.

Check out this link for more info.



Thursday, November 30, 2023

CRM Analytics: URL tips

In scenarios when we can't open a dashboard or dataset via "click", here are some shortcuts.

Open Dashboard JSON Editor

Add "/json" at the end of the Dashboard Id, e.g., https://domain.lightning.force.com/analytics/dashboard/0FK34000000KzniGAC/json


Explore Dataset 

https://domain.lightning.force.com/analytics/lens/new1/dataset/0FbHr000000dSdAKAU
If you are wondering what "new1" is, you can change it to new2 or new3, etc.


Edit Dataset

https://domain.lightning.force.com/analytics/dataset/0FbHr000000dSdAKAU
or 
https://domain.lightning.force.com/0FbHr000000dSdAKAU  This will be translated as https://domain.lightning.force.com/lightning/r/EdgeMart/0FbHr000000dSdAKAU/view


Reference

Tuesday, November 28, 2023

Salesforce: Reason for Access in Sharing

In an old blog written many years back, you can check the reason for access of a record to a user using the Sharing button. There is a slight difference in information given in Classic compared to Lightning.

Classic:
https://domain.my.salesforce.com/setup/own/entitywhylist.jsp?id=0060o00001TvlTM&uid=00590000000Ougm


Lightning:
https://domain.lightning.force.com/lightning/r/Opportunity/0060o00001TvlTMAAZ/recordShareHierarchy?userId=00590000000OugmAAC


Classic does not tell you which sharing rule, but only "Shared With". Lightning does better with the Rule Name, but in the above sample, the rule name is not very helpful "This_is_test".


The Sharing Rule

Let's look at the sharing rule; for the below example, since there's only one sharing rule with "Shared With" to a specific group, we can identify the sharing rule quickly, but if there are many, we need to click edit to each rule to see the rule name. 



The rule name will only be visible by clicking the "Edit" link.



Is there an easy way to find the rule? 
Yes, you can download the metadata, e.g., using Salesforce Inspector or Workbench. 

    <sharingCriteriaRules>
        <fullName>This_is_Test</fullName>
        <accessLevel>Read</accessLevel>
        <label>This is Test</label>
        <sharedTo>
            <group>Group_Staff_2B</group>
        </sharedTo>
        <criteriaItems>
            <field>FieldName</field>
            <operation>notEqual</operation>
            <value>CH1,SG1</value>
        </criteriaItems>
        <includeRecordsOwnedByAll>true</includeRecordsOwnedByAll>
    </sharingCriteriaRules>



Reference:





Saturday, November 25, 2023

Image Upload on Salesforce: The Capabilities and Limitations

Are you already using images on Salesforce? If not, you should be, as making your Salesforce more visual has benefits that exceed simple time saving and productivity increases. Image usage can empower your end users to do their jobs in the most effective way possible.

Here's how you can upload images natively in Salesforce:

1. Uploading files through standard buttons (and in Flows)

The standard “Upload File” button under the “Notes and Attachments” section can be used to upload images to Salesforce.

Additionally, the same function exists as a lightning component so that file (and image) upload can be used as a part of flows or self-developed screens. Through this method, you can add an Upload button to any of your flow screens.


2. Working with Images in Rich Text Fields

It is possible to upload pictures to the rich text field in Salesforce, the process is very easy, and the image is stored as a content document that will appear as a visual in the rich text field.


3. Take pictures and upload from your mobile device

The upload file and add images in rich text are also available on mobile. Doing so, lets you allow your users to open their device camera or device camera roll on either iOS or Android from their Salesforce mobile application. They can then snap photos and upload them directly to Salesforce. But also pick any pictures already taken from the camera roll to upload.

A component named Upload image and annotate is a good demonstration of what a developer can do in Field Service using the latest API available. As of now, this is only limited to being used from the menu item and is not applicable to flow. And only to be used by developers as it is only available as a source code as of now.


What are the limitations with uploading images in Salesforce?

While the Salesforce stock methods for uploading images may be suitable for you depending on your use case, there are limits for those who need to make frequent or heavy image photo uploads. Here are the principal limits for image upload in base Salesforce:

1. Rich text field upload limit

When you upload an image through the rich text field, it’s saved in the rich text data as a file, this file storage is limited to 1 megabit per image. This is a huge limitation for the type of image you can have based on file size and quality. That limit is especially hindering for users who use pictures taken from a mobile device, which naturally exceeds this limit.

 To put this in perspective, the average size of a photo captured with a newer iPhone is around 3 MB. If your end users are trying to upload files of this size, they will hit a roadblock that looks like this within Salesforce:

If you need to upload large images of any size or format and need them inserted in the rich text field, SharinPix has the solution for storing and presenting the image in the rich text field. 


2. Android upload limit

Many people in the USA are using Apple products for both their computer and cellphone needs, and those people as Salesforce users won’t have any problems uploading multiple images to Salesforce from their IOS devices. But it’s not always a guarantee that the users operating in your org will have an iPhone or an iPad at their disposal. 

For Android device users, even simply uploading photos is an incredibly time-consuming task. The current version of APIs used by the Salesforce Mobile App blocks Android devices from uploading multiple images from the camera roll at one time. This problem could be solved in the future through updates, but for now, it’s still a roadblock for Android users.

Take a look at these side-by-side screenshot examples of the experience on IOS versus Android for uploading multiple images to Salesforce:


3. Metadata is not available

With the standard upload methods in Salesforce (add file button, file upload component, rich text field, or otherwise), you don’t have access to some crucial information in the metadata by default. These data can be extracted or included with image upload using dev tricks with an external API, but it’s extra manual work.

These limitations exist because of concerns about technological privacy, where users don’t want data (location, date, time, etc.) associated with an image. So, operating systems and security services automatically clean this data out before upload.

Even if the data was uploaded along with the image, it wouldn’t be automatically exposed as a field in Salesforce, making it difficult to use efficiently. With the growing strength of AI capabilities today, it’s more important than ever to use metadata such as time and location to verify that an image is genuine and that you can trust the users who provided it.


4. Salesforce storage limitations

Storage costs on Salesforce could pose a huge problem for users who are uploading large amounts of images, regardless of origin. There is technically no limit to how much file storage you can have, but having to constantly increase that amount takes time and communication with Salesforce and can be impossible to accurately predict.


How to make Image usage on Salesforce easy? 

Using photos in Salesforce should be easy, but it’s a complicated headache that will cost you a lot of time and money. SharinPix exists to make it easy! We can help you unlock pro photo usage on Salesforce. SharinPix has everything you need to edit, resize, annotate, and watermark without leaving Salesforce.  


SharinPix will help you operate beyond the limits mentioned in this article as well as the other limits that exist within Salesforce. SharinPix will facilitate image upload on all fronts, allowing bulk uploads through drag and drop with features exposing metadata as usable information in Salesforce.

You can visit the SharinPix AppExchange listing to learn more about the solution or chat with one of our Visual Experts, who will be able to show you exactly how to get the smoothest visual experience in Salesforce. 

 

Author:
Jean-Michel Mougeolle
CEO of SharinPix
Salesforce MVP



Thursday, October 26, 2023

Salesforce: Case Age

In the Salesforce report, we can quickly add the 'Age' field to the report; it is even more flexible, where we can select the "unit" in Minutes, Hours, and Days. But before we discuss this further, let us agree on what is Case Age? 

  • For open cases, the elapsed time from creation to the present
  • For closed cases, the elapsed time from creation to the closing time of the case

Because 'Age' in the report is not an actual field, we cannot show it in the page layout or list view, to get this, we can create a custom Age field with the following formulas:

  • Case Age in Days - IF(IsClosed, ClosedDate - CreatedDate, NOW() - CreatedDate)
  • Case Age in Hours - IF(IsClosed, (ClosedDate - CreatedDate) * 24, (NOW() - CreatedDate) * 24)
  • Case Age in Minutes - IF(IsClosed, (ClosedDate - CreatedDate) * 1440, (NOW() - CreatedDate) * 1440)

But what if we want to exclude the weekends? Here is the formula to calculate case age without weekends in Days:

IF (IsClosed,
IF ((CASE(MOD( Datevalue(CreatedDate) - DATE(1900,1,1),7),
0, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,2,2,3,3,4,4,5,5,5,6,5,1),
1, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,2,2,3,3,4,4,4,5,4,6,5,1),
2, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,2,2,3,3,3,4,3,5,4,6,5,1),
3, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,2,2,2,3,2,4,3,5,4,6,5,1),
4, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,1,2,1,3,2,4,3,5,4,6,5,1),
5, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,0,2,1,3,2,4,3,5,4,6,5,0),
6, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,1,2,2,3,3,4,4,5,5,6,5,0),
999)
+ (FLOOR(( Datevalue(ClosedDate) - Datevalue(CreatedDate))/7)*5)
- 1) < 0,
0,
CASE(MOD( Datevalue(CreatedDate) - DATE(1900,1,1),7),
0, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,2,2,3,3,4,4,5,5,5,6,5,1),
1, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,2,2,3,3,4,4,4,5,4,6,5,1),
2, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,2,2,3,3,3,4,3,5,4,6,5,1),
3, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,2,2,2,3,2,4,3,5,4,6,5,1),
4, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,1,2,1,3,2,4,3,5,4,6,5,1),
5, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,0,2,1,3,2,4,3,5,4,6,5,0),
6, CASE( MOD( Datevalue(ClosedDate) - Datevalue(CreatedDate) ,7),1,1,2,2,3,3,4,4,5,5,6,5,0),
999)
+ (FLOOR(( Datevalue(ClosedDate) - Datevalue(CreatedDate))/7)*5)
- 1),
IF ((CASE(MOD( Datevalue(CreatedDate) - DATE(1900,1,1),7),
0, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,2,2,3,3,4,4,5,5,5,6,5,1),
1, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,2,2,3,3,4,4,4,5,4,6,5,1),
2, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,2,2,3,3,3,4,3,5,4,6,5,1),
3, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,2,2,2,3,2,4,3,5,4,6,5,1),
4, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,1,2,1,3,2,4,3,5,4,6,5,1),
5, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,0,2,1,3,2,4,3,5,4,6,5,0),
6, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,1,2,2,3,3,4,4,5,5,6,5,0),
999)
+ (FLOOR(( Today() - Datevalue(CreatedDate))/7)*5)
- 1) < 0,
0,
CASE(MOD( Datevalue(CreatedDate) - DATE(1900,1,1),7),
0, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,2,2,3,3,4,4,5,5,5,6,5,1),
1, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,2,2,3,3,4,4,4,5,4,6,5,1),
2, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,2,2,3,3,3,4,3,5,4,6,5,1),
3, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,2,2,2,3,2,4,3,5,4,6,5,1),
4, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,1,2,1,3,2,4,3,5,4,6,5,1),
5, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,0,2,1,3,2,4,3,5,4,6,5,0),
6, CASE( MOD( Today() - Datevalue(CreatedDate) ,7),1,1,2,2,3,3,4,4,5,5,6,5,0),
999)
+ (FLOOR(( Today() - Datevalue(CreatedDate))/7)*5)
- 1)
)

Some example: 


Questions:
  • Will the calculation include decimal points for time differences? No, unless someone has an updated formula to include the time
  • Will the calculation honor the user's timezone? Yes, the date is based on your user timezone in Salesforce. For example, user A with Pacific time will see a date time field as "10/01/2021 18:27"; however, user B in Singapore time will see the same data as "1/11/2021 10:27 AM". The formula field calculation will only based on date; therefore, the result of aging between A and B will be one day different. For example, the below case is an open case, and today's date is 3rd Nov 2023.

User A


User B


Note: since this formula field is using the DATEVALUE() formula, if your users are also located in the daylight savings timezone, you need to enable "Improve DATEVALUE() accuracy for DST" under "Company Information" in the setup menu (check out this article); otherwise the calculation for users (with daylight saving timezone) related to processing times between 11:00 PM and 1:00 AM may wrong.


Another sample: 

The report was run on 1-Dec-2023 at 3:23 PM, SGT.

The same report is opened by different users with Pacific time with "Improve DATEVALUE() accuracy for DST" enabled. The current time for this user was 30-Nov-2023 at 11:23 PM PST.

Case 12311766, 12311380, and 12311379 were created on the same day as the current day, 30-Nov-2023, for users in the Pacific time, so those cases' ages (excluding weekends) are 0 days.

Time difference

The above case age calculation will ignore the time of case creation and time of case closed. The following formula will return the time in hours (while ignoring the date) -- result in the number field with 2 decimal points.

(TIMENOW() - TIMEVALUE(CreatedDate))/3600000


The above report is run on 30-Nov-2023 at 4:34 PM:
  • the row 4th from bottom: this is counted between 4:46 PM with 4:34 PM = 23.81
  • the row 3rd from bottom: this is counted between 3:56 PM with 4:34 PM = 0.64
So, this is clear that the dates are simply ignored.


Reference:




Monday, October 23, 2023

CRM Analytics: Salesforce Output Connection

For those who use CRM Analytics, we know that we can use dataflow/recipe to prepare datasets, which means transforming data for use in dashboards. Additionally, using a recipe, you can use the data prepared (with transformed data) to store in Salesforce or another Salesforce org. Imagine that CRM Analytic experts now become a specialist without the need to write scripts for Apex Scheduler.

Push your prepared dataset data into any Salesforce org from CRM Analytics Salesforce Output connector and Data Prep. With your prepared data back in Salesforce, you can integrate external data, apply the suite of Salesforce automation tools to act on the data, and allow non-CRM Analytics users access to the data through reports and dashboards.

Here are the steps:

1. Enable "Enable Salesforce output connection" in the Analytics Setting in the Salesforce setup menu.



2. From Analytics Studio >> Data Manager, create an Output Connection; remember to add the security token after the password and change the Service URL if you plan to test in a sandbox



3. In the recipe Output node, select "Write To" with "Output Connection"; the operation could be Insert, Update, or Upsert. For the update operation, select a field from the destination object for the External ID to act as the unique record identifier, such as an Id from the source object, but it can't be a look field. The system will match using this field to determine if the operation to insert to update.


Scenario: sync a custom object from Account with a lookup field from the custom object to Account. 

As mentioned above, you can't use a lookup field as an External Id, so we need to create a text field to store the Account Id in the target object for matching. 

All columns from the source must be mapped one-to-one to the output object, which also means we can't map the field from the source node twice, so we need to clone the source field in a transform node.

Here is the detail of the Output node in a simple recipe:



External Id is set to the "Account Id (copy)" field, which is a text field in the target object to hold the Id of the Account record.

These are the fields of the target object :



Result after recipe run:




Reference:



Page-level ad