MAATRIX / Блог / Комиссионка: каждый товар в одном экземпляре — почему обычная товароучётка не годится

Комиссионка: каждый товар в одном экземпляре — почему обычная товароучётка не годится

MAATRIX

Владелец комиссионного магазина рано или поздно пробует поставить обычную товароучётную программу — ту же, что стоит у соседнего продуктового или у знакомого, торгующего одеждой оптом. И упирается в стену: система хочет знать артикул и количество на складе, а у него на складе сто пятьдесят вещей, и ни одна не повторяет другую. Диван от одной сдатчицы, три одинаковых на вид, но разных по состоянию куртки от трёх разных людей, кольцо, которое нельзя продать без согласия владельца после истечения срока хранения. Ниже — почему стандартная логика «товар + остаток» здесь не работает, и как вместо неё выстроить учёт по единичным позициям на собственном сервере.

Почему модель SKU и остатков не подходит комиссионке

В обычной рознице артикул — это абстракция. Условная «футболка модель X, размер M, цвет синий» существует в десяти экземплярах, и системе всё равно, какой именно из десяти уедет покупателю: они взаимозаменяемы. Списали один — остаток уменьшился на единицу, вещь как физический объект программу не интересует.

В комиссионке взаимозаменяемости нет в принципе. Даже если на витрине стоят две одинаковые на первый взгляд лампы, это две разные лампы: у них разные сдатчики, разная цена приёма, разный процент комиссии, возможно разное состояние (у одной скол на основании, у другой нет), и, что важнее всего, у каждой свой персональный срок — когда магазин обязан либо продать её, либо вернуть, либо связаться с комитентом по поводу уценки. «Остаток: 2 шт.» в этой ситуации не просто бесполезен — он стирает информацию, без которой бизнес не может работать: кому вернуть деньги за проданную лампу и кому отдать нераспроданную.

Отсюда и вырастает вся остальная разница. Обычная товароучётка проектировалась вокруг таблицы «товар — количество — цена», и всё, что вокруг неё построено (отчёты, справочники, интерфейс приёмки, штрихкоды), исходит из того, что одна карточка = один вид товара, а не одна карточка = один физический объект с собственной судьбой. Попытка «натянуть» такую систему на комиссионку заканчивается предсказуемо: каждая вещь заводится отдельной позицией с уникальным «артикулом» вроде названия и порядкового номера, поле «количество» у неё всегда равно 1, а всё остальное — кто сдал, когда истекает срок, какой процент — либо не помещается никуда и живёт в тетради или экселе рядом, либо втискивается в поля, для этого не предназначенные (например, комитента пишут в примечание, а срок хранения держат в уме или на бумажной бирке).

Что должно быть в карточке каждой вещи

Если строить учёт правильно — с прицелом именно на комиссионную модель, а не на розничную — карточка единицы товара должна нести на себе весь набор данных, специфичных для комиссии, а не только «название и цена»:

  • Комитент — кто сдал вещь: ФИО, контакты, реквизиты для выплаты (карта или наличные), у некоторых магазинов — паспортные данные, если это требуется по внутреннему договору комиссии.
  • Дата и условия приёма — когда вещь поступила, кто принимал, в каком состоянии (желательно с фото).
  • Цена продажи и процент комиссии — сколько магазин оставляет себе, сколько причитается комитенту; процент нередко плавающий (зависит от категории товара, суммы или договорённости с конкретным сдатчиком).
  • Срок хранения — дата, после которой магазин обязан либо продать по сниженной цене, либо вернуть вещь, либо списать невостребованное по условиям договора.
  • График уценки — во многих комиссионках цена не фиксирована на весь срок: не продалось за две недели — минус 10%, ещё через две — ещё минус, и так до минимальной планки или до истечения срока.
  • Статус — принята / на витрине / продана / возвращена комитенту / списана / в резерве под покупателя.
  • История движения — кто и когда менял цену, статус, кто выдал вещь при возврате.

Это ровно тот набор полей, которого нет в стандартной товароучётке, потому что там нет самого понятия «комитент» и «срок хранения конкретной единицы» — есть только товар и его остаток. Дописать эти поля поверх чужой системы обычно либо невозможно (закрытая структура данных), либо возможно ценой танцев с надстройками и внешними таблицами, которые постоянно расходятся с основной базой.

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Срок хранения и уценка — где чаще всего теряются деньги

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

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

Практическое решение здесь простое технически, но невозможное без правильной модели данных: у каждой вещи в базе есть storage_deadline и, если нужно, промежуточные даты уценки. Ежедневная задача (обычный cron на сервере) проходит по таблице и:

-- вещи, которым завтра пора планово уцениться
SELECT id, name, consignor_id, current_price
FROM items
WHERE status = 'on_sale'
  AND next_markdown_date = CURRENT_DATE + INTERVAL '1 day';

-- вещи, у которых истёк срок хранения и нет решения по ним
SELECT id, name, consignor_id, storage_deadline
FROM items
WHERE status = 'on_sale'
  AND storage_deadline < CURRENT_DATE;

Результат такого запроса можно превратить в список для продавца на утро или в автоматическое SMS/сообщение комитенту («ваша вещь не продана, срок хранения истекает такого-то числа, заберите или согласуйте уценку»). Это ровно тот класс задач, который обычная товароучётка не покрывает, потому что у неё нет ни поля под срок хранения конкретной единицы, ни механизма графика уценки, привязанного к дате приёма именно этой вещи.

Расчёты с комитентом: почему это не про остатки, а про движение по каждой позиции

В обычной рознице бухгалтерия смотрит на обороты по товарным группам. В комиссионке ключевая финансовая операция — это выплата конкретному человеку за конкретную проданную вещь, и таких выплат может быть десятки в неделю, каждая — по своим правилам (проценту, способу расчёта, иногда с удержанием за хранение сверх срока).

Комитенту, в отличие от поставщика в обычной рознице, не всё равно, что именно продалось и когда — он ждёт звонка или уведомления именно по своей вещи. Без системы, которая ведёт учёт по единичным позициям, эта связка «вещь → комитент → сумма к выплате → дата выплаты» держится на памяти продавца и бумажных расписках, и при текучке персонала или банальной невнимательности комитентам либо не доплачивают, либо забывают про них вовсе — что не только теряет деньги, но и подрывает доверие: сарафанное радио в этой нише работает в обе стороны.

Правильная модель — простая бухгалтерская книга движений, привязанная к позиции:

CREATE TABLE movements (
  id            SERIAL PRIMARY KEY,
  item_id       INT REFERENCES items(id),
  event_type    TEXT NOT NULL,   -- 'accepted', 'price_cut', 'sold', 'returned', 'written_off'
  amount        NUMERIC(10,2),
  occurred_at   TIMESTAMPTZ DEFAULT now(),
  comment       TEXT
);

Продажа вещи автоматически создаёт запись sold с суммой, из которой система тут же считает долю комитента по проценту, зафиксированному в карточке этой конкретной вещи (а не общему проценту «по товарной группе», как это чаще всего пытается сделать обычная товароучётка, если её вообще заставить работать с процентными выплатами). Ежемесячный или еженедельный отчёт по комитенту — это просто выборка движений sold за период с суммой к выплате, которую иначе пришлось бы вручную собирать по бумажным квитанциям и памяти.

Особенности чека и учёта при комиссионной торговле

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

Практически для системы учёта это значит одно: продажа вещи должна одним действием — нажатием кнопки «продано» на карточке конкретной позиции — тянуть за собой сразу несколько операций: списание вещи со статуса «на витрине», фиксацию суммы в движениях, расчёт доли комитента и (через интеграцию с кассой или фискальным регистратором) формирование корректного чека. Когда это разнесено по разным несвязанным системам — одна касса, другая тетрадь учёта вещей, третий блокнот с процентами, — расхождения между ними появляются регулярно, и найти их постфактум почти невозможно, потому что нет единого источника истины по конкретной вещи.

Если комитент — физическое лицо и с ним заключается договор с указанием паспортных данных для последующих расчётов, эти данные — персональные данные в смысле 152-ФЗ, и их хранение на своём сервере, а не в облачном сервисе неизвестно где, — вполне осмысленный довод в пользу собственной инфраструктуры; подробнее о требованиях к месту хранения таких данных — в отдельном материале про 152-ФЗ простыми словами.

Своя система вместо чужой товароучётки: как это выглядит на практике

Идея не в том, чтобы писать сложную ERP-платформу с нуля — для магазина с несколькими сотнями активных позиций достаточно небольшого веб-приложения на своём сервере, спроектированного вокруг правильной единицы учёта: не «товар», а «конкретная физическая вещь». Минимальный практический набор:

  • База данных — PostgreSQL с примерно такой структурой: consignors (комитенты), items (единичные позиции со всеми полями из раздела выше), movements (движения/выплаты), photos (ссылки на фото каждой вещи).
  • Веб-интерфейс приёмки — форма, где продавец на месте вносит вещь: комитент (выбор из справочника или создание нового), фото с телефона или планшета, цена, процент, срок хранения по умолчанию (например, 60 дней) с возможностью скорректировать вручную.
  • Уникальная маркировка каждой единицы — не штрихкод товарной позиции (его в комиссионке просто нет, повторюсь: одна вещь не равна артикулу), а внутренний номер, который печатается на бирке при приёме — обычный QR или штрихкод, генерируемый на сервере (python-barcode, qrcode или аналогичные библиотеки — задача типовая, тут не нужно ничего экзотического) и привязанный именно к этой физической вещи, а не к «модели товара».
  • Хранилище фото — файлы или объектное S3-совместимое хранилище (например, MinIO) на том же сервере: по каждой вещи желательно 2–4 фото при приёме, это и защита от споров о состоянии, и материал для карточки товара на сайте или в соцсетях, если магазин продаёт удалённо.
  • Ежедневные задачи — cron-скрипт, который проверяет сроки хранения и графики уценки и формирует список для продавца или рассылку комитентам.
  • Резервное копирование — база данных с историей приёмки, продаж и выплат комитентам критична для бизнеса не меньше, чем бухгалтерия; регулярный бэкап на отдельное хранилище — обязательное условие, а не опция «когда-нибудь настроим». Как это сделать без изобретения велосипеда, разобрано в материале про установку и настройку borgbackup на VPS.

По объёму такая система для магазина среднего размера не требует мощного сервера — узкое место здесь не процессор, а дисковое пространство под фотографии и предсказуемая доступность: сервер не должен «падать» в момент, когда продавец принимает вещь у клиента, стоящего у прилавка. Похожий подход — небольшое собственное веб-приложение вместо подписки на готовый чужой сервис под специфику конкретной ниши — разобран и в материале про CRM автосервиса: подписка против своего сервера, и в статье про самописную CRM риелтора на своём сервере — там та же логика: типовое ПО не заточено под нишу, и дешевле один раз собрать своё под реальный процесс, чем годами доплачивать за подписку и жить с полем «остаток», которое не отражает суть вашего бизнеса.

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

Нужен сервер под эту задачу?

Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.

Арендовать сервер

Нужны сами нейросети для контента?

Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.

Частые вопросы

Можно ли обойтись Excel-таблицей вместо отдельной системы?

На первых полусотне вещей — да, но таблица не умеет напоминать о сроках хранения, не защищена от случайного удаления строки с активной вещью и не масштабируется на нескольких продавцов одновременно без конфликтов правок. Как временное решение на старте — рабочий вариант, как постоянная система для растущего магазина — нет.

Что если часть вещей всё-таки повторяется, например одинаковые новые товары от одного поставщика вперемешку с комиссионными вещами?

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

Нужно ли обязательно фотографировать каждую вещь при приёме?

Формально не всегда обязательно, но на практике фото — самый дешёвый способ закрыть споры о состоянии вещи при возврате или претензии от комитента, и при уже настроенной системе это лишние 20–30 секунд на приёмку, а не отдельный процесс.

Что делать с историей после закрытия сделки — продажи или возврата?

Не удалять, а переводить в статус «архив»: движения по вещи остаются в базе для отчётности перед комитентом и на случай спора уже после того, как вещь покинула магазин.

Стоит ли переносить существующий архив бумажных записей в новую систему сразу целиком?

Обычно нет смысла оцифровывать всю историю — достаточно завести в системе то, что физически ещё на витрине или на хранении, а старые закрытые сделки оставить в бумажном архиве как есть.

Обсудить статью, задать вопрос или начать новую тему

Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.

Перейти в сообщество →