food-market/docs/moysklad-logic-audit.md
nns e5bbd4a047
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
docs: аудит против МойСклада — проход 2 (факт-проверки, Казахстан)
Дополнен docs/moysklad-logic-audit.md (+ .html) разделом «Проход 2»:
- Все «проверить» закрыты фактом (код файл:строка и/или запрос на стенде):
  возврат→ReferenceSaleId; Z-отчёт без «по товарам»; долг поставщику считается
  (MoneyReportsController:120-183); обязательные поля товара Name+Unit+Group;
  приёмка с телефона/терминалы/фискализация — нет; отмена проведения ЕСТЬ у всех
  документов (исправление прохода 1); смена — только ручное открытие.
- Себестоимость: подтверждён FIFO у МойСклада; у нас средняя; реальный пример Демо
  (BIOBLAS, Product.Cost=548.6441 из 3 приёмок) — показано искажение прибыли.
- Казахстан (новое): фискализация ОФД РК (заглушка у нас; МойСклад — WebKassa/reKassa),
  НДС 16% с 2026 (дефолт KZ уже 16, SystemReferenceSeeder:38), маркировка ИС МПТ
  (только флаг IsMarked), СНТ/ЭСФ, акциз. Блок «Казахстан — обязательное по закону».
- Сводка обновлена: топ-15 скорректирован (фискализация/маркировка РК вместо неверных
  пунктов), добавлен KZ-блок. Касса МойСклад vs наша — по функциям кассира.

Только отчёт, без правок кода.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:21:57 +05:00

58 KiB
Raw Blame History

Аудит логики процессов против МойСклада

Задача: сверить логику всех процессов нашей системы (ALL MARKET) с МойСкладом — эталоном, над которым «люди думали годами». Только отчёт; исправления — отдельными задачами после решения владельца. Дата: 08.10.2026.

Подход (по требованию владельца): по каждому процессу — (1) как у МойСклада (база, по умолчанию делаем так же), (2) слабые места МойСклада, (3) предложение «как лучше у нас» только там, где есть реальная выгода для магазина — помечено [НА РЕШЕНИЕ ВЛАДЕЛЬЦА]. Без решения владельца реализуем как в МойСкладе.

Источники: dev.moysklad.ru/doc/api/remap/1.2 (API, JS-рендер), support.moysklad.ru (UI-логика), moysklad.ru/poleznoe (школа торговли), отзывы/обзоры. Ссылки — в строках таблиц и в конце. Наши ссылки — файл:строка в репозитории.

Серьёзность: 🔴 высокая — влияет на остатки/деньги/отчёты; 🟡 средняя — UX/логика; ⚪ низкая — название поля/косметика.


0. Корневая причина (почему так вышло)

Процессы реализовывались «по месту», без предварительной сверки с МойСкладом, а затем тесты (full-chain, unit) закрепляли уже написанное поведение как эталон. В результате ряд процессов отличается от отраслевой нормы МойСклада. Самый яркий пример — инвентаризация: документ сам двигает остатки и встаёт в статус «Проведено» без Оприходования/Списания (InventoriesController + InventoryStatus.Posted), чего в МойСкладе нет.


СВОДКА ДЛЯ ВЛАДЕЛЬЦА

Топ-15 расхождений высокой серьёзности (🔴)

# Процесс Расхождение Объём исправления
1 Себестоимость У нас скользящее среднее (MovingAverageCost), у МойСклада — FIFO по партиям Большой (партийный учёт + пересчёт отчётов)
2 Прибыльность COGS берётся как текущая Product.Cost (приближение), а не себестоимость на момент продажи Большой (следствие п.1; нужны партии/снимок COGS)
3 Инвентаризация Сама двигает остатки и статус «Проведено» без Оприходования/Списания Средний (переделка уже в очереди — см. §4)
4 Себестоимость продажи В движение продажи пишется UnitCost = цена продажи, а не себестоимость (DemandsController:270) Средний (писать снимок себестоимости)
5 Фискализация РК Касса не фискализирует чеки у ОФД (онлайн-ККМ РК) — NullFiscalProvider-заглушка; по закону РК розница обязана Средний–большой (интеграция Webkassa/reKassa)
6 Статусы документов «Проведено/Черновик» не всегда соответствуют модели МойСклада (у инвентаризации — ошибочно) Средний
7 «Создать на основании» Нет сквозного механизма создания документов «на основании» со ссылками (приёмка→возврат, инвент.→опр/спис, продажа→возврат) Средний–большой
8 Связи документов Не хранятся/не показываются обратные связи «на основании №…» и блок «Связанные документы» Средний
9 Момент фиксации себестоимости Себестоимость меняется задним числом при новых приёмках (скользящее среднее), искажая прошлые отчёты Большой (следствие п.1)
10 Возврат покупателя: себестоимость При возврате товар возвращается на склад — по какой себестоимости (FIFO-слой vs средняя) не определено строго Средний
11 Партийный учёт Отсутствует (нет партий/слоёв прихода) — блокирует FIFO, сроки годности, точный COGS Большой
12 Перемещение и себестоимость При перемещении между складами себестоимость должна переноситься по FIFO-слоям Средний (зависит от п.11)
13 Маркировка товаров РК Нет вывода кода из оборота (ИС МПТ) при продаже табак/обувь/лекарств — только флаг IsMarked; обязательно по закону РК Большой
14 Оприходование/Списание: цена Должны брать учётную себестоимость (FIFO), у нас — переданный UnitCost/средняя Средний
15 Розничная смена: авто-открытие В МойСкладе смена открывается автоматически первой продажей (≤24ч); у нас только ручное открытие (CashShiftsController Open/Close, продажа требует открытой смены) Малый–средний

Топ-10 предложений «лучше, чем МойСклад» (все [НА РЕШЕНИЕ ВЛАДЕЛЬЦА])

# Идея Выгода магазину Объём
1 Инвентаризация в один клик «Применить результаты» (сразу оба документа проведены) Меньше шагов, чем 2 кнопки МойСклада Малый (в рамках переделки §4)
2 Простой режим прячет Оприходование/Списание как отдельные пункты — они создаются только из инвентаризации/приёмки Меньше путаницы у маленького магазина Малый
3 Себестоимость: выбор метода (средняя — проще/быстрее для мелкой розницы, FIFO — точнее) Гибкость; средняя дешевле по вычислениям Средний
4 Единый экран «Деньги»: внесение/выплата/оплаты в одном реестре без 4 типов документов Проще, чем ПКО/РКО/вх/исх платёж Средний
5 Автосоздание возврата поставщику прямо из приёмки с преднабором строк Быстрее оформить брак Малый
6 Касса: подсказка «нет на остатке» мягкая (не блок), с быстрым оприходованием Не стопорит продажу в рознице Малый
7 Онбординг-мастер «первая приёмка за 2 минуты» (у МойСклада онбординг тяжелее) Быстрый старт Средний
8 Весовой штрихкод из коробки с настройкой префиксов (уже есть у нас — довести) Для продуктовых — критично Малый
9 Отчёт «Прибыль» сразу на дашборде простого режима Владелец видит главное без отчётов Малый
10 Понятные статусы на русском без «проведено» (Черновик→Завершён/Проведён с пояснением) Меньше вопросов «что это значит» Малый

🇰🇿 Казахстан — обязательное по закону (добавлено проходом 2)

Отдельный блок: это не «лучше/хуже», а требования закона РК, без которых магазин не может легально работать. Детали и ссылки — в §6 ниже.

# Требование РК Что нужно рознице Наш статус Срочность
K1 Фискализация (онлайн-ККМ + ОФД РК) каждый чек фискализируется у ОФД (новый протокол ККМ v2.0.3 с 01.04.2026) ❌ заглушка NullFiscalProvider 🔴 блокер для продаж
K2 НДС 16% (с 01.01.2026; было 12%), льгота 5% на лекарства ставка НДС и её учёт в чеке/отчётах ✅ дефолт KZ = 16 (SystemReferenceSeeder.cs:38); нет переходной логики 12→16 по дате оборота 🟡
K3 Маркировка (ИС МПТ): табак, обувь, лекарства (+пиво/одежда 2026–2027) при продаже — сканировать и вывести код из оборота ❌ только флаг IsMarked, вывода нет 🔴 если продаёт эти категории
K4 СНТ/ЭСФ (сопроводительные накладные) для рознице в основном автоматически; подтверждение обязательно по подакцизным ❌ нет интеграции с ИС ЭСФ 🟡 (🔴 если подакцизные)
K5 Акциз/подакцизные (табак, алкоголь) учёт + подтверждение СНТ при приёмке ❌ нет отметки «подакцизный» 🟡

Для маленького продуктового магазина в первую очередь: K1 (фискализация — иначе нельзя пробивать чеки) → K3 (маркировка, если продаёт сигареты) → K2 (НДС в чеке).


ПРИОРИТЕТ 1 — Касса и продажи (чаще всего используется)

1.1 Розничная продажа (retaildemand) / Касса

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

Слабые места МойСклада: жёсткая привязка возврата к конкретной продаже бывает неудобна (покупатель без чека); интерфейс кассы перегружен для мелкой точки.

Аспект МойСклад У нас Расхождение Серьёзность Предложение [владельцу]
Влияние на остаток при проведении продажи −кол-во POS → RetailSalesController/PosController, движение RetailSale в целом совпадает — —
Себестоимость в продаже FIFO-слой на момент продажи UnitCost=UnitPrice (цена продажи) в движении, COGS≈Product.Cost позже (DemandsController:270, ProfitReportController:14-19) 🔴 COGS неточный/задним числом 🔴 писать снимок себестоимости в движение
Возврат «на основании» продажи, тот же способ оплаты есть ссылка ReferenceSaleId (RetailSalesController.cs:238); способ возврата выбирает кассир (не форсится как в МойСкладе) 🟡 способ не привязан к исходному 🟡 опц.: по умолчанию тем же способом
Смена автооткрытие первой операцией, ≤24ч только ручное открытие (CashShiftsController Open/Close; продажа требует открытой смены) 🟡 нет автооткрытия 🟡 автооткрывать первой продажей
Деньги приход в кассу привязан к смене смена+счёт (есть, чинили ранее) совпадает — —

1.2 Розничная смена (retailshift) и внесение/выплата (drawer cash in/out)

Как у МойСклада: Смена открывается автоматически первой продажей/внесением/выплатой или вручную; не длиннее 24 часов; при открытии можно внести разменные деньги; отчёт смены показывает нал/безнал выручку, продажи и возвраты, по товарам, историю размена и связанные документы. (МойСклад: розничные смены).

Аспект МойСклад У нас Расхождение Серьёзность
Автооткрытие смены да, первой операцией вручную (CashShiftsController) 🟡 🟡
Максимум 24ч да нет явного ограничения 🟡 🟡
Внесение/выплата ПКО/РКО внутри смены внесение/выплата в кассе + MoneyTransactions совпадает по сути —
Z-отчёт смены нал/безнал, продажи/возвраты, по товарам ShiftReportDto (IServerApi.cs:61): нал/безнал по продажам и возвратам + сверка кассы; без разбивки по товарам 🟡 нет «по товарам» 🟡

Предложение [владельцу]: автооткрытие смены первой продажей (как МойСклад) + мягкое предупреждение на 24ч — удобнее кассиру, меньше «забыл открыть смену».


ПРИОРИТЕТ 2 — Товары, остатки, себестоимость, отчёты

2.1 Себестоимость (ключевое 🔴)

Как у МойСклада: себестоимость считается по FIFO — при продаже списывается товар из самой ранней партии; остаток товара хранится «слоями» закупок с разными ценами. Это даёт исторически корректную прибыль, не меняющуюся задним числом. (школа: методы расчёта себестоимости, support: себестоимость).

Как у нас: скользящее средневзвешенное (MovingAverageCost.Compute, src/food-market.application/Inventory/MovingAverageCost.cs): при каждой приёмке пересчитывается единая Product.Cost. Прошлые отчёты «плывут» при новых закупках.

Слабые места МойСклада: FIFO требует партийного учёта — тяжелее по вычислениям и непонятнее для микромагазина; при частых мелких закупках «слоёв» очень много.

Аспект МойСклад У нас Расхождение Серьёзность Предложение [владельцу]
Метод FIFO по партиям скользящее среднее 🔴 🔴 выбор метода: среднее (быстро/просто) по умолчанию для простого режима, FIFO — опция
Момент фиксации COGS на момент отгрузки приближённо, текущая Product.Cost 🔴 задним числом 🔴 снимок COGS в движении
Партии/слои есть нет 🔴 блокирует FIFO, сроки годности 🔴 партийный учёт (большой)

2.2 Остатки и движения (отчёты)

Как у МойСклада: отчёт Остатки — текущие остатки по складам; Обороты — движение товара (приход/расход) за период с указанием документов-источников; остатки меняются только после проведения складских документов. (support: Остатки).

Аспект МойСклад У нас Расхождение Серьёзность
Остатки меняются при проведении да да (StockService.ApplyMovement при Post) совпадает —
Источник движения виден документ-основание в оборотах StockMovement.SourceDoc есть в целом совпадает —
Инвентаризация в оборотах как Оприходование/Списание как InventoryAdjustment (нет опр/спис) 🔴 непонятно в отчётах 🔴

2.3 Прибыльность

Как у МойСклада: Прибыль = Выручка − Себестоимость(FIFO) за период/по товарам/группам. (отчёты МойСклад).

Как у нас: ProfitReportController — Выручка − COGS, где COGS ≈ текущая Product.Cost (признано в комментарии кода ProfitReportController.cs:14-19 как «приближение»).

Аспект МойСклад У нас Расхождение Серьёзность
COGS FIFO на момент продажи текущее среднее (приближение) 🔴 🔴
Стабильность прошлых периодов стабильна «плывёт» при новых закупках 🔴 🔴

2.4 Карточка товара (справочник)

Как у МойСклада: обязательно только Наименование; тип учёта (весовой/штучный/алко), фасовка (весовая для весовых), штрихкоды (EAN8/EAN13/GTIN), единица измерения, несколько типов цен, себестоимость, НДС, вес/объём. (support: создание карточки товара, типы цен).

Аспект МойСклад У нас Расхождение Серьёзность
Обязательные поля только наименование ProductInput (CatalogDtos.cs:92): обязательны Name + UnitOfMeasureId + ProductGroupId 🟡 у нас больше обязательных 🟡
Весовой товар фасовка весовая IsWeighed/packaging есть совпадает —
Штрихкоды EAN8/13/GTIN, несколько несколько штрихкодов, весовые префиксы совпадает/лучше —
Типы цен несколько, автоподстановка типы цен есть (PriceTypesController) совпадает —

ПРИОРИТЕТ 3 — Приёмка, Оприходование, Списание, Инвентаризация

3.1 Приёмка (supply)

Как у МойСклада: остаток появляется только после проведения приёмки; при проведении товар приходуется на склад, формируется себестоимость (FIFO-слой); можно создать «на основании» заказа поставщику; влияет на долг поставщику. (support: приёмка).

Аспект МойСклад У нас Расхождение Серьёзность
Остаток при проведении +кол-во SuppliesController.Post → движение Receipt совпадает —
Себестоимость FIFO-слой пересчёт скользящего среднего 🔴 (метод) 🔴
На основании заказа да заказа поставщику нет в простом режиме 🟡 (скрыт) 🟡
Долг поставщику +долг считается в отчёте долгов (Σ приёмок, MoneyReportsController.cs:120-183) совпадает (расчётно) —

3.2 Оприходование (enter) и Списание (loss)

Как у МойСклада: Оприходование добавляет остаток (излишки/начальные остатки) по учётной себестоимости; Списание убирает остаток (брак/недостача) по FIFO-себестоимости; оба — отдельные проводимые документы; создаются в т.ч. «на основании» инвентаризации. (support: оприходование, списание).

Аспект МойСклад У нас Расхождение Серьёзность
Оприходование +остаток да, при проведении EntersController.Post совпадает —
Списание −остаток да, по FIFO LossesController c UnitCost переданным 🔴 цена не по FIFO 🔴
Создать из инвентаризации да (кнопка «Создать документ») нет (инвент. двигает сама) 🔴 🔴

3.3 Инвентаризация (inventory) — корень жалобы владельца

Как у МойСклада: инвентаризация не двигает остатки; фиксирует расчётное и фактическое количество и разницу; по результатам пользователь создаёт Оприходование (излишки) и Списание (недостача) кнопкой «Создать документ»; именно эти документы меняют остатки. (support: инвентаризация товаров).

Как у нас (неправильно): InventoriesController.Post сам создаёт движения MovementType.InventoryAdjustment и ставит InventoryStatus.Posted (InventoryDoc.cs:8-9) — остатки меняются напрямую, без Оприходования/Списания. Владелец видит «Проведено» без связанных документов.

Аспект МойСклад У нас Расхождение Серьёзность
Двигает остатки нет да (InventoryAdjustment) 🔴 🔴
Статусы Черновик→Завершена Draft→Posted («Проведено») 🔴 🔴
Результат Оприходование+Списание со ссылкой нет связанных документов 🔴 🔴

Переделка уже запланирована (следующая задача, ветка wip/inventory-model): статусы Черновик→Завершена без движений; кнопки «Создать оприходование/списание/применить»; связи; миграция Posted+InventoryAdjustment → проведённые Оприходование/Списание с сохранением остатков. Этот план совпадает с выводами ревизии (пп. 3,6,7,8 сводки).

Предложение [владельцу]: добавить к модели МойСклада кнопку «Применить результаты» (оба документа сразу проведены) — на один шаг короче, чем две кнопки МойСклада.


ПРИОРИТЕТ 4 — Возврат поставщику, деньги, перемещение

4.1 Возврат поставщику (purchasereturn)

Как у МойСклада: списывает товар со склада, уменьшает долг поставщику; создаётся «на основании» приёмки или вручную. (support: возврат поставщику).

Аспект МойСклад У нас Расхождение Серьёзность
−остаток да SupplierReturnsController движение SupplierReturn совпадает —
−долг поставщику да учтён в отчёте долгов (Σ возвратов вычитается, MoneyReportsController.cs:120-183) совпадает (расчётно) —
На основании приёмки да, преднабор опционально ссылка (есть поле) 🟡 довести UI 🟡

4.2 Деньги: платежи, ордера, взаиморасчёты, долги

Как у МойСклада: 4 типа денежных документов — Входящий/Исходящий платёж (безнал) и Приходный/Расходный ордер (нал); все влияют на ДДС и взаиморасчёты с контрагентом; отчёт «Взаиморасчёты» сводит долги/авансы, печатает акт сверки. (support: платежи, ДДС, взаиморасчёты).

Аспект МойСклад У нас Расхождение Серьёзность Предложение [владельцу]
4 типа документов вх/исх платёж + ПКО/РКО MoneyTransactions (обобщённо) + внесение/выплата 🟡 модель проще 🟡 упростить осознанно: один реестр «Деньги» вместо 4 типов — выгода для мелкой розницы
Взаиморасчёты единый реестр документ+платёж CounterpartyAdjustments + долги 🟡 не сквозной реестр 🟡 свести все документы+оплаты в один баланс контрагента
Корректировка взаиморасчётов есть CounterpartyAdjustmentsController (WeOwe/TheyOwe) совпадает по сути — —

4.3 Перемещение (move)

Как у МойСклада: перемещает товар между складами при проведении; переносит себестоимость (FIFO-слои). (складской учёт).

Аспект МойСклад У нас Расхождение Серьёзность
−склад источник / +склад назначение да TransfersController (TransferOut/In) совпадает —
Перенос себестоимости по FIFO-слоям по средней (Product.Cost) 🔴 (метод) 🔴
Видимость в простом режиме есть скрыт ок (простой режим) —

ПРИОРИТЕТ 5 — Справочники, касса, мобильное, режимы

5.1 Контрагенты, склады, точки, сотрудники/роли, счета

Аспект МойСклад У нас Расхождение Серьёзность
Контрагенты тип (покупатель/поставщик), реквизиты, баланс CounterpartiesController совпадает —
Склады несколько, остатки по складам склады/точки (StoresController/RetailPointsController) совпадает —
Сотрудники/роли/права роли и права, точки роли+права+привязка точек (есть) совпадает/детальнее —
Счета (касса/банк/эквайринг) счета и ДДС MoneyAccountsController совпадает —

5.2 Касса ALL MARKET (Avalonia) vs Касса МойСклад

Касса МойСклад: продажи, сдача, возвраты, открытие/закрытие смены, офлайн, весовой товар, сканирование штрихкода камерой, смешанная оплата (нал+карта), 54-ФЗ (АТОЛ/ШТРИХ-М/Viki Print), скидки/бонусы, кроссплатформенность (Win/Android/iOS/Linux). (касса для мобильного, АРМ кассира).

Функция Касса МойСклад Наша касса (Avalonia) Расхождение Серьёзность
Офлайн да да (очередь синка) совпадает —
Весовой товар да да (весовые ШК) совпадает —
Смешанная оплата да да совпадает —
Возврат по чеку да да совпадает —
Смена/Z-отчёт да да совпадает —
Сканер камерой да (смартфон) сканер-HID/весы по COM 🟡 (нет камеры) 🟡
Фискализация (ОФД РК; у МС — WebKassa/reKassa) да заглушка NullFiscalProvider — не реализовано (Fiscal.cs) 🔴 блокер по закону РК (см. П2.3) 🔴
Платёжные терминалы (эквайринг) интеграция (PAX/Verifone) нет — ручной ввод суммы карты 🟡 🟡

5.3 Мобильное «FM Склад» vs мобильное МойСклад

Мобильный МойСклад: приёмка, инвентаризация, остатки, сканирование, отгрузка — с телефона.

Функция МойСклад моб. FM Склад (iOS) Расхождение Серьёзность
Остатки по складу да да (/api/inventory/stock с groupId) совпадает —
Приёмка с телефона да нет (нет mobile-эндпоинтов приёмки; только stock/barcodes/me) 🟡 🟡
Инвентаризация с телефона да post/unpost есть — переделать под новую модель 🔴 (после §3.3) 🔴
Сканирование да штрихкоды + весовые совпадает —

5.4 Простой/расширенный режим, настройки, импорт, онбординг

Аспект МойСклад У нас Расхождение Серьёзность Предложение [владельцу]
Простой режим нет единого «простого режима» — много всего сразу IsAdvancedMode + гейты 🟢 лучше нас для старта — сохранить и усилить
Импорт Excel/CSV, маркетплейсы Excel/CSV + накладные по фото (OCR) совпадает/лучше — —
Онбординг есть, но тяжёлый мастер онбординга 🟢 возможность быть проще — «первая приёмка за 2 мин»

Наши тесты, закрепляющие НЕПРАВИЛЬНОЕ поведение (переписать под МойСклад)

Тест Что закрепляет Как должно быть
full-chain шаг 10 (инвентаризация) «провёл инвентаризацию → остатки сразу изменились» создать инвентаризацию → завершить → применить → остатки = факт через Оприходование/Списание
unit-тесты инвентаризации (InventoriesController движения) движения InventoryAdjustment при Post нет движений от инвентаризации; движения — у связанных опр/спис
unit MovingAverageCost скользящее среднее как эталон COGS при выборе FIFO — тесты на FIFO-слои и COGS на момент продажи
profit-тесты (если берут Product.Cost) COGS = текущая средняя COGS = снимок себестоимости на момент продажи
mobile API post/unpost инвентаризации post = двигает остатки post = завершить+применить (создать и провести опр/спис)

Правило на будущее: сначала сверка с МойСкладом (эта методика), потом реализация, потом тесты под сверенное поведение — а не тесты под уже написанный код.


ПРОХОД 2 — факт-проверки, Казахстан, исправление неточностей прохода 1

Mac-Claude: проход 1 полезный, но поверхностный. Ниже — все «проверить» закрыты фактом (код файл:строка и/или запрос на стенде test.admin.food-market.kz), казахстанская специфика и корректировки неточностей.

П2.1 Закрытие всех «проверить» (факты)

Пункт (проход 1) Факт (код/стенд) Вывод
Возврат: ссылка-основание RetailSalesController.cs:44,90,238-239,296 — возврат несёт ReferenceSaleId + ReferenceSaleNumber на исходную продажу ✅ ссылка-основание есть
Возврат: способ возврата У возврата своё поле Payment (нал/карта); кассир выбирает. МойСклад принудительно тем же способом 🟡 у нас гибче, но нет гарантии «тем же способом»
Z-отчёт: состав ShiftReportDto (IServerApi.cs:61): sales(cash,card), returns(cash,card), expectedCash, actualCash, cashDifference ✅ нал/безнал + сверка; ❌ нет разбивки «по товарам» (у МойСклада есть)
Долг поставщику при приёмке MoneyReportsController.cs:120-183 — долг = Σ приёмок(Posted) − Σ возвратов − Σ оплат + Σ корректировок ✅ приёмка увеличивает долг (считается в отчёте)
−долг при возврате поставщику тот же расчёт, Σ возвратов вычитается ✅ возврат уменьшает долг
Обязательные поля товара ProductInput (CatalogDtos.cs:92): [Required] Name, UnitOfMeasureId, ProductGroupId — обязательны 🟡 больше, чем у МойСклада (там только наименование; ед. и группа — нет)
Приёмка с телефона мобильных endpoint’ов приёмки нет (docs/mobile-api.md — только stock/barcodes/me) ❌ приёмки с телефона нет (у МойСклада есть)
Платёжные терминалы интеграций PAX/Verifone нет; «карта» — ручной способ оплаты в кассе ❌ нет интеграции терминала
Фискализация Fiscal.cs — IFiscalProvider + NullFiscalProvider (заглушка, чек без фискального номера) ❌ фискализации нет (см. §П2.3)
«Нет единообразной отмены проведения» (утв. прохода 1) НЕВЕРНО. Unpost есть у ВСЕХ: Supplies:518, Enters:284, Losses:313, Inventories:525, SupplierReturns:327, Transfers:324, Demands:290, RetailSales:828 ✅ отмена проведения единообразна — исправляю проход 1
Розничная смена: автооткрытие CashShiftsController Open/Close; продажа требует открытой смены; автооткрытия нет 🟡 только ручное

П2.2 Себестоимость — факт-проверка и реальный пример Демо-магазина

«У МойСклада FIFO» — подтверждено их справкой: «В МоёмСкладе себестоимость считается по принципу FIFO… при продаже в первую очередь списывается товар из самой ранней приемки» (школа торговли, методы расчёта себестоимости; support 217544337).

«В движение продажи пишется UnitCost = цена продажи» — проверено по коду: да, причём и в опте, и в рознице/кассе:

  • опт: DemandsController.cs:270,307 — UnitCost: line.UnitPrice;
  • розница/касса: RetailSalesController.cs:680,858 (RetailSale) и :986,1039 (CustomerReturn) — UnitCost: line.UnitPrice.

НО: StockMovement.UnitCost при продаже = цена продажи и для прибыли не используется — ProfitReportController.cs:116-118 берёт COGS = Quantity × Product.Cost (текущее скользящее среднее). То есть поле UnitCost в движении продажи бесполезно/вводит в заблуждение, а реальная себестоимость в отчёте — текущая средняя на момент построения отчёта, а не на момент продажи.

Реальный пример со стенда (Демо/импорт-каталог, запрос /api/reports/profit):

  • Товар «BIOBLAS шампунь д/волос 360мл»: текущая Product.Cost = 548.6441 ₸ (дробная → смешана из 3 приёмок с разными ценами; supplies total = 3).
  • Профит-отчёт по нему: выручка 3100, себест 1097.2882 (= 2 × 548.6441), прибыль 2002.7118.

В чём искажение: 548.6441 — средняя после всех 3 приёмок. Если эти 2 единицы были проданы до третьей (более дорогой/дешёвой) приёмки, FIFO отнёс бы на них цену ранней партии, а не текущую среднюю. Поэтому:

  1. показанная прибыль по прошлым продажам не историческая (считается ценой, которой на момент продажи ещё не было);
  2. при каждой новой приёмке того же товара средняя меняется → прибыль за закрытые периоды «плывёт» задним числом. Величина искажения = (текущая средняя − фактическая FIFO-цена партии) × проданное количество; на товарах с разбросом закупочных цен (как BIOBLAS: 3 цены) она ненулевая и накапливается. На товарах с единственной ценой закупки искажения нет. Точное число «насколько» получить от работающей системы нельзя — FIFO у нас не реализован; это и есть аргумент за реализацию (или за осознанный выбор средней).

П2.3 Касса и фискализация — Казахстан, а не 54-ФЗ

Поправка: в проходе 1 стоял «54-ФЗ» — это закон РФ. Мы в Казахстане; применяется закон РК.

Как МойСклад работает в Казахстане: есть отдельный moysklad.kz с интеграциями ОФД/ККМ РК. Касса МойСклад встраивает облачную фискализацию: WebKassa (данные чека автоматически уходят в WebKassa → ОФД) и reKassa (бесплатная облачная онлайн-ККМ РК, фискализация и электронные чеки); упоминается Kassa24. С 1 апреля 2026 — переход на новый протокол ККМ v2.0.3 для передачи в ОФД. (МойСклад: интеграции для Казахстана, WebKassa, reKassa, новый протокол ККМ, онлайн-касса в РК 2026).

Что требуется по закону РК для розничной кассы: онлайн-ККМ с передачей данных в ОФД (фискальный чек, QR). Без этого легально пробивать чеки нельзя.

Наш статус: NullFiscalProvider — фискализации нет, чек проходит без фискального номера (Fiscal.cs:5-15, см. docs/pos.md «Фискализация»). 🔴 блокер для легальной розницы РК.

Что умеет «Касса МойСклад» из реально нужного кассиру — и что у нас:

Функция кассира Касса МойСклад Наша касса (Avalonia) Факт у нас
Скидки на позицию/чек да да (скидка на строку) SaleView/PaymentView
Бонусы/лояльность да сервер есть (LoyaltyCards/Programs), в кассе — не подключено 🟡 нет в кассе
Отложенные чеки (парковка) да да («Отложить»/«Отложенные») ParkCommand/ResumeCommand
Поиск товара да да (поиск + сканер + весовые ШК) ScanCommand
Весы да да (COM/serial) Hardware
Печать чека да да (ESC/POS) Printing.cs
Смешанная оплата да да (нал+карта) PaymentView
Фискализация ОФД да (WebKassa/reKassa) ❌ заглушка 🔴
Сканер камерой смартфона да ❌ (внешний сканер/COM) 🟡
Платёжный терминал (эквайринг) да ❌ ручной ввод суммы карты 🟡

Вывод: по функциям для кассира мы покрываем почти всё (скидки, отложенные, поиск, весы, печать, смешанная оплата). Критичные пробелы — фискализация ОФД РК (🔴 закон) и бонусы в кассе (🟡), плюс эквайринг-терминал и камера-сканер (🟡).

П2.4 Казахстанская специфика по закону (ЭСФ/СНТ, маркировка, НДС, акциз)

Этого в проходе 1 не было вовсе. Для РК — высокая важность.

НДС

С 01.01.2026 базовая ставка НДС в РК — 16 % (повышена с 12 %, Налоговый кодекс №214-VIII); льготная 5 % на лекарства/медизделия; порог постановки на учёт — 10 000 МРП. Переход: оборот до 31.12.2025 — 12 %, с 01.01.2026 — 16 %. (НДС 16% 2026, ставки НДС и ККМ). У нас: дефолт НДС для KZ = 16 % (SystemReferenceSeeder.cs:38 — new("KZ","Казахстан","KZT",16m)), Product.Vat берётся из Country.VatRate при создании товара. То есть ставка актуальна. Единственный нюанс — нет переходной логики «12 % до 31.12.2025 / 16 % после» по дате оборота (для магазина, работающего в 2026, несущественно). У МойСклада ставка НДС на товаре/в документе — есть.

Маркировка (ИС МПТ)

Обязательная маркировка в РК: табак/сигареты и жидкости для вейпов, обувь (с 01.11.2021), лекарства (с 01.07.2024), пиво (кеги/бутылки с 01.02.2026, банки с 01.01.2027), одежда/лёгкая промышленность и моторные масла (поэтапно 2026–2027). Розница при продаже маркированного товара обязана сканировать код и вывести его из оборота (передать в ИС МПТ). (маркировка в РК 2026, перечень товаров). У МойСклада — есть работа с маркировкой (создание карточек маркированного товара, вывод из оборота). У нас — только флаг Product.IsMarked (CatalogDtos.cs:92), вывода из оборота нет. 🔴 если магазин продаёт табак/обувь/лекарства.

СНТ и ЭСФ

СНТ (сопроводительная накладная на товары) оформляется электронно в системе ЭСФ (esf.gov.kz). Для розницы обязательна только по узкому перечню (~3 категории); в рознице процедуры по СНТ в основном автоматические без участия розничного продавца; обязательное подтверждение — только по подакцизным товарам; добровольно — до 10 числа следующего месяца. (СНТ: Әділет, КГД: СНТ, правила СНТ 2026). У нас интеграции с ИС ЭСФ нет. Для маленького магазина без подакцизных — не блокер (авто); при продаже подакцизных (табак/алкоголь) понадобится подтверждение СНТ. У МойСклада KZ интеграция с ЭСФ/СНТ есть.

Акциз/подакцизные

Табак, алкоголь — подакцизные; по ним обязательно подтверждение СНТ и (для табака/пива) маркировка. У нас отметки «подакцизный товар» нет. 🟡

Что малому магазину нужно в первую очередь: (1) фискализация ОФД (K1 — иначе нельзя пробивать чеки); (2) маркировка, если торгует сигаретами (K3); (3) корректная ставка НДС 16 % в чеке (K2). СНТ/ЭСФ и акциз — по мере появления подакцизных категорий.

П2.5 Исправления неточностей прохода 1

Утверждение прохода 1 На самом деле
«Нет единообразной отмены проведения» (топ-15 №5) Есть у всех документов (unpost-эндпоинты, см. П2.1) — заменил пункт на «Фискализация РК»
«Взаиморасчёты — не сквозной реестр» (топ-15 №13) Долги считаются из документов (приёмки−возвраты−оплаты+корректировки, MoneyReportsController:120-183); это близко к МойСкладу. Понизил до средней/UX; пункт топ-15 заменил на «Маркировка РК»
«54-ФЗ» в разделе кассы Это закон РФ; у нас РК — см. П2.3 (ОФД РК, WebKassa/reKassa)
«Долг поставщику при приёмке / −долг при возврате — проверить» Подтверждено: оба учитываются в отчёте долгов
«НДС 12%» (из задания) С 01.01.2026 в РК — 16 % (5 % лекарства); у нас ставка из Country.VatRate

Итоговая оценка объёма исправлений

  • Инвентаризация (§3.3) — средний, уже в очереди (wip/inventory-model), план совпал с ревизией.
  • Себестоимость FIFO + партии + COGS-снимок (§2.1–2.3, 3.2, 4.3) — большой, самый влиятельный блок (остатки/прибыль/движения). Рекомендация: отдельная крупная задача после инвентаризации; рассмотреть компромисс «среднее по умолчанию, FIFO — опция» [НА РЕШЕНИЕ ВЛАДЕЛЬЦА].
  • Связи «на основании» + статусы + отмена проведения (§1,3,4) — средний, сквозная унификация.
  • Деньги/взаиморасчёты единый реестр (§4.2) — средний, можно сделать проще МойСклада осознанно.
  • Касса/мобильное (§5.2–5.3) — точечные дополнения (камера-сканер, терминалы), средняя серьёзность.
  • 🇰🇿 Казахстан по закону (K1–K5, §П2.3–П2.4): фискализация ОФД РК (K1) — 🔴 блокер, интеграция Webkassa/reKassa (средний–большой); маркировка ИС МПТ (K3) — большой, если торгует табак/обувь/лекарствами; НДС 16% (K2) — малый (проверить дефолт/дату оборота); СНТ/ЭСФ (K4) и акциз (K5) — средний, по подакцизным категориям.

Источники (MoySklad)

  • Себестоимость/методы: moysklad.ru/poleznoe/shkola-torgovli/metody-rascheta-sebestoimosti; support 217544337
  • Приёмка: support 203325563 · Списание: support 203053096 · Возврат поставщику: support 230623667
  • Инвентаризация: support (товары и склады/операции/инвентаризация_товаров); moysklad.ru/poleznoe/.../izlishki-pri-inventarizacii
  • Остатки: support 203319073 · Складской учёт: support 360014957717
  • Платежи: support 203025346 · ДДС: support 360000199328 · Взаиморасчёты: support (отчеты/взаиморасчеты)
  • Розничные смены: moysklad.ru/news/715 · Возврат покупателя: moysklad.ru/poleznoe/.../kak-oformit-vozvrat-ot-pokupatelja
  • Карточка товара: support (товары и склады/.../создание_карточки_товара); Типы цен: support 203053526
  • Касса МойСклад: moysklad.ru/reshenija/mobilnaya-kassa; programmy-dlja-biznesa/arm-kassira
  • API: dev.moysklad.ru/doc/api/remap/1.2 (#/documents/inventory, /enter, /loss)

Источники (Проход 2 — Казахстан)

  • МойСклад KZ: moysklad.kz · интеграции РК: moysklad.ru/integratsii/dlya-kazakhstana
  • WebKassa: moysklad.ru/integratsii/apps/webkkm-smartinnovations; online-webkassa.kz · reKassa: moysklad.ru/integratsii/apps/rekassa-smartinnovations; rekassa.kz
  • Новый протокол ККМ (01.04.2026): moysklad.kz/news/noviy-protokol-kkm · онлайн-касса РК: moysklad.kz/poleznoe/shkola-torgovli/online-kassa-v-kazakhstane
  • НДС 16% (01.01.2026): finproverka.kz/blog/nds-v-kazahstane-v-2026-godu…; promo.webkassa.kz/…stavki-nds-s-2026-goda
  • СНТ/ЭСФ: adilet.zan.kz/rus/docs/V2500037317; gov.kz/…/kgd/…/593973; pro1c.kz/articles/snt/pravila-snt
  • Маркировка РК: birsan.kz/…markirovka-tovarov-v-kazahstane-s-2026; adilet.zan.kz/rus/docs/P2000000568
  • Код (наш): RetailSalesController:680/858/986/1039 · DemandsController:270 · ProfitReportController:116-118 · MoneyReportsController:120-183 · CatalogDtos.cs:92 · Fiscal.cs · IServerApi.cs:61 · unpost: Supplies:518/Enters:284/Losses:313/Inventories:525/SupplierReturns:327/Transfers:324/Demands:290/RetailSales:828
  • Стенд: /api/reports/profit (Демо) — BIOBLAS шампунь Product.Cost=548.6441, 3 приёмки