Применить в корзине купон в обход его же правила через sale.order.ajax

Вот такую задачу не могу решить: Есть купон-скидка на первый заказ пользователя. У тестового пользователя есть один отмененный заказ, но скидка должна все равно учитываться.

В скопированном sale.order.ajax компоненте я пытался заново пересчитать скидки в методе класс SaleOrderAjax->getJsDataResult() : (проверял варианты и по корзине, и по "заказу", что в классе есть) Код

DiscountCouponsManager::init();
DiscountCouponsManager::clear(true);
DiscountCouponsManager::add($oneCoupon['COUPON']);

// $discounts = \Bitrix\Sale\Discount::buildFromBasket($basket, new Sale\Discount\Context\Fuser(Fuser::getId()));
$discounts = \Bitrix\Sale\Discount::buildFromOrder($this->order);
                                        
                                        
$discounts->calculate();
$discounts->save();
$discountResult = $discounts->getApplyResult();
$this->obtainBasket(); # 

// $basket->refresh();
// $basket->save();
$arErrors = DiscountCouponsManager::getErrors();

Пример с https://dev.1c-bitrix.ru/api_d7/bitrix/sale/classes/discountcouponsmanager/add.php , в комментарии который, хоть и устаревший, но все равно не смог под себя заставить работать применение купона.

Подскажите, пожалуйста, куда можно еще посмотреть.

Заранее благодарен


Ответы (1 шт):

Автор решения: Konstantin Likhachev

К сожалению больше нет идей. Могу поделиться своим методом, который создает скидку и добавляет к заказу купон с этой скидкой на указанную сумму. Понимаю, что не то, что вам нужно, но в свое время тоже столкнулся с проблемой реализации добавления купонов и просто методом тыка нашел работающее решение.

Есть еще проблема - Битрикс может добавить купон к заказу, но не применит скидку из него. В этом случае в админке на странице заказа купон будет серого цвета. Сработавший купон должен быть зеленым.

    public static function applyDiscountCoupon(SaleOrder $order, float $discount): void
    {
        DiscountCouponsManager::init(DiscountCouponsManagerBase::MODE_ORDER, [
            "userId"  => $order->getUserId(),
            "orderId" => $order->getId(),
        ]);

        $coupon = self::generateCoupon($order->getId(), $discount);

        DiscountCouponsManager::clearApply();
        DiscountCouponsManager::add($coupon);

        $discounts = $order->getDiscount();
        $discounts->setOrderRefresh(true);

        $basket = $order->getBasket();

        if (!$basket) {
            throw new \Exception(GetMessage("TICKET_ORDER_ERROR_NO_BASKET"));
        }

        $basket->refreshData(["PRICE", "COUPONS"]);

        $result = $discounts->calculate();

        if (!$result->isSuccess()) {
            throw new \Exception(implode(', ', $result->getErrors()));
        }

        $discountData = $result->getData();

        if (!empty($discountData) && is_array($discountData)) {
            $result = $order->applyDiscount($discountData);
            if (!$result->isSuccess()) {
                throw new \Exception(implode(', ', $result->getErrors()));
            }
        }
    }
    private static function generateCoupon(int $orderId, float $amount): string
    {
        $discount = self::getDiscount($amount);

        if (!$discount) {
            throw new \Exception("Can't get discount");
        }

        $fields = [
            'DISCOUNT_ID' => $discount['ID'],
            'COUPON'      => \CatalogGenerateCoupon(),
            'ACTIVE'      => 'Y',
            'TYPE'        => 2,
            'MAX_USE'     => 0,
        ];
        $result = DiscountCouponTable::add($fields);

        if (!$result->isSuccess()) {
            throw new \Exception(implode(', ', $result->getErrors()));
        }

        return $fields['COUPON'];
    }
    private static function getDiscount(float $amount): array|bool
    {
        Loader::includeModule('catalog');
        Loader::includeModule('sale');

        $xmlId = "api_discount_$amount";

        $discount = \CSaleDiscount::GetList([], ['XML_ID' => $xmlId])->Fetch();
        if ($discount) {
            return $discount;
        }

        Loc::loadMessages(__FILE__);

        $discountId = \CSaleDiscount::Add([
            'NAME'        => Loc::getMessage('TICKET_ORDER_DISCOUNT_TITLE', [
                '#VALUE#' => Price::format($amount, 'RUB', false),
            ]),
            'LID'         => 's1',
            'ACTIVE'      => 'Y',
            'XML_ID'      => $xmlId,
            'USER_GROUPS' => [TICKETS_DISCOUNT_USER_GROUP_ID],
            'CURRENCY'    => 'RUB',
            'CONDITIONS'  => [
                'CLASS_ID' => 'CondGroup',
                'DATA'     => [
                    'All'  => 'AND',
                    'True' => 'True',
                ],
                'CHILDREN' => [],
            ],
            'USE_COUPONS' => 'Y',
            'ACTIONS'     => [
                'CLASS_ID' => 'CondGroup',
                'DATA'     => [
                    'All' => 'AND',
                ],
                'CHILDREN' => [
                    [
                        'CLASS_ID' => 'ActSaleBsktGrp',
                        'DATA'     => [
                            'Type'  => 'Discount',
                            'Value' => $amount,
                            'Unit'  => 'CurAll',
                            'Max'   => 0,
                            'All'   => 'AND',
                            'True'  => 'True',
                        ],
                        'CHILDREN' => [],
                    ],
                ],
            ],
        ]);

        if ($discountId) {
            return \CSaleDiscount::GetByID($discountId);
        }

        global $APPLICATION;
        $exception = $APPLICATION->GetException();

        return false;
    }
→ Ссылка