Demystified Magento PWA Studio Checkout – Lars Roettig

In: Genel


10 dakika okuma

GitHub’daki gönderiyi düzenle

Varsayılan olarak, PWAStudio Braintree Kredi kartıyla birlikte gelir ve MO’yu kontrol edin (Havale) Ödeme Yöntemi olarak. Bunun iyi bir başlangıç ​​olduğunu söyleyebilirim ama projeniz için belki yeterli değil. Bir Ödeme Yöntemi oluşturmayı öğrenmeden önce, Ödeme İşleminin PWA Studio’da nasıl çalıştığını anlamak kesinlikle daha iyidir. Temel olarak, bu, bileşenlerin var olduğu ve bunları ödeme entegrasyonumuz için nasıl kullandığımızın temelidir.

CheckoutPage.js

Bu bileşen, tek adımlı Ödeme için ana giriş noktasıdır. Oluşturduğu duruma göre bölümleri işler. useCheckoutPage.

Bölüm durumu için Adım Numarası:

peregrine/lib/talons/useCheckoutPage.js

export const CHECKOUT_STEP = {
    SHIPPING_ADDRESS: 1,
    SHIPPING_METHOD: 2,
    PAYMENT: 3,
    REVIEW: 4
};

GitHub Çekirdek Dosyası

PaymentInformation/paymentInformation.js

Ödeme sayfası, ödeme adımında bileşeni görüntüler. ÖDEME.

Şunlardan sorumludur:

  • LoadingIndicator/indicator.js yükte
  • PaymentInformation/summary.js eğer doneEditing=true
  • PaymentInformation/paymentMethods.js eğer doneEditing=false

PaymentInformation/paymentMethods.js

Mevcut tüm Ödemeleri şu şekilde yükler: usePaymentMethods kanca ve onları karşılaştırır paymentMethodCollection.jsMagento Target aracılığıyla oluşturuldu.

Yalnızca her iki listenin de içerdiği bileşenleri işler!

PaymentInformation/paymentMethods.js

const radios = availablePaymentMethods
    .map(({ code, title }) => {
        // If we don't have an implementation for a method type, ignore it.
        if (!Object.keys(payments).includes(code)) {
            return;
        }
        const isSelected = currentSelectedPaymentMethod === code;
        const PaymentMethodComponent = payments[code];
        const renderedComponent = isSelected ? (
            <PaymentMethodComponent
                onPaymentSuccess={onPaymentSuccess}
                onPaymentError={onPaymentError}
                resetShouldSubmit={resetShouldSubmit}
                shouldSubmit={shouldSubmit}
            />
        ) : null;
        return (
            <div key={code} className={classes.payment_method}>
                <Radio
                    label={title}
                    value={code}
                    classes={{
                        label: classes.radio_label
                    }}
                    checked={isSelected}
                />
                {renderedComponent}
            </div>
        );
    })
    .filter(paymentMethod => !!paymentMethod);

GitHub Çekirdek Dosyası

PaymentInformation/summary.js. ReviewStep için bilgi işler

PWA Studio Checkout Ödeme İş Akışı Şeması

Ödeme Ödeme Uzatma noktası

Ödemeyi yeni bir Ödeme Yöntemi ile genişletmek için bir venia hedefi kullanabiliriz. paymentMethodCollection.js.

Hedeflere ve bunun nasıl çalıştığına aşina değilseniz,
PWA Studio Genişletilebilirliğine Başlarken Temel kavramını açıklar.

Resimde, özel uygulamaya izin vermek için fatura adresinin ödeme yöntemlerinin tasarım parçası olduğunu görebiliriz.

Not: Varsayılan Magento’da, siparişi tamamlamadan önce fatura adresinin tarafından ayarlandığından emin olmanız gerekir.

Tüm Ödeme Yöntemlerinin çoğu için fatura adresi formu aynı olacaktır. akımda develop şube bulabilirsin @magento/venia-ui/lib/components/BillingAddress. Ödeme Yönteminizi oluşturmaya başlamak için kopyalayabilirsiniz.

intercept.js

module.exports = (targets) => {
  const { specialFeatures } = targets.of("@magento/pwa-buildpack");
    /**
     *  Wee need to activate esModules, cssModules and GQL Queries to allow build pack to load our extension
     * {@link https://magento.github.io/pwa-studio/pwa-buildpack/reference/configure-webpack/#special-flags}.
     */
  specialFeatures.tap((flags) => {
    flags[targets.name] = {
      esModules: true,
      cssModules: true,
      graphqlQueries: true
    };
  });
 
   /** Registers our Payment **/
  const { checkoutPagePaymentTypes } = targets.of("@magento/venia-ui");
  checkoutPagePaymentTypes.tap((payments) =>
    payments.add({
      paymentCode: "payment-code",
      importPath: "@your-namespace/components/payment.js"
    })
  );
};

Ödeme bileşeniniz, ebeveyn tarafından enjekte edilen aşağıdaki aksesuarları alır.

<YourPaymentMethodComponent
  onPaymentSuccess={onPaymentSuccess}
  onPaymentError={onPaymentError}
  resetShouldSubmit={resetShouldSubmit}
  shouldSubmit={shouldSubmit}
/>
  • onPaymentSuccess:

    Geri Çağırma Yöntemi, gözden geçirme adımına geçmek için aramalıdır. Ödeme yönteminin bir jetona (nonce) ihtiyacı varsa, bu yöntemi çağırmadan önce başarıyla oluşturulmuş olanı almanız gerekir.

  • onPaymentError:

    Ödeme bileşeni hata verdiğinde çağrılacak geri arama

  • resetShouldSubmit:

    İnceleme siparişi düğmesi bayrağını sıfırlamak için geri arama

  • shouldSubmit (read-only):

    İnceleme düğmesi zirveye ulaşırsa doğru olarak değişecektir.

İlk önce bunları çevrimdışı ve çevrimiçi olarak ayırabilecek birçok ödeme yöntemi vardır. Seçenekte iki ana tür Bağlam / Bırakma ve Yönlendirme / Barındırılan ödeme sayfası vardır.

Bir PSP seçmeden önce, uygun bir GraphQL Arka Uç API’sini destekleyip desteklemediklerini kontrol edin, aksi takdirde onları oluşturmak için saatler harcarsınız.

  • Bağlamda / Bırak
  • Yönlendirme/Barındırılan ödeme sayfası

Burada hangi iş akışını bulacaksınız Adobe Ticaret varsayılan olarak destekler.

Adyen Kredi Kartı ile Ödeme İş Akışı 8.2.0

Adyen, son Module sürümüyle birlikte Adobe Commerce için kullanıma hazır bir GraphQL API yayınladı.

Çok iyi bir başlangıç ​​noktası, onların web düşüşü
Bunu ödeme bölümünde işleyin. Başvuru akışınızı kolaylaştırmak için ödeme bölümünde zaten ödeme yöntemi kodunu ayarlamanız gerekir.

mutation setAdyenPaymentOnCartWithAdditionalData(
	$cartId: String!
	$paymentMethod: String!
) {
	setPaymentMethodOnCart(
		input: { cart_id: $cartId, payment_method: { code: $paymentMethod } }
	) {
		cart {
			id
			selected_payment_method {
				code
				title
			}
		}
	}
}
Dikkat !!

Yeni bir ödeme bağlamı oluşturmanızı ve sonucu istemci tarafında bellekteki düşüşten saklamanızı öneririm. Adyen, PCI uyumluluğu açısından şifrelenmiş verileri saklamaz, bkz. setPaymentMethodAndPlaceOrder.

Saklamak için Gerekli Veriler

  • current CartId
  • Json kodlu stateData
  • cc_type

Sipariş Mutasyonu

mutation setPaymentMethodAndPlaceOrder(
    $cartId: String!
    $stateData: String!
) {
    setPaymentMethodOnCart(
        input: {
            cart_id: $cartId
            payment_method: {
                code: "adyen_cc"
                adyen_additional_data_cc: {
                    cc_type: "VI"
                    stateData: $stateData
                }
            }
        }
    ) {
        cart {
            selected_payment_method {
                code
                title
            }
        }
    }
 
    placeOrder(
        input: {
            cart_id: $cartId
        }
    ) {
        order {
            order_id
            adyen_payment_status {
                isFinal
                resultCode
                additionalData
                action
            }
        }
    }
}

PWAStudio sipariş ver düğmesini değiştir

Bazı Ödeme yöntemleri, varsayılan özel düğmeyi kullanmak yerine ek API çağrısı gerektirir.

PayPal ekspres uygulaması açısından, varsayılan sipariş siparişini özel bir siparişle değiştirmek istiyorsunuz.

@custom/checkout/src/components/PlaceOrderButton

import React from 'react';
import LoadingIndicator from '@magento/venia-ui/lib/components/LoadingIndicator';
 
import { usePlaceOrderButton } from '../talons/usePlaceOrderButton';
import placeOrderButtonCollection from './placeOrderButtonCollection';
 
/**
 * Replace the default place order button with a custom one.
 * @see @custom/checkout/src/target/extend-intercept.js
 *
 * @param {object} props
 * @param {React.ReactElement} props.originalPlaceOrderButton
 * @param {function} props.handlePlaceOrder
 * @returns {React.ReactElement}
 */
const PlaceOrderButton = props => {
    const { originalPlaceOrderButton, handlePlaceOrder } = props;
 
    // should fetch the current payment method from cart via a query or context
    const { paymentMethod, loading } = usePlaceOrderButton();
 
 
    if (loading && !paymentMethod) {
        return (
            <LoadingIndicator/>
        );
    }
 
    const PlaceOrderButton = placeOrderButtonCollection[paymentMethod] || null;
 
    if (PlaceOrderButton) {
        // custom place order button if payment method matches with a collection
        return <PlaceOrderButton handlePlaceOrder={handlePlaceOrder} />;
    }
 
    return originalPlaceOrderButton;
};
 
export default PlaceOrderButton;

@custom/checkout/src/components/placeOrderButtonCollection

/**
* This will be populated via webpack and target from a pwa studio
*/
export default {};

Dosyaları arayarak ve bildirerek yeni uzantı noktaları oluşturmamız gerekiyordu. bu pwa-studio.targets.intercept ve pwa-studio.targets.declare senin içindeki tanımlar package.json bu dosyalara yol gerekir.

@custom/checkout/src/target/declare.js

/**
 * These targets are available for interception to modules which depend on `@custom/checkout`.
 *
 * Their implementations can found in `./intercept.js`.
 *
 */
module.exports = targets => {
    targets.declare({
        orderButtonTypes: new targets.types.Sync(['orderButtonTypes']),
    });
};

@custom/checkout/src/target/intercept.js

const { Targetables } = require('@magento/pwa-buildpack');
const OrderButtonTypes = require("./OrderButtonTypes");
 
module.exports = targets => {
    targets.of('@magento/pwa-buildpack').specialFeatures.tap(flags => {
        /**
         *  Wee need to activated esModules and cssModules to allow build pack to load our extension
         * {@link https://magento.github.io/pwa-studio/pwa-buildpack/reference/configure-webpack/#special-flags}.
         */
        flags[targets.name] = {
            esModules: true,
            graphqlQueries: true,
        };
    });
 
    // Make payment button collection extendable
    const venia = Targetables.using(targets);
    new OrderButtonTypes(venia);
 
    const CheckoutPageComponent = venia.reactComponent(
        '@magento/venia-ui/lib/components/checkoutPage'
    );
 
    /**
     * Replace the place order button to the checkout page
     */
    const placeOrderButton = '{placeOrderButton}';
    CheckoutPageComponent.insertBeforeSource(
        placeOrderButton,
        '{customPlaceOrderButton}',
        {
            remove: placeOrderButton.length
        }
    );
 
    const CustomPlaceOrder = CheckoutPageComponent.addImport(
        "CustomPlaceOrder from '@custom/checkout/src/components/placeOrderButton'"
    );
 
    /**
     * Define the custom place order button
     */
    CheckoutPageComponent.insertBeforeSource(
        'const orderSummary',
        `const customPlaceOrderButton = checkoutStep === CHECKOUT_STEP.REVIEW ? (<${CustomPlaceOrder} originalPlaceOrderButton={placeOrderButton} handlePlaceOrder={handlePlaceOrder}></${CustomPlaceOrder}>): null;n`
    );
}

@özel/ödeme/paket.json

{
  "name": "@custom/checkout",
  "version": "0.1.0",
  "main": "src/targets/intercept.js",
 
  "pwa-studio": {
    "targets": {
      "intercept": "src/targets/intercept.js"
    }
  }
}

Modülünüzde oluşturulan hedef nasıl kullanılır:

@ödeme/src/target/intercept.js

module.exports = targets => {
    targets.of('@magento/pwa-buildpack').specialFeatures.tap(flags => {
        /**
         *  Wee need to activated esModules and cssModules to allow build pack to load our extension
         * {@link https://magento.github.io/pwa-studio/pwa-buildpack/reference/configure-webpack/#special-flags}.
         */
        flags[targets.name] = {
            esModules: true,
            cssModules: true,
            graphqlQueries: true,
            i18n: true
        };
    });
    const { orderButtonTypes } = targets.of('@custom/checkout');
    orderButtonTypes.tap(buttons =>
        buttons.add({
            paymentCode: 'payment_method_code',
            importPath: '@my-payment/src/components/placeOrderButtonExpress.js'
        })
    );
}

PWAStudio handlePlaceOrder mutasyonunu / eylemini değiştirin

PSP sağlayıcınız ayden gibi farklı bir yer siparişine ihtiyaç duyuyorsa, sarmanız gerekir. useCheckout.js.

Bunun için, bir mekanizmada binayı zaten kullanabiliriz. peregrine kullanmak. Peregrine pençeleri çağrıldığında ve/veya bu pençelerin davranışını ve çıktısını değiştirmek için. Bu, Magento’nun önleyici modeli olarak bilinen çevre eklentisi konsepti gibidir.

Ayrıca burada, tüm React Hook’larının çağrılması gereken React sınırlamasına da uymalısınız. exact same order her bileşende render. Şu anda var eslint hatası yok Erken kurtarmayı denerseniz, bu, uygulamanızın bellek sızıntısı olmasına veya kararlı olmamasına neden olur!!! Şanslı React’iniz konsolda bir hata yapacaksa, useEffect koşullu denir.

intercept.js

module.exports = targets => {
    targets.of('@magento/pwa-buildpack').specialFeatures.tap(flags => {
        /**
         *  Wee need to activated esModules and cssModules to allow build pack to load our extension
         * {@link https://magento.github.io/pwa-studio/pwa-buildpack/reference/configure-webpack/#special-flags}.
         */
        flags[targets.name] = {
            esModules: true,
            cssModules: true,
            graphqlQueries: true,
            i18n: true
        };
    });
    const { orderButtonTypes } = targets.of('@custom/checkout');
    orderButtonTypes.tap(buttons =>
        buttons.add({
            paymentCode: 'payment_method_code',
            importPath: '@my-payment/src/components/placeOrderButtonExpress.js'
        })
    );
 
 targets.of('@magento/peregrine').talons.tap(talons => {
        talons.CheckoutPage.useCheckoutPage.wrapWith(
            `@my-payment/src/wrapers/uwCheckout`
        );
    });
}
import { useCheckoutFlow } from "../talons/useCheckoutFlow";
 
 
/**
 * Allow extending useCheckout to overwrite function of the hook
 *
 * @param origUseCheckout
 * @returns {function(*): *&{orderNumber: *, placeOrderLoading: boolean, clearCart: ((function(): Promise<void>)|*), orderDetailsLoading: boolean, handlePlaceOrder: ((function(): void)|*), adyenCheckoutAction: *, orderDetailsData: *}}
 */
export default function wrapUseCheckout(origUseCheckout) {
    return function(props) {
        // we cloud also overwrite some props before we execute the useCheckout function.
        const originalReturn = origUseCheckout(props);
        // we partly overwrite the result and extend it
        return { ...originalReturn,...useCheckoutFlow(originalReturn) };
    };
}

pençeler/useCheckoutFlow.js

export const useCheckoutFlow = (props) => {
  const handleAdyenPlaceOrder = useCallback(() => {
    async function placeOrderAndCleanup() {
      await getOrderDetails({
        variables: {
          cartId,
        },
      });
    }
 
    placeOrderAndCleanup();
  }, [cartId, getOrderDetails]);
 
  /**
   * @param methodeCode string
   * @returns {*}
   */
  const isMyPaymentFlow = (methodeCode) => {
    return methodeCode.startsWith('my_payment');
  };
 
  if (isMyPaymentFlow(checkoutState.method) === false) {
    return {
      ...props,
      adyenCheckoutAction,
      orderDetailsLoading,
      clearCart
    };
  }
 
  return {
    orderNumber,
    orderDetailsData,
    orderDetailsLoading,
    handlePlaceOrder: handleAdyenPlaceOrder,
    placeOrderLoading,
    adyenCheckoutAction,
    clearCart
  };
};

Lars Roettig, Kıdemli Yazılım Mühendisidir. TechDivision GmbH. Adobe Commerce ve modern web geliştirmeye odaklanan dijital ajans. Kişisel amacım size kaliteli ve stabil yazılım yazmayı öğretmektir.

Lars hakkında daha fazla bilgi edinin

Bir cevap yazın

Ready to Grow Your Business?

We Serve our Clients’ Best Interests with the Best Marketing Solutions. Find out More

How Can We Help You?

Need to bounce off ideas for an upcoming project or digital campaign? Looking to transform your business with the implementation of full potential digital marketing?

For any career inquiries, please visit our careers page here.
[contact-form-7 404 "Bulunamadı"]