@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.
- package/client/pages/account-xero.js +8 -8
- package/dist-server/controllers/xero/apis/item/get-item.js +4 -5
- package/dist-server/controllers/xero/apis/item/get-item.js.map +1 -1
- package/dist-server/controllers/xero/apis/purchase-order/get-purchase-orders.js +28 -11
- package/dist-server/controllers/xero/apis/purchase-order/get-purchase-orders.js.map +1 -1
- package/dist-server/controllers/xero/platform-action.js +3 -1
- package/dist-server/controllers/xero/platform-action.js.map +1 -1
- package/dist-server/controllers/xero/xero.js +91 -24
- package/dist-server/controllers/xero/xero.js.map +1 -1
- package/package.json +15 -15
- package/server/controllers/xero/apis/item/get-item.ts +3 -6
- package/server/controllers/xero/apis/purchase-order/get-purchase-orders.ts +31 -12
- package/server/controllers/xero/platform-action.ts +4 -1
- package/server/controllers/xero/xero.ts +115 -32
- package/dist-server/controllers/xero/apis/purchaseOrder/get-purchase-orders.js +0 -40
- package/dist-server/controllers/xero/apis/purchaseOrder/get-purchase-orders.js.map +0 -1
- package/dist-server/controllers/xero/apis/purchaseOrder/index.js +0 -14
- package/dist-server/controllers/xero/apis/purchaseOrder/index.js.map +0 -1
|
@@ -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
|
-
|
|
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/{
|
|
7
|
+
path: '/Items/{Code}',
|
|
8
8
|
denormalize(req) {
|
|
9
9
|
return {
|
|
10
10
|
resource: {
|
|
11
|
-
|
|
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,
|
|
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
|
-
|
|
15
|
-
let results =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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":";;;;;;AAAA,4DAA8B;
|
|
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.
|
|
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.
|
|
29
|
-
"@things-factory/auth-ui": "^3.
|
|
30
|
-
"@things-factory/biz-base": "^3.
|
|
31
|
-
"@things-factory/code-ui": "^3.
|
|
32
|
-
"@things-factory/context-ui": "^3.
|
|
33
|
-
"@things-factory/grist-ui": "^3.
|
|
34
|
-
"@things-factory/i18n-ui": "^3.
|
|
35
|
-
"@things-factory/integration-ui": "^3.
|
|
36
|
-
"@things-factory/more-ui": "^3.
|
|
37
|
-
"@things-factory/product-base": "^3.
|
|
38
|
-
"@things-factory/resource-ui": "^3.
|
|
39
|
-
"@things-factory/setting-ui": "^3.
|
|
40
|
-
"@things-factory/system-ui": "^3.
|
|
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": "
|
|
55
|
+
"gitHead": "7e1cfc771ca9e8970d90493d3049d4d589e96f08"
|
|
56
56
|
}
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
export function getItem() {
|
|
2
2
|
return {
|
|
3
3
|
method: 'get',
|
|
4
|
-
path: '/Items/{
|
|
4
|
+
path: '/Items/{Code}',
|
|
5
5
|
denormalize(req) {
|
|
6
6
|
return {
|
|
7
7
|
resource: {
|
|
8
|
-
|
|
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
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
throw response
|
|
65
|
+
} else {
|
|
66
|
+
let result = await response.json()
|
|
67
|
+
debug('response result', result)
|
|
68
|
+
result = this.convertStatusCode(result)
|
|
57
69
|
|
|
58
|
-
|
|
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
|
-
|
|
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
|
-
|
|
87
|
-
|
|
88
|
-
|
|
102
|
+
throw response
|
|
103
|
+
} else {
|
|
104
|
+
let result = await response.json()
|
|
105
|
+
debug('response result', result)
|
|
106
|
+
result = this.convertStatusCode(result)
|
|
89
107
|
|
|
90
|
-
|
|
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
|
-
|
|
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
|
-
|
|
119
|
-
|
|
120
|
-
|
|
140
|
+
throw response
|
|
141
|
+
} else {
|
|
142
|
+
let result = await response.json()
|
|
143
|
+
debug('response result', result)
|
|
144
|
+
result = this.convertStatusCode(result)
|
|
121
145
|
|
|
122
|
-
|
|
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
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
178
|
+
throw response
|
|
179
|
+
} else {
|
|
180
|
+
let result = await response.json()
|
|
181
|
+
debug('response result', result)
|
|
182
|
+
result = this.convertStatusCode(result)
|
|
153
183
|
|
|
154
|
-
|
|
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"}
|