@govuk-pay/cli 0.0.121 → 0.0.123
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/package.json
CHANGED
|
@@ -124,7 +124,13 @@ services:
|
|
|
124
124
|
{{#each nodeApps}}
|
|
125
125
|
{{name}}:
|
|
126
126
|
{{#if localBuild}}
|
|
127
|
-
build:
|
|
127
|
+
build:
|
|
128
|
+
context: "$WORKSPACE/pay-{{name}}"
|
|
129
|
+
{{#if ../mountLocalNodeApps}}
|
|
130
|
+
target: base
|
|
131
|
+
{{else}}
|
|
132
|
+
target: final
|
|
133
|
+
{{/if}}
|
|
128
134
|
{{else}}
|
|
129
135
|
image: governmentdigitalservice/pay-{{name}}:{{imageTag}}
|
|
130
136
|
{{/if}}
|
|
@@ -164,6 +170,9 @@ services:
|
|
|
164
170
|
- RUN_APP=true
|
|
165
171
|
- DISABLE_INTERNAL_HTTPS=true
|
|
166
172
|
- PORT={{port}}
|
|
173
|
+
{{#unless ../mountLocalNodeApps}}
|
|
174
|
+
- NODE_OPTIONS=--inspect=0.0.0.0:{{debugPort}}
|
|
175
|
+
{{/unless}}
|
|
167
176
|
{{#if useEgressProxy}}
|
|
168
177
|
- http_proxy=http://egress:8080
|
|
169
178
|
- HTTP_PROXY=http://egress:8080
|
|
@@ -186,13 +195,17 @@ services:
|
|
|
186
195
|
{{/each}}
|
|
187
196
|
mem_limit: 1G
|
|
188
197
|
working_dir: '/app'
|
|
189
|
-
{{#
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
{{
|
|
198
|
+
{{#if localBuild}}
|
|
199
|
+
{{#if ../mountLocalNodeApps}}
|
|
200
|
+
{{#if entrypointOverrideLocal}}
|
|
201
|
+
entrypoint: {{{entrypointOverrideLocal}}}
|
|
202
|
+
{{else}}
|
|
203
|
+
{{#unless isBundled}}
|
|
204
|
+
entrypoint: "npx nodemon --inspect=0.0.0.0:{{debugPort}}"
|
|
205
|
+
{{/unless}}
|
|
206
|
+
{{/if}}
|
|
207
|
+
{{/if}}
|
|
208
|
+
{{/if}}
|
|
196
209
|
ports:
|
|
197
210
|
- "{{port}}:{{port}}"
|
|
198
211
|
{{#if debugPort}}
|
|
@@ -39,10 +39,12 @@ const appClient = {
|
|
|
39
39
|
const typedBody = body;
|
|
40
40
|
return typedBody._links;
|
|
41
41
|
},
|
|
42
|
-
async createService() {
|
|
42
|
+
async createService(serviceName = 'My service') {
|
|
43
43
|
const createServiceData = {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
service_name: {
|
|
45
|
+
en: serviceName,
|
|
46
|
+
cy: `Welsh name for ${serviceName}`
|
|
47
|
+
}
|
|
46
48
|
};
|
|
47
49
|
const url = urlFor('adminusers', '/v1/api/services');
|
|
48
50
|
const result = await (0, fetch_wrapper_1.postRequest)(url, createServiceData);
|
|
@@ -78,11 +80,11 @@ const appClient = {
|
|
|
78
80
|
}
|
|
79
81
|
return account;
|
|
80
82
|
},
|
|
81
|
-
async createAccount(serviceID) {
|
|
83
|
+
async createAccount(serviceID, paymentProvider = 'sandbox', type = 'test') {
|
|
82
84
|
const createAccountData = {
|
|
83
|
-
payment_provider:
|
|
84
|
-
service_name:
|
|
85
|
-
type
|
|
85
|
+
payment_provider: paymentProvider,
|
|
86
|
+
service_name: `My ${type} ${paymentProvider} service`,
|
|
87
|
+
type,
|
|
86
88
|
service_id: serviceID
|
|
87
89
|
};
|
|
88
90
|
const url = urlFor('connector', '/v1/api/accounts');
|
|
@@ -99,6 +101,97 @@ const appClient = {
|
|
|
99
101
|
const typedBody = body;
|
|
100
102
|
return typedBody;
|
|
101
103
|
},
|
|
104
|
+
async completeStripeOnboarding(serviceID) {
|
|
105
|
+
const patchStripeAccountSetupData = [{
|
|
106
|
+
op: 'replace',
|
|
107
|
+
path: 'bank_account',
|
|
108
|
+
value: true
|
|
109
|
+
}, {
|
|
110
|
+
op: 'replace',
|
|
111
|
+
path: 'responsible_person',
|
|
112
|
+
value: true
|
|
113
|
+
}, {
|
|
114
|
+
op: 'replace',
|
|
115
|
+
path: 'vat_number',
|
|
116
|
+
value: true
|
|
117
|
+
}, {
|
|
118
|
+
op: 'replace',
|
|
119
|
+
path: 'company_number',
|
|
120
|
+
value: true
|
|
121
|
+
}, {
|
|
122
|
+
op: 'replace',
|
|
123
|
+
path: 'director',
|
|
124
|
+
value: true
|
|
125
|
+
}, {
|
|
126
|
+
op: 'replace',
|
|
127
|
+
path: 'government_entity_document',
|
|
128
|
+
value: true
|
|
129
|
+
}, {
|
|
130
|
+
op: 'replace',
|
|
131
|
+
path: 'organisation_details',
|
|
132
|
+
value: true
|
|
133
|
+
}];
|
|
134
|
+
const url = urlFor('connector', `/v1/api/service/${serviceID}/account/live/stripe-setup`);
|
|
135
|
+
const result = await (0, fetch_wrapper_1.patchRequest)(url, patchStripeAccountSetupData);
|
|
136
|
+
if (!result.success) {
|
|
137
|
+
console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
return true;
|
|
141
|
+
},
|
|
142
|
+
async enableProviderSwitching(serviceID) {
|
|
143
|
+
const patchProviderSwitchingEnabledData = {
|
|
144
|
+
op: 'replace',
|
|
145
|
+
path: 'provider_switch_enabled',
|
|
146
|
+
value: true
|
|
147
|
+
};
|
|
148
|
+
const url = urlFor('connector', `/v1/api/service/${serviceID}/account/live`);
|
|
149
|
+
const result = await (0, fetch_wrapper_1.patchRequest)(url, patchProviderSwitchingEnabledData);
|
|
150
|
+
if (!result.success) {
|
|
151
|
+
console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
return true;
|
|
155
|
+
},
|
|
156
|
+
async createAccountCredentials(serviceID, paymentProvider) {
|
|
157
|
+
const url = urlFor('connector', `/v1/api/service/${serviceID}/account/live/credentials`);
|
|
158
|
+
const credentialsData = {
|
|
159
|
+
credentials: {},
|
|
160
|
+
payment_provider: paymentProvider
|
|
161
|
+
};
|
|
162
|
+
const result = await (0, fetch_wrapper_1.postRequest)(url, credentialsData);
|
|
163
|
+
if (!result.success) {
|
|
164
|
+
console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
const body = result.successfulResult?.body;
|
|
168
|
+
if (body === undefined || typeof body === 'string') {
|
|
169
|
+
console.error('The response to a create an account did not have a body, or the body was not JSON!');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
const typedBody = body;
|
|
173
|
+
return typedBody;
|
|
174
|
+
},
|
|
175
|
+
async updateStripeAccountCredentials(serviceID, credentialID) {
|
|
176
|
+
const url = urlFor('connector', `/v1/api/service/${serviceID}/account/live/credentials/${credentialID}`);
|
|
177
|
+
const patchAccountCredentialsData = [{
|
|
178
|
+
op: 'replace',
|
|
179
|
+
path: 'credentials',
|
|
180
|
+
value: { stripe_account_id: 'stripe-account-123' }
|
|
181
|
+
}];
|
|
182
|
+
const result = await (0, fetch_wrapper_1.patchRequest)(url, patchAccountCredentialsData);
|
|
183
|
+
if (!result.success) {
|
|
184
|
+
console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const body = result.successfulResult?.body;
|
|
188
|
+
if (body === undefined || typeof body === 'string') {
|
|
189
|
+
console.error('The response to a update a credential did not have a body, or the body was not JSON!');
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const typedBody = body;
|
|
193
|
+
return typedBody;
|
|
194
|
+
},
|
|
102
195
|
async getAccount(gatewayAccountId) {
|
|
103
196
|
const url = urlFor('connector', `/v1/api/accounts/${gatewayAccountId}`);
|
|
104
197
|
const result = await (0, fetch_wrapper_1.getRequest)(url);
|
|
@@ -137,6 +230,20 @@ const appClient = {
|
|
|
137
230
|
}
|
|
138
231
|
return true;
|
|
139
232
|
},
|
|
233
|
+
async setGoLiveStatusToLive(serviceID) {
|
|
234
|
+
const patchGoLiveStatusData = {
|
|
235
|
+
op: 'replace',
|
|
236
|
+
path: 'current_go_live_stage',
|
|
237
|
+
value: 'LIVE'
|
|
238
|
+
};
|
|
239
|
+
const url = urlFor('adminusers', `/v1/api/services/${serviceID}`);
|
|
240
|
+
const result = await (0, fetch_wrapper_1.patchRequest)(url, patchGoLiveStatusData);
|
|
241
|
+
if (!result.success) {
|
|
242
|
+
console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
return true;
|
|
246
|
+
},
|
|
140
247
|
async createToken(gatewayAccountID, serviceExternalId, serviceMode) {
|
|
141
248
|
const createTokenData = {
|
|
142
249
|
account_id: gatewayAccountID,
|
|
@@ -205,6 +312,32 @@ const appClient = {
|
|
|
205
312
|
};
|
|
206
313
|
return typedAugmentedBody;
|
|
207
314
|
},
|
|
315
|
+
async getUser(userEmailAddress) {
|
|
316
|
+
const url = urlFor('adminusers', '/v1/api/users/find');
|
|
317
|
+
const emailData = {
|
|
318
|
+
email: userEmailAddress
|
|
319
|
+
};
|
|
320
|
+
const result = await (0, fetch_wrapper_1.postRequest)(url, emailData);
|
|
321
|
+
if (!result.success) {
|
|
322
|
+
console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const body = result.successfulResult?.body;
|
|
326
|
+
return body;
|
|
327
|
+
},
|
|
328
|
+
async assignUserAsAdminToService(userExternalID, serviceExternalID) {
|
|
329
|
+
const url = urlFor('adminusers', `/v1/api/users/${userExternalID}/services`);
|
|
330
|
+
const serviceRoleData = {
|
|
331
|
+
service_external_id: serviceExternalID,
|
|
332
|
+
role_name: 'admin'
|
|
333
|
+
};
|
|
334
|
+
const result = await (0, fetch_wrapper_1.postRequest)(url, serviceRoleData);
|
|
335
|
+
if (!result.success) {
|
|
336
|
+
console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
return true;
|
|
340
|
+
},
|
|
208
341
|
async isHealthy(serviceName) {
|
|
209
342
|
const url = urlFor(serviceName, '/healthcheck');
|
|
210
343
|
const response = await (0, fetch_wrapper_1.getRequest)(url);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.builder = exports.handler = exports.desc = exports.command = void 0;
|
|
7
|
+
const standardContent_1 = require("../../../core/standardContent");
|
|
8
|
+
const app_client_1 = __importDefault(require("../app_client/app_client"));
|
|
9
|
+
exports.command = 'service <email>';
|
|
10
|
+
exports.desc = 'Create an Adyen migration service';
|
|
11
|
+
exports.handler = serviceHandler;
|
|
12
|
+
const builder = (yargs) => {
|
|
13
|
+
return yargs
|
|
14
|
+
.usage(`$0 local service <email> \n\n${exports.desc}`)
|
|
15
|
+
.positional('email', {
|
|
16
|
+
type: 'string',
|
|
17
|
+
description: 'Email address of an existing user to assign as admin for the service'
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
exports.builder = builder;
|
|
21
|
+
async function serviceHandler(argv) {
|
|
22
|
+
await (0, standardContent_1.showHeader)();
|
|
23
|
+
if (await app_client_1.default.isUnhealthy('adminusers')) {
|
|
24
|
+
console.error('Adminusers is unhealthy');
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (await app_client_1.default.isUnhealthy('connector')) {
|
|
28
|
+
console.error('Connector is unhealthy');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const serviceExternalID = await app_client_1.default.createService('Adyen migration service');
|
|
32
|
+
if (serviceExternalID === undefined) {
|
|
33
|
+
console.error('Unable to create a service');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(`💁 Service ID: ${serviceExternalID}`);
|
|
37
|
+
const userEmailAddress = argv.email;
|
|
38
|
+
const user = await app_client_1.default.getUser(userEmailAddress);
|
|
39
|
+
if (user === undefined) {
|
|
40
|
+
console.error('Failed to retrieve user');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const userAssignedToService = await app_client_1.default.assignUserAsAdminToService(user.external_id, serviceExternalID);
|
|
44
|
+
if (userAssignedToService === undefined) {
|
|
45
|
+
console.error('Failed to add user');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log(`🤓 Assigned user [${user.external_id}] as admin to service [${serviceExternalID}]`);
|
|
49
|
+
const testAccount = await app_client_1.default.createAccount(serviceExternalID);
|
|
50
|
+
if (testAccount === undefined) {
|
|
51
|
+
console.error('Failed to create a fully set up test account');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.log(`🆔 Test gateway account ID: ${testAccount.gateway_account_id}`);
|
|
55
|
+
const liveStripeAccount = await app_client_1.default.createAccount(serviceExternalID, 'stripe', 'live');
|
|
56
|
+
if (liveStripeAccount === undefined) {
|
|
57
|
+
console.error('Failed to create a live Stripe account');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const testAccountID = testAccount.gateway_account_id;
|
|
61
|
+
const liveStripeAccountId = liveStripeAccount.gateway_account_id;
|
|
62
|
+
const gatewayAccountsIDs = [testAccountID, liveStripeAccountId];
|
|
63
|
+
console.log(`🆔 Live Stripe gateway account ID: ${liveStripeAccountId}`);
|
|
64
|
+
for (const accountId of gatewayAccountsIDs) {
|
|
65
|
+
const success = await app_client_1.default.addGatewayAccountToService(accountId, serviceExternalID);
|
|
66
|
+
if (!success) {
|
|
67
|
+
console.error('Failed to add the gateway account to the service');
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.warn(`➕ Added gateway account ID [${accountId}] to Service ID [${serviceExternalID}]`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const stripeAccountSetupTasksCompleted = await app_client_1.default.completeStripeOnboarding(serviceExternalID);
|
|
74
|
+
if (stripeAccountSetupTasksCompleted === undefined) {
|
|
75
|
+
console.error('Failed to complete Stripe onboarding tasks');
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
console.log(`✅ Stripe onboarding tasks completed for gateway account [${liveStripeAccountId}]`);
|
|
79
|
+
const hasLiveStatus = await app_client_1.default.setGoLiveStatusToLive(serviceExternalID);
|
|
80
|
+
if (hasLiveStatus === undefined) {
|
|
81
|
+
console.error('Failed to update go live status for service');
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
console.log(`▶️ Go live status set to live for Service ID [${serviceExternalID}]`);
|
|
85
|
+
const liveStripeAccountResponse = await app_client_1.default.getAccount(liveStripeAccountId);
|
|
86
|
+
if (liveStripeAccountResponse === undefined) {
|
|
87
|
+
console.error(`No gateway account exists with ID: ${liveStripeAccount.gateway_account_id}`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const stripeCredentialID = liveStripeAccountResponse.gateway_account_credentials[0].external_id;
|
|
91
|
+
const stripeGatewayAccountCredential = await app_client_1.default.updateStripeAccountCredentials(serviceExternalID, stripeCredentialID);
|
|
92
|
+
if (stripeGatewayAccountCredential === undefined) {
|
|
93
|
+
console.error('Failed to create a Stripe account credential');
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
console.log(`⬆️ Live Stripe gateway account credential [${stripeGatewayAccountCredential.external_id}] set to active`);
|
|
97
|
+
const adyenGatewayAccountCredential = await app_client_1.default.createAccountCredentials(serviceExternalID, 'adyen');
|
|
98
|
+
if (adyenGatewayAccountCredential === undefined) {
|
|
99
|
+
console.error('Failed to create an Adyen account credential');
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
console.log(`📑 Live Adyen gateway account credential ID: ${adyenGatewayAccountCredential.external_id}`);
|
|
103
|
+
const liveStripeAccountSwitchingFlagEnabled = await app_client_1.default.enableProviderSwitching(serviceExternalID);
|
|
104
|
+
if (liveStripeAccountSwitchingFlagEnabled === undefined) {
|
|
105
|
+
console.error('Failed to enable provider switching');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
console.log(`🔁 Provider switching enabled for account [${liveStripeAccountId}]`);
|
|
109
|
+
}
|