547 lines
21 KiB
PHP
547 lines
21 KiB
PHP
<?php
|
||
|
||
/**
|
||
* @category Integration
|
||
* @package Intaro\RetailCrm\Service
|
||
* @author RetailCRM <integration@retailcrm.ru>
|
||
* @license MIT
|
||
* @link http://retailcrm.ru
|
||
* @see http://retailcrm.ru/docs
|
||
*/
|
||
|
||
namespace Intaro\RetailCrm\Service;
|
||
|
||
use Bitrix\Main\Loader;
|
||
use Bitrix\Sale\BasketItemBase;
|
||
use Bitrix\Sale\Order;
|
||
use Exception;
|
||
use Intaro\RetailCrm\Component\ConfigProvider;
|
||
use Intaro\RetailCrm\Component\Constants;
|
||
use Intaro\RetailCrm\Component\Factory\ClientFactory;
|
||
use Intaro\RetailCrm\Component\ServiceLocator;
|
||
use Intaro\RetailCrm\Model\Api\LoyaltyAccount;
|
||
use Intaro\RetailCrm\Model\Api\LoyaltyAccountApiFilterType;
|
||
use Intaro\RetailCrm\Model\Api\OrderProduct;
|
||
use Intaro\RetailCrm\Model\Api\PriceType;
|
||
use Intaro\RetailCrm\Model\Api\Request\Loyalty\Account\LoyaltyAccountRequest;
|
||
use Intaro\RetailCrm\Model\Api\Request\Loyalty\LoyaltyCalculateRequest;
|
||
use Intaro\RetailCrm\Model\Api\Request\Order\Loyalty\OrderLoyaltyApplyRequest;
|
||
use Intaro\RetailCrm\Model\Api\Response\Loyalty\LoyaltyCalculateResponse;
|
||
use Intaro\RetailCrm\Model\Api\Response\Order\Loyalty\OrderLoyaltyApplyResponse;
|
||
use Intaro\RetailCrm\Model\Api\SerializedOrder;
|
||
use Intaro\RetailCrm\Model\Api\SerializedOrderProduct;
|
||
use Intaro\RetailCrm\Model\Api\SerializedOrderProductOffer;
|
||
use Intaro\RetailCrm\Model\Api\SerializedOrderReference;
|
||
use Intaro\RetailCrm\Model\Api\SerializedRelationCustomer;
|
||
use Intaro\RetailCrm\Model\Bitrix\OrderLoyaltyData;
|
||
use Intaro\RetailCrm\Repository\CurrencyRepository;
|
||
use Intaro\RetailCrm\Repository\OrderLoyaltyDataRepository;
|
||
use Intaro\RetailCrm\Service\Exception\LpAccountsUnavailableException;
|
||
use Logger;
|
||
|
||
/**
|
||
* Class LoyaltyService
|
||
*
|
||
* @package Intaro\RetailCrm\Service
|
||
*/
|
||
class LoyaltyService
|
||
{
|
||
/**
|
||
* @var \Intaro\RetailCrm\Component\ApiClient\ClientAdapter
|
||
*/
|
||
private $client;
|
||
|
||
/**
|
||
* @var mixed
|
||
*/
|
||
private $site;
|
||
|
||
/**
|
||
* @var \Logger
|
||
*/
|
||
private $logger;
|
||
|
||
/**
|
||
* LoyaltyService constructor.
|
||
*
|
||
* @throws \Bitrix\Main\LoaderException
|
||
*/
|
||
public function __construct()
|
||
{
|
||
IncludeModuleLangFile(__FILE__);
|
||
|
||
$this->logger = Logger::getInstance();
|
||
$this->client = ClientFactory::createClientAdapter();
|
||
$this->site = ConfigProvider::getSitesAvailable();
|
||
|
||
Loader::includeModule('Catalog');
|
||
}
|
||
|
||
/**
|
||
* Выполняет запрос на применение бонусов по программе лояльности
|
||
*
|
||
* @link https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#post--api-v5-orders-loyalty-apply
|
||
*
|
||
* @param int $orderId ID заказа
|
||
* @param float $bonusCount количество бонусов для списания
|
||
*
|
||
* @return \Intaro\RetailCrm\Model\Api\Response\Order\Loyalty\OrderLoyaltyApplyResponse|mixed|null
|
||
*/
|
||
public function sendBonusPayment(int $orderId, float $bonusCount): ?OrderLoyaltyApplyResponse
|
||
{
|
||
$request = new OrderLoyaltyApplyRequest();
|
||
$request->order = new SerializedOrderReference();
|
||
$request->order->externalId = $orderId;
|
||
$request->bonuses = $bonusCount;
|
||
$request->site = $this->site;
|
||
$result = $this->client->loyaltyOrderApply($request);
|
||
|
||
Utils::handleApiErrors($result);
|
||
|
||
return $result;
|
||
}
|
||
|
||
/**
|
||
* Возвращает расчет привилегий на основе корзины и количества бонусов для списания
|
||
*
|
||
* @link https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#post--api-v5-loyalty-calculate
|
||
*
|
||
* @param array $basketItems корзина
|
||
* @param float $bonuses количество бонусов для списания
|
||
*
|
||
* @return \Intaro\RetailCrm\Model\Api\Response\Loyalty\LoyaltyCalculateResponse|mixed|null
|
||
*/
|
||
public function getLoyaltyCalculate(array $basketItems, float $bonuses = 0): ?LoyaltyCalculateResponse
|
||
{
|
||
global $USER;
|
||
|
||
$request = new LoyaltyCalculateRequest();
|
||
$request->order = new SerializedOrder();
|
||
$request->order->customer = new SerializedRelationCustomer();
|
||
$request->order->customer->id = $USER->GetID();
|
||
$request->order->customer->externalId = $USER->GetID();
|
||
|
||
$request->site = $this->site;
|
||
$request->bonuses = $bonuses;
|
||
|
||
foreach ($basketItems as $item) {
|
||
$product = new SerializedOrderProduct();
|
||
|
||
$fullPrice = $item['BASE_PRICE'] ?? $item['FULL_PRICE'];
|
||
$product->initialPrice = $fullPrice; //цена без скидки
|
||
|
||
if ($fullPrice > 0) {
|
||
$product->discountManualAmount = $fullPrice - $item['PRICE'];
|
||
}
|
||
|
||
$product->offer = new SerializedOrderProductOffer();
|
||
$product->offer->externalId = $item['ID'];
|
||
$product->offer->id = $item['ID'];
|
||
$product->offer->xmlId = $item['XML_ID'];
|
||
$product->quantity = $item['QUANTITY'];
|
||
|
||
$prices = ConfigProvider::getCrmPrices();
|
||
$product->priceType = new PriceType();
|
||
$serializePrice = unserialize($prices);
|
||
|
||
if (isset($serializePrice[$item['PRICE_TYPE_ID']])) {
|
||
$product->priceType->code = $serializePrice[$item['PRICE_TYPE_ID']];
|
||
}
|
||
|
||
$request->order->items[] = $product;
|
||
}
|
||
|
||
$result = $this->client->loyaltyCalculate($request);
|
||
|
||
if (isset($result->errorMsg) && !empty($result->errorMsg)) {
|
||
$this->logger->write($result->errorMsg, Constants::LOYALTY_ERROR);
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
//TODO доделать метод проверки регистрации в ПЛ
|
||
|
||
/**
|
||
* Возвращает список участий в программе лояльности
|
||
*
|
||
* @link https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#get--api-v5-loyalty-accounts
|
||
*
|
||
* @param int $idInLoyalty ID участия в программе лояльности
|
||
*
|
||
* @return null|\Intaro\RetailCrm\Model\Api\LoyaltyAccount
|
||
* @throws \Intaro\RetailCrm\Service\Exception\LpAccountsUnavailableException
|
||
*/
|
||
public function getLoyaltyAccounts(int $idInLoyalty): ?LoyaltyAccount
|
||
{
|
||
$request = new LoyaltyAccountRequest();
|
||
$request->filter = new LoyaltyAccountApiFilterType();
|
||
$request->filter->id = $idInLoyalty;
|
||
$request->filter->sites = is_array($this->site) ? $this->site : [$this->site];
|
||
|
||
$response = $this->client->getLoyaltyAccounts($request);
|
||
|
||
if ($response !== null && $response->success) {
|
||
if (!isset($response->loyaltyAccounts[0])) {
|
||
throw new LpAccountsUnavailableException();
|
||
}
|
||
|
||
return $response->loyaltyAccounts[0];
|
||
}
|
||
|
||
Utils::handleApiErrors($response);
|
||
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Повторно отправляет бонусную оплату
|
||
*
|
||
* Используется при необходимости еще раз отправить смс
|
||
*
|
||
* @param int $orderId
|
||
*
|
||
* @return \Intaro\RetailCrm\Model\Bitrix\SmsCookie|bool
|
||
*/
|
||
public function resendBonusPayment(int $orderId)
|
||
{
|
||
/** @var CookieService $service */
|
||
$service = ServiceLocator::get(CookieService::class);
|
||
$bonusCount = $this->getTotalBonusCount($orderId);
|
||
|
||
if ($bonusCount === false || $bonusCount === 0) {
|
||
return false;
|
||
}
|
||
|
||
/** @var OrderLoyaltyApplyResponse $response */
|
||
$response = $this->sendBonusPayment($orderId, $bonusCount);
|
||
|
||
if ($response === null || !($response instanceof OrderLoyaltyApplyResponse)) {
|
||
return false;
|
||
}
|
||
|
||
if (
|
||
isset($response->verification, $response->verification->checkId)
|
||
&& empty($response->verification->verifiedAt)
|
||
) {
|
||
return $service->setSmsCookie('lpOrderBonusConfirm', $response->verification);
|
||
}
|
||
|
||
if (!empty($response->verification->verifiedAt)) {
|
||
$this->saveBonusDiscounts(Order::load($orderId), $response);
|
||
$this->setDebitedStatus($orderId, true);
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* @param int $orderId
|
||
* @param bool $newStatus
|
||
*/
|
||
public function setDebitedStatus(int $orderId, bool $newStatus): void
|
||
{
|
||
$repository = new OrderLoyaltyDataRepository();
|
||
$products = $repository->getProductsByOrderId($orderId);
|
||
|
||
if (is_array($products)) {
|
||
/** @var OrderLoyaltyData $product */
|
||
foreach ($products as $product) {
|
||
$product->isDebited = $newStatus;
|
||
$repository->edit($product);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Добавляет данные о программе лояльности в массив корзины
|
||
*
|
||
* @param array $basketData
|
||
* @param \Intaro\RetailCrm\Model\Api\Response\Loyalty\LoyaltyCalculateResponse $calculate
|
||
*
|
||
* @return array
|
||
*/
|
||
public function addLoyaltyToBasket(array $basketData, LoyaltyCalculateResponse $calculate): array
|
||
{
|
||
$totalRenderData = &$basketData['TOTAL_RENDER_DATA'];
|
||
$basketData['LP_CALCULATE_SUCCESS'] = $calculate->success;
|
||
$totalRenderData['WILL_BE_CREDITED'] = $calculate->order->bonusesCreditTotal;
|
||
|
||
foreach ($calculate->calculations as $privilege) {
|
||
if ($privilege->maximum && $privilege->creditBonuses === 0.0) {
|
||
$totalRenderData['LOYALTY_DISCOUNT']
|
||
= round($privilege->discount - $basketData['DISCOUNT_PRICE_ALL'], 2);
|
||
$totalRenderData['LOYALTY_DISCOUNT_FORMATED'] = $totalRenderData['LOYALTY_DISCOUNT']
|
||
. ' ' . GetMessage($totalRenderData['CURRENCY']);
|
||
$totalRenderData['PRICE'] -= $totalRenderData['LOYALTY_DISCOUNT'];//общая сумма со скидкой
|
||
$totalRenderData['PRICE_FORMATED'] = $totalRenderData['PRICE']
|
||
. ' ' . GetMessage($totalRenderData['CURRENCY']); //отформатированная сумма со скидкой
|
||
$totalRenderData['SUM_WITHOUT_VAT_FORMATED'] = $totalRenderData['PRICE_FORMATED'];
|
||
$basketData['allSum_FORMATED'] = $totalRenderData['PRICE_FORMATED'];
|
||
$basketData['allSum_wVAT_FORMATED'] = $totalRenderData['PRICE_FORMATED'];
|
||
$basketData['allSum'] = $totalRenderData['PRICE'];
|
||
$totalRenderData['DISCOUNT_PRICE_FORMATED'] = $privilege->discount
|
||
. ' ' . GetMessage($totalRenderData['CURRENCY']);
|
||
$totalRenderData['LOYALTY_DISCOUNT_DEFAULT'] = $basketData['DISCOUNT_PRICE_ALL']
|
||
. ' ' . GetMessage($totalRenderData['CURRENCY']);
|
||
}
|
||
}
|
||
|
||
foreach ($basketData['BASKET_ITEM_RENDER_DATA'] as $key => &$item) {
|
||
$item['WILL_BE_CREDITED_BONUS'] = $calculate->order->items[$key]->bonusesCreditTotal;
|
||
|
||
if ($calculate->order->items[$key]->bonusesCreditTotal === 0.0) {
|
||
$item['PRICE'] -= $calculate->order->items[$key]->discountTotal
|
||
- ($item['SUM_DISCOUNT_PRICE'] / $item['QUANTITY']);
|
||
$item['SUM_PRICE'] = $item['PRICE'] * $item['QUANTITY'];
|
||
$item['PRICE_FORMATED'] = $item['PRICE'] . ' ' . GetMessage($item['CURRENCY']);
|
||
$item['SUM_PRICE_FORMATED'] = $item['SUM_PRICE'] . ' ' . GetMessage($item['CURRENCY']);
|
||
$item['SHOW_DISCOUNT_PRICE'] = true;
|
||
$item['SUM_DISCOUNT_PRICE'] = $calculate->order->items[$key]->discountTotal
|
||
* $item['QUANTITY'];
|
||
$item['SUM_DISCOUNT_PRICE_FORMATED'] = $item['SUM_DISCOUNT_PRICE']
|
||
. ' '
|
||
. GetMessage($item['CURRENCY']);
|
||
$item['DISCOUNT_PRICE_PERCENT'] = round($item['SUM_DISCOUNT_PRICE']
|
||
/ (($item['FULL_PRICE'] * $item['QUANTITY']) / 100));
|
||
$item['DISCOUNT_PRICE_PERCENT_FORMATED'] = $item['DISCOUNT_PRICE_PERCENT'] . '%';
|
||
|
||
if (isset($item['COLUMN_LIST'])) {
|
||
foreach ($item['COLUMN_LIST'] as &$column) {
|
||
$column['VALUE'] = $column['CODE'] === 'DISCOUNT'
|
||
? $item['DISCOUNT_PRICE_PERCENT_FORMATED'] : $column['VALUE'];
|
||
}
|
||
|
||
unset($column);
|
||
}
|
||
}
|
||
}
|
||
|
||
unset($item);
|
||
|
||
return $basketData;
|
||
}
|
||
|
||
/**
|
||
* @param array $orderArResult
|
||
* @param \Intaro\RetailCrm\Model\Api\Response\Loyalty\LoyaltyCalculateResponse $calculate
|
||
*
|
||
* @return array
|
||
*/
|
||
public function calculateOrderBasket(array $orderArResult, LoyaltyCalculateResponse $calculate): array
|
||
{
|
||
/** @var \Intaro\RetailCrm\Model\Api\LoyaltyCalculation $privilege */
|
||
foreach ($calculate->calculations as $privilege) {
|
||
if ($privilege->maximum) {
|
||
$orderArResult['AVAILABLE_BONUSES'] = $privilege->maxChargeBonuses;
|
||
|
||
$jsDataTotal = &$orderArResult['JS_DATA']['TOTAL'];
|
||
|
||
//если уровень скидочный
|
||
if ($privilege->maximum && $privilege->discount > 0) {
|
||
//Персональная скидка
|
||
$jsDataTotal['LOYALTY_DISCOUNT'] = $orderArResult['LOYALTY_DISCOUNT_INPUT']
|
||
= round($privilege->discount - $jsDataTotal['DISCOUNT_PRICE'], 2);
|
||
|
||
//общая стоимость
|
||
$jsDataTotal['ORDER_TOTAL_PRICE'] -= $jsDataTotal['LOYALTY_DISCOUNT'];
|
||
|
||
//обычная скидка
|
||
$jsDataTotal['DEFAULT_DISCOUNT'] = $jsDataTotal['DISCOUNT_PRICE'];
|
||
|
||
$jsDataTotal['ORDER_TOTAL_PRICE_FORMATED'] = round($jsDataTotal['ORDER_TOTAL_PRICE'], 2)
|
||
. ' ' . GetMessage($orderArResult['BASE_LANG_CURRENCY']);
|
||
|
||
$jsDataTotal['DISCOUNT_PRICE'] += $jsDataTotal['LOYALTY_DISCOUNT'];
|
||
|
||
$jsDataTotal['DISCOUNT_PRICE_FORMATED'] = $jsDataTotal['DISCOUNT_PRICE']
|
||
. ' ' . GetMessage($orderArResult['BASE_LANG_CURRENCY']);
|
||
|
||
$jsDataTotal['ORDER_PRICE'] -= $jsDataTotal['LOYALTY_DISCOUNT'];
|
||
|
||
$jsDataTotal['ORDER_PRICE_FORMATED'] = $jsDataTotal['ORDER_PRICE']
|
||
. ' ' . GetMessage($orderArResult['BASE_LANG_CURRENCY']);
|
||
|
||
$iterator = 0;
|
||
|
||
foreach ($orderArResult['JS_DATA']['GRID']['ROWS'] as $key => &$item) {
|
||
$item['data']['SUM_NUM'] = $orderArResult['CALCULATE_ITEMS_INPUT'][$key]['SUM_NUM']
|
||
= $item['data']['SUM_BASE']
|
||
- ($calculate->order->items[$iterator]->discountTotal
|
||
* $item['data']['QUANTITY']);
|
||
|
||
$orderArResult['CALCULATE_ITEMS_INPUT'][$key]['QUANTITY'] = $item['data']['QUANTITY'];
|
||
$orderArResult['CALCULATE_ITEMS_INPUT'][$key]['SHOP_ITEM_DISCOUNT']
|
||
= round($item['data']['BASE_PRICE'] - $item['data']['PRICE'], 2);
|
||
$orderArResult['CALCULATE_ITEMS_INPUT'][$key]['BASE_PRICE']
|
||
= $item['data']['BASE_PRICE'];
|
||
|
||
$item['data']['SUM'] = $item['data']['SUM_NUM']
|
||
. ' ' . GetMessage($orderArResult['BASE_LANG_CURRENCY']);
|
||
|
||
$item['data']['DISCOUNT_PRICE'] = $calculate->order->items[$iterator]->discountTotal;
|
||
|
||
$iterator++;
|
||
}
|
||
|
||
unset($item);
|
||
|
||
$orderArResult['CALCULATE_ITEMS_INPUT']
|
||
= htmlspecialchars(json_encode($orderArResult['CALCULATE_ITEMS_INPUT']));
|
||
}
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
$orderArResult['CHARGERATE'] = $calculate->loyalty->chargeRate;
|
||
$orderArResult['TOTAL_BONUSES_COUNT'] = $calculate->order->loyaltyAccount->amount;
|
||
$orderArResult['LP_CALCULATE_SUCCESS'] = $calculate->success;
|
||
$orderArResult['WILL_BE_CREDITED'] = $calculate->order->bonusesCreditTotal;
|
||
|
||
$currencyRepository = new CurrencyRepository();
|
||
$orderArResult['BONUS_CURRENCY'] = html_entity_decode($currencyRepository->getCurrencyFormatString());
|
||
|
||
return $orderArResult;
|
||
}
|
||
|
||
/**
|
||
* @param \Bitrix\Sale\Order $order
|
||
* @param array $calculateItemsInput
|
||
*/
|
||
public function saveDiscounts(Order $order, array $calculateItemsInput): void
|
||
{
|
||
try {
|
||
/** @var BasketItemBase $basketItem */
|
||
foreach ($order->getBasket() as $basketItem) {
|
||
$calcItemPosition = $calculateItemsInput[$basketItem->getId()];
|
||
$calculateItem = $calcItemPosition['SUM_NUM'] / $calcItemPosition['QUANTITY'];
|
||
|
||
$basketItem->setField('CUSTOM_PRICE', 'Y');
|
||
$basketItem->setField('DISCOUNT_PRICE', $basketItem->getBasePrice() - $calculateItem);
|
||
$basketItem->setField('PRICE', $calculateItem);
|
||
}
|
||
|
||
$order->save();
|
||
} catch (Exception $exception) {
|
||
$this->logger->write($exception->getMessage(), Constants::LOYALTY_ERROR);
|
||
}
|
||
}
|
||
|
||
|
||
/**
|
||
* @param \Bitrix\Sale\Order $order
|
||
* @param \Intaro\RetailCrm\Model\Api\Response\Order\Loyalty\OrderLoyaltyApplyResponse $response
|
||
*
|
||
* @return void|null
|
||
*/
|
||
public function saveBonusDiscounts(Order $order, OrderLoyaltyApplyResponse $response): void
|
||
{
|
||
try {
|
||
$basketItems = $order->getBasket();
|
||
|
||
if ($basketItems === null) {
|
||
$this->logger->write('No item in basket', Constants::LOYALTY_ERROR);
|
||
}
|
||
|
||
/** @var BasketItemBase $basketItem */
|
||
foreach ($basketItems as $key => $basketItem) {
|
||
/** @var OrderProduct $item */
|
||
$item = $response->order->items[$key];
|
||
$basePrice = $basketItem->getField('BASE_PRICE');
|
||
$basketItem->setField('CUSTOM_PRICE', 'Y');
|
||
$basketItem->setField('DISCOUNT_PRICE', $item->discountTotal);
|
||
$basketItem->setField('PRICE', $basePrice - $item->discountTotal);
|
||
}
|
||
|
||
$order->save();
|
||
} catch (Exception $exception) {
|
||
$this->logger->write($exception->getMessage(), Constants::LOYALTY_ERROR);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @param int $externalId
|
||
*
|
||
* @return float|null
|
||
*/
|
||
public function getInitialDiscount(int $externalId): ?float
|
||
{
|
||
$repository = new OrderLoyaltyDataRepository();
|
||
|
||
return $repository->getDefDiscountByProductPosition($externalId);
|
||
}
|
||
|
||
/**
|
||
* Списаны ли бонусы в заказе
|
||
*
|
||
* @param $orderId
|
||
*
|
||
* @return bool|null
|
||
*/
|
||
public function isBonusDebited($orderId): ?bool
|
||
{
|
||
$repository = new OrderLoyaltyDataRepository();
|
||
$products = $repository->getProductsByOrderId($orderId);
|
||
|
||
if ($products === null || count($products) === 0) {
|
||
return null;
|
||
}
|
||
|
||
foreach ($products as $product) {
|
||
if (!empty($product->checkId) && $product->isDebited === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Добавляет оплату бонусами в заказ Битрикс (устанавливает кастомные цены)
|
||
*
|
||
* @param \Bitrix\Sale\Order $order
|
||
* @param float $bonusCount /бонусная скидка в рублях
|
||
*
|
||
* @return \Intaro\RetailCrm\Model\Api\Response\Order\Loyalty\OrderLoyaltyApplyResponse|null
|
||
*/
|
||
public function applyBonusesInOrder(Order $order, float $bonusCount): ?OrderLoyaltyApplyResponse
|
||
{
|
||
$response = $this->sendBonusPayment($order->getId(), $bonusCount);
|
||
|
||
if ($response->success) {
|
||
$this->saveBonusDiscounts($order, $response);
|
||
} else {
|
||
Utils::handleApiErrors($response);
|
||
return null;
|
||
}
|
||
|
||
return $response;
|
||
}
|
||
|
||
/**
|
||
* @param $orderId
|
||
*
|
||
* @return int|null
|
||
*/
|
||
private function getTotalBonusCount($orderId): ?int
|
||
{
|
||
$repository = new OrderLoyaltyDataRepository();
|
||
$products = $repository->getProductsByOrderId($orderId);
|
||
|
||
if ($products === null || count($products) === 0) {
|
||
return null;
|
||
}
|
||
|
||
foreach ($products as $product) {
|
||
if ($product->bonusCountTotal > 0) {
|
||
return $product->bonusCountTotal;
|
||
}
|
||
}
|
||
|
||
return null;
|
||
}
|
||
}
|