Technical Whitepapers

Zivoke - Top Salesforce Consulting Partner with best in class Salesforce Managed Services, Integration & implementation. We provide Professional services with monthly retainer,On-Demand Support, Salesforce Automation, Service Cloud, Marketing Cloud, Pardot, Experience Cloud, Integration, Data migration and AI.

How to create a Visualforce Page to Generate PDF Invoices and Attach to Related Records

VF Page Code:

Visualforce Page (TaxInvoicePage): This Visualforce page is designed to display invoice details and provide functionality to attach the invoice as a PDF to the related record’s Files section.

  • Standard Controller (Invoice__c): The page is associated with the standard controller for the Invoice__c object, allowing it to access and display invoice details.
  • Extensions (ItemSubmissionInvoiceController): The page is extended by a custom controller ItemSubmissionInvoiceController. This controller handles the logic for generating the PDF and attaching it to the related record.
  • Page Title: The page title is dynamic, showing the invoice name along with the individual or company name based on certain conditions.
  • Google Fonts: The page includes a link to Google Fonts for styling purposes.
  • Navigation and Printing Buttons: There are buttons for navigation, printing, and attaching the PDF. JavaScript functions go_back() and print_page() are defined to handle these actions.

 

VF Page Code

<apex:page standardController=”Invoice__c” extensions=”ItemSubmissionInvoiceController” title=”{!Invoice__c.Name} / {!IF(Invoice__c.Account__r.Individual__c, Invoice__c.Account__r.Individual_First_Name__c +’ ‘+ Invoice__c.Account__r.Individual_Last_Name__c, Invoice__c.Account__r.CR_Official_Name__c)}”>

<apex:form >

<!– Google Font Section –>

<head>

<link rel=”preconnect” href=”https://fonts.gstatic.com” />

<link href=”https://fonts.googleapis.com/css2?family=Arsenal:wght@400;700&display=swap” rel=”stylesheet” />

</head>

 

<!– Navigation and Printing Buttons –>

<div style=”text-align:center;”>

<br />

<script type=”text/javascript”>

function go_back() {

window.history.back();

}

 

function print_page() {

var backButton = document.getElementById(“back”);

var printButton = document.getElementById(“btnprint”);

var header = document.getElementById(“header”);

var footer = document.getElementById(“footer”);

 

// Hide the back button and header

backButton.style.visibility = “hidden”;

header.style.display = “block”;

footer.style.display = “block”;

 

// Print the page

printButton.style.visibility = “hidden”;

window.print();

 

// Show the back button and header again

backButton.style.visibility = “visible”;

header.style.display = “none”;

footer.style.display = “none”;

printButton.style.visibility = “visible”;

// Function to remove currency symbol “BHD” from the value

/*function removeCurrency(value) {

if (value != null) {

return value.replace(‘BHD’, ”);

} else {

return ”;

}

}*/

}

</script>

 

<apex:commandButton value=”Attach PDF” action=”{!attachPDF}” />

<input type=”button” id=”back” value=”Back” onclick=”go_back()” />

<input type=”button” id=”btnprint” value=”Print” onclick=”print_page(), go_back()” />

</div>

VF Page code here….

</apex:page>

 

Controller Class:

Controller Class (ItemSubmissionInvoiceController): This Apex controller handles the backend logic for generating the PDF and attaching it to the related record.

  • Variables:
    • inv: Stores the current Invoice__c record.
    • submissions: Holds a list of related Item_Submission__c records for the invoice.
    • stdController: Reference to the standard controller.
  • Constructor (ItemSubmissionInvoiceController):
    • Initializes the controller with the standard controller and retrieves the current invoice record (inv).
    • Queries related Item_Submission__c records associated with the invoice.
  • Method attachPDF():
    • Generates a PDF blob from the Visualforce page (TaxInvoicePage).
    • Creates a ContentVersion object to store the PDF file as a Salesforce File (ContentVersion).
    • Sets the title of the PDF dynamically based on the invoice name and current date/time.
    • Inserts the ContentVersion into Salesforce Files related to the invoice.
    • Redirects to the invoice record page after attachment.

 

Controller Class with Method

 

public with sharing class ItemSubmissionInvoiceController {

public Invoice__c inv { get; private set; }

public List<Item_Submission__c> submissions { get; set; }

private ApexPages.StandardController stdController;

 

public ItemSubmissionInvoiceController(ApexPages.StandardController stdController) {

this.stdController = stdController;

 

// Get the current “Invoice” record

inv = (Invoice__c) stdController.getRecord();

 

// Query related “Item_Submission__c” records

submissions = [SELECT Name, Take_in_number__c, Report_Type__c, Submitted_Date__c, Product__c, Vat_Amount__c, Total__c, Item_Total__c, Pieces__c, Weight__c,

Units__c, Submission_ID_Backend__c, Description__c, Pro_Strung_Length__c, Pearl_Strung_Rows__c, Pearl_Strung_Detail_List__c, Average_Diameter__c,

Quantity__c, Discount__c, Discount_Amount__c, Duplicate_Report_Price__c, Duplicate_Report_Vat_Amount__c, Duplicate_Report_Price_Item_Total__c,

Remarks__c, Item_Type__c, Items__c

FROM Item_Submission__c WHERE Invoice__c = :inv.Id];

}

 

 public PageReference attachPDF() {

        // Generate PDF content from the Visualforce page

        Blob pdfBlob = Page.TaxInvoicePage.getContentAsPDF();

    

        // Create ContentVersion object to store the PDF file as a Salesforce File

        ContentVersion cv = new ContentVersion();

        String currentDate = Datetime.now().formatGMT(‘yyyy-MM-dd_HH:mm’);

        cv.Title = inv.Name + ‘_’ + currentDate + ‘.pdf’; // Set the PDF title dynamically with date and time

        cv.PathOnClient = cv.Title; // File name on the client side

        cv.VersionData = pdfBlob;

        cv.FirstPublishLocationId = inv.Id; // ParentId (Invoice__c record Id)

        cv.ContentLocation = ‘S’; // ‘S’ indicates Salesforce Files

        insert cv;

    

        // Redirect to the Invoice__c record page

        PageReference invoicePage = new PageReference(‘/’ + inv.Id);

        invoicePage.setRedirect(true); // Ensure a redirect after attachment

        return invoicePage;

    }

}

 

The implementation described in the post demonstrates an efficient method for generating PDF invoices within the Salesforce environment. By leveraging Visualforce pages and Apex controllers, the system provides dynamic functionality for displaying invoice details, attaching generated PDFs to related records, and enabling user interactions such as navigation and printing.

How To Delete the Record using lightning flow:

1. Login into the salesforce system. Click setup option

 

2. You will be redirected to the setup page. Search Flow in the find box.

 

blank

3. Choose the Flow option and now you will be redirected to the flow.

blank

 

4. Click the new flow button which is placed on your right side page.

blank

 

5. Now you will redirect to the flow wizard and choose the Record Trigger flow.

blank

 

6. Choose the option which I have mentioned in the below screenshot. We have chosen the flow event like when the record is before save or after save. We need to choose which we are  going to delete the same record or related.

blank

 

7. If you want to delete the record based on any criteria we will be able to give it here.

blank

8. Click Save Button.

9. Choose the Delete component on your right hand side. Drag and drop on the flow.

10. Now we need to choose the record id which we are going to delete. Finally click save and activate it.

blank

How to Change the Record Type based on a Field Value?

Lets directly dive into the problem. This article is purely about changing the record type in a Salesforce Object based on a field value. We are going to take the example of Case Object and a Picklist field. By the end of this article, if you have further questions, feel free to reach out to us

Problem Statement

Let us take a “Case” object and look at automatically changing the record type based on the value of the “Type__c” picklist field. This Picklist has 2 values – Complaint and Request.:

  • If Type__c is “Complaint”, the record type should be set to “Complaint”.
  • If Type__c is “Request”, the record type should be set to “Request”.

Solution

We’ll create a trigger on the Case object that executes before insert and before update events. This trigger will check the value of Type__c and set the RecordTypeId accordingly.

Here’s the complete code for the trigger:

apex
trigger CaseTypeTrigger on Case (before insert, before update) {
// Initialize record type IDs to null
Id complaintRecordTypeId = null;
Id requestRecordTypeId = null;

// Retrieve the record type IDs based on record type names
Map<String, Schema.RecordTypeInfo> recordTypeInfoMap = Schema.SObjectType.Case.getRecordTypeInfosByName();

if (recordTypeInfoMap.containsKey(‘Complaint’)) {
complaintRecordTypeId = recordTypeInfoMap.get(‘Complaint’).getRecordTypeId();
}

if (recordTypeInfoMap.containsKey(‘Request’)) {
requestRecordTypeId = recordTypeInfoMap.get(‘Request’).getRecordTypeId();
}

// Iterate over the cases and set the record type ID based on Type__c value
for (Case caseRecord : Trigger.new) {
if (caseRecord.Type__c == ‘Complaint’ && complaintRecordTypeId != null) {
caseRecord.RecordTypeId = complaintRecordTypeId;
} else if (caseRecord.Type__c == ‘Request’ && requestRecordTypeId != null) {
caseRecord.RecordTypeId = requestRecordTypeId;
}
}
}

Let’s get to the explanation

  1. Initialization: We start by initialising the record type IDs for “Complaint” and “Request” to null.
  2. Retrieve Record Type IDs: Using the Schema.SObjectType.Case.getRecordTypeInfosByName() method, we retrieve the record type IDs based on their names. We check if the record type names “Complaint” and “Request” exist, and if they do, we store their IDs.
  3. Iterate Over Cases: We loop through each case in Trigger.new, which represents the new or updated cases.
  4. Set Record Type: For each case, we check the value of Type__c. If it matches “Complaint” and the complaintRecordTypeId is not null, we set the case’s RecordTypeId to complaintRecordTypeId. Similarly, if Type__c is “Request” and the requestRecordTypeId is not null, we set the case’s RecordTypeId to requestRecordTypeId.

This technique can be used in other objects, fields and field values as well. Let us know if you have any questions, You can write to [email protected]. For other technical white papers on salesforce, please visit the technical resources we have written over the years. Happy reading!

Steps to integrate Postman with Salesforce:

Integrating Postman with Salesforce is a 2-step process:

  1. Create a connected app in Salesforce. This will generate a client ID and client secret that you will need to authenticate Postman to Salesforce. To create a connected app, go to Setup > App Manager > Create a new Connected App. Give the app a name and enable the OAuth settings. You will also need to choose the scopes that you want the app to have access to. Once you have created the connected app, you will be able to find the client ID and client secret in the app details.
  2. Authenticate Postman to Salesforce. To do this, you will need to create a new request in Postman and use a POST call to the following URL:

https://login.salesforce.com/services/oauth2/token

In the body of the request, you will need to include the following parameters:

Grant Type: password

Client ID: The client ID from your connected app

Client Secret: The client secret from your connected app

Username: Your Salesforce username

Password: Your Salesforce password

Once you have made the request, Postman will return an access token. You can then use this access token to call Salesforce REST APIs.

blank

Error (API security token required)

The error “Failed: API security token required” indicates that you’re trying to access a Salesforce API endpoint but your request lacks the necessary security token. Here are a couple of solutions to resolve this:

Solutions:

  1. Use a Security Token:
    • If your Salesforce organization requires security tokens for API access, you’ll need to obtain and include it in your request.
      • Login to Salesforce with your username and password.
      • Go to your Personal Setup (gear icon) and search for “Reset My Security Token”.
      • Reset your security token. You’ll receive a new token via email.
      • When making API calls through Postman or any other tool, include the security token along with your username and password.
  2. Add Your IP to Trusted Networks (if applicable):
    • Salesforce allows specifying trusted IP addresses that can access the API without requiring a security token.
      • If you’re making API calls from a consistent location (e.g., your office IP), you can ask your Salesforce admin to add that IP address to the trusted network list.
      • Go to Setup > Security > Network Access.
      • The admin can add your IP address here.
    • This approach might not be suitable if you’re making API calls from various locations.

 

Error (Username, Password flow disabled in Login History)

The error “Failed: Username, Password flow disabled in Login History” indicates that you tried to log in using your username and password, but this method is disabled for your Salesforce organization due to security reasons. Here’s how to address this:

Solutions:

  1. Use a More Secure Login Method (Recommended):
    • It’s strongly recommended to switch to a more secure OAuth 2.0 flow for logins. These flows involve creating a connected app in Salesforce and using access tokens for authentication. This approach offers better security compared to username and password.
    • Here are the steps: a. Create a Connected App: Go to Setup > App Manager > New Connected App. Provide a name, enable OAuth settings, and choose the access levels your app needs. You’ll get a client ID and client secret. b. Use OAuth in Your Tool: Refer to the documentation for your specific tool (e.g., Postman) on how to configure OAuth with the client ID and client secret obtained from the connected app. This typically involves configuring an OAuth 2.0 authorization code grant or password grant flow.
  2. Enable Username-Password Flow (with Caution): 
    Not recommended: If you’re an administrator and absolutely must use the username-password flow (avoid if possible due to security concerns), you can enable it, but proceed with caution: a. Go to Setup > Security > Remote Access Settings. b. Locate the setting Allow OAuth Username-Password Flows. c. Enable the setting (remember, this is not secure).

Get in touch with us if you have further questions. Zivoke helps organizations with Salesforce integration on a daily basis. For any Integration questions or support, our super smart tech team at Zivoke will be happy to help you.

Solving Time Display Problems or Formats in Salesforce: A Simple Guide

 

 

2 Step method to format Time (HH:MM:SS) in Salesforce using VisualForce Page (without Controller class or Methods)

After much research on the internet, we gave up searching for articles to help with Time/Date formatting In Salesforce. Our internal team put its time together on the whiteboard and arrived at the solution, more quickly than the time we took to research. 

In this White Paper we intend to show you an easy way to display hours, minutes, and seconds just the way you want them using Salesforce Apex / VisualForce.

I am sure most of us try to get the answer in google with the Error Codes to begin with. So, here we go with the most notorious error that Salesforce Developers encounter while meddling with time, hour and date formats.

Error:

“The value attribute on <apex:outputText> is not in a valid format. It must be a positive number, and of type Number, Date, Time, or Choice.”

This error mostly means there’s a problem with how you’re trying to show time. This can be solved by using the <apex:outputText> tag with <apex:param>. Very Importantly Time formatting can be achieved without any traditional Controller Classes or Methods. 

Salesforce VisualForce Code to solve the Time formatting issue:

<apex:outputText value=”{0,number,00}”>

<apex:param value=”{!Hour(Object__c.time__c)}” />

</apex:outputText>:

 

<apex:outputText value=”{0,number,00}”>

<apex:param value=”{!Minute(Object__c.time__c)}” />

</apex:outputText>:

<apex:outputText value=”{0,number,00}”>

<apex:param value=”{!Second(Object__c.time__c)}” />

</apex:outputText>

The above VF Page code is a way to display the hour, minute, and second components of the “Time__c” field in a specific format on a Salesforce Apex page.

Here’s a breakdown of each element:

  • <apex:outputText value=”{0,number,00}”>: This portion formats a numeric value ({0}) with a leading zero (00) if necessary. It sets the stage for presenting the time components in the desired format.
  • <apex:param value=”{!Hour(Object__c.Time__c)}” />: This segment retrieves the hour component from the “Time__c” field of the “Object__c” object. It ensures that the hour is accurately fetched and prepared for display.
  • <apex:param value=”{!Minute(Object__c.Time__c)}” />: Similar to the hour component, this section retrieves the minute component from the “Time__c” field. It ensures that minutes are seamlessly integrated into the time display.
  • <apex:param value=”{!Second(Object__c.Time__c)}” />: Lastly, this part fetches the second component from the “Time__c” field. It completes the trio of time components, ensuring that seconds are elegantly showcased alongside hours and minutes.

With this concise yet powerful code snippet, you can effortlessly display the hour, minute, and second components of the submission time in a format like “HH:MM:SS,” complete with leading zeros if needed. This functionality enhances the visual appeal and readability of your VF page, providing users with clear and concise time information.

Comment on this page or write to us with more observations and similar errors you are facing. Let’s try to solve them together.

#displaying time components in Salesforce Apex VF page

#Low code solution for Salesforce time, hour and date formatting.

#Salesforce resources for Date and Time Formatting.   

How to Change the Mass Ownership of Records in Salesforce Using Data Loader?

It is imperative to understand the basics of Salesforce Dataloader before getting on to changing ownership of multiple records in Salesforce. This can be a tricky task, especially when you encounter weird errors like “All accounts must have the same current owner and new owner.” 

This blog will guide you through a smart workaround to overcome this hurdle and successfully update ownership for multiple records using Salesforce Data Loader.

Step-by-Step Guide: Changing Ownership for Multiple Records

Step 1: Prepare Your Data Before you begin, gather the necessary data. Create a CSV file that contains two important columns: one for the Account ID and another for the new Owner ID. Make sure the Account IDs are 18-digit IDs (case-sensitive).

Step 2: Get Owner IDs To find the Owner ID for a specific user or group in Salesforce, navigate to their respective record and observe the URL. The Owner ID will be the last part of the URL, typically in the format /005XXXXXXXXXXXX for a User.

Step 3: Download and Install Data Loader If you haven’t already, download and install Salesforce Data Loader. This tool will enable you to perform bulk updates efficiently.

Step 4: Launch Data Loader Open Data Loader and log in using your Salesforce credentials.

Step 5: Select the Operation For updating ownership, choose the “Update” operation.

Step 6: Choose the Object Select the Salesforce object for which you want to update the ownership. In this case, choose “Account.”

Step 7: Map Fields Map the columns in your CSV file to the corresponding fields in Salesforce. The Account ID column should be mapped to the “Id” field, and the new Owner ID column should be mapped to the “OwnerId” field.

Step 8: Upload Your CSV File Upload the CSV file that you prepared earlier.

Step 9: Start the Update Click “Next” and then “Finish.” Review the summary of the update operation and click “Finish” again to initiate the update process.

Step 10: Monitor Progress Monitor the progress of your update in Data Loader. Once the process is completed, you will receive a success message.

Troubleshooting and Tips:

  • Sorting Owner IDs: To prevent errors like “All accounts must have the same current owner and new owner,” ensure that the Owner IDs in your CSV file are sorted. This step can prevent discrepancies and mixed ownership issues.

Conclusion: By following these steps and incorporating the Owner ID sorting trick, you can confidently update ownership for multiple records in Salesforce using Data Loader. This approach streamlines the process and helps you avoid common errors that can arise during bulk ownership updates. Keep experimenting and discovering new ways to optimize your Salesforce workflow!