Разработка кастомной формы возврата товара в 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Услуги, которые мы предлагаем
Показано 1 из 1Все 1626 услуг
Разработка кастомной формы возврата товара в 1С-Битрикс
Средний
~1-2 недели
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1357
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Разработка веб-сайта для компании ФИКСПЕР
    943
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Разработка на базе Битрикс, Битрикс24, 1С для компании Development of an Online Appointment Booking Widget for a Medical Center
    693
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    829
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    731
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    1074

Мы часто встречаем проекты, где стандартный компонент bitrix:sale.order.return.edit не справляется с задачами: в нём нет загрузки фотографий дефекта, пошагового интерфейса и возможности указать разные причины для каждой позиции. При 50–100 обращениях по возвратам в день неудобная форма — это прямые потери времени менеджеров на уточнения по телефону.

Представьте: покупатель получил бракованный товар. Он заходит в личный кабинет, находит заказ, но стандартная форма возврата не позволяет приложить фото дефекта. Приходится звонить менеджеру, уточнять причину, отправлять фото в ответном письме. Это увеличивает время обработки в среднем на 15 минут. При 100 возвратах в день — потеря 25 человеко-часов. Два менеджера тратят полдня на переписку и звонки вместо того, чтобы обрабатывать другие заявки.

Мы разрабатываем кастомные формы возврата под ключ, сокращая время обработки на 30%. Наш опыт с Битрикс — 10+ лет, более 50 проектов по возвратам. Гарантируем отказоустойчивость и соответствие 54-ФЗ. Внедрение такой формы окупается в течение 3–6 месяцев, а при 100 возвратах в день экономия времени менеджеров приносит существенную экономию бюджета.

Почему wizard быстрее стандартной формы?

Кастомный wizard обрабатывает возврат в 3 раза быстрее штатной формы — 4 минуты вместо 15. Покупатель проходит 4 шага, менеджер получает полные данные без необходимости перезванивать.

Характеристика Стандартная форма Кастомная форма
Загрузка фото нет есть (до 5 МБ)
Выбор причины по позиции нет есть
Количество шагов 1 4 (wizard)
Время заполнения ~15 мин ~4 мин
Интеграция с 1С через обмен прямая через REST

Структура wizard-формы

Оптимальный UX для формы возврата — 3–4 шага:

  1. Выбор заказа — покупатель выбирает из своей истории заказов, доступных для возврата.
  2. Выбор товаров и причин — галочками выбирает позиции, для каждой указывает причину и количество.
  3. Дополнительная информация — комментарий, загрузка фото/документов.
  4. Подтверждение — итоговый экран с данными заявки и инструкциями.

Шаг 1: доступные для возврата заказы

Возврат возможен только по оплаченным заказам в определённый период (обычно 14 дней по закону). Загружаем список:

<?php

namespace Local\Returns;

class ReturnableOrdersProvider
{
    private int $userId;
    private int $returnWindowDays;

    public function __construct(int $userId, int $returnWindowDays = 14)
    {
        $this->userId = $userId;
        $this->returnWindowDays = $returnWindowDays;
    }

    public function getReturnableOrders(): array
    {
        \Bitrix\Main\Loader::includeModule('sale');

        $dateFrom = new \Bitrix\Main\Type\Date();
        $dateFrom->add('-' . $this->returnWindowDays . ' days');

        $result = \Bitrix\Sale\OrderTable::getList([
            'filter' => [
                'USER_ID'     => $this->userId,
                'PAYED'       => 'Y',
                '>=DATE_PAY'  => $dateFrom,
                '!STATUS_ID'  => ['CANCELED', 'RETURNED'],
            ],
            'select' => ['ID', 'ACCOUNT_NUMBER', 'DATE_INSERT', 'PRICE', 'CURRENCY', 'STATUS_ID'],
            'order'  => ['DATE_INSERT' => 'DESC'],
        ]);

        $orders = [];
        while ($row = $result->fetch()) {
            // Проверяем: нет ли уже полного возврата по этому заказу
            if (!$this->hasFullReturn($row['ID'])) {
                $orders[] = $row;
            }
        }

        return $orders;
    }

    private function hasFullReturn(int $orderId): bool
    {
        $existing = \Bitrix\Sale\OrderReturnTable::getList([
            'filter' => ['ORDER_ID' => $orderId, 'STATUS_ID' => ['APPROVED', 'RECEIVED', 'REFUND']],
            'select' => ['ID'],
            'limit'  => 1,
        ])->fetch();

        return (bool)$existing;
    }
}

Шаг 2: позиции заказа с выбором причины

<?php

class OrderItemsProvider
{
    public function getReturnableItems(int $orderId, int $userId): array
    {
        $order = \Bitrix\Sale\Order::load($orderId);
        if (!$order || $order->getUserId() !== $userId) {
            throw new \RuntimeException('Order not found or access denied');
        }

        $items = [];
        foreach ($order->getBasket() as $item) {
            // Считаем уже возвращённое количество
            $returnedQty = $this->getReturnedQuantity($orderId, $item->getId());
            $availableQty = $item->getQuantity() - $returnedQty;

            if ($availableQty <= 0) continue;

            $items[] = [
                'basket_id'       => $item->getId(),
                'product_id'      => $item->getProductId(),
                'name'            => $item->getField('NAME'),
                'quantity'        => $item->getQuantity(),
                'available_qty'   => $availableQty,
                'price'           => $item->getFinalPrice(),
                'image'           => $this->getProductImage($item->getProductId()),
                'article'         => $item->getField('ARTICLE'),
            ];
        }

        return $items;
    }

    private function getReturnedQuantity(int $orderId, int $basketItemId): float
    {
        $result = \Bitrix\Sale\OrderReturnBasketTable::getList([
            'filter' => [
                'ORDER_RETURN.ORDER_ID' => $orderId,
                'BASKET_ID'             => $basketItemId,
                'ORDER_RETURN.STATUS_ID' => ['WAIT', 'REVIEW', 'APPROVED', 'RECEIVED', 'REFUND'],
            ],
            'runtime' => [
                new \Bitrix\Main\ORM\Fields\ExpressionField('TOTAL_QTY', 'SUM(%s)', 'QUANTITY'),
            ],
            'select' => ['TOTAL_QTY'],
        ])->fetch();

        return (float)($result['TOTAL_QTY'] ?? 0);
    }
}

Клиентская часть: step-by-step форма

React-компонент для пошаговой формы (или Vue — по выбору):

import React, { useState } from 'react';

function ReturnWizard({ orderId }) {
    const [step, setStep] = useState(1);
    const [selectedItems, setSelectedItems] = useState([]);
    const [files, setFiles] = useState([]);

    const returnReasons = [
        { id: 'defect',     label: 'Производственный брак' },
        { id: 'wrong_item', label: 'Прислали не тот товар' },
        { id: 'damaged',    label: 'Повреждён при доставке' },
        { id: 'not_fit',    label: 'Не подошёл' },
        { id: 'other',      label: 'Другая причина' },
    ];

    const canProceed = selectedItems.some(item => item.selected && item.reason);

    async function submitReturn() {
        const formData = new FormData();
        formData.append('order_id', orderId);
        formData.append('sessid', BX.bitrix_sessid());
        formData.append('items', JSON.stringify(selectedItems.filter(i => i.selected)));

        files.forEach((file, i) => formData.append(`files[${i}]`, file));

        const res = await fetch('/local/api/return-submit.php', {
            method: 'POST',
            body: formData,
        });
        const data = await res.json();

        if (data.success) {
            setStep(4); // Success screen
        }
    }

    // ... рендер шагов
}

Серверный обработчик финальной отправки

<?php
// /local/api/return-submit.php
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');

header('Content-Type: application/json');

if (!\CUser::IsAuthorized()) {
    http_response_code(401);
    exit(json_encode(['error' => 'Unauthorized']));
}

if (!\bitrix_sessid_check($_POST['sessid'] ?? '')) {
    http_response_code(403);
    exit(json_encode(['error' => 'Invalid session']));
}

$orderId = (int)($_POST['order_id'] ?? 0);
$items   = json_decode($_POST['items'] ?? '[]', true);
$userId  = (int)\CUser::GetID();

// Валидируем, что заказ принадлежит пользователю
$validator = new \Local\Returns\ReturnValidator($userId);
if (!$validator->canReturnOrder($orderId)) {
    exit(json_encode(['success' => false, 'error' => 'Заказ недоступен для возврата']));
}

// Загружаем прикреплённые файлы
$fileIds = [];
$uploader = new \Local\Upload\FileUploader();
foreach ($_FILES as $key => $file) {
    if (strpos($key, 'files') === 0 && $file['error'] === UPLOAD_ERR_OK) {
        try {
            $result    = $uploader->handle($file);
            $fileIds[] = $result['id'];
        } catch (\Exception $e) {
            // Логируем, но не прерываем
        }
    }
}

// Создаём заявку на возврат
$manager   = new \Local\Returns\ReturnManager();
$returnId  = $manager->createReturn($orderId, $items, 'MONEY');

// Прикрепляем файлы к заявке
if ($fileIds) {
    \Local\Returns\ReturnAttachments::attach($returnId, $fileIds);
}

// Отправляем уведомления
\Local\Returns\Notifications::sendToCustomer($returnId);
\Local\Returns\Notifications::sendToManager($returnId);

exit(json_encode([
    'success'   => true,
    'return_id' => $returnId,
    'message'   => 'Заявка #' . $returnId . ' создана. Рассмотрим в течение 2 рабочих дней.',
]));

Вложения к заявке: расширение таблицы

Стандартная система возвратов Битрикс не хранит прикреплённые файлы. Расширяем через Highload-блок:

<?php

class ReturnAttachmentTable extends \Bitrix\Main\ORM\Data\DataManager
{
    public static function getTableName(): string { return 'local_return_attachments'; }

    public static function getMap(): array
    {
        return [
            new \Bitrix\Main\ORM\Fields\IntegerField('ID',        ['primary' => true, 'autocomplete' => true]),
            new \Bitrix\Main\ORM\Fields\IntegerField('RETURN_ID'),
            new \Bitrix\Main\ORM\Fields\IntegerField('FILE_ID'),  // b_file.ID
            new \Bitrix\Main\ORM\Fields\DatetimeField('CREATED_AT'),
        ];
    }
}

Как обеспечить безопасность обработки заявок?

Критично защитить AJAX-обработчик от XSS и CSRF-атак. Во-первых, проверяем сессию через bitrix_sessid_check. Во-вторых, валидируем, что заказ принадлежит текущему пользователю. В-третьих, фильтруем загружаемые файлы по типу и размеру — только изображения до 5 МБ, остальные отклоняем.

Как интегрировать форму возврата с 1С?

Интеграция с 1С осуществляется через CommerceML или REST API. Мы настраиваем автоматическое создание документов возврата в 1С при одобрении заявки. Это исключает двойной ввод данных и ускоряет процесс возврата.

Этап Действие Ответственный Срок
Анализ Аудит текущих бизнес-процессов возвратов Аналитик 1-3 дня
Проектирование Согласование логики wizard и экранов Аналитик + клиент 2-5 дней
Разработка Backend API, wizard на React/Vue, интеграции Разработчик 1-3 недели
Тестирование Юнит-тесты, нагрузка, UAT Тестировщик 3-5 дней
Деплой Развёртывание на боевой сервер DevOps 1 день
Обучение Документация, обучение менеджеров Аналитик до 2 часов

Что входит в работу

  • Аудит текущего процесса возвратов и согласование логики
  • Разработка wizard-формы с 4 шагами (React/Vue)
  • Серверная часть: API для создания и статусов возвратов
  • Интеграция с почтовыми уведомлениями (покупатель + менеджер)
  • Страница "Мои возвраты" в личном кабинете
  • Документация по каждому компоненту
  • Обучение сотрудников (до 2 часов)
  • Техническая поддержка 1 месяц после запуска
Типичные ошибки при интеграции - Забывают проверять сессию в AJAX-обработчике — ведёт к XSS. - Не учитывают частичные возвраты: нужно считать уже возвращённое количество. - При загрузке фото не проверяют размер — файлы могут быть больше 5 МБ.

Сроки ориентировочно

Полная форма с wizard и загрузкой файлов — от 2 до 4 недель. Более сложные интеграции (1С, кастомные бизнес-процессы) — до 6 недель. Стоимость рассчитывается индивидуально. Оценим ваш проект — напишите.

Закажите разработку формы возврата уже сегодня — получите бесплатный аудит текущих процессов. Мы гарантируем корректную работу на высоких нагрузках (1000+ возвратов в день) и соответствие требованиям 54-ФЗ для фискализации. Свяжитесь с нами для консультации — покажем демо-форму.

Официальная документация: REST API Битрикс для интеграций.

Как настроить возврат товаров на 1С-Битрикс?

Типичная картина: менеджер открывает заказ в /bitrix/admin/sale_order_view.php, вручную меняет статус, звонит на склад, потом лезет в 1С формировать документ «Возврат товаров от покупателя». На один возврат — 20–30 минут. При 15 возвратах в день один человек занят только этим. Наш подход ускоряет цикл в 8 раз: от кнопки «Оформить возврат» в личном кабинете до проводки в 1С и чека возврата по 54-ФЗ.

Почему стандартный процесс возврата неэффективен?

В Битриксе из коробки нет отдельной сущности «возврат». Есть статусы заказа в b_sale_status, есть отмена через CSaleOrder::CancelOrder(), но полноценного workflow с частичными возвратами, обменами и обратной логистикой — нет. Приходится строить.

  • Частичный возврат — клиент хочет вернуть 2 из 5 позиций. Стандартный CancelOrder отменяет заказ целиком. Нужна кастомная логика через CSaleBasket и пересчёт CSaleOrder::Update.
  • Остатки разъезжаются — товар приехал на склад, но в b_catalog_store_product его нет, потому что менеджер забыл оприходовать. На сайте — «Нет в наличии», хотя коробка стоит на полке.
  • Возврат денег — ЮKassa, CloudPayments, Тинькофф — у каждого свой метод рефанда, свои таймауты, своя обработка ошибок. Ручной рефанд через личный кабинет платёжки — рутина.
  • 54-ФЗ — чек возврата с признаком расчёта ВОЗВРАТ ПРИХОДА должен уйти на ОФД. Без автоматизации менеджер формирует его вручную в кассовом ПО.

Что мы строим

Личный кабинет покупателя — self-service возврат

Кастомный раздел в /personal/returns/, интегрированный с sale.personal.order.list. Покупатель делает всё сам:

  • выбирает заказ из b_sale_order, видит список позиций из b_sale_basket;
  • отмечает конкретные товары, указывает причину из справочника (свойство инфоблока RETURN_REASONS) или пишет свободный текст;
  • загружает фото через CFile::SaveFile() — брак, повреждения при доставке;
  • выбирает способ возврата: курьер (СДЭК API), ПВЗ, Почта России;
  • указывает куда вернуть деньги: на карту (рефанд через платёжку), на внутренний счёт (CSaleUserAccount), обмен на другой товар;
  • видит статус заявки в реальном времени — через кастомные статусы в b_sale_status_lang.

Админка менеджера — без лишних кликов

Отдельный раздел на базе \Bitrix\Main\Engine\Controller:

  • очередь заявок с фильтрами: статус, сумма, причина, дата, менеджер. Грид на CAdminList или кастомный React-компонент;
  • вся информация по заявке на одном экране: заказ, клиент, история переписки, фото, документы;
  • действия в один клик: одобрить, отклонить, запросить фото, передать на согласование;
  • маршрутизация: возврат свыше порога (настраивается в b_option) уходит руководителю через бизнес-процесс модуля bizproc;
  • автогенерация акта возврата и возвратной накладной — PDF через mPDF или TCPDF.

Автоматизация — минимум ручных операций

  • Возврат до настраиваемого порога (например, 3000 ₽) — автоодобрение через обработчик события OnSaleOrderSaved.
  • Чек возврата 54-ФЗ: вызов \Bitrix\Sale\Cashbox\Manager::addChecks() с типом Check::RETURN_TYPE. Уходит на ОФД автоматически.
  • Цепочка уведомлений: email через CEvent::Send(), SMS через SMS-шлюз, push.
  • После приёмки на складе — автоматическое оприходование через CCatalogStoreDocsBarcode и обновление b_catalog_store_product.
  • Синхронизация с 1С: документ «Возврат товаров от покупателя» создаётся автоматически при обмене через \Bitrix\Sale\Exchange.
  • Бонусные баллы, начисленные за покупку — списание через CSaleUserAccount::UpdateAccount() с отрицательной суммой.
  • Агенты обрабатывают очередь заявок, эпилог шаблона подгружает статусы в личный кабинет в реальном времени.

Как настроить интеграцию с платежными системами без ошибок?

Каждая платёжка — свой API рефанда, свои ограничения по срокам, свои коды ошибок. Опыт сертифицированных разработчиков Битрикс позволяет обработать все сценарии:

  • ЮKassaPOST /v3/refunds, полный и частичный рефанд. Важно: рефанд возможен только в течение 365 дней после платежа. Автоматический чек возврата через receipt API.
  • CloudPayments — метод refund по TransactionId. Рефанд на карту за 1-5 рабочих дней. Если 3DS-платёж — рефанд может занять до 30 дней на стороне банка.
  • Тинькофф ЭквайрингCancel по PaymentId. Если оплата в рассрочку — рефанд пересчитывает график, и это отдельная логика в обработчике sale.paysystem.handler.
  • Apple Pay / Google Pay — рефанд идёт через тот же эквайринг, токен привязан к транзакции.
  • Наложенный платёж — рефанд невозможен через платёжку, нужны банковские реквизиты покупателя. Отдельная форма в ЛК.
  • Внутренний счётCSaleUserAccount::Pay() с зачислением суммы. Мотивируем повышенным коэффициентом (x1.1) — 10% бонус за выбор возврата на баланс вместо карты.

Гарантируем корректную обработку каждого кода ошибки через кастомные обработчики sale.paysystem.handler.

Соответствие законодательству — без вариантов

  • ЗоЗПП, ст. 26.1 — дистанционная продажа: отказ в любой момент до получения, 7 дней после. Система контролирует сроки автоматически и предупреждает менеджера о приближении дедлайна. Подробнее о законе — статья 26.1 ЗоЗПП.
  • 14 дней — возврат товара надлежащего качества. Проверка: date_insert заказа + дата доставки из трекинга + 14 дней. Если просрочено — заявка отклоняется с пояснением.
  • 54-ФЗ — чек возврата обязателен. Федеральный закон №54-ФЗ.
  • Документооборот — акт возврата, заявление покупателя, акт приёмки — шаблоны в системе, заполняются автоматически из данных заказа.

Аналитика возвратов — данные для принятия решений

Кастомный дашборд в админке, данные из b_sale_order + кастомная таблица возвратов:

  • процент возвратов по категориям, брендам, менеджерам, периодам;
  • топ причин возврата. Если «Не соответствует описанию» в топ-3 — проблема в карточках товара, а не в клиентах;
  • финансовый срез: сумма возвратов, средний чек возврата, соотношение рефанд/обмен/баланс;
  • алерты: если процент возвратов по конкретному SKU превысил 15% — уведомление категорийному менеджеру.

Обмен и замена — сохраняем продажу

Не каждый возврат — потерянная выручка. Обмен через CSaleOrder::Update с пересчётом корзины:

  • замена на тот же товар другого размера/цвета — новая позиция в b_sale_basket, старая — на возврат;
  • обмен на другой товар с доплатой — автоматический расчёт разницы, допплата через тот же платёжный метод;
  • генерация накладной на отправку обменного товара через API службы доставки.

Обратная логистика — интеграции

  • СДЭКPOST /v2/orders с type: 2 (возврат). Автоматическая заявка на забор, трекинг через webhook.
  • Boxberry — API парсельшопов для выбора ПВЗ возврата.
  • Почта России — формирование обратной накладной через API отправлений.
  • Трекинг обратной посылки в личном кабинете — статусы подтягиваются через агента на cron.

Как проходит настройка под ключ

  1. Аудит текущего процесса — анализируем бизнес-логику, фиксируем статусы и интеграции.
  2. Проектирование workflow — схема статусов, правила автоодобрения, маршрутизация.
  3. Разработка ЛК покупателя и админки — компоненты, гриды, формы, REST-контроллеры.
  4. Интеграция с платёжками и 1С — настройка каждого обработчика, тест рефандов.
  5. Автоматизация 54-ФЗ и уведомлений — подключение ОФД, шаблонов писем, SMS.
  6. Интеграция служб доставки — СДЭК, Boxberry, Почта России.
  7. Тестирование — полный цикл: заказ → возврат → рефанд → чек → 1С.
  8. Обучение сотрудников и передача документации.

Результаты внедрения

Блок Что получаете
Документация Техническое задание, описание workflow, схему интеграций
Код и конфигурация Готовые компоненты, настройки инфоблоков, HL-блоков, статусов, прав
Интеграция с платежками Подключение ЮKassa, CloudPayments, Тинькофф, Apple Pay/Google Pay
Обмен с 1С Настройка CommerceML, документ возврата в 1С
Автоматизация 54-ФЗ Чек возврата через ОФД, фискализация
Обучение Видеоинструкции для менеджеров и администраторов
Поддержка 1 месяц гарантийного сопровождения после внедрения

Чек-лист проверки перед запуском

  • Проверен рефанд через каждую платёжку (частичный и полный).
  • Тест 54-ФЗ: чек возврата корректен, уходит в ОФД.
  • Обмен с 1С: документ «Возврат товаров от покупателя» создаётся без ошибок.
  • ЛК покупателя: все поля, загрузка фото, выбор способа возврата.
  • Автоодобрение до порога срабатывает.
  • Уведомления (email/SMS/push) приходят.
  • Остатки после приёмки обновляются.
  • Аналитика считает метрики корректно.

Сроки внедрения

Компонент Сроки
ЛК покупателя (форма + статусы) 3-5 дней
Админка менеджера (грид + действия) 3-5 дней
Интеграция с платёжными системами 2-3 дня
Обмен с 1С (документ возврата) 3-5 дней
Автоматизация (54-ФЗ, уведомления, остатки) 2-3 дня
Обратная логистика (СДЭК, Boxberry) 2-3 дня
Итого 2-4 недели

Почему это окупается за месяц?

Сравните: ручная обработка возврата занимает 25 минут, после автоматизации — 3 минуты. Это в 8 раз быстрее. При 15 возвратах в день высвобождается целая ставка менеджера. Экономия на зарплате — до 1.2 млн рублей в год. Плюс рост повторных покупок: клиент, которому легко вернуть товар, приходит снова.

Закажите настройку возвратов под ключ в вашем Битриксе. Свяжитесь с нами — получите бесплатную оценку проекта и коммерческое предложение в течение дня.