«InventoryCancelResults» (22) не влезал в OrgAuditLog.Action varchar(20) →
SqlState 22001 → cancel-results возвращал 500. Укоротил до «InvCancelResults».
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Заголовок секции кассы на /pos → «Быстрая касса, которая работает и без
интернета» (как на главной). Grep по src/food-market.public на «светл» — чисто.
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>
Витрина пересеяна с исправленной фасовкой; админка пересобрана с переводами и
валютой ₸. Пересняты и пережаты в WebP: дашборд (Сводка/онлайн/Низкий остаток),
каталог (₸, один «Все товары», корректная фасовка), карточка товара и остальные.
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>
Добавлена проверка: создать инвентаризацию → завершить (остаток не меняется) →
создать оприходование излишков «на основании» → виден связанный документ → провести
оприходование (остаток +3) → в оприходовании ссылка «на основании инвентаризации №…».
Старый путь /post (мобильная совместимость) по-прежнему проверяется. 16/16 зелёный на стенде.
Co-Authored-By: Claude Opus 5.5 <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>
БЕЗОПАСНОСТЬ:
- Страница входа больше НЕ префилит e-mail/пароль dev-админа и не показывает
подсказку «Dev admin: …» — только в import.meta.env.DEV на localhost
(на стенде/проде поля пустые).
- DevDataSeeder: пароль SuperAdmin/демо-админа ТОЛЬКО из секрета
(Seed:SuperAdminPassword / env SEED_SUPERADMIN_PASSWORD). Дефолт «Admin12345!»
допустим лишь в Development. На stage/prod (ASPNETCORE_ENVIRONMENT=Production)
без секрета аккаунт с известным паролем НЕ создаётся (warning в лог).
- stage-compose: проброшен Seed__SuperAdminPassword (без дефолта).
- (Пароль существующего SuperAdmin на стенде сменён вручную на сложный и сохранён
в ~/.fm-watchdog/stage-superadmin-password; quick-login по sentinel/master цел.)
ТОСТ 404:
- StageBanner и QuickLoginBlock пробуют необязательный /api/dev/quick-login/accounts
через raw fetch (минуя axios-интерсептор) — на проде/без API 404 больше не
показывается глобальным тостом. На странице входа тостов ошибок нет.
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>
- EmailTemplates (invite/low-stock/weekly-summary): шапка с текстовым
вордмарком «all market» (бренд-цвета, всегда рендерится — без внешних
картинок и привязки к домену) + подпись «ALL MARKET — система учёта торговли».
- Имя отправителя по умолчанию, темы/тела системных писем, экспорт-README,
дневная сводка, тест SMTP → ALL MARKET.
- Цвета писем и домены не менялись.
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>
Правки по замечаниям на windows11-sale.png (VM 1280×800 maximized — высоты
меньше, чем в headless):
1. Адаптив правой панели по высоте (SaleView.axaml.cs, подписка на Bounds):
уровни normal/compact/tiny — сжимаются отступы, ИТОГО, кнопки; скрывается
блок «Последний чек»; ClipToBounds, чтобы ничего не уходило под полосу клавиш.
2. Шапка — Grid вместо StackPanel: чипы в отдельной колонке и не обрезаются;
адаптив по ширине (MainWindow.axaml.cs): <1400 короткие чипы, <1100 без «Магазин…».
BadgesCompact во VM переключает тексты ShiftBadge/QueueBadge.
3. Иконка «Выплата» (одиночная горизонталь) схлопывалась при Stretch=Uniform →
Stretch=None; «Внесение» выровнял так же.
4. Hover строки корзины — светлый #F7FBF8 вместо тёмного из темы.
5. Плитки избранного — Grid *,Auto: цена прибита к низу, у всех на одной линии.
6. Полоса горячих клавиш — выравнивание влево (как в макете).
7. --density: рендер экрана продажи в 1280×720/800, 1366×768, 1920×1080 для проверки.
--uitest OK, 82 unit зелёные, smoke OK, скорость не хуже.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Перенёс макет Mac-Claude (docs/pos-design/pos-mockup.html) в Avalonia по
размерам, а не на глаз:
- Оплата: модалка 880px поверх затемнённого экрана продажи (как в макете);
сегменты Нал/Карта/Смешанная с векторными иконками (активный зелёный —
иконка белая через стиль Button.seg.on Path); быстрые суммы 3×2
(без сдачи/4000/5000/10000/20000/своя сумма); клавиатура 3×4 по 72px.
- Продажа: исправлена подсветка выбранной строки — локальные
Background/IsVisible перекрывали сеттеры стиля :selected; теперь зелёный
акцент слева + светло-зелёный фон работают. Бейдж «Отложенные · N».
Чип связи «На связи · очередь пуста».
- Демо: --demo-pay открывает модалку оплаты для скриншота на Windows;
PayScrim в скриншотере рендерит оплату поверх реальной оболочки продажи.
- Инструмент сверки: CompareRunner (--compare, SkiaSharp) складывает
«макет | касса» рядом → docs/pos-design/compare-*.png.
Скорость не ухудшена (старт 74мс, скан 13.7мс). --uitest OK, 82 unit зелёные.
Co-Authored-By: Claude Opus 4.8 <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>
- --demo: окно с примером чека без логина (software-рендер на Windows, т.к. у
тест-VM нет GPU — иначе окно чёрное).
- Снят реальный экран кассы на Windows 11 (интерактивная сессия tester через
scheduled task /it + PrintWindow): подтверждён нативный рендер — кириллица,
формат «3 362 ₸», кнопки без обрезки → docs/pos-screenshots/windows/ + раздел
«Windows 11» в галерее.
- Ограничения VM (не код, честно в docs): нет GPU → software-рендер; консоль
1280×800 → 1366/1920 реальным окном недоступны (они в headless-кадрах, тот же
движок); меню «Пуск» VM залипает. Автоматизация логики UI — headless --uitest.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Публикация win-x64 с ReadyToRun (по одному RID, nice — dev-vm не уронили).
- Замеры на Windows-VM: первый запуск (свежая распаковка) 3.8–5.4 с (было 7.5 с),
прогретый 219 мс. Первый запуск упирается в Defender (скан свежего неподписанного
114 МБ exe) + холодное чтение диска, не в JIT.
- docs/pos.md: раздел «первый запуск медленный — что делать» (исключение Defender,
прогрев при установке, подпись exe). Trimming оставлен выкл. (Avalonia на рефлексии).
- Мелочь: убран warning CS8826 (имена параметров partial-методов смены).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Сервер: Employee.PinHash (PBKDF2, миграция Phase36); POST
/api/organization/employees/{id}/pin — админ задаёт/снимает PIN (4–6 цифр,
уникален среди активных сотрудников на пересекающихся точках). Кастомный
OpenIddict-грант grant_type=pin (retail_point_id + pin): находит кассира,
привязанного к точке, по PIN и выдаёт токены. Брутфорс-защита — in-memory по
точке (5 неверных → блок 5 мин). Клиент-сидер досоздаёт gt:pin существующим
клиентам (без пересоздания). Пароль остаётся запасным.
- Касса: PIN-пад на зарегистрированном устройстве (маскированный ввод, 0–9/⌫/
Войти), переключение на вход по логину; AuthService.PinLoginAsync.
- Тесты: unit PinHasher (9), integration (3): вход по PIN выдаёт рабочий токен;
5 неверных → блок; дубль PIN на точке → 409. + скриншот PIN-пада в галерее.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Сервер: /api/me отдаёт retailPointIds (точки, к которым привязан сотрудник).
- Касса: DeviceRegistration (чистая логика, 5 unit-тестов) — первый запуск:
админ выбирает точку из списка активных (сохраняется на устройстве, kv);
кассир на незарегистрированном устройстве → «обратитесь к администратору»;
кассир, не привязанный к точке устройства → «вы не привязаны к этой кассе»;
админ работает на любой точке. Смена точки — кнопка-сброс (новую выберет
только админ). Экран входа: шаг выбора точки (ComboBox активных точек).
- Заменяет прежний «берётся первая активная» (ошибка при двух точках).
- Тесты: unit (5 решений гейта) + integration (/api/me retailPointIds кассира).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Сервер: GET /api/pos/v1/sales/by-number/{number} — чек-основание с позициями
и доступным к возврату (продано − уже возвращено, по QtyReturned). POS-путь
возврата теперь валидирует over-return (нельзя вернуть больше остатка) и
инкрементит QtyReturned на исходных строках (как RetailSalesController).
- Контракт: PosReturnLookupDto/PosReturnLineDto; IServerApi.ReturnLookupAsync.
- Касса: экран возврата — найти чек по номеру/скану QR, степпер количества по
каждой позиции (0..доступно, кнопка «Всё»), сумма к выдаче, способ (нал/карта
как в исходном чеке); CheckoutService.CommitReturnAsync пишет возврат в офлайн-
очередь + печать + выгрузка.
- Тесты: integration — lookup by-number, возврат 2 из 3, over-return в Failed,
довозврат 1, QtyReturned/остатки корректны; 404 на неизвестный номер. 11/11 PosSyncTests.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
По итогам проверки Mac-Claude (скриншоты):
- Формат чисел как в вебе/мобильном: «3 422 ₸» (пробел-разделитель тысяч),
вес «1,235 кг» (запятая), единица измерения рядом с количеством («3 шт»).
PosFormat — культура ru-RU с NBSP-разделителем, применяется процессно.
- Скидка на строку видна: «1 560 → 1 500 ₸, скидка 60» под позицией, чтобы
цена×кол-во ≠ сумма не выглядело ошибкой (SaleLineVm.DiscountText/HasDiscount).
- Кнопки: текст по центру по вертикали и горизонтали (стиль Button.pos +
ContentPresenter); «Очистить» и «Enter · Провести и печать» больше не
обрезаются на 1366×768 и 1920×1080 (проверено скриншотами).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Инцидент #1791428701 (quality-watchdog): кассир получал 403 на /api/money/accounts
на странице смен. Фикс — узкий /api/money/shifts/accounts (см. 9dc033d). Retest на
стенде: menu-walk 3/3 роли зелёные.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Инцидент menu-walk 2026-10-08: demo-cashier получал 403 на
GET /api/money/accounts — страница смен (/money/shifts) дёргала его для выбора
кассы при открытии смены, но эндпоинт под MoneyView, а у кассира MoneyView=false
(«кассир не видит денег»), только CashShiftOperate.
- Новый узкий GET /api/money/shifts/accounts (RequiresPermission
"MoneyView,CashShiftOperate"): только активные наличные кассы + эквайринг,
без остатков и банковских счетов. Кассиру достаточно для выбора кассы/эквайринга
при открытии смены, но денег он по-прежнему не видит.
- Веб: CashShiftsPage использует useShiftAccounts() вместо useMoneyAccounts(true).
- Регресс-тесты: кассир 200 на /shifts/accounts (только нал+эквайринг) и 403 на
/money/accounts; /api/me permissions для кассира (advanced-only скрыт).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>