Fix: Stripping Lunar's Stripe Driver with Boboko's Stripe Payment Driver
This commit is contained in:
@@ -4,9 +4,6 @@ namespace Modules\Core\Payment\Drivers;
|
||||
|
||||
use Lunar\DataTypes\Price;
|
||||
use Lunar\Models\Currency;
|
||||
use Lunar\Stripe\Facades\Stripe;
|
||||
use Lunar\Stripe\Managers\StripeManager;
|
||||
use Lunar\Stripe\Models\StripePaymentIntent;
|
||||
use Modules\Core\Payment\Contracts\Configurable;
|
||||
use Modules\Core\Payment\Contracts\HandlesPaymentCallback;
|
||||
use Modules\Core\Payment\Contracts\SupportsAuthorization;
|
||||
@@ -26,17 +23,20 @@ use Modules\Core\Payment\Events\PaymentRefundFailed;
|
||||
use Modules\Core\Payment\Events\PaymentRefunded;
|
||||
use Modules\Core\Payment\Events\PaymentVoidFailed;
|
||||
use Modules\Core\Payment\Events\PaymentVoided;
|
||||
use Modules\Core\Payment\Models\StripePaymentIntent;
|
||||
use Modules\Core\Payment\Support\StripeManager;
|
||||
use Stripe\Exception\ApiErrorException;
|
||||
use Stripe\PaymentIntent;
|
||||
|
||||
/**
|
||||
* Talks to Stripe's PaymentIntent API directly — deliberately NOT via
|
||||
* Lunar\Stripe\Facades\Stripe::createIntent()/fetchOrCreateIntent(), which
|
||||
* take a Lunar\Models\Cart and derive amount/currency from it. Payment
|
||||
* must never receive a Cart (see docs/payments.md) — pay()/authorize()
|
||||
* already receive $amount explicitly as their own required Lunar Price
|
||||
* parameter (see PaymentResult's own docblock), the caller's job to
|
||||
* assemble, same as every other driver.
|
||||
* Lunar's own checkout flow (lunarphp/stripe, since removed — see
|
||||
* Modules\Core\Payment\Support\StripeManager's own docblock), which took a
|
||||
* Lunar\Models\Cart and derived amount/currency from it. Payment must
|
||||
* never receive a Cart (see docs/payments.md) — pay()/authorize() already
|
||||
* receive $amount explicitly as their own required Lunar Price parameter
|
||||
* (see PaymentResult's own docblock), the caller's job to assemble, same
|
||||
* as every other driver.
|
||||
*
|
||||
* Every amount that crosses this class's own boundary is converted right
|
||||
* there: Lunar's Price -> Stripe's minor-unit int going INTO a gateway
|
||||
@@ -45,12 +45,11 @@ use Stripe\PaymentIntent;
|
||||
* Nothing outside this class ever sees a Stripe-scaled integer.
|
||||
*
|
||||
* Correlating a later handleCallback() (a separate request — a webhook)
|
||||
* back to whatever $context identified this attempt is solved the same
|
||||
* way lunarphp/stripe's own StripePaymentType/ProcessStripeWebhook solve
|
||||
* it: real cart_id/order_id columns on Lunar\Stripe\Models\
|
||||
* StripePaymentIntent (a table already owned by lunarphp/stripe, already
|
||||
* shaped for exactly this), not a generic context blob. See
|
||||
* docs/payments.md "Async resolution" for the full reasoning.
|
||||
* back to whatever $context identified this attempt is solved via real
|
||||
* cart_id/order_id columns on Modules\Core\Payment\Models\
|
||||
* StripePaymentIntent (a table this app now owns outright, already shaped
|
||||
* for exactly this), not a generic context blob. See docs/payments.md
|
||||
* "Async resolution" for the full reasoning.
|
||||
*/
|
||||
class StripePaymentDriver implements
|
||||
Configurable,
|
||||
@@ -61,10 +60,13 @@ class StripePaymentDriver implements
|
||||
SupportsRefunds,
|
||||
HandlesPaymentCallback
|
||||
{
|
||||
public function __construct(
|
||||
private readonly StripeManager $stripe,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Same key lunarphp/stripe's own StripeManager reads its API key from
|
||||
* (Stripe::setApiKey(config('services.stripe.key'))) — no key, no
|
||||
* usable driver.
|
||||
* Same key StripeManager reads its API key from — no key, no usable
|
||||
* driver.
|
||||
*/
|
||||
public function isConfigured(): bool
|
||||
{
|
||||
@@ -114,7 +116,7 @@ class StripePaymentDriver implements
|
||||
}
|
||||
|
||||
try {
|
||||
$paymentIntent = Stripe::getClient()->paymentIntents->create($params);
|
||||
$paymentIntent = $this->stripe->getClient()->paymentIntents->create($params);
|
||||
} catch (ApiErrorException $e) {
|
||||
return $this->declined($type, $amount, $e, $context, authorizing: $captureMethod === 'manual');
|
||||
}
|
||||
@@ -128,7 +130,7 @@ class StripePaymentDriver implements
|
||||
{
|
||||
[$intentModel, $type, $context] = $this->resolveIntentModel($reference, $context, $data['type'] ?? '');
|
||||
|
||||
$paymentIntent = Stripe::getClient()->paymentIntents->retrieve($reference);
|
||||
$paymentIntent = $this->stripe->getClient()->paymentIntents->retrieve($reference);
|
||||
|
||||
$authorizing = $paymentIntent->capture_method === PaymentIntent::CAPTURE_METHOD_MANUAL;
|
||||
|
||||
@@ -136,7 +138,7 @@ class StripePaymentDriver implements
|
||||
// automatic capture_method, but Stripe stopped short of
|
||||
// capturing (rare, but the API contract allows it) — finish
|
||||
// the job pay() started.
|
||||
$paymentIntent = Stripe::getClient()->paymentIntents->capture($reference);
|
||||
$paymentIntent = $this->stripe->getClient()->paymentIntents->capture($reference);
|
||||
}
|
||||
|
||||
$intentModel?->update(['status' => $paymentIntent->status]);
|
||||
@@ -151,7 +153,7 @@ class StripePaymentDriver implements
|
||||
[$intentModel, $type, $context] = $this->resolveIntentModel($reference, $context);
|
||||
|
||||
try {
|
||||
$paymentIntent = Stripe::getClient()->paymentIntents->capture($reference, [
|
||||
$paymentIntent = $this->stripe->getClient()->paymentIntents->capture($reference, [
|
||||
'amount_to_capture' => StripeManager::toStripeAmount($amount->value, $amount->currency),
|
||||
]);
|
||||
} catch (ApiErrorException $e) {
|
||||
@@ -185,7 +187,7 @@ class StripePaymentDriver implements
|
||||
[$intentModel, $type, $context] = $this->resolveIntentModel($reference, $context);
|
||||
|
||||
try {
|
||||
$paymentIntent = Stripe::getClient()->paymentIntents->cancel($reference);
|
||||
$paymentIntent = $this->stripe->getClient()->paymentIntents->cancel($reference);
|
||||
} catch (ApiErrorException $e) {
|
||||
$result = $this->failure($amount, $e, $reference);
|
||||
PaymentVoidFailed::dispatch($type, $result, $context);
|
||||
@@ -216,7 +218,7 @@ class StripePaymentDriver implements
|
||||
[$intentModel, $type, $context] = $this->resolveIntentModel($reference, $context);
|
||||
|
||||
try {
|
||||
$refund = Stripe::getClient()->refunds->create([
|
||||
$refund = $this->stripe->getClient()->refunds->create([
|
||||
'payment_intent' => $reference,
|
||||
'amount' => StripeManager::toStripeAmount($amount->value, $amount->currency),
|
||||
]);
|
||||
@@ -253,7 +255,7 @@ class StripePaymentDriver implements
|
||||
'order_id' => $context['order_id'] ?? null,
|
||||
'status' => $paymentIntent->status,
|
||||
'payment_type' => $type,
|
||||
'context' => json_encode($context),
|
||||
'context' => $context,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -278,28 +280,10 @@ class StripePaymentDriver implements
|
||||
return [
|
||||
$intentModel,
|
||||
$intentModel?->payment_type ?? $typeFallback,
|
||||
$this->decodeContext($intentModel) ?? $context,
|
||||
$intentModel?->context ?? $context,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* StripePaymentIntent is a vendor model (lunarphp/stripe) with no cast
|
||||
* declared for our own 'context' column (added by boboko-core's own
|
||||
* migration, see database/migrations/..._add_context_to_stripe_
|
||||
* payment_intents.php) — we can't edit the vendor model to add one, so
|
||||
* decode manually here instead of assuming Eloquent already did it.
|
||||
*
|
||||
* @return array<string, mixed>|null
|
||||
*/
|
||||
private function decodeContext(?StripePaymentIntent $intentModel): ?array
|
||||
{
|
||||
if (! $intentModel || ! $intentModel->context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return json_decode($intentModel->context, associative: true) ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a live Stripe PaymentIntent's own amount/currency back
|
||||
* into Lunar's Price — the one place this class reads a Stripe
|
||||
@@ -383,7 +367,7 @@ class StripePaymentDriver implements
|
||||
return [];
|
||||
}
|
||||
|
||||
$charge = Stripe::getCharge(is_string($chargeId) ? $chargeId : $chargeId->id);
|
||||
$charge = $this->stripe->getCharge(is_string($chargeId) ? $chargeId : $chargeId->id);
|
||||
|
||||
$paymentType = collect($charge->payment_method_details)->keys()->first();
|
||||
$details = collect($charge->payment_method_details)->first();
|
||||
|
||||
Reference in New Issue
Block a user