Skip to content

Commit df47aa5

Browse files
committed
[0007914]: Fix Pay upon Invoice (PUI) . Added gatewaypayment flag to PayPalDefinitions and isGatewayPayment() method so PUI correctly falls through to OXID's core PaymentGateway.
1 parent d8e165f commit df47aa5

3 files changed

Lines changed: 15 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88

99
### FIX
1010

11+
- [0007914](https://bugs.oxid-esales.com/view.php?id=7914): Fix Pay upon Invoice (PUI) broken after 3.7.1 security patch. The `executePayment()` reject guard blocked PUI because it matched `isPayPalPayment()` but was not handled by any prior flow (not a button/proxy/UAPM/checkout payment). Added `gatewaypayment` flag to `PayPalDefinitions` and `isGatewayPayment()` method so PUI correctly falls through to OXID's core `PaymentGateway`.
1112
- [0007915](https://bugs.oxid-esales.com/view.php?id=7915): Fix fatal error "Call to a member function getId() on null" on product detail page when an out-of-stock variant is in the basket. `hasProductVariantInBasket()` delegated to `Basket::getArtStockInBasket()` which calls `getArticle(true)` (buyable-check). For out-of-stock variants this returns null. Replaced with direct basket iteration using `getArticle(false)` to skip the buyable check.
1213
- [0007916](https://bugs.oxid-esales.com/view.php?id=7916): Fix orphaned oscpaypal_order rows with OSCPAYPALSTATUS=COMPLETED and empty OXORDERID. When `sess_challenge` was cleared before `captureOrder()` completed (e.g. by a concurrent cancel request), the capture flow proceeded and created tracking records that could not be matched by webhook processing. Added defense-in-depth validation at four levels: `AjaxPaymentController::captureOrder()` now aborts if the shop order cannot be resolved, `PayPalOrderCompletedSubscriber` rejects events with empty shopOrderId, `Payment::trackPayPalOrder()` throws on empty shopOrderId, and `OrderRepository::paypalOrderByOrderIdAndPayPalId()` refuses to create new records with empty shopOrderId.
1314

src/Core/PayPalDefinitions.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,7 @@ final class PayPalDefinitions
198198
'onlybrutto' => false,
199199
'buttonpayment' => false,
200200
'proxycontroller' => false,
201+
'gatewaypayment' => true,
201202
'defaulton' => true,
202203
'paymentsource' => self::PAYMENT_SOURCE_PUI
203204
],
@@ -526,6 +527,13 @@ public static function isUAPMPayment(string $oxid): bool
526527
return (isset(self::PAYPAL_DEFINTIONS[$oxid]['isuapm']));
527528
}
528529

530+
public static function isGatewayPayment(string $oxid): bool
531+
{
532+
return (isset(self::PAYPAL_DEFINTIONS[$oxid])) ?
533+
!empty(self::PAYPAL_DEFINTIONS[$oxid]['gatewaypayment']) :
534+
false;
535+
}
536+
529537
public static function isButtonPayment(string $oxid): bool
530538
{
531539
return (isset(self::PAYPAL_DEFINTIONS[$oxid])) ?

src/Model/Order.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,12 @@ protected function executePayment(Basket $basket, $userpayment)
476476
return true;
477477
}
478478

479+
// Gateway payments (e.g. PUI) are processed by OXID's core PaymentGateway,
480+
// so they must fall through to parent::executePayment().
481+
if (PayPalDefinitions::isGatewayPayment($sessionPaymentId)) {
482+
return parent::executePayment($basket, $userpayment);
483+
}
484+
479485
// Reject any PayPal payment that was not handled by the flows above
480486
if (PayPalDefinitions::isPayPalPayment($sessionPaymentId)) {
481487
return self::ORDER_STATE_PAYMENTERROR;

0 commit comments

Comments
 (0)