@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
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
* @this {NunjucksContext}
|
|
4
4
|
* @param {string} name - The name of the component
|
|
5
5
|
*/
|
|
6
|
-
export function field(this: NunjucksContext, name: string): import("../../engine/components/TextField.js").TextField | import("../../engine/components/SelectField.js").SelectField | import("../../engine/components/RadiosField.js").RadiosField | import("../../engine/components/YesNoField.js").YesNoField | import("../../engine/components/CheckboxesField.js").CheckboxesField | import("../../engine/components/DatePartsField.js").DatePartsField | import("../../engine/components/DeclarationField.js").DeclarationField | import("../../engine/components/EastingNorthingField.js").EastingNorthingField | import("../../engine/components/EmailAddressField.js").EmailAddressField | import("../../engine/components/LatLongField.js").LatLongField | import("../../engine/components/MonthYearField.js").MonthYearField | import("../../engine/components/MultilineTextField.js").MultilineTextField | import("../../engine/components/NationalGridFieldNumberField.js").NationalGridFieldNumberField | import("../../engine/components/NumberField.js").NumberField | import("../../engine/components/OsGridRefField.js").OsGridRefField | import("../../engine/components/TelephoneNumberField.js").TelephoneNumberField | import("../../engine/components/UkAddressField.js").UkAddressField | import("../../engine/components/FileUploadField.js").FileUploadField | import("../../engine/components/HiddenField.js").HiddenField | import("../../engine/components/Details.js").Details | import("../../engine/components/Html.js").Html | import("../../engine/components/InsetText.js").InsetText | import("../../engine/components/List.js").List | import("../../engine/components/Markdown.js").Markdown | undefined;
|
|
6
|
+
export function field(this: NunjucksContext, name: string): import("../../engine/components/TextField.js").TextField | import("../../engine/components/SelectField.js").SelectField | import("../../engine/components/RadiosField.js").RadiosField | import("../../engine/components/YesNoField.js").YesNoField | import("../../engine/components/CheckboxesField.js").CheckboxesField | import("../../engine/components/DatePartsField.js").DatePartsField | import("../../engine/components/DeclarationField.js").DeclarationField | import("../../engine/components/EastingNorthingField.js").EastingNorthingField | import("../../engine/components/EmailAddressField.js").EmailAddressField | import("../../engine/components/LatLongField.js").LatLongField | import("../../engine/components/MonthYearField.js").MonthYearField | import("../../engine/components/MultilineTextField.js").MultilineTextField | import("../../engine/components/NationalGridFieldNumberField.js").NationalGridFieldNumberField | import("../../engine/components/NumberField.js").NumberField | import("../../engine/components/OsGridRefField.js").OsGridRefField | import("../../engine/components/TelephoneNumberField.js").TelephoneNumberField | import("../../engine/components/UkAddressField.js").UkAddressField | import("../../engine/components/FileUploadField.js").FileUploadField | import("../../engine/components/HiddenField.js").HiddenField | import("../../engine/components/PaymentField.js").PaymentField | import("../../engine/components/Details.js").Details | import("../../engine/components/Html.js").Html | import("../../engine/components/InsetText.js").InsetText | import("../../engine/components/List.js").List | import("../../engine/components/Markdown.js").Markdown | undefined;
|
|
7
7
|
import type { NunjucksContext } from '~/src/server/plugins/nunjucks/types.js';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determine which payment API key value to use.
|
|
3
|
+
* If a draft preview form or a live preview form, read the TEST API key value specific to that form.
|
|
4
|
+
* If a live (non-preview) form, read the LIVE API key value specific to that form.
|
|
5
|
+
* @param {boolean} isLivePayment - true if this is a live payment (as opposed to a test one)
|
|
6
|
+
* @param {string} formId - id of the form
|
|
7
|
+
* @returns {string}
|
|
8
|
+
*/
|
|
9
|
+
export function getPaymentApiKey(isLivePayment: boolean, formId: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a PaymentService instance with the appropriate API key
|
|
12
|
+
* @param {boolean} isLivePayment - true if this is a live payment
|
|
13
|
+
* @param {string} formId - id of the form
|
|
14
|
+
* @returns {PaymentService}
|
|
15
|
+
*/
|
|
16
|
+
export function createPaymentService(isLivePayment: boolean, formId: string): PaymentService;
|
|
17
|
+
/**
|
|
18
|
+
* Formats a payment date for display
|
|
19
|
+
* @param {string} isoString - ISO date string
|
|
20
|
+
* @returns {string} Formatted date string (e.g., "26 January 2026 5:01pm")
|
|
21
|
+
*/
|
|
22
|
+
export function formatPaymentDate(isoString: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Formats a payment amount with two decimal places
|
|
25
|
+
* @param {number} amount - amount in pounds
|
|
26
|
+
* @returns {string} Formatted amount (e.g., "£10.00")
|
|
27
|
+
*/
|
|
28
|
+
export function formatPaymentAmount(amount: number): string;
|
|
29
|
+
export const DEFAULT_PAYMENT_HELP_URL: "https://www.gov.uk/government/organisations/department-for-environment-food-rural-affairs";
|
|
30
|
+
import { PaymentService } from '~/src/server/plugins/payment/service.js';
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { format } from 'date-fns';
|
|
2
|
+
import { PaymentService } from "./service.js";
|
|
3
|
+
export const DEFAULT_PAYMENT_HELP_URL = 'https://www.gov.uk/government/organisations/department-for-environment-food-rural-affairs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Determine which payment API key value to use.
|
|
7
|
+
* If a draft preview form or a live preview form, read the TEST API key value specific to that form.
|
|
8
|
+
* If a live (non-preview) form, read the LIVE API key value specific to that form.
|
|
9
|
+
* @param {boolean} isLivePayment - true if this is a live payment (as opposed to a test one)
|
|
10
|
+
* @param {string} formId - id of the form
|
|
11
|
+
* @returns {string}
|
|
12
|
+
*/
|
|
13
|
+
export function getPaymentApiKey(isLivePayment, formId) {
|
|
14
|
+
const apiKeyValue = isLivePayment ? process.env[`PAYMENT_PROVIDER_API_KEY_LIVE_${formId}`] : process.env[`PAYMENT_PROVIDER_API_KEY_TEST_${formId}`];
|
|
15
|
+
if (!apiKeyValue) {
|
|
16
|
+
throw new Error(`Missing payment api key for ${isLivePayment ? 'live' : 'test'} form id ${formId}`);
|
|
17
|
+
}
|
|
18
|
+
return apiKeyValue;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a PaymentService instance with the appropriate API key
|
|
23
|
+
* @param {boolean} isLivePayment - true if this is a live payment
|
|
24
|
+
* @param {string} formId - id of the form
|
|
25
|
+
* @returns {PaymentService}
|
|
26
|
+
*/
|
|
27
|
+
export function createPaymentService(isLivePayment, formId) {
|
|
28
|
+
const apiKey = getPaymentApiKey(isLivePayment, formId);
|
|
29
|
+
return new PaymentService(apiKey);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Formats a payment date for display
|
|
34
|
+
* @param {string} isoString - ISO date string
|
|
35
|
+
* @returns {string} Formatted date string (e.g., "26 January 2026 5:01pm")
|
|
36
|
+
*/
|
|
37
|
+
export function formatPaymentDate(isoString) {
|
|
38
|
+
return format(new Date(isoString), 'd MMMM yyyy h:mmaaa');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Formats a payment amount with two decimal places
|
|
43
|
+
* @param {number} amount - amount in pounds
|
|
44
|
+
* @returns {string} Formatted amount (e.g., "£10.00")
|
|
45
|
+
*/
|
|
46
|
+
export function formatPaymentAmount(amount) {
|
|
47
|
+
return `£${amount.toFixed(2)}`;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=helper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.js","names":["format","PaymentService","DEFAULT_PAYMENT_HELP_URL","getPaymentApiKey","isLivePayment","formId","apiKeyValue","process","env","Error","createPaymentService","apiKey","formatPaymentDate","isoString","Date","formatPaymentAmount","amount","toFixed"],"sources":["../../../../src/server/plugins/payment/helper.js"],"sourcesContent":["import { format } from 'date-fns'\n\nimport { PaymentService } from '~/src/server/plugins/payment/service.js'\n\nexport const DEFAULT_PAYMENT_HELP_URL =\n 'https://www.gov.uk/government/organisations/department-for-environment-food-rural-affairs'\n\n/**\n * Determine which payment API key value to use.\n * If a draft preview form or a live preview form, read the TEST API key value specific to that form.\n * If a live (non-preview) form, read the LIVE API key value specific to that form.\n * @param {boolean} isLivePayment - true if this is a live payment (as opposed to a test one)\n * @param {string} formId - id of the form\n * @returns {string}\n */\nexport function getPaymentApiKey(isLivePayment, formId) {\n const apiKeyValue = isLivePayment\n ? process.env[`PAYMENT_PROVIDER_API_KEY_LIVE_${formId}`]\n : process.env[`PAYMENT_PROVIDER_API_KEY_TEST_${formId}`]\n\n if (!apiKeyValue) {\n throw new Error(\n `Missing payment api key for ${isLivePayment ? 'live' : 'test'} form id ${formId}`\n )\n }\n return apiKeyValue\n}\n\n/**\n * Creates a PaymentService instance with the appropriate API key\n * @param {boolean} isLivePayment - true if this is a live payment\n * @param {string} formId - id of the form\n * @returns {PaymentService}\n */\nexport function createPaymentService(isLivePayment, formId) {\n const apiKey = getPaymentApiKey(isLivePayment, formId)\n return new PaymentService(apiKey)\n}\n\n/**\n * Formats a payment date for display\n * @param {string} isoString - ISO date string\n * @returns {string} Formatted date string (e.g., \"26 January 2026 5:01pm\")\n */\nexport function formatPaymentDate(isoString) {\n return format(new Date(isoString), 'd MMMM yyyy h:mmaaa')\n}\n\n/**\n * Formats a payment amount with two decimal places\n * @param {number} amount - amount in pounds\n * @returns {string} Formatted amount (e.g., \"£10.00\")\n */\nexport function formatPaymentAmount(amount) {\n return `£${amount.toFixed(2)}`\n}\n"],"mappings":"AAAA,SAASA,MAAM,QAAQ,UAAU;AAEjC,SAASC,cAAc;AAEvB,OAAO,MAAMC,wBAAwB,GACnC,2FAA2F;;AAE7F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,gBAAgBA,CAACC,aAAa,EAAEC,MAAM,EAAE;EACtD,MAAMC,WAAW,GAAGF,aAAa,GAC7BG,OAAO,CAACC,GAAG,CAAC,iCAAiCH,MAAM,EAAE,CAAC,GACtDE,OAAO,CAACC,GAAG,CAAC,iCAAiCH,MAAM,EAAE,CAAC;EAE1D,IAAI,CAACC,WAAW,EAAE;IAChB,MAAM,IAAIG,KAAK,CACb,+BAA+BL,aAAa,GAAG,MAAM,GAAG,MAAM,YAAYC,MAAM,EAClF,CAAC;EACH;EACA,OAAOC,WAAW;AACpB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASI,oBAAoBA,CAACN,aAAa,EAAEC,MAAM,EAAE;EAC1D,MAAMM,MAAM,GAAGR,gBAAgB,CAACC,aAAa,EAAEC,MAAM,CAAC;EACtD,OAAO,IAAIJ,cAAc,CAACU,MAAM,CAAC;AACnC;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,iBAAiBA,CAACC,SAAS,EAAE;EAC3C,OAAOb,MAAM,CAAC,IAAIc,IAAI,CAACD,SAAS,CAAC,EAAE,qBAAqB,CAAC;AAC3D;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASE,mBAAmBA,CAACC,MAAM,EAAE;EAC1C,OAAO,IAAIA,MAAM,CAACC,OAAO,CAAC,CAAC,CAAC,EAAE;AAChC","ignoreList":[]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { config } from "../../../config/index.js";
|
|
2
|
+
import { formatPaymentAmount, formatPaymentDate, getPaymentApiKey } from "./helper.js";
|
|
3
|
+
describe('getPaymentApiKey', () => {
|
|
4
|
+
config.set('paymentProviderApiKeyTest', 'TEST-API-KEY');
|
|
5
|
+
const formId = 'form-id';
|
|
6
|
+
process.env['PAYMENT_PROVIDER_API_KEY_LIVE_form-id'] = 'LIVE-API-KEY';
|
|
7
|
+
process.env['PAYMENT_PROVIDER_API_KEY_TEST_form-id'] = 'TEST-API-KEY';
|
|
8
|
+
it('should read test key when non-live form', () => {
|
|
9
|
+
const apiKey = getPaymentApiKey(false, formId);
|
|
10
|
+
expect(apiKey).toBe('TEST-API-KEY');
|
|
11
|
+
});
|
|
12
|
+
it('should read live key when live form', () => {
|
|
13
|
+
const apiKey = getPaymentApiKey(true, formId);
|
|
14
|
+
expect(apiKey).toBe('LIVE-API-KEY');
|
|
15
|
+
});
|
|
16
|
+
it('should throw if TEST key is missing', () => {
|
|
17
|
+
expect(() => getPaymentApiKey(false, 'form-id-missing')).toThrow('Missing payment api key for test form id form-id-missing');
|
|
18
|
+
});
|
|
19
|
+
it('should throw if LIVE key is missing', () => {
|
|
20
|
+
expect(() => getPaymentApiKey(true, 'form-id-missing')).toThrow('Missing payment api key for live form id form-id-missing');
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
describe('formatPaymentDate', () => {
|
|
24
|
+
it('should format ISO date string to en-GB format', () => {
|
|
25
|
+
const result = formatPaymentDate('2025-11-10T17:01:29.000Z');
|
|
26
|
+
expect(result).toBe('10 November 2025 5:01pm');
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
describe('formatPaymentAmount', () => {
|
|
30
|
+
it('should format whole number with two decimal places', () => {
|
|
31
|
+
expect(formatPaymentAmount(10)).toBe('£10.00');
|
|
32
|
+
});
|
|
33
|
+
it('should format decimal amount', () => {
|
|
34
|
+
expect(formatPaymentAmount(99.5)).toBe('£99.50');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=helper.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.test.js","names":["config","formatPaymentAmount","formatPaymentDate","getPaymentApiKey","describe","set","formId","process","env","it","apiKey","expect","toBe","toThrow","result"],"sources":["../../../../src/server/plugins/payment/helper.test.js"],"sourcesContent":["import { config } from '~/src/config/index.js'\nimport {\n formatPaymentAmount,\n formatPaymentDate,\n getPaymentApiKey\n} from '~/src/server/plugins/payment/helper.js'\n\ndescribe('getPaymentApiKey', () => {\n config.set('paymentProviderApiKeyTest', 'TEST-API-KEY')\n const formId = 'form-id'\n process.env['PAYMENT_PROVIDER_API_KEY_LIVE_form-id'] = 'LIVE-API-KEY'\n process.env['PAYMENT_PROVIDER_API_KEY_TEST_form-id'] = 'TEST-API-KEY'\n\n it('should read test key when non-live form', () => {\n const apiKey = getPaymentApiKey(false, formId)\n expect(apiKey).toBe('TEST-API-KEY')\n })\n\n it('should read live key when live form', () => {\n const apiKey = getPaymentApiKey(true, formId)\n expect(apiKey).toBe('LIVE-API-KEY')\n })\n\n it('should throw if TEST key is missing', () => {\n expect(() => getPaymentApiKey(false, 'form-id-missing')).toThrow(\n 'Missing payment api key for test form id form-id-missing'\n )\n })\n\n it('should throw if LIVE key is missing', () => {\n expect(() => getPaymentApiKey(true, 'form-id-missing')).toThrow(\n 'Missing payment api key for live form id form-id-missing'\n )\n })\n})\n\ndescribe('formatPaymentDate', () => {\n it('should format ISO date string to en-GB format', () => {\n const result = formatPaymentDate('2025-11-10T17:01:29.000Z')\n expect(result).toBe('10 November 2025 5:01pm')\n })\n})\n\ndescribe('formatPaymentAmount', () => {\n it('should format whole number with two decimal places', () => {\n expect(formatPaymentAmount(10)).toBe('£10.00')\n })\n\n it('should format decimal amount', () => {\n expect(formatPaymentAmount(99.5)).toBe('£99.50')\n })\n})\n"],"mappings":"AAAA,SAASA,MAAM;AACf,SACEC,mBAAmB,EACnBC,iBAAiB,EACjBC,gBAAgB;AAGlBC,QAAQ,CAAC,kBAAkB,EAAE,MAAM;EACjCJ,MAAM,CAACK,GAAG,CAAC,2BAA2B,EAAE,cAAc,CAAC;EACvD,MAAMC,MAAM,GAAG,SAAS;EACxBC,OAAO,CAACC,GAAG,CAAC,uCAAuC,CAAC,GAAG,cAAc;EACrED,OAAO,CAACC,GAAG,CAAC,uCAAuC,CAAC,GAAG,cAAc;EAErEC,EAAE,CAAC,yCAAyC,EAAE,MAAM;IAClD,MAAMC,MAAM,GAAGP,gBAAgB,CAAC,KAAK,EAAEG,MAAM,CAAC;IAC9CK,MAAM,CAACD,MAAM,CAAC,CAACE,IAAI,CAAC,cAAc,CAAC;EACrC,CAAC,CAAC;EAEFH,EAAE,CAAC,qCAAqC,EAAE,MAAM;IAC9C,MAAMC,MAAM,GAAGP,gBAAgB,CAAC,IAAI,EAAEG,MAAM,CAAC;IAC7CK,MAAM,CAACD,MAAM,CAAC,CAACE,IAAI,CAAC,cAAc,CAAC;EACrC,CAAC,CAAC;EAEFH,EAAE,CAAC,qCAAqC,EAAE,MAAM;IAC9CE,MAAM,CAAC,MAAMR,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC,CAACU,OAAO,CAC9D,0DACF,CAAC;EACH,CAAC,CAAC;EAEFJ,EAAE,CAAC,qCAAqC,EAAE,MAAM;IAC9CE,MAAM,CAAC,MAAMR,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAACU,OAAO,CAC7D,0DACF,CAAC;EACH,CAAC,CAAC;AACJ,CAAC,CAAC;AAEFT,QAAQ,CAAC,mBAAmB,EAAE,MAAM;EAClCK,EAAE,CAAC,+CAA+C,EAAE,MAAM;IACxD,MAAMK,MAAM,GAAGZ,iBAAiB,CAAC,0BAA0B,CAAC;IAC5DS,MAAM,CAACG,MAAM,CAAC,CAACF,IAAI,CAAC,yBAAyB,CAAC;EAChD,CAAC,CAAC;AACJ,CAAC,CAAC;AAEFR,QAAQ,CAAC,qBAAqB,EAAE,MAAM;EACpCK,EAAE,CAAC,oDAAoD,EAAE,MAAM;IAC7DE,MAAM,CAACV,mBAAmB,CAAC,EAAE,CAAC,CAAC,CAACW,IAAI,CAAC,QAAQ,CAAC;EAChD,CAAC,CAAC;EAEFH,EAAE,CAAC,8BAA8B,EAAE,MAAM;IACvCE,MAAM,CAACV,mBAAmB,CAAC,IAAI,CAAC,CAAC,CAACW,IAAI,CAAC,QAAQ,CAAC;EAClD,CAAC,CAAC;AACJ,CAAC,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export class PaymentService {
|
|
2
|
+
/**
|
|
3
|
+
* @param {string} apiKey - API key to use (global config for test value, per-form config for live value)
|
|
4
|
+
*/
|
|
5
|
+
constructor(apiKey: string);
|
|
6
|
+
/**
|
|
7
|
+
* Creates a payment with delayed capture (pre-authorisation)
|
|
8
|
+
* @param {number} amount - in pence
|
|
9
|
+
* @param {string} description
|
|
10
|
+
* @param {string} returnUrl
|
|
11
|
+
* @param {string} reference
|
|
12
|
+
* @param {{ formId: string, slug: string }} metadata
|
|
13
|
+
*/
|
|
14
|
+
createPayment(amount: number, description: string, returnUrl: string, reference: string, metadata: {
|
|
15
|
+
formId: string;
|
|
16
|
+
slug: string;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
paymentId: string;
|
|
19
|
+
paymentUrl: string;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} paymentId
|
|
23
|
+
* @returns {Promise<GetPaymentResponse>}
|
|
24
|
+
*/
|
|
25
|
+
getPaymentStatus(paymentId: string): Promise<GetPaymentResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* Captures a payment that is in 'capturable' status
|
|
28
|
+
* @param {string} paymentId
|
|
29
|
+
* @returns {Promise<boolean>}
|
|
30
|
+
*/
|
|
31
|
+
capturePayment(paymentId: string): Promise<boolean>;
|
|
32
|
+
/**
|
|
33
|
+
* @param {CreatePaymentRequest} payload
|
|
34
|
+
*/
|
|
35
|
+
postToPayProvider(payload: CreatePaymentRequest): Promise<CreatePaymentResponse>;
|
|
36
|
+
#private;
|
|
37
|
+
}
|
|
38
|
+
import type { GetPaymentResponse } from '~/src/server/plugins/payment/types.js';
|
|
39
|
+
import type { CreatePaymentRequest } from '~/src/server/plugins/payment/types.js';
|
|
40
|
+
import type { CreatePaymentResponse } from '~/src/server/plugins/payment/types.js';
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { StatusCodes } from 'http-status-codes';
|
|
2
|
+
import { createLogger } from "../../common/helpers/logging/logger.js";
|
|
3
|
+
import { get, post, postJson } from "../../services/httpService.js";
|
|
4
|
+
const PAYMENT_BASE_URL = 'https://publicapi.payments.service.gov.uk';
|
|
5
|
+
const PAYMENT_ENDPOINT = '/v1/payments';
|
|
6
|
+
const logger = createLogger();
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} apiKey
|
|
10
|
+
* @returns {{ Authorization: string }}
|
|
11
|
+
*/
|
|
12
|
+
function getAuthHeaders(apiKey) {
|
|
13
|
+
return {
|
|
14
|
+
Authorization: `Bearer ${apiKey}`
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export class PaymentService {
|
|
18
|
+
/** @type {string} */
|
|
19
|
+
#apiKey;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} apiKey - API key to use (global config for test value, per-form config for live value)
|
|
23
|
+
*/
|
|
24
|
+
constructor(apiKey) {
|
|
25
|
+
this.#apiKey = apiKey;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Creates a payment with delayed capture (pre-authorisation)
|
|
30
|
+
* @param {number} amount - in pence
|
|
31
|
+
* @param {string} description
|
|
32
|
+
* @param {string} returnUrl
|
|
33
|
+
* @param {string} reference
|
|
34
|
+
* @param {{ formId: string, slug: string }} metadata
|
|
35
|
+
*/
|
|
36
|
+
async createPayment(amount, description, returnUrl, reference, metadata) {
|
|
37
|
+
const response = await this.postToPayProvider({
|
|
38
|
+
amount,
|
|
39
|
+
description,
|
|
40
|
+
reference,
|
|
41
|
+
metadata,
|
|
42
|
+
return_url: returnUrl,
|
|
43
|
+
delayed_capture: true
|
|
44
|
+
});
|
|
45
|
+
return {
|
|
46
|
+
paymentId: response.payment_id,
|
|
47
|
+
paymentUrl: response._links.next_url.href
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} paymentId
|
|
53
|
+
* @returns {Promise<GetPaymentResponse>}
|
|
54
|
+
*/
|
|
55
|
+
async getPaymentStatus(paymentId) {
|
|
56
|
+
const getByType = /** @type {typeof get<GetPaymentApiResponse>} */get;
|
|
57
|
+
try {
|
|
58
|
+
const response = await getByType(`${PAYMENT_BASE_URL}${PAYMENT_ENDPOINT}/${paymentId}`, {
|
|
59
|
+
headers: getAuthHeaders(this.#apiKey),
|
|
60
|
+
json: true
|
|
61
|
+
});
|
|
62
|
+
if (response.error) {
|
|
63
|
+
const errorMessage = response.error instanceof Error ? response.error.message : JSON.stringify(response.error);
|
|
64
|
+
throw new Error(`Failed to get payment status: ${errorMessage}`);
|
|
65
|
+
}
|
|
66
|
+
return {
|
|
67
|
+
state: response.payload.state,
|
|
68
|
+
_links: response.payload._links,
|
|
69
|
+
email: response.payload.email,
|
|
70
|
+
paymentId: response.payload.payment_id,
|
|
71
|
+
amount: response.payload.amount
|
|
72
|
+
};
|
|
73
|
+
} catch (err) {
|
|
74
|
+
const error = /** @type {Error} */err;
|
|
75
|
+
logger.error(error, `[payment] Error getting payment status for paymentId=${paymentId}: ${error.message}`);
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Captures a payment that is in 'capturable' status
|
|
82
|
+
* @param {string} paymentId
|
|
83
|
+
* @returns {Promise<boolean>}
|
|
84
|
+
*/
|
|
85
|
+
async capturePayment(paymentId) {
|
|
86
|
+
try {
|
|
87
|
+
const response = await post(`${PAYMENT_BASE_URL}${PAYMENT_ENDPOINT}/${paymentId}/capture`, {
|
|
88
|
+
headers: getAuthHeaders(this.#apiKey)
|
|
89
|
+
});
|
|
90
|
+
const statusCode = response.res.statusCode;
|
|
91
|
+
if (statusCode === StatusCodes.OK || statusCode === StatusCodes.NO_CONTENT) {
|
|
92
|
+
logger.info(`[payment] Successfully captured payment ${paymentId}`);
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
logger.error(`[payment] Capture failed for paymentId=${paymentId}: HTTP ${statusCode}`);
|
|
96
|
+
return false;
|
|
97
|
+
} catch (err) {
|
|
98
|
+
const error = /** @type {Error} */err;
|
|
99
|
+
logger.error(error, `[payment] Error capturing payment for paymentId=${paymentId}: ${error.message}`);
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {CreatePaymentRequest} payload
|
|
106
|
+
*/
|
|
107
|
+
async postToPayProvider(payload) {
|
|
108
|
+
const postJsonByType = /** @type {typeof postJson<CreatePaymentResponse>} */postJson;
|
|
109
|
+
try {
|
|
110
|
+
const response = await postJsonByType(`${PAYMENT_BASE_URL}${PAYMENT_ENDPOINT}`, {
|
|
111
|
+
payload,
|
|
112
|
+
headers: getAuthHeaders(this.#apiKey)
|
|
113
|
+
});
|
|
114
|
+
if (response.payload?.state.status !== 'created') {
|
|
115
|
+
throw new Error(`Failed to create payment for reference=${payload.reference}`);
|
|
116
|
+
}
|
|
117
|
+
return response.payload;
|
|
118
|
+
} catch (err) {
|
|
119
|
+
const error = /** @type {Error} */err;
|
|
120
|
+
logger.error(error, `[payment] Error creating payment for reference=${payload.reference}: ${error.message}`);
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @import { CreatePaymentRequest, CreatePaymentResponse, GetPaymentApiResponse, GetPaymentResponse } from '~/src/server/plugins/payment/types.js'
|
|
128
|
+
*/
|
|
129
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","names":["StatusCodes","createLogger","get","post","postJson","PAYMENT_BASE_URL","PAYMENT_ENDPOINT","logger","getAuthHeaders","apiKey","Authorization","PaymentService","constructor","createPayment","amount","description","returnUrl","reference","metadata","response","postToPayProvider","return_url","delayed_capture","paymentId","payment_id","paymentUrl","_links","next_url","href","getPaymentStatus","getByType","headers","json","error","errorMessage","Error","message","JSON","stringify","state","payload","email","err","capturePayment","statusCode","res","OK","NO_CONTENT","info","postJsonByType","status"],"sources":["../../../../src/server/plugins/payment/service.js"],"sourcesContent":["import { StatusCodes } from 'http-status-codes'\n\nimport { createLogger } from '~/src/server/common/helpers/logging/logger.js'\nimport { get, post, postJson } from '~/src/server/services/httpService.js'\n\nconst PAYMENT_BASE_URL = 'https://publicapi.payments.service.gov.uk'\nconst PAYMENT_ENDPOINT = '/v1/payments'\n\nconst logger = createLogger()\n\n/**\n * @param {string} apiKey\n * @returns {{ Authorization: string }}\n */\nfunction getAuthHeaders(apiKey) {\n return {\n Authorization: `Bearer ${apiKey}`\n }\n}\n\nexport class PaymentService {\n /** @type {string} */\n #apiKey\n\n /**\n * @param {string} apiKey - API key to use (global config for test value, per-form config for live value)\n */\n constructor(apiKey) {\n this.#apiKey = apiKey\n }\n\n /**\n * Creates a payment with delayed capture (pre-authorisation)\n * @param {number} amount - in pence\n * @param {string} description\n * @param {string} returnUrl\n * @param {string} reference\n * @param {{ formId: string, slug: string }} metadata\n */\n async createPayment(amount, description, returnUrl, reference, metadata) {\n const response = await this.postToPayProvider({\n amount,\n description,\n reference,\n metadata,\n return_url: returnUrl,\n delayed_capture: true\n })\n\n return {\n paymentId: response.payment_id,\n paymentUrl: response._links.next_url.href\n }\n }\n\n /**\n * @param {string} paymentId\n * @returns {Promise<GetPaymentResponse>}\n */\n async getPaymentStatus(paymentId) {\n const getByType = /** @type {typeof get<GetPaymentApiResponse>} */ (get)\n\n try {\n const response = await getByType(\n `${PAYMENT_BASE_URL}${PAYMENT_ENDPOINT}/${paymentId}`,\n {\n headers: getAuthHeaders(this.#apiKey),\n json: true\n }\n )\n\n if (response.error) {\n const errorMessage =\n response.error instanceof Error\n ? response.error.message\n : JSON.stringify(response.error)\n throw new Error(`Failed to get payment status: ${errorMessage}`)\n }\n\n return {\n state: response.payload.state,\n _links: response.payload._links,\n email: response.payload.email,\n paymentId: response.payload.payment_id,\n amount: response.payload.amount\n }\n } catch (err) {\n const error = /** @type {Error} */ (err)\n logger.error(\n error,\n `[payment] Error getting payment status for paymentId=${paymentId}: ${error.message}`\n )\n throw err\n }\n }\n\n /**\n * Captures a payment that is in 'capturable' status\n * @param {string} paymentId\n * @returns {Promise<boolean>}\n */\n async capturePayment(paymentId) {\n try {\n const response = await post(\n `${PAYMENT_BASE_URL}${PAYMENT_ENDPOINT}/${paymentId}/capture`,\n {\n headers: getAuthHeaders(this.#apiKey)\n }\n )\n\n const statusCode = response.res.statusCode\n\n if (\n statusCode === StatusCodes.OK ||\n statusCode === StatusCodes.NO_CONTENT\n ) {\n logger.info(`[payment] Successfully captured payment ${paymentId}`)\n return true\n }\n\n logger.error(\n `[payment] Capture failed for paymentId=${paymentId}: HTTP ${statusCode}`\n )\n return false\n } catch (err) {\n const error = /** @type {Error} */ (err)\n logger.error(\n error,\n `[payment] Error capturing payment for paymentId=${paymentId}: ${error.message}`\n )\n throw err\n }\n }\n\n /**\n * @param {CreatePaymentRequest} payload\n */\n async postToPayProvider(payload) {\n const postJsonByType =\n /** @type {typeof postJson<CreatePaymentResponse>} */ (postJson)\n\n try {\n const response = await postJsonByType(\n `${PAYMENT_BASE_URL}${PAYMENT_ENDPOINT}`,\n {\n payload,\n headers: getAuthHeaders(this.#apiKey)\n }\n )\n\n if (response.payload?.state.status !== 'created') {\n throw new Error(\n `Failed to create payment for reference=${payload.reference}`\n )\n }\n\n return response.payload\n } catch (err) {\n const error = /** @type {Error} */ (err)\n logger.error(\n error,\n `[payment] Error creating payment for reference=${payload.reference}: ${error.message}`\n )\n throw err\n }\n }\n}\n\n/**\n * @import { CreatePaymentRequest, CreatePaymentResponse, GetPaymentApiResponse, GetPaymentResponse } from '~/src/server/plugins/payment/types.js'\n */\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { PaymentService } from "./service.js";
|
|
2
|
+
import { get, post, postJson } from "../../services/httpService.js";
|
|
3
|
+
jest.mock("../../services/httpService.ts");
|
|
4
|
+
describe('payment service', () => {
|
|
5
|
+
const service = new PaymentService('my-api-key');
|
|
6
|
+
describe('constructor', () => {
|
|
7
|
+
it('should create instance', () => {
|
|
8
|
+
expect(service).toBeDefined();
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
describe('createPayment', () => {
|
|
12
|
+
it('should create a payment', async () => {
|
|
13
|
+
const createPaymentResult = {
|
|
14
|
+
payment_id: 'payment-id-12345',
|
|
15
|
+
_links: {
|
|
16
|
+
next_url: {
|
|
17
|
+
href: 'http://next-url-href/payment'
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
state: {
|
|
21
|
+
status: 'created'
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
jest.mocked(postJson).mockResolvedValueOnce({
|
|
25
|
+
res: (/** @type {IncomingMessage} */{
|
|
26
|
+
statusCode: 200,
|
|
27
|
+
headers: {}
|
|
28
|
+
}),
|
|
29
|
+
payload: createPaymentResult,
|
|
30
|
+
error: undefined
|
|
31
|
+
});
|
|
32
|
+
const referenceNumber = 'ABC-DEF-123';
|
|
33
|
+
const returnUrl = 'http://localhost:3009/payment-callback-handler';
|
|
34
|
+
const metadata = {
|
|
35
|
+
formId: 'form-id',
|
|
36
|
+
slug: 'my-form-slug'
|
|
37
|
+
};
|
|
38
|
+
const payment = await service.createPayment(100, 'Payment description', returnUrl, referenceNumber, metadata);
|
|
39
|
+
expect(payment.paymentId).toBe('payment-id-12345');
|
|
40
|
+
expect(payment.paymentUrl).toBe('http://next-url-href/payment');
|
|
41
|
+
});
|
|
42
|
+
it('should throw if fails to create a payment - failed API call', async () => {
|
|
43
|
+
jest.mocked(postJson).mockRejectedValueOnce(new Error('internal creation error'));
|
|
44
|
+
const referenceNumber = 'ABC-DEF-123';
|
|
45
|
+
const returnUrl = 'http://localhost:3009/payment-callback-handler';
|
|
46
|
+
const metadata = {
|
|
47
|
+
formId: 'form-id',
|
|
48
|
+
slug: 'my-form-slug'
|
|
49
|
+
};
|
|
50
|
+
await expect(() => service.createPayment(100, 'Payment description', returnUrl, referenceNumber, metadata)).rejects.toThrow('internal creation error');
|
|
51
|
+
});
|
|
52
|
+
it('should throw if fails to create a payment - bad result from API call', async () => {
|
|
53
|
+
const createPaymentResult = {
|
|
54
|
+
state: {
|
|
55
|
+
status: 'failed'
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
jest.mocked(postJson).mockResolvedValueOnce({
|
|
59
|
+
res: (/** @type {IncomingMessage} */{
|
|
60
|
+
statusCode: 200,
|
|
61
|
+
headers: {}
|
|
62
|
+
}),
|
|
63
|
+
payload: createPaymentResult,
|
|
64
|
+
error: undefined
|
|
65
|
+
});
|
|
66
|
+
const referenceNumber = 'ABC-DEF-123';
|
|
67
|
+
const returnUrl = 'http://localhost:3009/payment-callback-handler';
|
|
68
|
+
const metadata = {
|
|
69
|
+
formId: 'form-id',
|
|
70
|
+
slug: 'my-form-slug'
|
|
71
|
+
};
|
|
72
|
+
await expect(() => service.createPayment(100, 'Payment description', returnUrl, referenceNumber, metadata)).rejects.toThrow('Failed to create payment');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
describe('getPaymentStatus', () => {
|
|
76
|
+
it('should get payment status if exists', async () => {
|
|
77
|
+
const getPaymentStatusResult = {
|
|
78
|
+
payment_id: 'payment-id-12345',
|
|
79
|
+
_links: {
|
|
80
|
+
next_url: {
|
|
81
|
+
href: 'http://next-url-href/payment'
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
state: {
|
|
85
|
+
status: 'created'
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
jest.mocked(get).mockResolvedValueOnce({
|
|
89
|
+
res: (/** @type {IncomingMessage} */{
|
|
90
|
+
statusCode: 200,
|
|
91
|
+
headers: {}
|
|
92
|
+
}),
|
|
93
|
+
payload: getPaymentStatusResult,
|
|
94
|
+
error: undefined
|
|
95
|
+
});
|
|
96
|
+
const paymentStatus = await service.getPaymentStatus('payment-id-12345');
|
|
97
|
+
expect(paymentStatus.paymentId).toBe('payment-id-12345');
|
|
98
|
+
expect(paymentStatus._links.next_url?.href).toBe('http://next-url-href/payment');
|
|
99
|
+
});
|
|
100
|
+
it('should handle payment status error', async () => {
|
|
101
|
+
jest.mocked(get).mockResolvedValueOnce({
|
|
102
|
+
res: (/** @type {IncomingMessage} */{
|
|
103
|
+
statusCode: 200,
|
|
104
|
+
headers: {}
|
|
105
|
+
}),
|
|
106
|
+
payload: undefined,
|
|
107
|
+
error: new Error('some-error')
|
|
108
|
+
});
|
|
109
|
+
await expect(() => service.getPaymentStatus('payment-id-12345')).rejects.toThrow('Failed to get payment status: some-error');
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
describe('capturePayment', () => {
|
|
113
|
+
it('should return true when successful capture with statusCode 200', async () => {
|
|
114
|
+
const capturePaymentResult = {};
|
|
115
|
+
jest.mocked(post).mockResolvedValueOnce({
|
|
116
|
+
res: (/** @type {IncomingMessage} */{
|
|
117
|
+
statusCode: 200,
|
|
118
|
+
headers: {}
|
|
119
|
+
}),
|
|
120
|
+
payload: capturePaymentResult,
|
|
121
|
+
error: undefined
|
|
122
|
+
});
|
|
123
|
+
const captureResult = await service.capturePayment('payment-id-12345');
|
|
124
|
+
expect(captureResult).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
it('should return true when successful capture with statusCode 204', async () => {
|
|
127
|
+
const capturePaymentResult = {};
|
|
128
|
+
jest.mocked(post).mockResolvedValueOnce({
|
|
129
|
+
res: (/** @type {IncomingMessage} */{
|
|
130
|
+
statusCode: 204,
|
|
131
|
+
headers: {}
|
|
132
|
+
}),
|
|
133
|
+
payload: capturePaymentResult,
|
|
134
|
+
error: undefined
|
|
135
|
+
});
|
|
136
|
+
const captureResult = await service.capturePayment('payment-id-12345');
|
|
137
|
+
expect(captureResult).toBe(true);
|
|
138
|
+
});
|
|
139
|
+
it('should return false when status code not 200 or 204', async () => {
|
|
140
|
+
const capturePaymentResult = {};
|
|
141
|
+
jest.mocked(post).mockResolvedValueOnce({
|
|
142
|
+
res: (/** @type {IncomingMessage} */{
|
|
143
|
+
statusCode: 500,
|
|
144
|
+
headers: {}
|
|
145
|
+
}),
|
|
146
|
+
payload: capturePaymentResult,
|
|
147
|
+
error: undefined
|
|
148
|
+
});
|
|
149
|
+
const captureResult = await service.capturePayment('payment-id-12345');
|
|
150
|
+
expect(captureResult).toBe(false);
|
|
151
|
+
});
|
|
152
|
+
it('should throw when internal error', async () => {
|
|
153
|
+
jest.mocked(post).mockRejectedValueOnce(new Error('internal capture error'));
|
|
154
|
+
await expect(() => service.capturePayment('payment-id-12345')).rejects.toThrow('internal capture error');
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* @import { IncomingMessage } from 'node:http'
|
|
161
|
+
*/
|
|
162
|
+
//# sourceMappingURL=service.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.test.js","names":["PaymentService","get","post","postJson","jest","mock","describe","service","it","expect","toBeDefined","createPaymentResult","payment_id","_links","next_url","href","state","status","mocked","mockResolvedValueOnce","res","statusCode","headers","payload","error","undefined","referenceNumber","returnUrl","metadata","formId","slug","payment","createPayment","paymentId","toBe","paymentUrl","mockRejectedValueOnce","Error","rejects","toThrow","getPaymentStatusResult","paymentStatus","getPaymentStatus","capturePaymentResult","captureResult","capturePayment"],"sources":["../../../../src/server/plugins/payment/service.test.js"],"sourcesContent":["import { PaymentService } from '~/src/server/plugins/payment/service.js'\nimport { get, post, postJson } from '~/src/server/services/httpService.js'\n\njest.mock('~/src/server/services/httpService.ts')\n\ndescribe('payment service', () => {\n const service = new PaymentService('my-api-key')\n describe('constructor', () => {\n it('should create instance', () => {\n expect(service).toBeDefined()\n })\n })\n\n describe('createPayment', () => {\n it('should create a payment', async () => {\n const createPaymentResult = {\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 jest.mocked(postJson).mockResolvedValueOnce({\n res: /** @type {IncomingMessage} */ ({\n statusCode: 200,\n headers: {}\n }),\n payload: createPaymentResult,\n error: undefined\n })\n\n const referenceNumber = 'ABC-DEF-123'\n const returnUrl = 'http://localhost:3009/payment-callback-handler'\n const metadata = { formId: 'form-id', slug: 'my-form-slug' }\n const payment = await service.createPayment(\n 100,\n 'Payment description',\n returnUrl,\n referenceNumber,\n metadata\n )\n expect(payment.paymentId).toBe('payment-id-12345')\n expect(payment.paymentUrl).toBe('http://next-url-href/payment')\n })\n\n it('should throw if fails to create a payment - failed API call', async () => {\n jest\n .mocked(postJson)\n .mockRejectedValueOnce(new Error('internal creation error'))\n\n const referenceNumber = 'ABC-DEF-123'\n const returnUrl = 'http://localhost:3009/payment-callback-handler'\n const metadata = { formId: 'form-id', slug: 'my-form-slug' }\n await expect(() =>\n service.createPayment(\n 100,\n 'Payment description',\n returnUrl,\n referenceNumber,\n metadata\n )\n ).rejects.toThrow('internal creation error')\n })\n\n it('should throw if fails to create a payment - bad result from API call', async () => {\n const createPaymentResult = {\n state: {\n status: 'failed'\n }\n }\n jest.mocked(postJson).mockResolvedValueOnce({\n res: /** @type {IncomingMessage} */ ({\n statusCode: 200,\n headers: {}\n }),\n payload: createPaymentResult,\n error: undefined\n })\n\n const referenceNumber = 'ABC-DEF-123'\n const returnUrl = 'http://localhost:3009/payment-callback-handler'\n const metadata = { formId: 'form-id', slug: 'my-form-slug' }\n await expect(() =>\n service.createPayment(\n 100,\n 'Payment description',\n returnUrl,\n referenceNumber,\n metadata\n )\n ).rejects.toThrow('Failed to create payment')\n })\n })\n\n describe('getPaymentStatus', () => {\n it('should get payment status if exists', async () => {\n const getPaymentStatusResult = {\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: getPaymentStatusResult,\n error: undefined\n })\n\n const paymentStatus = await service.getPaymentStatus('payment-id-12345')\n expect(paymentStatus.paymentId).toBe('payment-id-12345')\n expect(paymentStatus._links.next_url?.href).toBe(\n 'http://next-url-href/payment'\n )\n })\n\n it('should handle payment status error', async () => {\n jest.mocked(get).mockResolvedValueOnce({\n res: /** @type {IncomingMessage} */ ({\n statusCode: 200,\n headers: {}\n }),\n payload: undefined,\n error: new Error('some-error')\n })\n\n await expect(() =>\n service.getPaymentStatus('payment-id-12345')\n ).rejects.toThrow('Failed to get payment status: some-error')\n })\n })\n\n describe('capturePayment', () => {\n it('should return true when successful capture with statusCode 200', async () => {\n const capturePaymentResult = {}\n jest.mocked(post).mockResolvedValueOnce({\n res: /** @type {IncomingMessage} */ ({\n statusCode: 200,\n headers: {}\n }),\n payload: capturePaymentResult,\n error: undefined\n })\n\n const captureResult = await service.capturePayment('payment-id-12345')\n expect(captureResult).toBe(true)\n })\n\n it('should return true when successful capture with statusCode 204', async () => {\n const capturePaymentResult = {}\n jest.mocked(post).mockResolvedValueOnce({\n res: /** @type {IncomingMessage} */ ({\n statusCode: 204,\n headers: {}\n }),\n payload: capturePaymentResult,\n error: undefined\n })\n\n const captureResult = await service.capturePayment('payment-id-12345')\n expect(captureResult).toBe(true)\n })\n\n it('should return false when status code not 200 or 204', async () => {\n const capturePaymentResult = {}\n jest.mocked(post).mockResolvedValueOnce({\n res: /** @type {IncomingMessage} */ ({\n statusCode: 500,\n headers: {}\n }),\n payload: capturePaymentResult,\n error: undefined\n })\n\n const captureResult = await service.capturePayment('payment-id-12345')\n expect(captureResult).toBe(false)\n })\n\n it('should throw when internal error', async () => {\n jest\n .mocked(post)\n .mockRejectedValueOnce(new Error('internal capture error'))\n\n await expect(() =>\n service.capturePayment('payment-id-12345')\n ).rejects.toThrow('internal capture error')\n })\n })\n})\n\n/**\n * @import { IncomingMessage } from 'node:http'\n */\n"],"mappings":"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","ignoreList":[]}
|