diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 7b9526b7..2f3f65f3 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -4,7 +4,7 @@ on: push: schedule: # Every 13th and 28th of the month at 07:42 - - cron: '42 7 13,28 * *' + - cron: '42 7 13,28 * *' jobs: tests: @@ -31,7 +31,7 @@ jobs: - name: Run Tests env: DJANGO_VERSION: ${{ matrix.django-version }} - run: "./dev_server.sh -d test" + run: './dev_server.sh -d test' all-tests: runs-on: ubuntu-latest diff --git a/dds_registration/fixtures/README.md b/dds_registration/fixtures/README.md index 7362e273..6ea65654 100644 --- a/dds_registration/fixtures/README.md +++ b/dds_registration/fixtures/README.md @@ -6,10 +6,10 @@ To install test data (for local testting), use: python manage.py loaddata site-local test-users test-event test-options ``` -To add test registration object: +To add test registration and payment objects: ``` -python manage.py loaddata test-registration +python manage.py loaddata test-payment-1-created test-registration-1-submited ``` Admin and the first user creating with `test` password. diff --git a/dds_registration/fixtures/test-event.yaml b/dds_registration/fixtures/test-event.yaml index dd658022..c2f1bffd 100644 --- a/dds_registration/fixtures/test-event.yaml +++ b/dds_registration/fixtures/test-event.yaml @@ -1,4 +1,4 @@ -# @changed 2024.03.28, 15:18 +# @changed 2024.04.06, 19:55 - model: dds_registration.event pk: 1 @@ -6,10 +6,10 @@ id: 1 code: 'first' title: 'The first event' - description: 'First event description' + description: 'The first event description' + success_email: 'dmia@yandex.ru' public: 1 - registration_open: '2024-03-25' - registration_close: '2024-04-20' + registration_open: '2024-04-06' + registration_close: '2024-04-25' max_participants: 5 - payment_deadline_days: 30 - payment_details: '' + refund_last_day: '2024-04-30' diff --git a/dds_registration/fixtures/test-options.yaml b/dds_registration/fixtures/test-options.yaml index ad84613a..8e014d65 100644 --- a/dds_registration/fixtures/test-options.yaml +++ b/dds_registration/fixtures/test-options.yaml @@ -1,4 +1,4 @@ -# @changed 2024.03.28, 15:18 +# @changed 2024.04.06, 19:59 - model: dds_registration.registrationoption pk: 1 @@ -6,7 +6,7 @@ id: 1 item: 'Registration' price: 100 - currency: 'USD' + currency: 'CHF' event_id: 1 - model: dds_registration.registrationoption @@ -14,6 +14,6 @@ fields: id: 2 item: 'T-Shirt' - price: 10 + price: 19 currency: 'USD' event_id: 1 diff --git a/dds_registration/fixtures/test-payment-1-created.yaml b/dds_registration/fixtures/test-payment-1-created.yaml new file mode 100644 index 00000000..4310eda2 --- /dev/null +++ b/dds_registration/fixtures/test-payment-1-created.yaml @@ -0,0 +1,10 @@ +# @changed 2024.04.06, 20:05 + +- model: dds_registration.payment + pk: 1 + fields: + id: 1 + created: '2024-04-06' + updated: '2024-04-06' + status: 'CREATED' + data: '{"user": {"id": 2, "name": "John Lennon", "address": "251 Menlove Avenue, Liverpool, Merseyside L25 7SA, UK"}, "extra": "", "kind": "event", "method": "STRIPE", "event": {"id": 1, "title": "The first event"}, "registration": {"id": 1}, "option": {"id": 1, "item": "Registration"}, "price": 100.0, "currency": "CHF"}' diff --git a/dds_registration/fixtures/test-registration.yaml b/dds_registration/fixtures/test-registration-1-submited.yaml similarity index 50% rename from dds_registration/fixtures/test-registration.yaml rename to dds_registration/fixtures/test-registration-1-submited.yaml index 67b89cb2..0b1b9932 100644 --- a/dds_registration/fixtures/test-registration.yaml +++ b/dds_registration/fixtures/test-registration-1-submited.yaml @@ -1,13 +1,13 @@ -# @changed 2024.03.28, 21:07 +# @changed 2024.04.06, 20:01 - model: dds_registration.registration pk: 1 fields: id: 1 status: 'SUBMITTED' - created_at: '2024-03-28 20:00:00.000000' - updated_at: '2024-03-28 20:00:00.000000' + created_at: '2024-04-06 19:59:46.154852' + updated_at: '2024-04-06 19:59:46.167242' event_id: 1 - invoice_id: null + payment_id: 1 user_id: 2 option_id: 1 diff --git a/dds_registration/models.py b/dds_registration/models.py index cb14051a..b30f9122 100644 --- a/dds_registration/models.py +++ b/dds_registration/models.py @@ -23,6 +23,7 @@ FileType, Mail, ) +import json from dds_registration.core.constants.payments import ( site_default_currency, @@ -175,6 +176,7 @@ class Payment(Model): # ("WISE", "Wise"), # Not yet implemented ] DEFAULT_METHOD = "INVOICE" + # Use `get_method_name` helper (below) to get method name # # User name and address, initialized by user's ones, by default # name = models.TextField(blank=False, default="") @@ -193,6 +195,33 @@ class Payment(Model): # invoice or a receipt data = models.JSONField(help_text="Read-only JSON object", default=dict) + def get_data(self): + data = self.data + if isinstance(data, str): + # Parse json... + try: + data = json.loads(data) + except: + # TODO: Throw an exception? + data = {} + return data + + + def get_method_name(self): + data = self.get_data() + method = data['method'] + methods = dict(Payment.METHODS) + if not method in methods: + # TODO: To throw an error? + return None + return methods[method] + + + @property + def method_name(self): + return self.get_method_name() + + def mark_paid(self): if self.status == "PAID": return @@ -344,13 +373,12 @@ class Event(Model): code = models.TextField(unique=True, default=random_code) # Show as an input title = models.TextField(unique=True, null=False, blank=False) # Show as an input description = models.TextField(blank=False, null=False) + # `success_email`: Can't see a description for this field. Can't see its usage anywhere in the app. Why is it required? Which email(s) should be here? success_email = models.TextField(blank=False, null=False) public = models.BooleanField(default=True) registration_open = models.DateField(auto_now_add=True, help_text="Date registration opens (inclusive)") registration_close = models.DateField(help_text="Date registration closes (inclusive)") - refund_last_day = models.DateField( - null=True, help_text="Last day that a fee refund can be offered" - ) + refund_last_day = models.DateField(null=True, help_text="Last day that a fee refund can be offered") max_participants = models.PositiveIntegerField( default=0, help_text="Maximum number of participants (0 = no limit)", diff --git a/dds_registration/views/membership.py b/dds_registration/views/membership.py index f47f3fa2..29b8ae03 100644 --- a/dds_registration/views/membership.py +++ b/dds_registration/views/membership.py @@ -28,6 +28,7 @@ def membership_application(request: HttpRequest): form = MembershipForm(request.POST) if form.is_valid(): + payment_method = form.cleaned_data["payment_method"] payment = Payment( status="CREATED", data={ @@ -41,7 +42,7 @@ def membership_application(request: HttpRequest): "membership": { "type": form.cleaned_data["membership_type"], }, - "method": form.cleaned_data["payment_method"], + "method": payment_method, "price": MEMBERSHIP_DATA[form.cleaned_data["membership_type"]]["price"], "currency": MEMBERSHIP_DATA[form.cleaned_data["membership_type"]]["currency"], }, diff --git a/src/assets/event_registration_form/event_registration_form.django b/src/assets/event_registration_form/event_registration_form.django index 5adfdf02..2aa945f2 100644 --- a/src/assets/event_registration_form/event_registration_form.django +++ b/src/assets/event_registration_form/event_registration_form.django @@ -45,5 +45,3 @@ {% endfor %} - - diff --git a/src/assets/events-list-table/events-list-table.django b/src/assets/events-list-table/events-list-table.django index c312ed5b..6c72e147 100644 --- a/src/assets/events-list-table/events-list-table.django +++ b/src/assets/events-list-table/events-list-table.django @@ -51,7 +51,7 @@ {% if payment %} - {{ payment.get_payment_method_display }} + {{ payment.get_method_name }} {% endif %} diff --git a/src/assets/scripts.ts b/src/assets/scripts.ts index 9f6be1bc..213b0913 100644 --- a/src/assets/scripts.ts +++ b/src/assets/scripts.ts @@ -1,22 +1,19 @@ /** * @desc Main js entry point module (scripts) * @module src/assets/scripts.ts - * @changed 2024.04.04, 16:06 + * @changed 2024.04.06, 22:00 */ -/* NOTE: These modules are unused. Used only - * `src/assets/stripe-init/stripe_payment_intents_support.ts`, via requirejs, - * without exposing to global scope. +/* // NOTE: These modules are unused. Used only + * // `src/assets/stripe-init/stripe_payment_intents_support.ts`, via requirejs, + * // without exposing to global scope. * - * import { billing_event_stripe_payment_proceed } from './stripe-init/billing_event_stripe_payment_proceed'; - * import { billing_membership_stripe_payment_proceed } from './stripe-init/billing_membership_stripe_payment_proceed'; - * - * // Expose functions to global scope... - * window.billing_event_stripe_payment_proceed = billing_event_stripe_payment_proceed; - * window.billing_membership_stripe_payment_proceed = billing_membership_stripe_payment_proceed; + * import { startStripeElementsForm } from './stripe-init/stripe_payment_intents_support'; * * console.log('[scripts] Main client code entry point', { - * billing_event_stripe_payment_proceed, - * billing_membership_stripe_payment_proceed, + * startStripeElementsForm, * }); */ + +// Empty root module +export {}; diff --git a/static/assets/scripts.js b/static/assets/scripts.js index 323f8e17..b6ca862a 100644 --- a/static/assets/scripts.js +++ b/static/assets/scripts.js @@ -1,24 +1,12 @@ /** * @desc Main js entry point module (scripts) * @module src/assets/scripts.ts - * @changed 2024.04.04, 16:06 - */ -/* NOTE: These modules are unused. Used only - * `src/assets/stripe-init/stripe_payment_intents_support.ts`, via requirejs, - * without exposing to global scope. - * - * import { billing_event_stripe_payment_proceed } from './stripe-init/billing_event_stripe_payment_proceed'; - * import { billing_membership_stripe_payment_proceed } from './stripe-init/billing_membership_stripe_payment_proceed'; - * - * // Expose functions to global scope... - * window.billing_event_stripe_payment_proceed = billing_event_stripe_payment_proceed; - * window.billing_membership_stripe_payment_proceed = billing_membership_stripe_payment_proceed; - * - * console.log('[scripts] Main client code entry point', { - * billing_event_stripe_payment_proceed, - * billing_membership_stripe_payment_proceed, - * }); + * @changed 2024.04.06, 22:00 */ +define("scripts", ["require", "exports"], function (require, exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); +}); /** * @module stripe_payment_intents_support.ts * @changed 2024.04.04, 00:21 @@ -32,7 +20,7 @@ define("stripe-init/stripe_payment_intents_support", ["require", "exports"], fun var success_url = params.success_url; event.preventDefault(); // @see https://docs.stripe.com/payments/accept-a-payment?platform=web&ui=elements#web-submit-payment - // const result = await + // TODO: Show 'busy' spinner at stripe interaction begin? (It could take some time.) stripe .confirmPayment({ elements: elements, @@ -43,7 +31,6 @@ define("stripe-init/stripe_payment_intents_support", ["require", "exports"], fun .then(function (result) { var error = result.error; if (error) { - // debugger; console.error('[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error', { error: error, event: event, @@ -64,7 +51,6 @@ define("stripe-init/stripe_payment_intents_support", ["require", "exports"], fun params: params, stripe: stripe, }); - debugger; window.location.href = success_url; } }) @@ -100,7 +86,7 @@ define("stripe-init/stripe_payment_intents_support", ["require", "exports"], fun if (!form) { var errorText = 'Form node could not be found!'; var error = new Error(errorText); - console.log('[stripe_payment_intents_support:startStripeElementsForm] error', errorText, { + console.error('[stripe_payment_intents_support:startStripeElementsForm] error', errorText, { error: error, params: params, stripe: stripe, @@ -109,6 +95,7 @@ define("stripe-init/stripe_payment_intents_support", ["require", "exports"], fun paymentElement: paymentElement, form: form, }); + // eslint-disable-next-line no-debugger debugger; return; } diff --git a/static/assets/scripts.js.map b/static/assets/scripts.js.map index e8c58cf8..1e2e27ef 100644 --- a/static/assets/scripts.js.map +++ b/static/assets/scripts.js.map @@ -1 +1 @@ -{"version":3,"sources":["src/assets/scripts.ts","src/assets/stripe-init/stripe_payment_intents_support.ts","src/assets/test/test.ts"],"names":[],"mappings":"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","file":"scripts.js","sourcesContent":["/**\n * @desc Main js entry point module (scripts)\n * @module src/assets/scripts.ts\n * @changed 2024.04.04, 16:06\n */\n\n/* NOTE: These modules are unused. Used only\n * `src/assets/stripe-init/stripe_payment_intents_support.ts`, via requirejs,\n * without exposing to global scope.\n *\n * import { billing_event_stripe_payment_proceed } from './stripe-init/billing_event_stripe_payment_proceed';\n * import { billing_membership_stripe_payment_proceed } from './stripe-init/billing_membership_stripe_payment_proceed';\n *\n * // Expose functions to global scope...\n * window.billing_event_stripe_payment_proceed = billing_event_stripe_payment_proceed;\n * window.billing_membership_stripe_payment_proceed = billing_membership_stripe_payment_proceed;\n *\n * console.log('[scripts] Main client code entry point', {\n * billing_event_stripe_payment_proceed,\n * billing_membership_stripe_payment_proceed,\n * });\n */\n","/**\n * @module stripe_payment_intents_support.ts\n * @changed 2024.04.04, 00:21\n */\n\nimport type {\n Stripe,\n StripeElements,\n StripeElementsOptionsClientSecret,\n StripeError,\n StripePaymentElement,\n} from '@stripe/stripe-js/dist/stripe-js';\n\n/** Form action */\nfunction submitStripeForm(\n stripe: Stripe,\n params: TCreateCheckoutSessionParams,\n elements: StripeElements,\n event: SubmitEvent,\n) {\n const { success_url } = params;\n\n event.preventDefault();\n\n // @see https://docs.stripe.com/payments/accept-a-payment?platform=web&ui=elements#web-submit-payment\n // const result = await\n stripe\n .confirmPayment({\n elements,\n confirmParams: {\n return_url: success_url,\n },\n })\n .then((result) => {\n const error: StripeError = result.error;\n\n if (error) {\n // debugger;\n console.error(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error',\n {\n error,\n event,\n params,\n stripe,\n },\n );\n\n // Show error\n const messageContainer = document.querySelector('#error-message');\n if (messageContainer) {\n messageContainer.textContent = error.message || '';\n }\n } else {\n // Success: redirect to success message\n console.log(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] success',\n {\n success_url,\n event,\n params,\n stripe,\n },\n );\n debugger;\n window.location.href = success_url;\n }\n })\n .catch((error) => {\n console.error(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error',\n {\n error,\n event,\n params,\n stripe,\n },\n );\n });\n}\n\n/** Start stripe payment form */\nexport function startStripeElementsForm(params: TCreateCheckoutSessionParams) {\n const {\n STRIPE_PUBLISHABLE_KEY,\n // success_url,\n client_secret,\n } = params;\n\n // Initialize Stripe.js\n const stripe: Stripe = window.Stripe(STRIPE_PUBLISHABLE_KEY);\n\n // @see https://docs.stripe.com/js/elements_object/create_payment_element#payment_element_create-options\n const options: StripeElementsOptionsClientSecret = {\n clientSecret: client_secret,\n // TODO: Customize forms (use bootstrap styles)...\n // appearance: {},\n };\n\n // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in a previous step\n const elements: StripeElements = stripe.elements(options);\n\n // Create and mount the Payment Element\n // @see https://docs.stripe.com/js/elements_object/create_payment_element\n const paymentElement: StripePaymentElement = elements.create('payment');\n paymentElement.mount('#payment-element');\n\n const form = document.getElementById('payment-form');\n\n if (!form) {\n const errorText = 'Form node could not be found!';\n const error = new Error(errorText);\n console.log('[stripe_payment_intents_support:startStripeElementsForm] error', errorText, {\n error,\n params,\n stripe,\n options,\n elements,\n paymentElement,\n form,\n });\n debugger;\n return;\n }\n\n form.addEventListener('submit', submitStripeForm.bind(null, stripe, params, elements));\n}\n","/**\n * @module test.ts\n * @changed 2024.04.04, 16:19\n */\n\n// console.log('Test', window);\n"]} \ No newline at end of file +{"version":3,"sources":["src/assets/scripts.ts","src/assets/stripe-init/stripe_payment_intents_support.ts","src/assets/test/test.ts"],"names":[],"mappings":"AAAA;;;;GAIG;;;;;ACJH;;;GAGG;;;;;IAUH,kBAAkB;IAClB,SAAS,gBAAgB,CACvB,MAAc,EACd,MAAoC,EACpC,QAAwB,EACxB,KAAkB;QAEV,IAAA,WAAW,GAAK,MAAM,YAAX,CAAY;QAE/B,KAAK,CAAC,cAAc,EAAE,CAAC;QAEvB,qGAAqG;QACrG,oFAAoF;QACpF,MAAM;aACH,cAAc,CAAC;YACd,QAAQ,UAAA;YACR,aAAa,EAAE;gBACb,UAAU,EAAE,WAAW;aACxB;SACF,CAAC;aACD,IAAI,CAAC,UAAC,MAAM;YACX,IAAM,KAAK,GAAgB,MAAM,CAAC,KAAK,CAAC;YAExC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CACX,iFAAiF,EACjF;oBACE,KAAK,OAAA;oBACL,KAAK,OAAA;oBACL,MAAM,QAAA;oBACN,MAAM,QAAA;iBACP,CACF,CAAC;gBAEF,aAAa;gBACb,IAAM,gBAAgB,GAAG,QAAQ,CAAC,aAAa,CAAC,gBAAgB,CAAC,CAAC;gBAClE,IAAI,gBAAgB,EAAE,CAAC;oBACrB,gBAAgB,CAAC,WAAW,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;gBACrD,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,uCAAuC;gBACvC,OAAO,CAAC,GAAG,CACT,mFAAmF,EACnF;oBACE,WAAW,aAAA;oBACX,KAAK,OAAA;oBACL,MAAM,QAAA;oBACN,MAAM,QAAA;iBACP,CACF,CAAC;gBACF,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,WAAW,CAAC;YACrC,CAAC;QACH,CAAC,CAAC;aACD,KAAK,CAAC,UAAC,KAAK;YACX,OAAO,CAAC,KAAK,CACX,iFAAiF,EACjF;gBACE,KAAK,OAAA;gBACL,KAAK,OAAA;gBACL,MAAM,QAAA;gBACN,MAAM,QAAA;aACP,CACF,CAAC;QACJ,CAAC,CAAC,CAAC;IACP,CAAC;IAED,gCAAgC;IAChC,SAAgB,uBAAuB,CAAC,MAAoC;QAExE,IAAA,sBAAsB,GAGpB,MAAM,uBAHc;QACtB,eAAe;QACf,aAAa,GACX,MAAM,cADK,CACJ;QAEX,uBAAuB;QACvB,IAAM,MAAM,GAAW,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAE7D,wGAAwG;QACxG,IAAM,OAAO,GAAsC;YACjD,YAAY,EAAE,aAAa;YAC3B,kDAAkD;YAClD,kBAAkB;SACnB,CAAC;QAEF,+GAA+G;QAC/G,IAAM,QAAQ,GAAmB,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAE1D,uCAAuC;QACvC,yEAAyE;QACzE,IAAM,cAAc,GAAyB,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACxE,cAAc,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAEzC,IAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;QAErD,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,IAAM,SAAS,GAAG,+BAA+B,CAAC;YAClD,IAAM,KAAK,GAAG,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,gEAAgE,EAAE,SAAS,EAAE;gBACzF,KAAK,OAAA;gBACL,MAAM,QAAA;gBACN,MAAM,QAAA;gBACN,OAAO,SAAA;gBACP,QAAQ,UAAA;gBACR,cAAc,gBAAA;gBACd,IAAI,MAAA;aACL,CAAC,CAAC;YACH,uCAAuC;YACvC,QAAQ,CAAC;YACT,OAAO;QACT,CAAC;QAED,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IACzF,CAAC;IA7CD,0DA6CC;;AC7HD;;;GAGG;AAEH,+BAA+B","file":"scripts.js","sourcesContent":["/**\n * @desc Main js entry point module (scripts)\n * @module src/assets/scripts.ts\n * @changed 2024.04.06, 22:00\n */\n\n/* // NOTE: These modules are unused. Used only\n * // `src/assets/stripe-init/stripe_payment_intents_support.ts`, via requirejs,\n * // without exposing to global scope.\n *\n * import { startStripeElementsForm } from './stripe-init/stripe_payment_intents_support';\n *\n * console.log('[scripts] Main client code entry point', {\n * startStripeElementsForm,\n * });\n */\n\n// Empty root module\nexport {};\n","/**\n * @module stripe_payment_intents_support.ts\n * @changed 2024.04.04, 00:21\n */\n\nimport type {\n Stripe,\n StripeElements,\n StripeElementsOptionsClientSecret,\n StripeError,\n StripePaymentElement,\n} from '@stripe/stripe-js/dist/stripe-js';\n\n/** Form action */\nfunction submitStripeForm(\n stripe: Stripe,\n params: TCreateCheckoutSessionParams,\n elements: StripeElements,\n event: SubmitEvent,\n) {\n const { success_url } = params;\n\n event.preventDefault();\n\n // @see https://docs.stripe.com/payments/accept-a-payment?platform=web&ui=elements#web-submit-payment\n // TODO: Show 'busy' spinner at stripe interaction begin? (It could take some time.)\n stripe\n .confirmPayment({\n elements,\n confirmParams: {\n return_url: success_url,\n },\n })\n .then((result) => {\n const error: StripeError = result.error;\n\n if (error) {\n console.error(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error',\n {\n error,\n event,\n params,\n stripe,\n },\n );\n\n // Show error\n const messageContainer = document.querySelector('#error-message');\n if (messageContainer) {\n messageContainer.textContent = error.message || '';\n }\n } else {\n // Success: redirect to success message\n console.log(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] success',\n {\n success_url,\n event,\n params,\n stripe,\n },\n );\n window.location.href = success_url;\n }\n })\n .catch((error) => {\n console.error(\n '[stripe_payment_intents_support:startStripeElementsForm:submitStripeForm] error',\n {\n error,\n event,\n params,\n stripe,\n },\n );\n });\n}\n\n/** Start stripe payment form */\nexport function startStripeElementsForm(params: TCreateCheckoutSessionParams) {\n const {\n STRIPE_PUBLISHABLE_KEY,\n // success_url,\n client_secret,\n } = params;\n\n // Initialize Stripe.js\n const stripe: Stripe = window.Stripe(STRIPE_PUBLISHABLE_KEY);\n\n // @see https://docs.stripe.com/js/elements_object/create_payment_element#payment_element_create-options\n const options: StripeElementsOptionsClientSecret = {\n clientSecret: client_secret,\n // TODO: Customize forms (use bootstrap styles)...\n // appearance: {},\n };\n\n // Set up Stripe.js and Elements to use in checkout form, passing the client secret obtained in a previous step\n const elements: StripeElements = stripe.elements(options);\n\n // Create and mount the Payment Element\n // @see https://docs.stripe.com/js/elements_object/create_payment_element\n const paymentElement: StripePaymentElement = elements.create('payment');\n paymentElement.mount('#payment-element');\n\n const form = document.getElementById('payment-form');\n\n if (!form) {\n const errorText = 'Form node could not be found!';\n const error = new Error(errorText);\n console.error('[stripe_payment_intents_support:startStripeElementsForm] error', errorText, {\n error,\n params,\n stripe,\n options,\n elements,\n paymentElement,\n form,\n });\n // eslint-disable-next-line no-debugger\n debugger;\n return;\n }\n\n form.addEventListener('submit', submitStripeForm.bind(null, stripe, params, elements));\n}\n","/**\n * @module test.ts\n * @changed 2024.04.04, 16:19\n */\n\n// console.log('Test', window);\n"]} \ No newline at end of file