[1C Битрикс] Оформление заказа в 1 клик с помощью умной формы обратной связи

По многочисленным просьбам приведу пример, как все счастливые обладатели модуля TS Умная форма обратной связи
могут сделать в каталоге товаров, как в списке, так и в детальной карточке, возможность Купить товар в 1 клик.

Итак, предположим, что вы уже пользуетесь модулем, знаете Битрикс, все досконально я не расписываю.

1) Нам потребуется один обработчик события в /bitrix/php_interface/init.php

AddEventHandler("api.feedback", "OnBeforeEmailSend", "OnBeforeEmailSendHandler");

Данный обработчик будет запускаться перед каждой отправкой письма во всех формах, которые обрабатывает модуль.
Чтобы не затрагивать остальные формы, а только одну, в параметрах обработчика события можно по ID формы сделать уникальную обработку.

Уникальный идентификатор формы задается в настройках компонента для каждой формы, вот здесь, автоматически, но можете сами вписать туда что-то типа form1

Далее привожу готовый листинг кода, который необходимо добавить в файл init.php, в любое место, он взят вроде из модуля оформления заказа Яндекс.Маркета, делал очень давно, точно не помню.

<?php

//---------- Оформление заказа в 1 клик ----------//
AddEventHandler("api.feedback", "OnBeforeEmailSend", "OnBeforeEmailSendHandler");
function OnBeforeEmailSendHandler(&$event_name, &$site_id, &$arFields, &$message_id)
{

    //Форма "Купить в 1 клик" оформит заказ в магазине
    if($arFields['FORM_ID'] == 'form1') {
        
    //Для тестирования формы подставить свой e-mail, чтобы не мешать менеджерам
        //$arFields['EMAIL_TO'] = "test@site.ru";

        if(CModule::IncludeModule('sale') && CModule::IncludeModule("iblock") && CModule::IncludeModule("catalog")) {
            require_once($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/sale/general/admin_tool.php");

            function API_makeOrderProps($address, $buyer, $psId, $deliveryId, $locationId, $personTypeId)
            {
                $psId = intval($psId);

                $arResult = array();

                $arPropFilter = array(
                     "PERSON_TYPE_ID" => $personTypeId,
                     "ACTIVE"         => "Y",
                );

                if($psId != 0) {
                    $arPropFilter["RELATED"]["PAYSYSTEM_ID"] = $psId;
                    $arPropFilter["RELATED"]["TYPE"]         = "WITH_NOT_RELATED";
                }

                if(strlen($deliveryId) > 0) {
                    $arPropFilter["RELATED"]["DELIVERY_ID"] = $deliveryId;
                    $arPropFilter["RELATED"]["TYPE"]        = "WITH_NOT_RELATED";
                }

                $dbOrderProps = CSaleOrderProps::GetList(
                     array(),
                     $arPropFilter,
                     false,
                     false,
                     array("ID", "CODE")
                );

                while($arOrderProps = $dbOrderProps->Fetch()) {
                    if($arOrderProps["CODE"] == 'FIO' && !empty($buyer)) {
                        $fio = $buyer["firstName"];

                        if(isset($buyer["middleName"]))
                            $fio .= ' ' . $buyer["middleName"];

                        if(isset($buyer["lastName"]))
                            $fio .= ' ' . $buyer["lastName"];

                        $arResult[ $arOrderProps["ID"] ] = $fio;
                    }
                    elseif($arOrderProps["CODE"] == 'EMAIL' && isset($buyer["email"]))
                        $arResult[ $arOrderProps["ID"] ] = $buyer["email"];
                    elseif($arOrderProps["CODE"] == 'PHONE' && isset($buyer["phone"]))
                        $arResult[ $arOrderProps["ID"] ] = $buyer["phone"];
                    elseif($arOrderProps["CODE"] == 'ZIP' && isset($address["postcode"]))
                        $arResult[ $arOrderProps["ID"] ] = $address["postcode"];
                    elseif($arOrderProps["CODE"] == 'CITY' && isset($address["city"]))
                        $arResult[ $arOrderProps["ID"] ] = $address["city"];
                    elseif($arOrderProps["CODE"] == 'LOCATION' && isset($locationId))
                        $arResult[ $arOrderProps["ID"] ] = $locationId;
                    elseif($arOrderProps["CODE"] == 'ADDRESS') {
                        $strAddr = "";

                        if(isset($address["postcode"]))
                            $strAddr .= $address["postcode"] . ", ";

                        if(isset($address["country"]) && isset($address["city"]))
                            $strAddr .= $address["country"] . ", " . $address["city"] . ", ";

                        if(isset($address["street"]))
                            $strAddr .= 'улица' . " " . $address["street"] . ", ";

                        if(isset($address["subway"]))
                            $strAddr .= 'метро' . " " . $address["subway"] . ", ";

                        if(isset($address["house"]))
                            $strAddr .= 'дом' . " " . $address["house"];

                        if(isset($address["block"]))
                            $strAddr .= ", " . 'корпус/строение' . " " . $address["block"];

                        if(isset($address["entrance"]))
                            $strAddr .= ", " . 'подъезд' . " " . $address["entrance"];

                        if(isset($address["entryphone"]))
                            $strAddr .= ", " . 'домофон' . " " . $address["entryphone"];

                        if(isset($address["floor"]))
                            $strAddr .= ", " . 'этаж' . " " . $address["floor"];

                        if(isset($address["apartment"]))
                            $strAddr .= ", " . 'офис/квартира' . " " . $address["apartment"];

                        if(isset($address["recipient"]))
                            $strAddr .= ", " . 'получатель' . " " . $address["recipient"];

                        if(isset($address["phone"]))
                            $strAddr .= ", " . 'телефон' . " " . $address["phone"];

                        $arResult[ $arOrderProps["ID"] ] = $strAddr;
                    }
                }

                return $arResult;
            }

            /**
             * Creates new anonymous user with e-mail 'anonymous_some_number@example.com' and returns his ID
             * Used mainly in CRM
             *
             * @return int - new user ID or ID of already existing anonymous user, 0 if error
             */
            function API_GetAnonymousUserID()
            {
                $bUserExists = false;

                $anonUserID = intval(COption::GetOptionInt("sale", "one_click_user_id", 0));

                if($anonUserID > 0) {
                    $by     = "id";
                    $order  = "asc";
                    $dbUser = CUser::GetList($by, $order, array("ID_EQUAL_EXACT" => $anonUserID), array("FIELDS" => array("ID")));
                    if($arUser = $dbUser->Fetch())
                        $bUserExists = true;
                }

                if(!$bUserExists) {
                    $anonUserEmail = "one_click_" . randString(9) . "@example.com";
                    $arErrors      = array();
                    $anonUserID    = CSaleUser::DoAutoRegisterUser(
                         $anonUserEmail,
                         array("NAME" => "Купить в 1 клик"),
                         SITE_ID,
                         $arErrors,
                         array("ACTIVE" => "N")
                    );

                    if($anonUserID > 0) {
                        COption::SetOptionInt("sale", "one_click_user_id", $anonUserID);
                    }
                    else {
                        $errorMessage = "";
                        if(!empty($arErrors)) {
                            $errorMessage = " ";
                            foreach($arErrors as $value) {
                                $errorMessage .= $value["TEXT"] . "<br>";
                            }
                        }

                        //Loc::getMessage("SU_ANONYMOUS_USER_CREATE", array("#ERROR#" => $errorMessage))
                        $GLOBALS["APPLICATION"]->ThrowException("Ошибка создания анонимного пользователя." . $errorMessage, "ANONYMOUS_USER_CREATE_ERROR");
                        return 0;
                    }
                }

                return $anonUserID;
            }



            $arErrors = $arWarnings = $arOptions = $arProducts = $arAdditionalFields = array();

            $IBLOCK_ID = 1; //Каталог товаров
            //$site_id = $site_id; //
            $user_id          = API_GetAnonymousUserID(); //7220
            $person_type_id   = 1; //Плательщик
            $delivery_id      = 3; //Самовывоз
            $pay_system_id    = 1; //Наличная оплата
            $location_id      = 2691; //Москва
            $user_description = trim($arFields['USER_DESCRIPTION']);
            $quantity         = (intval($arFields['PRODUCT_COUNT']) > 0 ? intval($arFields['PRODUCT_COUNT']) : 1);


            $arIblockFilter = array(
                 'IBLOCK_ID' => $IBLOCK_ID,
                 '=XML_ID'   => trim($arFields['PRODUCT_ID']),
            );
            $arElement      = CIBlockElement::GetList(array(), $arIblockFilter, false, false, array('ID', 'XML_ID', 'IBLOCK_EXTERNAL_ID'))->Fetch();

            if($arElement['ID']) {
                $arProduct = CCatalogProductProvider::GetProductData(array(
                     "PRODUCT_ID" => $arElement['ID'],
                     "RENEWAL"    => "N",
                     "QUANTITY"   => $quantity,
                     "SITE_ID"    => $site_id,
                ));

                $arProduct["PRODUCT_ID"]             = $arElement["ID"];
                $arProduct["MODULE"]                 = "catalog";
                $arProduct["PRODUCT_PROVIDER_CLASS"] = "CCatalogProductProvider";

                if(strlen($arElement["XML_ID"]) > 0)
                    $arProduct["PRODUCT_XML_ID"] = $arElement["XML_ID"];

                if(strlen($arElement["IBLOCK_EXTERNAL_ID"]) > 0)
                    $arProduct["CATALOG_XML_ID"] = $arElement["IBLOCK_EXTERNAL_ID"];

                if($arProduct["CAN_BUY"] == "Y")
                    $arProducts[] = $arProduct;

                $arOrderProductPrice = fGetUserShoppingCart($arProducts, $site_id, "N");

                $arShoppingCart = CSaleBasket::DoGetUserShoppingCart(
                     $site_id,
                     $user_id,
                     $arOrderProductPrice,
                     $arErrors
                );


                $arErrors           = $arWarnings = array();
                $arOptions          = array();
                $arOrderPropsValues = API_makeOrderProps(
                     '',
                     array(
                            'firstName' => $arFields['FIO'],
                            'phone'     => $arFields['PHONE'],
                     ),
                     $pay_system_id,
                     $delivery_id,
                     $location_id,
                     $person_type_id
                );

                $CSaleOrder = new CSaleOrder();
                $arOrder    = $CSaleOrder->DoCalculateOrder(
                     $site_id,
                     $user_id,
                     $arShoppingCart,
                     $person_type_id,
                     $arOrderPropsValues,
                     $delivery_id,
                     $pay_system_id,
                     $arOptions,
                     $arErrors,
                     $arWarnings
                );

                $arOrder["LID"] = $site_id;

                if($user_description)
                    $arAdditionalFields["USER_DESCRIPTION"] = $user_description;


                if($orderID = $CSaleOrder->DoSaveOrder($arOrder, $arAdditionalFields, 0, $arErrors)) {
                    $arOrderInfo = CSaleOrder::GetList(false, array('ID' => $orderID), false, false, array('ID', 'ACCOUNT_NUMBER'))->Fetch();

                    $arFields['SUBJECT'] .= ' №' . $arOrderInfo['ACCOUNT_NUMBER'];
                    $arFields['ORDER_URL'] = (CMain::IsHTTPS() ? 'https://' : 'http://') . 'site.ru/bitrix/admin/sale_order_detail.php?ID=' . $orderID . '&lang=ru';
                }
                else
                    $arFields['ORDER_URL'] = implode(' | ', $arErrors);
                /*if($orderID)
                {
                    echo "<pre>"; print_r($orderID);echo "</pre>";
                }
                else
                {
                    echo "<pre>"; print_r($arErrors);echo "</pre>";
                }*/
            }
        }
    }
}

Что вам необходимо тут сделать в своем случае, да, у каждого из нас будут разные идентификатор формы, инфоблока, самовывоз, наличная оплата, плательщик, город и т.д.

а) Проверить идентификатор формы, чтобы только указанную форму слушал обработчик.

if($arFields['FORM_ID'] == 'form1')

б) Подставить здесь свои идентификаторы, найти их надо в админке

$IBLOCK_ID = 1; //Каталог товаров
//$site_id = $site_id; //
$user_id          = API_GetAnonymousUserID(); //7220
$person_type_id   = 1; //Плательщик
$delivery_id      = 3; //Самовывоз
$pay_system_id    = 1; //Наличная оплата
$location_id      = 2691; //Москва
$user_description = trim($arFields['USER_DESCRIPTION']);
$quantity         = (intval($arFields['PRODUCT_COUNT']) > 0 ? intval($arFields['PRODUCT_COUNT']) : 1);

Комментарий к заказу прилетит из поля формы, о нем будет ниже

$user_description = trim($arFields['USER_DESCRIPTION']);

Количество товара также прилетит из поля формы, там счетчик можно включить

$quantity = (intval($arFields['PRODUCT_COUNT']) > 0 ? intval($arFields['PRODUCT_COUNT']) : 1);

в) Здесь тоже надо из полей формы подставить ФИО + Телефон, об этом будет ниже

$arOrderPropsValues = API_makeOrderProps(
   '',
   array(
      'firstName' => $arFields['FIO'],
      'phone'     => $arFields['PHONE'],
   ),
   $pay_system_id,
   $delivery_id,
   $location_id,
   $person_type_id
);

г) Вот это уже после оформления заказа полетит на вашу почту Тема письма + Ссылка на заказ в админке.
Но если отключить в форме отправку писем, то на почту ничего не полетит, будет только создаваться заказ в админке.

$arFields['SUBJECT'] .= ' №' . $arOrderInfo['ACCOUNT_NUMBER'];
$arFields['ORDER_URL'] = (CMain::IsHTTPS() ? 'https://' : 'http://') . 'site.ru/bitrix/admin/sale_order_detail.php?ID=' . $orderID . '&lang=ru';

Здесь вроде все, переделывайте код под себя, если что-то не работает, думайте, экспериментируйте.


2) Теперь сама форма, выглядеть она будет вот так:

Код формы необходимо вставить в футере шаблона сайта, например в файле:
/bitrix/templates/tpl2015/footer.php

Код вызова компонента формы, вставьте где-нибудь в конце, ближе к закрывающему тэгу </body>
<!--api:main.feedback-modal-->
<?$APPLICATION->IncludeComponent(
    "api:main.feedback",
    "modal",
    array(
        "COMPONENT_TEMPLATE" => "modal",
        "IBLOCK_TYPE" => "info",
        "IBLOCK_ID" => "12",
        "INSTALL_IBLOCK" => "N",
        "IBLOCK_ELEMENT_ACTIVE" => "N",
        "DISABLE_SEND_MAIL" => "Y",
        "REPLACE_FIELD_FROM" => "Y",
        "HIDE_FORM_AFTER_SEND" => "Y",
        "UNIQUE_FORM_ID" => "form1",
        "OK_TEXT" => "Спасибо за заказ!<br>В ближайшее время наш менеджер свяжется с вами.",
        "OK_TEXT_AFTER" => "",
        "EMAIL_TO" => "info@site.ru",
        "REDIRECT_PAGE" => "",
        "DISPLAY_FIELDS" => array(
        ),
        "REQUIRED_FIELDS" => array(
        ),
        "CUSTOM_FIELDS" => array(
            0 => "Ф.И.О@input@type=text@name=FIO@required@data-validation=[NOTEMPTY]@data-validation-label=Ваше имя",
            1 => "Номер телефона@input@type=text@name=PHONE@required@data-validation=[NOTEMPTY]@data-validation-label=Номер телефона@placeholder=+7(___)___-__-__@data-inputmask='mask': '+7(999)999-99-99'",
            2 => "Количество@input@type=stepper@name=PRODUCT_COUNT@value=1@class=stepper@data-type=int@data-limit=[1,null]@data-arrow-step=1",
            3 => "Комментарий к заказу@textarea@name=USER_DESCRIPTION@cols=30@rows=5",
            4 => "Наименование@input@type=hidden@name=PRODUCT_NAME",
            5 => "Артикул@input@type=hidden@name=PRODUCT_ID",
            6 => "Ссылка@input@type=hidden@name=PRODUCT_URL",
            7 => "Заказ@input@type=hidden@name=ORDER_URL",
        ),
        "ADMIN_EVENT_MESSAGE_ID" => array(
            0 => "179",
        ),
        "USER_EVENT_MESSAGE_ID" => array(
        ),
        "WRITE_MESS_DIV_STYLE" => "margin:0px 0px 20px 0px;",
        "WRITE_MESS_DIV_STYLE_NAME" => "font-weight:bold;",
        "WRITE_MESS_DIV_STYLE_VALUE" => "",
        "WRITE_MESS_FILDES_TABLE" => "N",
        "WRITE_MESS_TABLE_STYLE" => "border-collapse: collapse; border-spacing: 0;",
        "WRITE_MESS_TABLE_STYLE_NAME" => "max-width: 200px; color: #848484; vertical-align: middle; padding: 5px 30px 5px 0px; border-bottom: 1px solid #e0e0e0; border-top: 1px solid #e0e0e0;",
        "WRITE_MESS_TABLE_STYLE_VALUE" => "vertical-align: middle; padding: 5px 30px 5px 0px; border-bottom: 1px solid #e0e0e0; border-top: 1px solid #e0e0e0;",
        "FORM_CLASS" => "",
        "TITLE_DISPLAY" => "N",
        "FORM_TITLE" => "Заказ в 1 клик",
        "FORM_TITLE_LEVEL" => "2",
        "FIELD_ERROR_MESS" => "#FIELD_NAME# обязательное",
        "EMAIL_ERROR_MESS" => "Указанный E-mail некорректен",
        "DEFAULT_OPTION_TEXT" => "-- Выбрать --",
        "FORM_SUBMIT_CLASS" => "uk-button uk-button-primary uk-width-1-1",
        "FORM_SUBMIT_VALUE" => "Оформить заказ",
        "FORM_SUBMIT_STYLE" => "",
        "BUTTON_TEXT_BEFORE" => "",
        "FORM_TEXT_BEFORE" => "",
        "FORM_TEXT_AFTER" => "<small>Перед оформлением заказа уточняйте наличие товара у менеджеров</small>",
        "HIDE_FIELD_NAME" => "N",
        "HIDE_ASTERISK" => "N",
        "FORM_AUTOCOMPLETE" => "Y",
        "FIELD_BOX_SHADOW_ACTIVE" => "",
        "FIELD_BORDER_ACTIVE" => "",
        "FIELD_SIZE" => "default",
        "FIELD_NAME_POSITION" => "stacked",
        "FORM_LABEL_TEXT_ALIGN" => "left",
        "FORM_LABEL_WIDTH" => "200",
        "TEMPLATE_STYLE" => "uikit",
        "USE_HIDDEN_PROTECTION" => "Y",
        "USE_CAPTCHA" => "N",
        "INCLUDE_JQUERY" => "N",
        "INCLUDE_INPUTMASK" => "Y",
        "INCLUDE_PLACEHOLDER" => "N",
        "INCLUDE_AUTOSIZE" => "N",
        "SCROLL_TO_FORM_IF_MESSAGES" => "N",
        "SCROLL_TO_FORM_SPEED" => "1000",
        "INCLUDE_VALIDATION" => "Y",
        "INCLUDE_ICHECK" => "N",
        "BRANCH_ACTIVE" => "N",
        "SHOW_FILES" => "N",
        "UUID_LENGTH" => "10",
        "UUID_PREFIX" => "",
        "USE_YM_GOALS" => "Y",
        "AJAX_MODE" => "N",
        "AJAX_OPTION_JUMP" => "N",
        "AJAX_OPTION_STYLE" => "Y",
        "AJAX_OPTION_HISTORY" => "N",
        "AJAX_OPTION_ADDITIONAL" => "",
        "USER_AUTHOR_FIO" => "",
        "USER_AUTHOR_NAME" => "",
        "USER_AUTHOR_LAST_NAME" => "",
        "USER_AUTHOR_SECOND_NAME" => "",
        "USER_AUTHOR_EMAIL" => "",
        "USER_AUTHOR_PERSONAL_MOBILE" => "",
        "USER_AUTHOR_WORK_COMPANY" => "",
        "USER_AUTHOR_POSITION" => "",
        "USER_AUTHOR_PROFESSION" => "",
        "USER_AUTHOR_STATE" => "",
        "USER_AUTHOR_CITY" => "",
        "USER_AUTHOR_WORK_CITY" => "",
        "USER_AUTHOR_STREET" => "",
        "USER_AUTHOR_ADRESS" => "",
        "USER_AUTHOR_PERSONAL_PHONE" => "",
        "USER_AUTHOR_WORK_PHONE" => "",
        "USER_AUTHOR_FAX" => "",
        "USER_AUTHOR_MAILBOX" => "",
        "USER_AUTHOR_WORK_MAILBOX" => "",
        "USER_AUTHOR_SKYPE" => "",
        "USER_AUTHOR_ICQ" => "",
        "USER_AUTHOR_WWW" => "",
        "USER_AUTHOR_WORK_WWW" => "",
        "USER_AUTHOR_MESSAGE_THEME" => "",
        "USER_AUTHOR_MESSAGE" => "",
        "USER_AUTHOR_NOTES" => "",
        "INCLUDE_CSSMODAL" => "bootstrap3",
        "MODAL_BUTTON_HTML" => "",
        "MODAL_HEADER_HTML" => "Заказ в 1 клик",
        "MODAL_FOOTER_HTML" => "",
        "SHOW_CSS_MODAL_AFTER_SEND" => "N",
        "SUBJECT" => "Заказ в 1 клик",
        "PAGE_TITLE" => "",
        "PAGE_URI" => "",
        "PAGE_URL" => "",
        "DIR_URL" => "",
        "DATETIME" => "",
        "USE_AGREEMENT" => "N",
        "VALIDATION_MESSAGES" => array(
            0 => "'default':'\$ содержит ошибки.'",
            1 => "'NOTEMPTY':'\$ обязательно.'",
            2 => "'INTEGER':'\$ должно быть целым числом.'",
            3 => "'NUMERIC':'\$ должно быть числом.'",
            4 => "'MIXED':'\$ должно содержать буквы или цифры (без спец. символов).'",
            5 => "'NAME':'\$ обязательно и без спец.символов.'",
            6 => "'NOSPACE':'\$ не должно содержать пробелы.'",
            7 => "'TRIM':'\$ не должно начинаться или заканчиваться пробелом.'",
            8 => "'DATE':'\$ содержит недопустимый формат YYYY-MM-DD.'",
            9 => "'EMAIL':'\$ неверного формата.'",
            10 => "'URL':'\$ неверного формата.'",
            11 => "'PHONE':'\$ неверного формата.'",
            12 => "'<':'\$ должно быть меньше % символов.'",
            13 => "'<=':'\$ должно быть меньше или равно % символам.'",
            14 => "'>':'\$ должно быть больше % символов.'",
            15 => "'>=':'\$ должно быть больше или равно % символам.'",
            16 => "'==':'\$ должно быть равно % символам.'",
            17 => "'!=':'\$ должно быть не равно % символам.'",
            18 => "",
        ),
        "BCC" => "",
        "FORM_FIELD_WIDTH" => "",
        "YM_COUNTER_ID" => "22413496",
        "YM_TARGET_NAME" => "ONE_CLICK_ORDER",
        "MODAL_WIDTH" => "",
        "MODAL_BUTTON_CLASS" => "uk-button uk-button-danger",
        "SERVER_VARS" => array(
            0 => "",
            1 => "",
        ),
        "REQUEST_VARS" => array(
            0 => "",
            1 => "",
        ),
        "INCLUDE_CHOSEN" => "N",
    ),
    false
); ?>
<!--api:main.feedback-modal-->

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

Обратите внимание!
а) На айдишник формы из настроек компонента, мы его получаем в init.php

"UNIQUE_FORM_ID" => "form1"

б) На шаблон формы modal
Форма открывается во встроенном модальном окне, но если переключить на дефолтный шаблон, то можно форму в любом своем плагине модального окна загрузить, в томже фэнсибоксе

в) Ну и на список полей формы, часть из них скрыто передает данные о товаре в init.php

"CUSTOM_FIELDS" => array(
  0 => "Ф.И.О@input@type=text@name=FIO@required@data-validation=[NOTEMPTY]@data-validation-label=Ваше имя",
  1 => "Номер телефона@input@type=text@name=PHONE@required@data-validation=[NOTEMPTY]@data-validation-label=Номер телефона@placeholder=+7(___)___-__-__@data-inputmask='mask': '+7(999)999-99-99'",
  2 => "Количество@input@type=stepper@name=PRODUCT_COUNT@value=1@class=stepper@data-type=int@data-limit=[1,null]@data-arrow-step=1",
  3 => "Комментарий к заказу@textarea@name=USER_DESCRIPTION@cols=30@rows=5",
  4 => "Наименование@input@type=hidden@name=PRODUCT_NAME",
  5 => "Артикул@input@type=hidden@name=PRODUCT_ID",
  6 => "Ссылка@input@type=hidden@name=PRODUCT_URL",
  7 => "Заказ@input@type=hidden@name=ORDER_URL",
),


3) Остается сделать кнопки и js-код, который будет по клику открывать форму

3.1 Пример кода кнопки в шаблоне компонента bitrix:catalog.element

<?if($canBuy):?>
<div class="one-click">
  <span data-target="#API-MF-MODAL-FORM1"
        data-toggle="modal"
        class="uk-button uk-width-1-1 uk-button-large"
        data-id="<?=trim($arResult["XML_ID"])?>"
        data-name="<?=CUtil::JSEscape($arResult["NAME"])?>"
        data-url="<?= ($APPLICATION->IsHTTPS() ? 'https://' : 'http://')?><?=$_SERVER['HTTP_HOST']?><?=$arResult["DETAIL_PAGE_URL"]?>"><?=GetMessage('CT_BCE_CATALOG_ONE_CLICK_BTN')?></span>
</div>
<?endif?>

Т.к. форму запускает плагин Bootstrap3, то html-код кнопки будет таким, а если другой плагин открывает форму, то может отличаться, вам надо как-то сами узнать, как запустить модалку, по идентификатору формы в href или data-атрибуту, но если все как в статье, то должно работать.

Обратите внимание, какой идентификатор обертки всей формы будет, в верхнем регистре в конце FORM1, если что, найти сможете в исходном коде страницы, когда там форму вставите.

data-target="#API-MF-MODAL-FORM1"

Тут я подставляю вместо ID товара его XML_ID

data-id="<?=trim($arResult["XML_ID"])?>"

Чтобы в init.php найти товар вот по такому фильтру

$arIblockFilter = array(
   'IBLOCK_ID' => $IBLOCK_ID,
   '=XML_ID'   => trim($arFields['PRODUCT_ID']),
);

Тут я избавляюсь с помощью утилит от двойных кавычек в названии товара, которые могут порвать html-тег и ничего работать не будет, в названии товара там все, что угодно может прилететь, это будет надежно.

data-name="<?=CUtil::JSEscape($arResult["NAME"])?>"

Ну и адрес товара

data-url="<?= ($APPLICATION->IsHTTPS() ? 'https://' : 'http://')?><?=$_SERVER['HTTP_HOST']?><?=$arResult["DETAIL_PAGE_URL"]?>"><?=GetMessage('CT_BCE_CATALOG_ONE_CLICK_BTN')?></span>

Вообще, Название и Адрес товара наверно можно и убрать, если уведомления на почту будут отключены, вроде только для почты они были нужны.

3.2. Пример кода кнопки в шаблоне списка товаров bitrix:catalog.section

<? if($arElement["CAN_BUY"]):?>
  <?if($arElement['CATALOG_QUANTITY'] > 0): ?>
      <a href="<?=$arElement["ADD_URL"]?>" rel="nofollow" class="uk-button uk-button-primary"><?echo GetMessage("CATALOG_BUY")?></a>
      <span class="one-click uk-button uk-button-link">
          <span data-target="#API-MF-MODAL-FORM1"
                data-toggle="modal"
                data-id="<?=trim($arElement["XML_ID"])?>"
                data-name="<?=CUtil::JSEscape($arElement["NAME"])?>"
                data-url="<?= ($APPLICATION->IsHTTPS() ? 'https://' : 'http://')?><?=$_SERVER['HTTP_HOST']?><?=$arElement["DETAIL_PAGE_URL"]?>">Купить быстро</span>
      </span>
  <? else: ?>
    <div class="uk-button">Нет в наличии</div>
  <? endif; ?>
<? endif; ?>

Здесь тоже самое.

Суть кнопок Купить в 1 клик такова:
Главное кликнуть кнопку и открыть мадалку с формой, все остальное сделает jQuery, возьмет из атрибутов кнопки данные, подставит в скрытые поля формы, а при отправке формы нажатием Оформить заказ значения этих полей полетя в init.php в параметры события и там с ними делать можно все, что угодно, главное их туда отправить с формой.

3.3. Пример jQuery-кода

$(function(){

    // ---------------------------------------------------------
    //  one-click()
    // ---------------------------------------------------------
    $('.one-click span').click(function(){
        $('#API-MF-form1 input[name=PRODUCT_NAME]').val($(this).data('name'));
        $('#API-MF-form1 input[name=PRODUCT_URL]').val($(this).data('url'));
        $('#API-MF-form1 input[name=PRODUCT_ID]').val($(this).data('id'));
        $('#API-MF-form1 .uk-alert').removeClass('uk-alert-success').addClass('uk-alert-danger').html('Для повторного заказа обновите страницу.');
    });

});

Здесь обратите в внимание на айдишник самой формы #API-MF-form1 он отличается от обертки всей формы с айди  #API-MF-MODAL-FORM1
Не запутайтесь, там много всяких айдишников и классов, да в разных регистрах, к чему можно привязываться, я это называю "Мега-гибкостью"))

Ну вроде и все, с виду возможно покажется вам портянкой говнокода, но стоит пару раз так сделать и лучше будете понимать:
- как запускать модальные окна в списке товаров и в детальном.
- как передавать с помощью jQuery данные о товаре в форму, в скрытые поля
- как передавать из формы с помощью скрытых полей данные в init.php
- как обрабатывать события модуля в init.php


И на десерт, все обладатели данного модуля TS Умная форма обратной связи могут совершенно бесплатно получить купон на мой новый модуль TS Купить в 1 клик , там уже попроще, но есть ограничения, читайте все в документации к модулю.
Чтобы получить купон на новый модуль, пришлите на мою почту купон от формы обратной связи, неважно какой, действующий или нет, я вам в ответ отправлю купон от нового модуля.

Установка модуля