diff --git a/resources/pot/retailcrm-es_ES.pot b/resources/pot/retailcrm-es_ES.pot index b794686..356d5f0 100644 --- a/resources/pot/retailcrm-es_ES.pot +++ b/resources/pot/retailcrm-es_ES.pot @@ -449,31 +449,112 @@ msgid "Loyalty program" msgstr "Programa de fidelización" msgid "Activate program loyalty" -msgstr "Activar el programa de fidelización" +msgstr "Activar 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" +msgstr "Activa esta configuración para activar programa de fidelización en la página web" msgid "Terms of loyalty program" -msgstr "Condiciones del programa de fidelidad" +msgstr "Condiciones del programa de fidelización" msgid "Insert the terms and conditions of the loyalty program" -msgstr "Inserte las condiciones de participación en el programa de fidelidad" +msgstr "Introduce las condiciones del programa de fidelización" msgid "Conditions of personal data processing" -msgstr "Condiciones del tratamiento de datos personales" +msgstr "Condiciones de procesamiento de datos personales" msgid "Insert the terms and conditions for processing personal data" -msgstr "Inserte las condiciones para el tratamiento de datos personales" +msgstr "Introduce las condiciones para el procesamiento 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'." +msgstr "Para activar el programa de fidelización es necesario activar la opción 'habilitar el uso de cupones'" + +msgid "Bonus account" +msgstr "Cuenta de bonos" + +msgid "Participation ID: " +msgstr "ID de participación: " + +msgid "Current level: " +msgstr "Nivel actual: " + +msgid "Bonuses on the account: " +msgstr "Bonos en la cuenta: " + +msgid "Bonus card number: " +msgstr "Número de tarjeta de bonos: " + +msgid "Date of registration: " +msgstr "Fecha de registro: " + +msgid "Current level rules" +msgstr "Reglas del nivel actual" + +msgid "Required amount of purchases to move to the next level: " +msgstr "Cantidad de compras necesarias para pasar al siguiente nivel: " + +msgid "Activate participation in the loyalty program" +msgstr "Activar participación en el programa de fidelización" + +msgid "Send" +msgstr "Enviar" + +msgid "To register in the loyalty program, fill in the form:" +msgstr "Para registrarse en el programa de fidelización, rellena el formulario:" + +msgid " I agree with " +msgstr " Estoy de acuerdo con " + +msgid "loyalty program terms" +msgstr "términos del programa de fidelización" + +msgid "terms of personal data processing" +msgstr "términos de procesamiento de datos personales" + +msgid "Phone" +msgstr "Teléfono" + +msgid "Error while registering in the loyalty program. Try again later" +msgstr "Error al registrarse en el programa de fidelización. Inténtalo de nuevo más tarde" + +msgid "The card is not linked" +msgstr "La tarjeta no está vinculada" + +msgid "Error while retrieving data. Try again later" +msgstr "Error al recuperar los datos. Inténtalo de nuevo más tarde" + +msgid "Error when activating the loyalty program. Try again later" +msgstr "Error al activar el programa de fidelización. Inténtalo de nuevo más tarde" + +msgid "Enter the correct phone number" +msgstr "Introduce el número de teléfono correcto" + +msgid "Close" +msgstr "Cerrar" + +msgid "Ordinary products: accrual of 1 bonus for each %s %s" +msgstr "Productos ordinarios: acumulación de 1 bono por cada %s %s" + +msgid "Promotional products: accrual of 1 bonus for each %s %s" +msgstr "Productos promocionales: acumulación de 1 bono por cada %s %s" + +msgid "Ordinary products: bonus accrual in the amount of %s%% of the purchase amount" +msgstr "Productos ordinarios: acumulación de bonos en la cantidad de %s%% de la suma de la compra" + +msgid "Promotional products: bonus accrual in the amount of %s%% of the purchase amount" +msgstr "Productos promocionales: acumulación de bonos en la cantidad de %s%% de la suma de la compra" + +msgid "Ordinary products: %s%% discount" +msgstr "Productos ordinarios: %s%% de descuento" + +msgid "Promotional products: %s%% discount" +msgstr "Productos promocionales: %s%% de descuento" msgid "Uploading services" -msgstr "Descarga de servicios" +msgstr "Subida 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" +msgstr "Los productos con la opción 'virtual' activada se subirán a Simla como servicios" msgid "User not found in the system" msgstr "Usuario no encontrado en el sistema" @@ -482,19 +563,28 @@ 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" +msgstr "No se detectó la participación activa en el programa de fidelización" msgid "No bonuses for debiting" -msgstr "Sin bonificaciones por adeudo" +msgstr "No hay bonos para debitar" 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" +msgstr "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" + +msgid "It is possible to write off" +msgstr "Es posible debitar" + +msgid "bonuses" +msgstr "bonos" + +msgid "Use coupon:" +msgstr "Utiliza el cupón:" diff --git a/resources/pot/retailcrm-ru_RU.pot b/resources/pot/retailcrm-ru_RU.pot index d75fdfc..193c76e 100644 --- a/resources/pot/retailcrm-ru_RU.pot +++ b/resources/pot/retailcrm-ru_RU.pot @@ -572,10 +572,10 @@ msgid "Error when searching for participation in loyalty programs" msgstr "Ошибка при поиске участия в программах лояльности" msgid "No active participation in the loyalty program was detected" -msgstr "Активного участия в программе лояльности не обнаружено" +msgstr "Не обнаружено активного участия в программе лояльности" msgid "No bonuses for debiting" -msgstr "Бонусы на списание отсутствуют" +msgstr "Нет бонусов для списания" msgid "Loyalty program not found" msgstr "Программа лояльности не найдена" @@ -588,3 +588,12 @@ msgstr "Программа лояльности заблокирована" msgid "This user is a corporate person" msgstr "Данный пользователь является корпоратиным лицом" + +msgid "It is possible to write off" +msgstr "Возможно списать" + +msgid "bonuses" +msgstr "бонусов" + +msgid "Use coupon:" +msgstr "Используйте купон:" diff --git a/src/include/api/class-wc-retailcrm-client-v5.php b/src/include/api/class-wc-retailcrm-client-v5.php index 485db22..35b75b1 100644 --- a/src/include/api/class-wc-retailcrm-client-v5.php +++ b/src/include/api/class-wc-retailcrm-client-v5.php @@ -2992,12 +2992,12 @@ class WC_Retailcrm_Client_V5 } /** Maximum discount calculation */ - public function calculateDiscountLoyalty(string $site, array $order, float $bonuses) + public function calculateDiscountLoyalty(string $site, array $order) { return $this->client->makeRequest( "/loyalty/calculate", WC_Retailcrm_Request::METHOD_POST, - ['site' => $site, 'order' => json_encode($order), 'bonuses' => $bonuses] + ['site' => $site, 'order' => json_encode($order)] ); } diff --git a/src/include/class-wc-retailcrm-base.php b/src/include/class-wc-retailcrm-base.php index f7d29f5..710a813 100644 --- a/src/include/class-wc-retailcrm-base.php +++ b/src/include/class-wc-retailcrm-base.php @@ -104,12 +104,22 @@ if (!class_exists('WC_Retailcrm_Base')) { add_action('woocommerce_new_order', [$this, 'create_order'], 11, 1); - if (isset($this->settings['loyalty']) && $this->settings['loyalty'] === static::YES) { + if (isLoyaltyActivate($this->settings)) { 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); + + // Add coupon hooks for loyalty program + add_action('woocommerce_cart_coupon', [$this, 'coupon_info'], 11, 1); + //Remove coupons when cart changes + add_action('woocommerce_add_to_cart', [$this, 'refresh_loyalty_coupon'], 11, 1); + add_action('woocommerce_after_cart_item_quantity_update', [$this, 'refresh_loyalty_coupon'], 11, 1); + add_action('woocommerce_cart_item_removed', [$this, 'refresh_loyalty_coupon'], 11, 1); + add_action('woocommerce_before_cart_empted', [$this, 'clear_loyalty_coupon'], 11, 1); + add_action('woocommerce_removed_coupon', [$this, 'remove_coupon'], 11, 1); + add_action('woocommerce_applied_coupon', [$this, 'apply_coupon'], 11, 1); } // Subscribed hooks @@ -680,6 +690,59 @@ if (!class_exists('WC_Retailcrm_Base')) { wp_die(); } + public function coupon_info() + { + try { + $result = $this->loyalty->createLoyaltyCoupon(); + + if ($result) { + echo $result; + } + } catch (Throwable $exception) { + writeBaseLogs($exception->getMessage()); + } + } + + public function refresh_loyalty_coupon() + { + try { + $this->loyalty->createLoyaltyCoupon(true); + } catch (Throwable $exception) { + writeBaseLogs($exception->getMessage()); + } + } + + public function clear_loyalty_coupon() + { + try { + $this->loyalty->clearLoyaltyCoupon(); + } catch (Throwable $exception) { + writeBaseLogs($exception->getMessage()); + } + } + + public function remove_coupon($couponCode) + { + try { + if (!$this->loyalty->deleteLoyaltyCoupon($couponCode)) { + $this->loyalty->createLoyaltyCoupon(true); + } + } catch (Throwable $exception) { + writeBaseLogs($exception->getMessage()); + } + } + + public function apply_coupon($couponCode) + { + try { + if (!$this->loyalty->isLoyaltyCoupon($couponCode)) { + $this->loyalty->createLoyaltyCoupon(true); + } + } catch (Throwable $exception) { + writeBaseLogs($exception->getMessage()); + } + } + /** * In this method we include CSS file * diff --git a/src/include/class-wc-retailcrm-loyalty.php b/src/include/class-wc-retailcrm-loyalty.php index 936ec3d..c6da194 100644 --- a/src/include/class-wc-retailcrm-loyalty.php +++ b/src/include/class-wc-retailcrm-loyalty.php @@ -27,12 +27,18 @@ if (!class_exists('WC_Retailcrm_Loyalty')) : /** @var WC_Retailcrm_Loyalty_Form */ protected $loyaltyForm; + protected $validator; + 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(); + $this->validator = new WC_Retailcrm_Loyalty_Validator( + $this->apiClient, + isCorporateUserActivate($this->settings) + ); } public function getForm(int $userId) @@ -40,25 +46,13 @@ if (!class_exists('WC_Retailcrm_Loyalty')) : $result = []; try { - $response = $this->apiClient->customersGet($userId); - - if (!isset($response['customer']['id'])) { - return $result; - } - - $filter['customerId'] = $response['customer']['id']; - - $response = $this->apiClient->getLoyaltyAccountList($filter); + $response = $this->getLoyaltyAccounts($userId); } 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) { @@ -116,6 +110,298 @@ if (!class_exists('WC_Retailcrm_Loyalty')) : return false; } } + + private function getDiscountLoyalty($cartItems, $site, $customerId) + { + $order = [ + 'site' => $site, + 'customer' => ['externalId' => $customerId], + 'privilegeType' => 'loyalty_level' + ]; + + $useXmlId = isset($this->settings['bind_by_sku']) && $this->settings['bind_by_sku'] === WC_Retailcrm_Base::YES; + + foreach ($cartItems as $item) { + $product = $item['data']; + + $order['items'][] = [ + 'offer' => $useXmlId ? ['xmlId' => $product->get_sku()] : ['externalId' => $product->get_id()], + 'quantity' => $item['quantity'], + 'initialPrice' => wc_get_price_including_tax($product), + 'discountManualAmount' => ($item['line_subtotal'] - $item['line_total']) / $item['quantity'] + ]; + } + + $response = $this->apiClient->calculateDiscountLoyalty($site, $order); + + if (!$response->isSuccessful() || !isset($response['calculations'])) { + return 0; + } + + $discount = 0; + + //Checking if the loyalty discount is a percent discount + foreach ($response['order']['items'] as $item) { + if (!isset($item['discounts'])) { + continue; + } + + foreach ($item['discounts'] as $discountItem) { + if ($discountItem['type'] === 'loyalty_level') { + $discount += $discountItem['amount']; + } + } + } + + //If the discount has already been given, do not work with points deduction + if ($discount === 0) { + foreach ($response['calculations'] as $calculate) { + if ($calculate['privilegeType'] !== 'loyalty_level') { + continue; + } + + $discount = $calculate['maxChargeBonuses']; + } + } + + return $discount; + } + + private function getLoyaltyAccounts(int $userId) + { + $response = $this->apiClient->customersGet($userId); + + if (!isset($response['customer']['id'])) { + return []; + } + + $filter['customerId'] = $response['customer']['id']; + + $response = $this->apiClient->getLoyaltyAccountList($filter); + + if (!$response->isSuccessful() || !$response->offsetExists('loyaltyAccounts')) { + return null; + } + + return $response; + } + + public function createLoyaltyCoupon($refreshCoupon = false) + { + global $woocommerce; + + $site = $this->apiClient->getSingleSiteForKey(); + $cartItems = $woocommerce->cart->get_cart(); + $customerId = $woocommerce->customer ? $woocommerce->customer->get_id() : null; + + $resultString = ''; + + if (!$customerId || !$cartItems) { + return null; + } + + $couponsLp = []; + // Check exists used loyalty coupons + foreach ($woocommerce->cart->get_coupons() as $code => $coupon) { + if ($this->isLoyaltyCoupon($code)) { + $couponsLp[] = $code; + } + } + + // if you need to refresh coupon that does not exist + if (count($couponsLp) === 0 && $refreshCoupon) { + return null; + } + + //If one loyalty coupon is used, not generate a new one + if (count($couponsLp) === 1 && !$refreshCoupon) { + return null; + } + + // if more than 1 loyalty coupon is used, delete all coupons + if (count($couponsLp) > 1 || $refreshCoupon) { + foreach ($couponsLp as $code) { + $woocommerce->cart->remove_coupon($code); + + $coupon = new WC_Coupon($code); + + $coupon->delete(true); + } + + $woocommerce->cart->calculate_totals(); + } + + if (!$this->validator->checkAccount($customerId)) { + return null; + } + + $lpDiscountSum = $this->getDiscountLoyalty($woocommerce->cart->get_cart(), $site, $customerId); + + if ($lpDiscountSum === 0) { + return null; + } + + //Check the existence of loyalty coupons and delete them + $coupons = $this->getCouponLoyalty($woocommerce->customer->get_email()); + + foreach ($coupons as $item) { + $coupon = new WC_Coupon($item['code']); + + $coupon->delete(true); + } + + //Generate new coupon + $coupon = new WC_Coupon(); + + $coupon->set_usage_limit(0); + $coupon->set_amount($lpDiscountSum); + $coupon->set_email_restrictions($woocommerce->customer->get_email()); + $coupon->set_code('loyalty' . mt_rand()); + $coupon->save(); + + if ($refreshCoupon) { + $woocommerce->cart->apply_coupon($coupon->get_code()); + + return $resultString; + } + + //If a percentage discount, automatically apply a loyalty coupon + if ($this->validator->loyaltyAccount['level']['type'] === 'discount') { + $woocommerce->cart->apply_coupon($coupon->get_code()); + + return $resultString; + } + + $resultString .= '
' . __('It is possible to write off', 'retailcrm') . ' ' . $lpDiscountSum . ' ' . __('bonuses', 'retailcrm') . '
'; + return $resultString. '
' . __('Use coupon:', 'retailcrm') . ' ' . $coupon->get_code() . '
'; + } + + public function clearLoyaltyCoupon() + { + global $woocommerce; + + foreach ($woocommerce->cart->get_coupons() as $code => $coupon) { + if ($this->isLoyaltyCoupon($code)) { + $woocommerce->cart->remove_coupon($code); + + $coupon = new WC_Coupon($code); + + $coupon->delete(true); + } + } + } + + public function deleteLoyaltyCoupon($couponCode) + { + if ($this->isLoyaltyCoupon($couponCode)) { + $coupon = new WC_Coupon($couponCode); + + $coupon->delete(true); + + return true; + } + + return false; + } + + public function isLoyaltyCoupon($couponCode): bool + { + return preg_match('/^loyalty\d+$/m', $couponCode) === 1; + } + + public function getCouponLoyalty($email) + { + global $wpdb; + + return $wpdb->get_results( + $wpdb->prepare( + "SELECT posts.post_name code FROM {$wpdb->prefix}posts AS posts + LEFT JOIN {$wpdb->prefix}postmeta AS postmeta ON posts.ID = postmeta.post_id + WHERE posts.post_type = 'shop_coupon' AND posts.post_name LIKE 'loyalty%' + AND postmeta.meta_key = 'customer_email' AND postmeta.meta_value LIKE %s", + '%' . $email . '%' + ), ARRAY_A + ); + } + + public function deleteLoyaltyCouponInOrder($wcOrder) + { + $discountLp = 0; + $coupons = $wcOrder->get_coupons(); + + foreach ($coupons as $coupon) { + $code = $coupon->get_code(); + + if ($this->isLoyaltyCoupon($code)) { + $discountLp = $coupon->get_discount(); + $wcOrder->remove_coupon($code); + $objectCoupon = new WC_Coupon($code); + $objectCoupon->delete(true); + + $wcOrder->recalculate_coupons(); + break; + } + } + + return $discountLp; + } + + public function isValidOrder($wcUser, $wcOrder) + { + return !(!$wcUser || (isCorporateUserActivate($this->settings) && isCorporateOrder($wcUser, $wcOrder))); + } + + public function applyLoyaltyDiscount($wcOrder, $discountLp, $createdOrder) + { + $isPercentDiscount = false; + $items = []; + + // Verification of automatic creation of the percentage discount of the loyalty program + foreach ($createdOrder['items'] as $item) { + foreach ($item['discounts'] as $discount) { + if ($discount['type'] === 'loyalty_level') { + $isPercentDiscount = true; + $items = $createdOrder['items']; + + break 2; + } + } + } + + if (!$isPercentDiscount) { + $response = $this->apiClient->applyBonusToOrder($createdOrder['site'], ['externalId' => $createdOrder['externalId']], (float) $discountLp); + + if (!$response instanceof WC_Retailcrm_Response || !$response->isSuccessful()) { + return $response->getErrorString(); + } + + $items = $response['order']['items']; + } + + $wcItems = $wcOrder->get_items(); + + foreach ($items as $item) { + $externalId = $item['externalIds'][0]['value']; + $externalId = preg_replace('/^\d+\_/m', '', $externalId); + + if (isset($wcItems[(int) $externalId])) { + $discountLoyaltyTotal = 0; + + foreach ($item['discounts'] as $discount) { + if (in_array($discount['type'], ['bonus_charge', 'loyalty_level'])) { + $discountLoyaltyTotal += $discount['amount']; + } + } + + $wcItem = $wcItems[(int) $externalId]; + $wcItem->set_total($wcItem->get_total() - $discountLoyaltyTotal); + $wcItem->calculate_taxes(); + $wcItem->save(); + } + } + + $wcOrder->calculate_totals(); + } } endif; diff --git a/src/include/class-wc-retailcrm-orders.php b/src/include/class-wc-retailcrm-orders.php index 4b202b3..6bfe6ec 100644 --- a/src/include/class-wc-retailcrm-orders.php +++ b/src/include/class-wc-retailcrm-orders.php @@ -17,6 +17,9 @@ if (!class_exists('WC_Retailcrm_Orders')) : /** @var bool|WC_Retailcrm_Proxy|WC_Retailcrm_Client_V5 */ protected $retailcrm; + /** @var WC_Retailcrm_Loyalty|null */ + protected $loyalty = null; + /** @var array */ protected $retailcrm_settings; @@ -64,6 +67,10 @@ if (!class_exists('WC_Retailcrm_Orders')) : $this->orders = $orders; $this->order_payment = $order_payment; + if (isLoyaltyActivate($retailcrm_settings)) { + $this->loyalty = new WC_Retailcrm_Loyalty($retailcrm, $retailcrm_settings); + } + if (!empty($retailcrm_settings['order-meta-data-retailcrm'])) { $this->customFields = json_decode($retailcrm_settings['order-meta-data-retailcrm'], true); } @@ -87,8 +94,25 @@ if (!class_exists('WC_Retailcrm_Orders')) : $this->order_payment->resetData(); $wcOrder = wc_get_order($orderId); + $privilegeType = 'none'; + + if ($this->loyalty) { + $discountLp = $this->loyalty->deleteLoyaltyCouponInOrder($wcOrder); + $wcUser = $wcOrder->get_user(); + + if (!$this->loyalty->isValidOrder($wcUser, $wcOrder)) { + if ($discountLp > 0) { + writeBaseLogs('The user does not meet the requirements for working with the loyalty program. Order Id: ' . $orderId); + } + + $discountLp = 0; + } else { + $privilegeType = 'loyalty_level'; + } + } $this->processOrder($wcOrder); + $this->order['privilegeType'] = $privilegeType; $response = $this->retailcrm->ordersCreate($this->order); @@ -98,6 +122,10 @@ if (!class_exists('WC_Retailcrm_Orders')) : if (!$response instanceof WC_Retailcrm_Response || !$response->isSuccessful()) { return $response->getErrorString(); } + + if (isset($discountLp) && $discountLp > 0) { + $this->loyalty->applyLoyaltyDiscount($wcOrder, $discountLp, $response['order']); + } } catch (Throwable $exception) { writeBaseLogs( sprintf( diff --git a/src/include/functions.php b/src/include/functions.php index 4f82f5b..b1afd25 100644 --- a/src/include/functions.php +++ b/src/include/functions.php @@ -202,3 +202,18 @@ function useHpos() return class_exists(Automattic\WooCommerce\Utilities\OrderUtil::class) && Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled(); } + +function isLoyaltyActivate($settings) +{ + return isset($settings['loyalty']) && $settings['loyalty'] === WC_Retailcrm_Base::YES; +} + +function isCorporateUserActivate($settings) +{ + return isset($settings['corporate_enabled']) && $settings['corporate_enabled'] === WC_Retailcrm_Base::YES; +} + +function isCorporateOrder($wcUser, $wcOrder) +{ + return !empty($wcUser->get_billing_company()) || !empty($wcOrder->get_billing_company()); +} 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 index 6c46155..2e08d09 100644 --- a/src/include/validators/loyalty-validator/class-wc-retailcrm-loyalty-validator.php +++ b/src/include/validators/loyalty-validator/class-wc-retailcrm-loyalty-validator.php @@ -16,10 +16,13 @@ if (!class_exists('WC_Retailcrm_Loyalty_Validator')) : { /** @var WC_Retailcrm_Client_V5 */ protected $apiClient; - protected $crmUser; - protected $loyaltyAccount; + protected $isActiveCorp; + public $customer; + + public $loyaltyAccount; + public function __construct($apiClient, $isActiveCorp) { $this->apiClient = $apiClient; @@ -30,7 +33,7 @@ if (!class_exists('WC_Retailcrm_Loyalty_Validator')) : { try { $this->checkUser($userId); - $this->checkLoyaltyAccount($this->crmUser['id']); + $this->checkLoyaltyAccount($this->customer['id']); $this->checkActiveLoyalty($this->loyaltyAccount['loyalty']['id']); return true; @@ -56,19 +59,19 @@ if (!class_exists('WC_Retailcrm_Loyalty_Validator')) : $customer = new WC_Customer($userId); - if ($this->isActiveCorp && !empty($customer->get_shipping_company())) { + if ($this->isActiveCorp && !empty($customer->get_billing_company())) { throw new ValidatorException($this->isCorporateUser, 400); } - $this->crmUser = $responseUser['customer']; + $this->customer = $responseUser['customer']; } /** * @throws ValidatorException */ - private function checkLoyaltyAccount($crmUserId) + private function checkLoyaltyAccount($customerId) { - $filter['customerId'] = $crmUserId; + $filter['customerId'] = $customerId; $responseLoyalty = $this->apiClient->getLoyaltyAccountList($filter); if (!$responseLoyalty->isSuccessful() || !$responseLoyalty->offsetExists('loyaltyAccounts')) { diff --git a/src/languages/retailcrm-es_ES.l10n.php b/src/languages/retailcrm-es_ES.l10n.php index e3fb869..7a6b3e6 100644 --- a/src/languages/retailcrm-es_ES.l10n.php +++ b/src/languages/retailcrm-es_ES.l10n.php @@ -199,7 +199,54 @@ return [ "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", "Uploading services" => "Descarga de servicios", "Goods with the 'virtual' option enabled will be uploaded to Simla as services" => - "Los bienes con la opción 'virtual' activada se cargarán en Simla como servicios" + "Los bienes con la opción 'virtual' activada se cargarán en Simla como servicios", + "Loyalty program" => "Programa de fidelización", + "Activate program loyalty" => "Activar programa de fidelización", + "Enable this setting for activate program loyalty on site" => "Activa esta configuración para activar el programa de fidelización en la página web", + "Terms of loyalty program" => "Condiciones del programa de fidelización", + "Insert the terms and conditions of the loyalty program" => "Inserte las condiciones del programa de fidelización", + "Conditions of personal data processing" => "Condiciones de procesamiento de datos personales", + "Insert the terms and conditions for processing personal data" => "Inserte las condiciones para el procesamiento de datos personales", + "To activate the loyalty program it is necessary to activate the 'enable use of coupons option'" => + "Para activar el programa de fidelización es necesario activar la opción 'habilitar el uso de cupones'", + "Bonus account" => "Cuenta de bonificación", + "Participation ID: " => "ID de participación: ", + "Current level: " => "Nivel actual: ", + "Bonuses on the account: " => "Bonificaciones en la cuenta: ", + "Bonus card number: " => "Número de tarjeta de bonificación: ", + "Date of registration: " => "Fecha de registro: ", + "Current level rules" => "Reglas del nivel actual", + "Required amount of purchases to move to the next level: " => "Cantidad de compras necesarias para pasar al siguiente nivel: ", + "Activate participation in the loyalty program" => "Activar participación en el programa de fidelización", + "Send" => "Enviar", + "To register in the loyalty program, fill in the form:" => "Para registrarse en el programa de fidelización, rellene el formulario:", + " I agree with " => " Acepto ", + "loyalty program terms" => "términos del programa de fidelización", + "terms of personal data processing" => "términos de procesamiento de datos personales", + "Phone" => "Teléfono", + "Error while registering in the loyalty program. Try again later" => "Error al registrarse en el programa de fidelización. Inténtalo de nuevo más tarde", + "The card is not linked" => "La tarjeta no está vinculada", + "Error while retrieving data. Try again later" => "Error al recuperar los datos. Inténtalo de nuevo más tarde", + "Error when activating the loyalty program. Try again later" => "Error al activar el programa de fidelización. Inténtalo de nuevo más tarde", + "Enter the correct phone number" => "Introduce el número de teléfono correcto", + "Close" => "Cerrar", + "Ordinary products: accrual of 1 bonus for each %s %s" => "Productos ordinarios: acumulación de 1 bonificación por cada %s %s", + "Promotional products: accrual of 1 bonus for each %s %s" => "Productos promocionales: acumulación de 1 bonificación por cada %s %s", + "Ordinary products: bonus accrual in the amount of %s%% of the purchase amount" => "Productos ordinarios: acumulación de bonificación en la cantidad de %s%% del monto de la compra", + "Promotional products: bonus accrual in the amount of %s%% of the purchase amount" => "Productos promocionales: acumulación de bonificación en la cantidad de %s%% del monto de la compra", + "Ordinary products: %s%% discount" => "Productos ordinarios: descuento del %s%%", + "Promotional products: %s%% discount" => "Productos promocionales: descuento del %s%%", + "User not found in the system" => "Usuario no encontrado en el sistema", + "Error when searching for participation in loyalty programs" => "Error al buscar la participación en programas de fidelización", + "No active participation in the loyalty program was detected" => "No se detectó participación activa en el programa de fidelización", + "No bonuses for debiting" => "No hay bonificaciones para debitar", + "Loyalty program not found" => "Programa de fidelización no encontrado", + "Loyalty program is not active" => "El programa de fidelización no está activo", + "Loyalty program blocked" => "Programa de fidelización bloqueado", + "This user is a corporate person" => "Este usuario es una persona jurídica", + "It is possible to write off" => "Es posible debitar", + "bonuses" => "bonificaciones", + "Use coupon:" => "Utiliza el cupón:", ], "language" => "es", "x-generator" => "GlotPress/2.4.0-alpha", diff --git a/src/languages/retailcrm-es_ES.mo b/src/languages/retailcrm-es_ES.mo index 3ba8896..43567c3 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.l10n.php b/src/languages/retailcrm-ru_RU.l10n.php index 857338c..514c7e5 100644 --- a/src/languages/retailcrm-ru_RU.l10n.php +++ b/src/languages/retailcrm-ru_RU.l10n.php @@ -198,7 +198,54 @@ return [ "Валюта сайта отличается от валюты магазина в CRM. Для корректной работы интеграции, валюты в CRM и CMS должны совпадать", "Uploading services" => "Выгрузка услуг", "Goods with the 'virtual' option enabled will be uploaded to Simla as services" => - "Товары с включенной опцией 'виртуальные' будут выгружаться в CRM как услуги" + "Товары с включенной опцией 'виртуальные' будут выгружаться в CRM как услуги", + "Loyalty program" => "Программа лояльности", + "Activate program loyalty" => "Активировать программу лояльности", + "Enable this setting for activate program loyalty on site" => "Активируйте эту настройку для активации программы лояльности на сайте", + "Terms of loyalty program" => "Условия программы лояльности", + "Insert the terms and conditions of the loyalty program" => "Вставьте условия участия в программе лояльности", + "Conditions of personal data processing" => "Условия обработки персональных данных", + "Insert the terms and conditions for processing personal data" => "Вставьте условия обработки персональных данных", + "To activate the loyalty program it is necessary to activate the 'enable use of coupons option'" => + "Для активации программы лояльности необходимо активировать опцию 'включить использование купонов'", + "Bonus account" => "Бонусный счет", + "Participation ID: " => "ID участия: ", + "Current level: " => "Текущий уровень: ", + "Bonuses on the account: " => "Бонусов на счету: ", + "Bonus card number: " => "Номер бонусной карты: ", + "Date of registration: " => "Дата регистрации: ", + "Current level rules" => "Правила текущего уровня", + "Required amount of purchases to move to the next level: " => "Необходимая сумма покупок для перехода на следующий уровень: ", + "Activate participation in the loyalty program" => "Активировать участие в программе лояльности", + "Send" => "Отправить", + "To register in the loyalty program, fill in the form:" => "Для регистрации в программе лояльности заполните форму:", + " I agree with " => " Я согласен с ", + "loyalty program terms" => "условиями программы лояльности", + "terms of personal data processing" => "условиями обработки персональных данных", + "Phone" => "Телефон", + "Error while registering in the loyalty program. Try again later" => "Ошибка при регистрации в программе лояльности. Попробуйте позже", + "The card is not linked" => "Карта не привязана", + "Error while retrieving data. Try again later" => "Ошибка при получении данных. Попробуйте позже", + "Error when activating the loyalty program. Try again later" => "Ошибка при активации программы лояльности. Попробуйте позже", + "Enter the correct phone number" => "Введите корректный номер телефона", + "Close" => "Закрыть", + "Ordinary products: accrual of 1 bonus for each %s %s" => "Обычные товары: начисление 1 бонуса за каждые %s %s", + "Promotional products: accrual of 1 bonus for each %s %s" => "Акционные товары: начисление 1 бонуса за каждые %s %s", + "Ordinary products: bonus accrual in the amount of %s%% of the purchase amount" => "Обычные товары: начисление бонуса в размере %s%% от суммы покупки", + "Promotional products: bonus accrual in the amount of %s%% of the purchase amount" => "Акционные товары: начисление бонуса в размере %s%% от суммы покупки", + "Ordinary products: %s%% discount" => "Обычные товары: скидка %s%%", + "Promotional products: %s%% discount" => "Акционные товары: скидка %s%%", + "User not found in the system" => "Пользователь не найден в системе", + "Error when searching for participation in loyalty programs" => "Ошибка при поиске участия в программах лояльности", + "No active participation in the loyalty program was detected" => "Не обнаружено активного участия в программе лояльности", + "No bonuses for debiting" => "Нет бонусов для списания", + "Loyalty program not found" => "Программа лояльности не найдена", + "Loyalty program is not active" => "Программа лояльности не активна", + "Loyalty program blocked" => "Программа лояльности заблокирована", + "This user is a corporate person" => "Этот пользователь является корпоративным лицом", + "It is possible to write off" => "Возможно списать", + "bonuses" => "бонусов", + "Use coupon:" => "Используйте купон:", ], "language" => "ru", "x-generator" => "GlotPress/2.4.0-alpha", diff --git a/src/languages/retailcrm-ru_RU.mo b/src/languages/retailcrm-ru_RU.mo index 6f819be..acd4ebf 100644 Binary files a/src/languages/retailcrm-ru_RU.mo and b/src/languages/retailcrm-ru_RU.mo differ diff --git a/tests/datasets/data-loyalty-retailcrm.php b/tests/datasets/data-loyalty-retailcrm.php index ec44910..6793410 100644 --- a/tests/datasets/data-loyalty-retailcrm.php +++ b/tests/datasets/data-loyalty-retailcrm.php @@ -1,7 +1,4 @@ ['customer' => ['id' => 1]], 'wcUserType' => 'corp', 'throwMessage' => 'This user is a corporate person', - 'isCorpActive' => true, + 'isCorpActive' => true ], [ 'responseApiMethod' => ['customer' => ['id' => 1]], 'wcUserType' => 'corp', 'throwMessage' => null, - 'isCorpActive' => false, + 'isCorpActive' => false ], [ 'responseApiMethod' => ['customer' => ['id' => 1]], 'wcUserType' => 'individual', 'throwMessage' => null, - 'isCorpActive' => true, + 'isCorpActive' => true ], ]; } @@ -151,4 +148,198 @@ class DataLoyaltyRetailCrm ] ]; } + + public static function createProducts() + { + $product1 = new WC_Product(); + $product1->set_name('Test product 1'); + $product1->set_sku('test1' . mt_rand()); + $product1->set_regular_price('200'); + $product1->set_sale_price('200'); + $product1->save(); + + $product2 = new WC_Product(); + $product2->set_name('Test product 2'); + $product2->set_sku('test2' . mt_rand()); + $product2->set_regular_price('100'); + $product2->set_sale_price('50'); + $product2->save(); + + return [$product1, $product2]; + } + + public static function getDataCalculation() + { + return [ + [ + 'response' => [ + 'calculations' => [], + 'order' => [ + 'items' => [ + [ + 'discounts' => [ + [ + 'type' => 'loyalty_level', + 'amount' => 20 + ], + ] + ], + [ + 'discounts' => [ + [ + 'type' => 'loyalty_level', + 'amount' => 20 + ], + ] + ] + ] + ] + ], + 'expected' => 40 + ], + [ + 'response' => [ + 'calculations' => [ + [ + 'privilegeType' => 'test' + ], + [ + 'privilegeType' => 'loyalty_level', + 'maxChargeBonuses' => 50 + ] + ], + 'order' => [ + 'items' => [['discounts' => null], ['discounts' => null]], + ] + ], + 'expected' => 50 + ] + ]; + } + + public static function dataCheckLoyaltyCoupon() + { + return [ + [ + 'code' => 'loyalty49844894548', + 'expected' => true + ], + [ + 'code' => '56556446548484', + 'expected' => false + ], + [ + 'code' => 'dfhdfh54655pl', + 'expected' => false + ], + [ + 'code' => '654844pl18498', + 'expected' => false + ] + ]; + } + + public static function dataGetEmailsForPersonalCoupon() + { + return [ + [ + 'email' => 'test1@gmail.com', + 'code' => 'loyalty' . mt_rand() + ], + [ + 'email' => 'test2@gmail.com', + 'code' => 'loyalty' . mt_rand() + ], + [ + 'email' => 'test3@gmail.com', + 'expectedCode' => false + ] + ]; + } + + public static function dataValidUser() + { + $users = self::createUsers(); + + return [ + [ + 'customer' => $users[0], + 'corporate_enabled' => 'yes', + 'expected' => true, + 'orderCorporate' => false + ], + [ + 'customer' => $users[1], + 'corporate_enabled' => 'yes', + 'expected' => false, + 'orderCorporate' => false + ], + [ + 'customer' => $users[1], + 'corporate_enabled' => 'no', + 'expected' => true, + 'orderCorporate' => false + ], + [ + 'customer' => null, + 'corporate_enabled' => 'yes', + 'expected' => false, + 'orderCorporate' => false + + ], + [ + 'customer' => $users[0], + 'corporate_enabled' => 'yes', + 'expected' => false, + 'orderCorporate' => true + ] + ]; + } + + public static function createUsers() + { + $customer = new WC_Customer(); + + $customer->set_first_name('Tester 1'); + $customer->set_last_name('Tester 1'); + $customer->set_email(uniqid(md5(date('Y-m-d H:i:s'))) . '@mail.com'); + $customer->set_password('password'); + $customer->set_billing_phone('89000000000'); + $customer->set_date_created(date('Y-m-d H:i:s')); + $customer->save(); + + $customer1 = new WC_Customer(); + + $customer1->set_first_name('Tester 1'); + $customer1->set_last_name('Tester 1'); + $customer1->set_email(uniqid(md5(date('Y-m-d H:i:s'))) . '@mail.com'); + $customer1->set_password('password'); + $customer1->set_billing_phone('89000000000'); + $customer1->set_date_created(date('Y-m-d H:i:s')); + $customer1->set_billing_company('OOO TEST'); + $customer1->save(); + + return [$customer, $customer1]; + } + + public static function createCoupons($email1 = 'test1@gmail.com', $email2 = 'test2@gmail.com') + { + $coupon = new WC_Coupon(); + + $coupon->set_usage_limit(0); + $coupon->set_amount(100); + $coupon->set_email_restrictions($email1); + $coupon->set_code('loyalty' . mt_rand()); + $coupon->save(); + + $coupon1 = new WC_Coupon(); + + $coupon1->set_usage_limit(0); + $coupon1->set_amount(100); + $coupon1->set_email_restrictions($email2); + $coupon1->set_code('loyalty' . mt_rand()); + $coupon1->save(); + + return [$coupon, $coupon1]; + } } diff --git a/tests/loyalty/test-wc-retailcrm-client-v5.php b/tests/loyalty/test-wc-retailcrm-client-v5.php index 967ed1d..9c5ad52 100644 --- a/tests/loyalty/test-wc-retailcrm-client-v5.php +++ b/tests/loyalty/test-wc-retailcrm-client-v5.php @@ -116,7 +116,7 @@ class WC_Retailcrm_Loyalty_Client_Test extends WC_Retailcrm_Test_Case_Helper ], [ 'method' => 'calculateDiscountLoyalty', - 'parameters' => ['site', ['order'], 100] + 'parameters' => ['site', ['order']] ], [ 'method' => 'applyBonusToOrder', diff --git a/tests/test-wc-retailcrm-loyalty.php b/tests/test-wc-retailcrm-loyalty.php index 9e6f653..d0e11b3 100644 --- a/tests/test-wc-retailcrm-loyalty.php +++ b/tests/test-wc-retailcrm-loyalty.php @@ -1,6 +1,6 @@ apiMock = $this->getMockBuilder('\WC_Retailcrm_Client_V5') ->disableOriginalConstructor() - ->setMethods(['customersGet', 'getLoyaltyAccountList', 'createLoyaltyAccount', 'activateLoyaltyAccount']) + ->setMethods(['customersGet', 'getLoyaltyAccountList', 'createLoyaltyAccount', 'activateLoyaltyAccount', 'calculateDiscountLoyalty', 'getSingleSiteForKey', 'applyBonusToOrder']) ->getMock() ; $this->setMockResponse($this->apiMock, 'customersGet', ['customer' => ['id' => 1]]); $this->setMockResponse($this->apiMock, 'createLoyaltyAccount', $this->responseMock); $this->setMockResponse($this->apiMock, 'activateLoyaltyAccount', $this->responseMock); + $this->setMockResponse($this->apiMock, 'getSingleSiteForKey', 'woo'); $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, []); } /** - * @dataProvider responseLoyalty + * @dataProvider DataLoyaltyRetailCrm::getDataLoyalty() */ public function testGetForm($isSuccessful, $body, $expected) { @@ -85,8 +86,409 @@ class WC_Retailcrm_Loyalty_Test extends WC_Retailcrm_Test_Case_Helper $this->assertTrue($result); } - public function responseLoyalty() + /** + * @dataProvider DataLoyaltyRetailCrm::getDataCalculation() + */ + public function testGetDiscountLoyalty($response, $expected) { - return DataLoyaltyRetailCrm::getDataLoyalty(); + $responseMock = new WC_Retailcrm_Response(200, json_encode($response)); + $this->setMockResponse($this->apiMock, 'calculateDiscountLoyalty', $responseMock); + + $cartItems = $this->createCart(); + + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, []); + + $method = $this->getPrivateMethod('getDiscountLoyalty', $this->loyalty); + + $discount = $method->invokeArgs($this->loyalty, [$cartItems, 'test', 1]); + $this->assertEquals($expected, $discount); + + foreach ($cartItems as $items) { + $items['data']->delete(true); + } + } + + /** + * @dataProvider DataLoyaltyRetailCrm::dataCheckLoyaltyCoupon() + */ + public function testIsLoyaltyCoupon($code, $expected) + { + $this->assertEquals($expected, $this->loyalty->isLoyaltyCoupon($code)); + } + + /** + * @dataProvider DataLoyaltyRetailCrm::dataValidUser(); + */ + public function testIsValidOrder($customer, $corporate_enabled, $expected, $orderCorporate) + { + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, ['corporate_enabled' => $corporate_enabled]); + $wcOrder = new WC_Order(); + + if ($orderCorporate) { + $wcOrder->set_billing_company('OOO TEST'); + } + + $this->assertEquals($expected, $this->loyalty->isValidOrder($customer, $wcOrder)); + } + + /** + * @dataProvider DataLoyaltyRetailCrm::dataGetEmailsForPersonalCoupon() + */ + public function testGetCouponLoyalty($email, $code) + { + if ($code) { + $coupon = new WC_Coupon(); + + $coupon->set_usage_limit(0); + $coupon->set_amount(100); + $coupon->set_email_restrictions($email); + $coupon->set_code($code); + $coupon->save(); + } + + $coupons = $this->loyalty->getCouponLoyalty($email); + + if (!$coupons && $code === false) { + $this->assertTrue(true); + } else { + $result = false; + + foreach ($coupons as $item) { + $coupon = new WC_Coupon($item['code']); + $result = true; + + $this->assertTrue($code === $item['code']); + $coupon->delete(true); + } + + $this->assertTrue($result); + } + } + + public function testCreateLoyaltyCouponWithoutAppliedCoupon() + { + $products = DataLoyaltyRetailCrm::createProducts(); + $user = DataLoyaltyRetailcrm::createUsers()[0]; + + $cart = new WC_Cart(); + $cart->add_to_cart($products[0]->get_id()); + $cart->add_to_cart($products[1]->get_id()); + + $woocommerce = wc(); + $woocommerce->cart = $cart; + $woocommerce->customer = $user; + + $validatorMock = $this->getMockBuilder('\WC_Retailcrm_Loyalty_Validator') + ->disableOriginalConstructor() + ->getMock() + ; + $this->setMockResponse($validatorMock, 'checkAccount', true); + $validatorMock->loyaltyAccount['level']['type'] = 'loyalty_level'; + + $responseCalculation = DataLoyaltyRetailCrm::getDataCalculation()[1]; + $responseMock = new WC_Retailcrm_Response(200, json_encode($responseCalculation['response'])); + $this->setMockResponse($this->apiMock, 'calculateDiscountLoyalty', $responseMock); + + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, []); + $reflection = new \ReflectionClass($this->loyalty); + $reflection_property = $reflection->getProperty('validator'); + $reflection_property->setAccessible(true); + $reflection_property->setValue($this->loyalty, $validatorMock); + + $GLOBALS['woocommerce'] = $woocommerce; + $result = $this->loyalty->createLoyaltyCoupon(); + + $this->assertNotEmpty($result); + $this->assertNotEmpty($this->loyalty->getCouponLoyalty($woocommerce->customer->get_email())); + } + + public function testCreateLoyaltyCouponWithPercentDiscount() + { + $products = DataLoyaltyRetailCrm::createProducts(); + $user = DataLoyaltyRetailcrm::createUsers()[0]; + + $cart = new WC_Cart(); + $cart->add_to_cart($products[0]->get_id()); + $cart->add_to_cart($products[1]->get_id()); + + $woocommerce = wc(); + $woocommerce->cart = $cart; + $woocommerce->customer = $user; + + $validatorMock = $this->getMockBuilder('\WC_Retailcrm_Loyalty_Validator') + ->disableOriginalConstructor() + ->getMock() + ; + $this->setMockResponse($validatorMock, 'checkAccount', true); + $validatorMock->loyaltyAccount['level']['type'] = 'discount'; + + $responseCalculation = DataLoyaltyRetailCrm::getDataCalculation()[1]; + $responseMock = new WC_Retailcrm_Response(200, json_encode($responseCalculation['response'])); + $this->setMockResponse($this->apiMock, 'calculateDiscountLoyalty', $responseMock); + + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, []); + $reflection = new \ReflectionClass($this->loyalty); + $reflection_property = $reflection->getProperty('validator'); + $reflection_property->setAccessible(true); + $reflection_property->setValue($this->loyalty, $validatorMock); + + $GLOBALS['woocommerce'] = $woocommerce; + $result = $this->loyalty->createLoyaltyCoupon(); + + $this->assertEmpty($result); + $this->assertNotEmpty($this->loyalty->getCouponLoyalty($woocommerce->customer->get_email())); + $this->assertNotEmpty($woocommerce->cart->get_coupons()); + } + + public function testCreateLoyaltyCouponWithRefreshCoupon() + { + $products = DataLoyaltyRetailCrm::createProducts(); + $user = DataLoyaltyRetailcrm::createUsers()[0]; + + $cart = new WC_Cart(); + $cart->add_to_cart($products[0]->get_id()); + $cart->add_to_cart($products[1]->get_id()); + + $coupon = new WC_Coupon(); + $coupon->set_usage_limit(0); + $coupon->set_amount('50'); + $coupon->set_email_restrictions($user->get_email()); + $coupon->set_code('loyalty' . mt_rand()); + $coupon->save(); + $cart->apply_coupon($coupon->get_code()); + + $couponCode = $coupon->get_code(); + $woocommerce = wc(); + $woocommerce->cart = $cart; + $woocommerce->customer = $user; + + $validatorMock = $this->getMockBuilder('\WC_Retailcrm_Loyalty_Validator') + ->disableOriginalConstructor() + ->getMock() + ; + $this->setMockResponse($validatorMock, 'checkAccount', true); + $validatorMock->loyaltyAccount['level']['type'] = 'discount'; + + $responseCalculation = DataLoyaltyRetailCrm::getDataCalculation()[1]; + $responseMock = new WC_Retailcrm_Response(200, json_encode($responseCalculation['response'])); + $this->setMockResponse($this->apiMock, 'calculateDiscountLoyalty', $responseMock); + + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, []); + $reflection = new \ReflectionClass($this->loyalty); + $reflection_property = $reflection->getProperty('validator'); + $reflection_property->setAccessible(true); + $reflection_property->setValue($this->loyalty, $validatorMock); + + $GLOBALS['woocommerce'] = $woocommerce; + $result = $this->loyalty->createLoyaltyCoupon(true); + + $this->assertEmpty($result); + $this->assertNotEmpty($this->loyalty->getCouponLoyalty($woocommerce->customer->get_email())); + + $coupons = $woocommerce->cart->get_coupons(); + + $this->assertNotEmpty($coupons); + $this->assertFalse(isset($coupons[$couponCode])); + } + + public function testDeleteLoyaltyCouponInOrder() + { + $products = DataLoyaltyRetailCrm::createProducts(); + $user = DataLoyaltyRetailcrm::createUsers()[0]; + + $coupon = new WC_Coupon(); + $coupon->set_usage_limit(0); + $coupon->set_amount('50'); + $coupon->set_email_restrictions($user->get_email()); + $coupon->set_code('loyalty' . mt_rand()); + $coupon->save(); + + $wcOrder = wc_create_order([ + 'status' => null, + 'customer_id' => $user->get_id(), + 'customer_note' => null, + 'parent' => null, + 'created_via' => null, + 'cart_hash' => null, + 'order_id' => 0, + ]); + + $wcOrder->add_product($products[0]); + $wcOrder->add_product($products[1]); + $wcOrder->apply_coupon($coupon->get_code()); + $wcOrder->calculate_totals(); + $wcOrder->save(); + + $this->assertNotEmpty($wcOrder->get_coupons()); + $this->loyalty->deleteLoyaltyCouponInOrder($wcOrder); + $this->assertEmpty($wcOrder->get_coupons()); + + $wcOrder->delete(true); + } + + public function testApplyLoyaltyDiscountWithBonuses() + { + $products = DataLoyaltyRetailCrm::createProducts(); + $user = DataLoyaltyRetailcrm::createUsers()[0]; + + $wcOrder = wc_create_order([ + 'status' => null, + 'customer_id' => $user->get_id(), + 'customer_note' => null, + 'parent' => null, + 'created_via' => null, + 'cart_hash' => null, + 'order_id' => 0, + ]); + + $wcOrder->add_product($products[0]); + $wcOrder->add_product($products[1]); + $wcOrder->calculate_totals(); + $wcOrder->save(); + + foreach ($wcOrder->get_items() as $id => $item) { + $currentItemsPrice[$id] = $item->get_total(); + $itemIds[] = $id; + } + + $createdCrmOrderResponse = ['site' => 'test', 'externalId' => 1, 'items' => [['discounts' => [],], ['discounts' => []]]]; + $response = new WC_Retailcrm_Response( + 200, + json_encode([ + 'order' => [ + 'items' => [ + [ + 'externalIds' => [ + [ + 'value' => '11_' . $itemIds[0] + ] + ], + 'discounts' => [ + [ + 'type' => 'bonus_charge', + 'amount' => 25 + ] + ] + ], + [ + 'externalIds' => [ + [ + 'value' => '22_' . $itemIds[1] + ] + ], + 'discounts' => [ + [ + 'type' => 'bonus_charge', + 'amount' => 25 + ] + ] + ] + ] + ] + ]) + ); + + $this->setMockResponse($this->apiMock, 'applyBonusToOrder', $response); + $this->loyalty = new WC_Retailcrm_Loyalty($this->apiMock, []); + + $this->loyalty->applyLoyaltyDiscount($wcOrder, 50, $createdCrmOrderResponse); + + foreach ($wcOrder->get_items() as $id => $item) { + $this->assertNotEquals($item->get_total(), $currentItemsPrice[$id]); + } + } + + public function testApplyLoyaltyDiscountWithPercentDiscount() + { + $products = DataLoyaltyRetailCrm::createProducts(); + $user = DataLoyaltyRetailcrm::createUsers()[0]; + + $wcOrder = wc_create_order([ + 'status' => null, + 'customer_id' => $user->get_id(), + 'customer_note' => null, + 'parent' => null, + 'created_via' => null, + 'cart_hash' => null, + 'order_id' => 0, + ]); + + $wcOrder->add_product($products[0]); + $wcOrder->add_product($products[1]); + $wcOrder->calculate_totals(); + $wcOrder->save(); + + foreach ($wcOrder->get_items() as $id => $item) { + $currentItemsPrice[$id] = $item->get_total(); + $itemIds[] = $id; + } + + $createdCrmOrderResponse = [ + 'site' => 'test', + 'externalId' => 1, + 'items' => [ + [ + 'externalIds' => [ + [ + 'value' => '11_' . $itemIds[0] + ] + ], + 'discounts' => [ + [ + 'type' => 'loyalty_level', + 'amount' => 25 + ] + ] + ], + [ + 'externalIds' => [ + [ + 'value' => '22_' . $itemIds[1] + ] + ], + 'discounts' => [ + [ + 'type' => 'loyalty_level', + 'amount' => 25 + ] + ] + ] + ] + ]; + + $this->loyalty->applyLoyaltyDiscount($wcOrder, 0, $createdCrmOrderResponse); + + foreach ($wcOrder->get_items() as $id => $item) { + $this->assertNotEquals($item->get_total(), $currentItemsPrice[$id]); + } + } + + private function getPrivateMethod($method, $class) + { + $reflection = new ReflectionClass($class); + $method = $reflection->getMethod($method); + $method->setAccessible(true); + + return $method; + } + + private function createCart() + { + $products = DataLoyaltyRetailCrm::createProducts(); + + return [ + [ + 'data' => $products[0], + 'quantity' => 1, + 'line_subtotal' => $products[0]->get_regular_price(), + 'line_total' => $products[0]->get_regular_price(),//When sale_price identical regular price, sale is empty + ], + [ + 'data' => $products[1], + 'quantity' => 3, + 'line_subtotal' => $products[1]->get_regular_price() * 3, + 'line_total' => $products[1]->get_sale_price() * 3, + ], + ]; } } diff --git a/tests/validators/test-wc-retailcrm-loyalty-validator.php b/tests/validators/test-wc-retailcrm-loyalty-validator.php index f25694f..5640f69 100644 --- a/tests/validators/test-wc-retailcrm-loyalty-validator.php +++ b/tests/validators/test-wc-retailcrm-loyalty-validator.php @@ -1,6 +1,6 @@ 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->set_billing_company('TEST COMPANY'); $this->corpClient->save(); } - /** @dataProvider datasets\DataLoyaltyRetailCrm::dataCheckUser() */ + /** + * @dataProvider DataLoyaltyRetailCrm::dataCheckUser() + */ public function testCheckUser($responseApiMethod, $wcUserType, $throwMessage, $isCorpActive) { $this->setResponseMock(); @@ -57,7 +59,7 @@ class WC_Retailcrm_Loyalty_Validator_Test extends WC_Retailcrm_Test_Case_Helper } } - /** @dataProvider datasets\DataLoyaltyRetailCrm::dataLoyaltyAccount() */ + /** @dataProvider DataLoyaltyRetailCrm::dataLoyaltyAccount() */ public function testGetLoyaltyAccount($responseMock, $throwMessage) { $this->setResponseMock($responseMock); @@ -79,7 +81,7 @@ class WC_Retailcrm_Loyalty_Validator_Test extends WC_Retailcrm_Test_Case_Helper } } - /** @dataProvider datasets\DataLoyaltyRetailCrm::dataCheckActiveLoyalty() */ + /** @dataProvider DataLoyaltyRetailCrm::dataCheckActiveLoyalty() */ public function testCheckActivateLoyalty($responseMock, $throwMessage) { $this->setResponseMock($responseMock);