@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.
|
|
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.
|
|
40
|
-
"@defra-fish/connectors-lib": "1.63.0-rc.
|
|
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": "
|
|
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
|
|
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
|
-
|
|
97
|
-
|
|
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
|