@defra-fish/recurring-payments-job 1.63.0-rc.0 → 1.63.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@defra-fish/recurring-payments-job",
3
- "version": "1.63.0-rc.0",
3
+ "version": "1.63.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.63.0-rc.0",
40
- "@defra-fish/connectors-lib": "1.63.0-rc.0",
39
+ "@defra-fish/business-rules-lib": "1.63.0-rc.10",
40
+ "@defra-fish/connectors-lib": "1.63.0-rc.10",
41
41
  "commander": "^7.2.0",
42
42
  "debug": "^4.3.3",
43
43
  "moment-timezone": "^0.5.34"
44
44
  },
45
- "gitHead": "127bd6db86a97eb1b229f3de30e27046119ffca6"
45
+ "gitHead": "c4301461b148cbf244c1bb5c834521243ec0a534"
46
46
  }
@@ -1,5 +1,6 @@
1
1
  import commander from 'commander'
2
2
  import { processRecurringPayments } from '../recurring-payments-processor.js'
3
+ import fs from 'fs'
3
4
 
4
5
  jest.useFakeTimers()
5
6
 
@@ -17,12 +18,30 @@ jest.mock('commander', () => {
17
18
  return global.commander
18
19
  })
19
20
 
21
+ jest.mock('fs')
22
+
20
23
  describe('recurring-payments-job', () => {
21
24
  beforeEach(() => {
22
25
  jest.clearAllMocks()
23
26
  commander.args = ['test']
24
27
  })
25
28
 
29
+ it('logs startup details including name and version', () => {
30
+ const mockPkg = { name: 'recurring-payments-test', version: '1.2.3' }
31
+ fs.readFileSync.mockReturnValue(JSON.stringify(mockPkg))
32
+
33
+ jest.isolateModules(() => {
34
+ const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
35
+ require('../recurring-payments-job.js')
36
+ expect(logSpy).toHaveBeenCalledWith(
37
+ 'Recurring payments job starting at %s. name: %s. version: %s',
38
+ expect.any(String),
39
+ mockPkg.name,
40
+ mockPkg.version
41
+ )
42
+ })
43
+ })
44
+
26
45
  it('calls processRecurringPayments when no delay', () => {
27
46
  jest.isolateModules(() => {
28
47
  require('../recurring-payments-job.js')
@@ -20,17 +20,18 @@ jest.mock('@defra-fish/business-rules-lib', () => ({
20
20
  }))
21
21
  jest.mock('@defra-fish/connectors-lib', () => ({
22
22
  salesApi: {
23
- getDueRecurringPayments: jest.fn(() => []),
24
- preparePermissionDataForRenewal: jest.fn(() => ({
25
- licensee: { countryCode: 'GB-ENG' }
26
- })),
23
+ createPaymentJournal: jest.fn(),
27
24
  createTransaction: jest.fn(() => ({
28
25
  id: 'test-transaction-id',
29
26
  cost: 30
30
27
  })),
28
+ getDueRecurringPayments: jest.fn(() => []),
29
+ getPaymentJournal: jest.fn(),
30
+ preparePermissionDataForRenewal: jest.fn(() => ({
31
+ licensee: { countryCode: 'GB-ENG' }
32
+ })),
31
33
  processRPResult: jest.fn(),
32
- updatePaymentJournal: jest.fn(),
33
- getPaymentJournal: jest.fn()
34
+ updatePaymentJournal: jest.fn()
34
35
  }
35
36
  }))
36
37
 
@@ -59,8 +60,8 @@ const getMockPaymentRequestResponse = () => [
59
60
  }
60
61
  ]
61
62
 
62
- const getMockDueRecurringPayment = (referenceNumber = '123', agreementId = 'test-agreement-id') => ({
63
- entity: { agreementId },
63
+ const getMockDueRecurringPayment = ({ agreementId = 'test-agreement-id', id = 'abc-123', referenceNumber = '123' } = {}) => ({
64
+ entity: { id, agreementId },
64
65
  expanded: { activePermission: { entity: { referenceNumber } } }
65
66
  })
66
67
 
@@ -147,10 +148,10 @@ describe('recurring-payments-processor', () => {
147
148
  it('prepares and sends all payment requests, even if some fail', async () => {
148
149
  const agreementIds = [Symbol('agreementId1'), Symbol('agreementId2'), Symbol('agreementId3'), Symbol('agreementId4')]
149
150
  salesApi.getDueRecurringPayments.mockReturnValueOnce([
150
- getMockDueRecurringPayment('fee', agreementIds[0]),
151
- getMockDueRecurringPayment('fi', agreementIds[1]),
152
- getMockDueRecurringPayment('foe', agreementIds[2]),
153
- getMockDueRecurringPayment('fum', agreementIds[3])
151
+ getMockDueRecurringPayment({ referenceNumber: 'fee', agreementId: agreementIds[0] }),
152
+ getMockDueRecurringPayment({ referenceNumber: 'fi', agreementId: agreementIds[1] }),
153
+ getMockDueRecurringPayment({ referenceNumber: 'foe', agreementId: agreementIds[2] }),
154
+ getMockDueRecurringPayment({ referenceNumber: 'fum', agreementId: agreementIds[3] })
154
155
  ])
155
156
 
156
157
  const permissionData = { licensee: { countryCode: 'GB-ENG' } }
@@ -202,9 +203,9 @@ describe('recurring-payments-processor', () => {
202
203
  it('logs an error for every failure', async () => {
203
204
  const errors = [new Error('error 1'), new Error('error 2'), new Error('error 3')]
204
205
  salesApi.getDueRecurringPayments.mockReturnValueOnce([
205
- getMockDueRecurringPayment('fee', 'a1'),
206
- getMockDueRecurringPayment('fi', 'a2'),
207
- getMockDueRecurringPayment('foe', 'a3')
206
+ getMockDueRecurringPayment({ referenceNumber: 'fee', agreementId: 'a1' }),
207
+ getMockDueRecurringPayment({ referenceNumber: 'fi', agreementId: 'a2' }),
208
+ getMockDueRecurringPayment({ referenceNumber: 'foe', agreementId: 'a3' })
208
209
  ])
209
210
  const permissionData = { licensee: { countryCode: 'GB-ENG' } }
210
211
  salesApi.preparePermissionDataForRenewal
@@ -241,7 +242,7 @@ describe('recurring-payments-processor', () => {
241
242
 
242
243
  it('prepares the data for found recurring payments', async () => {
243
244
  const referenceNumber = Symbol('reference')
244
- salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment(referenceNumber)])
245
+ salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment({ referenceNumber })])
245
246
  const mockPaymentResponse = { payment_id: 'test-payment-id', created_date: '2025-01-01T00:00:00.000Z' }
246
247
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
247
248
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
@@ -252,7 +253,9 @@ describe('recurring-payments-processor', () => {
252
253
  })
253
254
 
254
255
  it('creates a transaction with the correct data', async () => {
255
- salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
256
+ const id = Symbol('recurring-payment-id')
257
+ const agreementId = Symbol('agreement-id')
258
+ salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment({ agreementId, id })])
256
259
 
257
260
  const isLicenceForYou = Symbol('isLicenceForYou')
258
261
  const isRenewal = Symbol('isRenewal')
@@ -277,7 +280,10 @@ describe('recurring-payments-processor', () => {
277
280
 
278
281
  const expectedData = {
279
282
  dataSource: 'Recurring Payment',
280
- agreementId: 'test-agreement-id',
283
+ recurringPayment: {
284
+ agreementId,
285
+ id
286
+ },
281
287
  permissions: [
282
288
  {
283
289
  isLicenceForYou,
@@ -303,6 +309,31 @@ describe('recurring-payments-processor', () => {
303
309
  expect(salesApi.createTransaction).toHaveBeenCalledWith(expectedData)
304
310
  })
305
311
 
312
+ it('creates a payment journal entry', async () => {
313
+ salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
314
+ const samplePayment = {
315
+ payment_id: Symbol('payment-id'),
316
+ created_date: Symbol('created-date')
317
+ }
318
+ const sampleTransaction = {
319
+ id: Symbol('transaction-id'),
320
+ cost: 99
321
+ }
322
+ sendPayment.mockResolvedValueOnce(samplePayment)
323
+ salesApi.createTransaction.mockResolvedValueOnce(sampleTransaction)
324
+
325
+ await processRecurringPayments()
326
+
327
+ expect(salesApi.createPaymentJournal).toHaveBeenCalledWith(
328
+ sampleTransaction.id,
329
+ expect.objectContaining({
330
+ paymentReference: samplePayment.payment_id,
331
+ paymentTimestamp: samplePayment.created_date,
332
+ paymentStatus: PAYMENT_JOURNAL_STATUS_CODES.InProgress
333
+ })
334
+ )
335
+ })
336
+
306
337
  it('strips the concession name returned by preparePermissionDataForRenewal before passing to createTransaction', async () => {
307
338
  salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment()])
308
339
 
@@ -387,7 +418,7 @@ describe('recurring-payments-processor', () => {
387
418
  const agreementId = Symbol('agreementId')
388
419
  const transactionId = 'transactionId'
389
420
 
390
- salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment('foo', agreementId)])
421
+ salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment({ referenceNumber: 'foo', agreementId: agreementId })])
391
422
 
392
423
  salesApi.preparePermissionDataForRenewal.mockReturnValueOnce({
393
424
  licensee: { countryCode: 'GB-ENG' }
@@ -529,7 +560,7 @@ describe('recurring-payments-processor', () => {
529
560
 
530
561
  it('should call setTimeout with correct delay when there are recurring payments', async () => {
531
562
  const referenceNumber = Symbol('reference')
532
- salesApi.getDueRecurringPayments.mockResolvedValueOnce([getMockDueRecurringPayment(referenceNumber)])
563
+ salesApi.getDueRecurringPayments.mockResolvedValueOnce([getMockDueRecurringPayment({ referenceNumber })])
533
564
  const mockPaymentResponse = { payment_id: 'test-payment-id' }
534
565
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
535
566
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
@@ -592,7 +623,7 @@ describe('recurring-payments-processor', () => {
592
623
  'console error displays "Payment failed. Recurring payment agreement for: %s set to be cancelled" when payment is a %status',
593
624
  async (agreementId, mockStatus, status) => {
594
625
  const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn())
595
- salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment('reference', agreementId)])
626
+ salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment({ agreementId })])
596
627
  const mockPaymentResponse = { payment_id: 'test-payment-id', created_date: '2025-01-01T00:00:00.000Z' }
597
628
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
598
629
  getPaymentStatus.mockResolvedValueOnce(mockStatus)
@@ -646,8 +677,8 @@ describe('recurring-payments-processor', () => {
646
677
  references.push(Symbol('reference' + i))
647
678
  }
648
679
  const mockGetDueRecurringPayments = []
649
- references.forEach(reference => {
650
- mockGetDueRecurringPayments.push(getMockDueRecurringPayment(reference))
680
+ references.forEach(referenceNumber => {
681
+ mockGetDueRecurringPayments.push(getMockDueRecurringPayment({ referenceNumber }))
651
682
  })
652
683
  salesApi.getDueRecurringPayments.mockReturnValueOnce(mockGetDueRecurringPayments)
653
684
  const mockPaymentResponse = { payment_id: 'test-payment-id' }
@@ -667,8 +698,14 @@ describe('recurring-payments-processor', () => {
667
698
 
668
699
  it('creates a transaction for each one', async () => {
669
700
  const mockGetDueRecurringPayments = []
701
+ const agreementIds = []
702
+ const ids = []
670
703
  for (let i = 0; i < count; i++) {
671
- mockGetDueRecurringPayments.push(getMockDueRecurringPayment(i))
704
+ const agreementId = Symbol(`agreement-id-${i}`)
705
+ const id = Symbol(`recurring-payment-${i}`)
706
+ agreementIds.push(agreementId)
707
+ ids.push(id)
708
+ mockGetDueRecurringPayments.push(getMockDueRecurringPayment({ agreementId, id, referenceNumber: i }))
672
709
  }
673
710
  salesApi.getDueRecurringPayments.mockReturnValueOnce(mockGetDueRecurringPayments)
674
711
 
@@ -685,11 +722,14 @@ describe('recurring-payments-processor', () => {
685
722
  })
686
723
 
687
724
  const expectedData = []
688
- permits.forEach(permit => {
725
+ permits.forEach((permit, i) => {
689
726
  expectedData.push([
690
727
  {
691
728
  dataSource: 'Recurring Payment',
692
- agreementId: 'test-agreement-id',
729
+ recurringPayment: {
730
+ agreementId: agreementIds[i],
731
+ id: ids[i]
732
+ },
693
733
  permissions: [expect.objectContaining({ permitId: permit })]
694
734
  }
695
735
  ])
@@ -706,7 +746,7 @@ describe('recurring-payments-processor', () => {
706
746
  for (let i = 0; i < count; i++) {
707
747
  const agreementId = Symbol(`agreementId${1}`)
708
748
  agreementIds.push(agreementId)
709
- mockGetDueRecurringPayments.push(getMockDueRecurringPayment(i, agreementId))
749
+ mockGetDueRecurringPayments.push(getMockDueRecurringPayment({ agreementId }))
710
750
  }
711
751
  salesApi.getDueRecurringPayments.mockReturnValueOnce(mockGetDueRecurringPayments)
712
752
 
@@ -749,7 +789,7 @@ describe('recurring-payments-processor', () => {
749
789
  for (let i = 0; i < count; i++) {
750
790
  const agreementId = Symbol(`agreementId${1}`)
751
791
  agreementIds.push(agreementId)
752
- mockGetDueRecurringPayments.push(getMockDueRecurringPayment(i, agreementId))
792
+ mockGetDueRecurringPayments.push(getMockDueRecurringPayment({ agreementId }))
753
793
  }
754
794
  salesApi.getDueRecurringPayments.mockReturnValueOnce(mockGetDueRecurringPayments)
755
795
 
@@ -1,6 +1,13 @@
1
1
  'use strict'
2
2
  import recurringPaymentsJob from 'commander'
3
3
  import { processRecurringPayments } from './recurring-payments-processor.js'
4
+ import path from 'path'
5
+ import fs from 'fs'
6
+
7
+ const pkgPath = path.join(process.cwd(), 'package.json')
8
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
9
+
10
+ console.log('Recurring payments job starting at %s. name: %s. version: %s', new Date().toISOString(), pkg.name, pkg.version)
4
11
 
5
12
  const delay = parseInt(process.env.RECURRING_PAYMENTS_LOCAL_DELAY || '0', 10)
6
13
  if (delay > 0) {
@@ -64,19 +64,25 @@ const requestPayments = async dueRCPayments => {
64
64
 
65
65
  const processRecurringPayment = async record => {
66
66
  const referenceNumber = record.expanded.activePermission.entity.referenceNumber
67
- const agreementId = record.entity.agreementId
68
- const transaction = await createNewTransaction(referenceNumber, agreementId)
67
+ const { agreementId, id } = record.entity
68
+ const transaction = await createNewTransaction(referenceNumber, { agreementId, id })
69
69
  return takeRecurringPayment(agreementId, transaction)
70
70
  }
71
71
 
72
- const createNewTransaction = async (referenceNumber, agreementId) => {
73
- const transactionData = await processPermissionData(referenceNumber, agreementId)
72
+ const createNewTransaction = async (referenceNumber, recurringPayment) => {
73
+ const transactionData = await processPermissionData(referenceNumber, recurringPayment)
74
74
  return salesApi.createTransaction(transactionData)
75
75
  }
76
76
 
77
77
  const takeRecurringPayment = async (agreementId, transaction) => {
78
78
  const preparedPayment = preparePayment(agreementId, transaction)
79
79
  const payment = await sendPayment(preparedPayment)
80
+ await salesApi.createPaymentJournal(transaction.id, {
81
+ paymentReference: payment.payment_id,
82
+ paymentTimestamp: payment.created_date,
83
+ paymentStatus: PAYMENT_JOURNAL_STATUS_CODES.InProgress
84
+ })
85
+
80
86
  return {
81
87
  agreementId,
82
88
  paymentId: payment.payment_id,
@@ -85,12 +91,12 @@ const takeRecurringPayment = async (agreementId, transaction) => {
85
91
  }
86
92
  }
87
93
 
88
- const processPermissionData = async (referenceNumber, agreementId) => {
94
+ const processPermissionData = async (referenceNumber, recurringPayment) => {
89
95
  const data = await salesApi.preparePermissionDataForRenewal(referenceNumber)
90
96
  const licenseeWithoutCountryCode = Object.assign((({ countryCode: _countryCode, ...l }) => l)(data.licensee))
91
97
  return {
92
98
  dataSource: 'Recurring Payment',
93
- agreementId,
99
+ recurringPayment,
94
100
  permissions: [
95
101
  {
96
102
  isLicenceForYou: data.isLicenceForYou,
@@ -16,9 +16,11 @@ describe('govuk-pay-service', () => {
16
16
 
17
17
  it('sendPayment should return response from createPayment in json format', async () => {
18
18
  const mockPreparedPayment = { id: 'test-payment-id' }
19
- const mockResponse = { status: 'success', paymentId: 'abc123' }
19
+ const mockResponse = { state: { status: 'created' }, payment_id: 'abcde12345' }
20
20
 
21
21
  const mockFetchResponse = {
22
+ status: 200,
23
+ ok: true,
22
24
  json: jest.fn().mockResolvedValue(mockResponse)
23
25
  }
24
26
  govUkPayApi.createPayment.mockResolvedValue(mockFetchResponse)
@@ -67,6 +69,66 @@ describe('govuk-pay-service', () => {
67
69
  expect(consoleSpy).toHaveBeenCalledWith('Error creating payment', preparedPayment.id)
68
70
  }
69
71
  })
72
+
73
+ it('should throw an error when response is not ok', async () => {
74
+ const mockFetchResponse = {
75
+ ok: false,
76
+ status: 400,
77
+ json: jest.fn().mockResolvedValue({
78
+ code: 'P0102',
79
+ field: 'agreement_id',
80
+ description: 'Invalid attribute value: agreement_id. Agreement does not exist'
81
+ })
82
+ }
83
+ govUkPayApi.createPayment.mockResolvedValueOnce(mockFetchResponse)
84
+
85
+ await expect(
86
+ sendPayment({
87
+ amount: 100,
88
+ description: 'The recurring card payment for your rod fishing licence',
89
+ id: 'a50f0d51-295f-42b3-98f8-97c0641ede5a',
90
+ authorisation_mode: 'agreement',
91
+ agreement_id: 'does_not_exist'
92
+ })
93
+ ).rejects.toThrow('Unexpected response from GOV.UK Pay API')
94
+ })
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
+ })
70
132
  })
71
133
 
72
134
  describe('getPaymentStatus', () => {
@@ -81,7 +143,7 @@ describe('govuk-pay-service', () => {
81
143
  })
82
144
 
83
145
  it('should return the payment status on successful response', async () => {
84
- const mockPaymentStatus = { code: 'P1234', description: 'Success' }
146
+ const mockPaymentStatus = { amount: 37.5, state: { status: 'success', finished: 'true' } }
85
147
  govUkPayApi.fetchPaymentStatus.mockResolvedValue({
86
148
  ok: true,
87
149
  json: jest.fn().mockResolvedValue(mockPaymentStatus)
@@ -96,25 +158,47 @@ describe('govuk-pay-service', () => {
96
158
  })
97
159
 
98
160
  it('should throw an error when response is not ok', async () => {
99
- const mockErrorDetails = { error: 'Payment not found' }
100
161
  const mockFetchResponse = {
101
162
  ok: false,
102
- json: jest.fn().mockResolvedValue(mockErrorDetails)
163
+ status: 404,
164
+ json: jest.fn().mockResolvedValue({
165
+ code: 'P0200',
166
+ field: 'payment_id',
167
+ description: 'No payment matched the payment id you provided'
168
+ })
103
169
  }
104
170
  govUkPayApi.fetchPaymentStatus.mockResolvedValue(mockFetchResponse)
105
171
 
106
- await expect(getPaymentStatus('invalid-payment-id')).rejects.toThrow('Payment not found')
172
+ await expect(getPaymentStatus('invalid-payment-id')).rejects.toThrow('Unexpected response from GOV.UK Pay API')
107
173
  })
108
174
 
109
- it('should throw an error when response is not ok but errorDetails has no value', async () => {
110
- const mockErrorDetails = {}
175
+ it('should log details when response is not ok', async () => {
176
+ const serviceResponseBody = {
177
+ code: 'P0200',
178
+ field: 'payment_id',
179
+ description: 'No payment matched the payment id you provided'
180
+ }
111
181
  const mockFetchResponse = {
112
182
  ok: false,
113
- json: jest.fn().mockResolvedValue(mockErrorDetails)
183
+ status: 404,
184
+ json: jest.fn().mockResolvedValue(serviceResponseBody)
114
185
  }
115
186
  govUkPayApi.fetchPaymentStatus.mockResolvedValue(mockFetchResponse)
187
+ jest.spyOn(console, 'error')
188
+ const paymentId = 'invalid-payment-id'
116
189
 
117
- await expect(getPaymentStatus('invalid-payment-id')).rejects.toThrow('Error fetching payment status')
190
+ try {
191
+ await getPaymentStatus(paymentId)
192
+ } catch {}
193
+
194
+ expect(console.error).toHaveBeenCalledWith(
195
+ expect.objectContaining({
196
+ method: 'GET',
197
+ status: mockFetchResponse.status,
198
+ response: serviceResponseBody,
199
+ paymentId
200
+ })
201
+ )
118
202
  })
119
203
 
120
204
  it('should throw an error when fetchPaymentStatus fails', async () => {
@@ -3,13 +3,26 @@ 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
- try {
7
- const response = await govUkPayApi.createPayment(preparedPayment, true)
8
- return await response.json()
9
- } catch (e) {
10
- console.error('Error creating payment', preparedPayment.id)
11
- throw e
6
+ const createPayment = async () => {
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
+ }
14
+ const response = await createPayment()
15
+ if (!response.ok) {
16
+ console.error({
17
+ method: 'POST',
18
+ status: response.status,
19
+ response: await response.json(),
20
+ transactionId: preparedPayment.id,
21
+ payload: preparedPayment
22
+ })
23
+ throw new Error('Unexpected response from GOV.UK Pay API')
12
24
  }
25
+ return response.json()
13
26
  }
14
27
 
15
28
  export const getPaymentStatus = async paymentId => {
@@ -17,21 +30,28 @@ export const getPaymentStatus = async paymentId => {
17
30
  throw new Error('Invalid payment ID')
18
31
  }
19
32
 
20
- try {
21
- const response = await govUkPayApi.fetchPaymentStatus(paymentId, true)
22
-
23
- if (!response.ok) {
24
- const errorDetails = await response.json()
25
- console.log(errorDetails)
26
- throw new Error(errorDetails.error || 'Error fetching payment status')
33
+ const fetchPaymentStatus = async () => {
34
+ try {
35
+ return await govUkPayApi.fetchPaymentStatus(paymentId, true)
36
+ } catch (e) {
37
+ console.error('Error fetching payment status', paymentId)
38
+ throw e
27
39
  }
40
+ }
41
+
42
+ const response = await fetchPaymentStatus()
28
43
 
29
- const paymentStatus = await response.json()
30
- return paymentStatus
31
- } catch (error) {
32
- console.error('Error in getPaymentStatus:', error)
33
- throw error
44
+ if (!response.ok) {
45
+ console.error({
46
+ method: 'GET',
47
+ status: response.status,
48
+ response: await response.json(),
49
+ paymentId
50
+ })
51
+ throw new Error('Unexpected response from GOV.UK Pay API')
34
52
  }
53
+
54
+ return response.json()
35
55
  }
36
56
 
37
57
  export const isGovPayUp = async () => {