diff --git a/config.xml b/config.xml index ec66308ea..53e4406a8 100644 --- a/config.xml +++ b/config.xml @@ -2,7 +2,7 @@ ps_checkout - + diff --git a/controllers/front/validate.php b/controllers/front/validate.php index be9c2ab95..1ef8999c7 100644 --- a/controllers/front/validate.php +++ b/controllers/front/validate.php @@ -402,6 +402,10 @@ private function handleException(Exception $exception) $exceptionMessageForCustomer = $this->module->l('Transaction expired, please try again.'); $notifyCustomerService = false; break; + case PayPalException::PAYMENT_SOURCE_CANNOT_BE_USED: + $exceptionMessageForCustomer = $this->module->l('The selected payment method does not support this type of transaction. Please choose another payment method or contact support for assistance.'); + $notifyCustomerService = false; + break; } } diff --git a/ps_checkout.php b/ps_checkout.php index 74e721f4e..8a0c38c98 100755 --- a/ps_checkout.php +++ b/ps_checkout.php @@ -123,7 +123,7 @@ class Ps_checkout extends PaymentModule // Needed in order to retrieve the module version easier (in api call headers) than instanciate // the module each time to get the version - const VERSION = '8.3.5.2'; + const VERSION = '8.3.5.3'; const INTEGRATION_DATE = '2022-14-06'; @@ -144,7 +144,7 @@ public function __construct() // We cannot use the const VERSION because the const is not computed by addons marketplace // when the zip is uploaded - $this->version = '8.3.5.2'; + $this->version = '8.3.5.3'; $this->author = 'PrestaShop'; $this->currencies = true; $this->currencies_mode = 'checkbox'; diff --git a/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php b/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php index 80319694e..504c85d2b 100644 --- a/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php +++ b/src/Builder/PayPalSdkLink/PayPalSdkLinkBuilder.php @@ -51,6 +51,9 @@ class PayPalSdkLinkBuilder /** @var ExpressCheckoutConfiguration */ private $expressCheckoutConfiguration; + /** @var array */ + private static $cache = []; + /** * @param PayPalConfiguration $configuration * @param PayPalPayLaterConfiguration $payLaterConfiguration @@ -347,6 +350,57 @@ private function getLocale() return ''; } + // TODO : Remove everything Sofort related after October 2024 when its no longer supported by PayPal + private function isSofortAvailableForMerchant() + { + if (isset(self::$cache['sofortAvailability'])) { + return self::$cache['sofortAvailability']; + } + + $query = new \DbQuery(); + $query->select('date_add'); + $query->from('configuration'); + $query->where('name = "PS_CHECKOUT_PAYPAL_ID_MERCHANT"'); + + $shopId = \Shop::getContextShopID(true); + if ($shopId) { + $query->where('id_shop IS NULL OR id_shop = ' . (int) $shopId); + } + + $dateAdd = \Db::getInstance()->getValue($query); + + if (empty($dateAdd) || strpos($dateAdd, '0000-00-00') !== false) { + // Sofort is unavailable for merchants who have not onboarded yet. + self::$cache['sofortAvailability'] = false; + + return false; + } + + $dtZone = new \DateTimeZone('UTC'); + $now = new \DateTime('now', $dtZone); + $createdAt = new \DateTime($dateAdd, $dtZone); + $deprecationDate = new \DateTime('2024-02-01', $dtZone); + $unavailabilityDate = new \DateTime('2024-09-30', $dtZone); + + if ($now > $unavailabilityDate) { + // Sofort is totally unavailable after September 30, 2024. + self::$cache['sofortAvailability'] = false; + + return false; + } + + if ($now > $deprecationDate && $createdAt >= $deprecationDate) { + // Sofort is unavailable for merchants onboarded after February 01, 2024. + self::$cache['sofortAvailability'] = false; + + return false; + } + + self::$cache['sofortAvailability'] = true; + + return true; + } + private function getEligibleAlternativePaymentMethods() { $fundingSourcesEnabled = []; @@ -414,6 +468,7 @@ private function getEligibleAlternativePaymentMethods() && $fundingSource['name'] === 'sofort' && (($context->currency->iso_code === 'EUR' && in_array($country, ['AT', 'BE', 'DE', 'ES', 'NL'], true)) || ($context->currency->iso_code === 'GBP' && in_array($country, ['GB', 'UK'], true))) + && $this->isSofortAvailableForMerchant() ) { $fundingSourcesEnabled[] = $fundingSource['name']; } diff --git a/src/Exception/PayPalException.php b/src/Exception/PayPalException.php index c95725238..015b0a728 100644 --- a/src/Exception/PayPalException.php +++ b/src/Exception/PayPalException.php @@ -153,4 +153,5 @@ class PayPalException extends PsCheckoutException const PAYMENT_DENIED = 128; const CARD_BRAND_NOT_SUPPORTED = 129; const RESOURCE_NOT_FOUND = 130; + const PAYMENT_SOURCE_CANNOT_BE_USED = 131; } diff --git a/src/PayPalError.php b/src/PayPalError.php index 8a6d2eea5..7d30d09c1 100644 --- a/src/PayPalError.php +++ b/src/PayPalError.php @@ -303,6 +303,8 @@ public function throwException() throw new PayPalException('Processing of this card brand is not supported. Use another type of card.', PayPalException::CARD_BRAND_NOT_SUPPORTED); case 'RESOURCE_NOT_FOUND': throw new PayPalException('The specified resource does not exist.', PayPalException::RESOURCE_NOT_FOUND); + case 'PAYMENT_SOURCE_CANNOT_BE_USED': + throw new PayPalException('The provided payment source cannot be used to pay for the order. Please try again with a different payment source by creating a new order.', PayPalException::PAYMENT_SOURCE_CANNOT_BE_USED); default: throw new PayPalException($this->message, PayPalException::UNKNOWN); }