@defra/forms-engine-plugin 4.0.42 → 4.0.44
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/.public/javascripts/shared.min.js +1 -1
- package/.public/javascripts/shared.min.js.map +1 -1
- package/.public/stylesheets/application.min.css +1 -1
- package/.public/stylesheets/application.min.css.map +1 -1
- package/.server/client/javascripts/location-map.js +8 -4
- package/.server/client/javascripts/location-map.js.map +1 -1
- package/.server/client/stylesheets/_payment-field.scss +8 -0
- package/.server/client/stylesheets/application.scss +2 -0
- package/.server/index.js +3 -1
- package/.server/index.js.map +1 -1
- package/.server/server/constants.d.ts +1 -0
- package/.server/server/constants.js +1 -0
- package/.server/server/constants.js.map +1 -1
- package/.server/server/forms/payment-test.yaml +42 -0
- package/.server/server/forms/register-as-a-unicorn-breeder.yaml +14 -0
- package/.server/server/plugins/engine/components/FormComponent.d.ts +1 -0
- package/.server/server/plugins/engine/components/FormComponent.js +1 -0
- package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
- package/.server/server/plugins/engine/components/PaymentField.d.ts +135 -0
- package/.server/server/plugins/engine/components/PaymentField.js +228 -0
- package/.server/server/plugins/engine/components/PaymentField.js.map +1 -0
- package/.server/server/plugins/engine/components/PaymentField.types.d.ts +21 -0
- package/.server/server/plugins/engine/components/PaymentField.types.js +2 -0
- package/.server/server/plugins/engine/components/PaymentField.types.js.map +1 -0
- package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -1
- package/.server/server/plugins/engine/components/UkAddressField.js +3 -1
- package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
- package/.server/server/plugins/engine/components/helpers/components.d.ts +1 -1
- package/.server/server/plugins/engine/components/helpers/components.js +3 -0
- package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
- package/.server/server/plugins/engine/components/index.d.ts +1 -0
- package/.server/server/plugins/engine/components/index.js +1 -0
- package/.server/server/plugins/engine/components/index.js.map +1 -1
- package/.server/server/plugins/engine/configureEnginePlugin.d.ts +1 -1
- package/.server/server/plugins/engine/configureEnginePlugin.js +4 -2
- package/.server/server/plugins/engine/configureEnginePlugin.js.map +1 -1
- package/.server/server/plugins/engine/helpers.d.ts +1 -0
- package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +3 -0
- package/.server/server/plugins/engine/models/SummaryViewModel.js +7 -0
- package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
- package/.server/server/plugins/engine/options.js +2 -1
- package/.server/server/plugins/engine/options.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js +34 -1
- package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +22 -0
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js +43 -1
- package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +29 -8
- package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +2 -0
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +17 -0
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +173 -51
- package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/errors.d.ts +31 -0
- package/.server/server/plugins/engine/pageControllers/errors.js +59 -2
- package/.server/server/plugins/engine/pageControllers/errors.js.map +1 -1
- package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +27 -0
- package/.server/server/plugins/engine/pageControllers/helpers/submission.js +77 -0
- package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -0
- package/.server/server/plugins/engine/plugin.js +10 -5
- package/.server/server/plugins/engine/plugin.js.map +1 -1
- package/.server/server/plugins/engine/routes/index.js +8 -4
- package/.server/server/plugins/engine/routes/index.js.map +1 -1
- package/.server/server/plugins/engine/routes/payment-helper.d.ts +14 -0
- package/.server/server/plugins/engine/routes/payment-helper.js +41 -0
- package/.server/server/plugins/engine/routes/payment-helper.js.map +1 -0
- package/.server/server/plugins/engine/routes/payment-helper.test.js +81 -0
- package/.server/server/plugins/engine/routes/payment-helper.test.js.map +1 -0
- package/.server/server/plugins/engine/routes/payment.d.ts +8 -0
- package/.server/server/plugins/engine/routes/payment.js +140 -0
- package/.server/server/plugins/engine/routes/payment.js.map +1 -0
- package/.server/server/plugins/engine/routes/payment.test.js +187 -0
- package/.server/server/plugins/engine/routes/payment.test.js.map +1 -0
- package/.server/server/plugins/engine/services/localFormsService.js +6 -0
- package/.server/server/plugins/engine/services/localFormsService.js.map +1 -1
- package/.server/server/plugins/engine/types/schema.js +7 -0
- package/.server/server/plugins/engine/types/schema.js.map +1 -1
- package/.server/server/plugins/engine/types.d.ts +20 -1
- package/.server/server/plugins/engine/types.js +4 -0
- package/.server/server/plugins/engine/types.js.map +1 -1
- package/.server/server/plugins/engine/validationHelpers.d.ts +1 -1
- package/.server/server/plugins/engine/validationHelpers.js.map +1 -1
- package/.server/server/plugins/engine/views/components/paymentfield.html +42 -0
- package/.server/server/plugins/engine/views/index.html +9 -1
- package/.server/server/plugins/engine/views/partials/form.html +20 -5
- package/.server/server/plugins/engine/views/summary.html +17 -1
- package/.server/server/plugins/map/routes/get-os-token.d.ts +6 -0
- package/.server/server/plugins/map/routes/get-os-token.js +41 -0
- package/.server/server/plugins/map/routes/get-os-token.js.map +1 -0
- package/.server/server/plugins/map/routes/get-os-token.test.js +49 -0
- package/.server/server/plugins/map/routes/get-os-token.test.js.map +1 -0
- package/.server/server/plugins/map/routes/index.d.ts +1 -11
- package/.server/server/plugins/map/routes/index.js +60 -16
- package/.server/server/plugins/map/routes/index.js.map +1 -1
- package/.server/server/plugins/map/types.d.ts +1 -0
- package/.server/server/plugins/map/types.js +1 -0
- package/.server/server/plugins/map/types.js.map +1 -1
- package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
- package/.server/server/plugins/payment/helper.d.ts +30 -0
- package/.server/server/plugins/payment/helper.js +49 -0
- package/.server/server/plugins/payment/helper.js.map +1 -0
- package/.server/server/plugins/payment/helper.test.js +37 -0
- package/.server/server/plugins/payment/helper.test.js.map +1 -0
- package/.server/server/plugins/payment/service.d.ts +40 -0
- package/.server/server/plugins/payment/service.js +129 -0
- package/.server/server/plugins/payment/service.js.map +1 -0
- package/.server/server/plugins/payment/service.test.js +162 -0
- package/.server/server/plugins/payment/service.test.js.map +1 -0
- package/.server/server/plugins/payment/types.d.ts +172 -0
- package/.server/server/plugins/payment/types.js +78 -0
- package/.server/server/plugins/payment/types.js.map +1 -0
- package/.server/server/types.d.ts +3 -0
- package/.server/server/types.js.map +1 -1
- package/.server/typings/hapi/index.d.js.map +1 -1
- package/README.md +12 -9
- package/package.json +2 -2
- package/src/client/javascripts/location-map.js +12 -4
- package/src/client/stylesheets/_payment-field.scss +8 -0
- package/src/client/stylesheets/application.scss +2 -0
- package/src/index.ts +5 -1
- package/src/server/constants.js +1 -0
- package/src/server/forms/payment-test.yaml +42 -0
- package/src/server/forms/register-as-a-unicorn-breeder.yaml +14 -0
- package/src/server/plugins/engine/components/FormComponent.ts +1 -0
- package/src/server/plugins/engine/components/PaymentField.test.ts +611 -0
- package/src/server/plugins/engine/components/PaymentField.ts +367 -0
- package/src/server/plugins/engine/components/PaymentField.types.ts +21 -0
- package/src/server/plugins/engine/components/UkAddressField.ts +2 -1
- package/src/server/plugins/engine/components/helpers/components.ts +5 -0
- package/src/server/plugins/engine/components/index.ts +1 -0
- package/src/server/plugins/engine/configureEnginePlugin.ts +4 -2
- package/src/server/plugins/engine/models/SummaryViewModel.ts +8 -0
- package/src/server/plugins/engine/options.js +2 -1
- package/src/server/plugins/engine/outputFormatters/human/v1.payment.test.ts +147 -0
- package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +105 -103
- package/src/server/plugins/engine/outputFormatters/human/v1.ts +61 -2
- package/src/server/plugins/engine/outputFormatters/machine/v2.payment.test.ts +115 -0
- package/src/server/plugins/engine/outputFormatters/machine/v2.ts +60 -1
- package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +32 -6
- package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +247 -72
- package/src/server/plugins/engine/pageControllers/errors.test.ts +13 -1
- package/src/server/plugins/engine/pageControllers/errors.ts +79 -4
- package/src/server/plugins/engine/pageControllers/helpers/submission.test.ts +299 -0
- package/src/server/plugins/engine/pageControllers/helpers/submission.ts +110 -0
- package/src/server/plugins/engine/plugin.ts +17 -10
- package/src/server/plugins/engine/routes/index.ts +17 -16
- package/src/server/plugins/engine/routes/payment-helper.js +39 -0
- package/src/server/plugins/engine/routes/payment-helper.test.js +90 -0
- package/src/server/plugins/engine/routes/payment.js +151 -0
- package/src/server/plugins/engine/routes/payment.test.js +180 -0
- package/src/server/plugins/engine/services/localFormsService.js +7 -0
- package/src/server/plugins/engine/types/schema.ts +9 -0
- package/src/server/plugins/engine/types.ts +25 -1
- package/src/server/plugins/engine/validationHelpers.ts +1 -1
- package/src/server/plugins/engine/views/components/paymentfield.html +42 -0
- package/src/server/plugins/engine/views/index.html +9 -1
- package/src/server/plugins/engine/views/partials/form.html +20 -5
- package/src/server/plugins/engine/views/summary.html +17 -1
- package/src/server/plugins/map/routes/get-os-token.js +41 -0
- package/src/server/plugins/map/routes/get-os-token.test.js +55 -0
- package/src/server/plugins/map/routes/index.js +70 -24
- package/src/server/plugins/map/types.js +1 -0
- package/src/server/plugins/payment/helper.js +56 -0
- package/src/server/plugins/payment/helper.test.js +52 -0
- package/src/server/plugins/payment/service.js +171 -0
- package/src/server/plugins/payment/service.test.js +205 -0
- package/src/server/plugins/payment/types.js +77 -0
- package/src/server/types.ts +3 -0
- package/src/typings/hapi/index.d.ts +1 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { getPaymentContext } from "./payment-helper.js";
|
|
2
|
+
import { get } from "../../../services/httpService.js";
|
|
3
|
+
jest.mock("../../../services/httpService.ts");
|
|
4
|
+
describe('payment helper', () => {
|
|
5
|
+
const uuid = '5a54c2fe-da49-4202-8cd3-2121eaca03c3';
|
|
6
|
+
it('should throw if no session', async () => {
|
|
7
|
+
const mockRequest = {
|
|
8
|
+
yar: {
|
|
9
|
+
get: jest.fn().mockReturnValueOnce(undefined)
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
// @ts-expect-error - partial request mock
|
|
13
|
+
await expect(() => getPaymentContext(mockRequest, uuid)).rejects.toThrow('No payment session found for uuid=5a54c2fe-da49-4202-8cd3-2121eaca03c3');
|
|
14
|
+
});
|
|
15
|
+
it('should throw if no payment id', async () => {
|
|
16
|
+
const mockRequest = {
|
|
17
|
+
yar: {
|
|
18
|
+
get: jest.fn().mockReturnValueOnce({})
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
// @ts-expect-error - partial request mock
|
|
22
|
+
await expect(() => getPaymentContext(mockRequest, uuid)).rejects.toThrow('No paymentId in session');
|
|
23
|
+
});
|
|
24
|
+
it('should get context successfully', async () => {
|
|
25
|
+
const mockRequest = {
|
|
26
|
+
yar: {
|
|
27
|
+
get: jest.fn().mockReturnValueOnce({
|
|
28
|
+
paymentId: 'payment-id',
|
|
29
|
+
isLivePayment: false,
|
|
30
|
+
formId: 'formid'
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const getPaymentStatusApiResult = {
|
|
35
|
+
payment_id: 'payment-id-12345',
|
|
36
|
+
_links: {
|
|
37
|
+
next_url: {
|
|
38
|
+
href: 'http://next-url-href/payment'
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
state: {
|
|
42
|
+
status: 'created'
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
jest.mocked(get).mockResolvedValueOnce({
|
|
46
|
+
res: (/** @type {IncomingMessage} */{
|
|
47
|
+
statusCode: 200,
|
|
48
|
+
headers: {}
|
|
49
|
+
}),
|
|
50
|
+
payload: getPaymentStatusApiResult,
|
|
51
|
+
error: undefined
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// @ts-expect-error - partial request mock
|
|
55
|
+
const res = await getPaymentContext(mockRequest, uuid);
|
|
56
|
+
expect(res).toEqual({
|
|
57
|
+
paymentStatus: {
|
|
58
|
+
paymentId: 'payment-id-12345',
|
|
59
|
+
_links: {
|
|
60
|
+
next_url: {
|
|
61
|
+
href: 'http://next-url-href/payment'
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
state: {
|
|
65
|
+
status: 'created'
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
session: {
|
|
69
|
+
formId: 'formid',
|
|
70
|
+
isLivePayment: false,
|
|
71
|
+
paymentId: 'payment-id'
|
|
72
|
+
},
|
|
73
|
+
sessionKey: 'payment-5a54c2fe-da49-4202-8cd3-2121eaca03c3'
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @import { IncomingMessage } from 'node:http'
|
|
80
|
+
*/
|
|
81
|
+
//# sourceMappingURL=payment-helper.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment-helper.test.js","names":["getPaymentContext","get","jest","mock","describe","uuid","it","mockRequest","yar","fn","mockReturnValueOnce","undefined","expect","rejects","toThrow","paymentId","isLivePayment","formId","getPaymentStatusApiResult","payment_id","_links","next_url","href","state","status","mocked","mockResolvedValueOnce","res","statusCode","headers","payload","error","toEqual","paymentStatus","session","sessionKey"],"sources":["../../../../../src/server/plugins/engine/routes/payment-helper.test.js"],"sourcesContent":["import { getPaymentContext } from '~/src/server/plugins/engine/routes/payment-helper.js'\nimport { get } from '~/src/server/services/httpService.js'\n\njest.mock('~/src/server/services/httpService.ts')\n\ndescribe('payment helper', () => {\n const uuid = '5a54c2fe-da49-4202-8cd3-2121eaca03c3'\n it('should throw if no session', async () => {\n const mockRequest = {\n yar: {\n get: jest.fn().mockReturnValueOnce(undefined)\n }\n }\n // @ts-expect-error - partial request mock\n await expect(() => getPaymentContext(mockRequest, uuid)).rejects.toThrow(\n 'No payment session found for uuid=5a54c2fe-da49-4202-8cd3-2121eaca03c3'\n )\n })\n\n it('should throw if no payment id', async () => {\n const mockRequest = {\n yar: {\n get: jest.fn().mockReturnValueOnce({})\n }\n }\n // @ts-expect-error - partial request mock\n await expect(() => getPaymentContext(mockRequest, uuid)).rejects.toThrow(\n 'No paymentId in session'\n )\n })\n\n it('should get context successfully', async () => {\n const mockRequest = {\n yar: {\n get: jest.fn().mockReturnValueOnce({\n paymentId: 'payment-id',\n isLivePayment: false,\n formId: 'formid'\n })\n }\n }\n\n const getPaymentStatusApiResult = {\n payment_id: 'payment-id-12345',\n _links: {\n next_url: {\n href: 'http://next-url-href/payment'\n }\n },\n state: {\n status: 'created'\n }\n }\n\n jest.mocked(get).mockResolvedValueOnce({\n res: /** @type {IncomingMessage} */ ({\n statusCode: 200,\n headers: {}\n }),\n payload: getPaymentStatusApiResult,\n error: undefined\n })\n\n // @ts-expect-error - partial request mock\n const res = await getPaymentContext(mockRequest, uuid)\n expect(res).toEqual({\n paymentStatus: {\n paymentId: 'payment-id-12345',\n _links: {\n next_url: {\n href: 'http://next-url-href/payment'\n }\n },\n state: {\n status: 'created'\n }\n },\n session: {\n formId: 'formid',\n isLivePayment: false,\n paymentId: 'payment-id'\n },\n sessionKey: 'payment-5a54c2fe-da49-4202-8cd3-2121eaca03c3'\n })\n })\n})\n\n/**\n * @import { IncomingMessage } from 'node:http'\n */\n"],"mappings":"AAAA,SAASA,iBAAiB;AAC1B,SAASC,GAAG;AAEZC,IAAI,CAACC,IAAI,mCAAuC,CAAC;AAEjDC,QAAQ,CAAC,gBAAgB,EAAE,MAAM;EAC/B,MAAMC,IAAI,GAAG,sCAAsC;EACnDC,EAAE,CAAC,4BAA4B,EAAE,YAAY;IAC3C,MAAMC,WAAW,GAAG;MAClBC,GAAG,EAAE;QACHP,GAAG,EAAEC,IAAI,CAACO,EAAE,CAAC,CAAC,CAACC,mBAAmB,CAACC,SAAS;MAC9C;IACF,CAAC;IACD;IACA,MAAMC,MAAM,CAAC,MAAMZ,iBAAiB,CAACO,WAAW,EAAEF,IAAI,CAAC,CAAC,CAACQ,OAAO,CAACC,OAAO,CACtE,wEACF,CAAC;EACH,CAAC,CAAC;EAEFR,EAAE,CAAC,+BAA+B,EAAE,YAAY;IAC9C,MAAMC,WAAW,GAAG;MAClBC,GAAG,EAAE;QACHP,GAAG,EAAEC,IAAI,CAACO,EAAE,CAAC,CAAC,CAACC,mBAAmB,CAAC,CAAC,CAAC;MACvC;IACF,CAAC;IACD;IACA,MAAME,MAAM,CAAC,MAAMZ,iBAAiB,CAACO,WAAW,EAAEF,IAAI,CAAC,CAAC,CAACQ,OAAO,CAACC,OAAO,CACtE,yBACF,CAAC;EACH,CAAC,CAAC;EAEFR,EAAE,CAAC,iCAAiC,EAAE,YAAY;IAChD,MAAMC,WAAW,GAAG;MAClBC,GAAG,EAAE;QACHP,GAAG,EAAEC,IAAI,CAACO,EAAE,CAAC,CAAC,CAACC,mBAAmB,CAAC;UACjCK,SAAS,EAAE,YAAY;UACvBC,aAAa,EAAE,KAAK;UACpBC,MAAM,EAAE;QACV,CAAC;MACH;IACF,CAAC;IAED,MAAMC,yBAAyB,GAAG;MAChCC,UAAU,EAAE,kBAAkB;MAC9BC,MAAM,EAAE;QACNC,QAAQ,EAAE;UACRC,IAAI,EAAE;QACR;MACF,CAAC;MACDC,KAAK,EAAE;QACLC,MAAM,EAAE;MACV;IACF,CAAC;IAEDtB,IAAI,CAACuB,MAAM,CAACxB,GAAG,CAAC,CAACyB,qBAAqB,CAAC;MACrCC,GAAG,GAAE,8BAAgC;QACnCC,UAAU,EAAE,GAAG;QACfC,OAAO,EAAE,CAAC;MACZ,CAAC,CAAC;MACFC,OAAO,EAAEZ,yBAAyB;MAClCa,KAAK,EAAEpB;IACT,CAAC,CAAC;;IAEF;IACA,MAAMgB,GAAG,GAAG,MAAM3B,iBAAiB,CAACO,WAAW,EAAEF,IAAI,CAAC;IACtDO,MAAM,CAACe,GAAG,CAAC,CAACK,OAAO,CAAC;MAClBC,aAAa,EAAE;QACblB,SAAS,EAAE,kBAAkB;QAC7BK,MAAM,EAAE;UACNC,QAAQ,EAAE;YACRC,IAAI,EAAE;UACR;QACF,CAAC;QACDC,KAAK,EAAE;UACLC,MAAM,EAAE;QACV;MACF,CAAC;MACDU,OAAO,EAAE;QACPjB,MAAM,EAAE,QAAQ;QAChBD,aAAa,EAAE,KAAK;QACpBD,SAAS,EAAE;MACb,CAAC;MACDoB,UAAU,EAAE;IACd,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ,CAAC,CAAC;;AAEF;AACA;AACA","ignoreList":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gets the payment routes for handling GOV.UK Pay callbacks
|
|
3
|
+
* @returns {ServerRoute[]}
|
|
4
|
+
*/
|
|
5
|
+
export function getRoutes(): ServerRoute[];
|
|
6
|
+
export const PAYMENT_RETURN_PATH: "/payment-callback";
|
|
7
|
+
export const PAYMENT_SESSION_PREFIX: "payment-";
|
|
8
|
+
import type { ServerRoute } from '@hapi/hapi';
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import Boom from '@hapi/boom';
|
|
2
|
+
import { StatusCodes } from 'http-status-codes';
|
|
3
|
+
import Joi from 'joi';
|
|
4
|
+
import { EXTERNAL_STATE_APPENDAGE } from "../../../constants.js";
|
|
5
|
+
import { getPaymentContext } from "./payment-helper.js";
|
|
6
|
+
export const PAYMENT_RETURN_PATH = '/payment-callback';
|
|
7
|
+
export const PAYMENT_SESSION_PREFIX = 'payment-';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Flash form component state after successful payment
|
|
11
|
+
* @param {Request} request - the request
|
|
12
|
+
* @param {PaymentSessionData} session - the session data containing payment state
|
|
13
|
+
* @param {GetPaymentResponse} paymentStatus - the payment status response from GOV.UK Pay
|
|
14
|
+
*/
|
|
15
|
+
function flashComponentState(request, session, paymentStatus) {
|
|
16
|
+
/** @type {PaymentState} */
|
|
17
|
+
const paymentState = {
|
|
18
|
+
paymentId: paymentStatus.paymentId,
|
|
19
|
+
reference: session.reference,
|
|
20
|
+
amount: session.amount,
|
|
21
|
+
description: session.description,
|
|
22
|
+
uuid: session.uuid,
|
|
23
|
+
formId: session.formId,
|
|
24
|
+
isLivePayment: session.isLivePayment,
|
|
25
|
+
payerEmail: paymentStatus.email,
|
|
26
|
+
preAuth: {
|
|
27
|
+
status: 'success',
|
|
28
|
+
createdAt: new Date().toISOString()
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** @type {ExternalStateAppendage} */
|
|
33
|
+
const appendage = {
|
|
34
|
+
component: session.componentName,
|
|
35
|
+
data: (/** @type {FormState} */ /** @type {unknown} */paymentState)
|
|
36
|
+
};
|
|
37
|
+
request.yar.flash(EXTERNAL_STATE_APPENDAGE, appendage, true);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Gets the payment routes for handling GOV.UK Pay callbacks
|
|
42
|
+
* @returns {ServerRoute[]}
|
|
43
|
+
*/
|
|
44
|
+
export function getRoutes() {
|
|
45
|
+
return [getReturnRoute()];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Handles successful payment states (capturable/success)
|
|
50
|
+
* @param {Request} request - the request
|
|
51
|
+
* @param {ResponseToolkit} h - the response toolkit
|
|
52
|
+
* @param {PaymentSessionData} session - the session data
|
|
53
|
+
* @param {string} sessionKey - the session key
|
|
54
|
+
* @param {GetPaymentResponse} paymentStatus - the payment status from GOV.UK Pay
|
|
55
|
+
*/
|
|
56
|
+
function handlePaymentSuccess(request, h, session, sessionKey, paymentStatus) {
|
|
57
|
+
flashComponentState(request, session, paymentStatus);
|
|
58
|
+
request.yar.clear(sessionKey);
|
|
59
|
+
return h.redirect(session.returnUrl).code(StatusCodes.SEE_OTHER);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Handles failed/cancelled/error payment states
|
|
64
|
+
* @param {Request} request - the request
|
|
65
|
+
* @param {ResponseToolkit} h - the response toolkit
|
|
66
|
+
* @param {PaymentSessionData} session - the session data
|
|
67
|
+
* @param {string} sessionKey - the session key
|
|
68
|
+
*/
|
|
69
|
+
function handlePaymentFailure(request, h, session, sessionKey) {
|
|
70
|
+
request.yar.clear(sessionKey);
|
|
71
|
+
return h.redirect(session.failureUrl).code(StatusCodes.SEE_OTHER);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Route handler for payment return URL
|
|
76
|
+
* This is called when GOV.UK Pay redirects the user back after payment
|
|
77
|
+
* @returns {ServerRoute}
|
|
78
|
+
*/
|
|
79
|
+
function getReturnRoute() {
|
|
80
|
+
return {
|
|
81
|
+
method: 'GET',
|
|
82
|
+
path: PAYMENT_RETURN_PATH,
|
|
83
|
+
async handler(request, h) {
|
|
84
|
+
const {
|
|
85
|
+
uuid
|
|
86
|
+
} = /** @type {{ uuid: string }} */request.query;
|
|
87
|
+
const {
|
|
88
|
+
session,
|
|
89
|
+
sessionKey,
|
|
90
|
+
paymentStatus
|
|
91
|
+
} = await getPaymentContext(request, uuid);
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @see https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle
|
|
95
|
+
*/
|
|
96
|
+
const {
|
|
97
|
+
status
|
|
98
|
+
} = paymentStatus.state;
|
|
99
|
+
switch (status) {
|
|
100
|
+
case 'capturable':
|
|
101
|
+
case 'success':
|
|
102
|
+
return handlePaymentSuccess(request, h, session, sessionKey, paymentStatus);
|
|
103
|
+
case 'cancelled':
|
|
104
|
+
case 'failed':
|
|
105
|
+
case 'error':
|
|
106
|
+
return handlePaymentFailure(request, h, session, sessionKey);
|
|
107
|
+
case 'created':
|
|
108
|
+
case 'started':
|
|
109
|
+
case 'submitted':
|
|
110
|
+
{
|
|
111
|
+
const nextUrl = paymentStatus._links.next_url?.href;
|
|
112
|
+
if (!nextUrl) {
|
|
113
|
+
throw Boom.badRequest(`Payment in state '${status}' but no next_url available`);
|
|
114
|
+
}
|
|
115
|
+
return h.redirect(nextUrl).code(StatusCodes.SEE_OTHER);
|
|
116
|
+
}
|
|
117
|
+
default:
|
|
118
|
+
{
|
|
119
|
+
const unknownStatus = /** @type {string} */status;
|
|
120
|
+
throw Boom.internal(`Unknown payment status: ${unknownStatus}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
options: {
|
|
125
|
+
validate: {
|
|
126
|
+
query: Joi.object().keys({
|
|
127
|
+
uuid: Joi.string().uuid().required()
|
|
128
|
+
}).required()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @import { Request, ResponseToolkit, ServerRoute } from '@hapi/hapi'
|
|
136
|
+
* @import { GetPaymentResponse, PaymentSessionData } from '~/src/server/plugins/payment/types.js'
|
|
137
|
+
* @import { PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'
|
|
138
|
+
* @import { ExternalStateAppendage, FormState } from '~/src/server/plugins/engine/types.js'
|
|
139
|
+
*/
|
|
140
|
+
//# sourceMappingURL=payment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment.js","names":["Boom","StatusCodes","Joi","EXTERNAL_STATE_APPENDAGE","getPaymentContext","PAYMENT_RETURN_PATH","PAYMENT_SESSION_PREFIX","flashComponentState","request","session","paymentStatus","paymentState","paymentId","reference","amount","description","uuid","formId","isLivePayment","payerEmail","email","preAuth","status","createdAt","Date","toISOString","appendage","component","componentName","data","yar","flash","getRoutes","getReturnRoute","handlePaymentSuccess","h","sessionKey","clear","redirect","returnUrl","code","SEE_OTHER","handlePaymentFailure","failureUrl","method","path","handler","query","state","nextUrl","_links","next_url","href","badRequest","unknownStatus","internal","options","validate","object","keys","string","required"],"sources":["../../../../../src/server/plugins/engine/routes/payment.js"],"sourcesContent":["import Boom from '@hapi/boom'\nimport { StatusCodes } from 'http-status-codes'\nimport Joi from 'joi'\n\nimport { EXTERNAL_STATE_APPENDAGE } from '~/src/server/constants.js'\nimport { getPaymentContext } from '~/src/server/plugins/engine/routes/payment-helper.js'\n\nexport const PAYMENT_RETURN_PATH = '/payment-callback'\nexport const PAYMENT_SESSION_PREFIX = 'payment-'\n\n/**\n * Flash form component state after successful payment\n * @param {Request} request - the request\n * @param {PaymentSessionData} session - the session data containing payment state\n * @param {GetPaymentResponse} paymentStatus - the payment status response from GOV.UK Pay\n */\nfunction flashComponentState(request, session, paymentStatus) {\n /** @type {PaymentState} */\n const paymentState = {\n paymentId: paymentStatus.paymentId,\n reference: session.reference,\n amount: session.amount,\n description: session.description,\n uuid: session.uuid,\n formId: session.formId,\n isLivePayment: session.isLivePayment,\n payerEmail: paymentStatus.email,\n preAuth: {\n status: 'success',\n createdAt: new Date().toISOString()\n }\n }\n\n /** @type {ExternalStateAppendage} */\n const appendage = {\n component: session.componentName,\n data: /** @type {FormState} */ (/** @type {unknown} */ (paymentState))\n }\n\n request.yar.flash(EXTERNAL_STATE_APPENDAGE, appendage, true)\n}\n\n/**\n * Gets the payment routes for handling GOV.UK Pay callbacks\n * @returns {ServerRoute[]}\n */\nexport function getRoutes() {\n return [getReturnRoute()]\n}\n\n/**\n * Handles successful payment states (capturable/success)\n * @param {Request} request - the request\n * @param {ResponseToolkit} h - the response toolkit\n * @param {PaymentSessionData} session - the session data\n * @param {string} sessionKey - the session key\n * @param {GetPaymentResponse} paymentStatus - the payment status from GOV.UK Pay\n */\nfunction handlePaymentSuccess(request, h, session, sessionKey, paymentStatus) {\n flashComponentState(request, session, paymentStatus)\n request.yar.clear(sessionKey)\n return h.redirect(session.returnUrl).code(StatusCodes.SEE_OTHER)\n}\n\n/**\n * Handles failed/cancelled/error payment states\n * @param {Request} request - the request\n * @param {ResponseToolkit} h - the response toolkit\n * @param {PaymentSessionData} session - the session data\n * @param {string} sessionKey - the session key\n */\nfunction handlePaymentFailure(request, h, session, sessionKey) {\n request.yar.clear(sessionKey)\n return h.redirect(session.failureUrl).code(StatusCodes.SEE_OTHER)\n}\n\n/**\n * Route handler for payment return URL\n * This is called when GOV.UK Pay redirects the user back after payment\n * @returns {ServerRoute}\n */\nfunction getReturnRoute() {\n return {\n method: 'GET',\n path: PAYMENT_RETURN_PATH,\n async handler(request, h) {\n const { uuid } = /** @type {{ uuid: string }} */ (request.query)\n const { session, sessionKey, paymentStatus } = await getPaymentContext(\n request,\n uuid\n )\n\n /**\n * @see https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle\n */\n const { status } = paymentStatus.state\n\n switch (status) {\n case 'capturable':\n case 'success':\n return handlePaymentSuccess(\n request,\n h,\n session,\n sessionKey,\n paymentStatus\n )\n\n case 'cancelled':\n case 'failed':\n case 'error':\n return handlePaymentFailure(request, h, session, sessionKey)\n\n case 'created':\n case 'started':\n case 'submitted': {\n const nextUrl = paymentStatus._links.next_url?.href\n\n if (!nextUrl) {\n throw Boom.badRequest(\n `Payment in state '${status}' but no next_url available`\n )\n }\n\n return h.redirect(nextUrl).code(StatusCodes.SEE_OTHER)\n }\n\n default: {\n const unknownStatus = /** @type {string} */ (status)\n throw Boom.internal(`Unknown payment status: ${unknownStatus}`)\n }\n }\n },\n options: {\n validate: {\n query: Joi.object()\n .keys({\n uuid: Joi.string().uuid().required()\n })\n .required()\n }\n }\n }\n}\n\n/**\n * @import { Request, ResponseToolkit, ServerRoute } from '@hapi/hapi'\n * @import { GetPaymentResponse, PaymentSessionData } from '~/src/server/plugins/payment/types.js'\n * @import { PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\n * @import { ExternalStateAppendage, FormState } from '~/src/server/plugins/engine/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { StatusCodes } from 'http-status-codes';
|
|
2
|
+
import { createServer } from "../../../index.js";
|
|
3
|
+
import { getPaymentContext } from "./payment-helper.js";
|
|
4
|
+
import { renderResponse } from "../../../../../test/helpers/component-helpers.js";
|
|
5
|
+
jest.mock("./payment-helper.js");
|
|
6
|
+
describe('Payment routes', () => {
|
|
7
|
+
/** @type {Server} */
|
|
8
|
+
let server;
|
|
9
|
+
beforeAll(async () => {
|
|
10
|
+
server = await createServer();
|
|
11
|
+
await server.initialize();
|
|
12
|
+
});
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
jest.resetAllMocks();
|
|
15
|
+
});
|
|
16
|
+
describe('Return route /payment-callback', () => {
|
|
17
|
+
const uuid = '06a5b11e-e3e0-48a2-8ac3-56c0fcb6c20d';
|
|
18
|
+
const options = {
|
|
19
|
+
method: 'get',
|
|
20
|
+
url: `/payment-callback?uuid=${uuid}`
|
|
21
|
+
};
|
|
22
|
+
const paymentSessionData = {
|
|
23
|
+
uuid,
|
|
24
|
+
formId: 'form-id',
|
|
25
|
+
reference: 'form-ref-123',
|
|
26
|
+
paymentId: 'payment-id',
|
|
27
|
+
amount: 123,
|
|
28
|
+
description: 'Payment desc',
|
|
29
|
+
isLivePayment: false,
|
|
30
|
+
componentName: 'my-component',
|
|
31
|
+
returnUrl: 'http://host.com/return-url',
|
|
32
|
+
failureUrl: 'http://host.com/failure-url'
|
|
33
|
+
};
|
|
34
|
+
const sessionKey = 'session-key';
|
|
35
|
+
test.each([{
|
|
36
|
+
status: 'capturable',
|
|
37
|
+
finalUrl: 'http://host.com/return-url'
|
|
38
|
+
}, {
|
|
39
|
+
status: 'success',
|
|
40
|
+
finalUrl: 'http://host.com/return-url'
|
|
41
|
+
}, {
|
|
42
|
+
status: 'cancelled',
|
|
43
|
+
finalUrl: 'http://host.com/failure-url'
|
|
44
|
+
}, {
|
|
45
|
+
status: 'failed',
|
|
46
|
+
finalUrl: 'http://host.com/failure-url'
|
|
47
|
+
}, {
|
|
48
|
+
status: 'error',
|
|
49
|
+
finalUrl: 'http://host.com/failure-url'
|
|
50
|
+
}, {
|
|
51
|
+
status: 'created',
|
|
52
|
+
finalUrl: '/next-url'
|
|
53
|
+
}, {
|
|
54
|
+
status: 'started',
|
|
55
|
+
finalUrl: '/next-url'
|
|
56
|
+
}, {
|
|
57
|
+
status: 'submitted',
|
|
58
|
+
finalUrl: '/next-url'
|
|
59
|
+
}])('should handle payment status of $row.status', async row => {
|
|
60
|
+
const paymentStatus = {
|
|
61
|
+
paymentId: 'new-payment-id',
|
|
62
|
+
amount: 125,
|
|
63
|
+
_links: {
|
|
64
|
+
next_url: {
|
|
65
|
+
href: '/next-url',
|
|
66
|
+
method: 'get'
|
|
67
|
+
},
|
|
68
|
+
self: {
|
|
69
|
+
href: '/self',
|
|
70
|
+
method: 'get'
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
state: (/** @type {PaymentResponseState} */{
|
|
74
|
+
status: row.status,
|
|
75
|
+
finished: true
|
|
76
|
+
})
|
|
77
|
+
};
|
|
78
|
+
jest.mocked(getPaymentContext).mockResolvedValueOnce({
|
|
79
|
+
session: paymentSessionData,
|
|
80
|
+
sessionKey,
|
|
81
|
+
paymentStatus
|
|
82
|
+
});
|
|
83
|
+
const {
|
|
84
|
+
response
|
|
85
|
+
} = await renderResponse(server, options);
|
|
86
|
+
expect(response.statusCode).toBe(StatusCodes.SEE_OTHER);
|
|
87
|
+
expect(response.headers.location).toBe(row.finalUrl);
|
|
88
|
+
});
|
|
89
|
+
it('should throw if nextUrl is missing', async () => {
|
|
90
|
+
const paymentStatus = {
|
|
91
|
+
paymentId: 'new-payment-id',
|
|
92
|
+
_links: {
|
|
93
|
+
next_url: {},
|
|
94
|
+
self: {
|
|
95
|
+
href: '/self',
|
|
96
|
+
method: 'get'
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
state: (/** @type {PaymentResponseState} */{
|
|
100
|
+
status: 'created',
|
|
101
|
+
finished: true
|
|
102
|
+
})
|
|
103
|
+
};
|
|
104
|
+
jest.mocked(getPaymentContext).mockResolvedValueOnce({
|
|
105
|
+
session: paymentSessionData,
|
|
106
|
+
sessionKey,
|
|
107
|
+
// @ts-expect-error - deliberate missing element from object
|
|
108
|
+
paymentStatus
|
|
109
|
+
});
|
|
110
|
+
const {
|
|
111
|
+
response
|
|
112
|
+
} = await renderResponse(server, options);
|
|
113
|
+
expect(response.statusCode).toBe(StatusCodes.BAD_REQUEST);
|
|
114
|
+
// @ts-expect-error - error object
|
|
115
|
+
expect(response.result?.message).toBe("Payment in state 'created' but no next_url available");
|
|
116
|
+
});
|
|
117
|
+
it('should throw if invalid status', async () => {
|
|
118
|
+
const paymentStatus = {
|
|
119
|
+
paymentId: 'new-payment-id',
|
|
120
|
+
_links: {
|
|
121
|
+
next_url: {
|
|
122
|
+
href: '/next-url',
|
|
123
|
+
method: 'get'
|
|
124
|
+
},
|
|
125
|
+
self: {
|
|
126
|
+
href: '/self',
|
|
127
|
+
method: 'get'
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
state: {
|
|
131
|
+
status: 'invalid',
|
|
132
|
+
finished: true
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
jest.mocked(getPaymentContext).mockResolvedValueOnce({
|
|
136
|
+
session: paymentSessionData,
|
|
137
|
+
sessionKey,
|
|
138
|
+
// @ts-expect-error - deliberate invalid value which doesnt meet type
|
|
139
|
+
paymentStatus
|
|
140
|
+
});
|
|
141
|
+
const {
|
|
142
|
+
response
|
|
143
|
+
} = await renderResponse(server, options);
|
|
144
|
+
expect(response.statusCode).toBe(StatusCodes.INTERNAL_SERVER_ERROR);
|
|
145
|
+
// @ts-expect-error - error object
|
|
146
|
+
expect(response.result?.message).toBe('Unknown payment status: invalid');
|
|
147
|
+
});
|
|
148
|
+
it('should handle payment with email from GOV.UK Pay response', async () => {
|
|
149
|
+
const paymentStatus = {
|
|
150
|
+
paymentId: 'new-payment-id',
|
|
151
|
+
payment_id: 'new-payment-id',
|
|
152
|
+
amount: 125,
|
|
153
|
+
email: 'payer@example.com',
|
|
154
|
+
_links: {
|
|
155
|
+
next_url: {
|
|
156
|
+
href: '/next-url',
|
|
157
|
+
method: 'get'
|
|
158
|
+
},
|
|
159
|
+
self: {
|
|
160
|
+
href: '/self',
|
|
161
|
+
method: 'get'
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
state: (/** @type {PaymentResponseState} */{
|
|
165
|
+
status: 'success',
|
|
166
|
+
finished: true
|
|
167
|
+
})
|
|
168
|
+
};
|
|
169
|
+
jest.mocked(getPaymentContext).mockResolvedValueOnce({
|
|
170
|
+
session: paymentSessionData,
|
|
171
|
+
sessionKey,
|
|
172
|
+
paymentStatus
|
|
173
|
+
});
|
|
174
|
+
const {
|
|
175
|
+
response
|
|
176
|
+
} = await renderResponse(server, options);
|
|
177
|
+
expect(response.statusCode).toBe(StatusCodes.SEE_OTHER);
|
|
178
|
+
expect(response.headers.location).toBe('http://host.com/return-url');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* @import { Server } from '@hapi/hapi'
|
|
185
|
+
* @import { PaymentResponseState } from '~/src/server/plugins/payment/types.js'
|
|
186
|
+
*/
|
|
187
|
+
//# sourceMappingURL=payment.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"payment.test.js","names":["StatusCodes","createServer","getPaymentContext","renderResponse","jest","mock","describe","server","beforeAll","initialize","beforeEach","resetAllMocks","uuid","options","method","url","paymentSessionData","formId","reference","paymentId","amount","description","isLivePayment","componentName","returnUrl","failureUrl","sessionKey","test","each","status","finalUrl","row","paymentStatus","_links","next_url","href","self","state","finished","mocked","mockResolvedValueOnce","session","response","expect","statusCode","toBe","SEE_OTHER","headers","location","it","BAD_REQUEST","result","message","INTERNAL_SERVER_ERROR","payment_id","email"],"sources":["../../../../../src/server/plugins/engine/routes/payment.test.js"],"sourcesContent":["import { StatusCodes } from 'http-status-codes'\n\nimport { createServer } from '~/src/server/index.js'\nimport { getPaymentContext } from '~/src/server/plugins/engine/routes/payment-helper.js'\nimport { renderResponse } from '~/test/helpers/component-helpers.js'\n\njest.mock('~/src/server/plugins/engine/routes/payment-helper.js')\n\ndescribe('Payment routes', () => {\n /** @type {Server} */\n let server\n\n beforeAll(async () => {\n server = await createServer()\n await server.initialize()\n })\n\n beforeEach(() => {\n jest.resetAllMocks()\n })\n\n describe('Return route /payment-callback', () => {\n const uuid = '06a5b11e-e3e0-48a2-8ac3-56c0fcb6c20d'\n const options = {\n method: 'get',\n url: `/payment-callback?uuid=${uuid}`\n }\n\n const paymentSessionData = {\n uuid,\n formId: 'form-id',\n reference: 'form-ref-123',\n paymentId: 'payment-id',\n amount: 123,\n description: 'Payment desc',\n isLivePayment: false,\n componentName: 'my-component',\n returnUrl: 'http://host.com/return-url',\n failureUrl: 'http://host.com/failure-url'\n }\n const sessionKey = 'session-key'\n\n test.each([\n { status: 'capturable', finalUrl: 'http://host.com/return-url' },\n { status: 'success', finalUrl: 'http://host.com/return-url' },\n { status: 'cancelled', finalUrl: 'http://host.com/failure-url' },\n { status: 'failed', finalUrl: 'http://host.com/failure-url' },\n { status: 'error', finalUrl: 'http://host.com/failure-url' },\n { status: 'created', finalUrl: '/next-url' },\n { status: 'started', finalUrl: '/next-url' },\n { status: 'submitted', finalUrl: '/next-url' }\n ])('should handle payment status of $row.status', async (row) => {\n const paymentStatus = {\n paymentId: 'new-payment-id',\n amount: 125,\n _links: {\n next_url: {\n href: '/next-url',\n method: 'get'\n },\n self: {\n href: '/self',\n method: 'get'\n }\n },\n state: /** @type {PaymentResponseState} */ ({\n status: row.status,\n finished: true\n })\n }\n jest.mocked(getPaymentContext).mockResolvedValueOnce({\n session: paymentSessionData,\n sessionKey,\n paymentStatus\n })\n const { response } = await renderResponse(server, options)\n\n expect(response.statusCode).toBe(StatusCodes.SEE_OTHER)\n expect(response.headers.location).toBe(row.finalUrl)\n })\n\n it('should throw if nextUrl is missing', async () => {\n const paymentStatus = {\n paymentId: 'new-payment-id',\n _links: {\n next_url: {},\n self: {\n href: '/self',\n method: 'get'\n }\n },\n state: /** @type {PaymentResponseState} */ ({\n status: 'created',\n finished: true\n })\n }\n jest.mocked(getPaymentContext).mockResolvedValueOnce({\n session: paymentSessionData,\n sessionKey,\n // @ts-expect-error - deliberate missing element from object\n paymentStatus\n })\n const { response } = await renderResponse(server, options)\n\n expect(response.statusCode).toBe(StatusCodes.BAD_REQUEST)\n // @ts-expect-error - error object\n expect(response.result?.message).toBe(\n \"Payment in state 'created' but no next_url available\"\n )\n })\n\n it('should throw if invalid status', async () => {\n const paymentStatus = {\n paymentId: 'new-payment-id',\n _links: {\n next_url: {\n href: '/next-url',\n method: 'get'\n },\n self: {\n href: '/self',\n method: 'get'\n }\n },\n state: {\n status: 'invalid',\n finished: true\n }\n }\n jest.mocked(getPaymentContext).mockResolvedValueOnce({\n session: paymentSessionData,\n sessionKey,\n // @ts-expect-error - deliberate invalid value which doesnt meet type\n paymentStatus\n })\n const { response } = await renderResponse(server, options)\n\n expect(response.statusCode).toBe(StatusCodes.INTERNAL_SERVER_ERROR)\n // @ts-expect-error - error object\n expect(response.result?.message).toBe('Unknown payment status: invalid')\n })\n\n it('should handle payment with email from GOV.UK Pay response', async () => {\n const paymentStatus = {\n paymentId: 'new-payment-id',\n payment_id: 'new-payment-id',\n amount: 125,\n email: 'payer@example.com',\n _links: {\n next_url: {\n href: '/next-url',\n method: 'get'\n },\n self: {\n href: '/self',\n method: 'get'\n }\n },\n state: /** @type {PaymentResponseState} */ ({\n status: 'success',\n finished: true\n })\n }\n jest.mocked(getPaymentContext).mockResolvedValueOnce({\n session: paymentSessionData,\n sessionKey,\n paymentStatus\n })\n const { response } = await renderResponse(server, options)\n\n expect(response.statusCode).toBe(StatusCodes.SEE_OTHER)\n expect(response.headers.location).toBe('http://host.com/return-url')\n })\n })\n})\n\n/**\n * @import { Server } from '@hapi/hapi'\n * @import { PaymentResponseState } from '~/src/server/plugins/payment/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -57,6 +57,12 @@ export const formsService = async () => {
|
|
|
57
57
|
title: 'Simple Form',
|
|
58
58
|
slug: 'simple-form'
|
|
59
59
|
});
|
|
60
|
+
await loader.addForm('src/server/forms/payment-test.yaml', {
|
|
61
|
+
...metadata,
|
|
62
|
+
id: 'b2c3d4e5-f6a7-8901-bcde-f01234567890',
|
|
63
|
+
title: 'Payment Test Form',
|
|
64
|
+
slug: 'payment-test'
|
|
65
|
+
});
|
|
60
66
|
return loader.toFormsService();
|
|
61
67
|
};
|
|
62
68
|
//# sourceMappingURL=localFormsService.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"localFormsService.js","names":["config","FileFormService","now","Date","user","id","displayName","author","createdAt","createdBy","updatedAt","updatedBy","metadata","organisation","teamName","teamEmail","submissionGuidance","notificationEmail","get","live","formsService","loader","addForm","title","slug","toFormsService"],"sources":["../../../../../src/server/plugins/engine/services/localFormsService.js"],"sourcesContent":["import { config } from '~/src/config/index.js'\nimport { FileFormService } from '~/src/server/utils/file-form-service.js'\n\n// Create shared form metadata\nconst now = new Date()\nconst user = { id: 'user', displayName: 'Username' }\nconst author = {\n createdAt: now,\n createdBy: user,\n updatedAt: now,\n updatedBy: user\n}\nconst metadata = {\n organisation: 'Defra',\n teamName: 'Team name',\n teamEmail: 'team@defra.gov.uk',\n submissionGuidance: \"Thanks for your submission, we'll be in touch\",\n notificationEmail: config.get('submissionEmailAddress'),\n ...author,\n live: author\n}\n\n/**\n * Return an function rather than the service directly. This is to prevent consumer applications\n * blowing up as they won't have these files on disk. We can defer the execution until when it's\n * needed, i.e. the createServer function of the devtool.\n */\nexport const formsService = async () => {\n // Instantiate the file loader form service\n const loader = new FileFormService()\n\n // Add a Yaml form\n await loader.addForm('src/server/forms/register-as-a-unicorn-breeder.yaml', {\n ...metadata,\n id: '641aeafd-13dd-40fa-9186-001703800efb',\n title: 'Register as a unicorn breeder',\n slug: 'register-as-a-unicorn-breeder'\n })\n\n await loader.addForm('src/server/forms/page-events.yaml', {\n ...metadata,\n id: '511db05e-ebbd-42e8-8270-5fe93f5c9762',\n title: 'Page events demo',\n slug: 'page-events-demo'\n })\n\n await loader.addForm('src/server/forms/components.json', {\n ...metadata,\n id: '6a872d3b-13f9e-804ce3e-4830-5c45fb32',\n title: 'Components',\n slug: 'components'\n })\n\n await loader.addForm('src/server/forms/simple-form.yaml', {\n ...metadata,\n id: 'a1b2c3d4-e5f6-7890-abcd-ef0123456789',\n title: 'Simple Form',\n slug: 'simple-form'\n })\n\n return loader.toFormsService()\n}\n"],"mappings":"AAAA,SAASA,MAAM;AACf,SAASC,eAAe;;AAExB;AACA,MAAMC,GAAG,GAAG,IAAIC,IAAI,CAAC,CAAC;AACtB,MAAMC,IAAI,GAAG;EAAEC,EAAE,EAAE,MAAM;EAAEC,WAAW,EAAE;AAAW,CAAC;AACpD,MAAMC,MAAM,GAAG;EACbC,SAAS,EAAEN,GAAG;EACdO,SAAS,EAAEL,IAAI;EACfM,SAAS,EAAER,GAAG;EACdS,SAAS,EAAEP;AACb,CAAC;AACD,MAAMQ,QAAQ,GAAG;EACfC,YAAY,EAAE,OAAO;EACrBC,QAAQ,EAAE,WAAW;EACrBC,SAAS,EAAE,mBAAmB;EAC9BC,kBAAkB,EAAE,+CAA+C;EACnEC,iBAAiB,EAAEjB,MAAM,CAACkB,GAAG,CAAC,wBAAwB,CAAC;EACvD,GAAGX,MAAM;EACTY,IAAI,EAAEZ;AACR,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMa,YAAY,GAAG,MAAAA,CAAA,KAAY;EACtC;EACA,MAAMC,MAAM,GAAG,IAAIpB,eAAe,CAAC,CAAC;;EAEpC;EACA,MAAMoB,MAAM,CAACC,OAAO,CAAC,qDAAqD,EAAE;IAC1E,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,+BAA+B;IACtCC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,mCAAmC,EAAE;IACxD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,kBAAkB;IACzBC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,kCAAkC,EAAE;IACvD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,YAAY;IACnBC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,mCAAmC,EAAE;IACxD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,aAAa;IACpBC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,OAAOH,MAAM,CAACI,cAAc,CAAC,CAAC;AAChC,CAAC","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"localFormsService.js","names":["config","FileFormService","now","Date","user","id","displayName","author","createdAt","createdBy","updatedAt","updatedBy","metadata","organisation","teamName","teamEmail","submissionGuidance","notificationEmail","get","live","formsService","loader","addForm","title","slug","toFormsService"],"sources":["../../../../../src/server/plugins/engine/services/localFormsService.js"],"sourcesContent":["import { config } from '~/src/config/index.js'\nimport { FileFormService } from '~/src/server/utils/file-form-service.js'\n\n// Create shared form metadata\nconst now = new Date()\nconst user = { id: 'user', displayName: 'Username' }\nconst author = {\n createdAt: now,\n createdBy: user,\n updatedAt: now,\n updatedBy: user\n}\nconst metadata = {\n organisation: 'Defra',\n teamName: 'Team name',\n teamEmail: 'team@defra.gov.uk',\n submissionGuidance: \"Thanks for your submission, we'll be in touch\",\n notificationEmail: config.get('submissionEmailAddress'),\n ...author,\n live: author\n}\n\n/**\n * Return an function rather than the service directly. This is to prevent consumer applications\n * blowing up as they won't have these files on disk. We can defer the execution until when it's\n * needed, i.e. the createServer function of the devtool.\n */\nexport const formsService = async () => {\n // Instantiate the file loader form service\n const loader = new FileFormService()\n\n // Add a Yaml form\n await loader.addForm('src/server/forms/register-as-a-unicorn-breeder.yaml', {\n ...metadata,\n id: '641aeafd-13dd-40fa-9186-001703800efb',\n title: 'Register as a unicorn breeder',\n slug: 'register-as-a-unicorn-breeder'\n })\n\n await loader.addForm('src/server/forms/page-events.yaml', {\n ...metadata,\n id: '511db05e-ebbd-42e8-8270-5fe93f5c9762',\n title: 'Page events demo',\n slug: 'page-events-demo'\n })\n\n await loader.addForm('src/server/forms/components.json', {\n ...metadata,\n id: '6a872d3b-13f9e-804ce3e-4830-5c45fb32',\n title: 'Components',\n slug: 'components'\n })\n\n await loader.addForm('src/server/forms/simple-form.yaml', {\n ...metadata,\n id: 'a1b2c3d4-e5f6-7890-abcd-ef0123456789',\n title: 'Simple Form',\n slug: 'simple-form'\n })\n\n await loader.addForm('src/server/forms/payment-test.yaml', {\n ...metadata,\n id: 'b2c3d4e5-f6a7-8901-bcde-f01234567890',\n title: 'Payment Test Form',\n slug: 'payment-test'\n })\n\n return loader.toFormsService()\n}\n"],"mappings":"AAAA,SAASA,MAAM;AACf,SAASC,eAAe;;AAExB;AACA,MAAMC,GAAG,GAAG,IAAIC,IAAI,CAAC,CAAC;AACtB,MAAMC,IAAI,GAAG;EAAEC,EAAE,EAAE,MAAM;EAAEC,WAAW,EAAE;AAAW,CAAC;AACpD,MAAMC,MAAM,GAAG;EACbC,SAAS,EAAEN,GAAG;EACdO,SAAS,EAAEL,IAAI;EACfM,SAAS,EAAER,GAAG;EACdS,SAAS,EAAEP;AACb,CAAC;AACD,MAAMQ,QAAQ,GAAG;EACfC,YAAY,EAAE,OAAO;EACrBC,QAAQ,EAAE,WAAW;EACrBC,SAAS,EAAE,mBAAmB;EAC9BC,kBAAkB,EAAE,+CAA+C;EACnEC,iBAAiB,EAAEjB,MAAM,CAACkB,GAAG,CAAC,wBAAwB,CAAC;EACvD,GAAGX,MAAM;EACTY,IAAI,EAAEZ;AACR,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMa,YAAY,GAAG,MAAAA,CAAA,KAAY;EACtC;EACA,MAAMC,MAAM,GAAG,IAAIpB,eAAe,CAAC,CAAC;;EAEpC;EACA,MAAMoB,MAAM,CAACC,OAAO,CAAC,qDAAqD,EAAE;IAC1E,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,+BAA+B;IACtCC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,mCAAmC,EAAE;IACxD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,kBAAkB;IACzBC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,kCAAkC,EAAE;IACvD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,YAAY;IACnBC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,mCAAmC,EAAE;IACxD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,aAAa;IACpBC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,MAAMH,MAAM,CAACC,OAAO,CAAC,oCAAoC,EAAE;IACzD,GAAGV,QAAQ;IACXP,EAAE,EAAE,sCAAsC;IAC1CkB,KAAK,EAAE,mBAAmB;IAC1BC,IAAI,EAAE;EACR,CAAC,CAAC;EAEF,OAAOH,MAAM,CAACI,cAAc,CAAC,CAAC;AAChC,CAAC","ignoreList":[]}
|
|
@@ -17,6 +17,13 @@ export const formAdapterSubmissionMessageMetaSchema = Joi.object().keys({
|
|
|
17
17
|
export const formAdapterSubmissionMessageDataSchema = Joi.object().keys({
|
|
18
18
|
main: Joi.object(),
|
|
19
19
|
repeaters: Joi.object(),
|
|
20
|
+
payment: Joi.object().keys({
|
|
21
|
+
paymentId: Joi.string().required(),
|
|
22
|
+
reference: Joi.string().required(),
|
|
23
|
+
amount: Joi.number().required(),
|
|
24
|
+
description: Joi.string().required(),
|
|
25
|
+
createdAt: Joi.string().required()
|
|
26
|
+
}).optional(),
|
|
20
27
|
files: Joi.object().pattern(Joi.string(), Joi.array().items(Joi.object().keys({
|
|
21
28
|
fileName: Joi.string().required(),
|
|
22
29
|
fileId: Joi.string().required(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","names":["FormStatus","formVersionMetadataSchema","idSchema","notificationEmailAddressSchema","slugSchema","titleSchema","Joi","FormAdapterSubmissionSchemaVersion","formAdapterSubmissionMessageMetaSchema","object","keys","schemaVersion","string","valid","Object","values","timestamp","date","required","referenceNumber","formName","formId","formSlug","status","isPreview","boolean","notificationEmail","versionMetadata","optional","custom","pattern","any","unknown","description","formAdapterSubmissionMessageDataSchema","main","repeaters","files","array","items","fileName","fileId","userDownloadLink","formAdapterSubmissionMessageResultSchema","formAdapterSubmissionMessagePayloadSchema","meta","data","result"],"sources":["../../../../../src/server/plugins/engine/types/schema.ts"],"sourcesContent":["import {\n FormStatus,\n formVersionMetadataSchema,\n idSchema,\n notificationEmailAddressSchema,\n slugSchema,\n titleSchema\n} from '@defra/forms-model'\nimport Joi from 'joi'\n\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult\n} from '~/src/server/plugins/engine/types.js'\n\nexport const formAdapterSubmissionMessageMetaSchema =\n Joi.object<FormAdapterSubmissionMessageMeta>().keys({\n schemaVersion: Joi.string().valid(\n ...Object.values(FormAdapterSubmissionSchemaVersion)\n ),\n timestamp: Joi.date().required(),\n referenceNumber: Joi.string().required(),\n formName: titleSchema,\n formId: idSchema,\n formSlug: slugSchema,\n status: Joi.string()\n .valid(...Object.values(FormStatus))\n .required(),\n isPreview: Joi.boolean().required(),\n notificationEmail: notificationEmailAddressSchema.required(),\n versionMetadata: formVersionMetadataSchema.optional(),\n custom: Joi.object()\n .pattern(/^/, Joi.any())\n .unknown()\n .optional()\n .description('Custom properties for the message')\n })\n\nexport const formAdapterSubmissionMessageDataSchema =\n Joi.object<FormAdapterSubmissionMessageData>().keys({\n main: Joi.object(),\n repeaters: Joi.object(),\n files: Joi.object().pattern(\n Joi.string(),\n Joi.array().items(\n Joi.object().keys({\n fileName: Joi.string().required(),\n fileId: Joi.string().required(),\n userDownloadLink: Joi.string().required()\n })\n )\n )\n })\n\nexport const formAdapterSubmissionMessageResultSchema =\n Joi.object<FormAdapterSubmissionMessageResult>().keys({\n files: Joi.object()\n .keys({\n main: Joi.string().required(),\n repeaters: Joi.object()\n })\n .required()\n })\n\nexport const formAdapterSubmissionMessagePayloadSchema =\n Joi.object<FormAdapterSubmissionMessagePayload>().keys({\n meta: formAdapterSubmissionMessageMetaSchema.required(),\n data: formAdapterSubmissionMessageDataSchema.required(),\n result: formAdapterSubmissionMessageResultSchema.required()\n })\n"],"mappings":"AAAA,SACEA,UAAU,EACVC,yBAAyB,EACzBC,QAAQ,EACRC,8BAA8B,EAC9BC,UAAU,EACVC,WAAW,QACN,oBAAoB;AAC3B,OAAOC,GAAG,MAAM,KAAK;AAErB,SAASC,kCAAkC;AAQ3C,OAAO,MAAMC,sCAAsC,GACjDF,GAAG,CAACG,MAAM,CAAmC,CAAC,CAACC,IAAI,CAAC;EAClDC,aAAa,EAAEL,GAAG,CAACM,MAAM,CAAC,CAAC,CAACC,KAAK,CAC/B,GAAGC,MAAM,CAACC,MAAM,CAACR,kCAAkC,CACrD,CAAC;EACDS,SAAS,EAAEV,GAAG,CAACW,IAAI,CAAC,CAAC,CAACC,QAAQ,CAAC,CAAC;EAChCC,eAAe,EAAEb,GAAG,CAACM,MAAM,CAAC,CAAC,CAACM,QAAQ,CAAC,CAAC;EACxCE,QAAQ,EAAEf,WAAW;EACrBgB,MAAM,EAAEnB,QAAQ;EAChBoB,QAAQ,EAAElB,UAAU;EACpBmB,MAAM,EAAEjB,GAAG,CAACM,MAAM,CAAC,CAAC,CACjBC,KAAK,CAAC,GAAGC,MAAM,CAACC,MAAM,CAACf,UAAU,CAAC,CAAC,CACnCkB,QAAQ,CAAC,CAAC;EACbM,SAAS,EAAElB,GAAG,CAACmB,OAAO,CAAC,CAAC,CAACP,QAAQ,CAAC,CAAC;EACnCQ,iBAAiB,EAAEvB,8BAA8B,CAACe,QAAQ,CAAC,CAAC;EAC5DS,eAAe,EAAE1B,yBAAyB,CAAC2B,QAAQ,CAAC,CAAC;EACrDC,MAAM,EAAEvB,GAAG,CAACG,MAAM,CAAC,CAAC,CACjBqB,OAAO,CAAC,GAAG,EAAExB,GAAG,CAACyB,GAAG,CAAC,CAAC,CAAC,CACvBC,OAAO,CAAC,CAAC,CACTJ,QAAQ,CAAC,CAAC,CACVK,WAAW,CAAC,mCAAmC;AACpD,CAAC,CAAC;AAEJ,OAAO,MAAMC,sCAAsC,GACjD5B,GAAG,CAACG,MAAM,CAAmC,CAAC,CAACC,IAAI,CAAC;EAClDyB,IAAI,EAAE7B,GAAG,CAACG,MAAM,CAAC,CAAC;EAClB2B,SAAS,EAAE9B,GAAG,CAACG,MAAM,CAAC,CAAC;EACvB4B,
|
|
1
|
+
{"version":3,"file":"schema.js","names":["FormStatus","formVersionMetadataSchema","idSchema","notificationEmailAddressSchema","slugSchema","titleSchema","Joi","FormAdapterSubmissionSchemaVersion","formAdapterSubmissionMessageMetaSchema","object","keys","schemaVersion","string","valid","Object","values","timestamp","date","required","referenceNumber","formName","formId","formSlug","status","isPreview","boolean","notificationEmail","versionMetadata","optional","custom","pattern","any","unknown","description","formAdapterSubmissionMessageDataSchema","main","repeaters","payment","paymentId","reference","amount","number","createdAt","files","array","items","fileName","fileId","userDownloadLink","formAdapterSubmissionMessageResultSchema","formAdapterSubmissionMessagePayloadSchema","meta","data","result"],"sources":["../../../../../src/server/plugins/engine/types/schema.ts"],"sourcesContent":["import {\n FormStatus,\n formVersionMetadataSchema,\n idSchema,\n notificationEmailAddressSchema,\n slugSchema,\n titleSchema\n} from '@defra/forms-model'\nimport Joi from 'joi'\n\nimport { FormAdapterSubmissionSchemaVersion } from '~/src/server/plugins/engine/types/enums.js'\nimport {\n type FormAdapterSubmissionMessageData,\n type FormAdapterSubmissionMessageMeta,\n type FormAdapterSubmissionMessagePayload,\n type FormAdapterSubmissionMessageResult\n} from '~/src/server/plugins/engine/types.js'\n\nexport const formAdapterSubmissionMessageMetaSchema =\n Joi.object<FormAdapterSubmissionMessageMeta>().keys({\n schemaVersion: Joi.string().valid(\n ...Object.values(FormAdapterSubmissionSchemaVersion)\n ),\n timestamp: Joi.date().required(),\n referenceNumber: Joi.string().required(),\n formName: titleSchema,\n formId: idSchema,\n formSlug: slugSchema,\n status: Joi.string()\n .valid(...Object.values(FormStatus))\n .required(),\n isPreview: Joi.boolean().required(),\n notificationEmail: notificationEmailAddressSchema.required(),\n versionMetadata: formVersionMetadataSchema.optional(),\n custom: Joi.object()\n .pattern(/^/, Joi.any())\n .unknown()\n .optional()\n .description('Custom properties for the message')\n })\n\nexport const formAdapterSubmissionMessageDataSchema =\n Joi.object<FormAdapterSubmissionMessageData>().keys({\n main: Joi.object(),\n repeaters: Joi.object(),\n payment: Joi.object()\n .keys({\n paymentId: Joi.string().required(),\n reference: Joi.string().required(),\n amount: Joi.number().required(),\n description: Joi.string().required(),\n createdAt: Joi.string().required()\n })\n .optional(),\n files: Joi.object().pattern(\n Joi.string(),\n Joi.array().items(\n Joi.object().keys({\n fileName: Joi.string().required(),\n fileId: Joi.string().required(),\n userDownloadLink: Joi.string().required()\n })\n )\n )\n })\n\nexport const formAdapterSubmissionMessageResultSchema =\n Joi.object<FormAdapterSubmissionMessageResult>().keys({\n files: Joi.object()\n .keys({\n main: Joi.string().required(),\n repeaters: Joi.object()\n })\n .required()\n })\n\nexport const formAdapterSubmissionMessagePayloadSchema =\n Joi.object<FormAdapterSubmissionMessagePayload>().keys({\n meta: formAdapterSubmissionMessageMetaSchema.required(),\n data: formAdapterSubmissionMessageDataSchema.required(),\n result: formAdapterSubmissionMessageResultSchema.required()\n })\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,7 +3,7 @@ import { type PluginProperties, type Request, type ResponseObject } from '@hapi/
|
|
|
3
3
|
import { type JoiExpression, type ValidationErrorItem } from 'joi';
|
|
4
4
|
import { type UkAddressState } from '~/src/server/plugins/engine/components/UkAddressField.js';
|
|
5
5
|
import { type Component } from '~/src/server/plugins/engine/components/helpers/components.js';
|
|
6
|
-
import { type FileUploadField } from '~/src/server/plugins/engine/components/index.js';
|
|
6
|
+
import { type FileUploadField, type PaymentField } from '~/src/server/plugins/engine/components/index.js';
|
|
7
7
|
import { type BackLink, type ComponentText, type ComponentViewModel, type DatePartsState, type EastingNorthingState, type LatLongState, type MonthYearState } from '~/src/server/plugins/engine/components/types.js';
|
|
8
8
|
import { type FormModel } from '~/src/server/plugins/engine/models/index.js';
|
|
9
9
|
import { type DetailItemField } from '~/src/server/plugins/engine/models/types.js';
|
|
@@ -240,6 +240,8 @@ export interface FormPageViewModel extends PageViewModelBase {
|
|
|
240
240
|
errors?: FormSubmissionError[];
|
|
241
241
|
hasMissingNotificationEmail?: boolean;
|
|
242
242
|
allowSaveAndExit: boolean;
|
|
243
|
+
showSubmitButton?: boolean;
|
|
244
|
+
showPaymentExpiredNotification?: boolean;
|
|
243
245
|
}
|
|
244
246
|
export interface RepeaterSummaryPageViewModel extends PageViewModelBase {
|
|
245
247
|
context: FormContext;
|
|
@@ -274,6 +276,8 @@ export interface ExternalArgs {
|
|
|
274
276
|
controller: QuestionPageController;
|
|
275
277
|
sourceUrl: string;
|
|
276
278
|
actionArgs: Record<string, string>;
|
|
279
|
+
isLive: boolean;
|
|
280
|
+
isPreview: boolean;
|
|
277
281
|
}
|
|
278
282
|
export interface PostcodeLookupExternalArgs extends ExternalArgs {
|
|
279
283
|
component: UkAddressFieldComponent;
|
|
@@ -303,6 +307,7 @@ export interface PluginOptions {
|
|
|
303
307
|
onRequest?: OnRequestCallback;
|
|
304
308
|
baseUrl: string;
|
|
305
309
|
ordnanceSurveyApiKey?: string;
|
|
310
|
+
ordnanceSurveyApiSecret?: string;
|
|
306
311
|
}
|
|
307
312
|
export interface FormAdapterSubmissionMessageMeta {
|
|
308
313
|
schemaVersion: FormAdapterSubmissionSchemaVersion;
|
|
@@ -327,6 +332,13 @@ export interface FormAdapterFile {
|
|
|
327
332
|
fileId: string;
|
|
328
333
|
userDownloadLink: string;
|
|
329
334
|
}
|
|
335
|
+
export interface FormAdapterPayment {
|
|
336
|
+
paymentId: string;
|
|
337
|
+
reference: string;
|
|
338
|
+
amount: number;
|
|
339
|
+
description: string;
|
|
340
|
+
createdAt: string;
|
|
341
|
+
}
|
|
330
342
|
export interface FormAdapterSubmissionMessageResult {
|
|
331
343
|
files: {
|
|
332
344
|
main: string;
|
|
@@ -339,11 +351,18 @@ export interface FormAdapterSubmissionMessageResult {
|
|
|
339
351
|
export type FileUploadFieldDetailitem = Omit<DetailItemField, 'field'> & {
|
|
340
352
|
field: FileUploadField;
|
|
341
353
|
};
|
|
354
|
+
/**
|
|
355
|
+
* A detail item specifically for payments
|
|
356
|
+
*/
|
|
357
|
+
export type PaymentFieldDetailItem = Omit<DetailItemField, 'field'> & {
|
|
358
|
+
field: PaymentField;
|
|
359
|
+
};
|
|
342
360
|
export type RichFormValue = FormValue | FormPayload | DatePartsState | MonthYearState | UkAddressState | EastingNorthingState | LatLongState;
|
|
343
361
|
export interface FormAdapterSubmissionMessageData {
|
|
344
362
|
main: Record<string, RichFormValue | null>;
|
|
345
363
|
repeaters: Record<string, Record<string, RichFormValue>[]>;
|
|
346
364
|
files: Record<string, FormAdapterFile[]>;
|
|
365
|
+
payment?: FormAdapterPayment;
|
|
347
366
|
}
|
|
348
367
|
export interface FormAdapterSubmissionMessagePayload {
|
|
349
368
|
meta: FormAdapterSubmissionMessageMeta;
|