Разработка личного кабинета поставщика при дропшиппинге 1С-Битрикс

Наша компания занимается разработкой, поддержкой и обслуживанием решений на Битрикс и Битрикс24 любой сложности. От простых одностраничных сайтов до сложных интернет магазинов, CRM систем с интеграцией 1С и телефонии. Опыт разработчиков подтвержден сертификатами от вендора.
Предлагаемые услуги
Показано 1 из 1 услугВсе 1626 услуг
Разработка личного кабинета поставщика при дропшиппинге 1С-Битрикс
Средняя
~1-2 недели
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1240
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    844
  • 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
    582
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Разработка на базе 1С Предприятие для компании МИРСАНБЕЛ
    749
  • image_crm_dolbimby_434_0.webp
    Разработка сайта на CRM Битрикс24 для компании DOLBIMBY
    657
  • image_crm_technotorgcomplex_453_0.webp
    Разработка на базе Битрикс24 для компании ТЕХНОТОРГКОМПЛЕКС
    981

Разработка личного кабинета поставщика при дропшиппинге 1С-Битрикс

При дропшиппинге поставщик должен видеть заказы, которые относятся именно к его товарам, обновлять остатки и цены, подтверждать отгрузку. Стандартный личный кабинет Битрикс (my) заточен под покупателей. Кабинет поставщика — отдельный раздел с доступом по роли, собственными компонентами и ограниченной видимостью данных.

Модель доступа и роли

В Битрикс разграничение прав реализуется через группы пользователей. Создаём группу «Поставщики» через API или административный интерфейс:

$groupId = CGroup::Add([
    'ACTIVE'  => 'Y',
    'NAME'    => 'Поставщики',
    'STRING_ID' => 'SUPPLIERS',
]);

Привязка конкретного поставщика к его товарам — через HL-блок SupplierProduct или свойство инфоблока. Проще всего — свойство SUPPLIER_ID типа «Привязка к пользователю» (E) у каждого товара. Тогда поставщик видит только товары, у которых SUPPLIER_ID = текущий пользователь.

Раздел кабинета поставщика закрывается через проверку группы:

if (!$USER->IsAuthorized() || !$USER->IsInGroup($supplierGroupId)) {
    LocalRedirect('/auth/?backurl=' . urlencode($_SERVER['REQUEST_URI']));
}

Блок «Мои товары»

Список товаров поставщика с текущим остатком и ценой. Запрос через CIBlockElement::GetList с фильтром по SUPPLIER_ID:

$userId = $USER->GetID();

$res = CIBlockElement::GetList(
    ['NAME' => 'ASC'],
    [
        'IBLOCK_ID'              => CATALOG_IBLOCK_ID,
        'ACTIVE'                 => 'Y',
        'PROPERTY_SUPPLIER_ID'   => $userId,
    ],
    false,
    false,
    ['ID', 'NAME', 'DETAIL_PAGE_URL', 'PREVIEW_PICTURE', 'PROPERTY_SUPPLIER_ID']
);

Для каждого товара показываем текущий остаток из b_catalog_store_product и цену из b_catalog_price:

$quantityRes = CCatalogStoreProduct::GetList(
    [],
    ['PRODUCT_ID' => $productId]
);
$totalQuantity = 0;
while ($qRow = $quantityRes->GetNext()) {
    $totalQuantity += (int)$qRow['AMOUNT'];
}

Форма обновления остатков и цен

Поставщик должен иметь возможность обновить цену и остаток без доступа к административной части. Форма отправляет AJAX-запрос:

// /local/ajax/supplier-update.php
$productId = (int)$_POST['product_id'];
$newPrice  = (float)$_POST['price'];
$newQty    = (int)$_POST['quantity'];

// Проверяем, что товар принадлежит текущему поставщику
$ownerCheck = CIBlockElement::GetProperty(
    CATALOG_IBLOCK_ID,
    $productId,
    'sort',
    'asc',
    ['CODE' => 'SUPPLIER_ID', 'VALUE' => $USER->GetID()]
);

if (!$ownerCheck->Fetch()) {
    echo json_encode(['error' => 'Доступ запрещён']);
    die();
}

// Обновляем цену
CCatalogProduct::Update($productId, []); // обновление без изменения полей продукта
$priceRow = CCatalogPrice::GetList(
    [], ['PRODUCT_ID' => $productId, 'CATALOG_GROUP_ID' => BASE_PRICE_GROUP_ID]
)->Fetch();

if ($priceRow) {
    CCatalogPrice::Update($priceRow['ID'], ['PRICE' => $newPrice, 'CURRENCY' => 'RUB']);
} else {
    CCatalogPrice::Add([
        'PRODUCT_ID'       => $productId,
        'CATALOG_GROUP_ID' => BASE_PRICE_GROUP_ID,
        'PRICE'            => $newPrice,
        'CURRENCY'         => 'RUB',
    ]);
}

// Обновляем остаток на складе поставщика
$storeProductRow = CCatalogStoreProduct::GetList(
    [], ['PRODUCT_ID' => $productId, 'STORE_ID' => getSupplierStoreId($userId)]
)->Fetch();

if ($storeProductRow) {
    CCatalogStoreProduct::Update($storeProductRow['ID'], ['AMOUNT' => $newQty]);
} else {
    CCatalogStoreProduct::Add([
        'PRODUCT_ID' => $productId,
        'STORE_ID'   => getSupplierStoreId($userId),
        'AMOUNT'     => $newQty,
    ]);
}

echo json_encode(['success' => true]);

Каждый поставщик имеет свой склад (b_catalog_store) — это позволяет отслеживать остатки по каждому поставщику независимо.

Блок «Мои заказы»

Поставщик видит только те заказы, в которых есть его товары. Прямой запрос к b_sale_order не подходит — нужна связь через корзину:

$supplierId = $USER->GetID();

$connection = \Bitrix\Main\Application::getConnection();
$orders = $connection->query("
    SELECT DISTINCT
        o.ID,
        o.DATE_INSERT,
        o.PRICE,
        o.STATUS_ID,
        o.USER_ID,
        u.NAME,
        u.LAST_NAME,
        u.EMAIL
    FROM b_sale_order o
    JOIN b_sale_basket b ON b.ORDER_ID = o.ID
    JOIN b_iblock_element_property ep
        ON ep.IBLOCK_ELEMENT_ID = b.PRODUCT_ID
        AND ep.IBLOCK_PROPERTY_ID = " . SUPPLIER_PROP_ID . "
        AND ep.VALUE_NUM = {$supplierId}
    LEFT JOIN b_user u ON u.ID = o.USER_ID
    WHERE o.DATE_INSERT >= DATE_SUB(NOW(), INTERVAL 90 DAY)
    ORDER BY o.DATE_INSERT DESC
    LIMIT 100
");

В детальной странице заказа поставщик видит только позиции корзины, относящиеся к его товарам — не весь заказ:

$basketItems = $connection->query("
    SELECT b.ID, b.NAME, b.QUANTITY, b.PRICE, b.PRODUCT_ID
    FROM b_sale_basket b
    JOIN b_iblock_element_property ep
        ON ep.IBLOCK_ELEMENT_ID = b.PRODUCT_ID
        AND ep.IBLOCK_PROPERTY_ID = " . SUPPLIER_PROP_ID . "
        AND ep.VALUE_NUM = {$supplierId}
    WHERE b.ORDER_ID = {$orderId}
");

Подтверждение отгрузки

Поставщик подтверждает отгрузку своей части заказа. Статус фиксируется в HL-блоке SupplierShipment:

  • UF_ORDER_ID — ID заказа
  • UF_SUPPLIER_ID — ID поставщика
  • UF_STATUSpending / confirmed / shipped / delivered
  • UF_TRACKING — трек-номер
  • UF_DATE_SHIPPED — дата отгрузки

Когда все поставщики заказа установили статус shipped, агент автоматически меняет статус заказа Битрикс на «Отправлен».

Массовая загрузка цен и остатков через CSV

Для поставщиков с большим ассортиментом — форма загрузки CSV-файла:

Артикул;Цена;Остаток
SKU-001;1500;25
SKU-002;2800;10

PHP-обработчик читает CSV через SplFileObject, находит товар по CML2_ARTICLE (свойство артикула), проверяет принадлежность поставщику и обновляет данные. Ограничение на размер файла и количество строк (до 5 000) — чтобы исключить таймаут PHP.

Сроки реализации

Объём Состав Срок
Базовый кабинет (список заказов + обновление остатков) Компоненты + AJAX-форма + роль 1–1.5 недели
Полноценный кабинет (склад, цены, отгрузка, CSV) + загрузка файлов + агент статусов 2–3 недели
Мультиязычный кабинет с аналитикой продаж + отчёты по продажам + i18n 3–4 недели