@defra-fish/payment-mop-up-job 1.63.0-rc.5 → 1.63.0-rc.7

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/payment-mop-up-job",
3
- "version": "1.63.0-rc.5",
3
+ "version": "1.63.0-rc.7",
4
4
  "description": "Process incomplete web-sales",
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.5",
40
- "@defra-fish/connectors-lib": "1.63.0-rc.5",
39
+ "@defra-fish/business-rules-lib": "1.63.0-rc.7",
40
+ "@defra-fish/connectors-lib": "1.63.0-rc.7",
41
41
  "bottleneck": "^2.19.5",
42
42
  "debug": "^4.3.3",
43
43
  "moment": "^2.29.1"
44
44
  },
45
- "gitHead": "313d1d1a8ab65bd841c27cf615f8abeec527f401"
45
+ "gitHead": "345c44f58b91a92723579e072235aa9607827efb"
46
46
  }
@@ -161,6 +161,105 @@ describe('processor', () => {
161
161
  })
162
162
  })
163
163
 
164
+ it('calls fetchPaymentStatus with recurring as true since agreementId exists', async () => {
165
+ salesApi.retrieveStagedTransaction.mockReturnValueOnce({ recurringPayment: { agreementId: '123' } })
166
+ const paymentReference = '15nioqikvvnuu5l8m2qeaj0qap'
167
+ const journalEntriesAgreement = [
168
+ {
169
+ id: 'a0e0e5c3-1004-4271-80ba-d05eda3e8220',
170
+ paymentStatus: 'In Progress',
171
+ paymentReference,
172
+ paymentTimestamp: '2020-06-01T10:35:56.873Z'
173
+ }
174
+ ]
175
+ salesApi.paymentJournals.getAll.mockReturnValue(journalEntriesAgreement)
176
+ salesApi.updatePaymentJournal.mockImplementation(jest.fn())
177
+ salesApi.finaliseTransaction.mockImplementation(jest.fn())
178
+ govUkPayApi.fetchPaymentStatus.mockResolvedValueOnce({
179
+ json: async () => ({ state: { status: 'success' } })
180
+ })
181
+ govUkPayApi.fetchPaymentEvents.mockResolvedValueOnce({
182
+ json: async () => ({ events: [{ state: { status: 'success' }, updated: '2020-06-01T10:35:56.873Z' }] })
183
+ })
184
+
185
+ await execute(1, 1)
186
+
187
+ expect(govUkPayApi.fetchPaymentStatus).toHaveBeenCalledWith(paymentReference, true)
188
+ })
189
+
190
+ it('calls fetchPaymentStatus with recurring as false since agreementId does not exist', async () => {
191
+ salesApi.retrieveStagedTransaction.mockReturnValueOnce({})
192
+ const paymentReference = '25nioqikvvnuu5l8m2qeaj0qap'
193
+ const journalEntriesAgreement = [
194
+ {
195
+ id: 'a0e0e5c3-1004-4271-80ba-d05eda3e8220',
196
+ paymentStatus: 'In Progress',
197
+ paymentReference,
198
+ paymentTimestamp: '2020-06-01T10:35:56.873Z'
199
+ }
200
+ ]
201
+ salesApi.paymentJournals.getAll.mockReturnValue(journalEntriesAgreement)
202
+ salesApi.updatePaymentJournal.mockImplementation(jest.fn())
203
+ salesApi.finaliseTransaction.mockImplementation(jest.fn())
204
+ govUkPayApi.fetchPaymentStatus.mockReturnValueOnce({
205
+ json: async () => ({ state: { status: 'success' } })
206
+ })
207
+
208
+ await execute(1, 1)
209
+
210
+ expect(govUkPayApi.fetchPaymentStatus).toHaveBeenCalledWith(paymentReference, false)
211
+ })
212
+
213
+ it('calls fetchPaymentEvents with recurring as true since agreementId exists', async () => {
214
+ salesApi.retrieveStagedTransaction.mockReturnValueOnce({ recurringPayment: { agreementId: '123' } })
215
+ const paymentReference = '35nioqikvvnuu5l8m2qeaj0qap'
216
+ const journalEntriesAgreement = [
217
+ {
218
+ id: 'a0e0e5c3-1004-4271-80ba-d05eda3e8220',
219
+ paymentStatus: 'In Progress',
220
+ paymentReference,
221
+ paymentTimestamp: '2020-06-01T10:35:56.873Z',
222
+ agreementId: 'c9267c6e-573d-488b-99ab-ea18431fc472'
223
+ }
224
+ ]
225
+ salesApi.paymentJournals.getAll.mockReturnValue(journalEntriesAgreement)
226
+ salesApi.updatePaymentJournal.mockImplementation(jest.fn())
227
+ salesApi.finaliseTransaction.mockImplementation(jest.fn())
228
+ govUkPayApi.fetchPaymentStatus.mockResolvedValueOnce({
229
+ json: async () => ({ state: { status: 'success' } })
230
+ })
231
+ govUkPayApi.fetchPaymentEvents.mockResolvedValueOnce({
232
+ json: async () => ({ events: [{ state: { status: 'success' }, updated: '2020-06-01T10:35:56.873Z' }] })
233
+ })
234
+
235
+ await execute(1, 1)
236
+
237
+ expect(govUkPayApi.fetchPaymentEvents).toHaveBeenCalledWith(paymentReference, true)
238
+ })
239
+
240
+ it('calls fetchPaymentEvents with recurring as false since agreementId does not exist', async () => {
241
+ salesApi.retrieveStagedTransaction.mockReturnValueOnce({})
242
+ const paymentReference = '45nioqikvvnuu5l8m2qeaj0qap'
243
+ const journalEntriesAgreement = [
244
+ {
245
+ id: 'a0e0e5c3-1004-4271-80ba-d05eda3e8220',
246
+ paymentStatus: 'In Progress',
247
+ paymentReference,
248
+ paymentTimestamp: '2020-06-01T10:35:56.873Z'
249
+ }
250
+ ]
251
+ salesApi.paymentJournals.getAll.mockReturnValue(journalEntriesAgreement)
252
+ salesApi.updatePaymentJournal.mockImplementation(jest.fn())
253
+ salesApi.finaliseTransaction.mockImplementation(jest.fn())
254
+ govUkPayApi.fetchPaymentStatus.mockReturnValueOnce({
255
+ json: async () => ({ state: { status: 'success' } })
256
+ })
257
+
258
+ await execute(1, 1)
259
+
260
+ expect(govUkPayApi.fetchPaymentEvents).toHaveBeenCalledWith(paymentReference, false)
261
+ })
262
+
164
263
  describe('Result not present in GovPay', () => {
165
264
  const NOT_FOUND_ID = journalEntries[2].id
166
265
  const NOT_FOUND_PAYMENT_REFERENCE = journalEntries[2].paymentReference
@@ -199,9 +298,7 @@ describe('processor', () => {
199
298
 
200
299
  it("when a payment isn't present in GovPay, it's marked as expired after 3 hours", async () => {
201
300
  const missingJournalEntry = journalEntries.find(je => je.id === NOT_FOUND_ID)
202
- missingJournalEntry.paymentTimestamp = moment()
203
- .subtract(3, 'hours')
204
- .toISOString()
301
+ missingJournalEntry.paymentTimestamp = moment().subtract(3, 'hours').toISOString()
205
302
  await execute(1, 1)
206
303
  expect(salesApi.updatePaymentJournal).toHaveBeenCalledWith(
207
304
  NOT_FOUND_ID,
@@ -213,9 +310,7 @@ describe('processor', () => {
213
310
 
214
311
  it("when a payment isn't present in GovPay, it's not marked as expired if 3 hours haven't passed", async () => {
215
312
  const missingJournalEntry = journalEntries.find(je => je.id === NOT_FOUND_ID)
216
- missingJournalEntry.paymentTimestamp = moment()
217
- .subtract(2, 'hours')
218
- .toISOString()
313
+ missingJournalEntry.paymentTimestamp = moment().subtract(2, 'hours').toISOString()
219
314
  await execute(1, 1)
220
315
  expect(salesApi.updatePaymentJournal).not.toHaveBeenCalledWith(
221
316
  NOT_FOUND_ID,
@@ -5,7 +5,6 @@ import {
5
5
  TRANSACTION_SOURCE,
6
6
  PAYMENT_TYPE
7
7
  } from '@defra-fish/business-rules-lib'
8
-
9
8
  import Bottleneck from 'bottleneck'
10
9
  import moment from 'moment'
11
10
  import db from 'debug'
@@ -61,11 +60,12 @@ const processPaymentResults = async transaction => {
61
60
  }
62
61
  }
63
62
 
64
- const getStatus = async paymentReference => {
65
- const paymentStatusResponse = await govUkPayApi.fetchPaymentStatus(paymentReference)
63
+ const getStatus = async (paymentReference, agreementId) => {
64
+ const recurring = !!agreementId
65
+ const paymentStatusResponse = await govUkPayApi.fetchPaymentStatus(paymentReference, recurring)
66
66
  const paymentStatus = await paymentStatusResponse.json()
67
67
  if (paymentStatus.state?.status === 'success') {
68
- const eventsResponse = await govUkPayApi.fetchPaymentEvents(paymentReference)
68
+ const eventsResponse = await govUkPayApi.fetchPaymentEvents(paymentReference, recurring)
69
69
  const { events } = await eventsResponse.json()
70
70
  paymentStatus.transactionTimestamp = events.find(e => e.state.status === 'success')?.updated
71
71
  }
@@ -82,8 +82,6 @@ export const execute = async (ageMinutes, scanDurationHours) => {
82
82
  const toTimestamp = moment().add(-1 * ageMinutes, 'minutes')
83
83
  const fromTimestamp = toTimestamp.clone().add(-1 * scanDurationHours, 'hours')
84
84
 
85
- console.log(`Scanning the payment journal for payments created between ${fromTimestamp} and ${toTimestamp}`)
86
-
87
85
  const paymentJournals = await salesApi.paymentJournals.getAll({
88
86
  paymentStatus: PAYMENT_JOURNAL_STATUS_CODES.InProgress,
89
87
  from: fromTimestamp.toISOString(),
@@ -92,10 +90,13 @@ export const execute = async (ageMinutes, scanDurationHours) => {
92
90
 
93
91
  // Get the status for each payment from the GOV.UK Pay API.
94
92
  const transactions = await Promise.all(
95
- paymentJournals.map(async p => ({
96
- ...p,
97
- paymentStatus: await getStatusWrapped(p.paymentReference)
98
- }))
93
+ paymentJournals.map(async p => {
94
+ const transactionRecord = await salesApi.retrieveStagedTransaction(p.id)
95
+ return {
96
+ ...p,
97
+ paymentStatus: await getStatusWrapped(p.paymentReference, transactionRecord?.recurringPayment?.agreementId)
98
+ }
99
+ })
99
100
  )
100
101
 
101
102
  // Process each result