billwerk_subscriptions-1.x-dev/modules/billwerk_subscriptions_manage/js/billwerk_subscriptions_manage.js

modules/billwerk_subscriptions_manage/js/billwerk_subscriptions_manage.js
/**
 * @file
 * Billwerk behaviors.
 *
 * @see https://billwerk.readme.io/reference/subscriptionjsportal
 */
(function (Drupal, drupalSettings) {
  Drupal.billwerk = {};
  Drupal.billwerk.subscriptionjs = {};

  Drupal.billwerk.handleError = (error) => {
    // Use Drupal JavaScript Messages API: https://www.drupal.org/node/2930536
    const messages = new Drupal.Message();
    if (error && error.errorMessage && messages) {
      messages.add(Drupal.t(error.errorMessage), {
        type: 'error',
      });

      if (
        drupalSettings.billwerk &&
        drupalSettings.billwerk.paymentFormWrapperId
      ) {
        // Until Billwerk allows us to validate the form in the iframe
        // or validates it itself, we need to scroll to the error messages
        // so that users notice the error.
        // Also we add an "error" class on the wrapper, as we can't access
        // the iframe contents due to CSP:
        const paymentFormWrapper = document.getElementById(
          drupalSettings.billwerk.paymentFormWrapperId,
        );
        if (paymentFormWrapper) {
          paymentFormWrapper.classList.add('error');
        }
      }

      // Scroll to the error messages (UX):
      window.scroll({
        top: 0,
        left: 0,
        behavior: 'smooth',
      });
    } else {
      console.error(error);
      alert(
        `Error! Please contact us with the following error report: "${error.errorMessage}"`,
      );
    }
  };

  Drupal.billwerk.getBillwerkSubscriptionsManageFormEl = () => {
    return document.querySelector('.billwerk-subscriptions-change-form');
  };

  Drupal.billwerk.validatePayerForm = () => {
    const formEl = Drupal.billwerk.getBillwerkSubscriptionsManageFormEl();

    const isValid = formEl.checkValidity();
    if (!isValid) {
      formEl.reportValidity();
    }
    return isValid;
  };

  Drupal.billwerk.getPayerFormData = () => {
    const formData = Object.fromEntries(
      new FormData(
        Drupal.billwerk.getBillwerkSubscriptionsManageFormEl(),
      ).entries(),
    );
    // Remove Drupal form values:
    delete formData.form_id;
    delete formData.form_token;
    delete formData.form_build_id;
    // Map the values to the CustomerData Object Structure:
    // @see https://billwerk.readme.io/reference/subscriptionjs-types#customerdata-object-structure
    const customerData = {
      // Only set the values that we select:
      // EmailAddress: formData.EmailAddress ?? "",
      CompanyName: formData.CompanyName ?? '',
      FirstName: formData.FirstName ?? '',
      LastName: formData.LastName ?? '',
      // PhoneNumber: formData.PhoneNumber ?? "",
      Address: {
        // AddressLine1: formData.CompanyName ?? "",
        Street: formData.Street ?? '',
        HouseNumber: formData.HouseNumber ?? '',
        PostalCode: formData.PostalCode ?? '',
        City: formData.City ?? '',
        Country: formData.Country ?? '',
      },
      VatId: formData.VatId ?? '',
      // Locale: formData.Country ?? "",
      // CustomFields: {
      // },
    };

    return customerData;
  };

  Drupal.billwerk.getPayerData = (billwerkPortal, success, error) => {
    billwerkPortal.contractDetails((contractData) => {
      const billwerkCustomerData = contractData.Customer;
      const payerFormData = Drupal.billwerk.getPayerFormData();
      if (!billwerkCustomerData || !payerFormData) {
        window.alert('Unable to determine required data. Please contact us!');
        throw new Error(
          'Unable to determine required data. Please contact us!',
        );
      }
      const payerData = {
        ...billwerkCustomerData,
        ...payerFormData,
      };
      // Remove data that should never change:
      delete payerData.Id;
      delete payerData.ExternalCustomerId;
      delete payerData.CreatedAt;
      delete payerData.Locale;
      success(payerData);
    }, error);
  };

  Drupal.billwerk.handlePaymentSuccess = (data, providerReturnUrl) => {
    // "data" typically has the following structure:
    /*
    {
      ContractId: "6585ab89cb4a71df107a1606",
      Currency: "EUR",
      CustomerId: "6585ab89cb4a71df107a1605",
      GrossTotal: 135.3,
      OrderId: "65b1019f5bc95f7014658fad",
      OrderStatus: "PaymentPending",
    */
    // Redirect to providerReturnUrl (if not empty):
    if (providerReturnUrl) {
      // Do not allow to use the "back"-button:
      window.location.replace(providerReturnUrl);
    }
  };

  Drupal.billwerk.ensureSubscriptionJS = () => {
    if (typeof SubscriptionJS !== 'object') {
      // Ensure subscriptionJS is loaded correctly:
      window.alert(
        'Error. SubscriptionJS is not loaded correctly, please contact us!',
      );
      throw new Error(
        'Error. SubscriptionJS is not loaded correctly, please contact us!',
      );
    }
  };

  Drupal.billwerk.initializeForm = (context, settings) => {
    // Ensure SubscriptionJS:
    Drupal.billwerk.ensureSubscriptionJS();

    // Assign our backend provided variables:
    const {
      selfserviceToken,
      selfservicePublicApiKey,
      order,
      userLocale,
      providerReturnUrl,
      currentContractPaymentProvider,
      paymentFormWrapperId,
    } = settings.billwerk;

    // Initialize Billwerk helpers:
    /* global SubscriptionJS */
    const billwerkPortal = new SubscriptionJS.Portal(selfserviceToken);

    // We need to determine if the user has a current payment
    // provider selected in the account or not
    // because billwerk doesn't provide a convenient way
    // to reuse the payment provider again and prefill the
    // payment selection form accordingly.
    // So we have to use two different ways of confirming the order:

    if (currentContractPaymentProvider !== '' && true) {
      // This is the synchronous payment method without payment method selection.
      // Sadly it doesn't provide an integrated way to update the customer
      // address in the same step, so we had to implement this ourselves:

      // Register the buy button:
      document.addEventListener(
        'click',
        (event) => {
          if (!event.target.matches('#buy')) return;
          if (!Drupal.billwerk.validatePayerForm()) return;
          event.preventDefault();

          // Get the existing customer data from Billwerk:
          Drupal.billwerk.getPayerData(
            billwerkPortal,
            (newCustomerData) => {
              // First we need to update the new customer data:
              // DANGER: This is not implemented very clever on the Billwerk
              // side and overwrites ALL fields (PUT, not PATCH)!
              // So we have to merge the form data with all existing customer
              // data to not lose any.
              // @see https://billwerk.readme.io/reference/subscriptionjsportal#customerchangecustomerdata-success-error
              billwerkPortal.customerChange(
                newCustomerData,
                () => {
                  // Success!
                  // Execute the payment now:
                  billwerkPortal.upgradePaySync(
                    order.OrderId,
                    (upgradePaySyncResult) => {
                      Drupal.billwerk.handlePaymentSuccess(
                        upgradePaySyncResult,
                        providerReturnUrl,
                      );
                    },
                    Drupal.billwerk.handleError,
                  );
                },
                Drupal.billwerk.handleError,
              );
            },
            Drupal.billwerk.handleError,
          );
        },
        false,
      );
    } else {
      // Initialize Billwerk payment form:
      const paymentFormWrapperElement =
        document.getElementById(paymentFormWrapperId);
      // Clear the container and remove the default text:
      paymentFormWrapperElement.innerHTML = '';

      // @see https://billwerk.readme.io/reference/appearance-1
      // @improve: We should inject this via an #attached, so it can be
      // altered in Drupal!
      const style = {
        /* Some example values of available properties
    {
        backgroundColor: '#ffffff',
        border: '1px solid #ccc',
        borderBottomColor: '#ccc',
        borderBottomWidth: '5px',
        borderColor: '#ccc',
        borderLeftColor: 'black',
        borderLeftWidth: '5px',
        borderRadius: '4px',
        borderRightColor: '#ccc',
        borderRightWidth: '5px',
        borderTopColor: '#ccc',
        borderTopWidth: '5px',
        borderWidth: '2px',
        boxShadow: 'inset 0 1px 1px rgba(0,0,0,.075)',
        color: '#444444',
        display: 'block'
        fontSize: '16px',
        fontFamily: '"Times New Roman", Times, serif',
        fontStyle: 'normal',
        fontWeight: '',
        height: '34px',
        lineHeight: 'normal',
        margin: '0',
        padding: '1px 2px'
    }
    */
        body: {
          fontFamily: 'Poppins, Helvetica, Arial, sans-serif',
          padding: 0,
          margin: 0,
        },
        container: {
          padding: 0,
          margin: 0,
          // width: "auto", // Unsupported!
        },
        input: {},
        inputInvalid: {},
        inputRequired: {},
        label: {},
        labelRequired: {},
        sectionContent: {
          margin: '15px',
          padding: 0,
          // width: "auto", // Unsupported!
        },
        select: {},
        selectInvalid: {},
        selectRequired: {},
      };
      const paymentForm = SubscriptionJS.createElement(
        'paymentForm',
        paymentFormWrapperElement,
        {
          // Public API key (required):
          publicApiKey: selfservicePublicApiKey,
          // Limit the payment methods (optional):
          // paymentMethods: ["Debit:FakePSP", "CreditCard:FakePSP"],
          locale: userLocale ?? 'en',
          providerReturnUrl,
        },
        style,
        Drupal.billwerk.handleError,
      );

      // Register the buy button:
      document.addEventListener(
        'click',
        (event) => {
          if (!event.target.matches('#buy')) return;
          if (!Drupal.billwerk.validatePayerForm()) return;
          event.preventDefault();

          Drupal.billwerk.getPayerData(
            billwerkPortal,
            (newCustomerData) => {
              // First we need to update the new customer data:
              // DANGER: This is not implemented very clever on the Billwerk
              // side and overwrites ALL fields (PUT, not PATCH)!
              // So we have to merge the form data with all existing customer
              // data to not lose any.
              // @see https://billwerk.readme.io/reference/subscriptionjsportal#customerchangecustomerdata-success-error
              billwerkPortal.customerChange(
                newCustomerData,
                () => {
                  // Inform the payment form about the new customer data:
                  // @see https://billwerk.readme.io/reference/subscriptionjscreateelement#paymentformpayerdatachangedcustomerdata
                  // This does NOT change the payer data at billwerk, we need to do that separately!
                  paymentForm.payerDataChanged(newCustomerData);
                  // Execute the order:
                  billwerkPortal.upgradePayInteractive(
                    null,
                    paymentForm,
                    order,
                    (data) => {
                      Drupal.billwerk.handlePaymentSuccess(
                        data,
                        providerReturnUrl,
                      );
                    },
                    Drupal.billwerk.handleError,
                  );
                },
                Drupal.billwerk.handleError,
              );
            },
            Drupal.billwerk.handleError,
          );
        },
        false,
      );
    }
  };

  Drupal.billwerk.finalize = (context, settings) => {
    // Ensure SubscriptionJS:
    Drupal.billwerk.ensureSubscriptionJS();

    // If finalize() fails, do NOT show an error to the users,
    // just log it. As this for example also happens when reloading
    // the success page and the order has already been finalized.
    SubscriptionJS.finalize((successData) => {}, console.error);
  };

  Drupal.behaviors.billwerkCheckoutInit = {
    attach(context, settings) {
      if (context === document) {
        // Execute the initialization based on the given "billwerk_context":
        switch (settings.billwerk_context) {
          case 'form':
            Drupal.billwerk.initializeForm(context, settings);
            break;

          case 'finalize':
            Drupal.billwerk.finalize(context, settings);
            break;

          default:
            // Nothing!
            break;
        }
      }
    },
  };
})(Drupal, drupalSettings);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc