From 10d249b8564d525a1efb169d1b6df60d04400117 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Tue, 4 Jul 2023 16:37:06 +0200 Subject: [PATCH 1/3] Check context before initialize it --- .../AbstractOrderCommandHandler.php | 17 +++++++++++++++++ .../CreateOrderCommandHandler.php | 4 +++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/Order/CommandHandler/AbstractOrderCommandHandler.php b/src/Order/CommandHandler/AbstractOrderCommandHandler.php index 47a6fc86b..7e630ad1f 100644 --- a/src/Order/CommandHandler/AbstractOrderCommandHandler.php +++ b/src/Order/CommandHandler/AbstractOrderCommandHandler.php @@ -23,6 +23,7 @@ use Address; use Cart; use Configuration; +use Context; use Country; use Currency; use Customer; @@ -119,4 +120,20 @@ protected function getAssociatedLanguage(Cart $cart) return $this->associatedLanguage; } + + protected function shouldSetCartContext(Context $context, Cart $cart) + { + return !Validate::isLoadedObject($context->cart) + || (int) $context->cart->id !== (int) $cart->id + || !Validate::isLoadedObject($context->customer) + || (int) $context->customer->id !== (int) $cart->id_customer + || !Validate::isLoadedObject($context->shop) + || (int) $context->shop->id !== (int) $cart->id_shop + || !Validate::isLoadedObject($context->currency) + || (int) $context->currency->id !== (int) $cart->id_currency + || !Validate::isLoadedObject($context->language) + || (int) $context->language->id !== (int) $cart->id_lang + || !Validate::isLoadedObject($context->country) + || (int) $context->country->id !== (int) $this->getCartTaxCountry($cart)->id; + } } diff --git a/src/Order/CommandHandler/CreateOrderCommandHandler.php b/src/Order/CommandHandler/CreateOrderCommandHandler.php index 4cf5850f8..782315d3a 100644 --- a/src/Order/CommandHandler/CreateOrderCommandHandler.php +++ b/src/Order/CommandHandler/CreateOrderCommandHandler.php @@ -160,7 +160,9 @@ public function handle(CreateOrderCommand $command) /** @var FundingSourceTranslationProvider $fundingSourceTranslationProvider */ $fundingSourceTranslationProvider = $this->module->getService('ps_checkout.funding_source.translation'); - $this->setCartContext($this->contextStateManager, $cart); + if ($this->shouldSetCartContext($this->contextStateManager->getContext(), $cart)) { + $this->setCartContext($this->contextStateManager, $cart); + } $extraVars = []; From eab9118f21e2c464b2b0f0ca53afd903f92e92ec Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Wed, 5 Jul 2023 17:30:11 +0200 Subject: [PATCH 2/3] Refresh core static cache to avoid issue --- src/Checkout/CheckoutChecker.php | 4 +++- .../CommandHandler/CreateOrderCommandHandler.php | 12 +++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Checkout/CheckoutChecker.php b/src/Checkout/CheckoutChecker.php index ed406ee46..9ffef68a2 100644 --- a/src/Checkout/CheckoutChecker.php +++ b/src/Checkout/CheckoutChecker.php @@ -101,7 +101,9 @@ public function continueWithAuthorization($cartId, $orderPayPal) throw new PsCheckoutException(sprintf('Cart with id %s not found.', var_export($cartId, true)), PsCheckoutException::PRESTASHOP_CART_NOT_FOUND); } - if (!$cart->nbProducts()) { + $products = $cart->getProducts(true); + + if (empty($products)) { throw new PsCheckoutException(sprintf('Cart with id %s has no product. Cannot capture the order.', var_export($cart->id, true)), PsCheckoutException::CART_PRODUCT_MISSING); } diff --git a/src/Order/CommandHandler/CreateOrderCommandHandler.php b/src/Order/CommandHandler/CreateOrderCommandHandler.php index 782315d3a..ec7408102 100644 --- a/src/Order/CommandHandler/CreateOrderCommandHandler.php +++ b/src/Order/CommandHandler/CreateOrderCommandHandler.php @@ -109,7 +109,11 @@ public function handle(CreateOrderCommand $command) /** @var PsCheckoutCart $psCheckoutCart */ $psCheckoutCart = $this->psCheckoutCartRepository->findOneByPayPalOrderId($command->getOrderPayPalId()->getValue()); - $cart = new Cart($psCheckoutCart->getIdCart()); + if (Validate::isLoadedObject($this->contextStateManager->getContext()->cart) && (int) $this->contextStateManager->getContext()->cart->id === $psCheckoutCart->getIdCart()) { + $cart = $this->contextStateManager->getContext()->cart; + } else { + $cart = new Cart($psCheckoutCart->getIdCart()); + } if (!Validate::isLoadedObject($cart)) { throw new PsCheckoutException('Cart not found', PsCheckoutException::PRESTASHOP_CART_NOT_FOUND); @@ -122,6 +126,12 @@ public function handle(CreateOrderCommand $command) return; } + $products = $cart->getProducts(true); + + if (empty($products)) { + throw new PsCheckoutException(sprintf('Cart with id %s has no product. Cannot create the order.', var_export($cart->id, true)), PsCheckoutException::CART_PRODUCT_MISSING); + } + $fundingSource = $psCheckoutCart->getPaypalFundingSource(); $transactionId = $orderStateId = $paidAmount = ''; $capture = $command->getCapturePayPal(); From e1e6076d646a5145e3d1034ee4896c702377ca71 Mon Sep 17 00:00:00 2001 From: Matt75 <5262628+Matt75@users.noreply.github.com> Date: Thu, 6 Jul 2023 09:58:33 +0200 Subject: [PATCH 3/3] Bump version to v7.3.3.1 --- config.xml | 2 +- ps_checkout.php | 4 +- upgrade/upgrade-7.3.3.1.php | 282 ++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+), 3 deletions(-) create mode 100644 upgrade/upgrade-7.3.3.1.php diff --git a/config.xml b/config.xml index ebc816dd0..31a9d9e02 100644 --- a/config.xml +++ b/config.xml @@ -2,7 +2,7 @@ ps_checkout - + diff --git a/ps_checkout.php b/ps_checkout.php index 3b06bf8eb..3a121bedc 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 = '7.3.3.0'; + const VERSION = '7.3.3.1'; const INTEGRATION_DATE = '2022-14-06'; @@ -142,7 +142,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 = '7.3.3.0'; + $this->version = '7.3.3.1'; $this->author = 'PrestaShop'; $this->currencies = true; $this->currencies_mode = 'checkbox'; diff --git a/upgrade/upgrade-7.3.3.1.php b/upgrade/upgrade-7.3.3.1.php new file mode 100644 index 000000000..55217f6f4 --- /dev/null +++ b/upgrade/upgrade-7.3.3.1.php @@ -0,0 +1,282 @@ + + * @copyright Since 2007 PrestaShop SA and Contributors + * @license https://opensource.org/licenses/AFL-3.0 Academic Free License version 3.0 + */ +if (!defined('_PS_VERSION_')) { + exit; +} + +/** + * Update main function for module version 7.3.3.1 + * + * @param Ps_checkout $module + * + * @return bool + */ +function upgrade_module_7_3_3_1($module) +{ + // Force PrestaShop to upgrade for all shop to avoid issues + $savedShopContext = Shop::getContext(); + $savedShopId = Shop::getContextShopID(); + $savedGroupShopId = Shop::getContextShopGroupID(); + Shop::setContext(Shop::CONTEXT_ALL); + + $module->registerHook('displayPaymentReturn'); + $module->registerHook('displayOrderDetail'); + $module->registerHook('displayHeader'); + + try { + $db = Db::getInstance(); + + // Installing FundingSource if table pscheckout_funding_source is empty or incomplete + $fundingSources = ['paypal', 'paylater', 'card', 'bancontact', 'eps', 'giropay', 'ideal', 'mybank', 'p24', 'sofort']; + $availableFundingSourcesByShops = []; + $maxPositionByShops = []; + $availableFundingSources = $db->executeS('SELECT * FROM ' . _DB_PREFIX_ . 'pscheckout_funding_source'); + + if (!empty($availableFundingSources)) { + foreach ($availableFundingSources as $availableFundingSource) { + $currentPosition = (int) $availableFundingSource['position']; + $shopId = (int) $availableFundingSource['id_shop']; + if ( + !isset($maxPositionByShops[$shopId]) + || $maxPositionByShops[$shopId] < $currentPosition + ) { + $maxPositionByShops[$shopId] = $currentPosition; + } + $availableFundingSourcesByShops[$shopId][] = $availableFundingSource['name']; + } + } + + foreach (Shop::getShops(false, null, true) as $shopId) { + $currentPosition = isset($maxPositionByShops[(int) $shopId]) ? $maxPositionByShops[(int) $shopId] + 1 : 1; + foreach ($fundingSources as $fundingSource) { + if (!in_array($fundingSource, $availableFundingSourcesByShops[(int) $shopId], true)) { + $db->insert( + 'pscheckout_funding_source', + [ + 'name' => pSQL($fundingSource), + 'active' => 1, + 'position' => (int) $currentPosition, + 'id_shop' => (int) $savedShopId, + ] + ); + ++$currentPosition; + } + } + } + + // Check module OrderState + $moduleOrderStates = [ + 'PS_CHECKOUT_STATE_WAITING_PAYPAL_PAYMENT' => (int) Configuration::getGlobalValue('PS_CHECKOUT_STATE_WAITING_PAYPAL_PAYMENT'), + 'PS_CHECKOUT_STATE_WAITING_CREDIT_CARD_PAYMENT' => (int) Configuration::getGlobalValue('PS_CHECKOUT_STATE_WAITING_CREDIT_CARD_PAYMENT'), + 'PS_CHECKOUT_STATE_WAITING_LOCAL_PAYMENT' => (int) Configuration::getGlobalValue('PS_CHECKOUT_STATE_WAITING_LOCAL_PAYMENT'), + 'PS_CHECKOUT_STATE_AUTHORIZED' => (int) Configuration::getGlobalValue('PS_CHECKOUT_STATE_AUTHORIZED'), + 'PS_CHECKOUT_STATE_PARTIAL_REFUND' => (int) Configuration::getGlobalValue('PS_CHECKOUT_STATE_PARTIAL_REFUND'), + 'PS_CHECKOUT_STATE_WAITING_CAPTURE' => (int) Configuration::getGlobalValue('PS_CHECKOUT_STATE_WAITING_CAPTURE'), + ]; + $moduleOrderStatesId = array_values($moduleOrderStates); + + $orderStateCollection = new PrestaShopCollection(OrderState::class); + $orderStateCollection->where('module_name', '=', $module->name); + $orderStateCollection->where('deleted', '=', '0'); + + /** @var OrderState[] $orderStates */ + $orderStates = $orderStateCollection->getResults(); + $currentModuleOrderStatesId = []; + + if (!empty($orderStates)) { + foreach ($orderStates as $orderState) { + $orderStateId = (int) $orderState->id; + if (!in_array($orderStateId, $moduleOrderStatesId, true)) { + $orderState->deleted = true; + $orderState->save(); + } else { + $currentModuleOrderStatesId[] = $orderStateId; + } + } + } + + foreach ($moduleOrderStates as $configuration_key => $id_order_state) { + if ( + !$id_order_state + || !in_array((int) $id_order_state, $currentModuleOrderStatesId, true) + ) { + switch ($configuration_key) { + case 'PS_CHECKOUT_STATE_WAITING_PAYPAL_PAYMENT': + ps_checkout_create_order_state_7_3_3_1( + 'PS_CHECKOUT_STATE_WAITING_PAYPAL_PAYMENT', + '#34209E', + [ + 'en' => 'Waiting for PayPal payment', + 'fr' => 'En attente de paiement par PayPal', + 'es' => 'Esperando el pago con PayPal', + 'it' => 'In attesa di pagamento con PayPal', + 'nl' => 'Wachten op PayPal-betaling', + 'de' => 'Warten auf PayPal-Zahlung', + 'pl' => 'Oczekiwanie na płatność PayPal', + 'pt' => 'Aguardando pagamento pelo PayPal', + ] + ); + break; + case 'PS_CHECKOUT_STATE_WAITING_CREDIT_CARD_PAYMENT': + ps_checkout_create_order_state_7_3_3_1( + 'PS_CHECKOUT_STATE_WAITING_CREDIT_CARD_PAYMENT', + '#34209E', + [ + 'en' => 'Waiting for Credit Card Payment', + 'fr' => 'En attente de paiement par Carte de Crédit', + 'es' => 'Esperando el pago con tarjeta de crédito', + 'it' => 'In attesa di pagamento con carta di credito', + 'nl' => 'Wachten op creditcard-betaling', + 'de' => 'Warten auf Kreditkartenzahlung', + 'pl' => 'Oczekiwanie na płatność kartą kredytową', + 'pt' => 'Aguardando pagamento por cartão de crédito', + ] + ); + break; + case 'PS_CHECKOUT_STATE_WAITING_LOCAL_PAYMENT': + ps_checkout_create_order_state_7_3_3_1( + 'PS_CHECKOUT_STATE_WAITING_LOCAL_PAYMENT', + '#34209E', + [ + 'en' => 'Waiting for Local Payment Method Payment', + 'fr' => 'En attente de paiement par moyen de paiement local', + 'es' => 'Esperando el pago con un método de pago local', + 'it' => 'In attesa di pagamento con metodo di pagamento locale', + 'nl' => 'Wachten op nlaatselijke betaling', + 'de' => 'Warten auf Zahlung per lokaler Zahlungsmethode', + 'pl' => 'Oczekiwanie na płatność lokalnym środkiem płatności', + 'pt' => 'Aguardando pagamento pelo método de pagamento local', + ] + ); + break; + case 'PS_CHECKOUT_STATE_AUTHORIZED': + ps_checkout_create_order_state_7_3_3_1( + 'PS_CHECKOUT_STATE_AUTHORIZED', + '#3498D8', + [ + 'en' => 'Authorized. To be captured by merchant', + 'fr' => 'Autorisation. A capturer par le marchand', + 'es' => 'Autorizado. El vendedor lo capturará', + 'it' => 'Autorizzato. Sarà acquisito dal commerciante', + 'nl' => 'Goedgekeurd. Door retailer te registreren.', + 'de' => 'Autorisiert. Wird von Händler erfasst.', + 'pl' => 'Pomyślna autoryzacja. Transfer do przeprowadzenia przez sklep', + 'pt' => 'Autorizado. A ser capturado pelo comerciante', + ] + ); + break; + case 'PS_CHECKOUT_STATE_PARTIAL_REFUND': + ps_checkout_create_order_state_7_3_3_1( + 'PS_CHECKOUT_STATE_PARTIAL_REFUND', + '#01B887', + [ + 'en' => 'Partial refund', + 'fr' => 'Remboursement partiel', + 'es' => 'Reembolso parcial', + 'it' => 'Rimborso parziale', + 'nl' => 'Gedeeltelijke terugbetaling', + 'de' => 'Teilweise Rückerstattung', + 'pl' => 'Częściowy zwrot', + 'pt' => 'Reembolso parcial', + ] + ); + break; + case 'PS_CHECKOUT_STATE_WAITING_CAPTURE': + ps_checkout_create_order_state_7_3_3_1( + 'PS_CHECKOUT_STATE_WAITING_CAPTURE', + '#3498D8', + [ + 'en' => 'Waiting capture', + 'fr' => 'En attente de capture', + 'es' => 'Esperando la captura', + 'it' => 'In attesa di essere acquisito', + 'nl' => 'Wachten op registratie', + 'de' => 'Warten auf Erfassung', + 'pl' => 'Oczekiwanie na transfer', + 'pt' => 'Aguardando a captura', + ] + ); + break; + } + } + } + + $db->delete( + 'pscheckout_cart', + 'paypal_order IS NULL' + ); + $db->update( + 'pscheckout_cart', + [ + 'paypal_token' => null, + 'paypal_token_expire' => null, + ], + 'paypal_token IS NOT NULL', + 0, + true + ); + } catch (Exception $exception) { + PrestaShopLogger::addLog($exception->getMessage(), 3, $exception->getCode(), Ps_checkout::class, $module->id, false); + } + + // Restore initial PrestaShop shop context + if (Shop::CONTEXT_SHOP === $savedShopContext) { + Shop::setContext($savedShopContext, $savedShopId); + } elseif (Shop::CONTEXT_GROUP === $savedShopContext) { + Shop::setContext($savedShopContext, $savedGroupShopId); + } else { + Shop::setContext($savedShopContext); + } + + return true; +} + +function ps_checkout_create_order_state_7_3_3_1($configuration_key, $color, $nameByLangIsoCode) +{ + $orderStateNameByLangId = []; + foreach ($nameByLangIsoCode as $langIsoCode => $name) { + foreach (Language::getLanguages(false) as $language) { + if (Tools::strtolower($language['iso_code']) === $langIsoCode) { + $orderStateNameByLangId[(int) $language['id_lang']] = $name; + } elseif (isset($nameByLangIsoCode['en'])) { + $orderStateNameByLangId[(int) $language['id_lang']] = $nameByLangIsoCode['en']; + } + } + } + + $orderState = new OrderState(); + $orderState->name = $orderStateNameByLangId; + $orderState->module_name = 'ps_checkout'; + $orderState->unremovable = true; + $orderState->color = $color; + $orderState->delivery = false; + $orderState->shipped = false; + $orderState->pdf_delivery = false; + $orderState->pdf_invoice = false; + $orderState->hidden = false; + $orderState->invoice = false; + $orderState->send_email = false; + $orderState->paid = false; + $orderState->logable = false; + $orderState->deleted = false; + $orderState->template = []; + $orderState->save(); + Configuration::updateGlobalValue($configuration_key, $orderState->id); +}