diff --git a/src/Processor/Checkout/CheckoutSessionTransitionProcessor.php b/src/Processor/Checkout/CheckoutSessionTransitionProcessor.php index 8e0da3c..febb7fb 100644 --- a/src/Processor/Checkout/CheckoutSessionTransitionProcessor.php +++ b/src/Processor/Checkout/CheckoutSessionTransitionProcessor.php @@ -23,21 +23,57 @@ public function process(PaymentRequestInterface $paymentRequest): void $details = $payment->getDetails(); $session = Session::constructFrom($details); - $transition = PaymentTransitions::TRANSITION_CANCEL; - if ($session->payment_status === Session::PAYMENT_STATUS_PAID) { - $transition = PaymentTransitions::TRANSITION_COMPLETE; - } + $transition = $this->getTransition($session); - if ($session->status === Session::STATUS_OPEN) { + if (null === $transition) { return; } if ($this->stateMachine->can($payment, PaymentTransitions::GRAPH, $transition)) { - $this->stateMachine->apply( - $payment, - PaymentTransitions::GRAPH, - $transition, - ); + $this->stateMachine->apply($payment, PaymentTransitions::GRAPH, $transition); + } + } + + private function getTransition(Session $session): ?string + { + $status = $session->status; + $paymentStatus = $session->payment_status; + + if ($this->isCompleteStatus($status, $paymentStatus)) { + return PaymentTransitions::TRANSITION_COMPLETE; + } + + if ($this->isFailStatus($status)) { + return PaymentTransitions::TRANSITION_FAIL; + } + + if ($this->isProcessStatus($status, $paymentStatus)) { + return PaymentTransitions::TRANSITION_PROCESS; + } + + return null; + } + + private function isCompleteStatus(?string $status, string $paymentStatus): bool + { + if (Session::STATUS_COMPLETE !== $status) { + return false; + } + + return Session::PAYMENT_STATUS_UNPAID !== $paymentStatus; + } + + private function isFailStatus(?string $status): bool + { + return Session::STATUS_EXPIRED === $status; + } + + private function isProcessStatus(?string $status, string $paymentStatus): bool + { + if (Session::STATUS_COMPLETE !== $status) { + return false; } + + return Session::PAYMENT_STATUS_UNPAID === $paymentStatus; } } diff --git a/src/Processor/WebElements/PaymentIntentTransitionProcessor.php b/src/Processor/WebElements/PaymentIntentTransitionProcessor.php index 3b21368..12f1437 100644 --- a/src/Processor/WebElements/PaymentIntentTransitionProcessor.php +++ b/src/Processor/WebElements/PaymentIntentTransitionProcessor.php @@ -23,22 +23,8 @@ public function process(PaymentRequestInterface $paymentRequest): void $details = $payment->getDetails(); $paymentIntent = PaymentIntent::constructFrom($details); - $transition = PaymentTransitions::TRANSITION_CANCEL; - if ($paymentIntent->status === PaymentIntent::STATUS_SUCCEEDED) { - $transition = PaymentTransitions::TRANSITION_COMPLETE; - } - if ($paymentIntent->status === PaymentIntent::STATUS_PROCESSING) { - $transition = PaymentTransitions::TRANSITION_PROCESS; - } - - if (in_array( - $paymentIntent->status, - [ - PaymentIntent::STATUS_REQUIRES_ACTION, - PaymentIntent::STATUS_REQUIRES_PAYMENT_METHOD, - ], - true, - )) { + $transition = $this->getTransition($paymentIntent); + if (null === $transition) { return; } @@ -46,4 +32,51 @@ public function process(PaymentRequestInterface $paymentRequest): void $this->stateMachine->apply($payment, PaymentTransitions::GRAPH, $transition); } } + + private function getTransition(PaymentIntent $paymentIntent): ?string + { + $status = $paymentIntent->status; + if (PaymentIntent::STATUS_SUCCEEDED === $status) { + return PaymentTransitions::TRANSITION_COMPLETE; + } + + if (PaymentIntent::STATUS_REQUIRES_CAPTURE === $status) { + return PaymentTransitions::TRANSITION_AUTHORIZE; + } + + if (PaymentIntent::STATUS_PROCESSING === $status) { + return PaymentTransitions::TRANSITION_PROCESS; + } + + if ($this->isCanceledStatus($status) || $this->isSpecialCanceledStatus($paymentIntent)) { + return PaymentTransitions::TRANSITION_CANCEL; + } + + return null; + } + + /** + * @see https://stripe.com/docs/payments/paymentintents/lifecycle + */ + private function isCanceledStatus(?string $status): bool + { + return PaymentIntent::STATUS_CANCELED === $status; + } + + /** + * @see https://stripe.com/docs/payments/paymentintents/lifecycle + */ + protected function isSpecialCanceledStatus(PaymentIntent $paymentIntent): bool + { + $status = $paymentIntent->status; + $lastPaymentError = $paymentIntent->last_payment_error; + + if (PaymentIntent::STATUS_REQUIRES_PAYMENT_METHOD === $status) { + if (null !== $lastPaymentError) { + return true; + } + } + + return false; + } }