Note:
“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.”
![](https://kreyaconsulting.com/wp-content/uploads/2023/12/ezgif.com-crop-2.gif)
![](https://kreyaconsulting.com/wp-content/uploads/2023/12/ezgif.com-crop-3.gif)
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 class AccountHelperClass {
public static Account createOrUpdateCustomer(Account acc){
if(String.isNotBlank(acc.QBO_Id__c)){
CustomerJSON accountData = AUthCallout .getCustomer(acc);
if(accountData.QueryResponse.Customer != null){
if(accountData.QueryResponse.Customer.size() == 1){
for(CustomerJSON.Customer c : accountData.QueryResponse.Customer){
acc.QBO_Id__c = c.id;
System.debug('QB Id: ' + acc.QBO_Id__c);
acc.QBO_SyncToken__c = c.SyncToken;
System.debug('QB Synctoken: ' + acc.QBO_SyncToken__c );
}
}else{
throw new ListException();
}
}
}
CustomerResponseJSON accountSend = AUthCallout .createCustomer(CustomerMap .mapAccountData(acc));
if(accountSend .Customer.Id != null){
acc.QBO_ID__c = accountSend .Customer.Id;
}
acc.QBO_SyncToken__c = accountSend .Customer.SyncToken;
acc.Sap_Trigger_Date_Time__c=System.Now();
acc.Integration_Result__c='Success';
acc.Integration_Message__c=JSON.serializePretty(accountPushData);
return acc;
}
public static Account getAccount(Id accId){
return [SELECT Id,Name, QBO_Id__c,QBO_SyncToken__c,ShippingCity,ShippingStreet,ShippingState,ShippingCountry,ShippingPostalCod,BillingCity,BillingStreet,BillingCountry,BillingPostalCode FROM Account WHERE Id =: accId];
}
}
public class CustomerMap {
public static String mapAccountData(Account acc){
CustomerJSON.Customer customer = new CustomerJSON.Customer();
customer.CompanyName = acc.Name;
customer.Taxable = True;
customer.SyncToken = acc.QBO_SyncToken__c;
customer.sparse = True;
QBCustomerJSON.BillAddr shipAddy = new QBCustomerJSON.BillAddr();
shipAddy.City = acc.ShippingCity;
shipAddy.Line1 = acc.ShippingStreet;
shipAddy.CountrySubDivisionCode = acc.ShippingState;
shipAddy.PostalCode = acc.ShippingPostalCode;
shipAddy.Country = acc.ShippingCountry;
customer.ShipAddr = shipAddy;
customer.Job = False;
customer.IsProject = False;
customer.Id = acc.QBO_ID__c;
customer.DisplayName = acc.Name;
customer.Active = True;
return JSON.serialize(customer, True);
}
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;
}
}
<apex:page standardController="Account" extensions="CustomerController">
</apex:page>