@defra/forms-engine-plugin 4.0.43 → 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.
Files changed (142) hide show
  1. package/.public/stylesheets/application.min.css +1 -1
  2. package/.public/stylesheets/application.min.css.map +1 -1
  3. package/.server/client/stylesheets/_payment-field.scss +8 -0
  4. package/.server/client/stylesheets/application.scss +2 -0
  5. package/.server/index.js +3 -1
  6. package/.server/index.js.map +1 -1
  7. package/.server/server/constants.d.ts +1 -0
  8. package/.server/server/constants.js +1 -0
  9. package/.server/server/constants.js.map +1 -1
  10. package/.server/server/forms/payment-test.yaml +42 -0
  11. package/.server/server/forms/register-as-a-unicorn-breeder.yaml +14 -0
  12. package/.server/server/plugins/engine/components/FormComponent.d.ts +1 -0
  13. package/.server/server/plugins/engine/components/FormComponent.js +1 -0
  14. package/.server/server/plugins/engine/components/FormComponent.js.map +1 -1
  15. package/.server/server/plugins/engine/components/PaymentField.d.ts +135 -0
  16. package/.server/server/plugins/engine/components/PaymentField.js +228 -0
  17. package/.server/server/plugins/engine/components/PaymentField.js.map +1 -0
  18. package/.server/server/plugins/engine/components/PaymentField.types.d.ts +21 -0
  19. package/.server/server/plugins/engine/components/PaymentField.types.js +2 -0
  20. package/.server/server/plugins/engine/components/PaymentField.types.js.map +1 -0
  21. package/.server/server/plugins/engine/components/UkAddressField.d.ts +1 -1
  22. package/.server/server/plugins/engine/components/UkAddressField.js +3 -1
  23. package/.server/server/plugins/engine/components/UkAddressField.js.map +1 -1
  24. package/.server/server/plugins/engine/components/helpers/components.d.ts +1 -1
  25. package/.server/server/plugins/engine/components/helpers/components.js +3 -0
  26. package/.server/server/plugins/engine/components/helpers/components.js.map +1 -1
  27. package/.server/server/plugins/engine/components/index.d.ts +1 -0
  28. package/.server/server/plugins/engine/components/index.js +1 -0
  29. package/.server/server/plugins/engine/components/index.js.map +1 -1
  30. package/.server/server/plugins/engine/helpers.d.ts +1 -0
  31. package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +3 -0
  32. package/.server/server/plugins/engine/models/SummaryViewModel.js +7 -0
  33. package/.server/server/plugins/engine/models/SummaryViewModel.js.map +1 -1
  34. package/.server/server/plugins/engine/outputFormatters/human/v1.js +34 -1
  35. package/.server/server/plugins/engine/outputFormatters/human/v1.js.map +1 -1
  36. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +22 -0
  37. package/.server/server/plugins/engine/outputFormatters/machine/v2.js +43 -1
  38. package/.server/server/plugins/engine/outputFormatters/machine/v2.js.map +1 -1
  39. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js +29 -8
  40. package/.server/server/plugins/engine/pageControllers/QuestionPageController.js.map +1 -1
  41. package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +2 -0
  42. package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +17 -0
  43. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js +173 -51
  44. package/.server/server/plugins/engine/pageControllers/SummaryPageController.js.map +1 -1
  45. package/.server/server/plugins/engine/pageControllers/errors.d.ts +31 -0
  46. package/.server/server/plugins/engine/pageControllers/errors.js +59 -2
  47. package/.server/server/plugins/engine/pageControllers/errors.js.map +1 -1
  48. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +27 -0
  49. package/.server/server/plugins/engine/pageControllers/helpers/submission.js +77 -0
  50. package/.server/server/plugins/engine/pageControllers/helpers/submission.js.map +1 -0
  51. package/.server/server/plugins/engine/plugin.js +4 -1
  52. package/.server/server/plugins/engine/plugin.js.map +1 -1
  53. package/.server/server/plugins/engine/routes/index.js +8 -4
  54. package/.server/server/plugins/engine/routes/index.js.map +1 -1
  55. package/.server/server/plugins/engine/routes/payment-helper.d.ts +14 -0
  56. package/.server/server/plugins/engine/routes/payment-helper.js +41 -0
  57. package/.server/server/plugins/engine/routes/payment-helper.js.map +1 -0
  58. package/.server/server/plugins/engine/routes/payment-helper.test.js +81 -0
  59. package/.server/server/plugins/engine/routes/payment-helper.test.js.map +1 -0
  60. package/.server/server/plugins/engine/routes/payment.d.ts +8 -0
  61. package/.server/server/plugins/engine/routes/payment.js +140 -0
  62. package/.server/server/plugins/engine/routes/payment.js.map +1 -0
  63. package/.server/server/plugins/engine/routes/payment.test.js +187 -0
  64. package/.server/server/plugins/engine/routes/payment.test.js.map +1 -0
  65. package/.server/server/plugins/engine/services/localFormsService.js +6 -0
  66. package/.server/server/plugins/engine/services/localFormsService.js.map +1 -1
  67. package/.server/server/plugins/engine/types/schema.js +7 -0
  68. package/.server/server/plugins/engine/types/schema.js.map +1 -1
  69. package/.server/server/plugins/engine/types.d.ts +19 -1
  70. package/.server/server/plugins/engine/types.js +4 -0
  71. package/.server/server/plugins/engine/types.js.map +1 -1
  72. package/.server/server/plugins/engine/validationHelpers.d.ts +1 -1
  73. package/.server/server/plugins/engine/validationHelpers.js.map +1 -1
  74. package/.server/server/plugins/engine/views/components/paymentfield.html +42 -0
  75. package/.server/server/plugins/engine/views/index.html +9 -1
  76. package/.server/server/plugins/engine/views/partials/form.html +20 -5
  77. package/.server/server/plugins/engine/views/summary.html +17 -1
  78. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  79. package/.server/server/plugins/payment/helper.d.ts +30 -0
  80. package/.server/server/plugins/payment/helper.js +49 -0
  81. package/.server/server/plugins/payment/helper.js.map +1 -0
  82. package/.server/server/plugins/payment/helper.test.js +37 -0
  83. package/.server/server/plugins/payment/helper.test.js.map +1 -0
  84. package/.server/server/plugins/payment/service.d.ts +40 -0
  85. package/.server/server/plugins/payment/service.js +129 -0
  86. package/.server/server/plugins/payment/service.js.map +1 -0
  87. package/.server/server/plugins/payment/service.test.js +162 -0
  88. package/.server/server/plugins/payment/service.test.js.map +1 -0
  89. package/.server/server/plugins/payment/types.d.ts +172 -0
  90. package/.server/server/plugins/payment/types.js +78 -0
  91. package/.server/server/plugins/payment/types.js.map +1 -0
  92. package/.server/server/types.d.ts +2 -0
  93. package/.server/server/types.js.map +1 -1
  94. package/.server/typings/hapi/index.d.js.map +1 -1
  95. package/README.md +12 -9
  96. package/package.json +2 -2
  97. package/src/client/stylesheets/_payment-field.scss +8 -0
  98. package/src/client/stylesheets/application.scss +2 -0
  99. package/src/index.ts +5 -1
  100. package/src/server/constants.js +1 -0
  101. package/src/server/forms/payment-test.yaml +42 -0
  102. package/src/server/forms/register-as-a-unicorn-breeder.yaml +14 -0
  103. package/src/server/plugins/engine/components/FormComponent.ts +1 -0
  104. package/src/server/plugins/engine/components/PaymentField.test.ts +611 -0
  105. package/src/server/plugins/engine/components/PaymentField.ts +367 -0
  106. package/src/server/plugins/engine/components/PaymentField.types.ts +21 -0
  107. package/src/server/plugins/engine/components/UkAddressField.ts +2 -1
  108. package/src/server/plugins/engine/components/helpers/components.ts +5 -0
  109. package/src/server/plugins/engine/components/index.ts +1 -0
  110. package/src/server/plugins/engine/models/SummaryViewModel.ts +8 -0
  111. package/src/server/plugins/engine/outputFormatters/human/v1.payment.test.ts +147 -0
  112. package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +105 -103
  113. package/src/server/plugins/engine/outputFormatters/human/v1.ts +61 -2
  114. package/src/server/plugins/engine/outputFormatters/machine/v2.payment.test.ts +115 -0
  115. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +60 -1
  116. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +32 -6
  117. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +247 -72
  118. package/src/server/plugins/engine/pageControllers/errors.test.ts +13 -1
  119. package/src/server/plugins/engine/pageControllers/errors.ts +79 -4
  120. package/src/server/plugins/engine/pageControllers/helpers/submission.test.ts +299 -0
  121. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +110 -0
  122. package/src/server/plugins/engine/plugin.ts +11 -6
  123. package/src/server/plugins/engine/routes/index.ts +17 -16
  124. package/src/server/plugins/engine/routes/payment-helper.js +39 -0
  125. package/src/server/plugins/engine/routes/payment-helper.test.js +90 -0
  126. package/src/server/plugins/engine/routes/payment.js +151 -0
  127. package/src/server/plugins/engine/routes/payment.test.js +180 -0
  128. package/src/server/plugins/engine/services/localFormsService.js +7 -0
  129. package/src/server/plugins/engine/types/schema.ts +9 -0
  130. package/src/server/plugins/engine/types.ts +24 -1
  131. package/src/server/plugins/engine/validationHelpers.ts +1 -1
  132. package/src/server/plugins/engine/views/components/paymentfield.html +42 -0
  133. package/src/server/plugins/engine/views/index.html +9 -1
  134. package/src/server/plugins/engine/views/partials/form.html +20 -5
  135. package/src/server/plugins/engine/views/summary.html +17 -1
  136. package/src/server/plugins/payment/helper.js +56 -0
  137. package/src/server/plugins/payment/helper.test.js +52 -0
  138. package/src/server/plugins/payment/service.js +171 -0
  139. package/src/server/plugins/payment/service.test.js +205 -0
  140. package/src/server/plugins/payment/types.js +77 -0
  141. package/src/server/types.ts +2 -0
  142. package/src/typings/hapi/index.d.ts +1 -0
@@ -0,0 +1,8 @@
1
+ @use "govuk-frontend" as *;
2
+
3
+ .app-payment-field {
4
+ background-color: govuk-colour("light-grey");
5
+ border-top: 5px solid govuk-colour("blue");
6
+ padding: govuk-spacing(4);
7
+ margin-bottom: govuk-spacing(6);
8
+ }
@@ -2,6 +2,8 @@
2
2
  @use "shared";
3
3
  @use "code";
4
4
  @use "tag-env";
5
+ @use "location-fields";
6
+ @use "payment-field";
5
7
 
6
8
  // An example of some user-supplied styling
7
9
  // Not great practice but it illustrates the point
package/.server/index.js CHANGED
@@ -17,7 +17,9 @@ const ordnanceSurveyApiKey = config.get('ordnanceSurveyApiKey');
17
17
  */
18
18
  async function startServer() {
19
19
  const server = await createServer({
20
- ordnanceSurveyApiKey
20
+ ordnanceSurveyApiKey,
21
+ // Enable save and exit for devserver
22
+ saveAndExit: (_request, h) => h.redirect('/')
21
23
  });
22
24
  await server.start();
23
25
  process.send?.('online');
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["getErrorMessage","config","createLogger","createServer","logger","process","on","error","err","info","port","get","ordnanceSurveyApiKey","startServer","server","start","send","catch"],"sources":["../src/index.ts"],"sourcesContent":["import { getErrorMessage } from '@defra/forms-model'\n\nimport { config } from '~/src/config/index.js'\nimport { createLogger } from '~/src/server/common/helpers/logging/logger.js'\nimport { createServer } from '~/src/server/index.js'\n\nconst logger = createLogger()\n\nprocess.on('unhandledRejection', (error) => {\n const err = getErrorMessage(error)\n logger.info('Unhandled rejection')\n logger.error(\n error,\n `[unhandledRejection] Unhandled promise rejection: ${err}`\n )\n throw error\n})\n\nconst port = config.get('port')\nconst ordnanceSurveyApiKey = config.get('ordnanceSurveyApiKey')\n\n/**\n * Main entrypoint to the application.\n */\nasync function startServer() {\n const server = await createServer({ ordnanceSurveyApiKey })\n await server.start()\n\n process.send?.('online')\n\n server.logger.info('Server started successfully')\n server.logger.info(`Access your frontend on http://localhost:${port}`)\n}\n\nstartServer().catch((error: unknown) => {\n const err = getErrorMessage(error)\n logger.info('Server failed to start :(')\n logger.error(error, `[serverStartup] Server failed to start: ${err}`)\n throw error\n})\n"],"mappings":"AAAA,SAASA,eAAe,QAAQ,oBAAoB;AAEpD,SAASC,MAAM;AACf,SAASC,YAAY;AACrB,SAASC,YAAY;AAErB,MAAMC,MAAM,GAAGF,YAAY,CAAC,CAAC;AAE7BG,OAAO,CAACC,EAAE,CAAC,oBAAoB,EAAGC,KAAK,IAAK;EAC1C,MAAMC,GAAG,GAAGR,eAAe,CAACO,KAAK,CAAC;EAClCH,MAAM,CAACK,IAAI,CAAC,qBAAqB,CAAC;EAClCL,MAAM,CAACG,KAAK,CACVA,KAAK,EACL,qDAAqDC,GAAG,EAC1D,CAAC;EACD,MAAMD,KAAK;AACb,CAAC,CAAC;AAEF,MAAMG,IAAI,GAAGT,MAAM,CAACU,GAAG,CAAC,MAAM,CAAC;AAC/B,MAAMC,oBAAoB,GAAGX,MAAM,CAACU,GAAG,CAAC,sBAAsB,CAAC;;AAE/D;AACA;AACA;AACA,eAAeE,WAAWA,CAAA,EAAG;EAC3B,MAAMC,MAAM,GAAG,MAAMX,YAAY,CAAC;IAAES;EAAqB,CAAC,CAAC;EAC3D,MAAME,MAAM,CAACC,KAAK,CAAC,CAAC;EAEpBV,OAAO,CAACW,IAAI,GAAG,QAAQ,CAAC;EAExBF,MAAM,CAACV,MAAM,CAACK,IAAI,CAAC,6BAA6B,CAAC;EACjDK,MAAM,CAACV,MAAM,CAACK,IAAI,CAAC,4CAA4CC,IAAI,EAAE,CAAC;AACxE;AAEAG,WAAW,CAAC,CAAC,CAACI,KAAK,CAAEV,KAAc,IAAK;EACtC,MAAMC,GAAG,GAAGR,eAAe,CAACO,KAAK,CAAC;EAClCH,MAAM,CAACK,IAAI,CAAC,2BAA2B,CAAC;EACxCL,MAAM,CAACG,KAAK,CAACA,KAAK,EAAE,2CAA2CC,GAAG,EAAE,CAAC;EACrE,MAAMD,KAAK;AACb,CAAC,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"index.js","names":["getErrorMessage","config","createLogger","createServer","logger","process","on","error","err","info","port","get","ordnanceSurveyApiKey","startServer","server","saveAndExit","_request","h","redirect","start","send","catch"],"sources":["../src/index.ts"],"sourcesContent":["import { getErrorMessage } from '@defra/forms-model'\n\nimport { config } from '~/src/config/index.js'\nimport { createLogger } from '~/src/server/common/helpers/logging/logger.js'\nimport { createServer } from '~/src/server/index.js'\n\nconst logger = createLogger()\n\nprocess.on('unhandledRejection', (error) => {\n const err = getErrorMessage(error)\n logger.info('Unhandled rejection')\n logger.error(\n error,\n `[unhandledRejection] Unhandled promise rejection: ${err}`\n )\n throw error\n})\n\nconst port = config.get('port')\nconst ordnanceSurveyApiKey = config.get('ordnanceSurveyApiKey')\n\n/**\n * Main entrypoint to the application.\n */\nasync function startServer() {\n const server = await createServer({\n ordnanceSurveyApiKey,\n // Enable save and exit for devserver\n saveAndExit: (_request, h) => h.redirect('/')\n })\n await server.start()\n\n process.send?.('online')\n\n server.logger.info('Server started successfully')\n server.logger.info(`Access your frontend on http://localhost:${port}`)\n}\n\nstartServer().catch((error: unknown) => {\n const err = getErrorMessage(error)\n logger.info('Server failed to start :(')\n logger.error(error, `[serverStartup] Server failed to start: ${err}`)\n throw error\n})\n"],"mappings":"AAAA,SAASA,eAAe,QAAQ,oBAAoB;AAEpD,SAASC,MAAM;AACf,SAASC,YAAY;AACrB,SAASC,YAAY;AAErB,MAAMC,MAAM,GAAGF,YAAY,CAAC,CAAC;AAE7BG,OAAO,CAACC,EAAE,CAAC,oBAAoB,EAAGC,KAAK,IAAK;EAC1C,MAAMC,GAAG,GAAGR,eAAe,CAACO,KAAK,CAAC;EAClCH,MAAM,CAACK,IAAI,CAAC,qBAAqB,CAAC;EAClCL,MAAM,CAACG,KAAK,CACVA,KAAK,EACL,qDAAqDC,GAAG,EAC1D,CAAC;EACD,MAAMD,KAAK;AACb,CAAC,CAAC;AAEF,MAAMG,IAAI,GAAGT,MAAM,CAACU,GAAG,CAAC,MAAM,CAAC;AAC/B,MAAMC,oBAAoB,GAAGX,MAAM,CAACU,GAAG,CAAC,sBAAsB,CAAC;;AAE/D;AACA;AACA;AACA,eAAeE,WAAWA,CAAA,EAAG;EAC3B,MAAMC,MAAM,GAAG,MAAMX,YAAY,CAAC;IAChCS,oBAAoB;IACpB;IACAG,WAAW,EAAEA,CAACC,QAAQ,EAAEC,CAAC,KAAKA,CAAC,CAACC,QAAQ,CAAC,GAAG;EAC9C,CAAC,CAAC;EACF,MAAMJ,MAAM,CAACK,KAAK,CAAC,CAAC;EAEpBd,OAAO,CAACe,IAAI,GAAG,QAAQ,CAAC;EAExBN,MAAM,CAACV,MAAM,CAACK,IAAI,CAAC,6BAA6B,CAAC;EACjDK,MAAM,CAACV,MAAM,CAACK,IAAI,CAAC,4CAA4CC,IAAI,EAAE,CAAC;AACxE;AAEAG,WAAW,CAAC,CAAC,CAACQ,KAAK,CAAEd,KAAc,IAAK;EACtC,MAAMC,GAAG,GAAGR,eAAe,CAACO,KAAK,CAAC;EAClCH,MAAM,CAACK,IAAI,CAAC,2BAA2B,CAAC;EACxCL,MAAM,CAACG,KAAK,CAACA,KAAK,EAAE,2CAA2CC,GAAG,EAAE,CAAC;EACrE,MAAMD,KAAK;AACb,CAAC,CAAC","ignoreList":[]}
@@ -3,3 +3,4 @@ export const FORM_PREFIX: "";
3
3
  export const EXTERNAL_STATE_PAYLOAD: "EXTERNAL_STATE_PAYLOAD";
4
4
  export const EXTERNAL_STATE_APPENDAGE: "EXTERNAL_STATE_APPENDAGE";
5
5
  export const COMPONENT_STATE_ERROR: "COMPONENT_STATE_ERROR";
6
+ export const PAYMENT_EXPIRED_NOTIFICATION: "PAYMENT_EXPIRED_NOTIFICATION";
@@ -3,4 +3,5 @@ export const FORM_PREFIX = '';
3
3
  export const EXTERNAL_STATE_PAYLOAD = 'EXTERNAL_STATE_PAYLOAD';
4
4
  export const EXTERNAL_STATE_APPENDAGE = 'EXTERNAL_STATE_APPENDAGE';
5
5
  export const COMPONENT_STATE_ERROR = 'COMPONENT_STATE_ERROR';
6
+ export const PAYMENT_EXPIRED_NOTIFICATION = 'PAYMENT_EXPIRED_NOTIFICATION';
6
7
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","names":["PREVIEW_PATH_PREFIX","FORM_PREFIX","EXTERNAL_STATE_PAYLOAD","EXTERNAL_STATE_APPENDAGE","COMPONENT_STATE_ERROR"],"sources":["../../src/server/constants.js"],"sourcesContent":["export const PREVIEW_PATH_PREFIX = '/preview'\nexport const FORM_PREFIX = ''\nexport const EXTERNAL_STATE_PAYLOAD = 'EXTERNAL_STATE_PAYLOAD'\nexport const EXTERNAL_STATE_APPENDAGE = 'EXTERNAL_STATE_APPENDAGE'\nexport const COMPONENT_STATE_ERROR = 'COMPONENT_STATE_ERROR'\n"],"mappings":"AAAA,OAAO,MAAMA,mBAAmB,GAAG,UAAU;AAC7C,OAAO,MAAMC,WAAW,GAAG,EAAE;AAC7B,OAAO,MAAMC,sBAAsB,GAAG,wBAAwB;AAC9D,OAAO,MAAMC,wBAAwB,GAAG,0BAA0B;AAClE,OAAO,MAAMC,qBAAqB,GAAG,uBAAuB","ignoreList":[]}
1
+ {"version":3,"file":"constants.js","names":["PREVIEW_PATH_PREFIX","FORM_PREFIX","EXTERNAL_STATE_PAYLOAD","EXTERNAL_STATE_APPENDAGE","COMPONENT_STATE_ERROR","PAYMENT_EXPIRED_NOTIFICATION"],"sources":["../../src/server/constants.js"],"sourcesContent":["export const PREVIEW_PATH_PREFIX = '/preview'\nexport const FORM_PREFIX = ''\nexport const EXTERNAL_STATE_PAYLOAD = 'EXTERNAL_STATE_PAYLOAD'\nexport const EXTERNAL_STATE_APPENDAGE = 'EXTERNAL_STATE_APPENDAGE'\nexport const COMPONENT_STATE_ERROR = 'COMPONENT_STATE_ERROR'\nexport const PAYMENT_EXPIRED_NOTIFICATION = 'PAYMENT_EXPIRED_NOTIFICATION'\n"],"mappings":"AAAA,OAAO,MAAMA,mBAAmB,GAAG,UAAU;AAC7C,OAAO,MAAMC,WAAW,GAAG,EAAE;AAC7B,OAAO,MAAMC,sBAAsB,GAAG,wBAAwB;AAC9D,OAAO,MAAMC,wBAAwB,GAAG,0BAA0B;AAClE,OAAO,MAAMC,qBAAqB,GAAG,uBAAuB;AAC5D,OAAO,MAAMC,4BAA4B,GAAG,8BAA8B","ignoreList":[]}
@@ -0,0 +1,42 @@
1
+ ---
2
+ schema: 2
3
+ name: Payment Test Form
4
+ declaration: "<p class=\"govuk-body\">All the answers you have provided are true to the best of your knowledge.</p>"
5
+ pages:
6
+ - title: What is your name?
7
+ path: '/person'
8
+ components:
9
+ - name: personName
10
+ title: What is your name?
11
+ type: TextField
12
+ shortDescription: Your name
13
+ options:
14
+ required: true
15
+ next:
16
+ - path: '/pay-for-your-licence'
17
+ - title: A page title
18
+ path: '/pay-for-your-licence'
19
+ components:
20
+ - name: pageGuidance
21
+ type: Html
22
+ title: Guidance
23
+ content: "<p class=\"govuk-body\">Random guidance</p>"
24
+ options: {}
25
+ - name: licencePayment
26
+ title: Payment details required
27
+ type: PaymentField
28
+ options:
29
+ required: true
30
+ amount: 300
31
+ description: Processing fee for your application.
32
+ next:
33
+ - path: '/summary'
34
+ - title: Summary
35
+ path: '/summary'
36
+ controller: './pages/summary.js'
37
+ components: []
38
+ next: []
39
+ conditions: []
40
+ sections: []
41
+ lists: []
42
+ startPage: '/person'
@@ -242,6 +242,20 @@ pages:
242
242
  content: 'Fill in this field'
243
243
  options:
244
244
  required: false
245
+ next:
246
+ - path: '/pay-for-your-licence'
247
+ - title: Pay for your licence
248
+ path: '/pay-for-your-licence'
249
+ section: section
250
+ components:
251
+ - name: licencePayment
252
+ title: Unicorn breeder licence fee
253
+ type: PaymentField
254
+ hint: You'll be redirected to GOV.UK Pay to complete your payment
255
+ options:
256
+ required: true
257
+ amount: 50
258
+ description: Unicorn breeder annual licence fee
245
259
  next:
246
260
  - path: '/summary'
247
261
  conditions:
@@ -7,6 +7,7 @@ export declare class FormComponent extends ComponentBase {
7
7
  hint: FormComponentsDef['hint'];
8
8
  label: string;
9
9
  isFormComponent: boolean;
10
+ isAppendageStateSingleObject: boolean;
10
11
  constructor(def: FormComponentsDef, props: ConstructorParameters<typeof ComponentBase>[1]);
11
12
  get keys(): string[];
12
13
  getFormDataFromState(state: FormSubmissionState): FormPayload;
@@ -5,6 +5,7 @@ export class FormComponent extends ComponentBase {
5
5
  hint;
6
6
  label;
7
7
  isFormComponent = true;
8
+ isAppendageStateSingleObject = false;
8
9
  constructor(def, props) {
9
10
  super(def, props);
10
11
  const {
@@ -1 +1 @@
1
- {"version":3,"file":"FormComponent.js","names":["ComponentBase","optionalText","FormComponent","type","hint","label","isFormComponent","constructor","def","props","shortDescription","title","keys","collection","name","fields","map","getFormDataFromState","state","getFormValue","getFormValueFromState","value","isValue","undefined","getStateFromValidForm","payload","getErrors","errors","list","filter","error","path","includes","length","getFirstError","getViewErrors","firstError","getViewModel","options","viewModel","isRequired","required","hideOptional","text","componentErrors","componentError","errorMessage","id","getDisplayStringFromFormValue","toString","getDisplayStringFromState","getContextValueFromFormValue","isState","values","Object","isFormValue","Array","isArray","getContextValueFromState","isFormState","getAllPossibleErrors","baseErrors","advancedSettingsErrors","onSubmit","_request","_metadata","_context","Promise","resolve","isRepeatState","every","isRepeatValue","itemId","isUploadState","isUploadValue","uploadId"],"sources":["../../../../../src/server/plugins/engine/components/FormComponent.ts"],"sourcesContent":["import {\n type FormComponentsDef,\n type FormMetadata,\n type Item\n} from '@defra/forms-model'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { optionalText } from '~/src/server/plugins/engine/components/constants.js'\nimport {\n type FormContext,\n type FormRequestPayload\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type FileState,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue,\n type RepeatItemState,\n type RepeatListState,\n type UploadState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class FormComponent extends ComponentBase {\n type: FormComponentsDef['type']\n hint: FormComponentsDef['hint']\n label: string\n\n isFormComponent = true\n\n constructor(\n def: FormComponentsDef,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { hint, type } = def\n\n this.type = type\n this.hint = hint\n this.label =\n 'shortDescription' in def && def.shortDescription\n ? def.shortDescription\n : def.title\n }\n\n get keys() {\n const { collection, name } = this\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormDataFromState(state)\n }\n\n return {\n [name]: this.getFormValue(state[name])\n }\n }\n\n getFormValueFromState(state: FormSubmissionState): FormValue | FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormValueFromState(state)\n }\n\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { collection, name } = this\n\n if (collection) {\n return collection.getStateFromValidForm(payload)\n }\n\n return {\n [name]: this.getFormValue(payload[name]) ?? null\n }\n }\n\n getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {\n const { name } = this\n\n // Filter component and child errors only\n const list = errors?.filter(\n (error) =>\n error.name === name ||\n error.path.includes(name) ||\n this.keys.includes(error.name)\n )\n\n if (!list?.length) {\n return\n }\n\n return list\n }\n\n getFirstError(\n errors?: FormSubmissionError[]\n ): FormSubmissionError | undefined {\n return this.getErrors(errors)?.[0]\n }\n\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const firstError = this.getFirstError(errors)\n return firstError && [firstError]\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const { hint, name, options = {}, title, viewModel } = this\n\n const isRequired = !('required' in options) || options.required !== false\n const hideOptional = 'optionalText' in options && options.optionalText\n const label = `${title}${!isRequired && !hideOptional ? optionalText : ''}`\n\n if (hint) {\n viewModel.hint = {\n text: hint\n }\n }\n\n // Filter component errors only\n const componentErrors = this.getErrors(errors)\n const componentError = this.getFirstError(componentErrors)\n\n if (componentErrors) {\n viewModel.errors = componentErrors\n }\n\n if (componentError) {\n viewModel.errorMessage = {\n text: componentError.text\n }\n }\n\n return {\n ...viewModel,\n label: {\n text: label\n },\n id: name,\n name,\n value: payload[name]\n }\n }\n\n getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n // Map selected values to text\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return this.isValue(value) ? value.toString() : ''\n }\n\n getDisplayStringFromState(state: FormSubmissionState): string {\n const value = this.getFormValueFromState(state)\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return this.getDisplayStringFromFormValue(value)\n }\n\n getContextValueFromFormValue(\n value: FormValue | FormPayload\n ): Item['value'] | Item['value'][] | null {\n // Filter object field values\n if (this.isState(value)) {\n const values = Object.values(value).filter(isFormValue)\n return values.length ? values : null\n }\n\n // Filter array field values\n if (this.isValue(value) && Array.isArray(value)) {\n return value.filter(isFormValue)\n }\n\n return this.isValue(value) ? value : null\n }\n\n getContextValueFromState(\n state: FormSubmissionState\n ): Item['value'] | Item['value'][] | null {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n isValue(\n value?: FormStateValue | FormState\n ): value is NonNullable<FormStateValue> {\n return isFormValue(value)\n }\n\n isState(value?: FormStateValue | FormState): value is FormState {\n return isFormState(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return FormComponent.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [],\n advancedSettingsErrors: []\n }\n }\n\n onSubmit(\n _request: FormRequestPayload,\n _metadata: FormMetadata,\n _context: FormContext\n ): Promise<void> {\n return Promise.resolve()\n }\n}\n\n/**\n * Check for form value\n */\nexport function isFormValue(\n value?: unknown\n): value is string | number | boolean {\n return (\n (typeof value === 'string' && value.length > 0) ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n )\n}\n\n/**\n * Check for form state with nested values\n */\nexport function isFormState(value?: unknown): value is FormState {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n // Skip empty objects\n return !!Object.values(value).length\n}\n\n/**\n * Check for repeat list state\n */\nexport function isRepeatState(value?: unknown): value is RepeatListState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isRepeatValue)\n}\n\n/**\n * Check for repeat list value\n */\nexport function isRepeatValue(value?: unknown): value is RepeatItemState {\n return isFormState(value) && typeof value.itemId === 'string'\n}\n\n/**\n * Check for upload state\n */\nexport function isUploadState(value?: unknown): value is UploadState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isUploadValue)\n}\n\n/**\n * Check for upload state value\n */\nexport function isUploadValue(value?: unknown): value is FileState {\n return isFormState(value) && typeof value.uploadId === 'string'\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"FormComponent.js","names":["ComponentBase","optionalText","FormComponent","type","hint","label","isFormComponent","isAppendageStateSingleObject","constructor","def","props","shortDescription","title","keys","collection","name","fields","map","getFormDataFromState","state","getFormValue","getFormValueFromState","value","isValue","undefined","getStateFromValidForm","payload","getErrors","errors","list","filter","error","path","includes","length","getFirstError","getViewErrors","firstError","getViewModel","options","viewModel","isRequired","required","hideOptional","text","componentErrors","componentError","errorMessage","id","getDisplayStringFromFormValue","toString","getDisplayStringFromState","getContextValueFromFormValue","isState","values","Object","isFormValue","Array","isArray","getContextValueFromState","isFormState","getAllPossibleErrors","baseErrors","advancedSettingsErrors","onSubmit","_request","_metadata","_context","Promise","resolve","isRepeatState","every","isRepeatValue","itemId","isUploadState","isUploadValue","uploadId"],"sources":["../../../../../src/server/plugins/engine/components/FormComponent.ts"],"sourcesContent":["import {\n type FormComponentsDef,\n type FormMetadata,\n type Item\n} from '@defra/forms-model'\n\nimport { ComponentBase } from '~/src/server/plugins/engine/components/ComponentBase.js'\nimport { optionalText } from '~/src/server/plugins/engine/components/constants.js'\nimport {\n type FormContext,\n type FormRequestPayload\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type FileState,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState,\n type FormValue,\n type RepeatItemState,\n type RepeatListState,\n type UploadState\n} from '~/src/server/plugins/engine/types.js'\n\nexport class FormComponent extends ComponentBase {\n type: FormComponentsDef['type']\n hint: FormComponentsDef['hint']\n label: string\n\n isFormComponent = true\n isAppendageStateSingleObject = false\n\n constructor(\n def: FormComponentsDef,\n props: ConstructorParameters<typeof ComponentBase>[1]\n ) {\n super(def, props)\n\n const { hint, type } = def\n\n this.type = type\n this.hint = hint\n this.label =\n 'shortDescription' in def && def.shortDescription\n ? def.shortDescription\n : def.title\n }\n\n get keys() {\n const { collection, name } = this\n\n if (collection) {\n const { fields } = collection\n return [name, ...fields.map(({ name }) => name)]\n }\n\n return [name]\n }\n\n getFormDataFromState(state: FormSubmissionState): FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormDataFromState(state)\n }\n\n return {\n [name]: this.getFormValue(state[name])\n }\n }\n\n getFormValueFromState(state: FormSubmissionState): FormValue | FormPayload {\n const { collection, name } = this\n\n if (collection) {\n return collection.getFormValueFromState(state)\n }\n\n return this.getFormValue(state[name])\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isValue(value) ? value : undefined\n }\n\n getStateFromValidForm(payload: FormPayload): FormState {\n const { collection, name } = this\n\n if (collection) {\n return collection.getStateFromValidForm(payload)\n }\n\n return {\n [name]: this.getFormValue(payload[name]) ?? null\n }\n }\n\n getErrors(errors?: FormSubmissionError[]): FormSubmissionError[] | undefined {\n const { name } = this\n\n // Filter component and child errors only\n const list = errors?.filter(\n (error) =>\n error.name === name ||\n error.path.includes(name) ||\n this.keys.includes(error.name)\n )\n\n if (!list?.length) {\n return\n }\n\n return list\n }\n\n getFirstError(\n errors?: FormSubmissionError[]\n ): FormSubmissionError | undefined {\n return this.getErrors(errors)?.[0]\n }\n\n getViewErrors(\n errors?: FormSubmissionError[]\n ): FormSubmissionError[] | undefined {\n const firstError = this.getFirstError(errors)\n return firstError && [firstError]\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const { hint, name, options = {}, title, viewModel } = this\n\n const isRequired = !('required' in options) || options.required !== false\n const hideOptional = 'optionalText' in options && options.optionalText\n const label = `${title}${!isRequired && !hideOptional ? optionalText : ''}`\n\n if (hint) {\n viewModel.hint = {\n text: hint\n }\n }\n\n // Filter component errors only\n const componentErrors = this.getErrors(errors)\n const componentError = this.getFirstError(componentErrors)\n\n if (componentErrors) {\n viewModel.errors = componentErrors\n }\n\n if (componentError) {\n viewModel.errorMessage = {\n text: componentError.text\n }\n }\n\n return {\n ...viewModel,\n label: {\n text: label\n },\n id: name,\n name,\n value: payload[name]\n }\n }\n\n getDisplayStringFromFormValue(value: FormValue | FormPayload): string {\n // Map selected values to text\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return this.isValue(value) ? value.toString() : ''\n }\n\n getDisplayStringFromState(state: FormSubmissionState): string {\n const value = this.getFormValueFromState(state)\n // eslint-disable-next-line @typescript-eslint/no-base-to-string\n return this.getDisplayStringFromFormValue(value)\n }\n\n getContextValueFromFormValue(\n value: FormValue | FormPayload\n ): Item['value'] | Item['value'][] | null {\n // Filter object field values\n if (this.isState(value)) {\n const values = Object.values(value).filter(isFormValue)\n return values.length ? values : null\n }\n\n // Filter array field values\n if (this.isValue(value) && Array.isArray(value)) {\n return value.filter(isFormValue)\n }\n\n return this.isValue(value) ? value : null\n }\n\n getContextValueFromState(\n state: FormSubmissionState\n ): Item['value'] | Item['value'][] | null {\n const value = this.getFormValueFromState(state)\n\n return this.getContextValueFromFormValue(value)\n }\n\n isValue(\n value?: FormStateValue | FormState\n ): value is NonNullable<FormStateValue> {\n return isFormValue(value)\n }\n\n isState(value?: FormStateValue | FormState): value is FormState {\n return isFormState(value)\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return FormComponent.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [],\n advancedSettingsErrors: []\n }\n }\n\n onSubmit(\n _request: FormRequestPayload,\n _metadata: FormMetadata,\n _context: FormContext\n ): Promise<void> {\n return Promise.resolve()\n }\n}\n\n/**\n * Check for form value\n */\nexport function isFormValue(\n value?: unknown\n): value is string | number | boolean {\n return (\n (typeof value === 'string' && value.length > 0) ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n )\n}\n\n/**\n * Check for form state with nested values\n */\nexport function isFormState(value?: unknown): value is FormState {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n // Skip empty objects\n return !!Object.values(value).length\n}\n\n/**\n * Check for repeat list state\n */\nexport function isRepeatState(value?: unknown): value is RepeatListState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isRepeatValue)\n}\n\n/**\n * Check for repeat list value\n */\nexport function isRepeatValue(value?: unknown): value is RepeatItemState {\n return isFormState(value) && typeof value.itemId === 'string'\n}\n\n/**\n * Check for upload state\n */\nexport function isUploadState(value?: unknown): value is UploadState {\n if (!Array.isArray(value)) {\n return false\n }\n\n // Skip checks when empty\n if (!value.length) {\n return true\n }\n\n return value.every(isUploadValue)\n}\n\n/**\n * Check for upload state value\n */\nexport function isUploadValue(value?: unknown): value is FileState {\n return isFormState(value) && typeof value.uploadId === 'string'\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,135 @@
1
+ import { type FormMetadata, type PaymentFieldComponent } from '@defra/forms-model';
2
+ import { type ObjectSchema } from 'joi';
3
+ import { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js';
4
+ import { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js';
5
+ import { type AnyFormRequest, type FormContext, type FormRequestPayload, type FormResponseToolkit } from '~/src/server/plugins/engine/types/index.js';
6
+ import { type ErrorMessageTemplateList, type FormPayload, type FormState, type FormStateValue, type FormSubmissionError, type FormSubmissionState } from '~/src/server/plugins/engine/types.js';
7
+ export declare class PaymentField extends FormComponent {
8
+ options: PaymentFieldComponent['options'];
9
+ formSchema: ObjectSchema;
10
+ stateSchema: ObjectSchema;
11
+ isAppendageStateSingleObject: boolean;
12
+ constructor(def: PaymentFieldComponent, props: ConstructorParameters<typeof FormComponent>[1]);
13
+ /**
14
+ * Gets the PaymentState from form submission state
15
+ */
16
+ getPaymentStateFromState(state: FormSubmissionState): PaymentState | undefined;
17
+ getDisplayStringFromState(state: FormSubmissionState): string;
18
+ getViewModel(payload: FormPayload, errors?: FormSubmissionError[]): {
19
+ amount: string;
20
+ description: string;
21
+ paymentState: PaymentState | undefined;
22
+ label: {
23
+ text: string;
24
+ };
25
+ id: string;
26
+ name: string;
27
+ value: import("~/src/server/plugins/engine/types.js").FormValue;
28
+ type?: string;
29
+ hint?: {
30
+ id?: string;
31
+ text: string;
32
+ };
33
+ prefix?: import("~/src/server/plugins/engine/types/index.js").ComponentText;
34
+ suffix?: import("~/src/server/plugins/engine/types/index.js").ComponentText;
35
+ classes?: string;
36
+ condition?: string;
37
+ errors?: FormSubmissionError[];
38
+ errorMessage?: {
39
+ text: string;
40
+ };
41
+ summaryHtml?: string;
42
+ html?: string;
43
+ attributes: {
44
+ autocomplete?: string;
45
+ maxlength?: number;
46
+ multiple?: string;
47
+ accept?: string;
48
+ inputmode?: string;
49
+ };
50
+ content?: import("~/src/server/plugins/engine/types/index.js").Content | import("~/src/server/plugins/engine/types/index.js").Content[] | string;
51
+ maxlength?: number;
52
+ maxwords?: number;
53
+ rows?: number;
54
+ items?: import("~/src/server/plugins/engine/types/index.js").ListItem[] | import("~/src/server/plugins/engine/types/index.js").DateInputItem[];
55
+ fieldset?: {
56
+ attributes?: string | Record<string, string>;
57
+ legend?: import("~/src/server/plugins/engine/types/index.js").Label;
58
+ };
59
+ formGroup?: {
60
+ classes?: string;
61
+ attributes?: string | Record<string, string>;
62
+ };
63
+ showFieldsetError?: boolean;
64
+ components?: import("~/src/server/plugins/engine/types/index.js").ComponentViewModel[];
65
+ upload?: {
66
+ count: number;
67
+ summaryList: import("~/src/server/plugins/engine/types.js").SummaryList;
68
+ };
69
+ };
70
+ /**
71
+ * Type guard to check if value is PaymentState
72
+ */
73
+ isPaymentState(value: unknown): value is PaymentState;
74
+ /**
75
+ * Static type guard to check if value is PaymentState
76
+ */
77
+ static isPaymentState(value: unknown): value is PaymentState;
78
+ /**
79
+ * Override base isState to validate PaymentState
80
+ */
81
+ isState(value?: FormStateValue | FormState): value is FormState;
82
+ getFormValue(value?: FormStateValue | FormState): NonNullable<FormStateValue> | undefined;
83
+ getContextValueFromState(state: FormSubmissionState): string;
84
+ /**
85
+ * For error preview page that shows all possible errors on a component
86
+ */
87
+ getAllPossibleErrors(): ErrorMessageTemplateList;
88
+ /**
89
+ * Static version of getAllPossibleErrors that doesn't require a component instance.
90
+ */
91
+ static getAllPossibleErrors(): ErrorMessageTemplateList;
92
+ /**
93
+ * Dispatcher for external redirect to GOV.UK Pay
94
+ */
95
+ static dispatcher(request: FormRequestPayload, h: FormResponseToolkit, args: PaymentDispatcherArgs): Promise<unknown>;
96
+ /**
97
+ * Called on form submission to capture the payment
98
+ * @see https://docs.payments.service.gov.uk/delayed_capture/#delay-taking-a-payment
99
+ */
100
+ onSubmit(request: FormRequestPayload, _metadata: FormMetadata, context: FormContext): Promise<void>;
101
+ /**
102
+ * Updates payment state to mark capture as successful
103
+ * This ensures we don't try to re-capture on submission retry
104
+ */
105
+ private markPaymentCaptured;
106
+ }
107
+ export interface PaymentDispatcherArgs {
108
+ controller: {
109
+ model: {
110
+ formId: string;
111
+ basePath: string;
112
+ name: string;
113
+ };
114
+ getState: (request: AnyFormRequest) => Promise<FormSubmissionState>;
115
+ };
116
+ component: PaymentField;
117
+ sourceUrl: string;
118
+ isLive: boolean;
119
+ isPreview: boolean;
120
+ }
121
+ /**
122
+ * Session data stored when dispatching to GOV.UK Pay
123
+ */
124
+ export interface PaymentSessionData {
125
+ uuid: string;
126
+ formId: string;
127
+ reference: string;
128
+ amount: number;
129
+ description: string;
130
+ paymentId: string;
131
+ componentName: string;
132
+ returnUrl: string;
133
+ failureUrl: string;
134
+ isLivePayment: boolean;
135
+ }
@@ -0,0 +1,228 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { StatusCodes } from 'http-status-codes';
3
+ import joi from 'joi';
4
+ import { FormComponent } from "./FormComponent.js";
5
+ import { getPluginOptions } from "../helpers.js";
6
+ import { PaymentErrorTypes, PaymentPreAuthError, PaymentSubmissionError } from "../pageControllers/errors.js";
7
+ import { createPaymentService } from "../../payment/helper.js";
8
+ export class PaymentField extends FormComponent {
9
+ isAppendageStateSingleObject = true;
10
+ constructor(def, props) {
11
+ super(def, props);
12
+ this.options = def.options;
13
+ const paymentStateSchema = joi.object({
14
+ paymentId: joi.string().required(),
15
+ reference: joi.string().required(),
16
+ amount: joi.number().required(),
17
+ description: joi.string().required(),
18
+ uuid: joi.string().uuid().required(),
19
+ formId: joi.string().required(),
20
+ isLivePayment: joi.boolean().required(),
21
+ preAuth: joi.object({
22
+ status: joi.string().valid('success', 'failed', 'started').required(),
23
+ createdAt: joi.string().isoDate().required()
24
+ }).required()
25
+ }).unknown(true).label(this.label);
26
+ this.formSchema = paymentStateSchema;
27
+ // 'required()' forces the payment page to be invalid until we have valid payment state
28
+ // i.e. the user will automatically be directed back to the payment page
29
+ // if they attempt to access future pages when no payment entered yet
30
+ this.stateSchema = paymentStateSchema.required();
31
+ }
32
+
33
+ /**
34
+ * Gets the PaymentState from form submission state
35
+ */
36
+ getPaymentStateFromState(state) {
37
+ const value = state[this.name];
38
+ return this.isPaymentState(value) ? value : undefined;
39
+ }
40
+ getDisplayStringFromState(state) {
41
+ const value = this.getPaymentStateFromState(state);
42
+ if (!value) {
43
+ return '';
44
+ }
45
+ return `£${value.amount.toFixed(2)} - ${value.description}`;
46
+ }
47
+ getViewModel(payload, errors) {
48
+ const viewModel = super.getViewModel(payload, errors);
49
+
50
+ // Payload is pre-populated from state if a payment has already been made
51
+ const paymentState = this.isPaymentState(payload[this.name]) ? payload[this.name] : undefined;
52
+
53
+ // When user initially visits the payment page, there is no payment state yet so the amount is read form the form definition.
54
+ const amount = paymentState?.amount ?? this.options.amount;
55
+ const formattedAmount = amount.toFixed(2);
56
+ return {
57
+ ...viewModel,
58
+ amount: formattedAmount,
59
+ description: this.options.description,
60
+ paymentState
61
+ };
62
+ }
63
+
64
+ /**
65
+ * Type guard to check if value is PaymentState
66
+ */
67
+ isPaymentState(value) {
68
+ return PaymentField.isPaymentState(value);
69
+ }
70
+
71
+ /**
72
+ * Static type guard to check if value is PaymentState
73
+ */
74
+ static isPaymentState(value) {
75
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
76
+ return false;
77
+ }
78
+ const state = value;
79
+ return typeof state.paymentId === 'string' && typeof state.amount === 'number' && typeof state.description === 'string';
80
+ }
81
+
82
+ /**
83
+ * Override base isState to validate PaymentState
84
+ */
85
+ isState(value) {
86
+ return this.isPaymentState(value);
87
+ }
88
+ getFormValue(value) {
89
+ return this.isPaymentState(value) ? value : undefined;
90
+ }
91
+ getContextValueFromState(state) {
92
+ return this.isPaymentState(state) ? `Reference: ${state.reference}\nAmount: ${state.amount.toFixed(2)}` : '';
93
+ }
94
+
95
+ /**
96
+ * For error preview page that shows all possible errors on a component
97
+ */
98
+ getAllPossibleErrors() {
99
+ return PaymentField.getAllPossibleErrors();
100
+ }
101
+
102
+ /**
103
+ * Static version of getAllPossibleErrors that doesn't require a component instance.
104
+ */
105
+ static getAllPossibleErrors() {
106
+ return {
107
+ baseErrors: [{
108
+ type: 'paymentRequired',
109
+ template: 'Complete the payment to continue'
110
+ }],
111
+ advancedSettingsErrors: []
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Dispatcher for external redirect to GOV.UK Pay
117
+ */
118
+ static async dispatcher(request, h, args) {
119
+ const {
120
+ options,
121
+ name: componentName
122
+ } = args.component;
123
+ const {
124
+ model
125
+ } = args.controller;
126
+ const state = await args.controller.getState(request);
127
+ const {
128
+ baseUrl
129
+ } = getPluginOptions(request.server);
130
+ const summaryUrl = `${baseUrl}/${model.basePath}/summary`;
131
+ const existingPaymentState = state[componentName];
132
+ if (PaymentField.isPaymentState(existingPaymentState) && existingPaymentState.preAuth?.status === 'success') {
133
+ return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER);
134
+ }
135
+ const isLivePayment = args.isLive && !args.isPreview;
136
+ const formId = args.controller.model.formId;
137
+ const paymentService = createPaymentService(isLivePayment, formId);
138
+ const uuid = randomUUID();
139
+ const reference = state.$$__referenceNumber;
140
+ const amount = options.amount;
141
+ const description = options.description;
142
+ const slug = `/${model.basePath}`;
143
+ const payCallbackUrl = `${baseUrl}/payment-callback?uuid=${uuid}`;
144
+ const paymentPageUrl = args.sourceUrl;
145
+ const amountInPence = Math.round(amount * 100);
146
+ const payment = await paymentService.createPayment(amountInPence, description, payCallbackUrl, reference, {
147
+ formId,
148
+ slug
149
+ });
150
+ const sessionData = {
151
+ uuid,
152
+ formId,
153
+ reference,
154
+ amount,
155
+ description,
156
+ paymentId: payment.paymentId,
157
+ componentName,
158
+ returnUrl: summaryUrl,
159
+ failureUrl: paymentPageUrl,
160
+ isLivePayment
161
+ };
162
+ request.yar.set(`payment-${uuid}`, sessionData);
163
+ return h.redirect(payment.paymentUrl).code(StatusCodes.SEE_OTHER);
164
+ }
165
+
166
+ /**
167
+ * Called on form submission to capture the payment
168
+ * @see https://docs.payments.service.gov.uk/delayed_capture/#delay-taking-a-payment
169
+ */
170
+ async onSubmit(request, _metadata, context) {
171
+ const paymentState = this.getPaymentStateFromState(context.state);
172
+ if (!paymentState) {
173
+ throw new PaymentPreAuthError(this, 'Complete the payment to continue', true, PaymentErrorTypes.PaymentIncomplete);
174
+ }
175
+ if (paymentState.capture?.status === 'success') {
176
+ return;
177
+ }
178
+ const {
179
+ paymentId,
180
+ isLivePayment,
181
+ formId
182
+ } = paymentState;
183
+ const paymentService = createPaymentService(isLivePayment, formId);
184
+
185
+ /**
186
+ * @see https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle
187
+ */
188
+ const status = await paymentService.getPaymentStatus(paymentId);
189
+ PaymentSubmissionError.checkPaymentAmount(status.amount, this.options.amount, this);
190
+ if (status.state.status === 'success') {
191
+ await this.markPaymentCaptured(request, paymentState);
192
+ return;
193
+ }
194
+ if (status.state.status !== 'capturable') {
195
+ throw new PaymentPreAuthError(this, 'Your payment authorisation has expired. Please add your payment details again.', true, PaymentErrorTypes.PaymentExpired);
196
+ }
197
+ const captured = await paymentService.capturePayment(paymentId);
198
+ if (!captured) {
199
+ throw new PaymentPreAuthError(this, 'There was a problem and your form was not submitted. Try submitting the form again.', false);
200
+ }
201
+ await this.markPaymentCaptured(request, paymentState);
202
+ }
203
+
204
+ /**
205
+ * Updates payment state to mark capture as successful
206
+ * This ensures we don't try to re-capture on submission retry
207
+ */
208
+ async markPaymentCaptured(request, paymentState) {
209
+ const updatedState = {
210
+ ...paymentState,
211
+ capture: {
212
+ status: 'success',
213
+ createdAt: new Date().toISOString()
214
+ }
215
+ };
216
+ if (this.page) {
217
+ const currentState = await this.page.getState(request);
218
+ await this.page.mergeState(request, currentState, {
219
+ [this.name]: updatedState
220
+ });
221
+ }
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Session data stored when dispatching to GOV.UK Pay
227
+ */
228
+ //# sourceMappingURL=PaymentField.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PaymentField.js","names":["randomUUID","StatusCodes","joi","FormComponent","getPluginOptions","PaymentErrorTypes","PaymentPreAuthError","PaymentSubmissionError","createPaymentService","PaymentField","isAppendageStateSingleObject","constructor","def","props","options","paymentStateSchema","object","paymentId","string","required","reference","amount","number","description","uuid","formId","isLivePayment","boolean","preAuth","status","valid","createdAt","isoDate","unknown","label","formSchema","stateSchema","getPaymentStateFromState","state","value","name","isPaymentState","undefined","getDisplayStringFromState","toFixed","getViewModel","payload","errors","viewModel","paymentState","formattedAmount","Array","isArray","isState","getFormValue","getContextValueFromState","getAllPossibleErrors","baseErrors","type","template","advancedSettingsErrors","dispatcher","request","h","args","componentName","component","model","controller","getState","baseUrl","server","summaryUrl","basePath","existingPaymentState","redirect","code","SEE_OTHER","isLive","isPreview","paymentService","$$__referenceNumber","slug","payCallbackUrl","paymentPageUrl","sourceUrl","amountInPence","Math","round","payment","createPayment","sessionData","returnUrl","failureUrl","yar","set","paymentUrl","onSubmit","_metadata","context","PaymentIncomplete","capture","getPaymentStatus","checkPaymentAmount","markPaymentCaptured","PaymentExpired","captured","capturePayment","updatedState","Date","toISOString","page","currentState","mergeState"],"sources":["../../../../../src/server/plugins/engine/components/PaymentField.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto'\n\nimport {\n type FormMetadata,\n type PaymentFieldComponent\n} from '@defra/forms-model'\nimport { StatusCodes } from 'http-status-codes'\nimport joi, { type ObjectSchema } from 'joi'\n\nimport { FormComponent } from '~/src/server/plugins/engine/components/FormComponent.js'\nimport { type PaymentState } from '~/src/server/plugins/engine/components/PaymentField.types.js'\nimport { getPluginOptions } from '~/src/server/plugins/engine/helpers.js'\nimport {\n PaymentErrorTypes,\n PaymentPreAuthError,\n PaymentSubmissionError\n} from '~/src/server/plugins/engine/pageControllers/errors.js'\nimport {\n type AnyFormRequest,\n type FormContext,\n type FormRequestPayload,\n type FormResponseToolkit\n} from '~/src/server/plugins/engine/types/index.js'\nimport {\n type ErrorMessageTemplateList,\n type FormPayload,\n type FormState,\n type FormStateValue,\n type FormSubmissionError,\n type FormSubmissionState\n} from '~/src/server/plugins/engine/types.js'\nimport { createPaymentService } from '~/src/server/plugins/payment/helper.js'\n\nexport class PaymentField extends FormComponent {\n declare options: PaymentFieldComponent['options']\n declare formSchema: ObjectSchema\n declare stateSchema: ObjectSchema\n isAppendageStateSingleObject = true\n\n constructor(\n def: PaymentFieldComponent,\n props: ConstructorParameters<typeof FormComponent>[1]\n ) {\n super(def, props)\n\n this.options = def.options\n\n const paymentStateSchema = joi\n .object({\n paymentId: joi.string().required(),\n reference: joi.string().required(),\n amount: joi.number().required(),\n description: joi.string().required(),\n uuid: joi.string().uuid().required(),\n formId: joi.string().required(),\n isLivePayment: joi.boolean().required(),\n preAuth: joi\n .object({\n status: joi\n .string()\n .valid('success', 'failed', 'started')\n .required(),\n createdAt: joi.string().isoDate().required()\n })\n .required()\n })\n .unknown(true)\n .label(this.label)\n\n this.formSchema = paymentStateSchema\n // 'required()' forces the payment page to be invalid until we have valid payment state\n // i.e. the user will automatically be directed back to the payment page\n // if they attempt to access future pages when no payment entered yet\n this.stateSchema = paymentStateSchema.required()\n }\n\n /**\n * Gets the PaymentState from form submission state\n */\n getPaymentStateFromState(\n state: FormSubmissionState\n ): PaymentState | undefined {\n const value = state[this.name]\n return this.isPaymentState(value) ? value : undefined\n }\n\n getDisplayStringFromState(state: FormSubmissionState): string {\n const value = this.getPaymentStateFromState(state)\n\n if (!value) {\n return ''\n }\n\n return `£${value.amount.toFixed(2)} - ${value.description}`\n }\n\n getViewModel(payload: FormPayload, errors?: FormSubmissionError[]) {\n const viewModel = super.getViewModel(payload, errors)\n\n // Payload is pre-populated from state if a payment has already been made\n const paymentState = this.isPaymentState(payload[this.name] as unknown)\n ? (payload[this.name] as unknown as PaymentState)\n : undefined\n\n // When user initially visits the payment page, there is no payment state yet so the amount is read form the form definition.\n const amount = paymentState?.amount ?? this.options.amount\n\n const formattedAmount = amount.toFixed(2)\n\n return {\n ...viewModel,\n amount: formattedAmount,\n description: this.options.description,\n paymentState\n }\n }\n\n /**\n * Type guard to check if value is PaymentState\n */\n isPaymentState(value: unknown): value is PaymentState {\n return PaymentField.isPaymentState(value)\n }\n\n /**\n * Static type guard to check if value is PaymentState\n */\n static isPaymentState(value: unknown): value is PaymentState {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return false\n }\n\n const state = value as PaymentState\n return (\n typeof state.paymentId === 'string' &&\n typeof state.amount === 'number' &&\n typeof state.description === 'string'\n )\n }\n\n /**\n * Override base isState to validate PaymentState\n */\n isState(value?: FormStateValue | FormState): value is FormState {\n return this.isPaymentState(value)\n }\n\n getFormValue(value?: FormStateValue | FormState) {\n return this.isPaymentState(value)\n ? (value as unknown as NonNullable<FormStateValue>)\n : undefined\n }\n\n getContextValueFromState(state: FormSubmissionState) {\n return this.isPaymentState(state)\n ? `Reference: ${state.reference}\\nAmount: ${state.amount.toFixed(2)}`\n : ''\n }\n\n /**\n * For error preview page that shows all possible errors on a component\n */\n getAllPossibleErrors(): ErrorMessageTemplateList {\n return PaymentField.getAllPossibleErrors()\n }\n\n /**\n * Static version of getAllPossibleErrors that doesn't require a component instance.\n */\n static getAllPossibleErrors(): ErrorMessageTemplateList {\n return {\n baseErrors: [\n {\n type: 'paymentRequired',\n template: 'Complete the payment to continue'\n }\n ],\n advancedSettingsErrors: []\n }\n }\n\n /**\n * Dispatcher for external redirect to GOV.UK Pay\n */\n static async dispatcher(\n request: FormRequestPayload,\n h: FormResponseToolkit,\n args: PaymentDispatcherArgs\n ): Promise<unknown> {\n const { options, name: componentName } = args.component\n const { model } = args.controller\n\n const state = await args.controller.getState(request)\n const { baseUrl } = getPluginOptions(request.server)\n const summaryUrl = `${baseUrl}/${model.basePath}/summary`\n\n const existingPaymentState = state[componentName]\n if (\n PaymentField.isPaymentState(existingPaymentState) &&\n existingPaymentState.preAuth?.status === 'success'\n ) {\n return h.redirect(summaryUrl).code(StatusCodes.SEE_OTHER)\n }\n\n const isLivePayment = args.isLive && !args.isPreview\n const formId = args.controller.model.formId\n const paymentService = createPaymentService(isLivePayment, formId)\n\n const uuid = randomUUID()\n\n const reference = state.$$__referenceNumber as string\n const amount = options.amount\n\n const description = options.description\n\n const slug = `/${model.basePath}`\n\n const payCallbackUrl = `${baseUrl}/payment-callback?uuid=${uuid}`\n const paymentPageUrl = args.sourceUrl\n\n const amountInPence = Math.round(amount * 100)\n const payment = await paymentService.createPayment(\n amountInPence,\n description,\n payCallbackUrl,\n reference,\n { formId, slug }\n )\n\n const sessionData: PaymentSessionData = {\n uuid,\n formId,\n reference,\n amount,\n description,\n paymentId: payment.paymentId,\n componentName,\n returnUrl: summaryUrl,\n failureUrl: paymentPageUrl,\n isLivePayment\n }\n\n request.yar.set(`payment-${uuid}`, sessionData)\n\n return h.redirect(payment.paymentUrl).code(StatusCodes.SEE_OTHER)\n }\n\n /**\n * Called on form submission to capture the payment\n * @see https://docs.payments.service.gov.uk/delayed_capture/#delay-taking-a-payment\n */\n async onSubmit(\n request: FormRequestPayload,\n _metadata: FormMetadata,\n context: FormContext\n ): Promise<void> {\n const paymentState = this.getPaymentStateFromState(context.state)\n\n if (!paymentState) {\n throw new PaymentPreAuthError(\n this,\n 'Complete the payment to continue',\n true,\n PaymentErrorTypes.PaymentIncomplete\n )\n }\n\n if (paymentState.capture?.status === 'success') {\n return\n }\n\n const { paymentId, isLivePayment, formId } = paymentState\n const paymentService = createPaymentService(isLivePayment, formId)\n\n /**\n * @see https://docs.payments.service.gov.uk/api_reference/#payment-status-lifecycle\n */\n const status = await paymentService.getPaymentStatus(paymentId)\n\n PaymentSubmissionError.checkPaymentAmount(\n status.amount,\n this.options.amount,\n this\n )\n\n if (status.state.status === 'success') {\n await this.markPaymentCaptured(request, paymentState)\n return\n }\n\n if (status.state.status !== 'capturable') {\n throw new PaymentPreAuthError(\n this,\n 'Your payment authorisation has expired. Please add your payment details again.',\n true,\n PaymentErrorTypes.PaymentExpired\n )\n }\n\n const captured = await paymentService.capturePayment(paymentId)\n\n if (!captured) {\n throw new PaymentPreAuthError(\n this,\n 'There was a problem and your form was not submitted. Try submitting the form again.',\n false\n )\n }\n\n await this.markPaymentCaptured(request, paymentState)\n }\n\n /**\n * Updates payment state to mark capture as successful\n * This ensures we don't try to re-capture on submission retry\n */\n private async markPaymentCaptured(\n request: FormRequestPayload,\n paymentState: PaymentState\n ): Promise<void> {\n const updatedState: PaymentState = {\n ...paymentState,\n capture: {\n status: 'success',\n createdAt: new Date().toISOString()\n }\n }\n\n if (this.page) {\n const currentState = await this.page.getState(request)\n await this.page.mergeState(request, currentState, {\n [this.name]: updatedState\n })\n }\n }\n}\n\nexport interface PaymentDispatcherArgs {\n controller: {\n model: {\n formId: string\n basePath: string\n name: string\n }\n getState: (request: AnyFormRequest) => Promise<FormSubmissionState>\n }\n component: PaymentField\n sourceUrl: string\n isLive: boolean\n isPreview: boolean\n}\n\n/**\n * Session data stored when dispatching to GOV.UK Pay\n */\nexport interface PaymentSessionData {\n uuid: string\n formId: string\n reference: string\n amount: number\n description: string\n paymentId: string\n componentName: string\n returnUrl: string\n failureUrl: string\n isLivePayment: boolean\n}\n"],"mappings":"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","ignoreList":[]}