Skip to content

Commit

Permalink
add alerting for unsettled payment requests (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
samplackett committed Aug 13, 2024
1 parent be2468c commit 5451306
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 17 deletions.
1 change: 1 addition & 0 deletions app/constants/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
PAYMENT_PROCESSING_FAILED: 'uk.gov.defra.ffc.pay.warning.processing.failed',
PAYMENT_RESET: 'uk.gov.defra.ffc.pay.payment.reset',
PAYMENT_SETTLED: 'uk.gov.defra.ffc.pay.payment.settled',
PAYMENT_SETTLEMENT_UNSETTLED: 'uk.gov.defra.ffc.pay.warning.settlement.unsettled',
PAYMENT_SETTLEMENT_UNMATCHED: 'uk.gov.defra.ffc.pay.warning.settlement.unmatched',
PAYMENT_SUPPRESSED: 'uk.gov.defra.ffc.pay.payment.suppressed.recovery'
}
14 changes: 9 additions & 5 deletions app/event/send-return-event.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const { EventPublisher } = require('ffc-pay-event-publisher')
const { getPaymentRequestByInvoiceAndFrn } = require('../processing/get-payment-request-by-invoice-frn')
const { UNKNOWN } = require('../constants/unknown')
const { SOURCE } = require('../constants/source')
const { PAYMENT_SETTLED, PAYMENT_SETTLEMENT_UNMATCHED } = require('../constants/events')
const { PAYMENT_SETTLED, PAYMENT_SETTLEMENT_UNMATCHED, PAYMENT_SETTLEMENT_UNSETTLED } = require('../constants/events')

const sendProcessingReturnEvent = async (message, isError = false) => {
const invoiceNumber = message.invoiceNumber ?? UNKNOWN
Expand All @@ -12,7 +12,7 @@ const sendProcessingReturnEvent = async (message, isError = false) => {
if (!isError) {
await raiseCompletedReturnEvent(invoiceNumber, frn)
} else {
await raiseErrorEvent(invoiceNumber, frn)
await raiseErrorEvent(invoiceNumber, frn, message.settled)
}
}

Expand All @@ -22,9 +22,9 @@ const raiseCompletedReturnEvent = async (invoiceNumber, frn) => {
}
}

const raiseErrorEvent = async (invoiceNumber, frn) => {
const raiseErrorEvent = async (invoiceNumber, frn, settled) => {
if (processingConfig.useV2Events) {
await raiseV2ErrorEvent(invoiceNumber, frn)
await raiseV2ErrorEvent(invoiceNumber, frn, settled)
}
}

Expand All @@ -39,7 +39,7 @@ const raiseV2CompletedReturnEvent = async (invoiceNumber, frn) => {
await eventPublisher.publishEvent(event)
}

const raiseV2ErrorEvent = async (invoiceNumber, frn) => {
const raiseV2ErrorEvent = async (invoiceNumber, frn, settled) => {
const event = {
source: SOURCE,
type: PAYMENT_SETTLEMENT_UNMATCHED,
Expand All @@ -49,6 +49,10 @@ const raiseV2ErrorEvent = async (invoiceNumber, frn) => {
invoiceNumber
}
}
if (!settled) {
event.type = PAYMENT_SETTLEMENT_UNSETTLED
event.data.message = `D365 has reported a settlement for Invoice number ${invoiceNumber}, FRN ${frn} was unsuccessful`
}
const eventPublisher = new EventPublisher(messageConfig.eventsTopic)
await eventPublisher.publishEvent(event)
}
Expand Down
2 changes: 1 addition & 1 deletion app/messaging/process-return-message.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const processReturnMessage = async (message, receiver) => {
console.log('Settlement statuses updated from return file')
} else {
await receiver.deadLetterMessage(message)
console.error('Unable to find settlement for payment request', message.body)
console.error('Settlement could not be processed for payment request', message.body)
}
} catch (err) {
console.error('Unable to process return request:', err)
Expand Down
16 changes: 8 additions & 8 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ffc-pay-processing",
"version": "2.55.20",
"version": "2.55.21",
"description": "Payment Hub processing service",
"homepage": "https://github.com/DEFRA/ffc-pay-processing",
"main": "app/index.js",
Expand Down
45 changes: 43 additions & 2 deletions test/unit/event/send-return-event.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const { getPaymentRequestByInvoiceAndFrn } = require('../../../app/processing/ge
jest.mock('../../../app/config')
const { processingConfig, messageConfig } = require('../../../app/config')

const { PAYMENT_SETTLEMENT_UNMATCHED, PAYMENT_SETTLED } = require('../../../app/constants/events')
const { PAYMENT_SETTLEMENT_UNMATCHED, PAYMENT_SETTLEMENT_UNSETTLED, PAYMENT_SETTLED } = require('../../../app/constants/events')
const { SOURCE } = require('../../../app/constants/source')

const { sendProcessingReturnEvent } = require('../../../app/event/send-return-event')
Expand All @@ -45,12 +45,22 @@ describe('V2 acknowledgement error event', () => {
processingConfig.useV2Events = true
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent).toHaveBeenCalled()
expect(mockPublishEvent.mock.calls[0][0].type).toBe(PAYMENT_SETTLEMENT_UNMATCHED)
})

test('should send V2 event for matched settlement if V2 events enabled', async () => {
processingConfig.useV2Events = true
await sendProcessingReturnEvent(settlement)
expect(mockPublishEvent).toHaveBeenCalled()
expect(mockPublishEvent.mock.calls[0][0].type).toBe(PAYMENT_SETTLED)
})

test('should send V2 event for unsettled settlement if V2 events enabled and settlement unsuccessful by D365', async () => {
processingConfig.useV2Events = true
settlement.settled = false
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent).toHaveBeenCalled()
expect(mockPublishEvent.mock.calls[0][0].type).toBe(PAYMENT_SETTLEMENT_UNSETTLED)
})

test('should not send V2 event for unmatched settlement if V2 events disabled', async () => {
Expand All @@ -65,6 +75,13 @@ describe('V2 acknowledgement error event', () => {
expect(mockPublishEvent).not.toHaveBeenCalled()
})

test('should not send V2 event for unsettled settlement if V2 events disabled', async () => {
processingConfig.useV2Events = false
settlement.settled = false
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent).not.toHaveBeenCalled()
})

test('should send unmatched settlement event to V2 topic', async () => {
await sendProcessingReturnEvent(settlement, true)
expect(MockEventPublisher.mock.calls[0][0]).toBe(messageConfig.eventsTopic)
Expand All @@ -75,6 +92,12 @@ describe('V2 acknowledgement error event', () => {
expect(MockEventPublisher.mock.calls[0][0]).toBe(messageConfig.eventsTopic)
})

test('should send unsettled settlement event to V2 topic', async () => {
settlement.settled = false
await sendProcessingReturnEvent(settlement, true)
expect(MockEventPublisher.mock.calls[0][0]).toBe(messageConfig.eventsTopic)
})

test('should raise unmatched settlement event with processing source', async () => {
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent.mock.calls[0][0].source).toBe(SOURCE)
Expand All @@ -85,21 +108,39 @@ describe('V2 acknowledgement error event', () => {
expect(mockPublishEvent.mock.calls[0][0].source).toBe(SOURCE)
})

test('should raise unsettled settlement event with processing source', async () => {
settlement.settled = false
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent.mock.calls[0][0].source).toBe(SOURCE)
})

test('should raise unmatched event type for unmatched settlement', async () => {
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent.mock.calls[0][0].type).toBe(PAYMENT_SETTLEMENT_UNMATCHED)
})

test('should raise payment invalid bank event type for matched settlement', async () => {
test('should raise payment settled event type for matched settlement', async () => {
await sendProcessingReturnEvent(settlement)
expect(mockPublishEvent.mock.calls[0][0].type).toBe(PAYMENT_SETTLED)
})

test('should raise unsettled event type for unsuccessful settlement', async () => {
settlement.settled = false
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent.mock.calls[0][0].type).toBe(PAYMENT_SETTLEMENT_UNSETTLED)
})

test('should include unmatched warning for unmatched settlement', async () => {
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent.mock.calls[0][0].data.message).toEqual('Unable to find payment request for settlement, Invoice number: S12345678C1234567V001 FRN: 1234567890')
})

test('should include unsettled warning for unsuccessful settlement', async () => {
settlement.settled = false
await sendProcessingReturnEvent(settlement, true)
expect(mockPublishEvent.mock.calls[0][0].data.message).toEqual('D365 has reported a settlement for Invoice number S12345678C1234567V001, FRN 1234567890 was unsuccessful')
})

test('should include payment request data for matched settlement', async () => {
await sendProcessingReturnEvent(settlement)
expect(mockPublishEvent.mock.calls[0][0].data).toEqual(paymentRequest)
Expand Down

0 comments on commit 5451306

Please sign in to comment.