@defra-fish/recurring-payments-job 1.63.0-rc.17 → 1.63.0-rc.18

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.17",
3
+ "version": "1.63.0-rc.18",
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.17",
40
- "@defra-fish/connectors-lib": "1.63.0-rc.17",
39
+ "@defra-fish/business-rules-lib": "1.63.0-rc.18",
40
+ "@defra-fish/connectors-lib": "1.63.0-rc.18",
41
41
  "commander": "^7.2.0",
42
42
  "debug": "^4.3.3",
43
43
  "moment-timezone": "^0.5.34"
44
44
  },
45
- "gitHead": "82f2847fb040f48f9d6ebd31002ef32985980d48"
45
+ "gitHead": "d21455813e5eddb476706bdfb49a75ea2f1c9404"
46
46
  }
@@ -1,19 +1,16 @@
1
1
  import commander from 'commander'
2
- import { airbrake } from '@defra-fish/connectors-lib'
3
- import { processRecurringPayments } from '../recurring-payments-processor.js'
2
+ import { execute } from '../recurring-payments-processor.js'
4
3
  import fs from 'fs'
5
4
 
6
5
  jest.useFakeTimers()
7
-
8
6
  jest.mock('../recurring-payments-processor.js')
9
- jest.mock('@defra-fish/connectors-lib', () => ({
10
- airbrake: {
11
- initialise: jest.fn(),
12
- flush: jest.fn()
7
+ jest.mock('fs', () => ({
8
+ readFileSync: jest.fn(),
9
+ promises: {
10
+ readFile: jest.fn()
13
11
  }
14
12
  }))
15
13
 
16
- jest.mock('fs')
17
14
  describe('recurring-payments-job', () => {
18
15
  beforeAll(() => {
19
16
  fs.readFileSync.mockReturnValue(JSON.stringify({ name: 'recurring-payments-test', version: '1.0.0' }))
@@ -24,81 +21,6 @@ describe('recurring-payments-job', () => {
24
21
  commander.args = ['test']
25
22
  })
26
23
 
27
- it('initialises airbrake', () => {
28
- jest.isolateModules(() => {
29
- require('../recurring-payments-job.js')
30
- expect(airbrake.initialise).toHaveBeenCalled()
31
- })
32
- })
33
-
34
- it('flushes airbrake before script ends', () => {
35
- jest.isolateModules(() => {
36
- require('../recurring-payments-job.js')
37
- expect(airbrake.flush).toHaveBeenCalled()
38
- })
39
- })
40
-
41
- it("doesn't flush airbrake before processRecurringPayments has been called", () => {
42
- jest.isolateModules(() => {
43
- processRecurringPayments.mockImplementationOnce(() => {
44
- expect(airbrake.flush).not.toHaveBeenCalled()
45
- })
46
- require('../recurring-payments-job.js')
47
- })
48
- })
49
-
50
- it.each([
51
- ['SIGINT', 130],
52
- ['SIGTERM', 137]
53
- ])('flushes airbrake on %s signal', (signal, code) => {
54
- jest.isolateModules(() => {
55
- // setup a delay so script doesn't call processRecurringPayments and exit naturally
56
- process.env.RECURRING_PAYMENTS_LOCAL_DELAY = '1'
57
- const signalCallbacks = {}
58
- jest.spyOn(process, 'on')
59
- jest.spyOn(process, 'exit')
60
- process.on.mockImplementation((signalToken, callback) => {
61
- signalCallbacks[signalToken] = callback
62
- })
63
- process.exit.mockImplementation(() => {
64
- // so we don't crash out of the tests!
65
- })
66
-
67
- require('../recurring-payments-job.js')
68
- signalCallbacks[signal]()
69
-
70
- expect(airbrake.flush).toHaveBeenCalled()
71
- process.on.mockRestore()
72
- process.exit.mockRestore()
73
- })
74
- })
75
-
76
- it.each([
77
- ['SIGINT', 130],
78
- ['SIGTERM', 137]
79
- ])('calls process.exit on %s signal with %i code', (signal, code) => {
80
- jest.isolateModules(() => {
81
- // setup a delay so script doesn't call processRecurringPayments and exit naturally
82
- process.env.RECURRING_PAYMENTS_LOCAL_DELAY = '1'
83
- const signalCallbacks = {}
84
- jest.spyOn(process, 'on')
85
- jest.spyOn(process, 'exit')
86
- process.on.mockImplementation((signalToken, callback) => {
87
- signalCallbacks[signalToken] = callback
88
- })
89
- process.exit.mockImplementation(() => {
90
- // so we don't crash out of the tests!
91
- })
92
-
93
- require('../recurring-payments-job.js')
94
- signalCallbacks[signal]()
95
-
96
- expect(process.exit).toHaveBeenCalledWith(code)
97
- process.on.mockRestore()
98
- process.exit.mockRestore()
99
- })
100
- })
101
-
102
24
  it('logs startup details including name and version', () => {
103
25
  const mockPkg = { name: 'recurring-payments-test', version: '1.2.3' }
104
26
  fs.readFileSync.mockReturnValueOnce(JSON.stringify(mockPkg))
@@ -116,11 +38,11 @@ describe('recurring-payments-job', () => {
116
38
  })
117
39
  })
118
40
 
119
- it('calls processRecurringPayments when no delay', () => {
41
+ it('calls execute when no delay', () => {
120
42
  jest.isolateModules(() => {
121
43
  process.env.RECURRING_PAYMENTS_LOCAL_DELAY = '0'
122
44
  require('../recurring-payments-job.js')
123
- expect(processRecurringPayments).toHaveBeenCalled()
45
+ expect(execute).toHaveBeenCalled()
124
46
  })
125
47
  })
126
48
 
@@ -133,12 +55,12 @@ describe('recurring-payments-job', () => {
133
55
  })
134
56
  })
135
57
 
136
- it('calls processRecurringPayments when delay', () => {
58
+ it('calls execute when delay', () => {
137
59
  process.env.RECURRING_PAYMENTS_LOCAL_DELAY = '5'
138
60
  jest.isolateModules(() => {
139
61
  require('../recurring-payments-job.js')
140
62
  jest.advanceTimersByTime(parseInt(process.env.RECURRING_PAYMENTS_LOCAL_DELAY) * 1000)
141
- expect(processRecurringPayments).toHaveBeenCalled()
63
+ expect(execute).toHaveBeenCalled()
142
64
  })
143
65
  })
144
66
 
@@ -1,6 +1,6 @@
1
- import { salesApi } from '@defra-fish/connectors-lib'
1
+ import { airbrake, salesApi } from '@defra-fish/connectors-lib'
2
2
  import { PAYMENT_STATUS, PAYMENT_JOURNAL_STATUS_CODES } from '@defra-fish/business-rules-lib'
3
- import { processRecurringPayments } from '../recurring-payments-processor.js'
3
+ import { execute } from '../recurring-payments-processor.js'
4
4
  import { getPaymentStatus, isGovPayUp, sendPayment } from '../services/govuk-pay-service.js'
5
5
  import db from 'debug'
6
6
 
@@ -19,6 +19,10 @@ jest.mock('@defra-fish/business-rules-lib', () => ({
19
19
  }
20
20
  }))
21
21
  jest.mock('@defra-fish/connectors-lib', () => ({
22
+ airbrake: {
23
+ initialise: jest.fn(),
24
+ flush: jest.fn()
25
+ },
22
26
  salesApi: {
23
27
  cancelRecurringPayment: jest.fn(),
24
28
  createPaymentJournal: jest.fn(),
@@ -75,49 +79,120 @@ describe('recurring-payments-processor', () => {
75
79
  global.setTimeout = jest.fn((cb, ms) => cb())
76
80
  })
77
81
 
82
+ it('initialises airbrake', () => {
83
+ jest.isolateModules(async () => {
84
+ require('../recurring-payments-processor.js')
85
+ await execute()
86
+ expect(airbrake.initialise).toHaveBeenCalled()
87
+ })
88
+ })
89
+
90
+ it('flushes airbrake before script ends', () => {
91
+ jest.isolateModules(async () => {
92
+ const { execute } = require('../recurring-payments-processor.js')
93
+ await execute()
94
+ expect(airbrake.flush).toHaveBeenCalled()
95
+ })
96
+ })
97
+
98
+ it("doesn't flush airbrake before execute has been called", () => {
99
+ jest.isolateModules(() => {
100
+ require('../recurring-payments-processor.js')
101
+ expect(airbrake.flush).not.toHaveBeenCalled()
102
+ })
103
+ })
104
+
105
+ it.each([
106
+ ['SIGINT', 130],
107
+ ['SIGTERM', 137]
108
+ ])('flushes airbrake on %s signal', (signal, code) => {
109
+ jest.isolateModules(() => {
110
+ // setup a delay so script doesn't call processRecurringPayments and exit naturally
111
+ process.env.RECURRING_PAYMENTS_LOCAL_DELAY = '1'
112
+ const signalCallbacks = {}
113
+ jest.spyOn(process, 'on')
114
+ jest.spyOn(process, 'exit')
115
+ process.on.mockImplementation((signalToken, callback) => {
116
+ signalCallbacks[signalToken] = callback
117
+ })
118
+ process.exit.mockImplementation(() => {
119
+ // so we don't crash out of the tests!
120
+ })
121
+
122
+ require('../recurring-payments-processor.js')
123
+ signalCallbacks[signal]()
124
+
125
+ expect(airbrake.flush).toHaveBeenCalled()
126
+ process.on.mockRestore()
127
+ process.exit.mockRestore()
128
+ })
129
+ })
130
+
131
+ it.each([
132
+ ['SIGINT', 130],
133
+ ['SIGTERM', 137]
134
+ ])('calls process.exit on %s signal with %i code', (signal, code) => {
135
+ jest.isolateModules(() => {
136
+ const signalCallbacks = {}
137
+ jest.spyOn(process, 'on')
138
+ jest.spyOn(process, 'exit')
139
+ process.on.mockImplementation((signalToken, callback) => {
140
+ signalCallbacks[signalToken] = callback
141
+ })
142
+ process.exit.mockImplementation(() => {
143
+ // so we don't crash out of the tests!
144
+ })
145
+
146
+ require('../recurring-payments-job.js')
147
+ signalCallbacks[signal]()
148
+
149
+ expect(process.exit).toHaveBeenCalledWith(code)
150
+ process.on.mockRestore()
151
+ process.exit.mockRestore()
152
+ })
153
+ })
154
+
78
155
  it('debug log displays "Recurring Payments job disabled" when env is false', async () => {
79
156
  process.env.RUN_RECURRING_PAYMENTS = 'false'
80
157
 
81
- await processRecurringPayments()
158
+ await execute()
82
159
 
83
160
  expect(debugLogger).toHaveBeenCalledWith('Recurring Payments job disabled')
84
161
  })
85
162
 
86
163
  it('debug log displays "Recurring Payments job enabled" when env is true', async () => {
87
- await processRecurringPayments()
164
+ await execute()
88
165
 
89
166
  expect(debugLogger).toHaveBeenCalledWith('Recurring Payments job enabled')
90
167
  })
91
168
 
92
- it('throws if Gov.UK Pay is not healthy', async () => {
169
+ it('logs console error if Gov.UK Pay is not healthy', async () => {
170
+ jest.spyOn(console, 'error')
93
171
  isGovPayUp.mockResolvedValueOnce(false)
94
- await expect(() => processRecurringPayments()).rejects.toThrow('Run aborted, Gov.UK Pay health endpoint is reporting problems.')
172
+ await execute()
173
+ expect(console.error).toHaveBeenCalledWith(
174
+ expect.objectContaining({
175
+ message: 'Run aborted, Gov.UK Pay health endpoint is reporting problems.'
176
+ })
177
+ )
178
+ console.error.mockReset()
95
179
  })
96
180
 
97
181
  it('get recurring payments is called when env is true', async () => {
98
182
  const date = new Date().toISOString().split('T')[0]
99
183
 
100
- await processRecurringPayments()
184
+ await execute()
101
185
 
102
186
  expect(salesApi.getDueRecurringPayments).toHaveBeenCalledWith(date)
103
187
  })
104
188
 
105
189
  it('debug log displays "Recurring Payments found:" when env is true', async () => {
106
- await processRecurringPayments()
190
+ await execute()
107
191
 
108
192
  expect(debugLogger).toHaveBeenNthCalledWith(2, 'Recurring Payments found:', [])
109
193
  })
110
194
 
111
195
  describe('When RP fetch throws an error...', () => {
112
- it('processRecurringPayments re-throws the error', async () => {
113
- const error = new Error('Test error')
114
- salesApi.getDueRecurringPayments.mockImplementationOnce(() => {
115
- throw error
116
- })
117
-
118
- await expect(processRecurringPayments()).rejects.toThrowError(error)
119
- })
120
-
121
196
  it('calls console.error with error message', async () => {
122
197
  const errorSpy = jest.spyOn(console, 'error').mockImplementation(jest.fn())
123
198
  const error = new Error('Test error')
@@ -126,7 +201,7 @@ describe('recurring-payments-processor', () => {
126
201
  })
127
202
 
128
203
  try {
129
- await processRecurringPayments()
204
+ await execute()
130
205
  } catch {}
131
206
 
132
207
  expect(errorSpy).toHaveBeenCalledWith('Run aborted. Error fetching due recurring payments:', error)
@@ -140,7 +215,7 @@ describe('recurring-payments-processor', () => {
140
215
  sendPayment.mockRejectedValueOnce(oopsie)
141
216
 
142
217
  try {
143
- await processRecurringPayments()
218
+ await execute()
144
219
  } catch {}
145
220
 
146
221
  expect(debugLogger).toHaveBeenCalledWith(expect.any(String), oopsie)
@@ -180,7 +255,7 @@ describe('recurring-payments-processor', () => {
180
255
  authorisation_mode: 'agreement'
181
256
  }
182
257
 
183
- await processRecurringPayments()
258
+ await execute()
184
259
 
185
260
  expect(sendPayment).toHaveBeenCalledTimes(4)
186
261
  expect(sendPayment).toHaveBeenNthCalledWith(
@@ -216,7 +291,7 @@ describe('recurring-payments-processor', () => {
216
291
  salesApi.createTransaction.mockRejectedValueOnce(errors[1]).mockReturnValueOnce({ cost: 50, id: 'transaction-id-3' })
217
292
  sendPayment.mockRejectedValueOnce(errors[2])
218
293
 
219
- await processRecurringPayments()
294
+ await execute()
220
295
 
221
296
  expect(debugLogger).toHaveBeenCalledWith(expect.any(String), ...errors)
222
297
  })
@@ -235,7 +310,7 @@ describe('recurring-payments-processor', () => {
235
310
  }
236
311
  salesApi.getDueRecurringPayments.mockReturnValueOnce(dueRecurringPayments)
237
312
 
238
- await processRecurringPayments()
313
+ await execute()
239
314
 
240
315
  expect(getPaymentStatus).toHaveBeenCalledTimes(6)
241
316
  })
@@ -248,7 +323,7 @@ describe('recurring-payments-processor', () => {
248
323
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
249
324
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
250
325
 
251
- await processRecurringPayments()
326
+ await execute()
252
327
 
253
328
  expect(salesApi.preparePermissionDataForRenewal).toHaveBeenCalledWith(referenceNumber)
254
329
  })
@@ -305,7 +380,7 @@ describe('recurring-payments-processor', () => {
305
380
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
306
381
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
307
382
 
308
- await processRecurringPayments()
383
+ await execute()
309
384
 
310
385
  expect(salesApi.createTransaction).toHaveBeenCalledWith(expectedData)
311
386
  })
@@ -323,7 +398,7 @@ describe('recurring-payments-processor', () => {
323
398
  sendPayment.mockResolvedValueOnce(samplePayment)
324
399
  salesApi.createTransaction.mockResolvedValueOnce(sampleTransaction)
325
400
 
326
- await processRecurringPayments()
401
+ await execute()
327
402
 
328
403
  expect(salesApi.createPaymentJournal).toHaveBeenCalledWith(
329
404
  sampleTransaction.id,
@@ -355,7 +430,7 @@ describe('recurring-payments-processor', () => {
355
430
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
356
431
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
357
432
 
358
- await processRecurringPayments()
433
+ await execute()
359
434
 
360
435
  expect(salesApi.createTransaction).toHaveBeenCalledWith(
361
436
  expect.objectContaining({
@@ -385,7 +460,7 @@ describe('recurring-payments-processor', () => {
385
460
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
386
461
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
387
462
 
388
- await processRecurringPayments()
463
+ await execute()
389
464
 
390
465
  expect(salesApi.createTransaction).toHaveBeenCalledWith(
391
466
  expect.objectContaining({
@@ -406,7 +481,7 @@ describe('recurring-payments-processor', () => {
406
481
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
407
482
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
408
483
 
409
- await processRecurringPayments()
484
+ await execute()
410
485
 
411
486
  expect(salesApi.createTransaction).toHaveBeenCalledWith(
412
487
  expect.objectContaining({
@@ -442,7 +517,7 @@ describe('recurring-payments-processor', () => {
442
517
  agreement_id: agreementId
443
518
  }
444
519
 
445
- await processRecurringPayments()
520
+ await execute()
446
521
 
447
522
  expect(sendPayment).toHaveBeenCalledWith(expectedData)
448
523
  })
@@ -468,7 +543,7 @@ describe('recurring-payments-processor', () => {
468
543
  const mockPaymentResponse = { payment_id: 'test-payment-id', agreementId: 'agreement-1' }
469
544
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
470
545
 
471
- await processRecurringPayments()
546
+ await execute()
472
547
 
473
548
  expect(getPaymentStatus).toHaveBeenCalledWith('test-payment-id')
474
549
  })
@@ -495,7 +570,7 @@ describe('recurring-payments-processor', () => {
495
570
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
496
571
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
497
572
 
498
- await processRecurringPayments()
573
+ await execute()
499
574
 
500
575
  console.log(debugLogger.mock.calls)
501
576
  expect(debugLogger).toHaveBeenCalledWith(`Payment status for ${mockPaymentId}: ${PAYMENT_STATUS.Success}`)
@@ -508,7 +583,7 @@ describe('recurring-payments-processor', () => {
508
583
  throw error
509
584
  })
510
585
 
511
- await processRecurringPayments()
586
+ await execute()
512
587
 
513
588
  expect(debugLogger).toHaveBeenCalledWith(expect.any(String), error)
514
589
  })
@@ -536,7 +611,7 @@ describe('recurring-payments-processor', () => {
536
611
  const apiError = { response: { status: statusCode, data: 'boom' } }
537
612
  getPaymentStatus.mockRejectedValueOnce(apiError)
538
613
 
539
- await processRecurringPayments()
614
+ await execute()
540
615
 
541
616
  expect(debugLogger).toHaveBeenCalledWith(expectedMessage)
542
617
  })
@@ -554,7 +629,7 @@ describe('recurring-payments-processor', () => {
554
629
  const networkError = new Error('network meltdown')
555
630
  getPaymentStatus.mockRejectedValueOnce(networkError)
556
631
 
557
- await processRecurringPayments()
632
+ await execute()
558
633
 
559
634
  expect(debugLogger).toHaveBeenCalledWith(`Unexpected error fetching payment status for ${mockPaymentId}.`)
560
635
  })
@@ -568,7 +643,7 @@ describe('recurring-payments-processor', () => {
568
643
 
569
644
  const setTimeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(cb => cb())
570
645
 
571
- await processRecurringPayments()
646
+ await execute()
572
647
 
573
648
  expect(setTimeoutSpy).toHaveBeenCalledWith(expect.any(Function), PAYMENT_STATUS_DELAY)
574
649
  })
@@ -578,7 +653,7 @@ describe('recurring-payments-processor', () => {
578
653
 
579
654
  const setTimeoutSpy = jest.spyOn(global, 'setTimeout').mockImplementation(cb => cb())
580
655
 
581
- await processRecurringPayments()
656
+ await execute()
582
657
 
583
658
  expect(setTimeoutSpy).not.toHaveBeenCalled()
584
659
  })
@@ -595,7 +670,7 @@ describe('recurring-payments-processor', () => {
595
670
  sendPayment.mockResolvedValueOnce({ payment_id: mockPaymentId, agreementId: 'agreement-1', created_date: mockPaymentCreatedDate })
596
671
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusSuccess())
597
672
 
598
- await processRecurringPayments()
673
+ await execute()
599
674
 
600
675
  console.log(salesApi.processRPResult.mock.calls, mockTransactionId, mockPaymentId, mockPaymentCreatedDate)
601
676
  expect(salesApi.processRPResult).toHaveBeenCalledWith(mockTransactionId, mockPaymentId, mockPaymentCreatedDate)
@@ -608,7 +683,7 @@ describe('recurring-payments-processor', () => {
608
683
  sendPayment.mockResolvedValueOnce({ payment_id: mockPaymentId, agreementId: 'agreement-1' })
609
684
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusFailure())
610
685
 
611
- await processRecurringPayments()
686
+ await execute()
612
687
 
613
688
  expect(salesApi.processRPResult).not.toHaveBeenCalled()
614
689
  })
@@ -629,7 +704,7 @@ describe('recurring-payments-processor', () => {
629
704
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
630
705
  getPaymentStatus.mockResolvedValueOnce(mockStatus)
631
706
 
632
- await processRecurringPayments()
707
+ await execute()
633
708
 
634
709
  expect(consoleErrorSpy).toHaveBeenCalledWith(
635
710
  `Payment failed. Recurring payment agreement for: ${agreementId} set to be cancelled. Updating payment journal.`
@@ -656,7 +731,7 @@ describe('recurring-payments-processor', () => {
656
731
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
657
732
  getPaymentStatus.mockResolvedValueOnce(mockStatus)
658
733
 
659
- await processRecurringPayments()
734
+ await execute()
660
735
 
661
736
  expect(salesApi.cancelRecurringPayment).toHaveBeenCalledWith(id)
662
737
  })
@@ -673,7 +748,7 @@ describe('recurring-payments-processor', () => {
673
748
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusFailure())
674
749
  salesApi.getPaymentJournal.mockResolvedValueOnce(true)
675
750
 
676
- await processRecurringPayments()
751
+ await execute()
677
752
 
678
753
  expect(salesApi.updatePaymentJournal).toHaveBeenCalledWith(transactionId, { paymentStatus: PAYMENT_JOURNAL_STATUS_CODES.Failed })
679
754
  })
@@ -690,7 +765,7 @@ describe('recurring-payments-processor', () => {
690
765
  getPaymentStatus.mockResolvedValueOnce(getPaymentStatusFailure())
691
766
  salesApi.getPaymentJournal.mockResolvedValueOnce(undefined)
692
767
 
693
- await processRecurringPayments()
768
+ await execute()
694
769
 
695
770
  expect(salesApi.updatePaymentJournal).not.toHaveBeenCalled()
696
771
  })
@@ -716,7 +791,7 @@ describe('recurring-payments-processor', () => {
716
791
  expectedData.push([reference])
717
792
  })
718
793
 
719
- await processRecurringPayments()
794
+ await execute()
720
795
 
721
796
  expect(salesApi.preparePermissionDataForRenewal.mock.calls).toEqual(expectedData)
722
797
  })
@@ -760,7 +835,7 @@ describe('recurring-payments-processor', () => {
760
835
  ])
761
836
  })
762
837
 
763
- await processRecurringPayments()
838
+ await execute()
764
839
 
765
840
  expect(salesApi.createTransaction.mock.calls).toEqual(expectedData)
766
841
  })
@@ -804,7 +879,7 @@ describe('recurring-payments-processor', () => {
804
879
  ])
805
880
  })
806
881
 
807
- await processRecurringPayments()
882
+ await execute()
808
883
  expect(sendPayment.mock.calls).toEqual(expectedData)
809
884
  })
810
885
 
@@ -842,7 +917,7 @@ describe('recurring-payments-processor', () => {
842
917
  sendPayment.mockResolvedValueOnce(mockPaymentResponse)
843
918
  })
844
919
 
845
- await processRecurringPayments()
920
+ await execute()
846
921
  expectedData.forEach(paymentId => {
847
922
  expect(getPaymentStatus).toHaveBeenCalledWith(paymentId)
848
923
  })
@@ -1,17 +1,12 @@
1
1
  'use strict'
2
2
  import recurringPaymentsJob from 'commander'
3
- import { processRecurringPayments } from './recurring-payments-processor.js'
4
- import { airbrake } from '@defra-fish/connectors-lib'
3
+ import { execute } from './recurring-payments-processor.js'
5
4
  import path from 'path'
6
5
  import fs from 'fs'
7
-
8
- const SIGINT_CODE = 130
9
- const SIGTERM_CODE = 137
10
6
  const pkgPath = path.join(process.cwd(), 'package.json')
11
7
  const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'))
12
8
 
13
9
  console.log('Recurring payments job starting at %s. name: %s. version: %s', new Date().toISOString(), pkg.name, pkg.version)
14
- airbrake.initialise()
15
10
 
16
11
  const delay = parseInt(process.env.RECURRING_PAYMENTS_LOCAL_DELAY || '0', 10)
17
12
  if (delay > 0) {
@@ -23,16 +18,7 @@ if (delay > 0) {
23
18
  }
24
19
 
25
20
  function executeRecurringPaymentsJob () {
26
- recurringPaymentsJob.action(processRecurringPayments())
27
- airbrake.flush()
28
- }
29
-
30
- const shutdown = code => {
31
- airbrake.flush()
32
- process.exit(code)
21
+ recurringPaymentsJob.action(execute())
33
22
  }
34
23
 
35
- process.on('SIGINT', () => shutdown(SIGINT_CODE))
36
- process.on('SIGTERM', () => shutdown(SIGTERM_CODE))
37
-
38
24
  export default recurringPaymentsJob
@@ -1,11 +1,13 @@
1
1
  import moment from 'moment-timezone'
2
2
  import { PAYMENT_STATUS, SERVICE_LOCAL_TIME, PAYMENT_JOURNAL_STATUS_CODES } from '@defra-fish/business-rules-lib'
3
- import { salesApi } from '@defra-fish/connectors-lib'
3
+ import { salesApi, airbrake } from '@defra-fish/connectors-lib'
4
4
  import { getPaymentStatus, sendPayment, isGovPayUp } from './services/govuk-pay-service.js'
5
5
  import db from 'debug'
6
6
 
7
7
  const debug = db('recurring-payments:processor')
8
8
 
9
+ const SIGINT_CODE = 130
10
+ const SIGTERM_CODE = 137
9
11
  const PAYMENT_STATUS_DELAY = 60000
10
12
  const MIN_CLIENT_ERROR = 400
11
13
  const MAX_CLIENT_ERROR = 499
@@ -15,18 +17,18 @@ const MAX_SERVER_ERROR = 599
15
17
  const isClientError = code => code >= MIN_CLIENT_ERROR && code <= MAX_CLIENT_ERROR
16
18
  const isServerError = code => code >= MIN_SERVER_ERROR && code <= MAX_SERVER_ERROR
17
19
 
18
- const fetchDueRecurringPayments = async date => {
20
+ export const execute = async () => {
21
+ airbrake.initialise()
19
22
  try {
20
- const duePayments = await salesApi.getDueRecurringPayments(date)
21
- debug('Recurring Payments found:', duePayments)
22
- return duePayments
23
- } catch (error) {
24
- console.error('Run aborted. Error fetching due recurring payments:', error)
25
- throw error
23
+ await processRecurringPayments()
24
+ } catch (e) {
25
+ console.error(e)
26
+ } finally {
27
+ await airbrake.flush()
26
28
  }
27
29
  }
28
30
 
29
- export const processRecurringPayments = async () => {
31
+ const processRecurringPayments = async () => {
30
32
  if (process.env.RUN_RECURRING_PAYMENTS?.toLowerCase() !== 'true') {
31
33
  debug('Recurring Payments job disabled')
32
34
  return
@@ -52,6 +54,17 @@ export const processRecurringPayments = async () => {
52
54
  await Promise.allSettled(payments.map(p => processRecurringPaymentStatus(p)))
53
55
  }
54
56
 
57
+ const fetchDueRecurringPayments = async date => {
58
+ try {
59
+ const duePayments = await salesApi.getDueRecurringPayments(date)
60
+ debug('Recurring Payments found:', duePayments)
61
+ return duePayments
62
+ } catch (error) {
63
+ console.error('Run aborted. Error fetching due recurring payments:', error)
64
+ throw error
65
+ }
66
+ }
67
+
55
68
  const requestPayments = async dueRCPayments => {
56
69
  const paymentRequestResults = await Promise.allSettled(dueRCPayments.map(processRecurringPayment))
57
70
  const payments = paymentRequestResults.filter(prr => prr.status === 'fulfilled').map(p => p.value)
@@ -168,3 +181,11 @@ const processRecurringPaymentStatus = async payment => {
168
181
  }
169
182
  }
170
183
  }
184
+
185
+ const shutdown = code => {
186
+ airbrake.flush()
187
+ process.exit(code)
188
+ }
189
+
190
+ process.on('SIGINT', () => shutdown(SIGINT_CODE))
191
+ process.on('SIGTERM', () => shutdown(SIGTERM_CODE))