eduardweb.
Payments (Stripe, PayPal, Netopia)Avansat#woocommerce#stripe#php#stripe-connect#marketplace

Split Payments în WooCommerce cu Stripe Connect: De la Separate Charges la refund-uri

De Bogdan Răducanu, 7 aug. 2026 · 3 vizualizări · 3 like-uri

Postat 7 aug. 2026
php
add_action('woocommerce_order_status_processing', 'my_custom_split_payment_stripe', 10, 1);
function my_custom_split_payment_stripe($order_id) {
    $order = wc_get_order($order_id);
    if (!$order || $order->get_meta('_stripe_transfers_completed')) {
        return;
    }

    \Stripe\Stripe::setApiKey(STRIPE_SECRET_KEY);

    foreach ($order->get_items() as $item_id => $item) {
        $vendor_stripe_account = get_post_meta($item->get_product_id(), '_vendor_stripe_account_id', true);
        $already_transferred = $item->get_meta('_stripe_transfer_id');

        if ($vendor_stripe_account && !$already_transferred) {
            // Retinem 12% comision platforma, trimitem 88% la vendor
            $amount_in_cents = intval(($item->get_total() * 0.88) * 100);

            try {
                $transfer = \Stripe\Transfer::create([
                    'amount' => $amount_in_cents,
                    'currency' => strtolower($order->get_currency()),
                    'destination' => $vendor_stripe_account,
                    'transfer_group' => 'ORDER_' . $order->get_id(),
                ]);

                $item->update_meta_data('_stripe_transfer_id', $transfer->id);
                $item->save();
            } catch (\Exception $e) {
                $order->add_order_note('Eroare transfer Stripe Vendor: ' . $e->getMessage());
            }
        }
    }

    $order->update_meta_data('_stripe_transfers_completed', '1');
    $order->save();
}

Dacă ai făcut vreodată un marketplace pe WooCommerce, știi că momentul în care trebuie să împarți banii între mai mulți vendori și platformă la un singur checkout e cel mai rapid mod de a-ți pierde somnul. Am implementat Stripe Connect pe un proiect cu 110 vendori activi și vreo 3.000 de comenzi pe lună, iar pluginurile clasice de Dokan sau WCFM pur și simplu se blocau la scenarii mai atipice. Am fost nevoit să scriu integrarea direct pe API-ul lor.

În postarea asta scurtă vreau să explic arhitectura corectă și capcanele mari de care m-am lovit pe parcurs.

Arhitectura: Destination Charges vs Separate Charges and Transfers

Când lucrezi cu Stripe Connect în WooCommerce, ai două opțiuni mari pentru fluxul de bani: Destination Charges și Separate Charges & Transfers. Prima opțiune e simplă, dar limitată. Dacă un client cumpără un tricou de la Vendor A și o cană de la Vendor B într-un singur coș Woo, Destination Charges pica din start pentru că Stripe nu știe să trimită banii direct către doi vendori diferiți într-o singură tranzacție PaymentIntent de tip destination.

Soluția pe care am mers a fost Separate Charges and Transfers. Cumpărătorul plătește suma totală către platforma ta (se creează un PaymentIntent pe contul principal), iar la hook-ul de processing sau la webhook-ul de payment succeeded, declanșezi transferuri separate către conturile Stripe Connect ale vendorilor.

Trade-off-ul e evident și dureros: platforma preia tot riscul financiar și comisioanele de procesare (acei ~1.4% + 1 leu) pe toată suma. Dacă Vendor A nu trimite produsul și clientul cere chargeback, banii ies din contul tău principal, iar tu trebuie să-ți recuperezi manual suma de la vendor printr-un Reverse Transfer.

Unde se leagă codul și problema de idempotență

Nu recomand să modifici pluginul oficial Stripe din Woo. Mai bine îți faci o extensie proprie care ascultă schimbarile de status. Noi am prins momentul în care comanda trece în processing. Se calculează comisionul platformei (în cazul nostru 12%), iar restul se trimite prin Stripe\Transfer.

Trebuie să fii hiper-atent la idempotență. Dacă WooCommerce declanșează din greșeală de două ori hook-ul (sau dacă un operator din wp-admin dă click de două ori pe "Mark as Processing"), riști să trimiți transferul de două ori. Salvează mereu transfer_id-ul în order_itemmeta pentru fiecare linie din comandă și verifică dacă există înainte de a apela API-ul Stripe.

Coșmarul refund-urilor parțiale

Aici am pierdut cel mai mult timp. Să zicem că avem o comandă de 500 RON (200 RON Vendor A, 300 RON Vendor B). Clientul vrea refund doar pe produsul Vendorului A.

Dacă faci refund simplu din WooCommerce, sistemul va încerca să returneze banii direct din soldul contului tău principal. Trebuie să prinzi hook-ul woocommerce_order_refunded și să apelezi Stripe\Transfer::createReversal(). Dacă vendorul și-a scos deja banii din Stripe în contul lui bancar, contul lui Stripe Connect va trece pe sold negativ, iar tu ești cel care acoperă temporar gaura până își alimentează el contul.

Tu cum ai rezolvat split-ul pe WooCommerce? Ai mers pe pluginuri gata făcute gen WCFM/Dokan sau ți-ai scris integrarea custom cu SDK-ul Stripe?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.