Skip to content

Commit ecd5c73

Browse files
committed
Additional logging
1 parent a6cab10 commit ecd5c73

5 files changed

Lines changed: 117 additions & 28 deletions

File tree

src/server/plugins/engine/components/PaymentField.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ export class PaymentField extends FormComponent {
225225
description,
226226
payCallbackUrl,
227227
reference,
228+
isLivePayment,
228229
{ formId, slug }
229230
)
230231

@@ -276,7 +277,10 @@ export class PaymentField extends FormComponent {
276277
/**
277278
* @see https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle
278279
*/
279-
const status = await paymentService.getPaymentStatus(paymentId)
280+
const status = await paymentService.getPaymentStatus(
281+
paymentId,
282+
isLivePayment
283+
)
280284

281285
PaymentSubmissionError.checkPaymentAmount(
282286
status.amount,

src/server/plugins/engine/routes/payment-helper.js

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,41 @@ export async function getPaymentContext(request, uuid) {
2828

2929
const apiKey = getPaymentApiKey(isLivePayment, formId)
3030
const paymentService = new PaymentService(apiKey)
31-
const paymentStatus = await paymentService.getPaymentStatus(paymentId)
31+
const paymentStatus = await paymentService.getPaymentStatus(
32+
paymentId,
33+
isLivePayment
34+
)
3235

3336
return { session, sessionKey, paymentStatus }
3437
}
3538

39+
/**
40+
* Builds an object for logging payment information
41+
* @param {string} action
42+
* @param {string} outcome
43+
* @param {string} reason
44+
* @param {boolean} isLivePayment
45+
* @param {string} paymentId
46+
*/
47+
export function buildPaymentInfo(
48+
action,
49+
outcome,
50+
reason,
51+
isLivePayment,
52+
paymentId
53+
) {
54+
return {
55+
event: {
56+
category: 'payment',
57+
action,
58+
outcome,
59+
reason,
60+
type: isLivePayment ? 'live' : 'test',
61+
reference: paymentId
62+
}
63+
}
64+
}
65+
3666
/**
3767
* @import { Request } from '@hapi/hapi'
3868
* @import { GetPaymentResponse, PaymentSessionData } from '~/src/server/plugins/payment/types.js'

src/server/plugins/engine/routes/payment.js

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,18 @@ import Boom from '@hapi/boom'
22
import { StatusCodes } from 'http-status-codes'
33
import Joi from 'joi'
44

5+
import { createLogger } from '~/src/server/common/helpers/logging/logger.js'
56
import { EXTERNAL_STATE_APPENDAGE } from '~/src/server/constants.js'
6-
import { getPaymentContext } from '~/src/server/plugins/engine/routes/payment-helper.js'
7+
import {
8+
buildPaymentInfo,
9+
getPaymentContext
10+
} from '~/src/server/plugins/engine/routes/payment-helper.js'
711

812
export const PAYMENT_RETURN_PATH = '/payment-callback'
913
export const PAYMENT_SESSION_PREFIX = 'payment-'
1014

15+
const logger = createLogger()
16+
1117
/**
1218
* Flash form component state after successful payment
1319
* @param {Request} request - the request
@@ -48,6 +54,42 @@ export function getRoutes() {
4854
return [getReturnRoute()]
4955
}
5056

57+
/**
58+
* Logs successful payment
59+
* @param {PaymentSessionData} session - the session data
60+
* @param {GetPaymentResponse} paymentStatus - the payment status from GOV.UK Pay
61+
*/
62+
function logPaymentSuccess(session, paymentStatus) {
63+
logger.info(
64+
buildPaymentInfo(
65+
'pre-auth',
66+
'success',
67+
`${paymentStatus.state.status} amount=${paymentStatus.amount}`,
68+
session.isLivePayment,
69+
paymentStatus.paymentId
70+
),
71+
`[payment] Successful pre-auth for paymentId=${paymentStatus.paymentId}`
72+
)
73+
}
74+
75+
/**
76+
* Logs failed/cancelled payment
77+
* @param {PaymentSessionData} session - the session data
78+
* @param {GetPaymentResponse} paymentStatus - the payment status from GOV.UK Pay
79+
*/
80+
function logPaymentFailure(session, paymentStatus) {
81+
logger.info(
82+
buildPaymentInfo(
83+
'pre-auth',
84+
'failed/cancelled',
85+
`${paymentStatus.state.status} amount=${paymentStatus.amount}`,
86+
session.isLivePayment,
87+
paymentStatus.paymentId
88+
),
89+
`[payment] Failed/cancelled pre-auth for paymentId=${paymentStatus.paymentId}`
90+
)
91+
}
92+
5193
/**
5294
* Handles successful payment states (capturable/success)
5395
* @param {Request} request - the request
@@ -98,6 +140,7 @@ function getReturnRoute() {
98140
switch (status) {
99141
case 'capturable':
100142
case 'success':
143+
logPaymentSuccess(session, paymentStatus)
101144
return handlePaymentSuccess(
102145
request,
103146
h,
@@ -109,6 +152,7 @@ function getReturnRoute() {
109152
case 'cancelled':
110153
case 'failed':
111154
case 'error':
155+
logPaymentFailure(session, paymentStatus)
112156
return handlePaymentFailure(request, h, session, sessionKey)
113157

114158
case 'created':

src/server/plugins/payment/service.js

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { StatusCodes } from 'http-status-codes'
22

33
import { createLogger } from '~/src/server/common/helpers/logging/logger.js'
4+
import { buildPaymentInfo } from '~/src/server/plugins/engine/routes/payment-helper.js'
45
import { get, post, postJson } from '~/src/server/services/httpService.js'
56

67
const PAYMENT_BASE_URL = 'https://publicapi.payments.service.gov.uk'
@@ -35,9 +36,17 @@ export class PaymentService {
3536
* @param {string} description
3637
* @param {string} returnUrl
3738
* @param {string} reference
39+
* @param {boolean} isLivePayment
3840
* @param {{ formId: string, slug: string }} metadata
3941
*/
40-
async createPayment(amount, description, returnUrl, reference, metadata) {
42+
async createPayment(
43+
amount,
44+
description,
45+
returnUrl,
46+
reference,
47+
isLivePayment,
48+
metadata
49+
) {
4150
const response = await this.postToPayProvider({
4251
amount,
4352
description,
@@ -48,15 +57,13 @@ export class PaymentService {
4857
})
4958

5059
logger.info(
51-
{
52-
event: {
53-
category: 'payment',
54-
action: 'create-payment',
55-
outcome: 'success',
56-
reason: `amount=${amount}`,
57-
reference: response.payment_id
58-
}
59-
},
60+
buildPaymentInfo(
61+
'create-payment',
62+
'success',
63+
`amount=${amount}`,
64+
isLivePayment,
65+
response.payment_id
66+
),
6067
`[payment] Created payment and user taken to enter pre-auth details for paymentId=${response.payment_id}`
6168
)
6269

@@ -68,9 +75,10 @@ export class PaymentService {
6875

6976
/**
7077
* @param {string} paymentId
78+
* @param {boolean} isLivePayment
7179
* @returns {Promise<GetPaymentResponse>}
7280
*/
73-
async getPaymentStatus(paymentId) {
81+
async getPaymentStatus(paymentId, isLivePayment) {
7482
const getByType = /** @type {typeof get<GetPaymentApiResponse>} */ (get)
7583

7684
try {
@@ -92,18 +100,15 @@ export class PaymentService {
92100

93101
const state = response.payload.state
94102
logger.info(
95-
{
96-
event: {
97-
category: 'payment',
98-
action: 'get-payment-status',
99-
outcome:
100-
state.status === 'capturable' || state.status === 'success'
101-
? 'success'
102-
: 'failure',
103-
reason: `status:${state.status} code:${state.code ?? 'N/A'} message:${state.message ?? 'N/A'}`,
104-
reference: paymentId
105-
}
106-
},
103+
buildPaymentInfo(
104+
'get-payment-status',
105+
state.status === 'capturable' || state.status === 'success'
106+
? 'success'
107+
: 'failure',
108+
`status:${state.status} code:${state.code ?? 'N/A'} message:${state.message ?? 'N/A'}`,
109+
isLivePayment,
110+
paymentId
111+
),
107112
`[payment] Got payment status for paymentId=${paymentId}: status=${state.status}`
108113
)
109114

src/server/plugins/payment/service.test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ describe('payment service', () => {
4141
'Payment description',
4242
returnUrl,
4343
referenceNumber,
44+
false,
4445
metadata
4546
)
4647
expect(payment.paymentId).toBe('payment-id-12345')
@@ -61,6 +62,7 @@ describe('payment service', () => {
6162
'Payment description',
6263
returnUrl,
6364
referenceNumber,
65+
false,
6466
metadata
6567
)
6668
).rejects.toThrow('internal creation error')
@@ -90,6 +92,7 @@ describe('payment service', () => {
9092
'Payment description',
9193
returnUrl,
9294
referenceNumber,
95+
false,
9396
metadata
9497
)
9598
).rejects.toThrow('Failed to create payment')
@@ -119,7 +122,10 @@ describe('payment service', () => {
119122
error: undefined
120123
})
121124

122-
const paymentStatus = await service.getPaymentStatus('payment-id-12345')
125+
const paymentStatus = await service.getPaymentStatus(
126+
'payment-id-12345',
127+
false
128+
)
123129
expect(paymentStatus.paymentId).toBe('payment-id-12345')
124130
expect(paymentStatus._links.next_url?.href).toBe(
125131
'http://next-url-href/payment'
@@ -137,7 +143,7 @@ describe('payment service', () => {
137143
})
138144

139145
await expect(() =>
140-
service.getPaymentStatus('payment-id-12345')
146+
service.getPaymentStatus('payment-id-12345', false)
141147
).rejects.toThrow('Failed to get payment status: some-error')
142148
})
143149
})

0 commit comments

Comments
 (0)