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
split_store_credit_amountsplit_cash_amountsplit_cash_statuspending, received eller declinedsplit_sc_invoice_idsplit_cash_invoice_idTillä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
- Skapa en delad betalnings-POC: App Builder- och AI-verktyg
- Skapa en delad betalning POC: App Builder fulldemo
- Delad betalnings-POC: arkitektur och designbeslut
- Delad betalnings-POC: förutsättningar och miljöinställningar
- Delad betalnings-POC: miljövariabelreferens
- Delad betalnings-POC: Commerce module AI prompt
- Delad betalning POC: App Builder orchestrator AI prompt
- Delad betalning POC: Experience Cloud UI-tillägg - AI-fråga
- Delad betalnings-POC: testnings- och verifieringshandbok
- Dela betalnings-POC: nästa steg efter konceptbeviset
- Dela betalnings-POC: självstudiekurs, snabbreferens för författare