From 62bb8ea54bd5e473df743a2fc0951378d6197cba Mon Sep 17 00:00:00 2001 From: Rohan singh Date: Mon, 22 Dec 2025 16:32:28 +0530 Subject: [PATCH] Fix place order API flow and payment validation. - Refactored order creation flow to validate payment before creating the order. - Added event to allow custom packages to handle the order flow. - Updated invoice creation process. - Removed payment validation from the invoice creation method. - Updated all locals. --- src/Helper/PaymentHelper.php | 64 ++++++++++++------- .../Shop/Customer/CheckoutMutation.php | 44 +++++++++++-- src/Resources/lang/ar/app.php | 2 + src/Resources/lang/bn/app.php | 2 + src/Resources/lang/ca/app.php | 2 + src/Resources/lang/de/app.php | 2 + src/Resources/lang/en/app.php | 2 + src/Resources/lang/es/app.php | 2 + src/Resources/lang/fa/app.php | 2 + src/Resources/lang/fr/app.php | 2 + src/Resources/lang/he/app.php | 2 + src/Resources/lang/hi_IN/app.php | 2 + src/Resources/lang/id/app.php | 2 + src/Resources/lang/it/app.php | 2 + src/Resources/lang/ja/app.php | 2 + src/Resources/lang/nl/app.php | 2 + src/Resources/lang/pl/app.php | 2 + src/Resources/lang/pt_BR/app.php | 2 + src/Resources/lang/ru/app.php | 2 + src/Resources/lang/sin/app.php | 2 + src/Resources/lang/tr/app.php | 2 + src/Resources/lang/uk/app.php | 2 + src/Resources/lang/zh_CN/app.php | 2 + src/graphql/shop/checkout/place_order.graphql | 7 +- 24 files changed, 124 insertions(+), 33 deletions(-) diff --git a/src/Helper/PaymentHelper.php b/src/Helper/PaymentHelper.php index b4a9bd25..4658d124 100644 --- a/src/Helper/PaymentHelper.php +++ b/src/Helper/PaymentHelper.php @@ -3,6 +3,7 @@ namespace Webkul\GraphQLAPI\Helper; use Illuminate\Support\Facades\DB; +use Illuminate\Support\Facades\Event; use Webkul\Paypal\Payment\SmartButton; use Webkul\Sales\Repositories\InvoiceRepository; use Webkul\Sales\Repositories\OrderRepository; @@ -22,28 +23,8 @@ public function __construct( public function createInvoice($cart, $paymentDetail, $order) { - if ( - ! empty($paymentDetail['error']) - || $paymentDetail['message'] != 'Success' - || $cart->payment->method != $paymentDetail['payment_method'] - ) { - return; - } - - $paymentMethod = $cart->payment->method; - $paymentIsCompleted = false; - - match ($paymentMethod) { - 'paypal_standard' => $paymentIsCompleted = $this->isNewTransaction($paymentDetail['txn_id']) && $this->checkPaypalPaymentStatus($paymentDetail['txn_id']), - 'paypal_smart_button' => $paymentIsCompleted = $this->isNewTransaction($paymentDetail['order_id']) && $this->checkSmartButtonPaymentStatus($paymentDetail['order_id']), - default => null, - }; - - if ( - $paymentIsCompleted - && $order->canInvoice() - ) { - if ($paymentMethod == 'paypal_smart_button') { + if ( $order->canInvoice() ) { + if ( $cart?->payment?->method && $cart->payment->method == 'paypal_smart_button') { request()->merge(['orderData' => [ 'orderID' => $paymentDetail['order_id'], ]]); @@ -116,4 +97,43 @@ public function checkSmartButtonPaymentStatus(string $orderId): bool return $transactionDetails['statusCode'] ?? 0 === 200; } + + /** + * Verify payment. + */ + public function isPaymentSuccessful(array $args, $cart): bool + { + $isPaymentComplete = match ($args['payment_method']) { + 'paypal_standard' => + ! empty($args['txn_id']) + && $this->isNewTransaction($args['txn_id']) + && $this->checkPaypalPaymentStatus($args['txn_id']), + + 'paypal_smart_button' => + ! empty($args['order_id']) + && $this->isNewTransaction($args['order_id']) + && $this->checkSmartButtonPaymentStatus($args['order_id']), + + 'cashondelivery' => true, + + 'moneytransfer' => true, + + default => null, + }; + + if ($isPaymentComplete !== null) { + return $isPaymentComplete; + } + + $eventData = [ + 'payment_method' => $args['payment_method'], + 'args' => $args, + 'cart' => $cart, + 'status' => false, // 👈 listener will update this + ]; + + Event::dispatch('checkout.order.payment.verify', $eventData); + + return (bool) $eventData['status']; + } } diff --git a/src/Mutations/Shop/Customer/CheckoutMutation.php b/src/Mutations/Shop/Customer/CheckoutMutation.php index ba58d6d7..820c0e2a 100755 --- a/src/Mutations/Shop/Customer/CheckoutMutation.php +++ b/src/Mutations/Shop/Customer/CheckoutMutation.php @@ -4,6 +4,7 @@ use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\Event; use Nuwave\Lighthouse\Support\Contracts\GraphQLContext; use Webkul\CartRule\Repositories\CartRuleCouponRepository; use Webkul\Checkout\Facades\Cart; @@ -472,29 +473,60 @@ public function saveOrder(mixed $rootValue, array $args, GraphQLContext $context $cart = Cart::getCart(); + if ( + isset($args['payment_method']) && + $cart->payment->method !== $args['payment_method'] + ) { + throw new CustomException(trans('bagisto_graphql::app.shop.checkout.payment.method-mismatch')); + } + + $isPaymentSuccess = $this->paymentHelper->isPaymentSuccessful($args, $cart); + + if (! $isPaymentSuccess) { + throw new CustomException(trans('bagisto_graphql::app.shop.checkout.payment.payment-failed')); + } + $orderData = (new OrderResource($cart))->jsonSerialize(); + $order = $this->orderRepository->create($orderData); if (core()->getConfigData('general.api.pushnotification.private_key')) { $this->prepareNotificationContent($order); } - if (! empty($args['is_payment_completed'])) { - $this->paymentHelper->createInvoice($cart, $args, $order); - } + $this->createInvoice($cart, $args, $order); Cart::deActivateCart(); return [ - 'success' => true, - 'redirect_url' => null, - 'order' => $order, + 'success' => true, + 'redirect_url' => null, + 'selected_method' => $cart->payment->method ?? null, + 'order' => $order, ]; } catch (\Exception $e) { throw new CustomException($e->getMessage()); } } + /** + * Create order invoice + */ + protected function createInvoice($cart, $args, $order):void + { + $eventData = new \stdClass(); + $eventData->restricted_payment_methods = [ + 'paypal_standard', + 'paypal_smart_button', + ]; + + Event::dispatch('checkout.order.payment.restricted_payment_methods', $eventData); + + if (in_array($args['payment_method'], $eventData->restricted_payment_methods)) { + $this->paymentHelper->createInvoice($cart, $args, $order); + } + } + /** * Validate order before creation * diff --git a/src/Resources/lang/ar/app.php b/src/Resources/lang/ar/app.php index fb5126aa..a3780128 100755 --- a/src/Resources/lang/ar/app.php +++ b/src/Resources/lang/ar/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'تم جلب طريقة الدفع بنجاح.', 'save-failed' => 'تحذير: لم يتم حفظ طريقة الدفع.', 'save-success' => 'تم حفظ طريقة الدفع بنجاح.', + 'method-mismatch' => 'عدم تطابق طريقة الدفع.', + 'payment-failed' => 'فشلت عملية الدفع. لم يتم إنشاء الطلب', ], 'coupon' => [ diff --git a/src/Resources/lang/bn/app.php b/src/Resources/lang/bn/app.php index 593b82ce..09f97ee1 100755 --- a/src/Resources/lang/bn/app.php +++ b/src/Resources/lang/bn/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'সাফল্যের সাথে পেমেন্ট পদ্ধতি পেয়েছেন।', 'save-failed' => 'সতর্কবার্তা: পেমেন্ট পদ্ধতি সংরক্ষণ করা হয়নি।', 'save-success' => 'সাফল্যের সাথে পেমেন্ট পদ্ধতি সংরক্ষণ করা হয়েছে।', + 'method-mismatch' => 'পেমেন্ট পদ্ধতির অমিল।', + 'payment-failed' => 'পেমেন্ট ব্যর্থ হয়েছে। অর্ডার তৈরি করা হয়নি', ], 'coupon' => [ diff --git a/src/Resources/lang/ca/app.php b/src/Resources/lang/ca/app.php index d0ba7169..b232c9be 100644 --- a/src/Resources/lang/ca/app.php +++ b/src/Resources/lang/ca/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Èxit: Mètode de pagament obtingut amb èxit.', 'save-failed' => 'Advertència: El mètode de pagament no s\'ha desat.', 'save-success' => 'Èxit: Mètode de pagament desat amb èxit.', + 'method-mismatch' => 'Zahlungsmethode stimmt nicht überein.', + 'payment-failed' => 'Zahlung fehlgeschlagen. Bestellung wurde nicht erstellt', ], 'coupon' => [ diff --git a/src/Resources/lang/de/app.php b/src/Resources/lang/de/app.php index 26dfa689..7053dc9e 100755 --- a/src/Resources/lang/de/app.php +++ b/src/Resources/lang/de/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Erfolg: Zahlungsmethode erfolgreich abgerufen.', 'save-failed' => 'Warnung: Zahlungsmethode nicht gespeichert.', 'save-success' => 'Erfolg: Zahlungsmethode erfolgreich gespeichert.', + 'method-mismatch' => 'Zahlungsmethode stimmt nicht überein.', + 'payment-failed' => 'Zahlung fehlgeschlagen. Bestellung wurde nicht erstellt', ], 'coupon' => [ diff --git a/src/Resources/lang/en/app.php b/src/Resources/lang/en/app.php index dcfee302..788788d3 100755 --- a/src/Resources/lang/en/app.php +++ b/src/Resources/lang/en/app.php @@ -181,6 +181,8 @@ 'method-fetched' => 'Success: Payment method fetched successfully.', 'save-failed' => 'Warning: Payment method not saved.', 'save-success' => 'Success: Payment method saved successfully.', + 'method-mismatch' => 'Payment method mismatch.', + 'payment-failed' => 'Payment failed. Order not created', ], 'coupon' => [ diff --git a/src/Resources/lang/es/app.php b/src/Resources/lang/es/app.php index 13b0d253..074d1226 100755 --- a/src/Resources/lang/es/app.php +++ b/src/Resources/lang/es/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Éxito: Método de pago obtenido correctamente.', 'save-failed' => 'Advertencia: No se pudo guardar el método de pago.', 'save-success' => 'Éxito: Método de pago guardado correctamente.', + 'method-mismatch' => 'Incompatibilidad en el método de pago.', + 'payment-failed' => 'El pago falló. El pedido no fue creado', ], 'coupon' => [ diff --git a/src/Resources/lang/fa/app.php b/src/Resources/lang/fa/app.php index 433a36ca..687f1979 100755 --- a/src/Resources/lang/fa/app.php +++ b/src/Resources/lang/fa/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'موفقیت: روش پرداخت با موفقیت دریافت شد.', 'save-failed' => 'هشدار: روش پرداخت ذخیره نشد.', 'save-success' => 'موفقیت: روش پرداخت با موفقیت ذخیره شد.', + 'method-mismatch' => 'عدم تطابق روش پرداخت.', + 'payment-failed' => 'پرداخت ناموفق بود. سفارش ایجاد نشد', ], 'coupon' => [ diff --git a/src/Resources/lang/fr/app.php b/src/Resources/lang/fr/app.php index dd980e5f..b4e6e013 100755 --- a/src/Resources/lang/fr/app.php +++ b/src/Resources/lang/fr/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Succès: Méthode de paiement récupérée avec succès.', 'save-failed' => 'Avertissement: Méthode de paiement non enregistrée.', 'save-success' => 'Succès: Méthode de paiement enregistrée avec succès.', + 'method-mismatch' => 'Incompatibilité du mode de paiement.', + 'payment-failed' => 'Le paiement a échoué. La commande n’a pas été créée', ], 'coupon' => [ diff --git a/src/Resources/lang/he/app.php b/src/Resources/lang/he/app.php index 8322ffb9..3a006464 100755 --- a/src/Resources/lang/he/app.php +++ b/src/Resources/lang/he/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'הצלחה: שיטת התשלום נטענה בהצלחה.', 'save-failed' => 'אזהרה: שיטת התשלום לא נשמרה.', 'save-success' => 'הצלחה: שיטת התשלום נשמרה בהצלחה.', + 'method-mismatch' => 'אי התאמה בשיטת התשלום.', + 'payment-failed' => 'התשלום נכשל. ההזמנה לא נוצרה', ], 'coupon' => [ diff --git a/src/Resources/lang/hi_IN/app.php b/src/Resources/lang/hi_IN/app.php index 55343eef..18f86ac3 100755 --- a/src/Resources/lang/hi_IN/app.php +++ b/src/Resources/lang/hi_IN/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'सफलतापूर्वक भुगतान विधि प्राप्त की गई।', 'save-failed' => 'चेतावनी: भुगतान विधि सहेजी नहीं गई।', 'save-success' => 'सफलतापूर्वक भुगतान विधि सहेजी गई।', + 'method-mismatch' => 'भुगतान विधि मेल नहीं खा रही है।', + 'payment-failed' => 'भुगतान असफल हुआ। ऑर्डर नहीं बनाया गया', ], 'coupon' => [ diff --git a/src/Resources/lang/id/app.php b/src/Resources/lang/id/app.php index 893a7131..2c6198cd 100644 --- a/src/Resources/lang/id/app.php +++ b/src/Resources/lang/id/app.php @@ -181,6 +181,8 @@ 'method-fetched' => 'Sukses: Metode pembayaran berhasil diambil.', 'save-failed' => 'Peringatan: Metode pembayaran tidak berhasil disimpan.', 'save-success' => 'Sukses: Metode pembayaran berhasil disimpan.', + 'method-mismatch' => 'Metode pembayaran tidak sesuai.', + 'payment-failed' => 'Pembayaran gagal. Pesanan tidak dibuat', ], 'coupon' => [ diff --git a/src/Resources/lang/it/app.php b/src/Resources/lang/it/app.php index d307f318..3ab0553f 100755 --- a/src/Resources/lang/it/app.php +++ b/src/Resources/lang/it/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Successo: Metodo di pagamento recuperato con successo.', 'save-failed' => 'Attenzione: Metodo di pagamento non salvato.', 'save-success' => 'Successo: Metodo di pagamento salvato con successo.', + 'method-mismatch' => 'Metodo di pagamento non corrispondente.', + 'payment-failed' => 'Pagamento non riuscito. Ordine non creato', ], 'coupon' => [ diff --git a/src/Resources/lang/ja/app.php b/src/Resources/lang/ja/app.php index c2a8b314..542dab58 100755 --- a/src/Resources/lang/ja/app.php +++ b/src/Resources/lang/ja/app.php @@ -180,6 +180,8 @@ 'method-fetched' => '成功: 支払い方法が正常に取得されました。', 'save-failed' => '注意: 支払い方法が保存されませんでした。', 'save-success' => '成功: 支払い方法が正常に保存されました。', + 'method-mismatch' => '支払い方法が一致しません。', + 'payment-failed' => '支払いに失敗しました。注文は作成されませんでした', ], 'coupon' => [ diff --git a/src/Resources/lang/nl/app.php b/src/Resources/lang/nl/app.php index ce9ed6e7..db32e81c 100755 --- a/src/Resources/lang/nl/app.php +++ b/src/Resources/lang/nl/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Succes: Betalingsmethode succesvol opgehaald.', 'save-failed' => 'Let op: Betalingsmethode niet opgeslagen.', 'save-success' => 'Succes: Betalingsmethode succesvol opgeslagen.', + 'method-mismatch' => 'Betalingsmethode komt niet overeen.', + 'payment-failed' => 'Betaling mislukt. Bestelling is niet aangemaakt', ], 'coupon' => [ diff --git a/src/Resources/lang/pl/app.php b/src/Resources/lang/pl/app.php index 673bc451..283a80d4 100755 --- a/src/Resources/lang/pl/app.php +++ b/src/Resources/lang/pl/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Sukces: Metoda płatności została pomyślnie pobrana.', 'save-failed' => 'Ostrzeżenie: Metoda płatności nie została zapisana.', 'save-success' => 'Sukces: Metoda płatności została pomyślnie zapisana.', + 'method-mismatch' => 'Niezgodność metody płatności.', + 'payment-failed' => 'Płatność nie powiodła się. Zamówienie nie zostało utworzone', ], 'coupon' => [ diff --git a/src/Resources/lang/pt_BR/app.php b/src/Resources/lang/pt_BR/app.php index 83178343..60b912da 100755 --- a/src/Resources/lang/pt_BR/app.php +++ b/src/Resources/lang/pt_BR/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Sucesso: Método de pagamento obtido com sucesso.', 'save-failed' => 'Aviso: Método de pagamento não salvo.', 'save-success' => 'Sucesso: Método de pagamento salvo com sucesso.', + 'method-mismatch' => 'Incompatibilidade no método de pagamento.', + 'payment-failed' => 'Pagamento falhou. Pedido não foi criado', ], 'coupon' => [ diff --git a/src/Resources/lang/ru/app.php b/src/Resources/lang/ru/app.php index 89d4ce44..10b12930 100755 --- a/src/Resources/lang/ru/app.php +++ b/src/Resources/lang/ru/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Успешно: Способ оплаты успешно получен.', 'save-failed' => 'Предупреждение: Способ оплаты не сохранен.', 'save-success' => 'Успешно: Способ оплаты успешно сохранен.', + 'method-mismatch' => 'Несоответствие способа оплаты.', + 'payment-failed' => 'Платеж не выполнен. Заказ не создан', ], 'coupon' => [ diff --git a/src/Resources/lang/sin/app.php b/src/Resources/lang/sin/app.php index d69561a3..574f1ede 100755 --- a/src/Resources/lang/sin/app.php +++ b/src/Resources/lang/sin/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'සාර්ථකත්වය: ගෙවීමේ ක්‍රමයක් සාර්ථකව ලබා ගත්තා.', 'save-failed' => 'අවවාදය: ගෙවීමේ ක්‍රමයක් සුරක්ෂිත නොකෙරුණා.', 'save-success' => 'සාර්ථකත්වය: ගෙවීමේ ක්‍රමයක් සාර්ථකව සුරක්ෂිත කෙරුණා.', + 'method-mismatch' => 'ගෙවීම් ක්‍රමය නොගැළපේ.', + 'payment-failed' => 'ගෙවීම අසාර්ථක විය. ඇණවුම සෑදූ නොවේ', ], 'coupon' => [ diff --git a/src/Resources/lang/tr/app.php b/src/Resources/lang/tr/app.php index 072ee1b7..cba563d8 100755 --- a/src/Resources/lang/tr/app.php +++ b/src/Resources/lang/tr/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Başarılı: Ödeme yöntemi başarıyla alındı.', 'save-failed' => 'Uyarı: Ödeme yöntemi kaydedilemedi.', 'save-success' => 'Başarılı: Ödeme yöntemi başarıyla kaydedildi.', + 'method-mismatch' => 'Ödeme yöntemi uyuşmuyor.', + 'payment-failed' => 'Ödeme başarısız oldu. Sipariş oluşturulmadı', ], 'coupon' => [ diff --git a/src/Resources/lang/uk/app.php b/src/Resources/lang/uk/app.php index a7dff57f..88038321 100755 --- a/src/Resources/lang/uk/app.php +++ b/src/Resources/lang/uk/app.php @@ -180,6 +180,8 @@ 'method-fetched' => 'Успішно: Спосіб оплати успішно отримано.', 'save-failed' => 'Попередження: Спосіб оплати не збережено.', 'save-success' => 'Успішно: Спосіб оплати успішно збережено.', + 'method-mismatch' => 'Невідповідність способу оплати.', + 'payment-failed' => 'Платіж не вдався. Замовлення не створено', ], 'coupon' => [ diff --git a/src/Resources/lang/zh_CN/app.php b/src/Resources/lang/zh_CN/app.php index cee6f220..8683861b 100755 --- a/src/Resources/lang/zh_CN/app.php +++ b/src/Resources/lang/zh_CN/app.php @@ -180,6 +180,8 @@ 'method-fetched' => '成功:成功获取付款方式。', 'save-failed' => '警告:未保存付款方式。', 'save-success' => '成功:付款方式已成功保存。', + 'method-mismatch' => '支付方式不匹配。', + 'payment-failed' => '支付失败。订单未创建', ], 'coupon' => [ diff --git a/src/graphql/shop/checkout/place_order.graphql b/src/graphql/shop/checkout/place_order.graphql index a9f2b9e6..b25d8ec1 100755 --- a/src/graphql/shop/checkout/place_order.graphql +++ b/src/graphql/shop/checkout/place_order.graphql @@ -1,12 +1,9 @@ # Shop\Checkout\PlaceOrder Related API extend type Mutation { placeOrder( - isPaymentCompleted: Boolean = false @rename(attribute: "is_payment_completed") - error: Boolean = true - message: String + paymentMethod: String! @rename(attribute: "payment_method") transactionId: String @rename(attribute: "txn_id") paymentStatus: String @rename(attribute: "payment_status") - paymentMethod: String @rename(attribute: "payment_method") paymentType: String @rename(attribute: "payment_type") orderID: String @rename(attribute: "order_id") ): PlacedOrderResponse @field(resolver: "Webkul\\GraphQLAPI\\Mutations\\Shop\\Customer\\CheckoutMutation@saveOrder") @@ -17,4 +14,4 @@ type PlacedOrderResponse { redirectUrl: String @rename(attribute: "redirect_url") selectedMethod: String @rename(attribute: "selected_method") order: Order -} \ No newline at end of file +}