Skip to content

Instantly share code, notes, and snippets.

@andrewroberts
Created September 25, 2017 11:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save andrewroberts/263863db04b641e9ce92f9a85be87484 to your computer and use it in GitHub Desktop.
Save andrewroberts/263863db04b641e9ce92f9a85be87484 to your computer and use it in GitHub Desktop.
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