Skip to content

Commit

Permalink
PIPRES-349: Restrict subscription product add to cart based on subscr…
Browse files Browse the repository at this point in the history
…iption settings (#850)

* PIPRES-349: Restrict subscription product add to cart based on subscription settings

* subtracted validation to a single service
  • Loading branch information
mandan2 authored Nov 28, 2023
1 parent ac4e891 commit 5644ede
Show file tree
Hide file tree
Showing 16 changed files with 400 additions and 50 deletions.
45 changes: 26 additions & 19 deletions controllers/front/ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
use Mollie\Adapter\ConfigurationAdapter;
use Mollie\Adapter\ToolsAdapter;
use Mollie\Controller\AbstractMollieController;
use Mollie\Errors\Http\HttpStatusCode;
use Mollie\Exception\FailedToProvidePaymentFeeException;
use Mollie\Infrastructure\Response\JsonResponse;
use Mollie\Provider\PaymentFeeProviderInterface;
use Mollie\Shared\Infrastructure\Repository\CurrencyRepositoryInterface;
use Mollie\Subscription\Exception\SubscriptionProductValidationException;
use Mollie\Subscription\Exception\ExceptionCode;
use Mollie\Subscription\Validator\CanProductBeAddedToCartValidator;
use Mollie\Utility\NumberUtility;

Expand Down Expand Up @@ -185,30 +187,35 @@ private function displayCheckoutError(): void

private function validateProduct(): void
{
/** @var CanProductBeAddedToCartValidator $cartValidation */
$cartValidation = $this->module->getService(CanProductBeAddedToCartValidator::class);
/** @var CanProductBeAddedToCartValidator $canProductBeAddedToCartValidator */
$canProductBeAddedToCartValidator = $this->module->getService(CanProductBeAddedToCartValidator::class);

$product = Tools::getValue('product');

$productCanBeAdded = true;
$message = '';

try {
$cartValidation->validate((int) $product['id_product_attribute']);
} catch (SubscriptionProductValidationException $e) {
$productCanBeAdded = false;
$message = $this->module->l('Please note: Only one subscription product can be added to the cart at a time.', self::FILE_NAME);
$canProductBeAddedToCartValidator->validate((int) ($product['id_product_attribute'] ?? 0));
} catch (\Throwable $exception) {
if ($exception->getCode() === ExceptionCode::CART_ALREADY_HAS_SUBSCRIPTION_PRODUCT) {
$this->ajaxResponse(JsonResponse::error(
$this->module->l('Please note: Only one subscription product can be added to the cart at a time.', self::FILE_NAME),
HttpStatusCode::HTTP_BAD_REQUEST
));
}

if ($exception->getCode() === ExceptionCode::CART_INVALID_SUBSCRIPTION_SETTINGS) {
$this->ajaxResponse(JsonResponse::error(
$this->module->l('Subscription service is disabled. Please change the attribute to Subscription: none.', self::FILE_NAME),
HttpStatusCode::HTTP_BAD_REQUEST
));
}

$this->ajaxResponse(JsonResponse::error(
$this->module->l('Unknown error. Try again or change the attribute to Subscription: none.', self::FILE_NAME),
HttpStatusCode::HTTP_BAD_REQUEST
));
}

$this->ajaxRender(
json_encode(
[
'success' => true,
'isValid' => $productCanBeAdded,
'message' => $message,
]
)
);
$this->ajaxResponse(JsonResponse::success([]));
}

private function returnDefaultOrderSummaryBlock(Cart $cart, array $errorData = [], array $presentedCart = null): void
Expand Down
11 changes: 5 additions & 6 deletions mollie.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
use Mollie\Repository\PaymentMethodRepositoryInterface;
use Mollie\Service\ExceptionService;
use Mollie\ServiceProvider\LeagueServiceContainerProvider;
use Mollie\Subscription\Exception\SubscriptionProductValidationException;
use Mollie\Subscription\Handler\CustomerAddressUpdateHandler;
use Mollie\Subscription\Install\AttributeInstaller;
use Mollie\Subscription\Install\DatabaseTableInstaller;
Expand Down Expand Up @@ -1014,14 +1013,14 @@ public function hookDisplayProductAdditionalInfo()
return '';
}

public function hookActionCartUpdateQuantityBefore($params)
public function hookActionCartUpdateQuantityBefore($params): void
{
/** @var CanProductBeAddedToCartValidator $cartValidation */
$cartValidation = $this->getService(CanProductBeAddedToCartValidator::class);
/** @var CanProductBeAddedToCartValidator $canProductBeAddedToCartValidator */
$canProductBeAddedToCartValidator = $this->getService(CanProductBeAddedToCartValidator::class);

try {
$cartValidation->validate((int) $params['id_product_attribute']);
} catch (SubscriptionProductValidationException $e) {
$canProductBeAddedToCartValidator->validate((int) $params['id_product_attribute']);
} catch (\Throwable $exception) {
$product = $this->makeProductNotOrderable($params['product']);

$params['product'] = $product;
Expand Down
2 changes: 1 addition & 1 deletion src/Config/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ class Config
const MOLLIE_CARRIER_CUSTOM_URL = 'MOLLIE_CARRIER_CUSTOM_URL_';

const MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID = 'MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID';
const MOLLIE_SUBSCRIPTION_ENABLE = 'MOLLIE_SUBSCRIPTION_ENABLE';
const MOLLIE_SUBSCRIPTION_ENABLED = 'MOLLIE_SUBSCRIPTION_ENABLED';

const MOLLIE_METHOD_ENABLED = 'MOLLIE_METHOD_ENABLED_';
const MOLLIE_METHOD_TITLE = 'MOLLIE_METHOD_TITLE_';
Expand Down
2 changes: 1 addition & 1 deletion src/Install/Installer.php
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ protected function initConfig()
$this->configurationAdapter->updateValue(Config::MOLLIE_BANCONTACT_QR_CODE_ENABLED, 0);

$this->configurationAdapter->updateValue(Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID, 0);
$this->configurationAdapter->updateValue(Config::MOLLIE_SUBSCRIPTION_ENABLE, 0);
$this->configurationAdapter->updateValue(Config::MOLLIE_SUBSCRIPTION_ENABLED, 0);
}

public function setDefaultCarrierStatuses()
Expand Down
2 changes: 1 addition & 1 deletion src/Install/Uninstall.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private function deleteConfig()
Config::MOLLIE_MAIL_WHEN_COMPLETED,
Config::MOLLIE_API_KEY_TEST,
Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID,
Config::MOLLIE_SUBSCRIPTION_ENABLE,
Config::MOLLIE_SUBSCRIPTION_ENABLED,
];

$this->deleteConfigurations($configurations);
Expand Down
36 changes: 36 additions & 0 deletions subscription/Exception/CouldNotValidateSubscriptionSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php
/**
* Mollie https://www.mollie.nl
*
* @author Mollie B.V. <[email protected]>
* @copyright Mollie B.V.
* @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md
*
* @see https://github.com/mollie/PrestaShop
* @codingStandardsIgnoreStart
*/

namespace Mollie\Subscription\Exception;

if (!defined('_PS_VERSION_')) {
exit;
}

class CouldNotValidateSubscriptionSettings extends MollieSubscriptionException
{
public static function subscriptionServiceDisabled(): self
{
return new self(
'Subscription service disabled.',
ExceptionCode::CART_SUBSCRIPTION_SERVICE_DISABLED
);
}

public static function subscriptionCarrierInvalid(): self
{
return new self(
'Subscription carrier invalid.',
ExceptionCode::CART_SUBSCRIPTION_CARRIER_INVALID
);
}
}
5 changes: 4 additions & 1 deletion subscription/Exception/ExceptionCode.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ class ExceptionCode

//Cart error codes starts from 2000

public const CART_ALREADY_HAS_SUBSCRIPTION_PRODUCT = 2001;
public const CART_INVALID_SUBSCRIPTION_SETTINGS = 2001;
public const CART_ALREADY_HAS_SUBSCRIPTION_PRODUCT = 2002;
public const CART_SUBSCRIPTION_SERVICE_DISABLED = 2003;
public const CART_SUBSCRIPTION_CARRIER_INVALID = 2004;

//Recurring order error codes starts from 3000

Expand Down
15 changes: 15 additions & 0 deletions subscription/Exception/SubscriptionProductValidationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,19 @@

class SubscriptionProductValidationException extends MollieSubscriptionException
{
public static function invalidSubscriptionSettings(): self
{
return new self(
'Invalid subscription settings',
ExceptionCode::CART_INVALID_SUBSCRIPTION_SETTINGS
);
}

public static function cartAlreadyHasSubscriptionProduct(): self
{
return new self(
'Cart already has subscription product',
ExceptionCode::CART_ALREADY_HAS_SUBSCRIPTION_PRODUCT
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function __construct(Configuration $configuration)
public function getConfiguration(): array
{
return [
'enable_subscriptions' => $this->configuration->getBoolean(Config::MOLLIE_SUBSCRIPTION_ENABLE),
'enable_subscriptions' => $this->configuration->getBoolean(Config::MOLLIE_SUBSCRIPTION_ENABLED),
'carrier' => $this->configuration->getInt(Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID),
];
}
Expand All @@ -53,7 +53,7 @@ public function updateConfiguration(array $configuration): array
}

$this->configuration->set(
Config::MOLLIE_SUBSCRIPTION_ENABLE,
Config::MOLLIE_SUBSCRIPTION_ENABLED,
(int) $configuration['enable_subscriptions']
);

Expand Down
38 changes: 30 additions & 8 deletions subscription/Validator/CanProductBeAddedToCartValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

use Mollie\Adapter\CartAdapter;
use Mollie\Adapter\ToolsAdapter;
use Mollie\Subscription\Exception\ExceptionCode;
use Mollie\Subscription\Exception\CouldNotValidateSubscriptionSettings;
use Mollie\Subscription\Exception\SubscriptionProductValidationException;

if (!defined('_PS_VERSION_')) {
Expand All @@ -33,15 +33,19 @@ class CanProductBeAddedToCartValidator

/** @var ToolsAdapter */
private $tools;
/** @var SubscriptionSettingsValidator */
private $subscriptionSettingsValidator;

public function __construct(
CartAdapter $cart,
SubscriptionProductValidator $subscriptionProductValidator,
ToolsAdapter $tools
ToolsAdapter $tools,
SubscriptionSettingsValidator $subscriptionSettingsValidator
) {
$this->cart = $cart;
$this->subscriptionProductValidator = $subscriptionProductValidator;
$this->tools = $tools;
$this->subscriptionSettingsValidator = $subscriptionSettingsValidator;
}

/**
Expand All @@ -55,14 +59,21 @@ public function validate(int $productAttributeId): bool
return true;
}

$isNewSubscriptionProduct = $this->subscriptionProductValidator->validate($productAttributeId);
if (!$this->subscriptionProductValidator->validate($productAttributeId)) {
return true;
}

if (!$this->validateSubscriptionSettings()) {
throw SubscriptionProductValidationException::invalidSubscriptionSettings();
}

return !$isNewSubscriptionProduct || $this->validateIfSubscriptionProductCanBeAdded($productAttributeId);
if (!$this->validateIfSubscriptionProductCanBeAdded($productAttributeId)) {
throw SubscriptionProductValidationException::cartAlreadyHasSubscriptionProduct();
}

return true;
}

/**
* @throws SubscriptionProductValidationException
*/
private function validateIfSubscriptionProductCanBeAdded(int $productAttributeId): bool
{
$cartProducts = $this->cart->getProducts();
Expand All @@ -76,7 +87,18 @@ private function validateIfSubscriptionProductCanBeAdded(int $productAttributeId
continue;
}

throw new SubscriptionProductValidationException('Cart already has subscription product', ExceptionCode::CART_ALREADY_HAS_SUBSCRIPTION_PRODUCT);
return false;
}

return true;
}

private function validateSubscriptionSettings(): bool
{
try {
$this->subscriptionSettingsValidator->validate();
} catch (CouldNotValidateSubscriptionSettings $exception) {
return false;
}

return true;
Expand Down
73 changes: 73 additions & 0 deletions subscription/Validator/SubscriptionSettingsValidator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php
/**
* Mollie https://www.mollie.nl
*
* @author Mollie B.V. <[email protected]>
* @copyright Mollie B.V.
* @license https://github.com/mollie/PrestaShop/blob/master/LICENSE.md
*
* @see https://github.com/mollie/PrestaShop
* @codingStandardsIgnoreStart
*/

namespace Mollie\Subscription\Validator;

use Mollie\Adapter\ConfigurationAdapter;
use Mollie\Config\Config;
use Mollie\Repository\CarrierRepositoryInterface;
use Mollie\Subscription\Exception\CouldNotValidateSubscriptionSettings;

if (!defined('_PS_VERSION_')) {
exit;
}

class SubscriptionSettingsValidator
{
/** @var ConfigurationAdapter */
private $configuration;
/** @var CarrierRepositoryInterface */
private $carrierRepository;

public function __construct(
ConfigurationAdapter $configuration,
CarrierRepositoryInterface $carrierRepository
) {
$this->configuration = $configuration;
$this->carrierRepository = $carrierRepository;
}

/**
* @throws CouldNotValidateSubscriptionSettings
*/
public function validate(): bool
{
if (!$this->isSubscriptionActive()) {
throw CouldNotValidateSubscriptionSettings::subscriptionServiceDisabled();
}

if (!$this->isSubscriptionCarrierValid()) {
throw CouldNotValidateSubscriptionSettings::subscriptionCarrierInvalid();
}

return true;
}

private function isSubscriptionActive(): bool
{
return (bool) $this->configuration->get(Config::MOLLIE_SUBSCRIPTION_ENABLED);
}

private function isSubscriptionCarrierValid(): bool
{
$carrierId = (int) $this->configuration->get(Config::MOLLIE_SUBSCRIPTION_ORDER_CARRIER_ID);

/** @var \Carrier|null $carrier */
$carrier = $this->carrierRepository->findOneBy([
'id_carrier' => $carrierId,
'active' => 1,
'deleted' => 0,
]);

return (bool) $carrier;
}
}
Loading

0 comments on commit 5644ede

Please sign in to comment.