@defra-fish/payment-mop-up-job 1.76.0 → 1.77.0-rc.1
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.
|
|
3
|
+
"version": "1.77.0-rc.1",
|
|
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.
|
|
40
|
-
"@defra-fish/connectors-lib": "1.
|
|
39
|
+
"@defra-fish/business-rules-lib": "1.77.0-rc.1",
|
|
40
|
+
"@defra-fish/connectors-lib": "1.77.0-rc.1",
|
|
41
41
|
"bottleneck": "2.19.5",
|
|
42
42
|
"debug": "4.3.3",
|
|
43
43
|
"moment": "2.29.1"
|
|
44
44
|
},
|
|
45
|
-
"gitHead": "
|
|
45
|
+
"gitHead": "2d2758c633c72fb22cd69fd5c9cbf0046568a9a9"
|
|
46
46
|
}
|
|
@@ -14,30 +14,35 @@ jest.mock('bottleneck', () =>
|
|
|
14
14
|
const journalEntries = () => [
|
|
15
15
|
{
|
|
16
16
|
id: '4fa393ab-07f4-407e-b233-89be2a6f5f77',
|
|
17
|
+
eligibleForEarlyMopUp: false,
|
|
17
18
|
paymentStatus: 'In Progress',
|
|
18
19
|
paymentReference: '05nioqikvvnuu5l8m2qeaj0qap',
|
|
19
20
|
paymentTimestamp: '2020-06-01T10:35:56.873Z'
|
|
20
21
|
},
|
|
21
22
|
{
|
|
22
23
|
id: 'aaced854-d337-47ee-8d5e-75b26aeb90fb',
|
|
24
|
+
eligibleForEarlyMopUp: false,
|
|
23
25
|
paymentStatus: 'In Progress',
|
|
24
26
|
paymentReference: '0f3dr9ugp7u68qq18vt9h8ma85',
|
|
25
27
|
paymentTimestamp: '2020-06-02T07:17:23.169Z'
|
|
26
28
|
},
|
|
27
29
|
{
|
|
28
30
|
id: 'a0e0e5c3-1004-4271-80ba-d05eda3e8213',
|
|
31
|
+
eligibleForEarlyMopUp: false,
|
|
29
32
|
paymentStatus: 'In Progress',
|
|
30
33
|
paymentReference: '7lufvi9sbh077rvrrmnqo63vme',
|
|
31
|
-
paymentTimestamp: '2020-06-
|
|
34
|
+
paymentTimestamp: '2020-06-04T11:04:30.802Z'
|
|
32
35
|
},
|
|
33
36
|
{
|
|
34
37
|
id: 'a0e0e5c3-1004-4271-80ba-d05eda3e8214',
|
|
38
|
+
eligibleForEarlyMopUp: true,
|
|
35
39
|
paymentStatus: 'In Progress',
|
|
36
40
|
paymentReference: '7lufvi9sbh077rvrrmnqo63vmf',
|
|
37
41
|
paymentTimestamp: '2020-06-04T12:04:30.802Z'
|
|
38
42
|
},
|
|
39
43
|
{
|
|
40
44
|
id: 'a0e0e5c3-1004-4271-80ba-d05eda3e8215',
|
|
45
|
+
eligibleForEarlyMopUp: false,
|
|
41
46
|
paymentStatus: 'In Progress',
|
|
42
47
|
paymentReference: '7lufvi9sbh077rvrrmnqo63vmg',
|
|
43
48
|
paymentTimestamp: '2020-06-04T12:04:30.802Z'
|
|
@@ -128,6 +133,10 @@ const createPaymentEventsEntry = paymentStatus => {
|
|
|
128
133
|
describe('processor', () => {
|
|
129
134
|
beforeEach(jest.clearAllMocks)
|
|
130
135
|
|
|
136
|
+
beforeAll(() => {
|
|
137
|
+
salesApi.paymentJournals.getAll.mockReturnValue([])
|
|
138
|
+
})
|
|
139
|
+
|
|
131
140
|
it('completes normally where there are no journal records retrieved', async () => {
|
|
132
141
|
salesApi.paymentJournals.getAll.mockReturnValueOnce([])
|
|
133
142
|
await execute(1, 1)
|
|
@@ -166,6 +175,69 @@ describe('processor', () => {
|
|
|
166
175
|
})
|
|
167
176
|
})
|
|
168
177
|
|
|
178
|
+
it.each([
|
|
179
|
+
['2026-09-10T09:00:00.000Z', 1, 1],
|
|
180
|
+
['2024-02-29T19:00:00.000Z', 14, 5],
|
|
181
|
+
['2026-09-10T00:01:00.000Z', 28, 37]
|
|
182
|
+
])(
|
|
183
|
+
"sends expected arguments to query payment journals when it's %s, we're looking for payments over %i minute(s) old and going back %i hour(s)",
|
|
184
|
+
async (now, ageMinutes, scanDurationHours) => {
|
|
185
|
+
jest.useFakeTimers().setSystemTime(new Date(now))
|
|
186
|
+
const expectedFrom = moment(now).subtract({ minutes: ageMinutes, hours: scanDurationHours }).toISOString()
|
|
187
|
+
|
|
188
|
+
await execute(ageMinutes, scanDurationHours)
|
|
189
|
+
|
|
190
|
+
expect(salesApi.paymentJournals.getAll).toHaveBeenCalledWith(
|
|
191
|
+
expect.objectContaining({
|
|
192
|
+
paymentStatus: PAYMENT_JOURNAL_STATUS_CODES.InProgress,
|
|
193
|
+
from: expectedFrom,
|
|
194
|
+
to: now
|
|
195
|
+
})
|
|
196
|
+
)
|
|
197
|
+
jest.useRealTimers()
|
|
198
|
+
}
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
it('only processes payments that are either within the payment window or have eligibleForEarlyMopUp flag', async () => {
|
|
202
|
+
const now = '2020-06-04T12:04:30.802Z'
|
|
203
|
+
jest.useFakeTimers().setSystemTime(new Date(now))
|
|
204
|
+
const sampleJournalEntries = journalEntries()
|
|
205
|
+
salesApi.paymentJournals.getAll.mockResolvedValueOnce(sampleJournalEntries)
|
|
206
|
+
for (let x = 0; x < sampleJournalEntries.length; x++) {
|
|
207
|
+
govUkPayApi.fetchPaymentStatus.mockImplementationOnce(ref => ({ json: async () => ({}) }))
|
|
208
|
+
govUkPayApi.fetchPaymentEvents.mockImplementationOnce(ref => ({
|
|
209
|
+
json: async () => ({
|
|
210
|
+
events: [
|
|
211
|
+
{
|
|
212
|
+
payment_id: ref,
|
|
213
|
+
state: {
|
|
214
|
+
status: 'success',
|
|
215
|
+
finished: true
|
|
216
|
+
},
|
|
217
|
+
amount: 8200
|
|
218
|
+
}
|
|
219
|
+
]
|
|
220
|
+
})
|
|
221
|
+
}))
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
await execute(1, 1)
|
|
225
|
+
|
|
226
|
+
const expectedIds = [
|
|
227
|
+
'05nioqikvvnuu5l8m2qeaj0qap',
|
|
228
|
+
'0f3dr9ugp7u68qq18vt9h8ma85',
|
|
229
|
+
'7lufvi9sbh077rvrrmnqo63vme',
|
|
230
|
+
'7lufvi9sbh077rvrrmnqo63vmf'
|
|
231
|
+
]
|
|
232
|
+
const unexpectedId = '7lufvi9sbh077rvrrmnqo63vmg'
|
|
233
|
+
for (const expectedId of expectedIds) {
|
|
234
|
+
expect(govUkPayApi.fetchPaymentStatus).toHaveBeenCalledWith(expectedId, expect.anything())
|
|
235
|
+
}
|
|
236
|
+
expect(govUkPayApi.fetchPaymentStatus).not.toHaveBeenCalledWith(unexpectedId, expect.anything())
|
|
237
|
+
|
|
238
|
+
jest.useRealTimers()
|
|
239
|
+
})
|
|
240
|
+
|
|
169
241
|
it('calls fetchPaymentStatus with recurring as true since agreementId exists', async () => {
|
|
170
242
|
salesApi.retrieveStagedTransaction.mockReturnValueOnce({ recurringPayment: { agreementId: '123' } })
|
|
171
243
|
const paymentReference = '15nioqikvvnuu5l8m2qeaj0qap'
|
|
@@ -112,17 +112,19 @@ export const execute = async (ageMinutes, scanDurationHours) => {
|
|
|
112
112
|
debug(`Running payment mop up processor with a payment age of ${ageMinutes} minutes and a scan duration of ${scanDurationHours} hours`)
|
|
113
113
|
|
|
114
114
|
const toTimestamp = moment().add(-1 * ageMinutes, 'minutes')
|
|
115
|
+
const now = moment()
|
|
115
116
|
const fromTimestamp = toTimestamp.clone().add(-1 * scanDurationHours, 'hours')
|
|
116
117
|
|
|
117
118
|
const paymentJournals = await salesApi.paymentJournals.getAll({
|
|
118
119
|
paymentStatus: PAYMENT_JOURNAL_STATUS_CODES.InProgress,
|
|
119
120
|
from: fromTimestamp.toISOString(),
|
|
120
|
-
to:
|
|
121
|
+
to: now.toISOString()
|
|
121
122
|
})
|
|
123
|
+
const paymentJournalsToMopUp = paymentJournals.filter(pj => toTimestamp.isAfter(pj.paymentTimestamp) || pj.eligibleForEarlyMopUp)
|
|
122
124
|
|
|
123
125
|
// Get the status for each payment from the GOV.UK Pay API.
|
|
124
126
|
const journalsWithRecurringPaymentIDs = await Promise.all(
|
|
125
|
-
|
|
127
|
+
paymentJournalsToMopUp.map(async p => {
|
|
126
128
|
const transactionRecord = await salesApi.retrieveStagedTransaction(p.id)
|
|
127
129
|
const paymentJournalWithStatus = {
|
|
128
130
|
...p,
|