分割払いPOC:アーキテクチャとデザインの決定

このページでは、分割支払い概念実証の背後にあるアーキテクチャの選択について説明します。 このシリーズでは、ビルドプロンプトを使用する前に、各コンポーネントの構造と、独自のプロジェクト内のパターンの適応方法について理解しておきましょう。

基本原則

概念実証は、最も洗練された分割支払いの実装についてではありません。 ビッグバンの書き換えなしで​Commerce ロジックをApp Builderに移行する方法を示します

全体を通して適用されるルールは次のとおりです。

何かがCommerce リクエストサイクルで同期的に実行される必要がある場合、またはクリーンな外部サーフェスを持たないCommerce内部APIを呼び出す必要がある場合、PHP内に残ります。 それ以外はすべてApp Builderに移動します。

Commerce(PHP)の概要とその理由

​1. ストア クレジット アプリケーション:PlaceOrderPlugin

店舗のクレジットは、Magento\CustomerBalance\Api\BalanceManagementInterface::apply()を使用してカートに適用されます。 この方法は、アクティブ​の買い物かごでのみ機能します。 注文が確定すると、カートは無効になります。 App Builderは、注文が完了した​ 後にI/O イベント ​を受け取るので、App Builderから店舗クレジットを適用することはできません。

レッスン :​注文前に買い物かごの状態を変更する必要があるすべては、Commerceで実行する必要があります。 回避策はありません。

​2. 同期しきい値ガード:CheckoutPlugin

$100の注文しきい値チェックでは、顧客が​ Place Order ​を選択する前に、支払い手順で顧客をブロックする必要があります。 応答は、Commerce リクエストサイクルで同期している必要があります。 App Builderはイベント駆動型で非同期なので、その瞬間に直ちにエラーを返すことはできません。

App Builder ​は(監査として)しきい値を検証しますが、カスタマーエクスペリエンスは、最初に実行されるCommerce チェックによって異なります。

​3. カスタム REST エンドポイント:webapi.xmlおよびSplitPaymentManagement

以下のエンドポイントが必要です。

  • SplitInvoiceServiceを呼び出します(Commerce内部請求書サービスを使用する請求書)
  • ShipOrder::execute()を呼び出します(Commerceの社内配送サービス)
  • Commerceの注文状況マシンで注文状況とステータスを更新する

/V1/split-payment/orders/:id/cash-received/V1/split-payment/orders/:id/cash-decline

このビヘイビアーにはクリーンなパブリック REST レイヤーがないので、Commerceはエンドポイントを公開します。 App Builderが呼び出します。

​4. 見積もりと注文の金額を分割:オブザーバーとプラグイン

Commerceでは、App Builderが読み取るREST応答と​ Admin ​注文ビューの両方で、注文に分割金額(split_store_credit_amountsplit_cash_amountsplit_cash_status)が必要です。 金額は拡張子属性で添付され、引用符からsales_model_service_quote_submit_beforeの観察者の順序にコピーされます。

App Builderの概要とその理由

​1. イベント駆動型の注文処理:payment-orchestrator

sales_order_place_beforeが発生すると、App Builderはイベントを受け取ります。 しきい値を再検証し(監査として)、注文に対する​ 現金保留中 ​のコメントを記録し、注文ステータスを更新します。 これには新しいPHPは必要なく、CommerceへのRESTのみが必要です。

​2. 現金受け入れ:payment-accept

ERP (またはダッシュボードのオペレーター)が現金を受け取ったことを確認すると、payment-acceptさんがPOST /V1/split-payment/orders/:id/cash-receivedに電話します。 請求書、発送、注文状況はCommerceで処理されます。 App Builderはトリガーです。

​3. 現金減少:payment-decline

payment-declineさんがPOST /V1/split-payment/orders/:id/cash-declineに電話し、Commerceが注文をキャンセルします。 現金受け入れと同じパターンです。

​4. オペレーターダッシュボード:demo-dashboard

App Builder web アクションから提供される自己完結型のHTML ダッシュボード。 これは、Commerce RESTから現金を待っている注文を取得し、上記のApp Builder アクションを呼び出す​Accept / Decline アクションを提供します。 Commerce Admin​は必要ありません。

しきい値:目的に応じて2回実施

Customer at checkout
        |
        v
[Commerce: CheckoutPlugin]     <- Synchronous, blocks immediately, user sees error
        |
        |  (if somehow bypassed: direct API call, and so on)
        v
[Order placed] -> I/O Event -> [App Builder: payment-orchestrator]
                                        |
                                        v
                              [evaluateThreshold()]  <- Async audit, records failure comment

Commerceがユーザー向けガードを所有し、App Builderがプレースメント後の監査を所有します。 それは意図的なことです。

ストアクレジット:なぜPHPに留まるか

What you might think would work (it does not):
  Order placed -> I/O Event -> App Builder -> PUT /V1/carts/:id/store-credit
  (Fails: cart is inactive after place order)

What actually works:
  AroundPlaceOrder plugin
  -> BalanceManagementInterface::apply($cartId, $amount)  <- cart is still active
  -> place order
  -> order placed
  -> I/O event: App Builder (store credit is already applied)

オーケストレーターのstore-credit.js ファイルがこれを文書化します。 なぜそれが使用されないのかを説明するコメント付きのノーアップスタブです。

拡張機能の属性:接着剤

分割金額は、次の拡張機能の属性でシステム内を移動します。

Checkout JavaScript (Knockout)
    |  POST /V1/split-payment/set
    v
SplitPaymentSession (PHP session)
    |  AroundPlaceOrder reads the session
    v
CartInterface extension attributes
    |  `sales_model_service_quote_submit_before` observer
    v
OrderInterface extension attributes -> `sales_order` flat columns
    |  I/O event payload includes these fields
    v
App Builder `payment-orchestrator` reads the split amounts

データモデル

このモジュールが追加する​sales_order個のフラット列

タイプ
目的
split_store_credit_amount
浮動小数
適用されたストアクレジット
split_cash_amount
浮動小数
現金支払期限
split_cash_status
varchar
pendingreceivedまたはdeclined
split_sc_invoice_id
int
店舗クレジット請求書のエンティティ ID
split_cash_invoice_id
int
現金請求書のエンティティ ID

拡張機能の属性CartInterfaceOrderInterfaceOrderPaymentInterface上)

  • split_store_credit_amount (浮動小数)
  • split_cash_amount (浮動小数)
  • split_cash_status (文字列)

I/O イベントペイロードフィールド

observer.sales_order_place_beforeio_events.xmlで設定されており、イベントに次のものが含まれます。

entity_id, quote_id, increment_id, subtotal,
split_store_credit_amount, split_cash_amount, split_cash_status

App Builderでは、注文IDとしてentity_idを使用し、しきい値の検証にsplit_store_credit_amountsplit_cash_amountを使用します。

概念実証でカバーされている5つのエッジケース

1. CapCustomerBalanceCollectPlugin

Commerceのネイティブ Customer balance​の合計コレクターは、過剰に適用できます(セッションで宣言された分割金額ではなく、利用可能な完全な残高を確認できます)。 このプラグインは、セッションで宣言された値に金額を上限とします。

2. FixSplitPaymentGrandTotalPlugin

店舗のクレジットが適用された後、見積もり​ Grand Total ​は現金のみの金額に落ちる可能性があります。 チェックアウト JavaScriptでは、その変更の​ ​にスプリット検証を行うための注文合計を計算する必要があります。 プラグインは合計コレクションの後に実行され、表示を修正しますが、JavaScriptはgrand_totalのみを信頼せず、小計セグメントから値を再構築します。

3. FixInvoiceCustomerBalanceAfterTotalsPlugin

請求書の合計が再収集されると、ストアクレジットを2回適用できます。 このプラグインは、請求書のcustomer_balance_amountを修正します。

4. SplitPaymentZeroTotalPlugin

店舗のクレジットが適用された後、買い物かご​ Grand Total ​は$0 (店舗のクレジット注文の全額)になります。 Commerceの​Zero subtotal checkout チェックは、その場合にCODをブロックできます。 このプラグインを使用すると、セッションのキャッシュ金額が0より大きい場合にCODを使用できます。

​5. BalanceManagementInterface::apply()以前の見積もり回収

apply()は、現在の​ Grand Total ​に対して金額をチェックします。 合計が既に現金部分のみの場合、apply()は失敗または上限を設定できます。 PlaceOrderPluginは、セッションフラグ (beginBalanceApply / endBalanceApply)を使用して、残高が適用されている間、総修正を一時的に一時停止します。

関連する分割支払POC リソース

recommendation-more-help
commerce-learn-help-home