Модуль одновременной наценки и скидки

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

Автор . Дата: 29.10.2014

Привалило мне недавно задание: нужно функцию наценки и одновременной скидки на одно и тоже число, причем чтобы получилась изначальная цена. Да и ещё чтобы для каждой категории товаров можно было назначать свою наценку. И делать все в один клик. Штатный механизм наценок и скидок не подошел по причине того, что не получается изначальной цены. Поэтому был написан свой компонент для админ панели, для реализации этого функционала.

Итак, начнем с того, что создадим файл cat_megaextra.php в /bitrix/admin/ и в него запишем:

<?
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/catalog/admin/cat_megaextra.php");
?>

Теперь создаем файл cat_megaextra.php в /bitrix/modules/catalog/admin/

<?
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/catalog/prolog.php");

if (!($USER->CanDoOperation('catalog_read') || $USER->CanDoOperation('catalog_price')))
    $APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));

CModule::IncludeModule('iblock');
CModule::IncludeModule("catalog");

$bReadOnly = !$USER->CanDoOperation('catalog_price');

IncludeModuleLangFile(__FILE__);

require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/catalog/prolog.php");

if ($ex = $APPLICATION->GetException())
{
    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");

    $strError = $ex->GetString();
    ShowError($strError);

    require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");
    die();
}

ClearVars();

$errorMessage = "";
$showForm = true;

require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/catalog/prolog.php");
$APPLICATION->SetTitle(GetMessage("EXTRA_TITLE"));
require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");

$context = new CAdminContextMenu($aMenu);
$context->Show();

CAdminMessage::ShowMessage($errorMessage);
?>

<?=bitrix_sessid_post();

$aTabs = array(
    array("DIV" => "edit1", "TAB" => GetMessage("CEEN_TAB_DISCOUNT"), "ICON" => "catalog", "TITLE" => GetMessage("CEEN_TAB_DISCOUNT_DESCR"))
);

$tabControl = new CAdminTabControl("tabControl", $aTabs);
$tabControl->Begin();

$tabControl->BeginNextTab();

function RecalculateCost($ID)
{
    global $productCounter, $discount, $DB;

    $dbSellingProposition = CPrice::GetList(
        array(),
        array('PRODUCT_ID' => intval($ID), 'CATALOG_GROUP_ID' => 1),
        false,
        array('nTopCount' => 1),
        array('ID', 'PRICE')
    );

    while ($b = $dbSellingProposition->Fetch())
    {
        $result_cost = $b["PRICE"] * $discount;

        $arNewSellingPropositionFields = array(
            'PRODUCT_ID' => $ID,
            'CATALOG_GROUP_ID' => 2,
            'PRICE' => $result_cost,
            'CURRENCY' => 'RUB'
        );

        $extraSellingProposition = CPrice::GetList(
            array(),
            array('PRODUCT_ID' => intval($ID), 'CATALOG_GROUP_ID' => 2),
            false,
            array('nTopCount' => 1),
            array('ID')
        );

        if ($c = $extraSellingProposition->Fetch())
        {
            echo CPrice::Update($c['ID'], $arNewSellingPropositionFields, false) == true ? 'Изменение цены удалось' : 'Изменение цены не удалось';
            echo '<br>';
        }
        else
        {
            echo CPrice::Add($arNewSellingPropositionFields, false) == true ? 'Добавление цены удалось' : 'Добавление цены не удалось';
            echo '<br>';
        }

        $DB->query("DELETE FROM `megaextra_discount` WHERE `PRODUCT_ID` = ".intval($ID));
        $DB->query("REPLACE INTO `megaextra_discount` (PRODUCT_ID, DISCOUNT) VALUES ('".intval($ID)."', '".$discount."')");

        $productCounter++;
    }
}

if ($REQUEST_METHOD == "POST" && $Update == "Y")
{
    $discount = 1 + $PERCENTAGE / 100;

    $showForm = false;

    $arElsFilter = array('SECTION_ID' => array_keys($_REQUEST['section']));

    $dbEls = CIBlockElement::GetList(false, $arElsFilter, false, false, array());
    $arEls = $arElsID = array();

    while ($arEl = $dbEls->Fetch())
    {
        $arEls[] = $arEl;
        $arElsID[] = $arEl['ID'];
    }
      
    if (!empty($arElsID))
    {
        $productCounter = 0;

        foreach ($arEls as $arEl)
        {
            if (CCatalogSKU::IsExistOffers($arEl['ID']))
            {
                echo 'Есть торговое предложение<br>';

                $arElID = intval($arEl['ID']);
                $arSkuInfo = CCatalogSKU::GetInfoByProductIBlock($arEl['IBLOCK_ID']);

                $SellingPropositions = CIBlockElement::GetList(
                    array(),
                    array('IBLOCK_ID' => $arSkuInfo['IBLOCK_ID'], '=PROPERTY_'.$arSkuInfo['SKU_PROPERTY_ID'] => $arElID),
                    false,
                    false,
                    array('ID', 'NAME')
                );

                $SellingPropositionsIDs = array();
                while ($a = $SellingPropositions->Fetch())
                {
                    $SellingPropositionsIDs[] = $a;
                }

                foreach ($SellingPropositionsIDs as $SellingPropositionsID)
                {
                    RecalculateCost($SellingPropositionsID['ID']);
                }
            }
            else
            {
                echo 'Нет торговых предложений<br>';
                RecalculateCost($arEl['ID']);
            }
            echo '<hr>';
        }
        echo '<h2 class="red">Всего изменено цен: '.$productCounter.'</h2>';         
    }
    else
    {
        echo '<h2 class="red">Элементы не найдены</h2>';
    }
}

$arResult["SECTIONS"] = array();
$rsSections = CIBlockSection::GetList(
   array(/*'depth_level' => 'ASC', 'NAME' => 'ASC'*/), 
   array(), 
   true, 
   array('ID', 'NAME', 'CODE', 'DEPTH_LEVEL', 'SECTION_PAGE_URL')
);

while($arSection = $rsSections->GetNext(false))
{   
   $arResult["SECTIONS"][] = $arSection;
}

?>

<? if ($showForm): ?>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script type="text/javascript">
    jQuery(document).ready(function() {
        jQuery('.extra-list input[type="checkbox"]').change(function() {
            var obParentLi = jQuery(this).parent('li');
            var bThisCheckboxState = jQuery(this).is(':checked');
            jQuery('input[type="checkbox"]', obParentLi).each(function() {
                jQuery(this).prop("checked", bThisCheckboxState);
            });
        });

        jQuery('#check-all').change(function() {
            var bThisCheckboxState = jQuery(this).is(':checked');
            jQuery('input[type="checkbox"]', jQuery('.extra-list')).each(function() {
                jQuery(this).prop("checked", bThisCheckboxState);
            });
        });
    });
</script>
<form action="<?echo $APPLICATION->GetCurPage()?>" id="form1" method="post">
<?echo GetFilterHiddens("filter_");?>
<input type="hidden" name="Update" value="Y">
<input type="hidden" name="lang" value="<?echo LANGUAGE_ID ?>">
    <tr class="adm-detail-required-field">
        <td width="40%"><?echo GetMessage("CEEN_PERCENTAGE")?>:</td>
        <td width="60%">
            <input type="text" name="PERCENTAGE" size="10" maxlength="20" value="0" />%
        </td>
    </tr>

    <tr class="adm-detail-required-field">
        <td width="40%"><?echo GetMessage("CEEN_CAT")?>:</td>
        <td width="60%"></td>
    </tr>

    <tr class="adm-detail-required-field">
        <td width="40%"></td>
        <td width="60%">
            <input type="checkbox" id="check-all" />
            <label>Выбрать все</label>
            <ul class="extra-list">
                <? $i = 1; ?>
                <? foreach ($arResult['SECTIONS'] as $arSection): ?>
                    <li>
                        <? //echo $arSection["DEPTH_LEVEL"]; ?>
                        <input type="checkbox" id="section<?=$arSection['ID'];?>" name="section[<?=$arSection['ID'];?>]" />
                        <label for="section<?=$arSection['ID'];?>"><?=$arSection["NAME"];?>&nbsp;(<?=$arSection["ELEMENT_CNT"]?>)</label>
                        <a target="_blank" href="<?=$arSection["SECTION_PAGE_URL"]?>">»»</a>
                        <? if (isset($arResult['SECTIONS'][$i]) && ($arResult['SECTIONS'][$i]['DEPTH_LEVEL'] > $arSection["DEPTH_LEVEL"])): ?>
                            <ul>
                        <? else: ?>
                            <? if ((isset($arResult['SECTIONS'][$i]) && ($arResult['SECTIONS'][$i]['DEPTH_LEVEL'] < $arSection["DEPTH_LEVEL"])) || ($i == count($arResult['SECTIONS']))): ?>
                                <? echo str_repeat("</li></ul>", $arSection["DEPTH_LEVEL"] - $arResult['SECTIONS'][$i]['DEPTH_LEVEL']); ?>
                            <? endif; ?>
                        </li>
                    <? endif; ?>
                    <? $i++; ?>
                <? endforeach ?>
            </ul>
        </td>
    </tr>
<?
$tabControl->Buttons(
    array(
        "disabled" => $bReadOnly,
        "back_url" => "/bitrix/admin/cat_megaextra.php?lang=".LANGUAGE_ID
    )
);
?>
</form>
<? endif; ?>

<?
$tabControl->EndTab();
$tabControl->End();
?>

<?
echo BeginNote();
echo GetMessage("EXTRA_NOTES");
echo EndNote();

require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");
?>

После этого вы можете перейти по адресу /bitrix/admin/cat_megaextra.php.

В поле Величина наценки указываете величину наценки-скидки, выбираете нужные категории и жмете сохранить. Но перед этим вам нужно будет создать таблицу в СУБД для хранения наценки-скидки:

DROP TABLE IF EXISTS `megaextra_discount`;
/*!40101 SET @saved_cs_client     = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `megaextra_discount` (
  `ID` int(11) NOT NULL AUTO_INCREMENT,
  `PRODUCT_ID` int(11) NOT NULL DEFAULT '0',
  `DISCOUNT` float NOT NULL DEFAULT '0',
  PRIMARY KEY (`ID`),
  KEY `IXS_CAT_PRICE_PID` (`PRODUCT_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=5153 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
/*!40101 SET character_set_client = @saved_cs_client */;

Вам так же нужно будет отредактировать файл /bitrix/modules/iblock/classes/general/comp_pricetools.php заменив:

                    $discountPrice = CCatalogProduct::CountPriceWithDiscount(
                        $arItem["CATALOG_PRICE_".$value["ID"]],
                        $arItem["CATALOG_CURRENCY_".$value["ID"]],
                        $arDiscounts
                    );

на

                    $discount = array();
                    $d = $DB->Query("SELECT * FROM megaextra_discount WHERE PRODUCT_ID = ".$arItem["ID"]);
                    $discount = $d->Fetch();
                    if ($discount['DISCOUNT'] != 0)
                    {
                        $discountPrice = $arItem["CATALOG_PRICE_".$value["ID"]] / $discount['DISCOUNT'];
                        $arItem["CATALOG_PRICE_".$value["ID"]] = ceil($arItem["CATALOG_PRICE_".$value["ID"]] / 10) * 10;
                    }
                    //---
                    else
                        $discountPrice = CCatalogProduct::CountPriceWithDiscount(
                            $arItem["CATALOG_PRICE_".$value["ID"]],
                            $arItem["CATALOG_CURRENCY_".$value["ID"]],
                            $arDiscounts
                        );

Приятного использования :-)