@things-factory/integration-accounting 3.6.55 → 3.7.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,9 @@
1
- import { html, css } from 'lit-element'
2
1
  import gql from 'graphql-tag'
2
+ import { css, html } from 'lit-element'
3
3
  import { connect } from 'pwa-helpers/connect-mixin.js'
4
- import { client, store, PageView } from '@things-factory/shell'
4
+
5
+ import { client, PageView, store } from '@things-factory/shell'
6
+
5
7
  import LOGO from '../../assets/images/xero-logo.png'
6
8
 
7
9
  const ACCOUNT_RESULT = `{
@@ -183,8 +185,6 @@ class AccountXero extends connect(store)(PageView) {
183
185
  `
184
186
  }
185
187
 
186
- stateChanged(state) {}
187
-
188
188
  updated(changed) {
189
189
  if (changed.has('account')) {
190
190
  var active = this.account && this.account.status == 'active'
@@ -212,7 +212,7 @@ class AccountXero extends connect(store)(PageView) {
212
212
 
213
213
  const response = await client.query({
214
214
  query: gql`
215
- query($id: String!) {
215
+ query account($id: String!) {
216
216
  account(id: $id) ${ACCOUNT_RESULT}
217
217
  }
218
218
  `,
@@ -234,7 +234,7 @@ class AccountXero extends connect(store)(PageView) {
234
234
  async getXeroAuthURL() {
235
235
  var response = await client.query({
236
236
  query: gql`
237
- query($accounting: String!) {
237
+ query getXeroAuthURL($accounting: String!) {
238
238
  getXeroAuthURL(accounting: $accounting)
239
239
  }
240
240
  `,
@@ -266,7 +266,7 @@ class AccountXero extends connect(store)(PageView) {
266
266
 
267
267
  var response = await client.mutate({
268
268
  mutation: gql`
269
- mutation($id: String!) {
269
+ mutation deactivateXeroAccount($id: String!) {
270
270
  deactivateXeroAccount(id: $id) ${ACCOUNT_RESULT}
271
271
  }
272
272
  `,
@@ -293,7 +293,7 @@ class AccountXero extends connect(store)(PageView) {
293
293
 
294
294
  var response = await client.mutate({
295
295
  mutation: gql`
296
- mutation($id: String!) {
296
+ mutation refreshXeroAccessToken($id: String!) {
297
297
  refreshXeroAccessToken(id: $id) ${ACCOUNT_RESULT}
298
298
  }
299
299
  `,
@@ -4,13 +4,12 @@ exports.getItem = void 0;
4
4
  function getItem() {
5
5
  return {
6
6
  method: 'get',
7
- path: '/Items/{itemId}',
7
+ path: '/Items/{Code}',
8
8
  denormalize(req) {
9
9
  return {
10
10
  resource: {
11
- itemId: req.itemId
12
- },
13
- payload: Object.assign({}, req)
11
+ Code: req.itemCode
12
+ }
14
13
  };
15
14
  },
16
15
  normalize(res) {
@@ -28,7 +27,7 @@ function getItem() {
28
27
  cogsAccountCode
29
28
  };
30
29
  });
31
- return results;
30
+ return results[0];
32
31
  }
33
32
  };
34
33
  }
@@ -1 +1 @@
1
- {"version":3,"file":"get-item.js","sourceRoot":"","sources":["../../../../../server/controllers/xero/apis/item/get-item.ts"],"names":[],"mappings":";;;AAAA,SAAgB,OAAO;IACrB,OAAO;QACL,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,iBAAiB;QACvB,WAAW,CAAC,GAAG;YACb,OAAO;gBACL,QAAQ,EAAE;oBACR,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB;gBACD,OAAO,oBACF,GAAG,CACP;aACF,CAAA;QACH,CAAC;QACD,SAAS,CAAC,GAAG;YACX,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAA;YAEnB,IAAI,OAAO,GAAU,EAAE,CAAA;YAEvB,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;gBACzB,IAAI,EACF,IAAI,EAAE,GAAG,EACT,WAAW,EAAE,WAAW,EACxB,eAAe,EACf,IAAI,EAAE,IAAI,EACV,oBAAoB,EAAE,oBAAoB,EAC1C,yBAAyB,EAAE,oBAAoB,EAChD,GAAG,IAAI,CAAA;gBACR,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,eAAe,CAAA;gBAEtD,OAAO;oBACL,GAAG;oBACH,WAAW;oBACX,IAAI;oBACJ,oBAAoB;oBACpB,oBAAoB;oBACpB,eAAe;iBAChB,CAAA;YACH,CAAC,CAAC,CAAA;YAEF,OAAO,OAAO,CAAA;QAChB,CAAC;KACF,CAAA;AACH,CAAC;AA3CD,0BA2CC"}
1
+ {"version":3,"file":"get-item.js","sourceRoot":"","sources":["../../../../../server/controllers/xero/apis/item/get-item.ts"],"names":[],"mappings":";;;AAAA,SAAgB,OAAO;IACrB,OAAO;QACL,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,eAAe;QACrB,WAAW,CAAC,GAAG;YACb,OAAO;gBACL,QAAQ,EAAE;oBACR,IAAI,EAAE,GAAG,CAAC,QAAQ;iBACnB;aACF,CAAA;QACH,CAAC;QACD,SAAS,CAAC,GAAG;YACX,IAAI,EAAE,KAAK,EAAE,GAAG,GAAG,CAAA;YAEnB,IAAI,OAAO,GAAU,EAAE,CAAA;YAEvB,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;gBACzB,IAAI,EACF,IAAI,EAAE,GAAG,EACT,WAAW,EAAE,WAAW,EACxB,eAAe,EACf,IAAI,EAAE,IAAI,EACV,oBAAoB,EAAE,oBAAoB,EAC1C,yBAAyB,EAAE,oBAAoB,EAChD,GAAG,IAAI,CAAA;gBACR,IAAI,EAAE,WAAW,EAAE,eAAe,EAAE,GAAG,eAAe,CAAA;gBAEtD,OAAO;oBACL,GAAG;oBACH,WAAW;oBACX,IAAI;oBACJ,oBAAoB;oBACpB,oBAAoB;oBACpB,eAAe;iBAChB,CAAA;YACH,CAAC,CAAC,CAAA;YAEF,OAAO,OAAO,CAAC,CAAC,CAAC,CAAA;QACnB,CAAC;KACF,CAAA;AACH,CAAC;AAxCD,0BAwCC"}
@@ -11,17 +11,34 @@ function getPurchaseOrders() {
11
11
  };
12
12
  },
13
13
  normalize(res) {
14
- var { PurchaseOrders } = res;
15
- let results = [];
16
- results = PurchaseOrders.map(purchaseOrder => {
17
- var { PurchaseOrderNumber: refNo, Reference: refNo2, DeliveryDateString, LineItems } = purchaseOrder;
18
- var etaDate = DeliveryDateString !== undefined ? String(DeliveryDateString.split('T')[0]) : 'undefined';
19
- var products = LineItems.length
20
- ? LineItems.map(item => {
21
- var { ItemCode: sku, Quantity: packQty, UnitAmount: unitPrice } = item;
22
- return { product: { sku }, batchId: refNo, packQty, unitPrice };
23
- })
24
- : ['undefined'];
14
+ const { PurchaseOrders } = res;
15
+ let results = PurchaseOrders.map(purchaseOrder => {
16
+ const { PurchaseOrderNumber: refNo, Reference: refNo2, DeliveryDateString, LineItems } = purchaseOrder;
17
+ const etaDate = DeliveryDateString !== undefined ? String(DeliveryDateString.split('T')[0]) : 'undefined';
18
+ let products = LineItems.map(lineItem => {
19
+ return {
20
+ product: { sku: lineItem.ItemCode },
21
+ batchId: refNo,
22
+ packQty: lineItem.Quantity,
23
+ unitPrice: lineItem.UnitAmount
24
+ };
25
+ }).reduce((newItem, item) => {
26
+ var foundItem = newItem.find(newItem => newItem.batchId === item.batchId && newItem.product.sku === item.product.sku);
27
+ if (!foundItem) {
28
+ newItem.push(Object.assign({}, item));
29
+ return newItem;
30
+ }
31
+ else {
32
+ return newItem.map(ni => {
33
+ if (ni.batchId === item.batchId && ni.product.sku === item.product.sku) {
34
+ return Object.assign(Object.assign({}, ni), { packQty: ni.packQty + item.packQty });
35
+ }
36
+ else {
37
+ return ni;
38
+ }
39
+ });
40
+ }
41
+ }, []);
25
42
  return {
26
43
  refNo,
27
44
  refNo2,
@@ -1 +1 @@
1
- {"version":3,"file":"get-purchase-orders.js","sourceRoot":"","sources":["../../../../../server/controllers/xero/apis/purchase-order/get-purchase-orders.ts"],"names":[],"mappings":";;;AAAA,SAAgB,iBAAiB;IAC/B,OAAO;QACL,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,iBAAiB;QACvB,WAAW,CAAC,GAAG;YACb,OAAO;gBACL,OAAO,oBACF,GAAG,CACP;aACF,CAAA;QACH,CAAC;QACD,SAAS,CAAC,GAAG;YACX,IAAI,EAAE,cAAc,EAAE,GAAG,GAAG,CAAA;YAE5B,IAAI,OAAO,GAAU,EAAE,CAAA;YAEvB,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;gBAC3C,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,GAAG,aAAa,CAAA;gBAEpG,IAAI,OAAO,GAAG,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAA;gBAEvG,IAAI,QAAQ,GAAG,SAAS,CAAC,MAAM;oBAC7B,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;wBACnB,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,IAAI,CAAA;wBACtE,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,CAAA;oBACjE,CAAC,CAAC;oBACJ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;gBAEjB,OAAO;oBACL,KAAK;oBACL,MAAM;oBACN,OAAO;oBACP,YAAY,EAAE,IAAI;oBAClB,WAAW,EAAE,KAAK;oBAClB,SAAS,EAAE,KAAK;oBAChB,aAAa,EAAE,QAAQ;iBACxB,CAAA;YACH,CAAC,CAAC,CAAA;YACF,OAAO,OAAO,CAAA;QAChB,CAAC;KACF,CAAA;AACH,CAAC;AAzCD,8CAyCC"}
1
+ {"version":3,"file":"get-purchase-orders.js","sourceRoot":"","sources":["../../../../../server/controllers/xero/apis/purchase-order/get-purchase-orders.ts"],"names":[],"mappings":";;;AAAA,SAAgB,iBAAiB;IAC/B,OAAO;QACL,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,iBAAiB;QACvB,WAAW,CAAC,GAAG;YACb,OAAO;gBACL,OAAO,oBACF,GAAG,CACP;aACF,CAAA;QACH,CAAC;QACD,SAAS,CAAC,GAAG;YACX,MAAM,EAAE,cAAc,EAAE,GAAG,GAAG,CAAA;YAE9B,IAAI,OAAO,GAAU,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;gBACtD,MAAM,EAAE,mBAAmB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,GAAG,aAAa,CAAA;gBACtG,MAAM,OAAO,GAAQ,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAA;gBAE9G,IAAI,QAAQ,GAAU,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;oBAC7C,OAAO;wBACL,OAAO,EAAE,EAAE,GAAG,EAAE,QAAQ,CAAC,QAAQ,EAAE;wBACnC,OAAO,EAAE,KAAK;wBACd,OAAO,EAAE,QAAQ,CAAC,QAAQ;wBAC1B,SAAS,EAAE,QAAQ,CAAC,UAAU;qBAC/B,CAAA;gBACH,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE;oBAC1B,IAAI,SAAS,GAAG,OAAO,CAAC,IAAI,CAC1B,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,CACxF,CAAA;oBACD,IAAI,CAAC,SAAS,EAAE;wBACd,OAAO,CAAC,IAAI,mBAAM,IAAI,EAAG,CAAA;wBACzB,OAAO,OAAO,CAAA;qBACf;yBAAM;wBACL,OAAO,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;4BACtB,IAAI,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;gCACtE,uCACK,EAAE,KACL,OAAO,EAAE,EAAE,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IACnC;6BACF;iCAAM;gCACL,OAAO,EAAE,CAAA;6BACV;wBACH,CAAC,CAAC,CAAA;qBACH;gBACH,CAAC,EAAE,EAAE,CAAC,CAAA;gBAEN,OAAO;oBACL,KAAK;oBACL,MAAM;oBACN,OAAO;oBACP,YAAY,EAAE,IAAI;oBAClB,WAAW,EAAE,KAAK;oBAClB,SAAS,EAAE,KAAK;oBAChB,aAAa,EAAE,QAAQ;iBACxB,CAAA;YACH,CAAC,CAAC,CAAA;YAEF,OAAO,OAAO,CAAA;QAChB,CAAC;KACF,CAAA;AACH,CAAC;AA5DD,8CA4DC"}
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.action = void 0;
4
- const xero_1 = require("./xero");
5
4
  const env_1 = require("@things-factory/env");
5
+ const xero_1 = require("./xero");
6
6
  const xeroConfig = env_1.config.get('accountingIntegrationXero', {});
7
7
  const { apiKey, apiSecret, callback } = xeroConfig;
8
8
  function substitute(path, obj) {
@@ -24,6 +24,8 @@ const action = async ({ accounting, method = 'get', path, request }) => {
24
24
  apiKey,
25
25
  apiSecret,
26
26
  accessToken: accounting.accessToken,
27
+ refreshToken: accounting.refreshToken,
28
+ operatoAccountId: accounting.id,
27
29
  tenantId: accounting.accountId,
28
30
  callback
29
31
  });
@@ -1 +1 @@
1
- {"version":3,"file":"platform-action.js","sourceRoot":"","sources":["../../../server/controllers/xero/platform-action.ts"],"names":[],"mappings":";;;AAAA,iCAA6B;AAE7B,6CAA4C;AAC5C,MAAM,UAAU,GAAG,YAAM,CAAC,GAAG,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAA;AAC9D,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAA;AAElD,SAAS,UAAU,CAAC,IAAI,EAAE,GAAG;IAC3B,IAAI,KAAK,GAAG,EAAE,CAAA;IACd,IAAI,EAAE,GAAG,YAAY,CAAA;IACrB,IAAI,IAAI,CAAA;IAER,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE;QAC7B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;KACpB;IAED,IAAI,MAAM,GAAG,IAAI,CAAA;IACjB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QACnB,IAAI,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC;AAEM,MAAM,MAAM,GAAG,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IAC5E,MAAM,MAAM,GAAG,IAAI,WAAI,CAAC;QACtB,MAAM;QACN,SAAS;QACT,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,QAAQ,EAAE,UAAU,CAAC,SAAS;QAC9B,QAAQ;KACT,CAAC,CAAA;IAEF,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,OAAO,CAAA;IAE/C,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IAEjC,OAAO,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AAC5C,CAAC,CAAA;AAdY,QAAA,MAAM,UAclB"}
1
+ {"version":3,"file":"platform-action.js","sourceRoot":"","sources":["../../../server/controllers/xero/platform-action.ts"],"names":[],"mappings":";;;AAAA,6CAA4C;AAE5C,iCAA6B;AAE7B,MAAM,UAAU,GAAG,YAAM,CAAC,GAAG,CAAC,2BAA2B,EAAE,EAAE,CAAC,CAAA;AAC9D,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,UAAU,CAAA;AAElD,SAAS,UAAU,CAAC,IAAI,EAAE,GAAG;IAC3B,IAAI,KAAK,GAAG,EAAE,CAAA;IACd,IAAI,EAAE,GAAG,YAAY,CAAA;IACrB,IAAI,IAAI,CAAA;IAER,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,EAAE;QAC7B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;KACpB;IAED,IAAI,MAAM,GAAG,IAAI,CAAA;IACjB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QACnB,IAAI,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAA;QAC5B,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,GAAG,EAAE,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAA;AACf,CAAC;AAEM,MAAM,MAAM,GAAG,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IAC5E,MAAM,MAAM,GAAG,IAAI,WAAI,CAAC;QACtB,MAAM;QACN,SAAS;QACT,WAAW,EAAE,UAAU,CAAC,WAAW;QACnC,YAAY,EAAE,UAAU,CAAC,YAAY;QACrC,gBAAgB,EAAE,UAAU,CAAC,EAAE;QAC/B,QAAQ,EAAE,UAAU,CAAC,SAAS;QAC9B,QAAQ;KACT,CAAC,CAAA;IAEF,MAAM,EAAE,QAAQ,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,OAAO,CAAA;IAE/C,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IAEjC,OAAO,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;AAC5C,CAAC,CAAA;AAhBY,QAAA,MAAM,UAgBlB"}
@@ -5,6 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.Xero = void 0;
7
7
  const node_fetch_1 = __importDefault(require("node-fetch"));
8
+ const typeorm_1 = require("typeorm");
9
+ const utils_1 = require("@things-factory/utils");
10
+ const entities_1 = require("../../entities");
8
11
  const ENDPOINT = 'https://api.xero.com/api.xro/2.0';
9
12
  const debug = require('debug')('things-factory:integration-accounting:xero');
10
13
  class Xero {
@@ -16,8 +19,8 @@ class Xero {
16
19
  const { apiKey, callback: redirectUrl } = this.config;
17
20
  return `https://login.xero.com/identity/connect/authorize?response_type=code&client_id=${apiKey}&scope=${scopes}&redirect_uri=${redirectUrl}&state=${nonce}`;
18
21
  }
19
- async get(path, data) {
20
- const { accessToken, tenantId } = this.config;
22
+ async get(path, data, retry = 0) {
23
+ const { apiKey, apiSecret, accessToken, refreshToken, operatoAccountId, tenantId } = this.config;
21
24
  const qs = Object.entries(data)
22
25
  .map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)
23
26
  .join('&');
@@ -33,15 +36,22 @@ class Xero {
33
36
  }
34
37
  });
35
38
  if (!response.ok) {
39
+ if (retry == 0) {
40
+ retry++;
41
+ await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret);
42
+ this.get(path, data, retry);
43
+ }
36
44
  throw response;
37
45
  }
38
- let result = await response.json();
39
- debug('response result', result);
40
- result = this.convertStatusCode(result);
41
- return result;
46
+ else {
47
+ let result = await response.json();
48
+ debug('response result', result);
49
+ result = this.convertStatusCode(result);
50
+ return result;
51
+ }
42
52
  }
43
- async post(path, data = {}) {
44
- const { accessToken, tenantId } = this.config;
53
+ async post(path, data = {}, retry = 0) {
54
+ const { apiKey, apiSecret, accessToken, refreshToken, operatoAccountId, tenantId } = this.config;
45
55
  debug('data', data);
46
56
  const jsondata = JSON.stringify(data);
47
57
  const endpoint = `${ENDPOINT}${path}`;
@@ -57,15 +67,22 @@ class Xero {
57
67
  body: jsondata
58
68
  });
59
69
  if (!response.ok) {
70
+ if (retry == 0) {
71
+ retry++;
72
+ await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret);
73
+ this.post(path, data, retry);
74
+ }
60
75
  throw response;
61
76
  }
62
- let result = await response.json();
63
- debug('response result', result);
64
- result = this.convertStatusCode(result);
65
- return result;
77
+ else {
78
+ let result = await response.json();
79
+ debug('response result', result);
80
+ result = this.convertStatusCode(result);
81
+ return result;
82
+ }
66
83
  }
67
- async put(path, data = {}) {
68
- const { accessToken, tenantId } = this.config;
84
+ async put(path, data = {}, retry = 0) {
85
+ const { apiKey, apiSecret, accessToken, refreshToken, operatoAccountId, tenantId } = this.config;
69
86
  debug('data', data);
70
87
  const jsondata = JSON.stringify(data);
71
88
  const endpoint = `${ENDPOINT}${path}`;
@@ -81,15 +98,22 @@ class Xero {
81
98
  body: jsondata
82
99
  });
83
100
  if (!response.ok) {
101
+ if (retry == 0) {
102
+ retry++;
103
+ await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret);
104
+ this.put(path, data, retry);
105
+ }
84
106
  throw response;
85
107
  }
86
- let result = await response.json();
87
- debug('response result', result);
88
- result = this.convertStatusCode(result);
89
- return result;
108
+ else {
109
+ let result = await response.json();
110
+ debug('response result', result);
111
+ result = this.convertStatusCode(result);
112
+ return result;
113
+ }
90
114
  }
91
- async delete(path, data = {}) {
92
- const { accessToken, tenantId } = this.config;
115
+ async delete(path, data = {}, retry = 0) {
116
+ const { apiKey, apiSecret, accessToken, refreshToken, operatoAccountId, tenantId } = this.config;
93
117
  debug('data', data);
94
118
  const jsondata = JSON.stringify(data);
95
119
  const endpoint = `${ENDPOINT}${path}`;
@@ -105,17 +129,60 @@ class Xero {
105
129
  body: jsondata
106
130
  });
107
131
  if (!response.ok) {
132
+ if (retry == 0) {
133
+ retry++;
134
+ await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret);
135
+ this.delete(path, data, retry);
136
+ }
108
137
  throw response;
109
138
  }
110
- let result = await response.json();
111
- debug('response result', result);
112
- result = this.convertStatusCode(result);
113
- return result;
139
+ else {
140
+ let result = await response.json();
141
+ debug('response result', result);
142
+ result = this.convertStatusCode(result);
143
+ return result;
144
+ }
114
145
  }
115
146
  convertStatusCode(result) {
116
147
  result.ok = result.Status.toLowerCase() === 'ok';
117
148
  return result;
118
149
  }
150
+ async refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret) {
151
+ const repository = (0, typeorm_1.getRepository)(entities_1.Account);
152
+ const account = await repository.findOne({
153
+ where: { id: operatoAccountId }
154
+ });
155
+ const refreshRequestData = {
156
+ grant_type: 'refresh_token',
157
+ refresh_token: refreshToken
158
+ };
159
+ const refreshResponse = await (0, node_fetch_1.default)(`https://identity.xero.com/connect/token`, {
160
+ method: 'post',
161
+ headers: {
162
+ Authorization: `Basic ${Buffer.from(apiKey + ':' + apiSecret).toString('base64')}`,
163
+ 'Content-Type': 'application/x-www-form-urlencoded'
164
+ },
165
+ body: Object.entries(refreshRequestData)
166
+ .map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value))
167
+ .join('&')
168
+ });
169
+ if (!refreshResponse.ok) {
170
+ throw new Error(`get account information failed: ${await refreshResponse.text()}`);
171
+ }
172
+ const body = await refreshResponse.json();
173
+ const { access_token /* token used to call the API */, id_token /* token containing user identity details (only returned if OpenID Connect scopes are requested) */, expires_in /* amount of seconds until the access token expires */, token_type: tokenType /* must be Bearer */, refresh_token
174
+ /* token used to refresh the access token once it has expired (only returned if the offline_access scope is requested).
175
+ */
176
+ } = body;
177
+ const { exp } = (0, utils_1.parseJwt)(access_token);
178
+ var patch = {
179
+ accessToken: access_token,
180
+ refreshToken: refresh_token,
181
+ tokenType,
182
+ expiresIn: new Date(exp * 1000)
183
+ };
184
+ return await repository.save(Object.assign(Object.assign({}, account), patch));
185
+ }
119
186
  }
120
187
  exports.Xero = Xero;
121
188
  //# sourceMappingURL=xero.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"xero.js","sourceRoot":"","sources":["../../../server/controllers/xero/xero.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"xero.js","sourceRoot":"","sources":["../../../server/controllers/xero/xero.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@things-factory/integration-accounting",
3
- "version": "3.6.55",
3
+ "version": "3.7.7",
4
4
  "main": "dist-server/index.js",
5
5
  "browser": "client/index.js",
6
6
  "things-factory": true,
@@ -25,19 +25,19 @@
25
25
  "test": "DEBUG=things-factory:* NODE_ENV=development npx mocha -r ts-node/register ./test/**/*spec.ts"
26
26
  },
27
27
  "dependencies": {
28
- "@things-factory/apptool-ui": "^3.6.55",
29
- "@things-factory/auth-ui": "^3.6.55",
30
- "@things-factory/biz-base": "^3.6.55",
31
- "@things-factory/code-ui": "^3.6.55",
32
- "@things-factory/context-ui": "^3.6.55",
33
- "@things-factory/grist-ui": "^3.6.52",
34
- "@things-factory/i18n-ui": "^3.6.55",
35
- "@things-factory/integration-ui": "^3.6.55",
36
- "@things-factory/more-ui": "^3.6.55",
37
- "@things-factory/product-base": "^3.6.55",
38
- "@things-factory/resource-ui": "^3.6.55",
39
- "@things-factory/setting-ui": "^3.6.55",
40
- "@things-factory/system-ui": "^3.6.55",
28
+ "@things-factory/apptool-ui": "^3.7.5",
29
+ "@things-factory/auth-ui": "^3.7.7",
30
+ "@things-factory/biz-base": "^3.7.5",
31
+ "@things-factory/code-ui": "^3.7.5",
32
+ "@things-factory/context-ui": "^3.7.5",
33
+ "@things-factory/grist-ui": "^3.7.5",
34
+ "@things-factory/i18n-ui": "^3.7.5",
35
+ "@things-factory/integration-ui": "^3.7.5",
36
+ "@things-factory/more-ui": "^3.7.5",
37
+ "@things-factory/product-base": "^3.7.7",
38
+ "@things-factory/resource-ui": "^3.7.7",
39
+ "@things-factory/setting-ui": "^3.7.5",
40
+ "@things-factory/system-ui": "^3.7.5",
41
41
  "debug": "^4.1.1",
42
42
  "node-fetch": "^2.6.0"
43
43
  },
@@ -52,5 +52,5 @@
52
52
  "nock": "^13.0.2",
53
53
  "should": "^13.2.3"
54
54
  },
55
- "gitHead": "a835d6fbfc58a2bef6b1ecb96338cd572a77bdc0"
55
+ "gitHead": "7e1cfc771ca9e8970d90493d3049d4d589e96f08"
56
56
  }
@@ -1,14 +1,11 @@
1
1
  export function getItem() {
2
2
  return {
3
3
  method: 'get',
4
- path: '/Items/{itemId}',
4
+ path: '/Items/{Code}',
5
5
  denormalize(req) {
6
6
  return {
7
7
  resource: {
8
- itemId: req.itemId
9
- },
10
- payload: {
11
- ...req
8
+ Code: req.itemCode
12
9
  }
13
10
  }
14
11
  },
@@ -38,7 +35,7 @@ export function getItem() {
38
35
  }
39
36
  })
40
37
 
41
- return results
38
+ return results[0]
42
39
  }
43
40
  }
44
41
  }
@@ -10,21 +10,39 @@ export function getPurchaseOrders() {
10
10
  }
11
11
  },
12
12
  normalize(res) {
13
- var { PurchaseOrders } = res
13
+ const { PurchaseOrders } = res
14
14
 
15
- let results: any[] = []
15
+ let results: any[] = PurchaseOrders.map(purchaseOrder => {
16
+ const { PurchaseOrderNumber: refNo, Reference: refNo2, DeliveryDateString, LineItems } = purchaseOrder
17
+ const etaDate: any = DeliveryDateString !== undefined ? String(DeliveryDateString.split('T')[0]) : 'undefined'
16
18
 
17
- results = PurchaseOrders.map(purchaseOrder => {
18
- var { PurchaseOrderNumber: refNo, Reference: refNo2, DeliveryDateString, LineItems } = purchaseOrder
19
-
20
- var etaDate = DeliveryDateString !== undefined ? String(DeliveryDateString.split('T')[0]) : 'undefined'
21
-
22
- var products = LineItems.length
23
- ? LineItems.map(item => {
24
- var { ItemCode: sku, Quantity: packQty, UnitAmount: unitPrice } = item
25
- return { product: { sku }, batchId: refNo, packQty, unitPrice }
19
+ let products: any[] = LineItems.map(lineItem => {
20
+ return {
21
+ product: { sku: lineItem.ItemCode },
22
+ batchId: refNo,
23
+ packQty: lineItem.Quantity,
24
+ unitPrice: lineItem.UnitAmount
25
+ }
26
+ }).reduce((newItem, item) => {
27
+ var foundItem = newItem.find(
28
+ newItem => newItem.batchId === item.batchId && newItem.product.sku === item.product.sku
29
+ )
30
+ if (!foundItem) {
31
+ newItem.push({ ...item })
32
+ return newItem
33
+ } else {
34
+ return newItem.map(ni => {
35
+ if (ni.batchId === item.batchId && ni.product.sku === item.product.sku) {
36
+ return {
37
+ ...ni,
38
+ packQty: ni.packQty + item.packQty
39
+ }
40
+ } else {
41
+ return ni
42
+ }
26
43
  })
27
- : ['undefined']
44
+ }
45
+ }, [])
28
46
 
29
47
  return {
30
48
  refNo,
@@ -36,6 +54,7 @@ export function getPurchaseOrders() {
36
54
  orderProducts: products
37
55
  }
38
56
  })
57
+
39
58
  return results
40
59
  }
41
60
  }
@@ -1,6 +1,7 @@
1
+ import { config } from '@things-factory/env'
2
+
1
3
  import { Xero } from './xero'
2
4
 
3
- import { config } from '@things-factory/env'
4
5
  const xeroConfig = config.get('accountingIntegrationXero', {})
5
6
  const { apiKey, apiSecret, callback } = xeroConfig
6
7
 
@@ -27,6 +28,8 @@ export const action = async ({ accounting, method = 'get', path, request }) => {
27
28
  apiKey,
28
29
  apiSecret,
29
30
  accessToken: accounting.accessToken,
31
+ refreshToken: accounting.refreshToken,
32
+ operatoAccountId: accounting.id,
30
33
  tenantId: accounting.accountId,
31
34
  callback
32
35
  })
@@ -1,4 +1,9 @@
1
1
  import fetch from 'node-fetch'
2
+ import { getRepository } from 'typeorm'
3
+
4
+ import { parseJwt } from '@things-factory/utils'
5
+
6
+ import { Account } from '../../entities'
2
7
 
3
8
  const ENDPOINT = 'https://api.xero.com/api.xro/2.0'
4
9
  const debug = require('debug')('things-factory:integration-accounting:xero')
@@ -7,6 +12,8 @@ export type XeroConfig = {
7
12
  apiKey: string
8
13
  apiSecret: string
9
14
  accessToken?: string
15
+ refreshToken?: string
16
+ operatoAccountId?: string
10
17
  tenantId?: string
11
18
  callback?: string
12
19
  }
@@ -27,8 +34,8 @@ export class Xero {
27
34
  return `https://login.xero.com/identity/connect/authorize?response_type=code&client_id=${apiKey}&scope=${scopes}&redirect_uri=${redirectUrl}&state=${nonce}`
28
35
  }
29
36
 
30
- async get(path: string, data: any) {
31
- const { accessToken, tenantId } = this.config
37
+ async get(path: string, data: any, retry = 0) {
38
+ const { apiKey, apiSecret, accessToken, refreshToken, operatoAccountId, tenantId } = this.config
32
39
 
33
40
  const qs = Object.entries(data)
34
41
  .map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)
@@ -48,18 +55,24 @@ export class Xero {
48
55
  })
49
56
 
50
57
  if (!response.ok) {
51
- throw response
52
- }
58
+ if (retry == 0) {
59
+ retry++
60
+ await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret)
61
+ this.get(path, data, retry)
62
+ }
53
63
 
54
- let result = await response.json()
55
- debug('response result', result)
56
- result = this.convertStatusCode(result)
64
+ throw response
65
+ } else {
66
+ let result = await response.json()
67
+ debug('response result', result)
68
+ result = this.convertStatusCode(result)
57
69
 
58
- return result
70
+ return result
71
+ }
59
72
  }
60
73
 
61
- async post(path: string, data: any = {}) {
62
- const { accessToken, tenantId } = this.config
74
+ async post(path: string, data: any = {}, retry = 0) {
75
+ const { apiKey, apiSecret, accessToken, refreshToken, operatoAccountId, tenantId } = this.config
63
76
 
64
77
  debug('data', data)
65
78
 
@@ -80,18 +93,24 @@ export class Xero {
80
93
  })
81
94
 
82
95
  if (!response.ok) {
83
- throw response
84
- }
96
+ if (retry == 0) {
97
+ retry++
98
+ await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret)
99
+ this.post(path, data, retry)
100
+ }
85
101
 
86
- let result = await response.json()
87
- debug('response result', result)
88
- result = this.convertStatusCode(result)
102
+ throw response
103
+ } else {
104
+ let result = await response.json()
105
+ debug('response result', result)
106
+ result = this.convertStatusCode(result)
89
107
 
90
- return result
108
+ return result
109
+ }
91
110
  }
92
111
 
93
- async put(path: string, data: any = {}) {
94
- const { accessToken, tenantId } = this.config
112
+ async put(path: string, data: any = {}, retry = 0) {
113
+ const { apiKey, apiSecret, accessToken, refreshToken, operatoAccountId, tenantId } = this.config
95
114
 
96
115
  debug('data', data)
97
116
 
@@ -112,18 +131,24 @@ export class Xero {
112
131
  })
113
132
 
114
133
  if (!response.ok) {
115
- throw response
116
- }
134
+ if (retry == 0) {
135
+ retry++
136
+ await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret)
137
+ this.put(path, data, retry)
138
+ }
117
139
 
118
- let result = await response.json()
119
- debug('response result', result)
120
- result = this.convertStatusCode(result)
140
+ throw response
141
+ } else {
142
+ let result = await response.json()
143
+ debug('response result', result)
144
+ result = this.convertStatusCode(result)
121
145
 
122
- return result
146
+ return result
147
+ }
123
148
  }
124
149
 
125
- async delete(path: string, data: any = {}) {
126
- const { accessToken, tenantId } = this.config
150
+ async delete(path: string, data: any = {}, retry = 0) {
151
+ const { apiKey, apiSecret, accessToken, refreshToken, operatoAccountId, tenantId } = this.config
127
152
 
128
153
  debug('data', data)
129
154
 
@@ -144,18 +169,76 @@ export class Xero {
144
169
  })
145
170
 
146
171
  if (!response.ok) {
147
- throw response
148
- }
172
+ if (retry == 0) {
173
+ retry++
174
+ await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret)
175
+ this.delete(path, data, retry)
176
+ }
149
177
 
150
- let result = await response.json()
151
- debug('response result', result)
152
- result = this.convertStatusCode(result)
178
+ throw response
179
+ } else {
180
+ let result = await response.json()
181
+ debug('response result', result)
182
+ result = this.convertStatusCode(result)
153
183
 
154
- return result
184
+ return result
185
+ }
155
186
  }
156
187
 
157
188
  private convertStatusCode(result: Record<string, any>): Record<string, any> {
158
189
  result.ok = result.Status.toLowerCase() === 'ok'
159
190
  return result
160
191
  }
192
+
193
+ async refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret) {
194
+ const repository = getRepository(Account)
195
+ const account: any = await repository.findOne({
196
+ where: { id: operatoAccountId }
197
+ })
198
+
199
+ const refreshRequestData = {
200
+ grant_type: 'refresh_token',
201
+ refresh_token: refreshToken
202
+ }
203
+
204
+ const refreshResponse = await fetch(`https://identity.xero.com/connect/token`, {
205
+ method: 'post',
206
+ headers: {
207
+ Authorization: `Basic ${Buffer.from(apiKey + ':' + apiSecret).toString('base64')}`,
208
+ 'Content-Type': 'application/x-www-form-urlencoded'
209
+ },
210
+ body: Object.entries(refreshRequestData)
211
+ .map(([key, value]) => encodeURIComponent(key) + '=' + encodeURIComponent(value))
212
+ .join('&')
213
+ })
214
+
215
+ if (!refreshResponse.ok) {
216
+ throw new Error(`get account information failed: ${await refreshResponse.text()}`)
217
+ }
218
+
219
+ const body = await refreshResponse.json()
220
+ const {
221
+ access_token /* token used to call the API */,
222
+ id_token /* token containing user identity details (only returned if OpenID Connect scopes are requested) */,
223
+ expires_in /* amount of seconds until the access token expires */,
224
+ token_type: tokenType /* must be Bearer */,
225
+ refresh_token
226
+ /* token used to refresh the access token once it has expired (only returned if the offline_access scope is requested).
227
+ */
228
+ } = body
229
+
230
+ const { exp } = parseJwt(access_token)
231
+
232
+ var patch = {
233
+ accessToken: access_token,
234
+ refreshToken: refresh_token,
235
+ tokenType,
236
+ expiresIn: new Date(exp * 1000)
237
+ }
238
+
239
+ return await repository.save({
240
+ ...account,
241
+ ...patch
242
+ })
243
+ }
161
244
  }
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getPurchaseOrders = void 0;
4
- function getPurchaseOrders() {
5
- return {
6
- method: 'get',
7
- path: '/PurchaseOrders',
8
- denormalize(req) {
9
- return {
10
- payload: Object.assign({}, req)
11
- };
12
- },
13
- normalize(res) {
14
- var { PurchaseOrders } = res;
15
- let results = [];
16
- results = PurchaseOrders.map(purchaseOrder => {
17
- var { PurchaseOrderNumber: refNo, Reference: refNo2, DeliveryDateString, LineItems } = purchaseOrder;
18
- var etaDate = DeliveryDateString !== undefined ? String(DeliveryDateString.split('T')[0]) : 'undefined';
19
- var products = LineItems.length
20
- ? LineItems.map(item => {
21
- var { ItemCode: sku, LineItemID: batchId, Quantity: packQty, UnitAmount: unitPrice, Description: remark } = item;
22
- return { product: { sku }, batchId, packQty, unitPrice, remark };
23
- })
24
- : ['undefined'];
25
- return {
26
- refNo,
27
- refNo2,
28
- etaDate,
29
- ownTransport: true,
30
- importCargo: false,
31
- container: false,
32
- orderProducts: products
33
- };
34
- });
35
- return results;
36
- }
37
- };
38
- }
39
- exports.getPurchaseOrders = getPurchaseOrders;
40
- //# sourceMappingURL=get-purchase-orders.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"get-purchase-orders.js","sourceRoot":"","sources":["../../../../../server/controllers/xero/apis/purchaseOrder/get-purchase-orders.ts"],"names":[],"mappings":";;;AAAA,SAAgB,iBAAiB;IAC/B,OAAO;QACL,MAAM,EAAE,KAAK;QACb,IAAI,EAAE,iBAAiB;QACvB,WAAW,CAAC,GAAG;YACb,OAAO;gBACL,OAAO,oBACF,GAAG,CACP;aACF,CAAA;QACH,CAAC;QACD,SAAS,CAAC,GAAG;YACX,IAAI,EAAE,cAAc,EAAE,GAAG,GAAG,CAAA;YAE5B,IAAI,OAAO,GAAU,EAAE,CAAA;YAEvB,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;gBAC3C,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,kBAAkB,EAAE,SAAS,EAAE,GAAG,aAAa,CAAA;gBAEpG,IAAI,OAAO,GAAG,kBAAkB,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAA;gBAEvG,IAAI,QAAQ,GAAG,SAAS,CAAC,MAAM;oBAC7B,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE;wBACnB,IAAI,EACF,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,OAAO,EACnB,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,SAAS,EACrB,WAAW,EAAE,MAAM,EACpB,GAAG,IAAI,CAAA;wBACR,OAAO,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,CAAA;oBAClE,CAAC,CAAC;oBACJ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;gBAEjB,OAAO;oBACL,KAAK;oBACL,MAAM;oBACN,OAAO;oBACP,YAAY,EAAE,IAAI;oBAClB,WAAW,EAAE,KAAK;oBAClB,SAAS,EAAE,KAAK;oBAChB,aAAa,EAAE,QAAQ;iBACxB,CAAA;YACH,CAAC,CAAC,CAAA;YACF,OAAO,OAAO,CAAA;QAChB,CAAC;KACF,CAAA;AACH,CAAC;AA/CD,8CA+CC"}
@@ -1,14 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
- };
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- __exportStar(require("./get-purchase-orders"), exports);
14
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../server/controllers/xero/apis/purchaseOrder/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,wDAAqC"}