boboko-core · competitive gap survey · 03

What payments elsewhere can do that boboko can't yet

Lunar's payment layer (Lunar\Facades\Payments, Transaction, the offline driver) is wired for a single "pay on delivery / bank transfer" flow. Everything downstream of that — cards, wallets, saved methods, self-service refunds, retries — is either scaffolded in Lunar core and unused here, or absent from the stack entirely. This is a research survey, not a build plan.

4 have 9 partial 14 missing
01

Payment method breadth

boboko currently ships one payment type: cash-in-hand via the offline driver. Every card/wallet/BNPL path below is theoretically pluggable but has zero live implementation.

Offline / pay-on-accounthave
The only configured type in config/lunar/payments.php (3dealer's published copy): 'cash-in-hand' => ['driver' => 'offline', 'authorized' => 'payment-offline'], backed by Lunar\PaymentTypes\OfflinePayment.
Card payments (Stripe/other gateway)missing
lunarphp/stripe is not present in either boboko-core/vendor/lunarphp or 3dealer/vendor/lunarphp, and not listed in either composer.json. docs/lunar.md's Stripe section documents Lunar's general capability, not something wired into this project.
Digital wallets (Apple Pay, Google Pay, Shop Pay)missing
Depends entirely on a card gateway (Stripe Payment Request Button or similar) that isn't installed. Shopify bundles Apple Pay, Google Pay, and Shop Pay as one-tap checkout by default.
Buy-now-pay-later (Klarna, Afterpay, Affirm)missing
No BNPL driver or config entry anywhere in the repo. Shopify bundles Klarna natively in eligible regions with Pay-in-4, Pay-Later, and financing tiers; WooCommerce and PrestaShop both offer it as installable gateway plugins.
Bank transfer / open banking (SEPA, Pay by Bank)missing
Not represented as a distinct payment type; only the generic cash-in-hand offline flow exists, which is manual reconciliation rather than an automated bank-transfer rail.
Crypto / stablecoin checkoutmissing
No driver, no research finding of it being used in this stack. Industry-wide it's still marginal — stablecoin payment volume is roughly 0.02% of global payments in 2026 per Nuvei's trend report — so this is low-priority even elsewhere.
Pluggable driver architecture for adding methodshave
Lunar\Managers\PaymentManager extends Laravel's Manager; Payments::extend('custom', fn ($app) => ...) registers a new driver, and any class extending Lunar\PaymentTypes\AbstractPayment implementing authorize()/capture()/refund() plugs in. The scaffolding is solid — nothing beyond offline is plugged into it yet.
02

Capture, refund & transaction lifecycle

The core primitives (intent/capture/refund, partial amounts, transaction chaining) exist in Lunar and are exposed in the Filament admin — but nothing calls them outside cash-in-hand, and none of it is customer-facing.

Authorize / capture / refund contracthave
Lunar\Base\PaymentTypeInterface defines authorize(), capture(Transaction $t, $amount), refund(Transaction $t, int $amount, $notes); Transaction::capture()/refund() forward to the transaction's own driver() via Payments::driver($this->driver).
Manual vs. automatic capture policypartial
The interface supports separate authorize/capture steps (intent vs. capture transaction types), but OfflinePayment::capture() just returns new PaymentCapture(true) unconditionally — there's no real deferred-capture gateway wired up to exercise the distinction.
Partial capturepartial
Admin Filament action passes an arbitrary $data['amount'] to $transaction->capture(bcmul($data['amount'], $record->currency->factor)) in ManageOrder.php — the plumbing supports partial amounts, but only staff can trigger it, and only against a real (non-offline) driver would it mean anything.
Partial / staged refundshave
Same file: the "refund" Filament action computes $response = $transaction->refund(bcmul($data['amount'], ...), $data['notes']), and isPartiallyRefunded() / order status logic (partial-refund, refunded) compares refundTotal against captureTotal/intentTotal. This genuinely works today through the offline driver's no-op refund().
Multiple payment attempts per orderpartial
Transaction.parent_transaction_id chains captures to intents and refunds to captures, and nothing in the model stops multiple transaction rows per order — but no code path in this repo actually retries a failed attempt with a second transaction; it's schema support, not a driven flow.
Transaction audit trailhave
Lunar\Observers\TransactionObserver::created() logs every transaction (amount, type, status, card_type, last_four, reference, notes) via Spatie activity log automatically — this is real and unconditional, independent of driver.
Webhook handling for async payment eventsmissing
Lunar's Stripe package registers a stripe/webhook route, but that package isn't installed here, so there is no webhook endpoint of any kind in this project today.
Payment attempt events for downstream hookshave
Lunar\Events\PaymentAttemptEvent is dispatched from OfflinePayment::authorize() with the resulting PaymentAuthorize DTO — a real, listenable event, though only one driver currently fires it.
03

Customer-facing payment experience

Everything a shopper would touch directly — saved cards, one-click repeat purchase, self-service refunds — is absent. Lunar's payment layer is staff/checkout-oriented, not account-oriented.

Saved payment methods on customer accountmissing
No vault/tokenization model exists anywhere in Lunar\Models — no PaymentMethod/Card model, no field on Customer. 2026 trend research (Nuvei, Checkout.com) treats network-tokenized saved cards as baseline for one-click checkout.
One-click repeat purchasemissing
Depends on saved payment methods, which don't exist. No "reorder" or "buy again" affordance found in boboko-core or 3dealer.
Customer self-service refund requestsmissing
The only refund entry point is the Filament staff action in ManageOrder.php (Actions\Action::make('refund')), gated behind admin auth. WooCommerce/PrestaShop ecosystems commonly expose a customer-initiated return/refund request flow; nothing equivalent exists here.
Split / partial payment plans (pay-in-installments at checkout)missing
Distinct from BNPL-as-a-gateway: this is a native "split into N charges" checkout option, seen as marketplace split-payment modules in the PrestaShop ecosystem. No equivalent concept in Lunar's cart/order/payment pipeline.
3D Secure / SCA authenticationmissing
3DS is a property of the card gateway integration (e.g. Stripe PaymentIntents), which isn't installed. WooPayments explicitly advertises 3DS/SCA compatibility with visible card-brand + last-four confirmation as a baseline expectation in 2026.
Fraud detection / risk scoringmissing
No fraud-scoring hook in PaymentTypeInterface or the offline driver. getPaymentChecks() exists as an extension point (Lunar\Base\DataTransferObjects\PaymentChecks, an iterable of pass/fail PaymentCheck DTOs) but AbstractPayment::getPaymentChecks() just returns an empty collection — real fraud tooling (Stripe Radar-style) isn't behind it.
Payment check / validation extension pointpartial
Transaction::paymentChecks() → driver's getPaymentChecks($transaction) is real, typed infrastructure for surfacing checks (e.g. "AVS matched") in the admin UI — but the default implementation is a no-op, so nothing populates it today.
04

Currency, subscriptions & recurring billing

Lunar's multi-currency model covers pricing display, not multi-currency payment settlement; recurring billing/dunning has no representation at all.

Multi-currency pricing displayhave
Lunar\Models\Currency (code, exchange_rate, decimal_places, default) with sync_prices-gated conversion, documented in docs/lunar.md "Channels and Currencies" — this is genuinely wired, cart/pricing layer already uses it.
Multi-currency payment processing (charge in customer's currency)partial
Pricing can display and calculate in any configured currency, but no payment driver in this project actually settles a charge — so whether a real gateway would charge in-currency is untested; the pricing half is there, the processing half isn't proven.
Recurring billing / subscriptionsmissing
No subscription model, no recurring-charge scheduler anywhere in Lunar\Models or boboko-core. This is a one-time-purchase order/cart model end to end.
Failed-payment retry / dunningmissing
No retry scheduling, no dunning email sequence, no soft-decline handling anywhere in the payment layer — there's nothing to retry against since there's no recurring billing and no live gateway. WooPayments' dunning (1-3 day delayed retry on soft declines) is the comparison point.
PCI compliance / tokenized card storagemissing
No card data is collected or stored anywhere in this codebase (offline driver never touches card fields), so there's no PCI-scope exposure today — but also no tokenized-vault capability to build saved cards or 3DS on top of when a real gateway is added.