Delad betalnings-POC: arkitektur och designbeslut

På den här sidan förklaras de arkitektoniska valen bakom det delade betalningsbeviset för konceptet. Läs det innan du använder bygganvisningarna i den här serien, så att du förstår hur varje komponent är strukturerad och hur du anpassar mönstren i ditt eget projekt.

Grundprincipen

Konceptbeviset handlar inte om den mest eleganta delade betalningsimplementeringen. Det handlar om att visa hur du kan börja flytta Commerce-logik till App Builder utan att behöva skriva om stora band.

Regeln som tillämpas genomgående är:

Om något måste köras synkront i Commerce-begärandecykeln, eller om det måste anropa Commerce-interna API:er som inte har någon ren extern yta, stannar det kvar i PHP. Allt annat flyttas till App Builder.

Vad finns i Commerce (PHP) och varför

​1. Butikskreditprogram: PlaceOrderPlugin

Butikskrediten tillämpas på vagnen med Magento\CustomerBalance\Api\BalanceManagementInterface::apply(). Den här metoden fungerar bara på en aktiv-kundvagn. Kundvagnen blir inaktiv när ordern läggs. App Builder tar emot I/O-händelsen efter att ordern har placerats, så det går inte att tillämpa butikskrediten från App Builder.

Lektionen: Allt som måste ändras i kundvagnens tillstånd innan orderplaceringen kan köras i Commerce. Det finns ingen lösning.

​2. Synkron tröskelvärdesskydd: CheckoutPlugin

Beställningströskelkontrollen på $100 måste blockera kunden i betalningssteget, innan de väljer Place Order. Svaret måste vara synkront i Commerce begärandecykel. App Builder är händelsestyrt och asynkront, så det går inte att returnera ett omedelbart fel i det ögonblicket.

App Builder validerar också tröskelvärdet (som en granskning), men kundupplevelsen beror först på att Commerce-kontrollen körs.

​3. Anpassade REST-slutpunkter: webapi.xml och SplitPaymentManagement

Följande slutpunkter måste:

  • Anropa SplitInvoiceService (fakturor som använder Commerce interna fakturatjänst)
  • Anropa ShipOrder::execute() (Commerce interna leveranstjänst)
  • Uppdatera orderstatus och status med Commerce ordertillståndsdator

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

Det finns inget rent offentligt REST-lager för det beteendet, så Commerce visar slutpunkterna. App Builder kallar dem.

​4. Dela belopp på offert och order: observatörer och plugin-program

Commerce behöver delningsbeloppen (split_store_credit_amount, split_cash_amount, split_cash_status) för ordern, både för REST-svaren som App Builder läser och för Admin-ordervyn. Beloppen är kopplade med tilläggsattribut och kopieras från offerten till ordningen i en observatör på sales_model_service_quote_submit_before.

Vad finns i App Builder och varför

​1. Händelsestyrd orderbearbetning: payment-orchestrator

När sales_order_place_before har utlösts tar App Builder emot händelsen. Det validerar tröskelvärdet (som en granskning), registrerar en kontantkommentar på ordern och uppdaterar orderstatusen. Inget av detta kräver en ny PHP, bara REST till Commerce.

​2. Kontantgodkännande: payment-accept

När en ERP (eller en operator i kontrollpanelen) bekräftar att kontanter har tagits emot, payment-accept anropar POST /V1/split-payment/orders/:id/cash-received. Faktura, leverans och orderstatus hanteras i Commerce. App Builder är utlösaren.

​3. Kontantavböjning: payment-decline

payment-decline anropar POST /V1/split-payment/orders/:id/cash-decline och Commerce avbryter ordern. Samma mönster som kontantgodkännande.

​4. Kontrollpanel för operator: demo-dashboard

En komplett HTML-kontrollpanel kom från App Builder webbåtgärd. Den hämtar order som väntar på kontanter från Commerce REST och tillhandahåller Accept / Decline åtgärder som anropar App Builder åtgärder ovan. Commerce Admin krävs inte.

Tröskelvärdet: två gånger används för ändamålet

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 äger den användarvänliga bevakningen. App Builder äger efterhandsgranskningen. Det är avsiktligt.

Butikskrediten: varför den stannar i 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)

Filen store-credit.js i orchestrator dokumenterar detta. Det är en helhetsbild med kommentarer som förklarar varför det inte används.

Tilläggsattribut: limmet

Delade mängder rör sig genom systemet på tilläggsattribut:

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

Datamodell

sales_orderplatta kolumner som läggs till i den här modulen

Kolumn
Typ
Syfte
split_store_credit_amount
float
Butikskredit som tillämpades
split_cash_amount
float
Förfallet kontantbelopp
split_cash_status
varchar
pending, received eller declined
split_sc_invoice_id
int
Enhets-ID för butikskreditfakturan
split_cash_invoice_id
int
Enhets-ID för kontantfakturan

Tilläggsattribut (på CartInterface, OrderInterface och OrderPaymentInterface)

  • split_store_credit_amount (flytande)
  • split_cash_amount (flytande)
  • split_cash_status (sträng)

I/O-händelsens nyttolastfält

observer.sales_order_place_before är konfigurerad i io_events.xml för att inkludera följande i händelsen:

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

App Builder använder entity_id som order-ID och split_store_credit_amount och split_cash_amount för tröskelvalidering.

De fem utkanterna som konceptbeviset täcker

1. CapCustomerBalanceCollectPlugin

Commerce inbyggda Customer balance total-insamlare kan övertillämpa (den kan se hela det tillgängliga saldot, inte det sessionsdeklarerade delningsbeloppet). Detta plugin-program kapslar beloppet till det värde som deklarerats i sessionen.

2. FixSplitPaymentGrandTotalPlugin

När butikskrediten har tillämpats kan offerten Grand Total sänkas till det kassakassabelopp som gäller. Utcheckningen av JavaScript måste beräkna ordersumman för delad validering före som ändras. Plugin-programmet körs efter totalmängden och korrigerar visningen, medan JavaScript inte litar på enbart grand_total och rekonstruerar värdet från delsummeringssegment.

3. FixInvoiceCustomerBalanceAfterTotalsPlugin

När fakturasummor har registrerats kan butikskrediter användas två gånger. Denna plugin korrigerar customer_balance_amount på fakturor.

4. SplitPaymentZeroTotalPlugin

När butikskrediten har tillämpats kan kundvagnen Grand Total vara $0 (kreditorder för fullständig butik). Commerce Zero subtotal checkout-kontroll kan blockera postförskott i så fall. Denna plugin tillåter postförskott när sessionsbeloppet är större än 0.

​5. Offertsamling före BalanceManagementInterface::apply()

apply() kontrollerar beloppet mot aktuell Grand Total. Om summan redan är kassadelen kan apply() misslyckas eller sätta ett tak. PlaceOrderPlugin gör tillfälligt uppehåll i heltalskorrigeringen när balans används, med en sessionsflagga (beginBalanceApply / endBalanceApply).

Relaterade POC-resurser för delad betalning

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