Skip to content
Malouf Developer Docs

Checkout

File Structure

index.js

  • Import the Api, Repository, and Service JS files from checkout
  • Initialize each by passing in the context
  • Set the context equal to the service, routing all method calls to the Service file
  • Call paymentMethodsFactory to initialize each payment method available within the region (using checkout/methods/factory.js)

service.js

  • Format incoming data correctly (setting defaults for optional variables such as in setShippingAddress())
  • Route method call to Repository

repository.js

  • Initialize store and api from context (given by index.js)
  • Set this.loading state as false initially (used to determine if an API call is in progress to prevent overlapping calls)
  • For methods that route to api.js, check loading state first, and then route the method call.

api.js

  • Initialize with axios provided by index.js file
  • Send requests to HQ, returning the resulting promise data

Methods

Apple Pay

Apple pay uses a custom payment window that integrates with their software, meaning this payment method will only become a payment option when accessing the site from Safari.

Apple Pay in index.js

  • Locate merchantId from the credentials in paymentService (set in checkout/repository:68)
    • If merchantId is not set, stop initialization and push an error to the console
  • Import the Api, Repository, and Service JS files from cart
  • Initialize each by passing in the context
  • Register components by setting them as globally available vue components (Vue.use(...))
  • Set the context equal to the service, routing all method calls to the Service file

Apple Pay in service.js

  • Initialize variables passed in from index.js (repository, clientId, environment)
    • Create a private _session variable which will be used to communicate with Apple Pay when processing and updating customer orders
      • Create a private _callbacks variable which will be set to an array of methods
  • isAvailable()
    • Called to verify that the script has successfully loaded before displaying it as a payment option (found in checkout/service:48)
      • If available, return a successful promise
  • getLatestSupportedVersion()
    • Verify the script has loaded
    • Run through versions to find which version of Apple Pay is supported by the user’s browser, returning that version number
  • startSession()
    • Called by frontend after verifying Apple Pay is an available payment method
    • Initializes callback methods passed in from frontend (used to update site when changes occur while interacting with the Apple Pay session)
    • Get cart and region data from the repository, and retrieve the latest supported version from the session
      • If any of these three values are null, throw an error and prevent the session from opening
    • Create new PaymentRequest instance (imported from /checkout/methods/applepay/entities/PaymentRequest:1)
    • Set total and items equal to data returned from _getLineItems()
    • Initialize data in the Apple Pay session through setTotal, setLineItems, and setShippingMethods
    • Launch session window and pass in private callback methods for Apple Pay to use to pass back data that is used to keep HQ in sync with the session data
  • _getLineItems()
    • Get cart and region data from the repository
    • Create a new LineItem object named total (imported from /checkout/methods/applepay/entities/PaymentRequest:85)
    • Create an array of items that contain details for Subtotal, Discounts, Shipping, Tax, and Fees
    • Return an object containing the total and the line items
  • _getShippingMethods()
    • Get cart and region data from the repository
    • Check if cart has a shipping service, and if so loop through available shipping services within the region
    • For each available service, push a new ShippingMethod object to an array which is then returned
  • _onValidateMerchant()
    • Call repository to verify validation url passed in
    • If returned data contains session_object, return the promise received from the Apple Pay session completeMerchantValidation method
      • If the session_object is missing, abort the session and return an error
    • Return error if URL could not be verified
  • _onShippingContactSelected()
    • Create address object from contact data passed in from session event data
    • Call repository setShippingAddress() to update the HQ stored data when the user updates their shipping address in the session window
      • When updated, call _getLineItems() to update cart totals (in case shipping address changed tax rates and therefore changed the order total)
      • Update shipping details (shipping methods, totals, line items) within the session after updates are made
  • _onShippingMethodSelected()
    • Get shipping method from session event data
    • Call repository setShippingService() to sync site with window data when user selects/updates the shipping method
  • _onPaymentAuthorized()
    • Get payment information from session event data, and then convert payment.token.paymentData to a JSON object
    • Call repository to process the order, passing in the token (to verify payment), billingContact, and shippingContact
      • If successful, call _session.completePayment to display successful payment and close the modal, then invoke website callback onSuccess() method

Apple Pay in repository.js

  • Initialize variables passed in from index.js (store, api, siteRepository, cartRepository, checkoutRepository)
  • verify()
    • Get cart, and call API to verify the cart UUID and passed in URL
  • setShippingAddress()
    • Get cart, and call API shipping method with cart UUID and address
      • If successful, update frontend with refreshed cart data
  • process()
    • Get cart, and call API process with cart UUID, session token (to verify transaction in HQ), billing address, and shipping address
      • If successful, return empty cart object and completed order data to the frontend to display order confirmation page

Apple Pay in api.js

  • Initialize using axios passed in from index.js
  • verify()
    • Use cart UUID and session URL to verify cart data and payment session. If successful, this will allow the session to launch
  • shipping()
    • Use cart UUID and address data to update order address in HQ, returning resulting data (which contains updated cart object)
  • process()
    • Use cart UUID and Apple Pay’s unique session Token
    • Post to process order in HQ, passing in Apple Pay data to verify order detail and amounts
      • If HQ order details match Apple Pay’s authrized order details, complete order to accept payment, and then process order within HQ
    • Return data (containing empty cart and new order object) to repository call

Apple Pay in entities

  • errors.js
    • Used to extend Apple Pay’s error functions (MerchantValidationError, ProcessPaymentError, and ShippingAddressError)
    • Allows frontend to communicate with payment session to account for the necessary errors and provide data to the user
  • PaymentRequest.js
    • PaymentRequest
      • Class used to initialize data with defaults that Apple Pay uses to display to users within the payment window
      • Define getter to retrieve the data stored in this class
      • Define setters to push data to the private class data (_total, _lineItems, etc.)
    • LineItem
      • Class used to store line item information (label, amount, type)
    • ShippingMethod
      • Class used to store shipping method information (label, identifier, amount, detail)

Apple Pay in ui/components

  • Create a button marked by classes passed in from frontend (to allow site-specific modifications)
    • Apple Pay specific classes set on line 64, which will be used for setting an event listener on the button when clicked
    • Props are validated to ensure they are formatted correctly before the session can start
  • renderButton()
    • Ensure Apple Pay is available, emiting canMakePaymentsWithActiveCard if true
  • openPaymentSetup()
    • Pass in the merchantId to open the payment session window, emiting errors if any occur
  • checkAvailability()
    • Verify ApplePaySession has successfully loaded within the window
    • Ensure Apple Pay is available, emiting canMakePayments if true

PayPal

Paypal uses their custom modal to process payments, meaning we send all data to them, provide methods as callbacks to update our data as it changes within their modal, and then once payment is processed we verify the payment and complete the order.

PayPal in index.js

  • Locate clientId from the credentials in paymentService (set in checkout/repository:68)
    • If clientId is not set, stop initialization and push an error to the console
  • Import the Api, Repository, and Service JS files from cart
  • Initialize each by passing in the context
  • Register components by setting them as globally available vue components (Vue.use(...))
  • Set the context equal to the service, routing all method calls to the Service file

PayPal in service.js

  • Initialize variables passed in from index.js (repository, clientId, environment)
    • Create a private _callbacks variable which will be set to an array of methods
    • Load PayPal’s SDK script, used to render their payment button that opens the payment modal
  • isAvailable()
    • Called to verify that the script has successfully loaded before displaying it as a payment option (found in checkout/service:48)
  • renderButton()
    • Called by PayPalButton.vue UI component when mounted after being registerd in index.js
    • Checks if PayPal script has loaded and is available within the window context
    • Initializes _callbacks to be an array of functions passed in from the frontend button component
      • Each callback, when triggered, will $emit a corresponding response that is processed by the site using the component
    • Call PayPal’s Buttons() method to create a button that uses styles set on line 52, and private methods created within the service file (_createOrder, _onApprove, etc.)
    • Pass in id of the div where the button will be placed on the page (selector)
  • _createOrder()
    • Set constants that retrieve data for the cart, region, and shipping address (at that moment the button was rendered and function called)
    • Setup PayPal’s parameters to Authorize payments, shipping address GET_FROM_FILE, and user action CONTINUE
    • Format cart items and totals for PayPal to read
    • Check if address is available
      • If user enters shipping address and continues to billing, provide the address to auto fill the PayPal window
    • Create order with params, which will create instance in PayPal window to complete checkout
  • _onApprove()
    • Callback function used by PayPal modal
      • Invoked when user submits order from modal
    • Authorize order, and if the returned data verifies the order was successfully placed and paid for, call Repository to process data
      • Pass in Order ID and Authorization Id (used to verify order within HQ api calls)
    • Call _onSuccess() if there was no error in processing order
  • _updateShipping()
    • Callback function used by PayPal Modal
      • Invoked when user updates their address within the PayPal modal (from actions such as logging in, or manually updating)
    • Extract address from data, and format that address how HQ expects to receive it
      • Call repository to update cart data with the new address to keep our system in sync with PayPal
    • If address update was successful, call PayPal’s patch method to replace the order total within PayPal
      • Necessary when address changes affect tax calculations and thereby changes order total
  • _onClick(), _onCancel(), _onError(), _onSuccess()
    • Callback methods used by PayPal Modal
      • onClick triggers when the ‘Pay with PayPal’ button is clicked
      • onCancel triggers when modal is exited or user cancels transaction before processing
      • onError triggers if an error occurs while PayPal is processing order
      • onSuccess triggers when order was successfully authorized in PayPal
  • _getShippingMethods()
    • Set constants with cart and region data, and initialize a methods array
    • If the cart has a shipping service applied, move the service to the first element in the array
    • Get shipping services from region, find the price (net discount), and add the method to the array of methods
      • Methods used in PayPal modal for user to be able to select which service they want

PayPal in repository.js

  • Initialize variables passed in from index.js (store, api, siteRepository, cartRepository, checkoutRepository)
  • setShippingAddress()
    • Require address and service_id data
    • Set constant with cart data (fetched from cartRepository)
    • Call checkoutRepository to set shipping service, and with returned cart data update the shipping address through API
      • Set cart equal to return cart data, updating frontend
  • process()
    • Require orderID and authorizationID data
    • Set constant with cart data (fetched from cartRepository)
    • Call API to process the order, using site cart UUID, and PayPal orderID and authorizationID
      • If successful, update site to the returned empty cart and newly created order data (to display order confirmation page)

PayPal in api.js

  • Initialize using axios passed in from index.js
  • shipping()
    • Use cart UUID and address data to update order address in HQ, returning resulting data (which contains updated cart object)
  • process()
    • Use cart UUID and PayPal’s orderID and authorizationID
    • Post to process order in HQ, passing in PayPal data to verify order detail and amounts
      • If HQ order details match PayPal’s authrized order details, complete order to accept payment, and then process order within HQ
    • Return data (containing empty cart and new order object) to repository call

PayPal in ui/components

  • Register PayPal button as a component using the designated name and imported vue component
  • Use <div> with a unique ID that is passed into the component’s renderButton() method
    • Method calls SDK’s paypal instance to determine if method is available, and if it is, call service’s renderButton method, passing in the necessary 4 callabck methods
    • Each callback method emits its value to be caught within the PayPal component on the website that registers this component, allowing it to display data correctly based on events PayPal passes back

Card

Standard card payments integrate with Authorize.net, but to allow for potentially more providers the SDK uses a factory to loop through methods if any other were available

Card in factory.js

  • Use a switch case to determine what payment methods are available (passed in from the paymentService), and routing calls to the necessary files by initializing those methods
    • As of now, only Authorize.net is used

Card in AuthorizeNet

Card in index.js
  • Initialize api, repository, and service files
  • Create new object (authNet) from the AuthorizeNet imported class, passing it in to the service constructor
  • Route method calls to the service
Card in service.js
  • Initialize repository and authNet passed in from index.js
  • process()
    • Pass in card information (number, month, year, code, name) to verify it is valid (getNonceForCard)
    • When verified and nonce is received, call repository to processNonce, passing in the nonce and customer address
    • If any errors, throw a new error to the frontend
Card in repository.js
  • Initialize store, api, cartRepository, and checkoutRepository passed in from index.js
  • processNonce()
    • Verify the cart exists, and call the API to process the transaction passing in the cart UUID, nonce, and customer address
    • Once complete, set the cart equal to the returned empty cart and return the completed order object (to display order confirmation page)
Card in api.js
  • Initialize using axios passed in from index.js
  • nonce
    • Call HQ to process card payment, passing in the UUID, nonce, and address (which was verified in the repository)
    • Return data (containing empty cart and new order object) to repository call
Card in authorizeNet.js
  • Initialize merchantId, publicKey, and environment passed in from fromPaymentService():14-15
  • Load window script to access Authorize.net payment methods
  • fromPaymentService()
    • Accept service and environment (defaulted to development)
    • Retrieve merchantID and publicKey from the payment service credentials
    • If variables exist, return a new AuthorizeNet class object
  • dispatch()
    • Called to verify the payment method selected
    • Check if the Authorize.net script has loaded (the Accept method)
    • Return a new promise that will resolve if the data is verified
      • Params required are authData and the method needing to be verified (cardData or bankData)
  • getNonceForCard()
    • Create parameter object with formated Authorize.net merchantId and publicKey
    • Specify the cardData, including card number, month, year, code, and full name
    • Call dispatch with card parameters
  • getNonceForBank()
    • Verify the type requested is checking, savings, or businessChecking
    • Create parameter object with formated Authorize.net merchantId and publicKey
    • Specify the bankData, including account number, routing number, name on account, and validated account type
    • Call dispatch with bank parameters

Financing

Financing provides users additional options to pay for their order. Synchrony uses a credit card to provide financing in 6 month and 24 month financing options. SetPay offers financing in 4 payments over 6 weeks. ChargeAfter is similar to synchrony in allowing for multi-month payments.

Financing in factory.js

  • Use a switch case to determine what payment merchants are available (passed in from the paymentService), and routing calls to the necessary files by initializing those methods

Financing with Synchrony

Pretty sure that our contract with Synchrony has been terminated - 2023/08/02

Financing in index.js
  • Initialize api, repository, and service files
  • Create new object (synchrony) from the Synchrony imported class, passing it in to the service constructor
  • Route method calls to the service
Financing in service.js
  • Initialize repository and synchrony passed in from index.js
  • launchCombinedModal()
    • Get cart total and customer shipping address, throwing an error if one or both are not defined
    • Create a params object using the current cart data
    • Call repository to authenticate the transaction
      • Append returned tokenId and clientTransId to the cart parameters, then call launchModal using style 3
    • If modal is successfully launched, call handleResponse
    • Once modal has closed, call repository to get the transaction status
    • After status is received (and data cached on HQ), process the transaction within HQ
  • handleResponse()
    • Return a promise that resolves if the code successfully addes an event listener that waits for the Synchrony modal to close
Financing in repository.js
  • Initialize store, api, cartRepository, and checkoutRepository passed in from index.js
  • getCartTotal()
    • Retrieve cart total and format it for the frontend (e.g., converting the value from 12345 to 123.45)
  • getShippingAddress()
    • Retrieve cart shipping address if it is available, returning null if not
  • authenticate()
    • Call API to authenticate the transaction (using the cart UUID)
      • Ensures payment is available and cart data required is correct
  • getStatus()
    • Call API to get the status of the payment method to see if user can checkout with Synchrony
  • process()
    • Call API to process the order with HQ, passing in the Synchrony API Token again to retrieve the order information needed to verify no alterations were made by user
Financing in api.js
  • Initialize using axios passed in from index.js
  • authenticate()
    • Authenticate the transaction details before allowing for order to processs
  • getStatus()
    • Get status from Synchrony to retrieve order and customer details (used to sync with HQ)
  • process()
    • Call HQ to process the order, passing in the UUID and Synchrony’s API key
      • HQ will get transaction details from Synchrony, verify they match records within the stored cart, and if they align then the order will process
    • Return data (containing empty cart and new order object) to repository call
Financing in synchrony.js
  • Initialize merchantId and environment passed in from fromPaymentService():13
  • Load window script to access Synchrony modal
  • fromPaymentService()
    • Accept service and environment (defaulted to development)
    • Retrieve merchantID from the payment service credentials
    • If variables exist, return a new Synchrony class object
  • launchModal()
    • Open Synchrony payment modal, passing in cart details to be displayed to the user within the modal while they checkout.

SetPay

Download SetPay’s “Helpful” Integration Guide

index.js
  • Initialize api, repository, and service files
  • Create new object (setpay) from the SetPay imported class, passing it in to the service constructor
  • Route method calls to the service
service.js
  • Initialize repository and setpay passed in from index.js
  • Create empty private variables that will be passed in from the frontend (_setLoad, _setTransProgress, _onSuccess)
  • launchWidget()
    • Set configuration by calling repository getSetpayConfit()
    • Initialize callback methods passed in from fronend
    • Set loading status on frontend with callback
      • Greys out the screen and adds a loading sign with text to update the user on what the site is loading
    • Get the cart total and shipping address
      • If either is null, break out of the process
    • Create a params object with formatted data to be passed into the SetPay hidden form
    • Call repository authenticate to retrieve the SetPay Access Token and transaction ID (used to verify the transaction in a later HQ call)
    • Load the SetPay script on the frontend
    • Call _setLoad() to default back to load = false, then call loadForm() to create the hidden form in the widget div
    • Add an event listener with handleResponse() that waits for the SetPay modal to return a ‘closed’ or ‘canceled’ event
    • When the modal is closed/canceled, call repository getStatus() to see if transaction went through
      • Returns false if the user closed the modal, canceled order before processing, or was no approved and was prompted to return to checkout
    • Check if order was complete (true if an account_number is returned from SetPay)
      • If true, update frontend data and call repository process(), else reload on error or return null otherwise
    • If returned value isn’t null, call _onSuccess() to emit event that displays order confirmation page with the return res data
      • Returned data contains an empty cart and the completed order object
  • loadForm()
    • Check if a form was already created, and delete the element if it was
    • Create a new form element
      • Create items in the form from the parameters passed in, and set each to be hidden
    • Locate the setpay-pay-div element in the page and add the form inside for SetPay to access the data
  • handleReponse()
    • Create an event listener that waits for SetPay to emit close-modal or back-to-partner
      • Stays in this promise until resolved, after which the event listener is removed
    • Returns the promise for launchWidget() to use
repository.js
  • Initialize store, api, cartRepository, checkoutRepository, and setpayConfig passed in from index.js
  • getSetpayConfig()
    • Returns the configuation object that was created in the frontend (e.g., DrOzSleep/main.js:431) ::: details Configuration Setup Example
      const setpayIds = {
          partnerId: 'PI60976880',
          merchantId: '6097688000000029',
      }
      ...
      const config = new EcommerceConfig()
      config.setpayConfig = setpayIds
      Vue.use(new Ecommerce(config))
      :::
    • authenticate()
      • Get cart object from cartRepository
      • Call API to authenticate transaction
        • Set cart equal to returned cart data
    • getStatus()
      • Call API to get transaction status
        • Returns response from SetPay with data for whether an account number exists or not (where having an account number means a successful transaction was placed)
    • process()
      • Get cart object from cartRepository
      • Call API to process transaction
        • Returns an empty cart and the completed order object if successful
        • Set cart and order to these returned values
api.js
  • Initialize using axios passed in from index.js
  • authenticate()
    • Verifies transaction and retrieves an OAuth token from SetPay that is used to complete the transaction later
  • getStatus()
    • Passes in merchantNumber from the config to access the site’s SetPay account
    • Calls SetPay’s API to see if a transaction was completed on their end
      • Returns limited order data to be used in the Service to determine next steps
  • process()
    • Calls SetPay’s API to retrieve order details, using the OAuth token generated before this call
      • If the data received matches the data stored in HQ through the cart UUID, the transaction is processed and the empty cart and completed order object are returned
setpay.js
  • Initialize partnerId, merchantId, and environment passed in from fromPaymentService():12-13
  • fromPaymentService()
    • Initialize partnerId and merchantId from values passed in from frontend’s setpayConfig
      • If missing, return null to break out of process before rendering button
    • Return a new SetPay class object
  • loadScript()
    • Use the environment to determine the correct script link
    • Return a promise that creates the script within the body of the page
      • Script is used to communicate with SetPay when requesting to render their button and open their payment modal

ChargeAfter

ChargeAfter Widgets are teh sux

Current integration is causing errors given ChargeAfter’s latest update to their widget. Integration may be modified, so documentation will be needed when this is completed.