Skip to content

Commit

Permalink
Merge pull request #288 from event-cloud/feature/xero-updates
Browse files Browse the repository at this point in the history
Xero connection
  • Loading branch information
paulkr authored Jul 11, 2023
2 parents c5ffc7f + 3d1b1d3 commit 1a75580
Show file tree
Hide file tree
Showing 7 changed files with 386 additions and 9 deletions.
3 changes: 2 additions & 1 deletion catalog/destinations/xero/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@
"createBuildableEnvVars": true,
"hasEvents": false,
"showEvents": false,
"oauth": true
"oauth": true,
"connectionBundled": true
},
"paths": null,
"events": [],
Expand Down
4 changes: 1 addition & 3 deletions catalog/destinations/xero/docs/connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

Xero is a cloud-based accounting software that helps small businesses manage their finances.

### Generate a Service Account key

-
This Connection requires an OAuth flow to authenticate and must be created via the [Event SDK](https://www.npmjs.com/package/@event-inc/connections).

### IP Whitelisting

Expand Down
44 changes: 39 additions & 5 deletions catalog/destinations/xero/xero.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { XeroClient } from "xero-node";
import axios from "axios";
import { AnyObject, DestinationClassI, TestConnection, Truthy } from "../../../types/destinationClassDefinition";
import jwt_decode from "jwt-decode";

export class XeroDriver implements DestinationClassI {
public client: XeroClient;
Expand Down Expand Up @@ -58,13 +59,23 @@ export class XeroDriver implements DestinationClassI {
// get a valid token set
const validTokenSet = await this.refreshTokenSet();

const accessToken = validTokenSet.access_token;

const decodedToken: {
authentication_event_id: string;
} = jwt_decode(accessToken);

// get and save all registered tenants
const response = await axios.get("https://api.xero.com/connections", {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${validTokenSet.access_token}`,
Authorization: `Bearer ${accessToken}`,
},
params: {
authEventId: decodedToken.authentication_event_id
}
});

this.tenantIds = response.data.map((item: any) => item.tenantId);
} catch (err) {
console.log("Error connecting to Xero", err);
Expand All @@ -78,27 +89,50 @@ export class XeroDriver implements DestinationClassI {

async testConnection(): Promise<TestConnection> {
try {
// get a valid token set
const validTokenSet = await this.refreshTokenSet();

// get and save all registered tenants
const accessToken = validTokenSet.access_token;

const decodedToken: {
authentication_event_id: string;
} = jwt_decode(accessToken);

this.client.setTokenSet(validTokenSet);

const response = await axios.get("https://api.xero.com/connections", {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${validTokenSet.access_token}`,
Authorization: `Bearer ${accessToken}`,
},
params: {
authEventId: decodedToken.authentication_event_id
}
});

this.tenantIds = response.data.map((item: any) => item.tenantId);

if (this.tenantIds.length === 0 || this.tenantIds.length > 1) {
const existingTenants = await axios.get("https://api.xero.com/connections", {
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
}
});

const tenantNames = existingTenants.data.map(item => item.tenantName).join(", ");
const existingTenantsMessage = tenantNames.length > 0 ? ` The following tenants are currently connected: ${tenantNames}.` : "";

throw new Error(`No tenant was explicitly selected on connect.${existingTenantsMessage}Ensure you disconnect and connect again with a single tenant selected.`);
}

await this.client.accountingApi.getAccounts(this.tenantIds[0]);

return {
success: true,
message: "Connection established successfully",
};
} catch (err) {
throw new Error(`Could not establish connection to Xero: ${err.response?.body}`);
throw new Error(err.message || `Could not establish connection to Xero: ${err.response?.body}`);
}
}

Expand Down
201 changes: 201 additions & 0 deletions catalog/sources/xero/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
{
"title": "Xero",
"description": "Xero is a cloud-based accounting software that helps small businesses manage their finances.",
"apiVersion": "NA",
"type": "xero",
"category": "accounting",
"image": "https://assets.buildable.dev/catalog/node-templates/xero.svg",
"tags": ["accounting", "finance", "payroll"],
"authentication": [
{
"name": "XERO_CLIENT_ID",
"label": "Enter your Xero Client ID",
"placeholder": "7C1120751AECA051C1234ABCD190AA92"
},
{
"name": "XERO_CLIENT_SECRET",
"label": "Enter your Xero Client Secret",
"placeholder": "e8uKLzfYb9RXQgD0IcAokNxjW7nHw3Sh1r4sTyvBp6mV-5tJ2"
},
{
"name": "XERO_ACCESS_TOKEN",
"label": "Enter your Xero OAuth2 Access Token",
"placeholder": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjF..."
},
{
"name": "XERO_REFRESH_TOKEN",
"label": "Enter your Xero OAuth2 Refresh Token",
"placeholder": "hUjddv7tUhdcUxJ5UyLYtmwT6_wbkrZc7zj37LCQ0cE"
}
],
"eventSchema": {},
"settings": {
"autoSubscribeAllEvents": true,
"showEvents": true,
"secureAuthFields": true,
"oauth": true,
"connectionBundled": true
},
"paths": {
"id": null,
"event": "_.body.event",
"payload": "_.body",
"secret": null,
"signature": null
},
"events": [
{
"name": "accounting.accounts.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.attachments.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.banktransactions.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.banktransfers.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.batchpayments.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.brandingthemes.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.budgets.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.contactgroups.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.contacts.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.creditnotes.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.currencies.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.employees.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.invoices.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.items.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.journals.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.linkedtransactions.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.manualjournals.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.organisation.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.overpayments.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.paymentservices.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.payments.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.prepayments.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.purchaseorders.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.quotes.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.repeatinginvoices.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.taxrates.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.trackingcategories.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.users.batch-pulled",
"description": "",
"group": "accounting"
},
{
"name": "accounting.batch-pulled.failed",
"description": "",
"group": "accounting"
}
],
"connectionTypes": ["source"],
"testConnection": true,
"classifications": {
"dataIngestion": {
"streamTypes": ["manual"],
"extractionTypes": []
}
}
}
13 changes: 13 additions & 0 deletions catalog/sources/xero/docs/connect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## Connect

Pull historical data from the Xero [Accounting API](https://developer.xero.com/documentation/api/accounting/overview).

This Connection requires an OAuth flow to authenticate and must be created via the [Event SDK](https://www.npmjs.com/package/@event-inc/connections).

### Securely Encrypted

Rest assured, your credentials are securely encrypted to keep your information safe.

### Need Help?

Start a conversation by sending an email to [[email protected]](mailto:[email protected]). Our Data Engineers are available 24/7 to help if you ever get stuck.
3 changes: 3 additions & 0 deletions catalog/sources/xero/docs/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## Xero Source Setup

Check out our [quick start guide](https://docs.event.dev/) to learn how to get started.
Loading

0 comments on commit 1a75580

Please sign in to comment.