diff --git a/oauth_test/sample_app.js b/oauth_test/sample_app.js index 8c55a2ca..09f37935 100644 --- a/oauth_test/sample_app.js +++ b/oauth_test/sample_app.js @@ -23,13 +23,45 @@ function getXeroApp(session) { var app = express(); -app.engine('handlebars', exphbs({ +var exphbs = exphbs.create({ defaultLayout: 'main', layoutsDir: __dirname + '/views/layouts', partialsDir: [ __dirname + '/views/partials/' - ] -})); + ], + helpers: { + ifCond: function(v1, operator, v2, options) { + + switch (operator) { + case '==': + return (v1 == v2) ? options.fn(this) : options.inverse(this); + case '===': + return (v1 === v2) ? options.fn(this) : options.inverse(this); + case '!=': + return (v1 != v2) ? options.fn(this) : options.inverse(this); + case '!==': + return (v1 !== v2) ? options.fn(this) : options.inverse(this); + case '<': + return (v1 < v2) ? options.fn(this) : options.inverse(this); + case '<=': + return (v1 <= v2) ? options.fn(this) : options.inverse(this); + case '>': + return (v1 > v2) ? options.fn(this) : options.inverse(this); + case '>=': + return (v1 >= v2) ? options.fn(this) : options.inverse(this); + case '&&': + return (v1 && v2) ? options.fn(this) : options.inverse(this); + case '||': + return (v1 || v2) ? options.fn(this) : options.inverse(this); + default: + return options.inverse(this); + } + } + } +}); + +app.engine('handlebars', exphbs.engine); + app.set('view engine', 'handlebars'); app.set('views', __dirname + '/views'); @@ -126,6 +158,45 @@ app.get('/contacts', function(req, res) { }) }); +app.get('/banktransactions', function(req, res) { + authorizedOperation(req, res, '/banktransactions', function(xeroApp) { + var bankTransactions = []; + xeroApp.core.bankTransactions.getBankTransactions({ pager: { callback: pagerCallback } }) + .then(function() { + res.render('banktransactions', { bankTransactions: bankTransactions }); + }) + + function pagerCallback(err, response, cb) { + bankTransactions.push.apply(bankTransactions, response.data); + cb() + } + }) +}); + +app.get('/banktransfers', function(req, res) { + authorizedOperation(req, res, '/banktransfers', function(xeroApp) { + var bankTransfers = []; + xeroApp.core.bankTransfers.getBankTransfers({ pager: { callback: pagerCallback } }) + .then(function() { + res.render('banktransfers', { bankTransfers: bankTransfers }); + }) + + function pagerCallback(err, response, cb) { + bankTransfers.push.apply(bankTransfers, response.data); + cb() + } + }) +}); + +app.get('/accounts', function(req, res) { + authorizedOperation(req, res, '/accounts', function(xeroApp) { + xeroApp.core.accounts.getAccounts() + .then(function(accounts) { + res.render('accounts', { accounts: accounts }); + }) + }) +}); + app.get('/timesheets', function(req, res) { authorizedOperation(req, res, '/timesheets', function(xeroApp) { diff --git a/oauth_test/views/accounts.handlebars b/oauth_test/views/accounts.handlebars new file mode 100644 index 00000000..45700595 --- /dev/null +++ b/oauth_test/views/accounts.handlebars @@ -0,0 +1,27 @@ +

Accounts

+ + + + + + + + + + + + {{#each accounts}} + + {{#ifCond this.Type '==' "BANK" }} + + {{else}} + + {{/ifCond}} + + + + + + + {{/each}} +
NameCodeTypeBankAccountNumberBankAccountTypeCurrencyCode
{{this.Name}}{{this.Name}}{{ this.Code }}{{ this.Type }}{{ this.BankAccountNumber }}{{ this.BankAccountType }}{{ this.CurrencyCode }}
\ No newline at end of file diff --git a/oauth_test/views/banktransactions.handlebars b/oauth_test/views/banktransactions.handlebars new file mode 100644 index 00000000..1ae10463 --- /dev/null +++ b/oauth_test/views/banktransactions.handlebars @@ -0,0 +1,23 @@ +

Bank Transactions

+ + + + + + + + + + + + {{#each bankTransactions}} + + + + + + + + + {{/each}} +
Contact NameTransaction Date# Line ItemsSubTotalTaxTotal
{{this.Contact.Name}}{{ this.Date }}{{ this.LineItems.length }}{{ this.SubTotal }}{{ this.TotalTax }}{{ this.Total }}
\ No newline at end of file diff --git a/oauth_test/views/banktransfers.handlebars b/oauth_test/views/banktransfers.handlebars new file mode 100644 index 00000000..61948db7 --- /dev/null +++ b/oauth_test/views/banktransfers.handlebars @@ -0,0 +1,21 @@ +

Bank Transfers

+ + + + + + + + + + + {{#each bankTransfers}} + + + + + + + + {{/each}} +
IDTransfer DateFrom Acct NameTo Acct NameAmount
{{ this.BankTransferID }}{{ this.Date }}{{ this.FromBankAccount.Name }} (ref){{ this.ToBankAccount.Name }} (ref){{ this.Amount }}
\ No newline at end of file diff --git a/oauth_test/views/contacts.handlebars b/oauth_test/views/contacts.handlebars index 467bddc2..e47861e0 100644 --- a/oauth_test/views/contacts.handlebars +++ b/oauth_test/views/contacts.handlebars @@ -2,7 +2,6 @@ - @@ -10,8 +9,7 @@ {{#each contacts}} - - + diff --git a/oauth_test/views/index.handlebars b/oauth_test/views/index.handlebars index ce2f4847..0415c171 100644 --- a/oauth_test/views/index.handlebars +++ b/oauth_test/views/index.handlebars @@ -1,2 +1,200 @@ -

Overview

-

This page talks about how to use the application

\ No newline at end of file +

Xero Node.js - Sample App

+

An API wrapper for the Xero API (http://developer.xero.com).

+

Supports all three applications types:

+ +

+ Features

+

The following endpoints are supported:

+ +

The following features are supported:

+ +

+ Installation

+
$ npm install xero-node --save
+
+

+ External Config

+

This SDK requires the config to be externalised to ensure private keys are not committed into your codebase by mistake.

+

The config file should be set up as follows:

+
{
+    "UserAgent" : "Tester - Application for testing Xero",
+    "ConsumerKey": "AAAAAAAAAAAAAAAAAA",
+    "ConsumerSecret": "BBBBBBBBBBBBBBBBBBBB",
+    "PrivateKeyPath": "/some/path/to/privatekey.pem",
+    "RunscopeBucketId" : "xxxyyyzzzz"
+}
+
+

+ Config Parameters

+
ID Name First name Last name
{{ this.ContactID }}{{ this.Name }}{{ this.Name }} {{ this.FirstName }} {{ this.LastName }}
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ParameterDescriptionMandatory
UserAgentThe useragent that should be used with all calls to the Xero APITrue
ConsumerKeyThe consumer key that is required with all calls to the Xero API.,True
ConsumerSecretThe secret key from the developer portal that is required to authenticate your API callsTrue
PrivateKeyPathThe filesystem path to your privatekey.pem file to sign the API callsTrue
RunscopeBucketIdYour personal runscope bucket for debugging API callsFalse
+
+

RunscopeBucketId has been added to support debugging the SDK. Runscope is a simple tool for Testing Complex + APIs. You can use Runscope to verify that the structure and content of your API calls meets your expectations.

+

Sign up for a free runscope account at runscope.com and place your bucket ID in the config + file to see API calls in real time.

+

Runscope is not endorsed by or affiliated with Xero. This tool was used by the SDK creator when authoring the code only.

+

+ Private App Usage

+
var PrivateApplication = require('xero-node').PrivateApplication;
+var privateApp = new PrivateApplication();
+
+// This checks the ~/.xero/config.json directory by default looking for a config file.
+// Alternatively a path to a JSON file can be provided as a parameter:
+
+var myConfigFile = "/tmp/config.json";
+var privateApp = new PrivateApplication(myConfigFile);
+
+

+ Pubic Usage

+
var PublicApplication = require('xero-node').PublicApplication;
+var publicApp = new PublicApplication(myConfigFile);
+
+

+ Partner Usage - (Not currently tested)

+
var ParnetApplication = require('xero-node').PartnerApplication;
+var partnerApp = new PartnerApplication(myConfigFile);
+
+

+ Examples

+

Print a count of invoices:

+
//Print a count of invoices
+privateApp.core.invoices.getInvoices()
+.then(function(invoices) {
+    console.log("Invoices: " + invoices.length);
+
+}).fail(function(err) {
+    console.error(err);
+});
+
+

Print the name of some filtered contacts:

+
//Print the name of a contact
+privateApp.core.contacts.getContacts({ 
+    where: 'Name.Contains("Bayside")' 
+})
+.then(function(contacts) {
+    contacts.forEach(function(contact) {
+        console.log(contact.Name);
+    });
+}).fail(function(err) {
+    console.error(err);
+});
+
+

Efficient paging:

+
privateApp.core.contacts.getContacts({ pager: {start:1 /* page number */, callback:onContacts}})
+    .fail(function(err) {
+        console.log('Oh no, an error');
+    });
+
+/* Called per page */
+function onContacts(err, response, cb) {
+    var contacts = response.data;
+    if (response.finished) // finished paging
+        ....
+    cb(); // Async support
+}
+
+

Filter support: Modified After

+
// No paging
+publicApp.core.contacts.getContacts({ 
+    modifiedAfter: new Date(2013,1,1) 
+})
+.then(function(contacts) {
+    _.each(contacts,  function(contact) {
+        // Do something with contact
+    })
+})
+
+
+

+ Tests

+

npm test

+

+ Release History

+ +

Copyright © 2017 Tim Shnaider, Guillermo Gette, Andrew Connell, Elliot Shepherd and Jordan Walsh

+

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation + files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software + is furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

\ No newline at end of file diff --git a/oauth_test/views/invoices.handlebars b/oauth_test/views/invoices.handlebars index 58b5a39a..6e9d1695 100644 --- a/oauth_test/views/invoices.handlebars +++ b/oauth_test/views/invoices.handlebars @@ -1,20 +1,36 @@

Invoices

- - - - - - - - - + + + + + + + + {{#each invoices}} - - + {{#ifCond this.Type '==' 'ACCREC'}} + + {{else}} + + {{/ifCond}} @@ -22,4 +38,4 @@ {{/each}} -
IDInvoice NumberDateDue DateStatusTotal
Invoice NumberDateDue DateStatusTotal
{{ this.InvoiceID }}{{ this.InvoiceNumber}} + {{#if this.InvoiceNumber}} + {{this.InvoiceNumber}} + {{else}} + {{this.InvoiceID}} + {{/if}} + + + {{#if this.InvoiceNumber}} + {{this.InvoiceNumber}} + {{else}} + {{this.InvoiceID}} + {{/if}} + + {{ this.Date }} {{ this.DueDate }} {{ this.Status}}Email
\ No newline at end of file + \ No newline at end of file diff --git a/oauth_test/views/partials/nav.handlebars b/oauth_test/views/partials/nav.handlebars index cfc0288d..53b9d9d5 100644 --- a/oauth_test/views/partials/nav.handlebars +++ b/oauth_test/views/partials/nav.handlebars @@ -1,11 +1,14 @@