@defra-fish/recurring-payments-job 1.60.0-rc.2 → 1.60.0-rc.4

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.60.0-rc.2",
3
+ "version": "1.60.0-rc.4",
4
4
  "description": "Rod Licensing Recurring Payments Job",
5
5
  "type": "module",
6
6
  "engines": {
@@ -36,10 +36,10 @@
36
36
  "test": "echo \"Error: run tests from root\" && exit 1"
37
37
  },
38
38
  "dependencies": {
39
- "@defra-fish/business-rules-lib": "1.60.0-rc.2",
40
- "@defra-fish/connectors-lib": "1.60.0-rc.2",
39
+ "@defra-fish/business-rules-lib": "1.60.0-rc.4",
40
+ "@defra-fish/connectors-lib": "1.60.0-rc.4",
41
41
  "commander": "^7.2.0",
42
42
  "moment-timezone": "^0.5.34"
43
43
  },
44
- "gitHead": "35b29edb1fd37ed3b467e2140f9704787044ad96"
44
+ "gitHead": "0c5c50b668c126c636f7a7a018dc5706e2d74eaf"
45
45
  }
@@ -10,8 +10,10 @@ jest.mock('@defra-fish/connectors-lib', () => ({
10
10
  licensee: { countryCode: 'GB-ENG' }
11
11
  })),
12
12
  createTransaction: jest.fn(() => ({
13
+ id: 'test-transaction-id',
13
14
  cost: 30
14
- }))
15
+ })),
16
+ processRPResult: jest.fn()
15
17
  }
16
18
  }))
17
19
 
@@ -21,6 +23,19 @@ jest.mock('../services/govuk-pay-service.js', () => ({
21
23
  }))
22
24
 
23
25
  const PAYMENT_STATUS_DELAY = 60000
26
+ const getPaymentStatusSuccess = () => ({ state: { status: 'success' } })
27
+ const getMockPaymentRequestResponse = () => [
28
+ {
29
+ entity: { agreementId: 'agreement-1' },
30
+ expanded: {
31
+ activePermission: {
32
+ entity: {
33
+ referenceNumber: 'ref-1'
34
+ }
35
+ }
36
+ }
37
+ }
38
+ ]
24
39
 
25
40
  describe('recurring-payments-processor', () => {
26
41
  beforeEach(() => {
@@ -65,9 +80,9 @@ describe('recurring-payments-processor', () => {
65
80
  it('prepares the data for found recurring payments', async () => {
66
81
  const referenceNumber = Symbol('reference')
67
82
  salesApi.getDueRecurringPayments.mockReturnValueOnce([getMockDueRecurringPayment(referenceNumber)])
68
- const mockPaymentResponse = { payment_id: 'test-payment-id' }
83
+ const mockPaymentResponse = { payment_id: 'test-payment-id', created_date: '2025-01-01T00:00:00.000Z' }
69
84
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
70
- getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Success' } })
85
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
71
86
 
72
87
  await processRecurringPayments()
73
88
 
@@ -119,7 +134,7 @@ describe('recurring-payments-processor', () => {
119
134
 
120
135
  const mockPaymentResponse = { payment_id: 'test-payment-id', agreementId: 'test-agreement-id' }
121
136
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
122
- getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Success' } })
137
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
123
138
 
124
139
  await processRecurringPayments()
125
140
 
@@ -144,7 +159,7 @@ describe('recurring-payments-processor', () => {
144
159
 
145
160
  const mockPaymentResponse = { payment_id: 'test-payment-id' }
146
161
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
147
- getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Success' } })
162
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
148
163
 
149
164
  await processRecurringPayments()
150
165
 
@@ -174,7 +189,7 @@ describe('recurring-payments-processor', () => {
174
189
 
175
190
  const mockPaymentResponse = { payment_id: 'test-payment-id' }
176
191
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
177
- getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Success' } })
192
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
178
193
 
179
194
  await processRecurringPayments()
180
195
 
@@ -195,7 +210,7 @@ describe('recurring-payments-processor', () => {
195
210
 
196
211
  const mockPaymentResponse = { payment_id: 'test-payment-id' }
197
212
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
198
- getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Success' } })
213
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
199
214
 
200
215
  await processRecurringPayments()
201
216
 
@@ -233,7 +248,7 @@ describe('recurring-payments-processor', () => {
233
248
 
234
249
  const mockPaymentResponse = { payment_id: 'test-payment-id', agreementId }
235
250
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
236
- getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Success' } })
251
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
237
252
 
238
253
  const expectedData = {
239
254
  amount: 5000,
@@ -261,16 +276,15 @@ describe('recurring-payments-processor', () => {
261
276
  }
262
277
  }
263
278
  ]
264
- salesApi.getDueRecurringPayments.mockResolvedValue(mockResponse)
265
- salesApi.createTransaction.mockResolvedValue({
279
+ salesApi.getDueRecurringPayments.mockResolvedValueOnce(mockResponse)
280
+ salesApi.createTransaction.mockResolvedValueOnce({
266
281
  id: 'payment-id-1'
267
282
  })
268
- getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Success' } })
283
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
269
284
  const mockPaymentResponse = { payment_id: 'test-payment-id', agreementId: 'agreement-1' }
270
285
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
271
286
 
272
287
  await processRecurringPayments()
273
- jest.useFakeTimers(60000)
274
288
 
275
289
  expect(getPaymentStatus).toHaveBeenCalledWith('test-payment-id')
276
290
  })
@@ -290,20 +304,17 @@ describe('recurring-payments-processor', () => {
290
304
  }
291
305
  }
292
306
  ]
293
- salesApi.getDueRecurringPayments.mockResolvedValue(mockResponse)
294
- salesApi.createTransaction.mockResolvedValue({
307
+ salesApi.getDueRecurringPayments.mockResolvedValueOnce(mockResponse)
308
+ salesApi.createTransaction.mockResolvedValueOnce({
295
309
  id: mockPaymentId
296
310
  })
297
311
  const mockPaymentResponse = { payment_id: mockPaymentId, agreementId: 'agreement-1' }
298
312
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
299
- const mockPaymentStatus = { state: { status: 'Success' } }
300
- getPaymentStatus.mockResolvedValueOnce(mockPaymentStatus)
301
- const mockStatus = JSON.stringify(mockPaymentStatus.state.status)
313
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
302
314
 
303
315
  await processRecurringPayments()
304
- jest.advanceTimersByTime(60000)
305
316
 
306
- expect(consoleLogSpy).toHaveBeenCalledWith(`Payment status for ${mockPaymentId}: ${mockStatus}`)
317
+ expect(consoleLogSpy).toHaveBeenCalledWith(`Payment status for ${mockPaymentId}: success`)
307
318
  })
308
319
 
309
320
  it('should call setTimeout with correct delay when there are recurring payments', async () => {
@@ -311,7 +322,7 @@ describe('recurring-payments-processor', () => {
311
322
  salesApi.getDueRecurringPayments.mockResolvedValueOnce([getMockDueRecurringPayment(referenceNumber)])
312
323
  const mockPaymentResponse = { payment_id: 'test-payment-id' }
313
324
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
314
- getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Success' } })
325
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
315
326
 
316
327
  const setTimeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(cb => cb())
317
328
 
@@ -330,6 +341,32 @@ describe('recurring-payments-processor', () => {
330
341
  expect(setTimeoutSpy).not.toHaveBeenCalled()
331
342
  })
332
343
 
344
+ it('calls processRPResult with transaction id, payment id and created date when payment is successful', async () => {
345
+ const mockTransactionId = 'test-transaction-id'
346
+ const mockPaymentId = 'test-payment-id'
347
+ const mockPaymentCreatedDate = '2025-01-01T00:00:00.000Z'
348
+ salesApi.getDueRecurringPayments.mockResolvedValueOnce(getMockPaymentRequestResponse())
349
+ salesApi.createTransaction.mockResolvedValueOnce({ id: mockTransactionId, cost: 30 })
350
+ sendPayment.mockResolvedValueOnce({ payment_id: mockPaymentId, agreementId: 'agreement-1', created_date: mockPaymentCreatedDate })
351
+ getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
352
+
353
+ await processRecurringPayments()
354
+
355
+ expect(salesApi.processRPResult).toHaveBeenCalledWith(mockTransactionId, mockPaymentId, mockPaymentCreatedDate)
356
+ })
357
+
358
+ it("doesn't call processRPResult if payment status is not successful", async () => {
359
+ const mockPaymentId = 'test-payment-id'
360
+ salesApi.getDueRecurringPayments.mockResolvedValueOnce(getMockPaymentRequestResponse())
361
+ salesApi.createTransaction.mockResolvedValueOnce({ id: mockPaymentId, cost: 30 })
362
+ sendPayment.mockResolvedValueOnce({ payment_id: mockPaymentId, agreementId: 'agreement-1' })
363
+ getPaymentStatus.mockResolvedValueOnce({ state: { status: 'Pending' } })
364
+
365
+ await processRecurringPayments()
366
+
367
+ expect(salesApi.processRPResult).not.toHaveBeenCalledWith()
368
+ })
369
+
333
370
  describe.each([2, 3, 10])('if there are %d recurring payments', count => {
334
371
  it('prepares the data for each one', async () => {
335
372
  const references = []
@@ -344,7 +381,7 @@ describe('recurring-payments-processor', () => {
344
381
  salesApi.getDueRecurringPayments.mockReturnValueOnce(mockGetDueRecurringPayments)
345
382
  const mockPaymentResponse = { payment_id: 'test-payment-id' }
346
383
  sendPayment.mockResolvedValue(mockPaymentResponse)
347
- const mockPaymentStatus = { state: { status: 'Success' } }
384
+ const mockPaymentStatus = getPaymentStatusSuccess()
348
385
  getPaymentStatus.mockResolvedValue(mockPaymentStatus)
349
386
 
350
387
  const expectedData = []
@@ -5,6 +5,7 @@ import { getPaymentStatus, sendPayment } from './services/govuk-pay-service.js'
5
5
 
6
6
  const PAYMENT_STATUS_DELAY = 60000
7
7
  const payments = []
8
+ const PAYMENT_STATUS_SUCCESS = 'success'
8
9
 
9
10
  export const processRecurringPayments = async () => {
10
11
  if (process.env.RUN_RECURRING_PAYMENTS?.toLowerCase() === 'true') {
@@ -48,7 +49,9 @@ const takeRecurringPayment = async (agreementId, transaction) => {
48
49
  const payment = await sendPayment(preparedPayment)
49
50
  payments.push({
50
51
  agreementId,
51
- paymentId: payment.payment_id
52
+ paymentId: payment.payment_id,
53
+ created_date: payment.created_date,
54
+ transaction
52
55
  })
53
56
  }
54
57
 
@@ -101,10 +104,13 @@ const processRecurringPaymentStatus = async record => {
101
104
  const {
102
105
  state: { status }
103
106
  } = await getPaymentStatus(paymentId)
104
- console.log(`Payment status for ${paymentId}: ${JSON.stringify(status)}`)
107
+ console.log(`Payment status for ${paymentId}: ${status}`)
108
+ if (status === PAYMENT_STATUS_SUCCESS) {
109
+ const payment = payments.find(p => p.paymentId === paymentId)
110
+ await salesApi.processRPResult(payment.transaction.id, paymentId, payment.created_date)
111
+ }
105
112
  }
106
113
 
107
114
  const getPaymentId = agreementId => {
108
- const payment = payments.find(p => p.agreementId === agreementId)
109
- return payment.paymentId
115
+ return payments.find(p => p.agreementId === agreementId).paymentId
110
116
  }