From 2cc71745c2052d8838d894ca23edf030e6887034 Mon Sep 17 00:00:00 2001 From: Kocmonavtik <61938582+Kocmonavtik@users.noreply.github.com> Date: Thu, 4 Apr 2024 09:10:34 +0300 Subject: [PATCH] ref #71905 Add API methods for loyalty program (#324) rebase rebase --- resources/pot/retailcrm-es_ES.pot | 24 ++ resources/pot/retailcrm-ru_RU.pot | 105 +++++ src/assets/css/retailcrm-loyalty-style.css | 34 ++ src/assets/js/retailcrm-loyalty-actions.js | 121 ++++++ src/assets/js/retailcrm-loyalty.js | 36 ++ .../class-wc-retailcrm-abstracts-settings.php | 36 ++ .../api/class-wc-retailcrm-client-v5.php | 403 ++++++++++-------- src/include/class-wc-retailcrm-base.php | 123 +++++- src/include/class-wc-retailcrm-loyalty.php | 121 ++++++ .../class-wc-retailcrm-loyalty-form.php | 90 ++++ src/languages/retailcrm-es_ES.mo | Bin 13576 -> 14660 bytes src/languages/retailcrm-ru_RU.mo | Bin 16757 -> 21307 bytes src/retailcrm.php | 2 + tests/datasets/data-loyalty-retailcrm.php | 76 ++++ .../class-wc-retailcrm-test-case-helper.php | 5 +- tests/loyalty/test-wc-retailcrm-client-v5.php | 131 ++++++ tests/test-wc-retailcrm-base.php | 5 + tests/test-wc-retailcrm-loyalty.php | 92 ++++ 18 files changed, 1216 insertions(+), 188 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/assets/js/retailcrm-loyalty.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/loyalty/test-wc-retailcrm-client-v5.php create mode 100644 tests/test-wc-retailcrm-loyalty.php diff --git a/resources/pot/retailcrm-es_ES.pot b/resources/pot/retailcrm-es_ES.pot index 970ebdc..e859fd0 100644 --- a/resources/pot/retailcrm-es_ES.pot +++ b/resources/pot/retailcrm-es_ES.pot @@ -445,6 +445,30 @@ msgstr "Se requiere clave API con acceso a una tienda" msgid "The currency of the site differs from the currency of the store in CRM. For the integration to work correctly, the currencies in CRM and CMS must match" msgstr "La moneda del sitio web es distinto a la tienda del CRM. Para el funcionamiento correcto de la integración, las monedas del CMS y CRM deben coincid" +msgid "Loyalty program" +msgstr "Programa de fidelización" + +msgid "Activate program loyalty" +msgstr "Activar el programa de fidelización" + +msgid "Enable this setting for activate program loyalty on site" +msgstr "Active esta opción para activar el programa de fidelización en el sitio web" + +msgid "Terms of loyalty program" +msgstr "Condiciones del programa de fidelidad" + +msgid "Insert the terms and conditions of the loyalty program" +msgstr "Inserte las condiciones de participación en el programa de fidelidad" + +msgid "Conditions of personal data processing" +msgstr "Condiciones del tratamiento de datos personales" + +msgid "Insert the terms and conditions for processing personal data" +msgstr "Inserte las condiciones para el tratamiento de datos personales" + +msgid "To activate the loyalty program it is necessary to activate the 'enable use of coupons option'" +msgstr "Para activar el programa de fidelización es necesario activar la opción 'habilitar uso de cupones'." + msgid "Uploading services" msgstr "Descarga de servicios" diff --git a/resources/pot/retailcrm-ru_RU.pot b/resources/pot/retailcrm-ru_RU.pot index b353e9a..f19b664 100644 --- a/resources/pot/retailcrm-ru_RU.pot +++ b/resources/pot/retailcrm-ru_RU.pot @@ -454,6 +454,111 @@ msgstr "Требуется API ключ с доступом к одному ма msgid "The currency of the site differs from the currency of the store in CRM. For the integration to work correctly, the currencies in CRM and CMS must match" msgstr "Валюта сайта отличается от валюты магазина в CRM. Для корректной работы интеграции, валюты в CRM и CMS должны совпадать" +msgid "Loyalty program" +msgstr "Программа лояльности" + +msgid "Activate program loyalty" +msgstr "Активировать программу лояльности" + +msgid "Enable this setting for activate program loyalty on site" +msgstr "Активируйте эту настройку для активации программы лояльности на сайте" + +msgid "Terms of loyalty program" +msgstr "Условия программы лояльности" + +msgid "Insert the terms and conditions of the loyalty program" +msgstr "Вставьте условия участия в программе лояльности" + +msgid "Conditions of personal data processing" +msgstr "Условия обработки персональных данных" + +msgid "Insert the terms and conditions for processing personal data" +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%% скидка" + msgid "Uploading services" msgstr "Выгрузка услуг" 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/assets/js/retailcrm-loyalty.js b/src/assets/js/retailcrm-loyalty.js new file mode 100644 index 0000000..c043d51 --- /dev/null +++ b/src/assets/js/retailcrm-loyalty.js @@ -0,0 +1,36 @@ +jQuery(function() { + if (jQuery('#woocommerce_integration-retailcrm_loyalty').is(':checked')) { + checkActiveCoupon(); + } + + jQuery('#woocommerce_integration-retailcrm_loyalty').change(function () { + if (this.checked) { + checkActiveCoupon(); + } + }) + + function checkActiveCoupon() + { + jQuery.ajax({ + url: AdminUrl.url + '/admin-ajax.php?action=get_status_coupon', + method: 'POST', + timeout: 0, + data: {ajax: 1}, + dataType: 'json' + }) + .done(function (response) { + if (response.coupon_status !== 'yes') { + var checkElement = jQuery('#woocommerce_integration-retailcrm_loyalty'); + checkElement.parent().css('color', 'red'); + checkElement.css('border-color', 'red'); + checkElement.prop('checked', false); + + if (!jQuery('#coupon_warning').length) { + checkElement.parent().parent().append( + "

" + response.translate.coupon_warning + "

" + ); + } + } + }) + } +}); diff --git a/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php b/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php index ba8bbef..9adf83b 100644 --- a/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php +++ b/src/include/abstracts/class-wc-retailcrm-abstracts-settings.php @@ -117,6 +117,7 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration $this->form_fields['online_assistant'] = [ 'title' => __('Online assistant', 'retailcrm'), + 'css' => 'width:400px; height:215px; resize: horizontal;', 'type' => 'textarea', 'id' => 'online_assistant', 'placeholder' => __('Insert the Online consultant code here', 'retailcrm') @@ -593,6 +594,41 @@ abstract class WC_Retailcrm_Abstracts_Settings extends WC_Integration 'description' => __('WhatsApp chat will be opened with this contact', 'retailcrm') ]; + /** + * Loyalty Program + */ + + $this->form_fields[] = [ + 'title' => __('Loyalty program', 'retailcrm'), + 'type' => 'heading', + 'description' => '', + 'id' => 'loyalty_options' + ]; + + $this->form_fields['loyalty'] = [ + 'label' => __('Activate program loyalty', 'retailcrm'), + 'title' => __('Loyalty program', 'retailcrm'), + 'class' => 'checkbox', + 'type' => 'checkbox', + 'description' => __('Enable this setting for activate program loyalty on site', 'retailcrm') + ]; + + $this->form_fields['loyalty_terms'] = [ + 'title' => __('Terms of loyalty program', 'retailcrm'), + 'css' => 'width:400px; height:215px; resize: horizontal;', + 'type' => 'textarea', + 'id' => 'loyalty_terms', + 'placeholder' => __('Insert the terms and conditions of the loyalty program', 'retailcrm') + ]; + + $this->form_fields['loyalty_personal'] = [ + 'title' => __('Conditions of personal data processing', 'retailcrm'), + 'css' => 'width:400px; height:215px; resize: horizontal;', + 'type' => 'textarea', + 'id' => 'loyalty_personal', + 'placeholder' => __('Insert the terms and conditions for processing personal data', 'retailcrm') + ]; + /** * Generate icml file */ diff --git a/src/include/api/class-wc-retailcrm-client-v5.php b/src/include/api/class-wc-retailcrm-client-v5.php index 449125f..485db22 100644 --- a/src/include/api/class-wc-retailcrm-client-v5.php +++ b/src/include/api/class-wc-retailcrm-client-v5.php @@ -169,17 +169,7 @@ class WC_Retailcrm_Client_V5 */ public function customersCorporateList(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/customers-corporate', @@ -273,17 +263,7 @@ class WC_Retailcrm_Client_V5 */ public function customersCorporateNotesList(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/customers-corporate/notes', @@ -421,17 +401,8 @@ class WC_Retailcrm_Client_V5 ) { $this->checkIdParameter($by); - $parameters = ['by' => $by]; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); + $parameters['by'] = $by; return $this->client->makeRequest( "/customers-corporate/$id/addresses", @@ -537,17 +508,8 @@ class WC_Retailcrm_Client_V5 ) { $this->checkIdParameter($by); - $parameters = ['by' => $by]; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); + $parameters['by'] = $by; return $this->client->makeRequest( "/customers-corporate/$id/companies", @@ -640,17 +602,8 @@ class WC_Retailcrm_Client_V5 ) { $this->checkIdParameter($by); - $parameters = ['by' => $by]; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); + $parameters['by'] = $by; return $this->client->makeRequest( "/customers-corporate/$id/contacts", @@ -769,17 +722,7 @@ class WC_Retailcrm_Client_V5 */ public function usersList(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/users', @@ -840,17 +783,7 @@ class WC_Retailcrm_Client_V5 */ public function segmentsList(array $filter = [], $limit = null, $page = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/segments', @@ -870,17 +803,7 @@ class WC_Retailcrm_Client_V5 */ public function customFieldsList(array $filter = [], $limit = null, $page = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/custom-fields', @@ -994,17 +917,7 @@ class WC_Retailcrm_Client_V5 */ public function customDictionariesList(array $filter = [], $limit = null, $page = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/custom-fields/dictionaries', @@ -1101,17 +1014,7 @@ class WC_Retailcrm_Client_V5 */ public function ordersList(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/orders', @@ -1445,17 +1348,7 @@ class WC_Retailcrm_Client_V5 */ public function customersList(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/customers', @@ -1666,16 +1559,8 @@ class WC_Retailcrm_Client_V5 */ public function customersNotesList(array $filter = [], $page = null, $limit = null) { - $parameters = []; - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); + return $this->client->makeRequest( '/customers/notes', WC_Retailcrm_Request::METHOD_GET, @@ -1748,17 +1633,7 @@ class WC_Retailcrm_Client_V5 */ public function ordersPacksList(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/orders/packs', @@ -1899,17 +1774,7 @@ class WC_Retailcrm_Client_V5 */ public function tasksList(array $filter = [], $limit = null, $page = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/tasks', @@ -2008,17 +1873,7 @@ class WC_Retailcrm_Client_V5 */ public function storeProductsGroups(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/store/product-groups', @@ -2042,17 +1897,7 @@ class WC_Retailcrm_Client_V5 */ public function storeInventories(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/store/inventories', @@ -2180,17 +2025,7 @@ class WC_Retailcrm_Client_V5 */ public function storeProducts(array $filter = [], $page = null, $limit = null) { - $parameters = []; - - if (count($filter)) { - $parameters['filter'] = $filter; - } - if (null !== $page) { - $parameters['page'] = (int) $page; - } - if (null !== $limit) { - $parameters['limit'] = (int) $limit; - } + $parameters = $this->buildParameters($filter, $page, $limit); return $this->client->makeRequest( '/store/products', @@ -3008,6 +2843,183 @@ class WC_Retailcrm_Client_V5 ); } + /** Loyalty program */ + + /** Customer registration in the loyalty program */ + public function createLoyaltyAccount(array $parameters, $site = null) + { + if ([] === $parameters) { + throw new InvalidArgumentException( + 'Parameter `parameters` must contains a data' + ); + } + + return $this->client->makeRequest( + '/loyalty/account/create', + WC_Retailcrm_Request::METHOD_POST, + $this->fillSite($site, ['loyaltyAccount' => json_encode($parameters)]) + ); + } + + /** Receiving information about participation in the loyalty program */ + public function getLoyaltyClientInfo(int $clientIdLoyalty) + { + return $this->client->makeRequest( + "/loyalty/account/$clientIdLoyalty", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** Activation of participation in the loyalty program */ + public function activateLoyaltyAccount(int $clientIdLoyalty) + { + return $this->client->makeRequest( + "/loyalty/account/$clientIdLoyalty/activate", + WC_Retailcrm_Request::METHOD_POST + ); + } + + /** Editing participation in the loyalty program */ + public function editLoyaltyAccount(int $clientIdLoyalty, array $parameters) + { + return $this->client->makeRequest( + "/loyalty/account/$clientIdLoyalty/edit", + WC_Retailcrm_Request::METHOD_POST, + ['id' => $clientIdLoyalty, 'loyaltyAccount' => json_encode($parameters)] + ); + } + + /** List of participation in the loyalty program */ + public function getLoyaltyAccountList(array $filter = [], $limit = null, $page = null) + { + $parameters = $this->buildParameters($filter, $limit, $page); + + return $this->client->makeRequest( + '/loyalty/accounts', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** List of loyalty programs */ + public function getListLoyalty(array $filter = [], $limit = null, $page = null) + { + $parameters = $this->buildParameters($filter, $limit, $page); + + return $this->client->makeRequest( + '/loyalty/loyalties', + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** Receiving information about the loyalty program */ + public function getLoyalty(int $idLoyalty) + { + return $this->client->makeRequest( + "/loyalty/loyalties/$idLoyalty", + WC_Retailcrm_Request::METHOD_GET + ); + } + + /** Charge bonus */ + public function chargeBonusLoyalty(int $clientIdLoyalty, float $amount, string $comment = '') + { + return $this->client->makeRequest( + "/loyalty/account/$clientIdLoyalty/bonus/charge", + WC_Retailcrm_Request::METHOD_POST, + ['amount' => $amount, 'comment' => $comment] + ); + } + + public function creditBonusLoyalty(int $clientIdLoyalty, array $parameters) + { + if (!isset($parameters['amount'])) { + throw new InvalidArgumentException( + 'Parameter `amount` does not exist' + ); + } + + return $this->client->makeRequest( + "/loyalty/account/$clientIdLoyalty/bonus/credit", + WC_Retailcrm_Request::METHOD_POST, + $parameters + ); + } + + /** History of the client's bonus account */ + public function getClientBonusHistory(int $clientIdLoyalty, array $filter = [], $limit = null, $page = null) + { + $parameters = $this->buildParameters($filter, $limit, $page); + $parameters['id'] = $clientIdLoyalty; + + return $this->client->makeRequest( + "/loyalty/account/$clientIdLoyalty/bonus/operations", + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + public function getDetailClientBonus( + int $clientIdLoyalty, + string $status, + array $filter = [], + $limit = null, + $page = null + ) { + $parameters = $this->buildParameters($filter, $limit, $page); + $parameters['id'] = $clientIdLoyalty; + $parameters['status'] = $status; + + return $this->client->makeRequest( + "/loyalty/account/$clientIdLoyalty/bonus/$status/details", + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** Bonus account history for all participants */ + public function getBonusHistory(string $cursor, array $filter = [], $limit = null) + { + $parameters = $this->buildParameters($filter, $limit); + $parameters['cursor'] = $cursor; + + return $this->client->makeRequest( + "/loyalty/bonus/operations", + WC_Retailcrm_Request::METHOD_GET, + $parameters + ); + } + + /** Maximum discount calculation */ + public function calculateDiscountLoyalty(string $site, array $order, float $bonuses) + { + return $this->client->makeRequest( + "/loyalty/calculate", + WC_Retailcrm_Request::METHOD_POST, + ['site' => $site, 'order' => json_encode($order), 'bonuses' => $bonuses] + ); + } + + /** Application of bonuses under the loyalty program */ + public function applyBonusToOrder(string $site, array $order, float $bonuses) + { + return $this->client->makeRequest( + "/orders/loyalty/apply", + WC_Retailcrm_Request::METHOD_POST, + ['site' => $site, 'order' => json_encode($order), 'bonuses' => $bonuses] + ); + } + + public function cancelBonusOrder(string $site, array $order) + { + return $this->client->makeRequest( + "/orders/loyalty/cancel-bonus-operations", + WC_Retailcrm_Request::METHOD_POST, + ['site' => $site, 'order' => json_encode($order)] + ); + } + /** * Update CRM basic statistic * @@ -3121,4 +3133,23 @@ class WC_Retailcrm_Client_V5 return $params; } + + protected function buildParameters(array $filter = [], $limit = null, $page = null): array + { + $parameters = []; + + if (count($filter)) { + $parameters['filter'] = $filter; + } + + if (isset($page)) { + $parameters['page'] = (int) $page; + } + + if (isset($limit)) { + $parameters['limit'] = (int) $limit; + } + + return $parameters; + } } diff --git a/src/include/class-wc-retailcrm-base.php b/src/include/class-wc-retailcrm-base.php index 707d1c2..f7d29f5 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. * @@ -86,6 +89,7 @@ if (!class_exists('WC_Retailcrm_Base')) { add_action('wp_ajax_generate_icml', [$this, 'generate_icml']); add_action('wp_ajax_upload_selected_orders', [$this, 'upload_selected_orders']); add_action('wp_ajax_clear_cron_tasks', [$this, 'clear_cron_tasks']); + add_action('wp_ajax_get_status_coupon', [$this, 'get_status_coupon']); add_action('admin_print_footer_scripts', [$this, 'ajax_generate_icml'], 99); add_action('woocommerce_update_customer', [$this, 'update_customer'], 10, 1); add_action('user_register', [$this, 'create_customer'], 10, 2); @@ -99,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); @@ -127,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']); @@ -607,6 +622,64 @@ if (!class_exists('WC_Retailcrm_Base')) { $this->include_js_scripts_for_admin(); } + public function get_status_coupon() + { + echo json_encode( + [ + 'coupon_status' => get_option('woocommerce_enable_coupons'), + 'translate' => [ + 'coupon_warning' => __( + "To activate the loyalty program it is necessary to activate the 'enable use of coupons option'", + 'retailcrm' + ) + ] + ]); + + 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 * @@ -645,9 +718,10 @@ if (!class_exists('WC_Retailcrm_Base')) { 'retailcrm-cron-info', 'retailcrm-meta-fields', 'retailcrm-module-settings', + 'retailcrm-loyalty' ]; - $wpAdminUrl = ['url' => get_admin_url()]; + $wpAdminUrl = ['url' => get_admin_url()]; $jsScriptsPath = plugins_url() . '/woo-retailcrm/assets/js/'; foreach ($jsScripts as $scriptName) { @@ -803,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-es_ES.mo b/src/languages/retailcrm-es_ES.mo index 3b176fa7e3896dce16b8ba6d7e623916cdaae174..d0b0ad65c37a3ddb0253207f16b12647b1c22ea4 100644 GIT binary patch delta 4288 zcma*pe{5Cd9mny9wv?6@O8HS*VDpsG77Dbbb_J9If^-&X`C%z`%O2r%puO_81oxEozD*?Z;~++Fdr+h7$@RVEW|Zf zfE%$0x8oGtfn_)x+#kVG&Y#7(_&P2(CT-4gFq;ddll=!8@H)<0Q4RIu2HcIR_${1) z@8ftpA6&nPm7HhO3)NSRx!8;}VOnu2ZV%3*IE(hpFb6ZaaSS!+AESDB3f17psFC~) zXW;}c7UNu02OE&K%_=O%w%~po)scO;7Qc^-*!%&P;T$SiMEhnd2QKczg?Jv7@>06H z2rXQLt*DMXf^GOCRL3tPb(-R7{z&H{eKmF1jH^-iA4E;r6T$uGFs%w+4lcZdt(^ZB zt8w9UWA4HZya``HRd^YB#H?l>H1c-T^C8p}9L5#+GB)Bx)bk5UjH$sU)W9Moi z&V_nBjq3T|QFHbgs=`V1QX^cAybJ$bA| zJzrKz{#!U$#08~h0FU5))NYtYzVomSRq=9UFs2QeB@;%inE}*u_n{g(7@R+i>d5n0 zi!b3k{3B|h`Ds>^UMNG_G>h>VHse?EEH1`R@GH2G6;*{TsONX0GVu_0;2G2umC$+SF6qYh1Vm)uU|7pNb+>>gJ%XSEEwah}!qfsMK#j zb)*Bes9e+lMo=Ak2KD?&+yAL#avcs4YuP>+>cA}pQwyg&G)|x_4CR9MlQHq zP)|?c7W@b`fhY3=`~|}_YHojpYWOd>82^Q}Sjh@og&nvKN3a+_Mpb+PwHqpUi8f3Zw&6ik zM?OS#_#$fC=B3G#Qr(2SYc}KUxECkj2gpt_ze7F&=2O%Zl+l}|SdFT<8+Cmc*@@<1 zbnpdK{l#^B_pt)i;h&-EPyd<&J@8?0<2-5&e2V#4%*4&a*{F_Oj|I2|^RNr~XL|Y3 zE;)|sz{$Y3k!554ijU!xdjFID9Nw(`|27Bg98-L~f1?34_uKIXycf6PtEiMuCU4WQ z9lwKps0J=z7Eb@VzZPa9A3IZl%$`|;6ETY8aR|$`|I-|(11FI6V&23VcmXw+IZUi} zNfWBVPF#TlsE%gP#`o|xT*|!Y{X_UZp1@q(O=XiYjY|DtoJjj-go6@1fqL-Oz%!_+ z_$6v>e1uAQ?sC6@BAm{71!}5pz;UQ`qLNLx#P^83gi42x3F9q<+8-;LUzN>-Rym8* zt5~B{i4$9hO*)}i#3MQgN_QYj$D8XL@ettQhT824h>6lb-ZIo|tp#Oh(DPWg)b31x- z4+okfzRYGm!LBn&f)#6;h)IM>JE6s>qBU}58RX=N;KIGA#d>FOE;QA#EAt=W!aO2G z93<`{9wJn}OR&DYbx?$r1Pgww=wmZLXgz2VK1#4$yt0ztjYJPoNNDl)5-RCd-?87- z9IXq^n(rL4GRwOoLM^ZzXbA`8#n->kcDK{2PTCpB0?j(}2 zs2#DwcFMMRJme&kZnQVEWO6}PsU1qW19r;MjW5(Qd&-WSbka$rtW=+4rJO{6(z2sr zD-;{6yeF2pqP{OSWLl!vewm)B;-K53>Byp&#nK6+imu^ixF}{DF-=k!hJxmp#+# z4pm(BdS$jg9KRG-0_Z%S~EQM|rRlLssgl=U3QPU&85Ws#+Ddd!44i(Bh<% zN|CW-)ygU-YIjE*Ygf`yZbPwMaWBnrb+~Fpt-aE;XMQ*U8_unc+W}lM8rxlY`foeqI8Hin66lIEU8X1bGba8b+cnRNv1It z_bRgDcES!uo3O6cq~%0)KdE(*xpQ9rcyDgWzn%1_H0X#|;s5STFuh-XpN>;SigCsL zu?7tX%j@%89)AXg9R8gk0rZX$O>Hp70umJ3Y qJ39Lbaxs?IYp#JlyW5SpDLcV3@TMxHRp2CZy#-K{d9iL=&VK-Ef_^#x delta 3276 zcmYk;drZ}39LMo5$0GuYfET=g3UaYPJ&Je33z!~31w|!9@dkJo(?}r9BZ@b)Fv+RS z^bafh!*cU%wN-P&VNxwy>8jOI+j5F4olQ5>6}>;_{AfMndtT4)a-Pfgd7d*`w(MKy zyWYcn#3+Y}c;c+v>=I^%^Ff*0&8!Q~!xUVE5$HqytbvcNcod`XG)AKz`(cao{5lTi z`Yuku$Vjs|nlUexzT7CqLAVXo!3ms=XHX43#NODsJArYi`-wjMh&C^r{R03 zncl^rm`vkqaUQ1Qr`U!5?KTy?a38ZVp58QoWtfLGs1dg!uh>o03?CqETRYCcD5k6D zg-DidHR^dK>ihN1^$DEA^;z_#QF%gTIi~b9%fdaV23wIoi|Q4eaT4nN3{1rm)bn~A zj>k|Fxs1x_L(ITFteXa$i~3#>YM{Q}`52dE{O$qu9s zYeaqV47%_V>e#iSGH?x*@>{4GhOrZs$rxnv)))2MgF0mesEqlxP#I5UH)>a3K>qA& zKD4H77-)d}m2&ODdDw)?+%5bBpP~lz5u;Sr=kb%U^ae^`o#<9ri?+YaX(atlW`@^LS^7XRK{9RDZh!D&~0Q)_Qbj0pZse= ziKvW@z~1z4UMjp}C8#g>P#HLdDfm8Wjjy0Ox`7(dQ&dL@Nx@Aw3U%$pXR#Rdy?Rt; zkD&I}Ma;#1G~&}5mr>b_O*j%e)2n{z#^G4Z#(blsYjM@WX zOxuHFF$Pzm+Ns9zcna>tbXT%y*y4^HgHV8~e!?qaJKWt?j!w z5ijFHbd4~Zjzy?}o`d+@{?d~$mA`QQAJ<|cE(9a`#zgSMIDzT%VPUb zOL88yX051QACeJlZ~$gv7Aub`-pCYHl@l0qL|o1 z^dVFfJ-9#QyNW4nuL@XwfiH@>^ijLYWVi2*C*hOeFc9dKy`dv^-AtnWC{MYQL z6QQF0rcy!wmOvyDDpQGkVil1@Oeb=PSBRcON6}86?OeQooK9QqT#JK*cKH%wFL8hv zOr#U~-8f9BsDEqF2PKMlnb2+?Lj1q%cP?UZ7_prwa_))Y#C)QJSU^M&Dpf?aDp_-L z5@wax1YBQUlTfv`a!tafra_Sh{VkDMA^xFJVJ`p1m|S;LdTfioJ=W97@9pn#`5(o* oL;VAj@V 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 SADf;%WyqZNRQ$^Cv-ux$+HTqa delta 3414 zcmYk-32;qU9LMo<6R{_L&YHPWimj${U*I#aC~GezmNVr!@0-+R}LGx^`oxyw8Eoc}rJ=IevjKV_Ep zm+(3}4Mm4o;#?hLzQefnDz!XEd5V;INzkEj>j$D#NHLvdh;G0kv12H`x^^&(U|Yp^bU zg#5%D!f-t1o}b4U&aYq;?>7&rXs`|FzIqmcYA_8ol0m2+cHnX41d5VjA1zHU@B^a z9^@TnBo4$}_x@pI7R*=f{clmfzk(X*ee~*wVG+jUU;-v%Ax^`+n1#LEE}RE5Pa04<>V>m06*r?ge!3a?*AFjoK_mLxy%7{?On1&Bur3Zp zI%|d_ZJX(+29}^+v=-H|FHr5AM?GJIL+~yt6KM>8D|%3iy*i5g*QfG;3u^cY(gzd5 zQYG6a3AHxTP|x*6y=aJgJ{i@Kd`!V&Ou_@G%zlr0z6LAs9=5`@%xh;n;HA=%N)@)l z2goxfniZ!Ebj5L)kD7v$NFPldR+xSlividhwGA^+85n{}`9xI5SD-Sv4oQY7N18I; z161_jY1Fp6g-Trj`RR$xP;)&Dxn(A!QeKK`=rGQ}(>M|n>6J3L2v6W9RL2G~Y)!!^ zRK}(v*S%&Q6{V^awVyYjQoa?{kv*tIbObe$8dQgFp`L$;e6vg~7F)(VN4;oayfI^N zC2Dt7qdI&8m7%{dLHj?D&D((sZBQc|j{KPd4%t|a-LM8V(qPi11{S)OVOP#=)S9Wp zBD{);n9V^MD@6TnKXS_)#Z2CBs;KCL62{8Wc8bM#9E9rFEbN2ZF$1em83^Tj+#BOi z4NpXxG6kp?Zbkk66tb+$9gM>Ow%llJjox@Fi>dU(3fzd-u>kW}k(2N;?#IsU{a>_; zs27IPdJjy%c{mzMV^sU`?9s89iGy)R3i+p#=B9h0 z9^D_r`3O|XcVjVLL#E&4FwwKI5Y>?ytF|=q7gJD)ZlVrAfZN8 zM*8t>IkN0qH%r`W`jWOK>Jd8$n^0No$MaOA@96(Vs;Y-IP8No5FM)4D-o&xQXkDO8BeoK2i8;h% zLV49HQl6uTend+(xrj;*p`!J@g;+`C5-Nd&Ht-rklclApGJ+UIv?pQ-a_{?6yn`wQ zgjUBJ#6}{K7)-D>%oM_37*am9QumY<=KC+MS!MP5K1uE^AALENy>ww4b?vbiMaxzt z*^hY-$GCN&jr=yjRy3@3GhQj}Ps}7#<`aCmd}STS7`I-G-H0OhJPx(VUz9>BLBv!d z(!JQ)wFfpLJj7h0oCqd15Hn|UP{}63d^P{3TSh&Vm`EfMjR}=jetgI695=soK7jf- z;w|^uP@F{A6-`ds`$CV|o5D8Pp6~(ok#NUZ91&(YXPSB}yLIGrr&HAV0DD% + * @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/loyalty/test-wc-retailcrm-client-v5.php b/tests/loyalty/test-wc-retailcrm-client-v5.php new file mode 100644 index 0000000..967ed1d --- /dev/null +++ b/tests/loyalty/test-wc-retailcrm-client-v5.php @@ -0,0 +1,131 @@ + + * @license http://retailcrm.ru Proprietary + * @link http://retailcrm.ru + * @see http://help.retailcrm.ru + */ + +class WC_Retailcrm_Loyalty_Client_Test extends WC_Retailcrm_Test_Case_Helper +{ + protected $responseMock; + protected $apiMock; + + /** @var \WC_Retailcrm_Client_V5 */ + protected $clientMock; + + 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_Request') + ->disableOriginalConstructor() + ->setMethods(['makeRequest']) + ->getMock() + ; + + $this->setMockResponse($this->apiMock, 'makeRequest', $this->responseMock); + + $this->clientMock = new \WC_Retailcrm_Client_V5('https://test@retailcrm.ru', 'test', 'test'); + + $reflection = new ReflectionClass($this->clientMock); + $reflection_property = $reflection->getProperty('client'); + $reflection_property->setAccessible(true); + + $reflection_property->setValue($this->clientMock, $this->apiMock); + } + + /** + * @dataProvider requestLoyaltyData + */ + public function testLoyaltyRequest($method, $parameters) + { + /** @var WC_Retailcrm_Response $test */ + $test = call_user_func([$this->clientMock, $method], ...$parameters); + + $this->assertTrue($test->isSuccessful()); + } + + public function requestLoyaltyData() + { + return [ + [ + 'method' => 'createLoyaltyAccount', + 'parameters' => [['test'], 'testSite'] + ], + [ + 'method' => 'getLoyaltyClientInfo', + 'parameters' => [1] + ], + [ + 'method' => 'activateLoyaltyAccount', + 'parameters' => [1] + ], + [ + 'method' => 'editLoyaltyAccount', + 'parameters' => [1, ['test']] + ], + [ + 'method' => 'getLoyaltyAccountList', + 'parameters' => [['filter'], 20, 1] + ], + [ + 'method' => 'getListLoyalty', + 'parameters' => [['filter'], 20, 1] + ], + [ + 'method' => 'getLoyalty', + 'parameters' => [1] + ], + [ + 'method' => 'chargeBonusLoyalty', + 'parameters' => [1, 100, 'test'] + ], + [ + 'method' => 'creditBonusLoyalty', + 'parameters' => [1, ['amount' => 100]] + ], + [ + 'method' => 'getClientBonusHistory', + 'parameters' => [1, ['filter'], 20, 1] + ], + [ + 'method' => 'getDetailClientBonus', + 'parameters' => [1, 'status', ['filter'], 20, 1] + ], + [ + 'method' => 'getBonusHistory', + 'parameters' => ['cursor', ['filter'], 20] + ], + [ + 'method' => 'calculateDiscountLoyalty', + 'parameters' => ['site', ['order'], 100] + ], + [ + 'method' => 'applyBonusToOrder', + 'parameters' => ['site', ['order'], 100] + ], + [ + 'method' => 'cancelBonusOrder', + 'parameters' => ['site', ['order']] + ], + ]; + } +} 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(); + } +}