“Here, we have created a custom object ‘Invoice’ for the simple mapping of opportunity product lists for product creation purposes to send invoices for related customers.
The approach we follow is to first query the customer and add them to the invoice. Then, we send a POST request for the invoice related to that particular customer.
Here, we have a sample JSON file for the official documentation, which they provided. You can also visit and refer to this link to check them out:
Create a wrapper class for the request and response handling of the invoice object. You can refer to this website for the JSON data to convert the wrapper.
public class InvoiceJSON {
public class Line {
public Double Amount;
public String DetailType;
public Double Qty;
public String Description;
public SalesItemLineDetail SalesItemLineDetail;
}
public class CustomField {
public String DefinitionId;
public String StringValue;
public String Type;
public String Name;
}
public class BillAddr {
public String Id;
public String Line1;
public String Line2;
public String Line3;
public String Line4;
public String Line5;
public String City;
public String CountrySubDivisionCode;
public String PostalCode;
public String Lat;
public String Long_x;
public String Country;
}
public class SalesTermRef {
public String value;
}
public List<Line> Line;
public List<CustomField> CustomField;
public CustomerRef CustomerRef;
public Date DueDate;
public Double Balance;
public String Id;
public String SyncToken;
public SalesTermRef SalesTermRef;
public BillAddr BillAddr;
public BillAddr ShipAddr;
public EmailAddress BillEmail;
public MemoRef CustomerMemo;
public String EmailStatus;
public String DocNumber;
public Boolean AutoDocNumber;
public Boolean AllowOnlineACHPayment;
public Boolean AllowOnlineCreditCardPayment;
public TxnTaxDetail TxnTaxDetail;
public class EmailAddress{
public string Address;
}
public class TxnTaxDetail{
public TxnTaxCodeRef TxnTaxCodeRef;
public Decimal TotalTax;
}
public class TxnTaxCodeRef{
public String value;
}
public class MemoRef{
public string value;
}
public class SalesItemLineDetail {
public ItemRef ItemRef;
public Decimal Qty;
public Decimal UnitPrice;
public ItemRef TaxCodeRef;
}
public class ItemRef {
public String value;
public String name;
}
public class CustomerRef {
public String value;
}
public static InvoiceJSON parse(String json) {
return (InvoiceJSON ) System.JSON.deserialize(json, InvoiceJSON .class);
}
}
public class InvoiceQueryJSON {
public class CurrencyRef {
public String value {get;set;}
public String name {get;set;}
public CurrencyRef(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'value') {
value = parser.getText();
} else if (text == 'name') {
name = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'CurrencyRef consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Invoice {
public Integer Deposit {get;set;}
public Boolean AllowIPNPayment {get;set;}
public Boolean AllowOnlinePayment {get;set;}
public Boolean AllowOnlineCreditCardPayment {get;set;}
public Boolean AllowOnlineACHPayment {get;set;}
public String domain {get;set;}
public Boolean sparse {get;set;}
public String Id {get;set;}
public String SyncToken {get;set;}
public MetaData MetaData {get;set;}
public List<CustomField> CustomField {get;set;}
public String DocNumber {get;set;}
public String TxnDate {get;set;}
public CurrencyRef CurrencyRef {get;set;}
public List<LinkedTxn> LinkedTxn {get;set;}
public List<Line> Line {get;set;}
public CurrencyRef CustomerRef {get;set;}
public TaxCodeRef SalesTermRef {get;set;}
public String DueDate {get;set;}
public Double TotalAmt {get;set;}
public Boolean ApplyTaxAfterDiscount {get;set;}
public String PrintStatus {get;set;}
public String EmailStatus {get;set;}
public Double Balance {get;set;}
public String PrivateNote {get;set;}
public TaxCodeRef CustomerMemo {get;set;}
public BillEmail BillEmail {get;set;}
public BillEmail BillEmailCc {get;set;}
public BillEmail BillEmailBcc {get;set;}
public TxnTaxDetail TxnTaxDetail {get;set;}
public DeliveryInfo DeliveryInfo {get;set;}
public Invoice(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'Deposit') {
Deposit = parser.getIntegerValue();
} else if (text == 'AllowIPNPayment') {
AllowIPNPayment = parser.getBooleanValue();
} else if (text == 'AllowOnlinePayment') {
AllowOnlinePayment = parser.getBooleanValue();
} else if (text == 'AllowOnlineCreditCardPayment') {
AllowOnlineCreditCardPayment = parser.getBooleanValue();
} else if (text == 'AllowOnlineACHPayment') {
AllowOnlineACHPayment = parser.getBooleanValue();
} else if (text == 'domain') {
domain = parser.getText();
} else if (text == 'sparse') {
sparse = parser.getBooleanValue();
} else if (text == 'Id') {
Id = parser.getText();
} else if (text == 'SyncToken') {
SyncToken = parser.getText();
} else if (text == 'MetaData') {
MetaData = new MetaData(parser);
} else if (text == 'CustomField') {
CustomField = arrayOfCustomField(parser);
} else if (text == 'DocNumber') {
DocNumber = parser.getText();
} else if (text == 'TxnDate') {
TxnDate = parser.getText();
} else if (text == 'PrivateNote') {
PrivateNote = parser.getText();
} else if (text == 'CurrencyRef') {
CurrencyRef = new CurrencyRef(parser);
} else if (text == 'DeliveryInfo') {
DeliveryInfo = new DeliveryInfo(parser);
} else if (text == 'LinkedTxn') {
LinkedTxn = arrayOfLinkedTxn(parser);
} else if (text == 'Line') {
Line = arrayOfLine(parser);
} else if (text == 'CustomerRef') {
CustomerRef = new CurrencyRef(parser);
} else if (text == 'SalesTermRef') {
SalesTermRef = new TaxCodeRef(parser);
} else if (text == 'BillEmail') {
BillEmail = new BillEmail(parser);
} else if (text == 'BillEmailBcc') {
BillEmailBcc = new BillEmail(parser);
} else if (text == 'BillEmailCc') {
BillEmailCc = new BillEmail(parser);
} else if (text == 'TxnTaxDetail') {
TxnTaxDetail = new TxnTaxDetail(parser);
} else if (text == 'DueDate') {
DueDate = parser.getText();
} else if (text == 'TotalAmt') {
TotalAmt = parser.getDoubleValue();
} else if (text == 'ApplyTaxAfterDiscount') {
ApplyTaxAfterDiscount = parser.getBooleanValue();
} else if (text == 'PrintStatus') {
PrintStatus = parser.getText();
} else if (text == 'EmailStatus') {
EmailStatus = parser.getText();
} else if (text == 'Balance') {
Balance = parser.getDoubleValue();
} else if (text == 'CustomerMemo') {
CustomerMemo = new TaxCodeRef(parser);
} else {
System.debug(LoggingLevel.WARN, 'Invoice consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Line_Z {
public String Id {get;set;}
public Integer LineNum {get;set;}
public Double Amount {get;set;}
public String DetailType {get;set;}
public SalesItemLineDetail SalesItemLineDetail {get;set;}
public LinkedTxn SubTotalLineDetail {get;set;}
public Line_Z(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'Id') {
Id = parser.getText();
} else if (text == 'LineNum') {
LineNum = parser.getIntegerValue();
} else if (text == 'Amount') {
Amount = parser.getDoubleValue();
} else if (text == 'DetailType') {
DetailType = parser.getText();
} else if (text == 'SalesItemLineDetail') {
SalesItemLineDetail = new SalesItemLineDetail(parser);
} else if (text == 'SubTotalLineDetail') {
SubTotalLineDetail = new LinkedTxn(parser);
} else {
System.debug(LoggingLevel.WARN, 'Line_Z consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class DeliveryInfo {
public String DeliveryType {get;set;}
public String DeliveryTime {get;set;}
public DeliveryInfo(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'DeliveryType') {
DeliveryType = parser.getText();
} else if (text == 'DeliveryTime') {
DeliveryTime = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'InvoiceQueryJSON consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Line_Y {
public String Id {get;set;}
public Integer LineNum {get;set;}
public Double Amount {get;set;}
public String DetailType {get;set;}
public SalesItemLineDetail_Z SalesItemLineDetail {get;set;}
public LinkedTxn SubTotalLineDetail {get;set;}
public Line_Y(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'Id') {
Id = parser.getText();
} else if (text == 'LineNum') {
LineNum = parser.getIntegerValue();
} else if (text == 'Amount') {
Amount = parser.getDoubleValue();
} else if (text == 'DetailType') {
DetailType = parser.getText();
} else if (text == 'SalesItemLineDetail') {
SalesItemLineDetail = new SalesItemLineDetail_Z(parser);
} else if (text == 'SubTotalLineDetail') {
SubTotalLineDetail = new LinkedTxn(parser);
} else {
System.debug(LoggingLevel.WARN, 'Line_Y consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class SalesItemLineDetail {
public CurrencyRef ItemRef {get;set;}
public CurrencyRef ItemAccountRef {get;set;}
public TaxCodeRef TaxCodeRef {get;set;}
public Decimal UnitPrice {get;set;}
public Decimal Qty {get;set;}
public String ServiceDate {get;set;}
public SalesItemLineDetail(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'ItemRef') {
ItemRef = new CurrencyRef(parser);
} else if (text == 'ItemAccountRef') {
ItemAccountRef = new CurrencyRef(parser);
} else if (text == 'UnitPrice') {
UnitPrice = parser.getDecimalValue();
} else if (text == 'Qty') {
Qty = parser.getDecimalValue();
} else if (text == 'ServiceDate') {
ServiceDate = parser.getText();
} else if (text == 'TaxCodeRef') {
TaxCodeRef = new TaxCodeRef(parser);
} else {
System.debug(LoggingLevel.WARN, 'SalesItemLineDetail consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class TxnTaxDetail {
public Double TotalTax {get;set;}
public TxnTaxDetail(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'TotalTax') {
TotalTax = parser.getDoubleValue();
} else {
System.debug(LoggingLevel.WARN, 'InvoiceQueryJSON consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class Line {
public String Id {get;set;}
public Integer LineNum {get;set;}
public Double Amount {get;set;}
public String DetailType {get;set;}
public SalesItemLineDetail SalesItemLineDetail {get;set;}
public GroupLineDetail GroupLineDetail {get;set;}
public LinkedTxn SubTotalLineDetail {get;set;}
public String Description {get;set;}
// 17549
public Line(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'Id') {
Id = parser.getText();
} else if (text == 'LineNum') {
LineNum = parser.getIntegerValue();
} else if (text == 'Amount') {
Amount = parser.getDoubleValue();
} else if (text == 'DetailType') {
DetailType = parser.getText();
} else if (text == 'Description') {
Description = parser.getText();
} else if (text == 'SalesItemLineDetail') {
SalesItemLineDetail = new SalesItemLineDetail(parser);
} else if (text == 'SubTotalLineDetail') {
SubTotalLineDetail = new LinkedTxn(parser);
} else if (text == 'GroupLineDetail') {
GroupLineDetail = new GroupLineDetail(parser);
} else {
System.debug(LoggingLevel.WARN, 'Line consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class GroupLineDetail {
public GroupItemRef GroupItemRef {get;set;}
public Decimal Quantity {get;set;}
public Decimal Amount {get;set;}
public GroupLineDetail(JSONParser parser){
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'GroupItemRef') {
GroupItemRef = new GroupItemRef(parser);
} else if(text == 'Quantity'){
Quantity = parser.getDecimalValue();
} else if(text == 'Amount'){
Amount = parser.getDecimalValue();
} else {
System.debug(LoggingLevel.WARN, 'SalesItemLineDetail_Z consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class SalesItemLineDetail_Z {
public CurrencyRef ItemRef {get;set;}
public Integer UnitPrice {get;set;}
public Integer Qty {get;set;}
public CurrencyRef ItemAccountRef {get;set;}
public TaxCodeRef TaxCodeRef {get;set;}
public SalesItemLineDetail_Z(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'ItemRef') {
ItemRef = new CurrencyRef(parser);
} else if (text == 'UnitPrice') {
UnitPrice = parser.getIntegerValue();
} else if (text == 'Qty') {
Qty = parser.getIntegerValue();
} else if (text == 'ItemAccountRef') {
ItemAccountRef = new CurrencyRef(parser);
} else if (text == 'TaxCodeRef') {
TaxCodeRef = new TaxCodeRef(parser);
} else {
System.debug(LoggingLevel.WARN, 'SalesItemLineDetail_Z consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class GroupItemRef {
public String name {get;set;}
public String value {get;set;}
public GroupItemRef(JSONParser parser){
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'value') {
value = parser.getText();
} else if (text == 'name') {
name = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'TaxCodeRef consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class TaxCodeRef {
public String value {get;set;}
public String name {get;set;}
public TaxCodeRef(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'value') {
value = parser.getText();
} else if (text == 'name') {
name = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'TaxCodeRef consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public QueryResponse QueryResponse {get;set;}
public InvoiceQueryJSON (JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'QueryResponse') {
QueryResponse = new QueryResponse(parser);
} else {
System.debug(LoggingLevel.WARN, 'QBInvoiceQueryJSON consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
public class MetaData {
public String CreateTime {get;set;}
public String LastUpdatedTime {get;set;}
public MetaData(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'CreateTime') {
CreateTime = parser.getText();
} else if (text == 'LastUpdatedTime') {
LastUpdatedTime = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'MetaData consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class QueryResponse {
public List<Invoice> Invoice {get;set;}
public Integer startPosition {get;set;}
public Integer maxResults {get;set;}
public Integer totalCount {get;set;}
public QueryResponse(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'Invoice') {
Invoice = arrayOfInvoice(parser);
} else if (text == 'startPosition') {
startPosition = parser.getIntegerValue();
} else if (text == 'maxResults') {
maxResults = parser.getIntegerValue();
} else if (text == 'totalCount') {
totalCount = parser.getIntegerValue();
} else {
System.debug(LoggingLevel.WARN, 'QueryResponse consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class CustomField {
public String DefinitionId {get;set;}
public String Type_Z {get;set;} // in json: Type
public CustomField(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'DefinitionId') {
DefinitionId = parser.getText();
} else if (text == 'Type') {
Type_Z = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'CustomField consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class LinkedTxn {
public String TxnId;
public String TxnType;
public LinkedTxn(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
{
System.debug(LoggingLevel.WARN, 'LinkedTxn consuming unrecognized property: '+text);
consumeObject(parser);
if (text == 'TxnId') {
TxnId = parser.getText();
} else if (text == 'TxnType') {
TxnType = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'LinkedTxn consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
}
public class BillEmail {
public String Address;
public BillEmail(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
{
System.debug(LoggingLevel.WARN, 'LinkedTxn consuming unrecognized property: '+text);
consumeObject(parser);
if (text == 'Address') {
Address = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'LinkedTxn consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
}
public static InvoiceQueryJSON parse(String json) {
System.JSONParser parser = System.JSON.createParser(json);
return new QBInvoiceQueryJSON(parser);
}
public static void consumeObject(System.JSONParser parser) {
Integer depth = 0;
do {
System.JSONToken curr = parser.getCurrentToken();
if (curr == System.JSONToken.START_OBJECT ||
curr == System.JSONToken.START_ARRAY) {
depth++;
} else if (curr == System.JSONToken.END_OBJECT ||
curr == System.JSONToken.END_ARRAY) {
depth--;
}
} while (depth > 0 && parser.nextToken() != null);
}
private static List<CustomField> arrayOfCustomField(System.JSONParser p) {
List<CustomField> res = new List<CustomField>();
if (p.getCurrentToken() == null) p.nextToken();
while (p.nextToken() != System.JSONToken.END_ARRAY) {
res.add(new CustomField(p));
}
return res;
}
private static List<Line> arrayOfLine(System.JSONParser p) {
List<Line> res = new List<Line>();
if (p.getCurrentToken() == null) p.nextToken();
while (p.nextToken() != System.JSONToken.END_ARRAY) {
res.add(new Line(p));
}
return res;
}
private static List<LinkedTxn> arrayOfLinkedTxn(System.JSONParser p) {
List<LinkedTxn> res = new List<LinkedTxn>();
if (p.getCurrentToken() == null) p.nextToken();
while (p.nextToken() != System.JSONToken.END_ARRAY) {
res.add(new LinkedTxn(p));
}
return res;
}
private static List<Line_Z> arrayOfLine_Z(System.JSONParser p) {
List<Line_Z> res = new List<Line_Z>();
if (p.getCurrentToken() == null) p.nextToken();
while (p.nextToken() != System.JSONToken.END_ARRAY) {
res.add(new Line_Z(p));
}
return res;
}
private static List<Invoice> arrayOfInvoice(System.JSONParser p) {
List<Invoice> res = new List<Invoice>();
if (p.getCurrentToken() == null) p.nextToken();
while (p.nextToken() != System.JSONToken.END_ARRAY) {
res.add(new Invoice(p));
}
return res;
}
private static List<Line_Y> arrayOfLine_Y(System.JSONParser p) {
List<Line_Y> res = new List<Line_Y>();
if (p.getCurrentToken() == null) p.nextToken();
while (p.nextToken() != System.JSONToken.END_ARRAY) {
res.add(new Line_Y(p));
}
return res;
}
}
A Comprehensive Guide to Automating Statistics and Business Processes through QuickBooks-Salesforce Integration”
Unlock the potential of seamless automation for your business statistics and processes with the strategic integration of QuickBooks and Salesforce. In this blog, we offer invaluable insights and guidance to empower you in automating crucial aspects of your operations, ensuring efficiency and accuracy through the synergy of these powerful platforms.
Essential Steps to Follow for Seamless Integration
Getting Started: Signing Up for QuickBooks and Salesforce Accounts
The first step to begin your journey with QuickBooks and Salesforce is to sign up for an account on both platforms. Follow these easy steps to get started:
QuickBooks Account Signup: Visit the QuickBooks website and look for the “Sign Up” or “Create Account” option. Fill in the required information, such as your business details and contact information. Once completed, you’ll have your own QuickBooks account ready to use.
Salesforce Account Signup: Head over to the Salesforce website and locate the “Sign Up” or “click this link https://developer.salesforce.com/signup” . Provide the necessary details, including your name, email, and organization information. After completing the signup process, you’ll have access to your new Salesforce account.
Creating Your App in QuickBooks: A Step-by-Step Guide
Log In to QuickBooks: Start by logging in to your QuickBooks account. Enter your credentials to access the dashboard.
Navigate to the Dashboard: Once logged in, locate and click on the “Dashboard” option. This is usually the central hub where you can access various tools and features.
Access the App Creation Section: Look for the “Apps” or “App Management” section in the dashboard. Depending on your QuickBooks version, this may be found in the main menu or a designated area within the dashboard.
Initiate App Creation: Within the “Apps” section, you should find an option to create a new app. Click on this option to begin the app creation process.
Fill in App Details: Provide necessary details about your app, such as its name, description, and purpose. This information helps QuickBooks understand the function and scope of your app.
After creating your QuickBooks app, find the Client ID and Client Secret, crucial for secure integration. Retrieve additional credentials like Company ID and Callback URL, and follow the authentication process to establish a secure link between your app and QuickBooks.
Creating Your Site and Remote Site Settings in Salesforce :
(1). Create your site and add inside for the webhooks
(2). Create Remote site settings and add information
Url :https://oauth.platform.intuit.com
Active -true
Create an apex class
The webhook class is designed to capture and store Item information of Quickbooks within the Salesforce platform during creation.
Its purpose is to handle webhook events, ensuring the seamless storage of details related to the products in the system
/**
* Salesforce REST Resource class for handling QuickBooks webhooks to create or update products.
*/
@RestResource(urlMapping='/api/Webhooks/pushDemo/*')
global class CreateWebHookQuickBooks {
/**
* REST method to handle the creation or update of products in Salesforce triggered by QuickBooks webhooks.
*/
@HttpPost
global static void createProductFromQB() {
RestRequest request = RestContext.request;
RestResponse response = RestContext.response;
// Deserialize the incoming webhook payload
RespHookClass resp = (RespHookClass) system.JSON.deserialize(RestContext.request.requestBody.toString(), RespHookClass.class);
try {
/*
* Create or update a product in Salesforce from Quickbooks products (item) if created or updated.
*/
if(!resp.eventNotifications.isEmpty() && resp.eventNotifications.size()>0){
if(resp.eventNotifications[0].dataChangeEvent.entities[0].Name == 'Item'){
AUthCallout call = new AUthCallout ();
String responseStr = call.getItemById('' + resp.eventNotifications[0].dataChangeEvent.entities[0].Id);
ItemWrapper wrapper = (ItemWrapper) system.JSON.deserialize(responseStr, ItemWrapper.class);
// Prepare Product2 object for insertion or update
Product2 ProductToInsert = new Product2(
Name = wrapper.Item.Name,
Description = wrapper.Item.Description,
Rate__c = wrapper.Item.UnitPrice,
IsActive = true,
QB_Id__c = wrapper.Item.Id,
QBO_SyncToken__c = wrapper.Item.SyncToken
);
// Upsert the product based on operation type (Create or Update)
if (resp.eventNotifications[0].dataChangeEvent.entities[0].operation == 'Create' || resp.eventNotifications[0].dataChangeEvent.entities[0].operation == 'Update') {
List<Product2> existingProduct = [SELECT Id FROM Product2 WHERE QB_Id__c = :wrapper.Item.Id LIMIT 1];
ProductToInsert.Id = (!existingProduct.isEmpty() && existingProduct[0] != null) ? existingProduct[0].id : null;
if(ProductToInsert != null){
upsert ProductToInsert;
}
}
// Create Pricebook entries for the product
if(resp.eventNotifications[0].dataChangeEvent.entities[0].operation == 'Create'){
PriceBook2 pb2Standard = [select Id from Pricebook2 where isStandard=true];
PricebookEntry objPBEntry = new PricebookEntry(
Pricebook2Id = pb2Standard.Id,
Product2Id = ProductToInsert.Id,
UnitPrice = wrapper.Item.UnitPrice,
IsActive = true
);
insert objPBEntry;
PriceBook2 pb2Custom = [select Id from Pricebook2 where isStandard=false];
PricebookEntry pbe = new PricebookEntry(
Pricebook2Id = pb2Custom.Id,
Product2Id = ProductToInsert.Id,
UnitPrice = wrapper.Item.UnitPrice,
IsActive = true
);
insert pbe;
}
// Log integration success
Integration_Log__c inglog = new Integration_Log__c();
inglog.Name = resp.eventNotifications[0].dataChangeEvent.entities[0].Name;
inglog.Event_Date_And_Time__c = System.Now();
inglog.Request_Body__c = JSON.serializePretty(resp);
inglog.Event_Status__c = 'Success';
insert inglog;
}
}
} catch(Exception e) {
// Log integration error
System.debug('error occurred:'+e.getMessage()+' '+e.getLineNumber());
Integration_Log__c inglog = new Integration_Log__c();
inglog.Name = resp.eventNotifications[0].dataChangeEvent.entities[0].Name;
inglog.Event_Date_And_Time__c = System.Now();
inglog.Request_Body__c = JSON.serializePretty(resp);
inglog.Error_Message__c = e.getMessage() + ' ' + e.getLineNumber() + ' ' + e.getCause() + ' ' + e.getTypeName();
inglog.Event_Status__c = 'Error';
insert inglog;
}
}
}
public class AUthCallout {
private String accessToken{get;set;}
private String refreshToken{get;set;}
public List<String> refresh(){
QBData__c QBData = [SELECT ID,
Name,
refresh_token__c,
client_id__c,
client_secret__c,
auth_url__c
FROM QBData__c];
String url = QBData.auth_url__c;
String clientId = QBData.client_id__c;
String clientSecret = QBData.client_secret__c;
String header = 'Basic ' + EncodingUtil.base64Encode(Blob.valueOf(clientId + ':' + clientSecret));
String refresh_token = QBData.refresh_token__c;
String body = 'grant_type=refresh_token&refresh_token=' + refresh_token;
Http h = new Http();
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
req.setEndpoint(url);
req.setMethod('POST');
req.setBody(body);
req.setHeader('Authorization', header);
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
res = h.send(req);
System.debug('res.getBody()==>'+res.getBody());
QBRefreshJSON json = QBRefreshJSON.parse(res.getBody());
System.debug('QBRefreshJSON==>'+json);
List<String> tokens = new List<String>{json.access_token,json.refresh_token};
accessToken = tokens[0];
refreshToken = tokens[1];
System.debug('accesToken==>'+accessToken);
System.debug('refreshToken==>'+refreshToken);
return tokens;
}
public String getItemById(String itemId){
//Initialze url endpoint
QBO_Metadata__mdt QBData = [SELECT ID,
base_url__c,
Company_Id__c,
minorversion__c
FROM QBO_Metadata__mdt];
String url = 'https://sandbox-quickbooks.api.intuit.com/v3/company/4620816365312541260/item/'+itemId+'?minorversion=65';
//Start http request
Http h = new Http();
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
System.debug(accessToken);
req.setEndpoint(url);
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer ' + accessToken);
req.setheader('Accept', 'application/json');
req.setHeader('Content-Type', 'application/text');
res = h.send(req);
String str = res.getBody();
return str;
}
public AUthCallout(){
List<String> tokens = refresh();
}
}
public class RespHookClass {
public List<EventNotification> eventNotifications;
public class EventNotification {
public String realmId;
public DataChangeEvent dataChangeEvent;
}
public class DataChangeEvent {
public List<Entity> entities;
}
public class Entity {
public String name;
public String id;
public String operation;
public String lastUpdated;
}
}
// Generated by JSON2Apex http://json2apex.herokuapp.com/
public class ItemWrapper {
public Item Item {get;set;}
public String time_Z {get;set;} // in json: time
public ItemWrapper(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'Item') {
Item = new Item(parser);
} else if (text == 'time') {
time_Z = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'ItemWrapper consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
public class Item {
public String Name {get;set;}
public String Description {get;set;}
public Boolean Active {get;set;}
public String FullyQualifiedName {get;set;}
public Boolean Taxable {get;set;}
public Integer UnitPrice {get;set;}
public String Type {get;set;}
public IncomeAccountRef IncomeAccountRef {get;set;}
public String PurchaseDesc {get;set;}
public Integer PurchaseCost {get;set;}
public IncomeAccountRef ExpenseAccountRef {get;set;}
public IncomeAccountRef AssetAccountRef {get;set;}
public Boolean TrackQtyOnHand {get;set;}
public Integer QtyOnHand {get;set;}
public String InvStartDate {get;set;}
public IncomeAccountRef TaxClassificationRef {get;set;}
public String domain {get;set;}
public Boolean sparse {get;set;}
public String Id {get;set;}
public String SyncToken {get;set;}
public MetaData MetaData {get;set;}
public Item(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'Name') {
Name = parser.getText();
} else if (text == 'Description') {
Description = parser.getText();
} else if (text == 'Active') {
Active = parser.getBooleanValue();
} else if (text == 'FullyQualifiedName') {
FullyQualifiedName = parser.getText();
} else if (text == 'Taxable') {
Taxable = parser.getBooleanValue();
} else if (text == 'UnitPrice') {
UnitPrice = parser.getIntegerValue();
} else if (text == 'Type') {
Type = parser.getText();
} else if (text == 'IncomeAccountRef') {
IncomeAccountRef = new IncomeAccountRef(parser);
} else if (text == 'PurchaseDesc') {
PurchaseDesc = parser.getText();
} else if (text == 'PurchaseCost') {
PurchaseCost = parser.getIntegerValue();
} else if (text == 'ExpenseAccountRef') {
ExpenseAccountRef = new IncomeAccountRef(parser);
} else if (text == 'AssetAccountRef') {
AssetAccountRef = new IncomeAccountRef(parser);
} else if (text == 'TrackQtyOnHand') {
TrackQtyOnHand = parser.getBooleanValue();
} else if (text == 'QtyOnHand') {
QtyOnHand = parser.getIntegerValue();
} else if (text == 'InvStartDate') {
InvStartDate = parser.getText();
} else if (text == 'TaxClassificationRef') {
TaxClassificationRef = new IncomeAccountRef(parser);
} else if (text == 'domain') {
domain = parser.getText();
} else if (text == 'sparse') {
sparse = parser.getBooleanValue();
} else if (text == 'Id') {
Id = parser.getText();
} else if (text == 'SyncToken') {
SyncToken = parser.getText();
} else if (text == 'MetaData') {
MetaData = new MetaData(parser);
} else {
System.debug(LoggingLevel.WARN, 'Item consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class MetaData {
public String CreateTime {get;set;}
public String LastUpdatedTime {get;set;}
public MetaData(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'CreateTime') {
CreateTime = parser.getText();
} else if (text == 'LastUpdatedTime') {
LastUpdatedTime = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'MetaData consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public class IncomeAccountRef {
public String value {get;set;}
public String name {get;set;}
public IncomeAccountRef(JSONParser parser) {
while (parser.nextToken() != System.JSONToken.END_OBJECT) {
if (parser.getCurrentToken() == System.JSONToken.FIELD_NAME) {
String text = parser.getText();
if (parser.nextToken() != System.JSONToken.VALUE_NULL) {
if (text == 'value') {
value = parser.getText();
} else if (text == 'name') {
name = parser.getText();
} else {
System.debug(LoggingLevel.WARN, 'IncomeAccountRef consuming unrecognized property: '+text);
consumeObject(parser);
}
}
}
}
}
}
public static ItemWrapper parse(String json) {
System.JSONParser parser = System.JSON.createParser(json);
return new ItemWrapper(parser);
}
public static void consumeObject(System.JSONParser parser) {
Integer depth = 0;
do {
System.JSONToken curr = parser.getCurrentToken();
if (curr == System.JSONToken.START_OBJECT ||
curr == System.JSONToken.START_ARRAY) {
depth++;
} else if (curr == System.JSONToken.END_OBJECT ||
curr == System.JSONToken.END_ARRAY) {
depth--;
}
} while (depth > 0 && parser.nextToken() != null);
}
}
“Simply map all these classes and fields, and store the information such as company ID, secret, client ID, refresh token, and access token inside Custom Settings and Custom Metadata. With this approach, your integration setup is complete.
“Thank you for taking the time to read our blog! We appreciate your interest and hope you found valuable insights within these articles. If you have any questions, comments, or suggestions, we’d love to hear from you. Your feedback is invaluable as we strive to provide content that matters to you. Stay tuned for more enriching articles, and once again, thank you for being part of our reading community!”
“Please refer to the previous post for instructions on configuring if you haven’t created a QuickBooks account or Salesforce accounts and configured these settings before.”
First, you have to create a field in the Account object, QBO_Id__c (external), and SyncToken__c (Text – 255), to map the QuickBooks ID to the Salesforce Account ID
“Create a wrapper class for customer creation from QuickBooks inside the API. If needed, you can also refer to the official API documentation for page references regarding the request and response.”
public class CustomerJSON {
public class BillAddr {
public String Id;
public String Line1;
public String City;
public String CountrySubDivisionCode;
public String PostalCode;
public String Lat;
public String Long_x;
public String Country;
}
public class ParentRef {
public String value;
}
public class CurrencyRef {
public String value;
public String name;
}
public QueryResponse QueryResponse;
public String timeString;
public class PrimaryPhone {
public String FreeFormNumber;
}
public class Customer {
public Boolean Taxable;
public BillAddr BillAddr;
public BillAddr ShipAddr;
public Boolean Job;
public Boolean BillWithParent;
public ParentRef ParentRef;
public Integer Level;
public Decimal Balance;
public Decimal BalanceWithJobs;
public CurrencyRef CurrencyRef;
public String PreferredDeliveryMethod;
public Boolean IsProject;
public String domain;
public Boolean sparse;
public String Id;
public String SyncToken;
public MetaData MetaData;
public String FullyQualifiedName;
public String CompanyName;
public String GivenName;
public String FamilyName;
public String DisplayName;
public String PrintOnCheckName;
public Boolean Active;
public PrimaryPhone PrimaryPhone;
public PrimaryEmailAddr PrimaryEmailAddr;
public ParentRef DefaultTaxCodeRef;
public String TaxExemptionReasonId;
public String ResaleNum;
}
public class MetaData {
public String CreateTime;
public String LastUpdatedTime;
}
public class QueryResponse {
public List<Customer> Customer;
public Integer startPosition;
public Integer maxResults;
}
public class PrimaryEmailAddr {
public String Address;
}
public static QBCustomerJSON parse(String json) {
return (QBCustomerJSON) System.JSON.deserialize(json, QBCustomerJSON.class);
}
public static QBCustomerJSON.Customer parseCustomer(String json) {
return (QBCustomerJSON.Customer) System.JSON.deserialize(json, QBCustomerJSON.Customer.class);
}
}
public class CustomerResponseJSON {
public class CurrencyRef {
public String value;
public String name;
}
public class Customer {
public Boolean Taxable;
public Boolean Job;
public Boolean BillWithParent;
public Decimal Balance;
public Decimal BalanceWithJobs;
public CurrencyRef CurrencyRef;
public String PreferredDeliveryMethod;
public Boolean IsProject;
public String domain;
public Boolean sparse;
public String Id;
public String SyncToken;
public MetaData MetaData;
public String GivenName;
public String FamilyName;
public String FullyQualifiedName;
public String CompanyName;
public String DisplayName;
public String PrintOnCheckName;
public Boolean Active;
public PrimaryEmailAddr PrimaryEmailAddr;
public DefaultTaxCodeRef DefaultTaxCodeRef;
}
public class MetaData {
public String CreateTime;
public String LastUpdatedTime;
}
public Customer Customer;
public String times;
public class DefaultTaxCodeRef {
public String value;
}
public class PrimaryEmailAddr {
public String Address;
}
public static CustomerResponseJSON parse(String json) {
return (QBCustomerResponseJSON) System.JSON.deserialize(json, QBCustomerResponseJSON.class);
}
}
public with sharing class CustomerController {
public Id accId{get;set;}
public Account acc {get;set;}
public CustomerController (ApexPages.StandardController controller) {
accId = controller.getRecord().Id;
acc = AccountHelperClass.getAccount(accId);
}
public Pagereference syncQB(){
acc = AccountHelperClass .createOrUpdateCustomer(acc);
update acc;
return new PageReference('/'+accId);
}
}
/**
* This class handles authentication and QuickBooks API calls for customer creation.
*/
public class AuthCallOut {
// Variables to store access and refresh tokens
private String accessToken { get; set; }
private String refreshToken { get; set; }
/**
* Refreshes the access token using the stored refresh token.
* @return List of strings containing the new access and refresh tokens.
*/
public List<String> refresh() {
// Retrieve QuickBooks data from custom setting
QBData__c QBData = [SELECT ID, Name, refresh_token__c, client_id__c, client_secret__c, auth_url__c
FROM QBData__c];
// Construct OAuth request
String url = QBData.auth_url__c;
String clientId = QBData.client_id__c;
String clientSecret = QBData.client_secret__c;
String header = 'Basic ' + EncodingUtil.base64Encode(Blob.valueOf(clientId + ':' + clientSecret));
String refresh_token = QBData.refresh_token__c;
String body = 'grant_type=refresh_token&refresh_token=' + refresh_token;
// Perform HTTP callout to refresh access token
Http h = new Http();
HttpRequest req = new HttpRequest();
HttpResponse res = new HttpResponse();
req.setEndpoint(url);
req.setMethod('POST');
req.setBody(body);
req.setHeader('Authorization', header);
req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
res = h.send(req);
// Parse response and update tokens
QBRefreshJSON json = QBRefreshJSON.parse(res.getBody());
List<String> tokens = new List<String>{json.access_token, json.refresh_token};
accessToken = tokens[0];
refreshToken = tokens[1];
return tokens;
}
/**
* Performs a QuickBooks API call to create a customer.
* @param customerJson JSON string containing customer data.
* @return Parsed response for the customer creation.
*/
public static CustomerResponseJSON createCustomer(String customerJson) {
// Perform authenticated API callout to create a customer
HttpResponse res = Authcallout('customer', 'POST', customerJson);
return QBCustomerResponseJSON.parse(res.getBody());
}
/**
* Internal method to perform authenticated QuickBooks API callouts.
* @param endpoint The API endpoint to call.
* @param method The HTTP method (GET, POST, PUT, DELETE).
* @param body The request body in JSON format.
* @return HTTPResponse object containing the API response.
*/
private static HttpResponse Authcallout(String endpoint, String method, String body) {
// Retrieve QuickBooks metadata from custom metadata type
QBO_Metadata__mdt credentials;
List<QBO_Metadata__mdt> creds = [SELECT Id, base_url__c, Company_Id__c, MinorVersion__c
FROM QBO_Metadata__mdt WHERE DeveloperName = 'Default'];
credentials = creds[0];
// Construct API endpoint URL with minor version
HttpRequest req = new HttpRequest();
String url = 'v3/company/' + credentials.Company_Id__c + '/' + endpoint;
if (!url.contains('?')) {
url += '?minorversion=' + credentials.MinorVersion__c;
} else {
url += '&minorversion=' + credentials.MinorVersion__c;
}
req.setEndpoint(credentials.base_url__c + '/' + url);
req.setMethod(method);
req.setBody(body);
req.setHeader('Accept', 'application/json');
req.setHeader('Content-Type', 'application/json');
req.setHeader('Authorization', 'Bearer ' + accessToken);
// Adjust content type for query endpoints
if (endpoint.contains('query')) {
req.setHeader('Content-Type', 'application/text');
}
// Perform HTTP callout and handle exceptions
Http http = new Http();
HttpResponse res;
try {
res = http.send(req);
} catch (Exception e) {
System.debug(e.getMessage());
}
return res;
}
}
Streamlining Communication and Collaboration: Integrating Salesforce with Slack
In today’s fast-paced business environment, effective communication and collaboration are paramount to success. Companies are constantly on the lookout for innovative ways to bridge the gap between their various platforms and tools, ensuring seamless information flow. One such powerful integration is between Salesforce, the leading customer relationship management (CRM) platform, and Slack, a popular team communication app. In this blog post, we’ll dive into a specific use case that highlights the potential of this integration: notifying Slack users about important updates within Salesforce using the @mention chatter feed feature.
The Use Case: Salesforce Integration with Slack App
Imagine you’re a sales professional working with Salesforce to manage your customer interactions, deals, and opportunities. On the other hand, your team relies on Slack for real-time communication and collaboration. Now, consider a scenario where you want to keep your team updated about the status of deals in Salesforce without having to switch back and forth between platforms. This is where the integration between Salesforce and Slack comes to the rescue.
Seamless @Mentions via Chatter Posts
Salesforce offers a robust feature called Chatter, which allows users to collaborate and communicate within the CRM platform. You can use Chatter to make posts and comments related to various records, including deals, leads, and contacts. With the integration set up, you can now leverage the @mention functionality in Chatter posts to bring the attention of specific team members to important updates.
For instance, let’s say you’ve just closed a deal that was being managed in Salesforce. Instead of sending separate emails or messages to your team members, you can create a Chatter post and @mention relevant users. For example, you can write a post like, “@gaurav Hii, we have a big deal please close asap !” This simple action ensures that Gaurav receives a notification about the update.
Instant Notifications on Slack
Here’s where the integration’s magic truly shines. As soon as you hit the “Post” button on your Chatter update, the integration between Salesforce and Slack springs into action. The mentioned user, in this case, Gaurav, will receive a notification directly on Slack. This means that Gaurav doesn’t need to keep checking Salesforce for updates; the information comes to him in a platform he’s actively engaged with.
Setting Up the Integration
Setting up this integration doesn’t have to be a daunting task. Both Salesforce and Slack offer user-friendly methods to connect the two platforms. By using Salesforce’s AppExchange and Slack’s App Directory, you can find pre-built integrations or connect the platforms using APIs if you require more customized functionality. Follow the step-by-step guides provided by both platforms to ensure a smooth and secure integration process.
In Conclusion
The integration between Salesforce and Slack offers a powerful solution for enhancing communication and collaboration within your organization. By harnessing the capabilities of Chatter’s @mention feature and the instant notification system in Slack, you can keep your team members informed about important updates without any friction. This streamlined process not only saves time but also ensures that everyone is on the same page when it comes to crucial deals and customer interactions. So, whether you’re a sales professional, a project manager, or anyone looking to optimize their workflow, consider integrating Salesforce with Slack to experience a new level of efficiency and connectivity.
Step 1: Install and Authorize
The first step in the integration process is to install the Slack app and grant the necessary permissions. Follow these steps:
Install Slack App: Head over to your Salesforce account’s AppExchange and search for the Slack integration app.or you can click the link https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FnD9mUAF. Once you’ve found it, click on the “Get It Now” button and follow the installation instructions. This will ensure the app is added to your Salesforce instance.
Authorize Slack App: After installation, open the Slack app from your Salesforce account. You’ll be prompted to authorize the app to access your Slack workspace. This step is crucial for enabling data sharing between the two platforms. Click “Authorize” and follow the authentication steps provided.
Step 2: Create a Custom Field
To effectively link the Slack user IDs with Salesforce records, you’ll need to create a custom field in the User object. Here’s how:
Navigate to Object Manager: From your Salesforce homepage, click on the “App Launcher” (grid icon) and search for “Object Manager.” Select “User” from the list of objects.
Create a Custom Field: In the User object, click on “Fields & Relationships” and then “New.” Choose the data type as “Text” and give the field a meaningful name like “Slack ID.”
Field Properties: Set the field properties according to your preferences. You can choose whether the field should be visible to all users, required, or unique.
Step 3: Authorize your workspace
Click 9 dots in your salesforce org search the slack setup app click and authorize to your workspace.
Step 4: Click the automatic configuration
Click the new Message Destination button A modal will appear to provide the necessary information.
Like MessageDestination Name, Slack workspace, Slack channel, or person Name, And Hit save.
Step 4: Mapping IDs
Now that you have the necessary components in place, it’s time to establish a connection between the Slack user IDs and Salesforce records:
Gather Slack User IDs: In your Slack app, find the user IDs that correspond to each user in your Salesforce organization. These IDs are unique identifiers within Slack and will help establish the link.
Copy the message destinationId and Update Salesforce User Records: Go to the user profiles in Salesforce one by one. In the newly created “Slack ID” field, input the corresponding Slack user ID. This step effectively maps each user’s Salesforce profile with their Slack identity.
Now Create a Record-Trigger flow To Feed Item Object
Follow these steps to create a flow:
Final will Look like this
/*
* Author Name: Gaurav Kumar
Date: 30-Aug-2023
Purpose: Purpose for the method to get the chatter post text items,and mention user
*
*/
public class feedinvocable {
@InvocableMethod(Label='get the feed items')
public static List<List<Id>> getfeed(List<FeedItem> lstfeed){
List<List<Id>> lstId = new List<List<Id>>();
String communityId = null;
List<Id> mentionUser =new List<Id>();
try{
for(FeedItem fd : lstfeed){
ConnectApi.FeedElement feedItem = ConnectApi.ChatterFeeds.getFeedElement(communityId, fd.id);
List<ConnectApi.MessageSegment> messageSegments = feedItem.body.messageSegments;
for (ConnectApi.MessageSegment messageSegment : messageSegments) {
if (messageSegment instanceof ConnectApi.MentionSegment) {
ConnectApi.MentionSegment mentionSegment = (ConnectApi.MentionSegment) messageSegment;
System.debug('Mentioned user name: ' + mentionSegment.name);
System.debug('Mentioned user id: ' + mentionSegment.record.id);
mentionUser.add(mentionSegment.record.id);
}
}
lstId.add(mentionUser);
}
return lstId;
}catch(Exception e){
System.debug('exception occuurred is '+e.getMessage());
System.debug('exception occuurred is '+e.getLineNumber());
return null;
}
}
}
Overview
The feedinvocable class is an Apex class in Salesforce that contains an invocable method used to extract mentioned user IDs from Chatter feed items.
Invocable Method: getfeed
The getfeed method is an invocable method within the feedinvocable class. It takes a list of FeedItem objects as input and returns a list of lists of user IDs.
Signature
public static List<List<Id>> getfeed(List<FeedItem> lstfeed)
Parameters
lstfeed (Type: List<FeedItem>) – A list of FeedItem objects representing Chatter feed items from which mentioned user IDs need to be extracted.
Return Value
Type: List<List<Id>> – A list of lists of user IDs. Each inner list corresponds to the user IDs mentioned in a particular feed item.
Description
The getfeed method iterates through the input list of FeedItem objects. For each FeedItem, it retrieves the associated Chatter feed element using the ConnectApi.ChatterFeeds.getFeedElement method. It then extracts mentioned user IDs from the feed element’s body message segments.
The method specifically looks for ConnectApi.MentionSegment instances within the message segments. For each mention found, the mentioned user’s ID is extracted and added to the mentionUser list. After processing all message segments in a feed item, the mentionUser list is added to the lstId list.
Finally, the lstId list, containing lists of mentioned user IDs, is returned
If an exception occurs during the process, the method catches the exception, logs relevant debug information (error message and line number), and returns null.
Conclusion
The feedinvocable class provides a convenient way to extract mentioned user IDs from Chatter feed items using the getfeed invocable method. It can be utilized in Salesforce applications to enhance collaboration and communication among users
Welcome to the technical documentation for the Drag-and-Drop Lightning Web Component (LWC). This guide will walk you through the implementation and usage of this component, which provides a streamlined interface for managing opportunities using a Kanban-style view, with our own custom customization
Installation and Setup
Salesforce Environment Setup: Before you begin, make sure you have a Salesforce environment set up for Lightning Component development.
Deploy the LWC: To use the Drag-and-Drop LWC in your org, follow these steps:
Retrieve the source code of the component.
Deploy the component to your Salesforce org using Salesforce CLI or another appropriate deployment method.
Component Architecture
The Drag-and-Drop LWC is structured as follows:
dragAndDropLwc Folder:
dragAndDropLwc.html: This file contains the HTML template for the component’s user interface,and child componet of drag-and-drop-list
dragAndDropLwc.js: The JavaScript file holds the component’s logic, including data fetching, drag-and-drop handling, and stage updates.
dragAndDropLwc.css: CSS styling to enhance the component’s visual appearance.
dragAndDropList Folder:
dragAndDropList.html: This file contains the HTML template for the component’s user interface.
dragAndDropList.js: The JavaScript file holds the component’s logic.
dragAndDropCard Folder:
dragAndDropCard.html: This file contains the HTML template for the component’s user interface.
dragAndDropCard.js: The JavaScript file holds the component’s logic,
The primary purpose is to create an interactive interface where stages are displayed as tab-like elements, each showing the stage’s name and the count of records associated with it. Users can engage with these stages using drag-and-drop functionality. The component’s structure includes an iteration loop to dynamically generate these elements for each stage. Additionally, the component utilizes a nested child component, c-drag-and-drop-list, to display and manage the records associated with each stage. The main goal is to provide an intuitive way for users to view, interact with, and rearrange records across different stages through a visually engaging and user-friendly interface.
Let’s dive into the code that powers the Drag-and-Drop LWC. JavaScript
Fetching Opportunities and Stages
The connectedCallback method is called when the component is connected to the DOM. Inside this method, the getTopOpportunities Apex method is used to fetch a list of opportunities and their associated stages. The fetched data is stored in the records and pickVals properties.
The for:each loop in the HTML template iterates over each stage in the pickVals array and renders a tab for each stage. The equalwidthHorizontalAndVertical getter calculates the width of each tab based on the number of stages.
The handleListItemDrag method is triggered when an opportunity is dragged within the list. It captures the ID of the dragged opportunity.
handleListItemDrag(event) {
this.recordId = event.detail;
}
Updating Opportunity Stages
The handleItemDrop method is called when an opportunity is dropped onto a new stage. This method triggers the updateHandler to update the opportunity’s stage.
handleItemDrop(event) {
const stage = event.detail;
this.updateHandler(stage);
}
Class: OpportunityKanbanController
Purpose
This class provides backend functionality for retrieving and managing data related to Opportunities in a Kanban view within a Salesforce Lightning component.
Methods
getTopOpportunities()
Description: Retrieves a list of opportunities categorized by priority and stage. Also, provides a count of opportunities in each stage.