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.”
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>