Skip to content

How to finish the active transaction #704

@stepan-twnty

Description

@stepan-twnty

I use Google Pay, and when something goes wrong, I redirect the user to the Failure page.

For example, the user didn't pass 3D authentication. Below is my code where you can check all occasions of redirection to the Failure page (check where the forwardToFailurePage function is called). The problem occurs when the user tries to choose another payment method on the Failure page and than Shopware returns the error: The order has an active transaction - 019899b8ba3d703f829f4fac4a13dd21. I understand that the status of the order is In progress, that's why I see the error, but using Store-API, I can't change the status of the Payment.

Can you help deal with the situation?

import React, { ReactElement } from 'react'
import { useRouter } from 'next/router'
import { AdyenCheckout } from '@adyen/adyen-web'

import Preloader from '@comp/atoms/Preloader'
import LayoutSecure, { MetaDataI } from '@comp/templates/LayoutSecure'
import useShopware from '@hooks/useShopware'
import useStatus, { Status } from '@hooks/useStatus'
import useHeaderDimensions from '@hooks/useHeaderDimensions'
import { environment, path } from '@configs'
import { addExceptionToLog } from '@utils/addExceptionToLog'

import type { NextPageWithLayout } from '@pages/_app'

const AdyenFinalize: NextPageWithLayout = () => {
  const threeDRef = React.useRef<HTMLDivElement>(null)
  const [status, setStatus] = useStatus()
  const router = useRouter()
  const { headerHeightInRem } = useHeaderDimensions()
  const shopwareApiClient = useShopware()
  const orderId = Array.isArray(router.query.orderId) ? router.query.orderId[0] : router.query.orderId
  const thankYouPage = `${path.CHECKOUT_THANK_YOU}?order=${orderId}`
  const failurePage = `${path.CHECKOUT_FAILURE}?order=${orderId}`

  const forwardToFailurePage = async () => {
    //change payment status to Failed?
    await router.push(failurePage)

    return
  }

  React.useEffect(() => {
    let ignore = false
    if (!router.isReady || !threeDRef.current) return
    if (!orderId) return void forwardToFailurePage()

    const handleAdditionalActions = async () => {
      try {
        setStatus(Status.loading)
        const paymentStatus = await shopwareApiClient.invoke('readAdyenPaymentStatus post /adyen/payment-status', {
          body: { orderId },
        })

        if (paymentStatus.data.isFinal && paymentStatus.data.resultCode === 'Refused') {
          return await forwardToFailurePage()
        }
        if (paymentStatus.data.isFinal) return void router.push(thankYouPage)
        if (!paymentStatus.data.action?.type) {
          const errorMessage = `Adyen returns action undefined which we not able handle. Data: ${JSON.stringify(paymentStatus.data)}`
          await addExceptionToLog(new Error(errorMessage))

          return await forwardToFailurePage()
        }

        const checkout = await AdyenCheckout({
          countryCode: 'DE',
          environment: environment.isProduction ? 'live' : 'test',
          clientKey: process.env.NEXT_PUBLIC_ADYEN_SECRET,
          onAdditionalDetails: async (state, _, actions) => {
            const additionalPaymentDetails = await shopwareApiClient.invoke(
              'submitAdyenAdditionalPaymentDetails post /adyen/payment-details',
              { body: { orderId, stateData: JSON.stringify(state.data) } }
            )

            if (!actions && additionalPaymentDetails.data.resultCode === 'Authorised') {
              return void router.push(thankYouPage)
            }
            if (!actions && additionalPaymentDetails.data.resultCode === 'Refused') {
              return void router.push(failurePage)
            }

            actions.resolve({ resultCode: additionalPaymentDetails.data.resultCode })
          },
          onPaymentCompleted() {
            router.push(thankYouPage)
          },
          onPaymentFailed() {
            forwardToFailurePage()
          },
        })
        const component = checkout.createFromAction(paymentStatus.data.action, { challengeWindowSize: '02' })

        if (!ignore) {
          component
            .isAvailable()
            .then(() => {
              if (!threeDRef.current) return

              component.mount(threeDRef.current)
              setStatus(Status.succeeded)
            })
            .catch(() => void forwardToFailurePage())
        }
      } catch (e) {
        void forwardToFailurePage()
      }
    }

    void handleAdditionalActions()

    return () => {
      ignore = true
    }
  }, [router.isReady, orderId, thankYouPage, failurePage])

  return (
    <div className="relative flex items-center justify-center" style={{ height: `calc(100vh - ${headerHeightInRem})` }}>
      {status === Status.loading && (
        <div className="absolute z-10 flex size-full items-center justify-center bg-white-60 opacity-80">
          <Preloader />
        </div>
      )}
      <div ref={threeDRef} />
    </div>
  )
}

AdyenFinalize.getLayout = function getLayout(page: ReactElement) {
  const seoData: MetaDataI = { title: 'Wir arbeiten an Ihrer Bestellung | Priwatt' }

  return (
    <LayoutSecure seoData={seoData} isNewsLetterVisible={false} isNoIndex>
      {page}
    </LayoutSecure>
  )
}

export default AdyenFinalize

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions