From c334ebc0e4b4adda2baaf1b6a26886ea5100a11c Mon Sep 17 00:00:00 2001 From: Kocmonavtik <61938582+Kocmonavtik@users.noreply.github.com> Date: Fri, 12 Apr 2024 14:45:24 +0300 Subject: [PATCH] ref #72067 Client registration in PL (#326) --- resources/pot/retailcrm-ru_RU.pot | 81 ++++++++++++ src/assets/css/retailcrm-loyalty-style.css | 34 +++++ src/assets/js/retailcrm-loyalty-actions.js | 121 ++++++++++++++++++ .../api/class-wc-retailcrm-client-v5.php | 2 +- src/include/class-wc-retailcrm-base.php | 103 +++++++++++++++ src/include/class-wc-retailcrm-loyalty.php | 121 ++++++++++++++++++ .../class-wc-retailcrm-loyalty-form.php | 90 +++++++++++++ src/languages/retailcrm-ru_RU.mo | Bin 17803 -> 21014 bytes src/retailcrm.php | 2 + tests/datasets/data-loyalty-retailcrm.php | 76 +++++++++++ .../class-wc-retailcrm-test-case-helper.php | 5 +- tests/test-wc-retailcrm-base.php | 5 + tests/test-wc-retailcrm-loyalty.php | 92 +++++++++++++ 13 files changed, 730 insertions(+), 2 deletions(-) create mode 100644 src/assets/css/retailcrm-loyalty-style.css create mode 100644 src/assets/js/retailcrm-loyalty-actions.js create mode 100644 src/include/class-wc-retailcrm-loyalty.php create mode 100644 src/include/components/class-wc-retailcrm-loyalty-form.php create mode 100644 tests/datasets/data-loyalty-retailcrm.php create mode 100644 tests/test-wc-retailcrm-loyalty.php diff --git a/resources/pot/retailcrm-ru_RU.pot b/resources/pot/retailcrm-ru_RU.pot index 67e62fb..208ff6b 100644 --- a/resources/pot/retailcrm-ru_RU.pot +++ b/resources/pot/retailcrm-ru_RU.pot @@ -483,3 +483,84 @@ msgstr "Вставьте условия обработки персональн msgid "To activate the loyalty program it is necessary to activate the 'enable use of coupons option'" msgstr "Для активации программы лояльности необходимо активировать опцию 'включить использование купонов'" + +msgid "Bonus account" +msgstr "Бонусный счёт" + +msgid "Participation ID: " +msgstr "ID участия: " + +msgid "Current level: " +msgstr "Текущий уровень: " + +msgid "Bonuses on the account: " +msgstr "Бонусов на счёте: " + +msgid "Bonus card number: " +msgstr "Номер бонусной карты: " + +msgid "Date of registration: " +msgstr "Дата регистрации: " + +msgid "Current level rules" +msgstr "Правила текущего уровня" + +msgid "Required amount of purchases to move to the next level: " +msgstr "Необходимая сумма покупок для перехода на следующий уровень: " + +msgid "Activate participation in the loyalty program" +msgstr "Активировать участие в программе лояльности" + +msgid "Send" +msgstr "Отправить" + +msgid "To register in the loyalty program, fill in the form:" +msgstr "Для регистрации в программе лояльности заполните форму:" + +msgid " I agree with " +msgstr " Я согласен с " + +msgid "loyalty program terms" +msgstr "условиями программы лояльности" + +msgid "terms of personal data processing" +msgstr "условиями обработки персональных данных" + +msgid "Phone" +msgstr "Телефон" + +msgid "Error while registering in the loyalty program. Try again later" +msgstr "Ошибка при регистрации в программе лояльности. Попробуйте позже" + +msgid "The card is not linked" +msgstr "Карта не привязана" + +msgid "Error while retrieving data. Try again later" +msgstr "Ошибка при получении данных. Попробуйте позже" + +msgid "Error when activating the loyalty program. Try again later" +msgstr "Ошибка при активации программы лояльности. Попробуйте позже" + +msgid "Enter the correct phone number" +msgstr "Введите корректный номер телефона" + +msgid "Close" +msgstr "Закрыть" + +msgid "Ordinary products: accrual of 1 bonus for each %s %s" +msgstr "Обычные товары: начисление 1 бонуса за каждые %s %s" + +msgid "Promotional products: accrual of 1 bonus for each %s %s" +msgstr "Акционные товары: начисление 1 бонуса за каждые %s %s" + +msgid "Ordinary products: bonus accrual in the amount of %s%% of the purchase amount" +msgstr "Обычные товары: начисление бонусов в размере %s%% от суммы покупки" + +msgid "Promotional products: bonus accrual in the amount of %s%% of the purchase amount" +msgstr "Акционные товары: начисление бонусов в размере %s%% от суммы покупки" + +msgid "Ordinary products: %s%% discount" +msgstr "Обычные товары: %s%% скидка" + +msgid "Promotional products: %s%% discount" +msgstr "Акционные товары: %s%% скидка" diff --git a/src/assets/css/retailcrm-loyalty-style.css b/src/assets/css/retailcrm-loyalty-style.css new file mode 100644 index 0000000..933467b --- /dev/null +++ b/src/assets/css/retailcrm-loyalty-style.css @@ -0,0 +1,34 @@ +.popup-fade-loyalty { + display: none; +} +.popup-fade-loyalty:before { + content: ''; + background: #000; + position: fixed; + left: 0; + top: 0; + width: 100%; + height: 100%; + opacity: 0.7; + z-index: 9999; +} +.popup-loyalty { + position: fixed; + top: 20%; + left: 50%; + padding: 20px; + width: 1000px; + margin-left: -500px; + height: 50%; + background: #fff; + border: 1px solid orange; + border-radius: 4px; + z-index: 99999; + opacity: 1; + overflow: auto; +} +.popup-close-loyalty { + position: absolute; + top: 10px; + right: 10px; +} diff --git a/src/assets/js/retailcrm-loyalty-actions.js b/src/assets/js/retailcrm-loyalty-actions.js new file mode 100644 index 0000000..256fadf --- /dev/null +++ b/src/assets/js/retailcrm-loyalty-actions.js @@ -0,0 +1,121 @@ +jQuery(function() { + jQuery('#loyaltyRegisterForm').on("submit", function (event) { + var termsCheck = jQuery('#termsLoyalty'); + var privacyCheck = jQuery('#privacyLoyalty'); + + if (termsCheck.length) { + if (!termsCheck.is(':checked')) { + event.preventDefault(); + return false; + } + } + + if (privacyCheck.length) { + if (!privacyCheck.is(':checked')) { + event.preventDefault(); + return false; + } + } + + let phone = jQuery('#phoneLoyalty'); + + if (!phone.val().match(/(?:\+|\d)[\d\-\(\) ]{7,}\d/)) { + + if (!jQuery('#warningLoyaltyPhone').length) { + phone.parent().append('' + messagePhone + '') + } + + event.preventDefault(); + return false; + } else { + jQuery('#warningLoyaltyPhone').remove(); + } + + jQuery.ajax({ + url: loyaltyUrl.url + '/admin-ajax.php?action=register_customer_loyalty', + method: 'POST', + timeout: 0, + data: {ajax: 1, phone: phone.val(), userId: customerId}, + dataType: 'json' + }) + .done(function (response) { + if (response.hasOwnProperty('error')) { + jQuery('#loyaltyRegisterForm').append('

'+ response.error + '

') + + event.preventDefault(); + return false; + } else { + location.reload(); + } + }) + + event.preventDefault(); + }); + + jQuery('#loyaltyActivateForm').on("submit", function (event) { + var activateCheckbox = jQuery('#loyaltyActiveCheckbox'); + + if (activateCheckbox.length) { + if (!activateCheckbox.is(':checked')) { + event.preventDefault(); + return false; + } + } + + jQuery.ajax({ + url: loyaltyUrl.url + '/admin-ajax.php?action=activate_customer_loyalty', + method: 'POST', + timeout: 0, + data: {ajax: 1, loyaltyId: loyaltyId}, + dataType: 'json' + }) + .done(function (response) { + if (response.hasOwnProperty('error')) { + jQuery('#loyaltyRegisterForm').append('

'+ response.error + '

') + + event.preventDefault(); + return false; + } else { + location.reload(); + } + }) + + event.preventDefault(); + }); + + jQuery('.popup-open-loyalty').click(function() { + if (jQuery(this).attr('id') === 'terms-popup') { + jQuery('#popup-loyalty-text').html(termsLoyalty); + } else { + jQuery('#popup-loyalty-text').html(privacyLoyalty); + } + + jQuery('.popup-fade-loyalty').fadeIn(); + return false; + }); + + jQuery('.popup-close-loyalty').click(function() { + jQuery(this).parents('.popup-fade-loyalty').fadeOut(); + return false; + }); + + jQuery(document).keydown(function(e) { + if (e.keyCode === 27) { // Key Escape + e.stopPropagation(); + jQuery('.popup-fade-loyalty').fadeOut(); + } + }); + + jQuery('.popup-fade-loyalty').click(function(e) { + if (jQuery(e.target).closest('.popup-loyalty').length == 0) { + jQuery(this).fadeOut(); + } + }); + + jQuery('#phoneLoyalty').keydown(function (e) { + let key = e.key; + + return (key >= '0' && key <= '9') || key == '+' || key == '(' || key == ')'|| key == '-' || + key == 'ArrowLeft' || key == 'ArrowRight' || key == 'Delete' || key == 'Backspace'; + }); +}); diff --git a/src/include/api/class-wc-retailcrm-client-v5.php b/src/include/api/class-wc-retailcrm-client-v5.php index 540172a..485db22 100644 --- a/src/include/api/class-wc-retailcrm-client-v5.php +++ b/src/include/api/class-wc-retailcrm-client-v5.php @@ -2972,7 +2972,7 @@ class WC_Retailcrm_Client_V5 $parameters['status'] = $status; return $this->client->makeRequest( - "/api/v5/loyalty/account/$clientIdLoyalty/bonus/$status/details", + "/loyalty/account/$clientIdLoyalty/bonus/$status/details", WC_Retailcrm_Request::METHOD_GET, $parameters ); diff --git a/src/include/class-wc-retailcrm-base.php b/src/include/class-wc-retailcrm-base.php index 6144498..68e0821 100644 --- a/src/include/class-wc-retailcrm-base.php +++ b/src/include/class-wc-retailcrm-base.php @@ -33,6 +33,9 @@ if (!class_exists('WC_Retailcrm_Base')) { /** @var WC_Retailcrm_Cart */ protected $cart; + /** @var WC_Retailcrm_Loyalty */ + protected $loyalty; + /** * Init and hook in the integration. * @@ -100,6 +103,15 @@ if (!class_exists('WC_Retailcrm_Base')) { add_action('admin_enqueue_scripts', [$this, 'include_files_for_admin'], 101); add_action('woocommerce_new_order', [$this, 'create_order'], 11, 1); + + if (isset($this->settings['loyalty']) && $this->settings['loyalty'] === static::YES) { + add_action('wp_ajax_register_customer_loyalty', [$this, 'register_customer_loyalty']); + add_action('wp_ajax_activate_customer_loyalty', [$this, 'activate_customer_loyalty']); + add_action('init', [$this, 'add_loyalty_endpoint'], 11, 1); + add_action('woocommerce_account_menu_items', [$this, 'add_loyalty_item'], 11, 1); + add_action('woocommerce_account_loyalty_endpoint', [$this, 'show_loyalty'], 11, 1); + } + // Subscribed hooks add_action('register_form', [$this, 'subscribe_register_form'], 99); add_action('woocommerce_register_form', [$this, 'subscribe_woocommerce_register_form'], 99); @@ -128,6 +140,8 @@ if (!class_exists('WC_Retailcrm_Base')) { add_action('woocommerce_cart_emptied', [$this, 'clear_cart']); } + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiClient, $this->settings); + // Deactivate hook add_action('retailcrm_deactivate', [$this, 'deactivate']); @@ -624,6 +638,48 @@ if (!class_exists('WC_Retailcrm_Base')) { wp_die(); } + public function register_customer_loyalty() + { + $phone = filter_input(INPUT_POST, 'phone'); + $userId = filter_input(INPUT_POST, 'userId'); + $site = $this->apiClient->getSingleSiteForKey(); + $isSuccessful = false; + + if (!empty($site) && $userId && $phone) { + $isSuccessful = $this->loyalty->registerCustomer($userId, $phone, $site); + } + + if (!$isSuccessful) { + writeBaseLogs('Errors when registering a loyalty program. Passed parameters: ' . + json_encode(['site' => $site, 'userId' => $userId, 'phone' => $phone]) + ); + echo json_encode(['error' => __('Error while registering in the loyalty program. Try again later', 'retailcrm')]); + } else { + echo json_encode(['isSuccessful' => true]); + } + + wp_die(); + } + + public function activate_customer_loyalty() + { + $loyaltyId = filter_input(INPUT_POST, 'loyaltyId'); + $isSuccessful = false; + + if ($loyaltyId) { + $isSuccessful = $this->loyalty->activateLoyaltyCustomer($loyaltyId); + } + + if (!$isSuccessful) { + writeBaseLogs('Errors when activate loyalty program. Passed parameters: ' . json_encode(['loyaltyId' => $loyaltyId])); + echo json_encode(['error' => __('Error when activating the loyalty program. Try again later', 'retailcrm')]); + } else { + echo json_encode(['isSuccessful' => true]); + } + + wp_die(); + } + /** * In this method we include CSS file * @@ -821,6 +877,53 @@ if (!class_exists('WC_Retailcrm_Base')) { wp_die(); } + public function add_loyalty_item($items) + { + $items['loyalty'] = __('Loyalty program', 'retailcrm'); + + return $items; + } + + public function add_loyalty_endpoint() + { + add_rewrite_endpoint('loyalty', EP_PAGES); + } + + public function show_loyalty() + { + $userId = get_current_user_id(); + + if (!isset($userId)) { + return; + } + + $jsScript = 'retailcrm-loyalty-actions'; + $loyaltyUrl = ['url' => get_admin_url()]; + $jsScriptsPath = plugins_url() . '/woo-retailcrm/assets/js/'; + $cssPath = plugins_url() . '/woo-retailcrm/assets/css/'; + $messagePhone = __('Enter the correct phone number', 'retailcrm'); + + wp_register_script($jsScript, $jsScriptsPath . $jsScript . '.js', false, '0.1'); + wp_enqueue_script($jsScript, $jsScriptsPath . $jsScript . '.js', '', '', true); + wp_localize_script($jsScript, 'loyaltyUrl', $loyaltyUrl); + wp_localize_script($jsScript, 'customerId', $userId); + wp_localize_script($jsScript, 'messagePhone', $messagePhone); + wp_localize_script($jsScript, 'termsLoyalty', $this->settings['loyalty_terms']); + wp_localize_script($jsScript, 'privacyLoyalty', $this->settings['loyalty_personal']); + wp_register_style('retailcrm-loyalty-style', $cssPath . 'retailcrm-loyalty-style.css', false, '0.1'); + wp_enqueue_style('retailcrm-loyalty-style'); + + $result = $this->loyalty->getForm($userId); + + if ([] === $result) { + echo '

'. __('Error while retrieving data. Try again later', 'retailcrm') . '

'; + } else { + wp_localize_script($jsScript, 'loyaltyId', $result['loyaltyId'] ?? null); + echo $result['form']; + } + } + + /** * Get custom fields with CRM * diff --git a/src/include/class-wc-retailcrm-loyalty.php b/src/include/class-wc-retailcrm-loyalty.php new file mode 100644 index 0000000..936ec3d --- /dev/null +++ b/src/include/class-wc-retailcrm-loyalty.php @@ -0,0 +1,121 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + class WC_Retailcrm_Loyalty + { + /** @var WC_Retailcrm_Client_V5 */ + protected $apiClient; + + protected $dateFormat; + + protected $settings; + + /** @var WC_Retailcrm_Loyalty_Form */ + protected $loyaltyForm; + + public function __construct($apiClient, $settings) + { + $this->apiClient = $apiClient; + $this->settings = $settings; + $this->dateFormat = 'Y-m-d H:i:sP'; + $this->loyaltyForm = new WC_Retailcrm_Loyalty_Form(); + } + + public function getForm(int $userId) + { + $result = []; + + try { + $response = $this->apiClient->customersGet($userId); + + if (!isset($response['customer']['id'])) { + return $result; + } + + $filter['customerId'] = $response['customer']['id']; + + $response = $this->apiClient->getLoyaltyAccountList($filter); + } catch (Throwable $exception) { + writeBaseLogs('Exception get loyalty accounts: ' . $exception->getMessage()); + + return $result; + } + + if (!$response->isSuccessful() || !$response->offsetExists('loyaltyAccounts')) { + return $result; + } + + $loyaltyAccount = $response['loyaltyAccounts'][0] ?? null; + + if ($loyaltyAccount && (int) $loyaltyAccount['customer']['externalId'] === $userId) { + if ($loyaltyAccount['active'] === true) { + $result['form'] = $this->loyaltyForm->getInfoLoyalty($loyaltyAccount); + } else { + $result['form'] = $this->loyaltyForm->getActivationForm(); + + $result['loyaltyId'] = $loyaltyAccount['id']; + } + } else { + $result['form'] = $this->loyaltyForm->getRegistrationForm(); + } + + return $result; + } + + public function registerCustomer(int $userId, string $phone, string $site): bool + { + $parameters = [ + 'phoneNumber' => $phone, + 'customer' => [ + 'externalId' => $userId + ] + ]; + + try { + $response = $this->apiClient->createLoyaltyAccount($parameters, $site); + + if (!$response->isSuccessful()) { + writeBaseLogs('Error while registering in the loyalty program: ' . $response->getRawResponse()); + } + + return $response->isSuccessful(); + } catch (Throwable $exception) { + writeBaseLogs('Exception while registering in the loyalty program: ' . $exception->getMessage()); + + return false; + } + } + + public function activateLoyaltyCustomer(int $loyaltyId) + { + try { + $response = $this->apiClient->activateLoyaltyAccount($loyaltyId); + + if (!$response->isSuccessful()) { + writeBaseLogs('Error while registering in the loyalty program: ' . $response->getRawResponse()); + } + + return $response->isSuccessful(); + } catch (Throwable $exception) { + writeBaseLogs('Exception while activate loyalty account: ' . $exception->getMessage()); + + return false; + } + } + } + +endif; diff --git a/src/include/components/class-wc-retailcrm-loyalty-form.php b/src/include/components/class-wc-retailcrm-loyalty-form.php new file mode 100644 index 0000000..0e600db --- /dev/null +++ b/src/include/components/class-wc-retailcrm-loyalty-form.php @@ -0,0 +1,90 @@ + +

%s

+

%s%s.

+

%s%s.

+

+

+ + + ', + __('To register in the loyalty program, fill in the form:', 'retailcrm'), + __(' I agree with ', 'retailcrm'), + __('loyalty program terms', 'retailcrm'), + __(' I agree with ', 'retailcrm'), + __('terms of personal data processing', 'retailcrm'), + __('Phone', 'retailcrm'), + __('Send', 'retailcrm'), + __('Close', 'retailcrm') + ); + } + + public function getActivationForm() + { + return sprintf(' +
+

%s

+ +
', + __('Activate participation in the loyalty program', 'retailcrm'), + __('Send', 'retailcrm') + ); + } + + public function getInfoLoyalty(array $loyaltyAccount) + { + $data = [ + '' . __('Bonus account', 'retailcrm') . '', + __('Participation ID: ', 'retailcrm') . $loyaltyAccount['id'], + __('Current level: ', 'retailcrm') . $loyaltyAccount['level']['name'], + __('Bonuses on the account: ', 'retailcrm') . $loyaltyAccount['amount'], + __('Bonus card number: ' , 'retailcrm') . ($loyaltyAccount['cardNumber'] ?? __('The card is not linked', 'retailcrm')), + __('Date of registration: ', 'retailcrm') . $loyaltyAccount['activatedAt'], + '
', + '' . __('Current level rules', 'retailcrm') . '', + __('Required amount of purchases to move to the next level: ', 'retailcrm') . $loyaltyAccount['nextLevelSum'] . ' ' . $loyaltyAccount['loyalty']['currency'] + ]; + + switch ($loyaltyAccount['level']['type']) { + case 'bonus_converting': + $data[] = sprintf(__('Ordinary products: accrual of 1 bonus for each %s %s', 'retailcrm'), $loyaltyAccount['level']['privilegeSize'], $loyaltyAccount['loyalty']['currency']); + $data[] = sprintf(__('Promotional products: accrual of 1 bonus for each %s %s', 'retailcrm'), $loyaltyAccount['level']['privilegeSizePromo'], $loyaltyAccount['loyalty']['currency']); + break; + case 'bonus_percent': + $data[] = sprintf(__('Ordinary products: bonus accrual in the amount of %s%% of the purchase amount', 'retailcrm'), $loyaltyAccount['level']['privilegeSize']); + $data[] = sprintf(__('Promotional products: bonus accrual in the amount of %s%% of the purchase amount', 'retailcrm'), $loyaltyAccount['level']['privilegeSizePromo']); + break; + case 'discount': + $data[] = sprintf(__('Ordinary products: %s%% discount', 'retailcrm'), $loyaltyAccount['level']['privilegeSize']); + $data[] = sprintf(__('Promotional products: %s%% discount', 'retailcrm'), $loyaltyAccount['level']['privilegeSizePromo']); + break; + } + + $result = ''; + + foreach ($data as $line) { + $result .= "

$line

"; + } + + return $result; + } + } + + +endif; diff --git a/src/languages/retailcrm-ru_RU.mo b/src/languages/retailcrm-ru_RU.mo index 6aaec635745737aab7d090c5edb2b1d027a8507b..ff0da707b92e4cd5af44cd86f85a4c9c138b61bb 100644 GIT binary patch delta 6402 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 O_M;Kg1FX8jtbYLs7 + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class DataLoyaltyRetailCrm +{ + public static function getDataLoyalty() + { + return [ + [ + 'isSuccessful' => true, + 'body' => json_encode(['loyaltyAccounts' => []]), + 'expected' => 'id="loyaltyRegisterForm"' + ], + [ + 'isSuccessful' => true, + 'body' => json_encode( + [ + 'loyaltyAccounts' => [ + 0 => [ + 'active' => false, + 'customer' => [ + 'externalId' => 1 + ], + 'id' => 1 + ] + ] + ] + ), + 'expected' => 'id="loyaltyActivateForm"' + ], + [ + 'isSuccessful' => true, + 'body' => json_encode( + [ + 'loyaltyAccounts' => [ + 0 => [ + 'id' => 1, + 'level' => [ + 'name' => 'Test level', + 'privilegeSize' => 5, + 'privilegeSizePromo' => 3, + 'type' => 'bonus_converting' + ], + 'amount' => 1000, + 'cardNumber' => '12345', + 'activatedAt' => '2024-04-10 15:00:00', + 'nextLevelSum' => 15000, + 'loyalty' => [ + 'currency' => 'USD' + ], + 'customer' => [ + 'externalId' => 1 + ], + 'active' => true + ] + ] + ] + ), + 'expected' => 'Ordinary products: accrual of 1 bonus for each' + ], + ]; + } +} diff --git a/tests/helpers/class-wc-retailcrm-test-case-helper.php b/tests/helpers/class-wc-retailcrm-test-case-helper.php index 2c09d1c..3ce02f1 100644 --- a/tests/helpers/class-wc-retailcrm-test-case-helper.php +++ b/tests/helpers/class-wc-retailcrm-test-case-helper.php @@ -80,7 +80,10 @@ class WC_Retailcrm_Test_Case_Helper extends WC_Unit_Test_Case 'product_description' => 'full', 'stores_for_uploading' => ['woocommerce', 'main'], 'woo_coupon_apply_field' => 'testField', - 'icml_unload_services' => 'yes' + 'icml_unload_services' => 'yes', + 'loyalty' => 'yes', + 'loyalty_terms' => 'Test terms', + 'loyalty_personal' => 'Test privacy' ]; update_option(WC_Retailcrm_Base::$option_key, $options); diff --git a/tests/test-wc-retailcrm-base.php b/tests/test-wc-retailcrm-base.php index aa280df..c24c3c9 100644 --- a/tests/test-wc-retailcrm-base.php +++ b/tests/test-wc-retailcrm-base.php @@ -132,6 +132,11 @@ class WC_Retailcrm_Base_Test extends WC_Retailcrm_Test_Case_Helper $this->assertArrayHasKey('bind_by_sku', $this->baseRetailcrm->form_fields); $this->assertArrayHasKey('update_number', $this->baseRetailcrm->form_fields); $this->assertArrayHasKey('product_description', $this->baseRetailcrm->form_fields); + + //loyalty + $this->assertArrayHasKey('loyalty', $this->baseRetailcrm->form_fields); + $this->assertArrayHasKey('loyalty_terms', $this->baseRetailcrm->form_fields); + $this->assertArrayHasKey('loyalty_personal', $this->baseRetailcrm->form_fields); } public function test_retailcrm_form_fields_value() diff --git a/tests/test-wc-retailcrm-loyalty.php b/tests/test-wc-retailcrm-loyalty.php new file mode 100644 index 0000000..9e6f653 --- /dev/null +++ b/tests/test-wc-retailcrm-loyalty.php @@ -0,0 +1,92 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ +class WC_Retailcrm_Loyalty_Test extends WC_Retailcrm_Test_Case_Helper +{ + protected $responseMock; + protected $apiMock; + + /** @var \WC_Retailcrm_Loyalty */ + protected $loyalty; + + public function setUp() + { + $this->responseMock = $this->getMockBuilder('\WC_Retailcrm_Response_Helper') + ->disableOriginalConstructor() + ->setMethods(['isSuccessful']) + ->getMock() + ; + + $this->responseMock->setResponse(['success' => true]); + $this->setMockResponse($this->responseMock, 'isSuccessful', true); + + $this->apiMock = $this->getMockBuilder('\WC_Retailcrm_Client_V5') + ->disableOriginalConstructor() + ->setMethods(['customersGet', 'getLoyaltyAccountList', 'createLoyaltyAccount', 'activateLoyaltyAccount']) + ->getMock() + ; + + $this->setMockResponse($this->apiMock, 'customersGet', ['customer' => ['id' => 1]]); + $this->setMockResponse($this->apiMock, 'createLoyaltyAccount', $this->responseMock); + $this->setMockResponse($this->apiMock, 'activateLoyaltyAccount', $this->responseMock); + + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, []); + } + + /** + * @dataProvider responseLoyalty + */ + public function testGetForm($isSuccessful, $body, $expected) + { + $response = new WC_Retailcrm_Response($isSuccessful ? 200 : 400, $body); + + $this->setMockResponse($this->apiMock, 'getLoyaltyAccountList', $response); + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, []); + + $result = $this->loyalty->getForm(1); + + if (isset($result['form'])) { + $this->assertTrue((bool) stripos($result['form'], $expected)); + } + } + + public function testRegistrationLoyalty() + { + $result = $this->loyalty->registerCustomer(1, '89999999999', 'test'); + + $this->assertTrue($result); + } + + public function testActivateLoyalty() + { + $result = $this->loyalty->activateLoyaltyCustomer(1); + + $this->assertTrue($result); + } + + public function responseLoyalty() + { + return DataLoyaltyRetailCrm::getDataLoyalty(); + } +}