@things-factory/integration-accounting 3.7.12 → 3.8.1
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/dist-server/controllers/xero/platform-action.js +15 -3
- package/dist-server/controllers/xero/platform-action.js.map +1 -1
- package/dist-server/controllers/xero/xero.js +28 -59
- package/dist-server/controllers/xero/xero.js.map +1 -1
- package/package.json +14 -14
- package/server/controllers/xero/platform-action.ts +14 -3
- package/server/controllers/xero/xero.ts +37 -66
|
@@ -19,19 +19,31 @@ function substitute(path, obj) {
|
|
|
19
19
|
});
|
|
20
20
|
return result;
|
|
21
21
|
}
|
|
22
|
-
|
|
22
|
+
async function _action({ accounting, method = 'get', path, request }) {
|
|
23
23
|
const client = new xero_1.Xero({
|
|
24
24
|
apiKey,
|
|
25
25
|
apiSecret,
|
|
26
26
|
accessToken: accounting.accessToken,
|
|
27
|
-
refreshToken: accounting.refreshToken,
|
|
28
|
-
operatoAccountId: accounting.id,
|
|
29
27
|
tenantId: accounting.accountId,
|
|
30
28
|
callback
|
|
31
29
|
});
|
|
32
30
|
const { resource = {}, payload = {} } = request;
|
|
33
31
|
path = substitute(path, resource);
|
|
34
32
|
return await client[method](path, payload);
|
|
33
|
+
}
|
|
34
|
+
const action = async ({ accounting, method = 'get', path, request }) => {
|
|
35
|
+
try {
|
|
36
|
+
return await _action({ accounting, method, path, request });
|
|
37
|
+
}
|
|
38
|
+
catch (ex) {
|
|
39
|
+
if (ex.status === 401) {
|
|
40
|
+
var refreshedAccounting = await xero_1.Xero.refreshAccessToken(apiKey, apiSecret, accounting);
|
|
41
|
+
return await _action({ accounting: refreshedAccounting, method, path, request });
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
throw ex;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
35
47
|
};
|
|
36
48
|
exports.action = action;
|
|
37
49
|
//# sourceMappingURL=platform-action.js.map
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAED,KAAK,UAAU,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE;IAClE,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;AAEM,MAAM,MAAM,GAAG,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,GAAG,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE;IAC5E,IAAI;QACF,OAAO,MAAM,OAAO,CAAC,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;KAC5D;IAAC,OAAO,EAAE,EAAE;QACX,IAAI,EAAE,CAAC,MAAM,KAAK,GAAG,EAAE;YACrB,IAAI,mBAAmB,GAAG,MAAM,WAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,CAAC,CAAA;YACtF,OAAO,MAAM,OAAO,CAAC,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;SACjF;aAAM;YACL,MAAM,EAAE,CAAA;SACT;KACF;AACH,CAAC,CAAA;AAXY,QAAA,MAAM,UAWlB"}
|
|
@@ -7,7 +7,7 @@ exports.Xero = void 0;
|
|
|
7
7
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
|
8
8
|
const typeorm_1 = require("typeorm");
|
|
9
9
|
const utils_1 = require("@things-factory/utils");
|
|
10
|
-
const
|
|
10
|
+
const account_1 = require("../../entities/account");
|
|
11
11
|
const ENDPOINT = 'https://api.xero.com/api.xro/2.0';
|
|
12
12
|
const debug = require('debug')('things-factory:integration-accounting:xero');
|
|
13
13
|
class Xero {
|
|
@@ -19,8 +19,8 @@ class Xero {
|
|
|
19
19
|
const { apiKey, callback: redirectUrl } = this.config;
|
|
20
20
|
return `https://login.xero.com/identity/connect/authorize?response_type=code&client_id=${apiKey}&scope=${scopes}&redirect_uri=${redirectUrl}&state=${nonce}`;
|
|
21
21
|
}
|
|
22
|
-
async get(path, data
|
|
23
|
-
const {
|
|
22
|
+
async get(path, data) {
|
|
23
|
+
const { accessToken, tenantId } = this.config;
|
|
24
24
|
const qs = Object.entries(data)
|
|
25
25
|
.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)
|
|
26
26
|
.join('&');
|
|
@@ -36,22 +36,15 @@ class Xero {
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
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
|
-
}
|
|
44
39
|
throw response;
|
|
45
40
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
41
|
+
let result = await response.json();
|
|
42
|
+
debug('response result', result);
|
|
43
|
+
result = this.convertStatusCode(result);
|
|
44
|
+
return result;
|
|
52
45
|
}
|
|
53
|
-
async post(path, data = {}
|
|
54
|
-
const {
|
|
46
|
+
async post(path, data = {}) {
|
|
47
|
+
const { accessToken, tenantId } = this.config;
|
|
55
48
|
debug('data', data);
|
|
56
49
|
const jsondata = JSON.stringify(data);
|
|
57
50
|
const endpoint = `${ENDPOINT}${path}`;
|
|
@@ -67,22 +60,15 @@ class Xero {
|
|
|
67
60
|
body: jsondata
|
|
68
61
|
});
|
|
69
62
|
if (!response.ok) {
|
|
70
|
-
if (retry == 0) {
|
|
71
|
-
retry++;
|
|
72
|
-
await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret);
|
|
73
|
-
this.post(path, data, retry);
|
|
74
|
-
}
|
|
75
63
|
throw response;
|
|
76
64
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return result;
|
|
82
|
-
}
|
|
65
|
+
let result = await response.json();
|
|
66
|
+
debug('response result', result);
|
|
67
|
+
result = this.convertStatusCode(result);
|
|
68
|
+
return result;
|
|
83
69
|
}
|
|
84
|
-
async put(path, data = {}
|
|
85
|
-
const {
|
|
70
|
+
async put(path, data = {}) {
|
|
71
|
+
const { accessToken, tenantId } = this.config;
|
|
86
72
|
debug('data', data);
|
|
87
73
|
const jsondata = JSON.stringify(data);
|
|
88
74
|
const endpoint = `${ENDPOINT}${path}`;
|
|
@@ -98,22 +84,15 @@ class Xero {
|
|
|
98
84
|
body: jsondata
|
|
99
85
|
});
|
|
100
86
|
if (!response.ok) {
|
|
101
|
-
if (retry == 0) {
|
|
102
|
-
retry++;
|
|
103
|
-
await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret);
|
|
104
|
-
this.put(path, data, retry);
|
|
105
|
-
}
|
|
106
87
|
throw response;
|
|
107
88
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
89
|
+
let result = await response.json();
|
|
90
|
+
debug('response result', result);
|
|
91
|
+
result = this.convertStatusCode(result);
|
|
92
|
+
return result;
|
|
114
93
|
}
|
|
115
|
-
async delete(path, data = {}
|
|
116
|
-
const {
|
|
94
|
+
async delete(path, data = {}) {
|
|
95
|
+
const { accessToken, tenantId } = this.config;
|
|
117
96
|
debug('data', data);
|
|
118
97
|
const jsondata = JSON.stringify(data);
|
|
119
98
|
const endpoint = `${ENDPOINT}${path}`;
|
|
@@ -129,32 +108,21 @@ class Xero {
|
|
|
129
108
|
body: jsondata
|
|
130
109
|
});
|
|
131
110
|
if (!response.ok) {
|
|
132
|
-
if (retry == 0) {
|
|
133
|
-
retry++;
|
|
134
|
-
await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret);
|
|
135
|
-
this.delete(path, data, retry);
|
|
136
|
-
}
|
|
137
111
|
throw response;
|
|
138
112
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return result;
|
|
144
|
-
}
|
|
113
|
+
let result = await response.json();
|
|
114
|
+
debug('response result', result);
|
|
115
|
+
result = this.convertStatusCode(result);
|
|
116
|
+
return result;
|
|
145
117
|
}
|
|
146
118
|
convertStatusCode(result) {
|
|
147
119
|
result.ok = result.Status.toLowerCase() === 'ok';
|
|
148
120
|
return result;
|
|
149
121
|
}
|
|
150
|
-
async refreshAccessToken(
|
|
151
|
-
const repository = (0, typeorm_1.getRepository)(entities_1.Account);
|
|
152
|
-
const account = await repository.findOne({
|
|
153
|
-
where: { id: operatoAccountId }
|
|
154
|
-
});
|
|
122
|
+
static async refreshAccessToken(apiKey, apiSecret, account) {
|
|
155
123
|
const refreshRequestData = {
|
|
156
124
|
grant_type: 'refresh_token',
|
|
157
|
-
refresh_token: refreshToken
|
|
125
|
+
refresh_token: account.refreshToken
|
|
158
126
|
};
|
|
159
127
|
const refreshResponse = await (0, node_fetch_1.default)(`https://identity.xero.com/connect/token`, {
|
|
160
128
|
method: 'post',
|
|
@@ -181,6 +149,7 @@ class Xero {
|
|
|
181
149
|
tokenType,
|
|
182
150
|
expiresIn: new Date(exp * 1000)
|
|
183
151
|
};
|
|
152
|
+
const repository = (0, typeorm_1.getRepository)(account_1.Account);
|
|
184
153
|
return await repository.save(Object.assign(Object.assign({}, account), patch));
|
|
185
154
|
}
|
|
186
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xero.js","sourceRoot":"","sources":["../../../server/controllers/xero/xero.ts"],"names":[],"mappings":";;;;;;AAAA,4DAA8B;AAC9B,qCAAuC;AAEvC,iDAAgD;AAEhD,
|
|
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.8.1",
|
|
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.
|
|
28
|
+
"@things-factory/apptool-ui": "^3.8.0",
|
|
29
|
+
"@things-factory/auth-ui": "^3.8.0",
|
|
30
|
+
"@things-factory/biz-base": "^3.8.0",
|
|
31
|
+
"@things-factory/code-ui": "^3.8.0",
|
|
32
|
+
"@things-factory/context-ui": "^3.8.0",
|
|
33
33
|
"@things-factory/grist-ui": "^3.7.5",
|
|
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.
|
|
34
|
+
"@things-factory/i18n-ui": "^3.8.0",
|
|
35
|
+
"@things-factory/integration-ui": "^3.8.0",
|
|
36
|
+
"@things-factory/more-ui": "^3.8.0",
|
|
37
|
+
"@things-factory/product-base": "^3.8.1",
|
|
38
|
+
"@things-factory/resource-ui": "^3.8.0",
|
|
39
|
+
"@things-factory/setting-ui": "^3.8.0",
|
|
40
|
+
"@things-factory/system-ui": "^3.8.0",
|
|
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": "2f2534de2c0866a693f6ec9949b35a5a0e65065f"
|
|
56
56
|
}
|
|
@@ -23,13 +23,11 @@ function substitute(path, obj) {
|
|
|
23
23
|
return result
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
async function _action({ accounting, method = 'get', path, request }) {
|
|
27
27
|
const client = new Xero({
|
|
28
28
|
apiKey,
|
|
29
29
|
apiSecret,
|
|
30
30
|
accessToken: accounting.accessToken,
|
|
31
|
-
refreshToken: accounting.refreshToken,
|
|
32
|
-
operatoAccountId: accounting.id,
|
|
33
31
|
tenantId: accounting.accountId,
|
|
34
32
|
callback
|
|
35
33
|
})
|
|
@@ -40,3 +38,16 @@ export const action = async ({ accounting, method = 'get', path, request }) => {
|
|
|
40
38
|
|
|
41
39
|
return await client[method](path, payload)
|
|
42
40
|
}
|
|
41
|
+
|
|
42
|
+
export const action = async ({ accounting, method = 'get', path, request }) => {
|
|
43
|
+
try {
|
|
44
|
+
return await _action({ accounting, method, path, request })
|
|
45
|
+
} catch (ex) {
|
|
46
|
+
if (ex.status === 401) {
|
|
47
|
+
var refreshedAccounting = await Xero.refreshAccessToken(apiKey, apiSecret, accounting)
|
|
48
|
+
return await _action({ accounting: refreshedAccounting, method, path, request })
|
|
49
|
+
} else {
|
|
50
|
+
throw ex
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -3,7 +3,7 @@ import { getRepository } from 'typeorm'
|
|
|
3
3
|
|
|
4
4
|
import { parseJwt } from '@things-factory/utils'
|
|
5
5
|
|
|
6
|
-
import { Account } from '../../entities'
|
|
6
|
+
import { Account } from '../../entities/account'
|
|
7
7
|
|
|
8
8
|
const ENDPOINT = 'https://api.xero.com/api.xro/2.0'
|
|
9
9
|
const debug = require('debug')('things-factory:integration-accounting:xero')
|
|
@@ -12,8 +12,6 @@ export type XeroConfig = {
|
|
|
12
12
|
apiKey: string
|
|
13
13
|
apiSecret: string
|
|
14
14
|
accessToken?: string
|
|
15
|
-
refreshToken?: string
|
|
16
|
-
operatoAccountId?: string
|
|
17
15
|
tenantId?: string
|
|
18
16
|
callback?: string
|
|
19
17
|
}
|
|
@@ -34,8 +32,8 @@ export class Xero {
|
|
|
34
32
|
return `https://login.xero.com/identity/connect/authorize?response_type=code&client_id=${apiKey}&scope=${scopes}&redirect_uri=${redirectUrl}&state=${nonce}`
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
async get(path: string, data: any
|
|
38
|
-
const {
|
|
35
|
+
async get(path: string, data: any) {
|
|
36
|
+
const { accessToken, tenantId } = this.config
|
|
39
37
|
|
|
40
38
|
const qs = Object.entries(data)
|
|
41
39
|
.map(([k, v]) => `${k}=${encodeURIComponent(String(v))}`)
|
|
@@ -55,24 +53,18 @@ export class Xero {
|
|
|
55
53
|
})
|
|
56
54
|
|
|
57
55
|
if (!response.ok) {
|
|
58
|
-
if (retry == 0) {
|
|
59
|
-
retry++
|
|
60
|
-
await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret)
|
|
61
|
-
this.get(path, data, retry)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
56
|
throw response
|
|
65
|
-
} else {
|
|
66
|
-
let result = await response.json()
|
|
67
|
-
debug('response result', result)
|
|
68
|
-
result = this.convertStatusCode(result)
|
|
69
|
-
|
|
70
|
-
return result
|
|
71
57
|
}
|
|
58
|
+
|
|
59
|
+
let result = await response.json()
|
|
60
|
+
debug('response result', result)
|
|
61
|
+
result = this.convertStatusCode(result)
|
|
62
|
+
|
|
63
|
+
return result
|
|
72
64
|
}
|
|
73
65
|
|
|
74
|
-
async post(path: string, data: any = {}
|
|
75
|
-
const {
|
|
66
|
+
async post(path: string, data: any = {}) {
|
|
67
|
+
const { accessToken, tenantId } = this.config
|
|
76
68
|
|
|
77
69
|
debug('data', data)
|
|
78
70
|
|
|
@@ -93,24 +85,18 @@ export class Xero {
|
|
|
93
85
|
})
|
|
94
86
|
|
|
95
87
|
if (!response.ok) {
|
|
96
|
-
if (retry == 0) {
|
|
97
|
-
retry++
|
|
98
|
-
await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret)
|
|
99
|
-
this.post(path, data, retry)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
88
|
throw response
|
|
103
|
-
} else {
|
|
104
|
-
let result = await response.json()
|
|
105
|
-
debug('response result', result)
|
|
106
|
-
result = this.convertStatusCode(result)
|
|
107
|
-
|
|
108
|
-
return result
|
|
109
89
|
}
|
|
90
|
+
|
|
91
|
+
let result = await response.json()
|
|
92
|
+
debug('response result', result)
|
|
93
|
+
result = this.convertStatusCode(result)
|
|
94
|
+
|
|
95
|
+
return result
|
|
110
96
|
}
|
|
111
97
|
|
|
112
|
-
async put(path: string, data: any = {}
|
|
113
|
-
const {
|
|
98
|
+
async put(path: string, data: any = {}) {
|
|
99
|
+
const { accessToken, tenantId } = this.config
|
|
114
100
|
|
|
115
101
|
debug('data', data)
|
|
116
102
|
|
|
@@ -131,24 +117,18 @@ export class Xero {
|
|
|
131
117
|
})
|
|
132
118
|
|
|
133
119
|
if (!response.ok) {
|
|
134
|
-
if (retry == 0) {
|
|
135
|
-
retry++
|
|
136
|
-
await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret)
|
|
137
|
-
this.put(path, data, retry)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
120
|
throw response
|
|
141
|
-
} else {
|
|
142
|
-
let result = await response.json()
|
|
143
|
-
debug('response result', result)
|
|
144
|
-
result = this.convertStatusCode(result)
|
|
145
|
-
|
|
146
|
-
return result
|
|
147
121
|
}
|
|
122
|
+
|
|
123
|
+
let result = await response.json()
|
|
124
|
+
debug('response result', result)
|
|
125
|
+
result = this.convertStatusCode(result)
|
|
126
|
+
|
|
127
|
+
return result
|
|
148
128
|
}
|
|
149
129
|
|
|
150
|
-
async delete(path: string, data: any = {}
|
|
151
|
-
const {
|
|
130
|
+
async delete(path: string, data: any = {}) {
|
|
131
|
+
const { accessToken, tenantId } = this.config
|
|
152
132
|
|
|
153
133
|
debug('data', data)
|
|
154
134
|
|
|
@@ -169,20 +149,14 @@ export class Xero {
|
|
|
169
149
|
})
|
|
170
150
|
|
|
171
151
|
if (!response.ok) {
|
|
172
|
-
if (retry == 0) {
|
|
173
|
-
retry++
|
|
174
|
-
await this.refreshAccessToken(operatoAccountId, refreshToken, apiKey, apiSecret)
|
|
175
|
-
this.delete(path, data, retry)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
152
|
throw response
|
|
179
|
-
} else {
|
|
180
|
-
let result = await response.json()
|
|
181
|
-
debug('response result', result)
|
|
182
|
-
result = this.convertStatusCode(result)
|
|
183
|
-
|
|
184
|
-
return result
|
|
185
153
|
}
|
|
154
|
+
|
|
155
|
+
let result = await response.json()
|
|
156
|
+
debug('response result', result)
|
|
157
|
+
result = this.convertStatusCode(result)
|
|
158
|
+
|
|
159
|
+
return result
|
|
186
160
|
}
|
|
187
161
|
|
|
188
162
|
private convertStatusCode(result: Record<string, any>): Record<string, any> {
|
|
@@ -190,15 +164,10 @@ export class Xero {
|
|
|
190
164
|
return result
|
|
191
165
|
}
|
|
192
166
|
|
|
193
|
-
async refreshAccessToken(
|
|
194
|
-
const repository = getRepository(Account)
|
|
195
|
-
const account: any = await repository.findOne({
|
|
196
|
-
where: { id: operatoAccountId }
|
|
197
|
-
})
|
|
198
|
-
|
|
167
|
+
public static async refreshAccessToken(apiKey, apiSecret, account) {
|
|
199
168
|
const refreshRequestData = {
|
|
200
169
|
grant_type: 'refresh_token',
|
|
201
|
-
refresh_token: refreshToken
|
|
170
|
+
refresh_token: account.refreshToken
|
|
202
171
|
}
|
|
203
172
|
|
|
204
173
|
const refreshResponse = await fetch(`https://identity.xero.com/connect/token`, {
|
|
@@ -236,6 +205,8 @@ export class Xero {
|
|
|
236
205
|
expiresIn: new Date(exp * 1000)
|
|
237
206
|
}
|
|
238
207
|
|
|
208
|
+
const repository = getRepository(Account)
|
|
209
|
+
|
|
239
210
|
return await repository.save({
|
|
240
211
|
...account,
|
|
241
212
|
...patch
|