diff --git a/resources/pot/retailcrm-es_ES.pot b/resources/pot/retailcrm-es_ES.pot index e859fd0..b794686 100644 --- a/resources/pot/retailcrm-es_ES.pot +++ b/resources/pot/retailcrm-es_ES.pot @@ -474,3 +474,27 @@ msgstr "Descarga de servicios" msgid "Goods with the 'virtual' option enabled will be uploaded to Simla as services" msgstr "Los bienes con la opción 'virtual' activada se cargarán en Simla como servicios" + +msgid "User not found in the system" +msgstr "Usuario no encontrado en el sistema" + +msgid "Error when searching for participation in loyalty programs" +msgstr "Error al buscar la participación en programas de fidelización" + +msgid "No active participation in the loyalty program was detected" +msgstr "No se detectó ninguna participación activa en el programa de fidelización" + +msgid "No bonuses for debiting" +msgstr "Sin bonificaciones por adeudo" + +msgid "Loyalty program not found" +msgstr "Programa de fidelización no encontrado" + +msgid "Loyalty program is not active" +msgstr "El programa de fidelización no está activo" + +msgid "Loyalty program blocked" +msgstr "Programa de fidelización bloqueado" + +msgid "This user is a corporate person" +msgstr "Este usuario es una persona jurídica" diff --git a/resources/pot/retailcrm-ru_RU.pot b/resources/pot/retailcrm-ru_RU.pot index f19b664..d75fdfc 100644 --- a/resources/pot/retailcrm-ru_RU.pot +++ b/resources/pot/retailcrm-ru_RU.pot @@ -564,3 +564,27 @@ msgstr "Выгрузка услуг" msgid "Goods with the 'virtual' option enabled will be uploaded to Simla as services" msgstr "Товары с включенной опцией 'виртуальные' будут выгружаться в CRM как услуги" + +msgid "User not found in the system" +msgstr "Пользователь не найден в системе" + +msgid "Error when searching for participation in loyalty programs" +msgstr "Ошибка при поиске участия в программах лояльности" + +msgid "No active participation in the loyalty program was detected" +msgstr "Активного участия в программе лояльности не обнаружено" + +msgid "No bonuses for debiting" +msgstr "Бонусы на списание отсутствуют" + +msgid "Loyalty program not found" +msgstr "Программа лояльности не найдена" + +msgid "Loyalty program is not active" +msgstr "Программа лояльности не активна" + +msgid "Loyalty program blocked" +msgstr "Программа лояльности заблокирована" + +msgid "This user is a corporate person" +msgstr "Данный пользователь является корпоратиным лицом" diff --git a/src/include/validators/loyalty-validator/class-wc-retailcrm-loyalty-constraint.php b/src/include/validators/loyalty-validator/class-wc-retailcrm-loyalty-constraint.php new file mode 100644 index 0000000..838bae9 --- /dev/null +++ b/src/include/validators/loyalty-validator/class-wc-retailcrm-loyalty-constraint.php @@ -0,0 +1,33 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + class WC_Retailcrm_Loyalty_Constraint + { + public $notFoundCrmUser = 'User not found in the system'; + + public $errorFoundLoyalty = 'Error when searching for participation in loyalty programs'; + + public $notFoundActiveParticipation = 'No active participation in the loyalty program was detected'; + + public $notExistBonuses = 'No bonuses for debiting'; + + public $notFoundLoyalty = 'Loyalty program not found'; + + public $loyaltyInactive = 'Loyalty program is not active'; + + public $loyaltyBlocked = 'Loyalty program blocked'; + + public $isCorporateUser = 'This user is a corporate person'; + } +endif; diff --git a/src/include/validators/loyalty-validator/class-wc-retailcrm-loyalty-validator.php b/src/include/validators/loyalty-validator/class-wc-retailcrm-loyalty-validator.php new file mode 100644 index 0000000..6c46155 --- /dev/null +++ b/src/include/validators/loyalty-validator/class-wc-retailcrm-loyalty-validator.php @@ -0,0 +1,117 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + class WC_Retailcrm_Loyalty_Validator extends WC_Retailcrm_Loyalty_Constraint + { + /** @var WC_Retailcrm_Client_V5 */ + protected $apiClient; + protected $crmUser; + protected $loyaltyAccount; + protected $isActiveCorp; + + public function __construct($apiClient, $isActiveCorp) + { + $this->apiClient = $apiClient; + $this->isActiveCorp = $isActiveCorp; + } + + public function checkAccount(int $userId): bool + { + try { + $this->checkUser($userId); + $this->checkLoyaltyAccount($this->crmUser['id']); + $this->checkActiveLoyalty($this->loyaltyAccount['loyalty']['id']); + + return true; + } catch (ValidatorException $exception) { + WC_Admin_Settings::add_error((esc_html__($exception->getMessage(), 'retailcrm')) . "userId: $userId"); + } catch (Throwable $exception) { + WC_Admin_Settings::add_error($exception->getMessage()); + } + + return false; + } + + /** + * @throws ValidatorException + */ + private function checkUser($userId) + { + $responseUser = $this->apiClient->customersGet($userId); + + if (!isset($responseUser['customer']['id'])) { + throw new ValidatorException($this->notFoundCrmUser, 400); + } + + $customer = new WC_Customer($userId); + + if ($this->isActiveCorp && !empty($customer->get_shipping_company())) { + throw new ValidatorException($this->isCorporateUser, 400); + } + + $this->crmUser = $responseUser['customer']; + } + + /** + * @throws ValidatorException + */ + private function checkLoyaltyAccount($crmUserId) + { + $filter['customerId'] = $crmUserId; + $responseLoyalty = $this->apiClient->getLoyaltyAccountList($filter); + + if (!$responseLoyalty->isSuccessful() || !$responseLoyalty->offsetExists('loyaltyAccounts')) { + throw new ValidatorException($this->errorFoundLoyalty, 400); + } + + $actualAccount = null; + + foreach ($responseLoyalty['loyaltyAccounts'] as $loyaltyAccount) { + if ($loyaltyAccount['active'] === true) { + $actualAccount = $loyaltyAccount; + } + } + + if (!isset($actualAccount)) { + throw new ValidatorException($this->notFoundActiveParticipation, 400); + } + + if ($actualAccount['amount'] === 0 && $actualAccount['level']['type'] !== 'discount') { + throw new ValidatorException($this->notExistBonuses, 400); + } + + $this->loyaltyAccount = $actualAccount; + } + + /** + * @throws ValidatorException + */ + private function checkActiveLoyalty($idLoyalty) + { + $responseLoyalty = $this->apiClient->getLoyalty($idLoyalty); + + if (!$responseLoyalty->isSuccessful() || !$responseLoyalty->offsetExists('loyalty')) { + throw new ValidatorException($this->notFoundLoyalty, 400); + } + + if ($responseLoyalty['loyalty']['active'] !== true) { + throw new ValidatorException($this->loyaltyInactive, 400); + } + + if ($responseLoyalty['loyalty']['blocked'] === true) { + throw new ValidatorException($this->loyaltyBlocked, 400); + } + } + } +endif; diff --git a/src/languages/retailcrm-es_ES.mo b/src/languages/retailcrm-es_ES.mo index d0b0ad6..3ba8896 100644 Binary files a/src/languages/retailcrm-es_ES.mo and b/src/languages/retailcrm-es_ES.mo differ diff --git a/src/languages/retailcrm-ru_RU.mo b/src/languages/retailcrm-ru_RU.mo index 80f4849..6f819be 100644 Binary files a/src/languages/retailcrm-ru_RU.mo and b/src/languages/retailcrm-ru_RU.mo differ diff --git a/src/retailcrm.php b/src/retailcrm.php index 517ec01..afc7ead 100644 --- a/src/retailcrm.php +++ b/src/retailcrm.php @@ -134,6 +134,8 @@ if (!class_exists( 'WC_Integration_Retailcrm')) : require_once(self::checkCustomFile('include/validators/url-validator/class-wc-retailcrm-url-validator.php')); require_once(self::checkCustomFile('include/validators/class-wc-retailcrm-validator-exception.php')); require_once(self::checkCustomFile('include/components/class-wc-retailcrm-loyalty-form.php')); + require_once(self::checkCustomFile('include/validators/loyalty-validator/class-wc-retailcrm-loyalty-constraint.php')); + require_once(self::checkCustomFile('include/validators/loyalty-validator/class-wc-retailcrm-loyalty-validator.php')); } /** diff --git a/tests/datasets/data-loyalty-retailcrm.php b/tests/datasets/data-loyalty-retailcrm.php index ef9044f..ec44910 100644 --- a/tests/datasets/data-loyalty-retailcrm.php +++ b/tests/datasets/data-loyalty-retailcrm.php @@ -73,4 +73,82 @@ class DataLoyaltyRetailCrm ], ]; } + + public static function dataCheckUser() + { + return [ + [ + 'responseApiMethod' => [], + 'wcUserType' => 'individual', + 'throwMessage' => 'User not found in the system', + 'isCorpActive' => false + ], + [ + 'responseApiMethod' => ['customer' => ['id' => 1]], + 'wcUserType' => 'corp', + 'throwMessage' => 'This user is a corporate person', + 'isCorpActive' => true, + ], + [ + 'responseApiMethod' => ['customer' => ['id' => 1]], + 'wcUserType' => 'corp', + 'throwMessage' => null, + 'isCorpActive' => false, + ], + [ + 'responseApiMethod' => ['customer' => ['id' => 1]], + 'wcUserType' => 'individual', + 'throwMessage' => null, + 'isCorpActive' => true, + ], + ]; + } + + public static function dataLoyaltyAccount() + { + return [ + [ + 'responseMock' => ['success' => true], + 'throwMessage' => 'Error when searching for participation in loyalty programs' + ], + [ + 'responseMock' => ['success' => true, 'loyaltyAccounts' => []], + 'throwMessage' => 'No active participation in the loyalty program was detected' + ], + [ + 'responseMock' => ['success' => true, 'loyaltyAccounts' => [['active' => true, 'amount' => 0, 'level' => ['type' => 'bonus_converting']]]], + 'throwMessage' => 'No bonuses for debiting' + ], + [ + 'responseMock' => ['success' => true, 'loyaltyAccounts' => [['active' => true, 'amount' => 0, 'level' => ['type' => 'discount']]]], + 'throwMessage' => null + ], + [ + 'responseMock' => ['success' => true, 'loyaltyAccounts' => [['active' => true, 'amount' => 100, 'level' => ['type' => 'bonus_converting']]]], + 'throwMessage' => null + ], + ]; + } + + public static function dataCheckActiveLoyalty() + { + return [ + [ + 'responseMock' => ['success' => true], + 'throwMessage' => 'Loyalty program not found' + ], + [ + 'responseMock' => ['success' => true, 'loyalty' => ['active' => false]], + 'throwMessage' => 'Loyalty program is not active' + ], + [ + 'responseMock' => ['success' => true, 'loyalty' => ['active' => true, 'blocked' => true]], + 'throwMessage' => 'Loyalty program blocked' + ], + [ + 'responseMock' => ['success' => true, 'loyalty' => ['active' => true, 'blocked' => false]], + 'throwMessage' => null + ] + ]; + } } diff --git a/tests/validators/test-wc-retailcrm-loyalty-validator.php b/tests/validators/test-wc-retailcrm-loyalty-validator.php new file mode 100644 index 0000000..f25694f --- /dev/null +++ b/tests/validators/test-wc-retailcrm-loyalty-validator.php @@ -0,0 +1,140 @@ +individualClient = new WC_Customer(); + $this->individualClient->set_first_name('Test'); + $this->individualClient->set_last_name('Test'); + $this->individualClient->set_email(uniqid(md5(date('Y-m-d H:i:s'))) . '@mail.com'); + $this->individualClient->set_billing_email( $this->individualClient->get_email()); + $this->individualClient->set_password('password'); + $this->individualClient->set_billing_phone('89000000000'); + $this->individualClient->set_date_created(date('Y-m-d H:i:s')); + $this->individualClient->save(); + + $this->corpClient = new WC_Customer(); + $this->corpClient->set_first_name('Test'); + $this->corpClient->set_last_name('Test'); + $this->corpClient->set_email(uniqid(md5(date('Y-m-d H:i:s'))) . '@mail.com'); + $this->corpClient->set_billing_email($this->corpClient->get_email()); + $this->corpClient->set_password('password'); + $this->corpClient->set_billing_phone('89000000000'); + $this->corpClient->set_date_created(date('Y-m-d H:i:s')); + $this->corpClient->set_shipping_company('TEST COMPANY'); + $this->corpClient->save(); + } + + /** @dataProvider datasets\DataLoyaltyRetailCrm::dataCheckUser() */ + public function testCheckUser($responseApiMethod, $wcUserType, $throwMessage, $isCorpActive) + { + $this->setResponseMock(); + $this->setApiMock('customersGet', $responseApiMethod); + + $validator = new WC_Retailcrm_Loyalty_Validator($this->apiMock, $isCorpActive); + $method = $this->getPrivateMethod('checkUser', $validator); + + $wcUserId = $wcUserType === 'individual' ? $this->individualClient->get_id() : $this->corpClient->get_id(); + + try { + $method->invokeArgs($validator, [$wcUserId]); + + if ($throwMessage) { + $this->fail('ValidatorException was not thrown'); + } else { + $this->assertTrue(true); + } + } catch (ValidatorException $exception) { + $this->assertEquals($throwMessage, $exception->getMessage()); + } + } + + /** @dataProvider datasets\DataLoyaltyRetailCrm::dataLoyaltyAccount() */ + public function testGetLoyaltyAccount($responseMock, $throwMessage) + { + $this->setResponseMock($responseMock); + $this->setApiMock('getLoyaltyAccountList', $this->responseMock); + + $validator = new WC_Retailcrm_Loyalty_Validator($this->apiMock, true); + $method = $this->getPrivateMethod('checkLoyaltyAccount', $validator); + + try { + $method->invokeArgs($validator, [777]); + + if ($throwMessage) { + $this->fail('ValidatorException was not thrown'); + } else { + $this->assertTrue(true); + } + } catch (ValidatorException $exception) { + $this->assertEquals($throwMessage, $exception->getMessage()); + } + } + + /** @dataProvider datasets\DataLoyaltyRetailCrm::dataCheckActiveLoyalty() */ + public function testCheckActivateLoyalty($responseMock, $throwMessage) + { + $this->setResponseMock($responseMock); + $this->setApiMock('getLoyalty', $this->responseMock); + + $validator = new WC_Retailcrm_Loyalty_Validator($this->apiMock, true); + $method = $this->getPrivateMethod('checkActiveLoyalty', $validator); + + try { + $method->invokeArgs($validator, [1]); + + if ($throwMessage) { + $this->fail('ValidatorException was not thrown'); + } else { + $this->assertTrue(true); + } + } catch (ValidatorException $exception) { + $this->assertEquals($throwMessage, $exception->getMessage()); + } + } + + private function setResponseMock($response = ['success' => true]) + { + $this->responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(['isSuccessful']) + ->getMock() + ; + + $this->responseMock->setResponse($response); + $this->setMockResponse($this->responseMock, 'isSuccessful', true); + } + + private function setApiMock($method, $response) + { + $this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Client_V5') + ->disableOriginalConstructor() + ->setMethods([$method]) + ->getMock() + ; + $this->setMockResponse($this->apiMock, $method, $response); + } + + private function getPrivateMethod($method, $class) + { + $reflection = new ReflectionClass($class); + $method = $reflection->getMethod($method); + $method->setAccessible(true); + + return $method; + } + + public function tearDown() + { + $this->individualClient->delete(); + $this->corpClient->delete(); + } +}