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.

Error Fetching Work Items in DevOps Center (Salesforce): Causes, Impact, and Workaround

Introduction

Salesforce DevOps Center is designed to streamline metadata deployments and improve release management across environments. However, users may occasionally encounter platform-level issues that interrupt standard workflows.

One such issue is the “Error fetching work items” message during metadata commits. This article provides a detailed analysis of the issue, validated findings, official confirmation, and a practical workaround to maintain delivery continuity.

Issue

During the process of committing metadata from a Sandbox environment via the Change Management interface in Salesforce DevOps Center, users may encounter the following error: Error fetching work items Failed to fetch work items for project from remote DevOps Center.

This error prevents the system from retrieving associated work items, thereby blocking the commit process within the Sandbox environment.

Error Fetching Work Items

Root Cause Analysis

After a thorough technical investigation, the following conclusions were drawn:

  • Named Credentials Configuration:
    All Named Credentials across Sandbox and Production environments were properly authenticated and functioning as expected.
  • Work Item Status Validation:
    The relevant Work Item was in the correct lifecycle stage (In Progress) and eligible for association.
  • Environment Integrity:
    No discrepancies were found in environment setup, permissions, or connectivity.
    Despite validating all standard configurations, the issue persisted—indicating a platform-level defect rather than a configuration issue.

Salesforce Acknowledgment

The issue was escalated through an official Salesforce Support case. The response from Salesforce confirmed:

  • This is a known bug in DevOps Center.
  • A fix has been scheduled for version 260.12 (upcoming patch release).
  • Salesforce has recommended an interim workaround to bypass the issue.

Business Impact

This issue affects organizations using a structured DevOps pipeline such as:
Development Sandbox → UAT Sandbox → Production

Key Impacts:

  • Disruption in committing metadata from Sandbox environments
  • Temporary deviation from standard DevOps workflows
  • Additional manual steps required for deployment

However:

  • Development activities can continue without interruption
  • The issue is non-blocking with the available workaround

Recommended Workaround

Until Salesforce releases the official fix, the following approach is recommended:

1. Commit Changes from Production DevOps Center

    • Perform metadata commits directly within DevOps Center in the Production org
    • Continue development and testing activities in Sandbox environments as usual

2. Maintain Change Tracking

    • Document changes clearly to ensure traceability during this interim process
    • Align teams on the temporary workflow adjustment

Best Practices Moving Forward

  • Monitor Salesforce release notes for version 260.12 deployment
  • Validate the fix in a lower environment before resuming standard workflows
  • Maintain flexibility in DevOps processes to handle platform-level issues

Conclusion

The Error fetching work items issue in Salesforce DevOps Center is a confirmed product bug with an upcoming fix. While it introduces a temporary disruption in Sandbox-based commits, organizations can effectively mitigate its impact using the recommended workaround. By adapting processes and maintaining

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

blank

 

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

blank

 

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.