@defra-fish/recurring-payments-job 1.64.0-rc.0 → 1.64.0-rc.10
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/README.md
CHANGED
|
@@ -8,21 +8,13 @@ When the RP job runs, all RP entries with an nextDueDate of the current date, a
|
|
|
8
8
|
|
|
9
9
|
# Environment variables
|
|
10
10
|
|
|
11
|
-
| name | description | required | default | valid | notes
|
|
12
|
-
| ------------------------------ | --------------------------------------------------------------- | :------: | ------------------- | ----------------------------- |
|
|
13
|
-
| NODE_ENV | Node environment | no | | development, test, production |
|
|
14
|
-
| RUN_RECURRING_PAYMENTS | Determine whether to run recurring payments job or not | yes | | |
|
|
15
|
-
| SALES_API_URL | URL for the sales API | no | http://0.0.0.0:4000 | |
|
|
16
|
-
| SALES_API_TIMEOUT_MS | The timeout in milliseconds requests to the API | no | 10000 | |
|
|
17
|
-
|
|
|
18
|
-
| OAUTH_TENANT | OAuth 2.0 tenant | yes | | | |
|
|
19
|
-
| OAUTH_CLIENT_ID | OAuth 2.0 client ID for client credentials flow | yes | | | |
|
|
20
|
-
| OAUTH_CLIENT_SECRET | OAuth 2.0 client secret for client credentials flow | yes | | | |
|
|
21
|
-
| OAUTH_SCOPE | OAuth 2.0 scope to request (client credentials resource) | yes | | | |
|
|
22
|
-
| DYNAMICS_API_PATH | Full URL to the Dynamics API | yes | | | The full URL to the dynamics web api. e.g. https://dynamics-server/api/data/v9.1/ |
|
|
23
|
-
| DYNAMICS_API_VERSION | The version of the Dynamics API | yes | | | The version of the dynamics web api. e.g. 9.1 |
|
|
24
|
-
| 1 |
|
|
25
|
-
| RECURRING_PAYMENTS_LOCAL_DELAY | Delay for running recurring payments until sales api is running | no | | | | |
|
|
11
|
+
| name | description | required | default | valid | notes |
|
|
12
|
+
| ------------------------------ | --------------------------------------------------------------- | :------: | ------------------- | ----------------------------- | ----- |
|
|
13
|
+
| NODE_ENV | Node environment | no | | development, test, production | |
|
|
14
|
+
| RUN_RECURRING_PAYMENTS | Determine whether to run recurring payments job or not | yes | | | |
|
|
15
|
+
| SALES_API_URL | URL for the sales API | no | http://0.0.0.0:4000 | | |
|
|
16
|
+
| SALES_API_TIMEOUT_MS | The timeout in milliseconds requests to the API | no | 10000 | | |
|
|
17
|
+
| RECURRING_PAYMENTS_LOCAL_DELAY | Delay for running recurring payments until sales api is running | no | | | |
|
|
26
18
|
|
|
27
19
|
### See also:
|
|
28
20
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@defra-fish/recurring-payments-job",
|
|
3
|
-
"version": "1.64.0-rc.
|
|
3
|
+
"version": "1.64.0-rc.10",
|
|
4
4
|
"description": "Rod Licensing Recurring Payments Job",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"test": "echo \"Error: run tests from root\" && exit 1"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@defra-fish/business-rules-lib": "1.64.0-rc.
|
|
40
|
-
"@defra-fish/connectors-lib": "1.64.0-rc.
|
|
41
|
-
"commander": "
|
|
42
|
-
"debug": "
|
|
43
|
-
"moment-timezone": "
|
|
39
|
+
"@defra-fish/business-rules-lib": "1.64.0-rc.10",
|
|
40
|
+
"@defra-fish/connectors-lib": "1.64.0-rc.10",
|
|
41
|
+
"commander": "7.2.0",
|
|
42
|
+
"debug": "4.3.3",
|
|
43
|
+
"moment-timezone": "0.5.34"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "c70266a7758feee3a9eb9a6b68304d767c4929ce"
|
|
46
46
|
}
|
|
@@ -70,6 +70,13 @@ const getMockDueRecurringPayment = ({ agreementId = 'test-agreement-id', id = 'a
|
|
|
70
70
|
expanded: { activePermission: { entity: { referenceNumber } } }
|
|
71
71
|
})
|
|
72
72
|
|
|
73
|
+
// eslint-disable-next-line camelcase
|
|
74
|
+
const getMockSendPaymentResponse = ({ payment_id = 'pay-1', agreementId = 'agr-1', created_date = '2025-01-01T00:00:00.000Z' } = {}) => ({
|
|
75
|
+
payment_id,
|
|
76
|
+
agreementId,
|
|
77
|
+
created_date
|
|
78
|
+
})
|
|
79
|
+
|
|
73
80
|
describe('recurring-payments-processor', () => {
|
|
74
81
|
const [{ value: debugLogger }] = db.mock.results
|
|
75
82
|
|
|
@@ -209,7 +216,8 @@ describe('recurring-payments-processor', () => {
|
|
|
209
216
|
})
|
|
210
217
|
|
|
211
218
|
describe('When payment request throws an error...', () => {
|
|
212
|
-
it('
|
|
219
|
+
it('console.error is called with error message', async () => {
|
|
220
|
+
jest.spyOn(console, 'error')
|
|
213
221
|
salesApi.getDueRecurringPayments.mockReturnValueOnce(getMockPaymentRequestResponse())
|
|
214
222
|
const oopsie = new Error('payment gate down')
|
|
215
223
|
sendPayment.mockRejectedValueOnce(oopsie)
|
|
@@ -218,7 +226,7 @@ describe('recurring-payments-processor', () => {
|
|
|
218
226
|
await execute()
|
|
219
227
|
} catch {}
|
|
220
228
|
|
|
221
|
-
expect(
|
|
229
|
+
expect(console.error).toHaveBeenCalledWith(expect.any(String), oopsie)
|
|
222
230
|
})
|
|
223
231
|
|
|
224
232
|
it('prepares and sends all payment requests, even if some fail', async () => {
|
|
@@ -277,6 +285,7 @@ describe('recurring-payments-processor', () => {
|
|
|
277
285
|
})
|
|
278
286
|
|
|
279
287
|
it('logs an error for every failure', async () => {
|
|
288
|
+
jest.spyOn(console, 'error')
|
|
280
289
|
const errors = [new Error('error 1'), new Error('error 2'), new Error('error 3')]
|
|
281
290
|
salesApi.getDueRecurringPayments.mockReturnValueOnce([
|
|
282
291
|
getMockDueRecurringPayment({ referenceNumber: 'fee', agreementId: 'a1' }),
|
|
@@ -293,7 +302,7 @@ describe('recurring-payments-processor', () => {
|
|
|
293
302
|
|
|
294
303
|
await execute()
|
|
295
304
|
|
|
296
|
-
expect(
|
|
305
|
+
expect(console.error).toHaveBeenCalledWith(expect.any(String), ...errors)
|
|
297
306
|
})
|
|
298
307
|
})
|
|
299
308
|
|
|
@@ -577,6 +586,7 @@ describe('recurring-payments-processor', () => {
|
|
|
577
586
|
})
|
|
578
587
|
|
|
579
588
|
it('logs an error if createTransaction fails', async () => {
|
|
589
|
+
jest.spyOn(console, 'error')
|
|
580
590
|
salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
|
|
581
591
|
const error = new Error('Wuh-oh!')
|
|
582
592
|
salesApi.createTransaction.mockImplementationOnce(() => {
|
|
@@ -585,9 +595,142 @@ describe('recurring-payments-processor', () => {
|
|
|
585
595
|
|
|
586
596
|
await execute()
|
|
587
597
|
|
|
588
|
-
expect(
|
|
598
|
+
expect(console.error).toHaveBeenCalledWith(expect.any(String), error)
|
|
599
|
+
})
|
|
600
|
+
|
|
601
|
+
// --- //
|
|
602
|
+
|
|
603
|
+
it('should log errors from await salesApi.processRPResult', async () => {
|
|
604
|
+
salesApi.getDueRecurringPayments.mockResolvedValueOnce([getMockDueRecurringPayment()])
|
|
605
|
+
salesApi.createTransaction.mockResolvedValueOnce({ id: 'trans-1', cost: 30 })
|
|
606
|
+
|
|
607
|
+
const payment = getMockSendPaymentResponse()
|
|
608
|
+
sendPayment.mockResolvedValueOnce(payment)
|
|
609
|
+
|
|
610
|
+
getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
|
|
611
|
+
|
|
612
|
+
const boom = new Error('boom')
|
|
613
|
+
|
|
614
|
+
salesApi.processRPResult.mockImplementation(transId => (transId === 'trans-1' ? Promise.reject(boom) : Promise.resolve()))
|
|
615
|
+
|
|
616
|
+
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
617
|
+
|
|
618
|
+
await execute()
|
|
619
|
+
|
|
620
|
+
expect(errorSpy).toHaveBeenCalledWith('Failed to process Recurring Payment for trans-1', boom)
|
|
621
|
+
|
|
622
|
+
errorSpy.mockRestore()
|
|
589
623
|
})
|
|
590
624
|
|
|
625
|
+
describe('handling failures for multiple due payments', () => {
|
|
626
|
+
beforeEach(() => {
|
|
627
|
+
salesApi.getDueRecurringPayments.mockResolvedValueOnce([getMockDueRecurringPayment(), getMockDueRecurringPayment()])
|
|
628
|
+
|
|
629
|
+
salesApi.preparePermissionDataForRenewal.mockResolvedValueOnce({ licensee: { countryCode: 'GB-ENG' } })
|
|
630
|
+
|
|
631
|
+
salesApi.createTransaction.mockResolvedValueOnce({ id: 'trans-1', cost: 30 }).mockResolvedValueOnce({ id: 'trans-2', cost: 30 })
|
|
632
|
+
})
|
|
633
|
+
|
|
634
|
+
it('continues when one sendPayment rejects (Promise.allSettled check)', async () => {
|
|
635
|
+
const secondPayment = getMockSendPaymentResponse({
|
|
636
|
+
payment_id: 'test-payment-second',
|
|
637
|
+
agreementId: 'agr-2',
|
|
638
|
+
created_date: '2025-01-01T00:00:00.000Z'
|
|
639
|
+
})
|
|
640
|
+
|
|
641
|
+
const gatewayDown = new Error('gateway down')
|
|
642
|
+
sendPayment.mockRejectedValueOnce(gatewayDown).mockResolvedValueOnce(secondPayment)
|
|
643
|
+
getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
|
|
644
|
+
salesApi.processRPResult.mockResolvedValueOnce()
|
|
645
|
+
|
|
646
|
+
await execute()
|
|
647
|
+
|
|
648
|
+
const summary = {
|
|
649
|
+
statusArgs: getPaymentStatus.mock.calls,
|
|
650
|
+
rpResultArgs: salesApi.processRPResult.mock.calls
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
expect(summary).toEqual({
|
|
654
|
+
statusArgs: [[secondPayment.payment_id]],
|
|
655
|
+
rpResultArgs: [['trans-2', secondPayment.payment_id, secondPayment.created_date]]
|
|
656
|
+
})
|
|
657
|
+
})
|
|
658
|
+
|
|
659
|
+
it('continues when processRPResult rejects for one payment', async () => {
|
|
660
|
+
const firstPayment = getMockSendPaymentResponse({
|
|
661
|
+
payment_id: 'pay-1',
|
|
662
|
+
agreementId: 'agr-1',
|
|
663
|
+
created_date: '2025-01-01T00:00:00.000Z'
|
|
664
|
+
})
|
|
665
|
+
const secondPayment = getMockSendPaymentResponse({
|
|
666
|
+
payment_id: 'pay-2',
|
|
667
|
+
agreementId: 'agr-2',
|
|
668
|
+
created_date: '2025-01-01T00:01:00.000Z'
|
|
669
|
+
})
|
|
670
|
+
|
|
671
|
+
sendPayment.mockResolvedValueOnce(firstPayment).mockResolvedValueOnce(secondPayment)
|
|
672
|
+
getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess()).mockResolvedValueOnce(getPaymentStatusSuccess())
|
|
673
|
+
|
|
674
|
+
const boom = new Error('boom')
|
|
675
|
+
salesApi.processRPResult.mockImplementation(transId => (transId === 'trans-1' ? Promise.reject(boom) : Promise.resolve()))
|
|
676
|
+
|
|
677
|
+
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
678
|
+
|
|
679
|
+
await execute()
|
|
680
|
+
|
|
681
|
+
const summary = {
|
|
682
|
+
rpResultArgs: salesApi.processRPResult.mock.calls,
|
|
683
|
+
rpCount: salesApi.processRPResult.mock.calls.length,
|
|
684
|
+
firstError: errorSpy.mock.calls[0]
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
errorSpy.mockRestore()
|
|
688
|
+
|
|
689
|
+
expect(summary).toEqual({
|
|
690
|
+
rpResultArgs: expect.arrayContaining([
|
|
691
|
+
['trans-1', firstPayment.payment_id, firstPayment.created_date],
|
|
692
|
+
['trans-2', secondPayment.payment_id, secondPayment.created_date]
|
|
693
|
+
]),
|
|
694
|
+
rpCount: 2,
|
|
695
|
+
firstError: ['Failed to process Recurring Payment for trans-1', boom]
|
|
696
|
+
})
|
|
697
|
+
})
|
|
698
|
+
|
|
699
|
+
it('does not abort when getPaymentStatus rejects for one payment (allSettled at status stage)', async () => {
|
|
700
|
+
const p1 = getMockSendPaymentResponse({ payment_id: 'pay-1', created_date: '2025-01-01T00:00:00.000Z' })
|
|
701
|
+
const p2 = getMockSendPaymentResponse({ payment_id: 'pay-2', created_date: '2025-01-01T00:01:00.000Z' })
|
|
702
|
+
|
|
703
|
+
sendPayment.mockResolvedValueOnce(p1).mockResolvedValueOnce(p2)
|
|
704
|
+
|
|
705
|
+
getPaymentStatus.mockImplementation(async id => {
|
|
706
|
+
if (id === p1.payment_id) {
|
|
707
|
+
throw Object.assign(new Error('HTTP 500'), { response: { status: 500, data: 'boom' } })
|
|
708
|
+
}
|
|
709
|
+
return getPaymentStatusSuccess()
|
|
710
|
+
})
|
|
711
|
+
|
|
712
|
+
salesApi.processRPResult.mockResolvedValueOnce()
|
|
713
|
+
|
|
714
|
+
await execute()
|
|
715
|
+
|
|
716
|
+
const summary = {
|
|
717
|
+
statusArgs: getPaymentStatus.mock.calls,
|
|
718
|
+
statusCount: getPaymentStatus.mock.calls.length,
|
|
719
|
+
rpResultArgs: salesApi.processRPResult.mock.calls,
|
|
720
|
+
rpCount: salesApi.processRPResult.mock.calls.length
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
expect(summary).toEqual({
|
|
724
|
+
statusArgs: expect.arrayContaining([[p1.payment_id], [p2.payment_id]]),
|
|
725
|
+
statusCount: 2,
|
|
726
|
+
rpResultArgs: expect.arrayContaining([['trans-2', p2.payment_id, p2.created_date]]),
|
|
727
|
+
rpCount: 1
|
|
728
|
+
})
|
|
729
|
+
})
|
|
730
|
+
})
|
|
731
|
+
|
|
732
|
+
// --- //
|
|
733
|
+
|
|
591
734
|
it.each([
|
|
592
735
|
[400, 'Failed to fetch status for payment test-payment-id, error 400'],
|
|
593
736
|
[486, 'Failed to fetch status for payment test-payment-id, error 486'],
|
|
@@ -596,6 +739,7 @@ describe('recurring-payments-processor', () => {
|
|
|
596
739
|
[512, 'Payment status API error for test-payment-id, error 512'],
|
|
597
740
|
[599, 'Payment status API error for test-payment-id, error 599']
|
|
598
741
|
])('logs the correct message when getPaymentStatus rejects with HTTP %i', async (statusCode, expectedMessage) => {
|
|
742
|
+
jest.spyOn(console, 'error')
|
|
599
743
|
const mockPaymentId = 'test-payment-id'
|
|
600
744
|
const mockResponse = [
|
|
601
745
|
{ entity: { agreementId: 'agreement-1' }, expanded: { activePermission: { entity: { referenceNumber: 'ref-1' } } } }
|
|
@@ -613,10 +757,11 @@ describe('recurring-payments-processor', () => {
|
|
|
613
757
|
|
|
614
758
|
await execute()
|
|
615
759
|
|
|
616
|
-
expect(
|
|
760
|
+
expect(console.error).toHaveBeenCalledWith(expectedMessage)
|
|
617
761
|
})
|
|
618
762
|
|
|
619
763
|
it('logs the generic unexpected-error message and still rejects', async () => {
|
|
764
|
+
jest.spyOn(console, 'error')
|
|
620
765
|
const mockPaymentId = 'test-payment-id'
|
|
621
766
|
salesApi.getDueRecurringPayments.mockResolvedValueOnce(getMockPaymentRequestResponse())
|
|
622
767
|
salesApi.createTransaction.mockResolvedValueOnce({ id: mockPaymentId })
|
|
@@ -631,7 +776,7 @@ describe('recurring-payments-processor', () => {
|
|
|
631
776
|
|
|
632
777
|
await execute()
|
|
633
778
|
|
|
634
|
-
expect(
|
|
779
|
+
expect(console.error).toHaveBeenCalledWith(`Unexpected error fetching payment status for ${mockPaymentId}.`)
|
|
635
780
|
})
|
|
636
781
|
|
|
637
782
|
it('should call setTimeout with correct delay when there are recurring payments', async () => {
|
|
@@ -70,7 +70,7 @@ const requestPayments = async dueRCPayments => {
|
|
|
70
70
|
const payments = paymentRequestResults.filter(prr => prr.status === 'fulfilled').map(p => p.value)
|
|
71
71
|
const failures = paymentRequestResults.filter(prr => prr.status === 'rejected').map(f => f.reason)
|
|
72
72
|
if (failures.length) {
|
|
73
|
-
|
|
73
|
+
console.error('Error requesting payments:', ...failures)
|
|
74
74
|
}
|
|
75
75
|
return payments
|
|
76
76
|
}
|
|
@@ -155,8 +155,13 @@ const processRecurringPaymentStatus = async payment => {
|
|
|
155
155
|
debug(`Payment status for ${payment.paymentId}: ${status}`)
|
|
156
156
|
|
|
157
157
|
if (status === PAYMENT_STATUS.Success) {
|
|
158
|
-
|
|
159
|
-
|
|
158
|
+
try {
|
|
159
|
+
await salesApi.processRPResult(payment.transaction.id, payment.paymentId, payment.created_date)
|
|
160
|
+
debug(`Processed Recurring Payment for ${payment.transaction.id}`)
|
|
161
|
+
} catch (err) {
|
|
162
|
+
console.error(`Failed to process Recurring Payment for ${payment.transaction.id}`, err)
|
|
163
|
+
throw err
|
|
164
|
+
}
|
|
160
165
|
}
|
|
161
166
|
if (status === PAYMENT_STATUS.Failure || status === PAYMENT_STATUS.Error) {
|
|
162
167
|
console.error(
|
|
@@ -173,11 +178,11 @@ const processRecurringPaymentStatus = async payment => {
|
|
|
173
178
|
const status = error.response?.status
|
|
174
179
|
|
|
175
180
|
if (isClientError(status)) {
|
|
176
|
-
|
|
181
|
+
console.error(`Failed to fetch status for payment ${payment.paymentId}, error ${status}`)
|
|
177
182
|
} else if (isServerError(status)) {
|
|
178
|
-
|
|
183
|
+
console.error(`Payment status API error for ${payment.paymentId}, error ${status}`)
|
|
179
184
|
} else {
|
|
180
|
-
|
|
185
|
+
console.error(`Unexpected error fetching payment status for ${payment.paymentId}.`)
|
|
181
186
|
}
|
|
182
187
|
}
|
|
183
188
|
}
|
|
@@ -57,19 +57,6 @@ describe('govuk-pay-service', () => {
|
|
|
57
57
|
}
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
-
it('should log error message when the GOV.UK Pay API raises an error', async () => {
|
|
61
|
-
const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
|
|
62
|
-
govUkPayApi.createPayment.mockImplementationOnce(() => {
|
|
63
|
-
throw new Error()
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
await sendPayment(preparedPayment)
|
|
68
|
-
} catch (error) {
|
|
69
|
-
expect(consoleSpy).toHaveBeenCalledWith('Error creating payment', preparedPayment.id)
|
|
70
|
-
}
|
|
71
|
-
})
|
|
72
|
-
|
|
73
60
|
it('should throw an error when response is not ok', async () => {
|
|
74
61
|
const mockFetchResponse = {
|
|
75
62
|
ok: false,
|
|
@@ -92,43 +79,6 @@ describe('govuk-pay-service', () => {
|
|
|
92
79
|
})
|
|
93
80
|
).rejects.toThrow('Unexpected response from GOV.UK Pay API')
|
|
94
81
|
})
|
|
95
|
-
|
|
96
|
-
it('should log details when response is not ok', async () => {
|
|
97
|
-
const status = 400
|
|
98
|
-
const serviceResponseBody = {
|
|
99
|
-
code: 'P0102',
|
|
100
|
-
field: 'agreement_id',
|
|
101
|
-
description: 'Invalid attribute value: agreement_id. Agreement does not exist'
|
|
102
|
-
}
|
|
103
|
-
const transactionId = 'a50f0d51-295f-42b3-98f8-97c0641ede5a'
|
|
104
|
-
const preparedPayment = {
|
|
105
|
-
amount: 100,
|
|
106
|
-
description: 'The recurring card payment for your rod fishing licence',
|
|
107
|
-
id: transactionId,
|
|
108
|
-
authorisation_mode: 'agreement',
|
|
109
|
-
agreement_id: 'does_not_exist'
|
|
110
|
-
}
|
|
111
|
-
govUkPayApi.createPayment.mockResolvedValueOnce({
|
|
112
|
-
ok: false,
|
|
113
|
-
status,
|
|
114
|
-
json: jest.fn().mockResolvedValue(serviceResponseBody)
|
|
115
|
-
})
|
|
116
|
-
jest.spyOn(console, 'error')
|
|
117
|
-
|
|
118
|
-
try {
|
|
119
|
-
await sendPayment(preparedPayment)
|
|
120
|
-
} catch {}
|
|
121
|
-
|
|
122
|
-
expect(console.error).toHaveBeenCalledWith(
|
|
123
|
-
expect.objectContaining({
|
|
124
|
-
method: 'POST',
|
|
125
|
-
status,
|
|
126
|
-
response: serviceResponseBody,
|
|
127
|
-
transactionId,
|
|
128
|
-
payload: preparedPayment
|
|
129
|
-
})
|
|
130
|
-
)
|
|
131
|
-
})
|
|
132
82
|
})
|
|
133
83
|
|
|
134
84
|
describe('getPaymentStatus', () => {
|
|
@@ -3,24 +3,15 @@ import db from 'debug'
|
|
|
3
3
|
const debug = db('recurring-payments:gov.uk-pay-service')
|
|
4
4
|
|
|
5
5
|
export const sendPayment = async preparedPayment => {
|
|
6
|
-
const createPayment =
|
|
7
|
-
try {
|
|
8
|
-
return await govUkPayApi.createPayment(preparedPayment, true)
|
|
9
|
-
} catch (e) {
|
|
10
|
-
console.error('Error creating payment', preparedPayment.id)
|
|
11
|
-
throw e
|
|
12
|
-
}
|
|
13
|
-
}
|
|
6
|
+
const createPayment = () => govUkPayApi.createPayment(preparedPayment, true)
|
|
14
7
|
const response = await createPayment()
|
|
15
8
|
if (!response.ok) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
})
|
|
23
|
-
throw new Error('Unexpected response from GOV.UK Pay API')
|
|
9
|
+
throw new Error(`Unexpected response from GOV.UK Pay API.
|
|
10
|
+
Status: ${response.status},
|
|
11
|
+
Response: ${JSON.stringify(await response.json())}
|
|
12
|
+
Transaction ID: ${preparedPayment.id}
|
|
13
|
+
Payload: ${JSON.stringify(preparedPayment)}
|
|
14
|
+
`)
|
|
24
15
|
}
|
|
25
16
|
return response.json()
|
|
26
17
|
}
|