Множественные свойства для заказов в 1С Битрикс

Множественные свойства для заказов очень сильно пригодились бы. Например, чтобы покупатель мог указать несколько номеров телефонов. Но, к сожалению, разработчики модуля bitrix.eshop не подумали об этом. Сейчас мы исправим это досадное недораз...

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

Множественные свойства для заказов очень сильно пригодились бы. Например, чтобы покупатель мог указать несколько номеров телефонов. Но, к сожалению, разработчики модуля bitrix.eshop не подумали об этом. Сейчас мы исправим это досадное недоразумение.

Внимание! Действия описанные в данной статье повлекут за собой изменение кода модулей, и у вас может перестать работать обновление, или оно будет работать не корректно. Если хотите следовать bitrix-way, то сделайте копию модуля и всех его компонентов, измените namespace и подключайте именно измененный модуль и компоненты, не трогая стандартные.

Итак, для начала нам нужно добавить новый тип свойств. Поскольку самое сложное в программировании, это придумывать название переменным, то назовем наш тип MULTILIST. Откроем файл /bitrix/modules/sale/include.php, найдем массив $GLOBALS["SALE_FIELD_TYPES"] и добавим в него новый элемент:

$GLOBALS["SALE_FIELD_TYPES"] = array(
        "CHECKBOX" => GetMessage("SALE_TYPE_CHECKBOX"),
        "TEXT" => GetMessage("SALE_TYPE_TEXT"),
        "SELECT" => GetMessage("SALE_TYPE_SELECT"),
        "MULTISELECT" => GetMessage("SALE_TYPE_MULTISELECT"),
        "TEXTAREA" => GetMessage("SALE_TYPE_TEXTAREA"),
        "LOCATION" => GetMessage("SALE_TYPE_LOCATION"),
        "RADIO" => GetMessage("SALE_TYPE_RADIO"),
        "MULTILIST" => GetMessage("SALE_TYPE_MULTILIST")
    );

Все, теперь в админке, на странице создания новых свойств к заказу у нас добавится новый тип свойств.

Теперь нам нужно оформить отображение нового типа свойств при оформлении заказа а так же их сохранение. Открываем файл props.php шаблона компонента sale.order.ajax. Сложно привести точное место в коде, куда вам нужно вставить новый код, т.к. наш шаблон был изрядно изменен. Поэтому попробуйте найти это место сами. Опозновательным знаком будут условия, где проверяется тип свойства и в зависимости от этого будет различное отображение. У меня это после условия:

elseif ($arProperties["TYPE"] == "RADIO")

Добавляем следующее условие:

                    elseif ($arProperties["TYPE"] == "MULTILIST")
                    {
                        ?>
                        <div class="field <?if(in_array($arProperties['CODE'], (array)$arResultErrors)){ echo "error";}?>">
                            <div class="input-container">
                                <input type="text" maxlength="250" size="<?=$arProperties["SIZE1"]?>" value="<?=$arProperties["VALUE"]?>" name="<?=$arProperties["FIELD_NAME"]?>[0]" id="<?=$arProperties["FIELD_NAME"]?>"><br />
                                <a href="#" id="<?=$arProperties["FIELD_NAME"]?>_add_record" data-index=0>
                                <?
                                switch($arProperties['CODE'])
                                {
                                    case 'PHONE':
                                        echo 'Добавить номер';
                                        break;
                                    default:
                                        echo 'Добавить поле';
                                }
                                ?>
                                </a>
                            </div>
                            <div class="input-description"><?
                            switch($arProperties['CODE'])
                            {
                                case 'FIO':
                                    echo 'Введите свое имя, чтобы мы знали, как к вам обращаться.';
                                    break;
                                case 'EMAIL':
                                    echo 'Введите свой e-mail, чтобы получить доступ в личный кабинет на сайте и возможность отслеживать состояние заказа.';
                                    break;
                                case 'PHONE':
                                    echo 'Введите свой телефон с кодом города или оператора сотовой сети, чтобы наш сотрудник мог связаться с Вами для подтверждения заказа. Например: +7 (999) 999-9999';
                                    break;
                            }
                        ?>    </div>
                        </div>
                        <script type="text/javascript">
                            $(function () {
                                <? if ($arProperties['CODE'] == 'PHONE'): ?>
                                var $input = $('#<?=$arProperties["FIELD_NAME"]?>').mask('+7 (999) 999-9999');
                                <? endif ?>
                                
                                $('#<?=$arProperties["FIELD_NAME"]?>_add_record').click(function(event) {
                                    event.preventDefault();

                                    $(this).attr('data-index', parseInt($(this).attr('data-index')) + 1);            
                                    $('<input type="text" maxlength="250" size="<?=$arProperties["SIZE1"]?>" name="<?=$arProperties["FIELD_NAME"]?>[' + $(this).attr('data-index') + ']" id="<?=$arProperties["FIELD_NAME"]?>_' + $(this).attr('data-index') + '"><br />')
                                        .insertBefore($(this))<? if ($arProperties['CODE'] == 'PHONE'): ?>.mask('+7 (999) 999-9999')<? endif ?>;

                                    return false;
                                });
                            });
                        </script>
                        <?
                    }

После этого мы получим примерно следующее:

При нажатии на ссылку Добавить номер, будет добавляться новое поле, куда можно ввести ещё один номер телефона. Ссылка будет иметь тест Добавить номер только для полей, с кодом PHONE, для всех остальных будет отображаться Добавить поле. Так же к номерам будет применяться маска номера телефона.

Остался последний шаг, нужно реализовать сохранение новых данных в БД. Открываем файл components.php компонента sale.order.ajax, находим в нем обработку свойств. Она будет происходить в цикле:

while ($arOrderProperties = $dbOrderProperties->Fetch())

Находим в нем условие:

if (strlen($curVal) > 0)

И заменяем эту строку на следующий код:

                        if ($arOrderProperties["TYPE"] == "MULTILIST")
                        {
                            foreach ($curVal as $val)
                            {
                                if (strlen($val) > 0)
                                {
                                    $arFields = array(
                                            "ORDER_ID" => $arResult["ORDER_ID"],
                                            "ORDER_PROPS_ID" => $arOrderProperties["ID"],
                                            "NAME" => $arOrderProperties["NAME"],
                                            "CODE" => $arOrderProperties["CODE"],
                                            "VALUE" => $val
                                        );
                                    CSaleOrderPropsValue::Add($arFields);
                                }
                            }
                        }
                        else if (strlen($curVal) > 0)

Если тип поля равен MULTILIST, то $curVal у нас будет массивом. Проходимся по нему, и если длина строки, содержащаяся в массиве больше нуля (т.е. в поле что-то введено), то вызываем метод CSaleOrderPropsValue::Add и добавляем в базу.

И заключительный штрих: нужно изменить индекс в БД. Находим таблицу b_sale_order_props_value и изменяем индекс IX_SOPV_ORD_PROP_UNI. Меняем Index type с UNIQUE на INDEX. Это нужно для того, чтобы все записи сохранялись в БД, а не только первая. Вот и все, теперь у нас есть множественные свойста, и они нормально сохраняются в БД.