RetailOversellingTests ждал 409 на продажу сверх остатка — устаревшая политика.
По решению владельца 08.10 продажа в минус разрешена и создаёт предупреждение об
отрицательном остатке. Тест переписан: проведение успешно, остаток уходит в минус,
создан negative-stock alert. Плюс обновлён docs/filters-sweep-progress.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Остатки строились ОТ таблицы Stocks (JOIN Products), поэтому товары без строки
Stock (ни разу не приходованные) не попадали в список вообще, а includeZero лишь
снимал фильтр Quantity!=0 у существующих строк. То же в отчёте «Остатки на дату»,
в экспорте и в фильтре по группе (iOS получал total 0).
- GetStock/ExportStock: выборка ОТ Products (не-услуги, не-архивные) с остатком
коррелированным подзапросом (товар без Stock = 0). Склад выбран → строка склада;
без склада → агрегат «Все склады». Нулевые видны при includeZero; negativeOnly и
пагинация/сортировка/поиск/экспорт работают и для нулевых. Остаток/ед./штрихкод
дотягиваются batch-запросом по id страницы (EF8 не переводит подзапросы в SELECT+ORDER BY).
- Отчёт «Остатки на дату»: includeZero добавляет товары без движений (Qty 0);
фильтр по группе теперь с вложенностью.
- groupId/productGroupId — синонимы с вложенными группами на всех списках остатков
и в каталоге (List + Export). Раньше catalog?productGroupId молча игнорировался.
- Штрихкод рядом с артикулом в списке/экспорте — различать одноимённые товары
(4× «BIOBLAS шампунь» с разными артикулами из МойСклада — не удалять).
- Demo (30 894 товара): без флага 12, includeZero → 30 894, <500мс/страница.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
now-pos-sale.png / now-pos-login.png были сняты 17:41, до фикса 3a0f9e2 (18:07).
Переснято с текущего UI: лого ALL MARKET ~140px, «Касса» через разделитель,
бейдж «Отложенные 2» целиком внутри кнопки.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hangfire DataQualityJob (ночью 02:20 UTC) считает по орг. счётчики проблем: без группы
(корень/«Без группы»), без цены продажи, без штрихкода (кроме услуг), дубль штрихкода,
возможный дубль имя+единица; товары в минусе — ссылкой на центр (не дублируем). Результаты
в data_quality_results (Phase43), живые детальные списки — по запросу.
API /api/data-quality: сводка, {check}/products, recompute, dismiss («это разные товары»),
bulk set-group/set-price/generate-barcodes, PUT settings (отключение проверок). unknown-cost
отложен до FIFO; PLU убран (поправка владельца). Integration-тест: счётчики/список/bulk/dismiss.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
POST /api/purchases/supplier-returns/from-supply/{supplyId}: черновик возврата с
преднабором строк из проведённой приёмки (товар/кол-во/цена), поставщик/склад/валюта
и ссылка ReferenceSupplyId. Integration-тест: преднабор + связь.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
П.7: типы денег названы привычно — «Приход наличных (ПКО)», «Расход наличных (РКО)»,
«Входящий/Исходящий платёж», «Перевод между счетами».
П.8: блок «Прибыль за сегодня/месяц» на дашборде (во всех режимах, /api/dashboard/margin),
с пометкой «приблизительно; точно после FIFO».
П.9: общий DocStatusBadge (Черновик/Проведён/Завершена) с tooltip «что это значит»,
применён на списках Приёмок/Продаж/Инвентаризаций.
П.6: проверено — Оприходование/Списание в простом режиме не прячутся (отдельные пункты).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Правки владельца 08.10 (п.4 паритета):
- Сохранить можно при наличии Наименования. Единица не обязательна в запросе →
дефолт «шт»; группа → корень. Штрихкод ОБЯЗАТЕЛЕН у любого товара: нет в запросе/
импорте → автогенерация внутреннего EAN-13 (верная контр. цифра, префикс не
пересекается с весовыми/ценовыми префиксами орг. — InternalBarcode).
- Цена продажи не обязательна для сохранения; но ПРОДАТЬ без неё нельзя — касса и
розничная продажа дают «У товара «X» нет цены продажи» (можно ввести вручную).
- Быстрое создание из кассы/приёмки: POST /api/catalog/products/quick (имя + опц.
штрихкод/цена/весовой).
- Снят FluentValidation NotEqual(Guid.Empty) на единицу (контроллер подставляет дефолт).
Тесты: unit InternalBarcode 3/3 (валидный EAN-13, не парсится как весовой, обходит
префиксы); integration 3/3 (создание по одному имени, продажа без цены → 400, quick).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- docs/moysklad-pos-startup.md: прямой замер «Кассы МойСклад» (Celeron N4120, 99–113 с
до готовности; каталог перезаписывается целиком, полный JSON+FTS) — подтверждённые
причины, не догадки.
- docs/pos-progress.md: раздел «Мгновенный старт» — что сделано (касса из локальной базы +
фоновый синк, дельта остатков, gzip-каталог ×7.3, синк вне UI-потока) + таблица замеров
(Linux/стенд + Win11 VM + 1 ядро как прокси Celeron). Цель <2 с тёплый старт на слабом
CPU достигнута (<1 с). Серверный кэш снимка осознанно не делали (риск памяти, путь
«раз на установку»).
- deploy/pos-install.ps1: установщик Windows (исключение Defender + прогрев + ярлык);
холодный старт 10 с → 4,5 с. deploy/pos-win-measure.ps1 — скрипт замеров на VM.
- docs/pos.md: обновлён раздел первого запуска + варианты/стоимость подписи exe (не покупали).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Пасс 3: касса (индикатор+предупреждение+офлайн), Web Push (VAPID), e2e колокольчика.
Итог: unit 299/299, integration 4/4, POS 4/4, e2e-браузер 2/2.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Таблица токенов устройств (device_tokens, Phase40) + POST/DELETE /api/me/device-tokens
для регистрации iOS/Android/Web push-токенов. Контракт IPushSender.SendAsync; в DI
включён StubPushSender (пишет в лог) — реальный APNs/FCM/VAPID подменит заглушку, когда
появятся ключи, без правок вызывающего кода. Описано в docs/mobile-api.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Решение владельца 08.10: продавать/списывать в минус РАЗРЕШЕНО, но с постоянным
предупреждением и требованием провести инвентаризацию.
- Снята блокировка «недостаточно остатка» (409 oversell): розница, касса (POS-синк),
опт-отгрузка, списание, перемещение, возврат поставщику, отмена приёмки. Деньги
(минус счёта) — по-прежнему запрещены (другое правило).
- NegativeStockAlert (сущность + миграция Phase39): создаётся/обновляется при уходе
остатка < 0 (единая точка — StockService), авто-закрытие при возврате ≥ 0. Частичный
уникальный индекс: один открытый алерт на (org, store, product). Причина: тип/номер
документа/автор/время.
- API /api/negative-stock: список (с подсказкой «возможно, не проведена приёмка П-…»),
/count (для баннеров), /recount (черновик инвентаризации по минусам склада). Отчёт
«Остатки» — фильтр negativeOnly.
- Веб: постоянный баннер «N товаров в минусе — нужна инвентаризация» (сворачивается,
крестиком не закрыть) + «Пересчитать эти товары»; в остатках — красная пометка и
фильтр «Только минусы».
- Тесты: integration 2/2 (минус разрешён → алерт → recount → авто-закрытие; фильтр);
full-chain шаг 9/13 переписаны (oversell/отмена приёмки → проведено + предупреждение).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Было: unpost при проведённых связанных Оприходовании/Списании молча снимал их с
проведения и УДАЛЯЛ (204, номера исчезали). Хуже МойСклада, теряется история.
- unpost при ПРОВЕДЁННЫХ связанных → 409 с номерами О-/С- и текстом «Сначала
отмените результаты». Если связанные только черновики — удаляем черновики
(не влияли на остатки) и возвращаем инвентаризацию в черновик.
- Новое POST /{id}/cancel-results (InventoryEdit + EnterEdit/LossEdit): снимает
связанные Оприходование/Списание с проведения, НЕ удаляя (остаются черновиками,
видны в «Связанных документах», истории, аудите); остатки возвращаются; для
Оприходования — гард на уход остатка в минус. Аудит InventoryCancelResults.
- Веб: кнопка «Отменить результаты» (при проведённых связанных) + диалог со
списком документов и влиянием на остатки; «Вернуть в черновик» переформулирован.
- docs/mobile-api.md: unpost больше не удаляет проведённые (409), добавлен cancel-results.
- Тесты: integration (409 + cancel-results оставляет черновики + повторное
проведение) + full-chain шаг 10.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Галерея docs/site-screenshots/ — задеплоенные страницы test.food-market.kz
с новыми честными текстами (главная, касса, импорт, возможности, перенос и
интеграции, тарифы, для продуктовых, о нас). Удалён кадр удалённой вертикали.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Убраны обещания того, чего нет: фискализация ОФД/Kaspi Pay (skeleton) →
«в разработке»; ЕГАИС/акцизы/модификаторы/серии-сроки/размерные сетки →
удалены 5 выдуманных страниц-вертикалей (остался продуктовый); CRM/публичный
API убраны; «О нас» без выдуманной истории и команды. Касса — Windows и Linux
(не .msi), «Скачать» → «скоро». Импорт — CSV/1С-CSV/МойСклад. Лояльность — в
админке, не в кассе. Интеграции — честный блок «есть / в разработке».
Язык владельца магазина, без жаргона (дашборд, нативно, вертикали, фишки,
триал, SLA, CRM, Unlimited, кейсы) и пафоса. Заголовок кассы: «Быстрая касса,
которая работает и без интернета». Цены тарифов не менялись.
По правкам Mac-Claude после ревью docs/site-copy-draft.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Проверил каждое утверждение сайта по коду/стенду: фискализация ОФД/Kaspi Pay —
skeleton (нет), ЕГАИС/акцизы/модификаторы/серии-сроки/размерные сетки/гарантии —
нет, CRM — нет, лояльность — в админке не в кассе, импорт — CSV/1С-CSV/МойСклад,
касса — Windows+Linux (zip/AppImage, не .msi), «О нас» — выдуманная история.
Замеры скорости кассы: холодный старт 82 мс, инициализация 625 мс (< 1 c), поиск
по ШК 36 мс. Черновик переписанных текстов — docs/site-copy-draft.md (было→стало).
НЕ выкладывается до «ок» Mac-Claude.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1. Английские строки в админке → русский: ru.json dashboard.title «Dashboard»→
«Сводка», common.live/offline «live/offline»→«онлайн/офлайн»; дашборд-виджеты
defaultValue «Low-stock alerts»→«Низкий остаток», «Live-обновление»→«Обновляется
в реальном времени».
2. Каталог: системная группа «Все товары» больше не дублирует корень дерева
(ProductGroupDto.IsSystem + ProductGroupTree прячет системные группы).
3. Валюта: розничная цена в каталоге теперь «₸», а не «KZT» (символ вместо кода).
4. Касса на сайте: вместо HTML-макета — НАСТОЯЩИЙ экран Avalonia-кассы
(--screenshots) с витринными данными «Магазин у дома», кассир Виктория Ким, с
логотипом; убран префикс «Магазин » в шапке (не было двойного «Магазин Магазин»).
HTML-макет удалён из публичного пайплайна.
5. Витрина: фасовка/единица товара выводится из названия (кг→весовой, иначе
штучный) — нет «Авокадо 1шт весовой» / «Бешбармак 1кг штучный».
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Скриншоты задеплоенных страниц test.food-market.kz (главная/касса/импорт/
тарифы/вертикали/о компании) для проверки на глаз. Все новые скриншоты ALL MARKET
на витринных данных отрисовываются корректно.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Пересняты скриншоты публичного сайта в интерфейсе ALL MARKET на витринной
организации «Магазин у дома» (200 товаров, ~30 дней продаж, чистые данные
без e2e/test-мусора). Светлая тема, 1440×900 @2x, WebP + srcset, alt по-русски.
- screenshots.mjs: стенд + витринный владелец, 14 экранов (дашборд/каталог/
карточка/приёмки/остатки/инвентаризация/деньги/отчёты/контрагенты), скрытие
баннеров стенда/«что нового»/MoM-дельты, резолв AsyncSelect-подписей
- optimize-screenshots.mjs: PNG→WebP (1x 1440w / 2x 2880w) через canvas, все ≤300КБ
- pos-mockup/pos-mockup.html: светлая касса ALL MARKET «Магазин у дома» (продажа+оплата)
- index.astro: hero-дашборд + каталог + новый блок «Касса»; pos.astro: продажа+оплата
- ShowcaseSeeder: стартовый завоз всех товаров (нет отрицательных остатков)
- deploy/showcase-seed.sh: RESET=1 пересоздаёт витрину с нуля
- исходные PNG не коммитятся (.gitignore), доставка — только WebP
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ShowcaseSeeder — чистые данные для публичных скриншотов: 200 товаров без
Article-маркеров, реальные EAN-13, боевой формат номеров документов
(П-2026-…, ПР-2026-…), 3 поставщика, счета (касса/Kaspi/эквайринг),
сотрудники с нормальными именами, ~30 дней продаж, приёмки, 2 списания,
1 завершённая инвентаризация. Без e2e/test/Y1/DEMO в видимых данных.
- POST /api/admin/seed-demo?showcase=1 (DemoSeedController)
- повторяемый deploy/showcase-seed.sh (signup + seed, идемпотентно)
- YearDemoSeeder: data-массивы → internal для переиспользования
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- InventoryEditPage: «Завершить подсчёт» вместо «Провести»; на завершённой — кнопки
«Создать оприходование излишков» / «Создать списание недостачи» (блокируются, если нет
разницы или документ уже создан) + блок «Связанные документы» + «Вернуть в черновик».
- InventoriesPage: статус «Завершена»; колонка «Результат» (опр./спис. № или «не применено»).
- Enter/LossEditPage: «На основании инвентаризации №…» со ссылкой.
- types.ts: InventoryStatus Draft/Completed; related в InventoryDto; результат в списке;
inventoryDocId/Number в Enter/Loss DTO.
- docs/inventory-moysklad-reference.md (сверка), inventory-model-progress.md,
supply-inventory.md («Как провести инвентаризацию», 5 шагов), mobile-api.md (compat post/unpost).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Замечание владельца: инвентаризация стояла «Проведено» без оприходования/списания.
Переделано по МойСкладу (docs/inventory-moysklad-reference.md):
- InventoryStatus Draft→Completed (было Posted; значение 1 то же). Инвентаризация
остатки НЕ двигает: endpoint complete замораживает строки без движений.
- create-enter (излишки diff>0) / create-loss (недостача diff<0) — создают черновики
Оприходования/Списания со строками разницы + ссылка InventoryDocId. Повторно нельзя (409).
- Кнопки «Применить результаты» НЕТ (поправка Mac-Claude — не одобрено владельцем).
- unpost («вернуть в черновик») отменяет проведение и удаляет связанные документы.
- post/unpost — временная совместимость для мобильного «FM Склад» (post = завершить +
создать и провести оба документа); помечено в docs/mobile-api.md.
- Enter/Loss: поле InventoryDocId (+ миграция Phase38) + в DTO «на основании инвентаризации №…».
- InventoryResult (application) — чистая разбивка diff→излишки/недостача (unit-тесты:
разница/сумма/только посчитанные строки/округление).
- InventoryMigrationController (dry-run/apply): старые Posted+InventoryAdjustment →
связанные проведённые документы переметкой движений (не задваивает), с проверкой
неизменности остатков. Скрипт deploy/migrate-inventory-to-docs.sh (backup + запуск).
- Демо-сидеры: инвентаризации теперь Completed без прямых движений.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Дополнен 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>
Сверка всех процессов простого режима + справочников/кассы/мобильного/отчётов с
МойСкладом (API dev.moysklad.ru + support.moysklad.ru + школа торговли). Для каждого:
как в МойСкладе (ссылки) | как у нас (файл:строка) | расхождение | серьёзность |
слабые места МойСклада | предложение «как лучше» [НА РЕШЕНИЕ ВЛАДЕЛЬЦА].
Главные находки (🔴): себестоимость у нас скользящее среднее vs FIFO у МойСклада;
прибыль берёт COGS приближённо (Product.Cost), а не на момент продажи; инвентаризация
сама двигает остатки и статус «Проведено» без оприходования/списания. Также — какие
наши тесты закрепляют неправильное поведение и должны быть переписаны.
docs/moysklad-logic-audit.md — полный отчёт; .html — краткая версия для владельца.
Только отчёт, без правок кода.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- now-web-login-stage.png: вход на test.admin.food-market.kz после деплоя —
баннер стенда, быстрый вход, логотип ALL MARKET, без тостов ошибок.
- rollback-logo-foodmarket.png: подтверждение отката (лого Food Market).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Отчёт по ревью безопасности (сидер/префилл/ротация пароля стенда), результат
проверки отката в worktree, уточнённые границы (артефакты кассы, маркетинг-скриншоты).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Верхняя полоса: логотип ALL MARKET высотой 48 (ширина ≈140px ≥ минимума
брендбука), «Касса» отделена тонким разделителем (не оторвана).
- Бейдж количества у «Отложенные» теперь целиком внутри кнопки (меньше паддинг
кнопки, плотнее контент) — не обрезается правым краем.
- Перегенерированы скриншоты кассы; обновлён кадр веб-входа в галерее (без тоста,
без префилла пароля).
- Зелёный UI не менялся (--color-brand #00B207, идентичен дорибрендинговому).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/rebrand-screenshots/ + index.html: пары Было|Стало по логотипу, favicon,
письму-приглашению, OG-картинке, кассе (вход/продажа); «Стало» для веб-входа и
публичной главной. «Было» извлечено из тега pre-rebrand-all-market.
Отмечено, что встроенные продуктовые скриншоты маркетинг-сайта обновятся при
прод-выкатке (screenshots.mjs против живой админки).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- docs/imports.md, docs/simple-mode.md: «Food Market» → «ALL MARKET».
- Перегенерированы скриншоты кассы (вход/продажа/оплата/смена/возврат) с
логотипом ALL MARKET в шапке и на экране входа.
- Внутренние TZ/verify-доки оставлены как историческая фиксация.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Верхняя полоса и экран входа: логотип-изображение ALL MARKET из ресурсов
(avares Assets/), color на светлой теме и white на тёмной (Brand.ApplyLogo).
- Заголовок окна «ALL MARKET · Касса»; иконка окна и ApplicationIcon = allmarket.ico
(собрана из фирменных PNG 32/180/192).
- Чек: в шапке — название точки/магазина (резолвится из RetailPoint, PosSession.StoreName),
внизу мелко «ALL MARKET — система учёта торговли» (был хардкод «Food Market» в шапке).
- AppImage .desktop: Name «ALL MARKET Касса» + фирменная иконка.
- Эталон-макет pos-mockup.html — логотип «all market».
- AssemblyName/exe (foodmarket.Pos) и имена артефактов не менялись (инфраструктура).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Тег pre-rebrand-all-market на дорибрендинговом main (c8c0be5), запушен.
- docs/rebrand-all-market-progress.md — план и границы (что НЕ трогаем).
- docs/rebrand-rollback.md — точные команды отката кода (revert-диапазон) и стенда.
- deploy/rebrand-rollback.sh — dry-run по умолчанию, --apply для реального отката.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Реальное окно Windows 11 заново: продажа (1280×800, компактный уровень —
«Очистить чек» виден, ничего не перекрывается) и оплата.
- docs/pos-screenshots/density/: экран продажи в 1280×720/800, 1366×768, 1920×1080
(подтверждает адаптив панели по высоте и шапки по ширине) + раздел в галерее.
- Перегенерированы «Стало»-кадры и compare-*.png — вёрстка 1:1 с макетом сохранена.
- docs/pos-ui-progress.md: раздел «Полировка» 7/7.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Текст во ВСЕХ кнопках по центру: HorizontalAlignment=Stretch + Horizontal/
VerticalContentAlignment=Center в стилях Button.pos/key/seg (раньше key/seg не
наследовали центровку → цифры/«−/+»/«Сброс»/«⌫» липли влево-вверх).
- Клавиатура оплаты — ровная сетка 3×4 одинаковых крупных клавиш (72px), цифры по центру.
- Быстрые суммы и сегменты «Нал/Карта/Смешанная» — UniformGrid одинаковой ширины;
сегменты слитным переключателем; «Без сдачи» не обрезается.
- Модалка оплаты по высоте содержимого, по центру, на затемнённой подложке (#0F1F17 ~40%).
- Правая панель: ровная 2-кол. сетка вторичных кнопок; добавлены «Возврат · F9» и
«Внесение/Выплата · F10»; «Очистить · Esc» — красный контур во всю ширину; без пустот
(блок компактный, Оплатить сразу под ИТОГО).
- Строка корзины: степпер 44×44 с количеством по центру, отступ до иконки удаления.
- Экран продажи снимается С ОБОЛОЧКОЙ (верхняя полоса + капсулы горячих клавиш);
«Избранное» — шеврон ▾/▸. --uitest OK, 44 unit зелёные.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Избранное: Product.IsFavorite/FavoriteOrder (миграция Phase37), в POS-синке
(ProductSyncDto) и в карточке товара (ProductInput). Касса: PosStore хранит
флаг (+ALTER для старых БД) и GetFavorites(); на экране продажи — сворачиваемая
сетка плиток «быстрых товаров» (товары без штрихкода: хлеб, овощи на вес),
тап добавляет в чек. Unit-тест GetFavorites (порядок/фильтр). 44 POS unit зелёные.
- Тёмная тема — опция: кнопка-переключатель в шапке (ToggleTheme), выбор
сохраняется на устройстве (kv device.theme), применяется при старте. На тех же
токенах (ThemeDictionaries Light/Dark). По умолчанию — светлая. Кадр «тёмная тема» в галерее.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>