Google Apps Script snippet for accessing the Quick Books Online API
// 34567890123456789012345678901234567890123456789012345678901234567890123456789 | |
// JSHint - TODO | |
/* jshint asi: true */ | |
(function() {"use strict"})() | |
// API_.gs | |
// ======= | |
// | |
// Wrapper for QuickBooks API | |
var API_ = { | |
/** | |
* Create a new estimate | |
* | |
* @param {String} customerReferenceNumber | |
* | |
* @return {String} the new estimate number | |
*/ | |
createEstimate: function(customerReferenceNumber) { | |
Log.functionEntryPoint() | |
var service = OAuth1_.getService() | |
if (!service.hasAccess()) { | |
throw new Error( | |
'Need to authorise script' + | |
'Open the following URL and re-run the script: ' + service.authorize()) | |
} | |
var companyId = PropertiesService | |
.getUserProperties() | |
.getProperty(PROPERTY_COMPANY_ID) | |
Log.fine('companyId: ' + companyId) | |
var url = QUICKBOOKS_API_URL + 'company/' + companyId + '/estimate' | |
var payload = JSON.stringify({ | |
"Line": [ | |
{ | |
"Id": "1", | |
"LineNum": 1, | |
"Amount": 0, | |
"DetailType": "SalesItemLineDetail", | |
"SalesItemLineDetail": { | |
"ItemRef": { | |
"value": "221", | |
"name": "Dummy Product - DO NOT DELETE" | |
}, | |
"UnitPrice": 0, | |
"Qty": 1, | |
"TaxCodeRef": { | |
"value": "8" | |
} | |
} | |
}, | |
{ | |
"Amount": 0, | |
"DetailType": "SubTotalLineDetail", | |
"SubTotalLineDetail": {} | |
} | |
], | |
"TxnTaxDetail": { | |
"TotalTax": 0, | |
"TaxLine": [ | |
{ | |
"Amount": 0, | |
"DetailType": "TaxLineDetail", | |
"TaxLineDetail": { | |
"TaxRateRef": { | |
"value": "9" | |
}, | |
"PercentBased": true, | |
"TaxPercent": 0, | |
"NetAmountTaxable": 0 | |
} | |
} | |
] | |
}, | |
/* | |
"Line": [ | |
{ | |
"Amount": 0, | |
"DetailType": "SalesItemLineDetail", | |
"SalesItemLineDetail": { | |
"ItemRef": { | |
"value": "221", | |
"name": "Dummy Product" | |
}, | |
"UnitPrice": 0, | |
"Qty": 1, | |
"TaxCodeRef": { | |
"value": "10" | |
} | |
} | |
}, | |
{ | |
"Amount": 0, | |
"DetailType": "SubTotalLineDetail", | |
"SubTotalLineDetail": {} | |
} | |
], | |
"TxnTaxDetail": { | |
"TotalTax": 0 | |
}, | |
*/ | |
/* | |
"Line": [ | |
{ | |
"Amount": 0, | |
"DetailType": "SalesItemLineDetail", | |
"SalesItemLineDetail": { | |
"ItemRef": { | |
"value": "221", | |
"name": "Dummy Product" | |
}, | |
"UnitPrice": 0, | |
"Qty": 0, | |
"TaxCodeRef": { | |
"value": "10" | |
} | |
} | |
}, | |
], | |
*/ | |
"CustomerRef": { | |
"value": customerReferenceNumber, | |
}, | |
}) | |
var options = { | |
headers: { | |
'Accept': 'application/json' | |
}, | |
contentType: 'application/json', | |
method: 'post', | |
payload: payload, | |
muteHttpExceptions: true, | |
} | |
var response = service.fetch(url, options) | |
var code = response.getResponseCode() | |
if (code !== 200) { | |
throw new Error('Fetch failed, code: ' + code + ', message: ' + response.getContentText()) | |
} | |
var result = JSON.parse(response.getContentText()); | |
// Logger.log(JSON.stringify(result, null, 2)) | |
var id = result.Estimate.Id | |
Log.info('Created new estimate, id: ' + id) | |
return id | |
}, // API_.createEstimate() | |
/** | |
* Create a customer | |
* | |
* @param {Number} rowNumber | |
* @param {Sheet} responseSheet | |
* | |
* @return {Object} | |
*/ | |
createCustomer: function(rowNumber, responseSheet) { | |
Log.functionEntryPoint() | |
var service = OAuth1_.getService(); | |
if (!service.hasAccess()) { | |
throw new Error( | |
'Need to authorise script' + | |
'Open the following URL and re-run the script: ' + service.authorize()) | |
} | |
var companyId = PropertiesService | |
.getUserProperties() | |
.getProperty(PROPERTY_COMPANY_ID) | |
Log.fine('companyId: ' + companyId) | |
var url = QUICKBOOKS_API_URL + 'company/' + companyId + '/customer' | |
var customer = getCustomerFromSheet(rowNumber, responseSheet) | |
var payload = JSON.stringify({ | |
DisplayName: customer.client, | |
BillAddr:{ | |
Line1: customer.address, | |
PostalCode: customer.postcode, | |
}, | |
PrimaryPhone: { | |
FreeFormNumber: customer.phoneNumber1, | |
}, | |
AlternatePhone: { | |
FreeFormNumber: customer.phoneNumber2, | |
}, | |
PrimaryEmailAddr: { | |
Address: customer.emailAddress, | |
}, | |
FamilyName: customer.contactName, | |
}) | |
var options = { | |
headers: { | |
'Accept': 'application/json' | |
}, | |
contentType: 'application/json', | |
method: 'post', | |
payload: payload, | |
muteHttpExceptions: true, | |
} | |
var response = service.fetch(url, options) | |
var code = response.getResponseCode() | |
if (code !== 200) { | |
Log.warning('Fetch failed, code: ' + code + ', message: ' + response.getContentText()) | |
// throw new Error('Fetch failed, code: ' + code + ', message: ' + response.getContentText()) | |
return null | |
} | |
var result = JSON.parse(response.getContentText()) | |
// Logger.log('Customer ID: ' + result.Customer.Id) | |
var id = result.Customer.Id | |
Log.info('Created new customer, id: ' + id) | |
return id | |
// Private Functions | |
// ----------------- | |
/** | |
* Get the customer details from the response sheet | |
* | |
* @param {Number} rowNumber | |
* @param {Sheet} sheet | |
* | |
* @return {Object} row object | |
*/ | |
function getCustomerFromSheet(rowNumber, sheet) { | |
Log.functionEntryPoint() | |
var rowRange = sheet.getRange(rowNumber, 1, 1, sheet.getLastColumn()) | |
var rowObject = SsObjects.getRowsData(sheet, rowRange, 1)[0] | |
return rowObject | |
} // getCustomerFromSheet() | |
} // API_.createCustomer() | |
} // API_ |
// From https://github.com/googlesamples/apps-script-oauth1/blob/master/samples/QuickBooks.gs | |
// Consumer key and secret in Config.gs | |
var OAuth1_ = { | |
/** | |
* Connect to the API | |
*/ | |
connect: function() { | |
Log.functionEntryPoint() | |
var service = OAuth1_.getService() | |
if (!service.hasAccess()) { | |
throw new Error( | |
'Need to authorise script' + | |
'Open the following URL and re-run the script: ' + service.authorize()) | |
} else { | |
Log.info('Already connected to QuickBooks API') | |
} | |
}, // connect() | |
/** | |
* Reset the authorization state, so that it can be re-tested. | |
*/ | |
reset: function() { | |
var service = this.getService(); | |
service.reset(); | |
}, | |
/** | |
* Configures the service. | |
*/ | |
getService: function () { | |
return OAuth1.createService('QuickBooks') | |
// Set the endpoint URLs. | |
.setAccessTokenUrl('https://oauth.intuit.com/oauth/v1/get_access_token') | |
.setRequestTokenUrl('https://oauth.intuit.com/oauth/v1/get_request_token') | |
.setAuthorizationUrl('https://appcenter.intuit.com/Connect/Begin') | |
// Set the consumer key and secret. | |
.setConsumerKey(CONSUMER_KEY) | |
.setConsumerSecret(CONSUMER_SECRET) | |
// Set the name of the callback function in the script referenced | |
// above that should be invoked to complete the OAuth flow. | |
.setCallbackFunction('authCallback') | |
// Set the property store where authorized tokens should be persisted. | |
.setPropertyStore(PropertiesService.getUserProperties()); | |
}, | |
} // OAuth_ | |
/** | |
* Handles the OAuth callback. | |
*/ | |
function authCallback(request) { | |
var service = OAuth1_.getService(); | |
var authorized = service.handleCallback(request); | |
if (authorized) { | |
PropertiesService | |
.getUserProperties() | |
.setProperty(PROPERTY_COMPANY_ID, request.parameter.realmId); | |
return HtmlService.createHtmlOutput('Success!'); | |
} else { | |
return HtmlService.createHtmlOutput('Denied'); | |
} | |
} | |
/* | |
{ | |
"CompanyInfo": { | |
"CompanyName": "Sandbox Company_US_1", | |
"LegalName": "Sandbox Company_US_1", | |
"CompanyAddr": { | |
"Id": "1", | |
"Line1": "123 Sierra Way", | |
"City": "San Pablo", | |
"CountrySubDivisionCode": "CA", | |
"PostalCode": "87999", | |
"Lat": "36.6788345", | |
"Long": "-5.4464622" | |
}, | |
"CustomerCommunicationAddr": { | |
"Id": "1", | |
"Line1": "123 Sierra Way", | |
"City": "San Pablo", | |
"CountrySubDivisionCode": "CA", | |
"PostalCode": "87999", | |
"Lat": "36.6788345", | |
"Long": "-5.4464622" | |
}, | |
"LegalAddr": { | |
"Id": "1", | |
"Line1": "123 Sierra Way", | |
"City": "San Pablo", | |
"CountrySubDivisionCode": "CA", | |
"PostalCode": "87999", | |
"Lat": "36.6788345", | |
"Long": "-5.4464622" | |
}, | |
"PrimaryPhone": {}, | |
"CompanyStartDate": "2016-08-02", | |
"FiscalYearStartMonth": "January", | |
"Country": "US", | |
"Email": { | |
"Address": "noreply@quickbooks.com" | |
}, | |
"WebAddr": {}, | |
"SupportedLanguages": "en", | |
"NameValue": [ | |
{ | |
"Name": "NeoEnabled", | |
"Value": "true" | |
}, | |
{ | |
"Name": "IsQbdtMigrated", | |
"Value": "false" | |
}, | |
{ | |
"Name": "CompanyType", | |
"Value": "Other" | |
}, | |
{ | |
"Name": "SubscriptionStatus", | |
"Value": "TRIAL" | |
}, | |
{ | |
"Name": "OfferingSku", | |
"Value": "QuickBooks Online Plus" | |
}, | |
{ | |
"Name": "PayrollFeature", | |
"Value": "false" | |
}, | |
{ | |
"Name": "AccountantFeature", | |
"Value": "false" | |
}, | |
{ | |
"Name": "QBOIndustryType", | |
"Value": "Landscaping Services" | |
}, | |
{ | |
"Name": "ItemCategoriesFeature", | |
"Value": "false" | |
} | |
], | |
"domain": "QBO", | |
"sparse": false, | |
"Id": "1", | |
"SyncToken": "8", | |
"MetaData": { | |
"CreateTime": "2016-08-02T01:04:58-07:00", | |
"LastUpdatedTime": "2016-08-02T02:34:46-07:00" | |
} | |
}, | |
"time": "2016-08-02T03:07:03.743-07:00" | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment