Commit graph

527 commits

Author SHA1 Message Date
nns 85e486abc7 docs(pos-ui): реальное окно Windows 11 — новая светлая тема
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:53:57 +05:00
nns 29ef76990e fix(pos-ui): выравнивание по замечаниям (кнопки, клавиатура, модалка, правая панель)
- Текст во ВСЕХ кнопках по центру: 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>
2026-10-08 13:46:17 +05:00
nns ac55da8d06 feat(pos): избранные товары (плитки) + переключатель тёмной темы
- Избранное: 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>
2026-10-08 13:35:56 +05:00
nns 7a93c1941d feat(pos-ui): светлая стильная тема по умолчанию (Square/Loyverse-подход)
По просьбе владельца («фон мрачный — сделай светлее, стильнее, удобнее»).
- Дизайн-система на токенах: Styles/Tokens.axaml (ThemeDictionaries Light/Dark) +
  Styles/PosStyles.axaml (карточки/кнопки/чипы/клавиши/сегменты). RequestedThemeVariant=Light.
  Палитра: фон #F4F6F5, карточки белые, бренд-зелёный #16A34A, опасное — красный контур,
  предупреждение — янтарь. Inter, крупная иерархия, скругления 12–14, мягкие тени, сетка 8px.
- Экран продажи: белая верхняя полоса (лого/точка/кассир + чипы смены и связи), поиск со
  скан-иконкой, корзина-карточки со степпером [−]N[+] и удалением, скидка в строке зелёным,
  пустая корзина-заглушка, правая карточка чека с крупным зелёным ИТОГО и «Оплатить · F12»,
  вторичные кнопки-контуры, капсулы горячих клавиш.
- Оплата (светлое модальное): сегменты Наличные/Карта/Смешанная, быстрые суммы, цифровая
  клавиатура, крупная «Сдача».
- Вход (логин + PIN-пад), смена/Z-отчёт (разница цветом), возврат (степперы) — в том же стиле.
- Кнопки ≥48px, клавиши крупные. Скорость не ухудшилась (старт 149мс, скан 11мс, поиск 33мс).
  --uitest OK, 43 unit зелёные. Галерея: разделы «Стало»/«Было».

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:26:07 +05:00
nns 7437305265 docs(pos): итог доводки — full-chain 16/16, смоки, хэши коммитов
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:03:47 +05:00
nns 84fc350bb6 test(pos): реальное окно на Windows 11 + демо-режим + раздел галереи
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
- --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>
2026-10-08 09:55:20 +05:00
nns 9cca062061 perf(pos): R2R-сборка + замеры первого запуска Windows + Defender-гайд
- Публикация 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>
2026-10-08 09:44:06 +05:00
nns 6b959ac59d feat(pos): быстрый вход кассира по PIN (grant_type=pin) + lockout
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
- Сервер: 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>
2026-10-08 09:38:36 +05:00
nns ff69dec527 feat(pos): регистрация устройства на точке продаж + привязка кассира
- Сервер: /api/me отдаёт retailPointIds (точки, к которым привязан сотрудник).
- Касса: DeviceRegistration (чистая логика, 5 unit-тестов) — первый запуск:
  админ выбирает точку из списка активных (сохраняется на устройстве, kv);
  кассир на незарегистрированном устройстве → «обратитесь к администратору»;
  кассир, не привязанный к точке устройства → «вы не привязаны к этой кассе»;
  админ работает на любой точке. Смена точки — кнопка-сброс (новую выберет
  только админ). Экран входа: шаг выбора точки (ComboBox активных точек).
- Заменяет прежний «берётся первая активная» (ошибка при двух точках).
- Тесты: unit (5 решений гейта) + integration (/api/me retailPointIds кассира).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:24:51 +05:00
nns 01b47cc0c8 feat(pos): возврат по чеку — экран выбора позиций + защита от over-return
- Сервер: 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>
2026-10-08 09:16:48 +05:00
nns c5ff1ade94 fix(pos-ui): формат чисел KZ/RU, скидка в строке, центровка/обрезка кнопок
По итогам проверки 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>
2026-10-08 09:07:29 +05:00
nns 87eb48cca9 docs(incident): menu-walk demo-cashier 403 — root cause + фикс + retest
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
Инцидент #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>
2026-10-08 08:40:44 +05:00
nns 9dc033d07a fix(money): кассир открывает смену без доступа к модулю «Деньги» (403)
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Инцидент 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>
2026-10-08 08:28:36 +05:00
nns bd5d43fdf5 docs(mobile-api): итог + деплой на стенд + хэши коммитов
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:46:53 +05:00
nns ad812ee2b5 docs(mobile-api): описание API для мобильного клиента + прогресс
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:39:37 +05:00
nns 14001069a2 test(mobile-api): unit + integration доработок для «FM Склад»
- unit: WeightedBarcode (префиксы/код/вес/цена/настройки) + RolePermissions.Effective
  (SuperAdmin/Admin/роль × простой/расширенный) — 10 тестов.
- integration (Testcontainers): фильтр остатков по вложенной группе; добавление
  штрихкода (201/идемпотентно/409 дубль/400); /api/me permissions; весовая этикетка
  в by-barcode (товар + количество) — 4 теста.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:39:37 +05:00
nns 2a4ba14d38 feat(auth): эффективные права пользователя в /api/me (единый источник)
- RolePermissions.Effective(role, isSuperAdmin, isAdmin, advancedMode) — флаги с
  учётом роли и простого/расширенного режима; AdvancedOnly — единый список
  advanced-only прав (зеркалит [RequiresAdvancedMode]).
- /api/me теперь отдаёт permissions (имя→bool). Мобильное и веб скрывают одно и то же.
- Веб: хук useCan() читает me.permissions (раньше гейтил только по именам ролей).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:39:37 +05:00
nns 7231c83d23 feat(inventory): фильтр остатков по группе товаров с вложенными
GET /api/inventory/stock?groupId= — остатки по группе включая все вложенные
подгруппы (через денормализованный ProductGroup.Path). Комбинируется с
storeId/search/сортировкой. Нужно мобильному «FM Склад» для навигации по категориям.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:39:37 +05:00
nns 5173eaa07c feat(catalog): штрихкоды товара — добавление + весовые этикетки
- POST /api/catalog/products/{id}/barcodes {code, kind}: добавить штрихкод к
  товару, уникальность в организации, 409 «штрихкод уже у товара X» (+название),
  идемпотентно при повторе тому же товару, автоопределение типа по длине.
- Весовые этикетки (внутримагазинные EAN-13, как в МойСкладе): общий парсер
  food-market.shared/Barcodes/WeightedBarcode (настраиваемые префиксы веса/цены,
  длина PLU); касса pos.core делегирует туда. Настройки организации
  (WeightBarcode*: enabled/префиксы/длина кода) + миграция Phase35.
- GET /api/catalog/products/by-barcode/{value} разбирает весовую этикетку →
  товар + количество (вес) / встроенная цена; обычный ШК — как прежде.
- GET/PUT /api/organization/settings отдаёт/принимает настройки (блок весовых
  применяется только если передан — round-trip-safe для текущей веб-формы).
- Офлайн-каталог ProductSyncDto: явный isWeighed (packaging==2) для мобильного/кассы.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:39:20 +05:00
nns dd5604b6ea docs(pos): итог + хэши коммитов в прогресс-док
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:06:09 +05:00
nns b305cc9b9a feat(pos): отложенный чек (park/resume) + снимок корзины
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
- Cart.Snapshot()/Restore() — независимая копия строк и скидки на чек.
- SaleViewModel: ParkCommand («Отложить» — сохранить чек, начать новый) и
  ResumeCommand («Вернуть» — восстановить отложенный); кнопки на экране продажи.
- Unit-тест независимости снимка (38 POS unit-тестов зелёные). Скриншоты обновлены.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 05:03:18 +05:00
nns 81085aed8b build(pos): сборка Win/Linux + AppImage, документация, скриншоты
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
- deploy/pos-publish.sh: self-contained Windows x64 (zip) + Linux x64 (tar.gz) +
  AppImage (если есть appimagetool); VERSION.txt для автообновления.
- docs/pos.md — инструкция кассиру/администратору (установка, горячие клавиши,
  смена, продажа, возврат, весы, печать, офлайн, фискализация-позже, автообновление).
- docs/pos-moysklad-reference.md — сверка розничной модели с МойСклад.
- docs/pos-progress.md — честный статус 11/11 пунктов + замеры + известные огранич.
- docs/pos-screenshots/ — 20 кадров (1920×1080 + 1366×768) + index.html галерея.
- .gitignore: сборки кассы (deploy/pos-dist) и TestResults — не в git.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 04:59:06 +05:00
nns cbf92dca3b feat(web): карточка скачивания кассы на странице «Кассы»
Запрашивает GET /api/pos/v1/version и показывает версию + кнопки «Скачать для
Windows / для Linux» (ссылки из конфигурации сервера, секция Pos). Если ссылки
не настроены — подсказка администратору.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 04:58:54 +05:00
nns fcd4a69624 feat(pos-ui): WPF→Avalonia 11, живая касса кассира (Win/Linux)
- Кроссплатформенный Avalonia-UI (net8.0, не net8.0-windows): экраны вход/
  продажа/оплата/смена/возврат, тёмная тема, ViewLocator, компилируемые привязки.
- Живое связывание: логин→сессия→Refit-API, привязка к точке; продажа (скан/
  поиск/количество/весовой/скидки/удаление), модальная оплата → запись чека в
  офлайн-очередь + печать + попытка выгрузки; смена open/close/drawer на
  api/money/shifts; горячие клавиши F1/F2/F7/F9/F10/F12/Esc/Del (работа без мыши);
  индикатор связи/очереди + фоновая синхронизация; автопроверка версии.
- Оборудование: ESC/POS-билдер (CP866, USB/COM/сеть, 58/80мм) + текст/PDF
  запасной; весы CAS/Масса-К (COM) + ручной ввод; IFiscalProvider — заглушка.
- DpapiTokenStore (Windows, scope CurrentUser) для refresh-токена; 0600 на Linux.
- Инструменты CLI: --smoke (замеры/сценарий без UI), --screenshots (headless
  рендер экранов), --uitest (headless UI-автотест, 15 проверок, Avalonia.Headless).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 04:58:39 +05:00
nns 2b63bc9c66 feat(pos-core): логика кассы без UI + 37 unit-тестов
- Модели (товар/корзина/строка/смена), парсер весовых ШК (EAN-13 20–29),
  корзина (штучный инкремент, весовой, скидки строка/чек с клампом), математика
  оплаты и смены (должно/факт/разница).
- PosStore на raw Microsoft.Data.Sqlite (быстрый старт, AOT-дружелюбно): каталог
  + штрихкоды + очередь продаж + kv; индексы по штрихкоду/NameLower (кириллица
  не сворачивается через LIKE) и barcodes.ProductId (дельта-синк O(n), не O(n²)).
- SyncService: дельта-pull каталога + push очереди с детерминированным
  idempotency-ключом (MD5 отсортированных ClientSaleId → один набор = один ключ).
- Auth: password/refresh grant, ITokenStore (FileTokenStore 0600 на Unix,
  InMemory для тестов). Checkout.BuildSale: сборка серверного чека, скидка на чек
  распределяется по строкам (сервер понимает только построчную). UpdateCheck.
- Тесты: штрихкод/корзина/оплата/смена/стор/синк-ключ/checkout/офлайн(5 без
  дублей)/версия — 37 зелёных.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 04:58:22 +05:00
nns 606b81b4d9 feat(pos-api): привязка чеков кассы к смене/точке + возвраты + версия
- PosSaleDto: CashShiftId/RetailPointId/IsReturn/ReferenceSaleId (nullable,
  обратносовместимо с v1). PosController проставляет их в RetailSale, резолвит
  склад по точке продаж, проверяет что смена открыта. Без этого чеки кассы не
  попадали в Z-отчёт/материализацию денег смены (MoneyService агрегирует продажи
  по CashShiftId).
- Возврат покупателю (IsReturn): движение +остаток (CustomerReturn), без
  pre-flight на остаток; наличные к выдаче, учитывается в смене.
- GET /api/pos/v1/version (anon): версия + ссылки на сборки из конфигурации Pos
  (автообновление кассы + ссылка в админке).
- Интеграционные тесты: продажа в смене попадает в expected cash при закрытии;
  возврат возвращает остаток (9/9 PosSyncTests зелёные, Testcontainers).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 04:58:05 +05:00
nns 6752601ed8 docs(money): хэши коммитов в прогресс-док
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:11:34 +05:00
nns 0977c639cd docs(money): модель «деньги смены → остатки» + МойСклад reference + прогресс
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:11:10 +05:00
nns 005c4ac5bf test(money): независимый инвариант остатка счёта (нач+платежи+смены) + unit/integration
full-chain: indepBalance() считает остаток независимо (касса += факт−размен,
эквайринг += картой−возвраты) и сверяет с API /balances — а не с суммой из того же
API; шаг 8 — оплата нал ≤ остатка кассы + проверка отказа при превышении (409).
Unit: shift-net == факт−размен (MoneyMathTests). Integration: закрытие смены пишет
нал в остаток кассы, расход больше остатка → 409 (MoneyModuleTests); существующим
тестам оплаты дан достаточный остаток кассы.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:11:09 +05:00
nns 1e6d7fb2ab fix(money): движения смены попадают в остатки счетов + запрет отрицательного остатка
Раньше продажи/возвраты/внесения/выплаты/расхождение смены не влияли на остаток
кассы (касса уходила в −, эквайринг оставался 0). Теперь при закрытии смены
MoneyService.MaterializeShiftMovementsAsync создаёт Posted-движения money_transactions
по типам (Category): продажи нал/карта, возвраты нал/карта, внесение, выплата,
излишек/недостача — привязанные к смене, идемпотентно. Остаток кассы/эквайринга и
отчёт «Деньги» теперь верны автоматически (всё читает money_transactions).

Отрицательный остаток: расход (CashOut/PaymentOut/TransferOut) больше остатка счёта
и выплата из смены больше наличных смены → 409 insufficient-funds; настройка
Organization.AllowNegativeBalance (по умолч. выкл., меняет только Admin).

Миграция Phase34 (idempotent): money_transactions.Category/.CashShiftId,
organizations.AllowNegativeBalance.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 03:11:09 +05:00
nns b6c4d6056d docs(e2e): хэши коммитов full-chain в прогресс-док
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:48 +05:00
nns 6f10896d8c chore(deploy): SQL-скрипты очистки Демо и исправления внутренних EAN-13
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
stage-reset-demo.sql — очистка орги от транзакционных данных (KEEP каталог/
сотрудники/точки). fix-internal-ean13.sql — пересчёт неверной контрольной цифры у
уже выданных внутренних EAN-13 (на стенде исправлен 41 код, список — docs/ean13-fixed-20261008.txt).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:11 +05:00
nns 886cb92f30 test(e2e): сквозной сценарий full-chain «жизнь магазина» + харнес со скриншотами
16 шагов против настоящего стенда: регистрация→справочники→сотрудники/точки→
деньги→3 приёмки→оплаты→смена/продажи/возврат/Z→склад→отчёты→инварианты→откат.
Сверяет конкретные числа и инварианты, 0×5xx/0×тостов/0×console.error. Режимы
C (temp-орг) и B (Демо на реальном каталоге). Hi-res скриншоты каждого процесса +
галерея. Включён в nightly-verify и quality-watchdog (скрипты в $HOME).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:11 +05:00
nns fddf552411 fix(reports): «сегодня/за день» считать по Asia/Almaty (UTC+5), а не по UTC
Хелпер BusinessTime (UTC+5). Дашборд (RevenueToday/Week/Month + график) и
группировка period:day в отчётах продаж/прибыли теперь по местной дате.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:11 +05:00
nns 009a9d8a50 fix(web): EAN-13 контрольная цифра, валюты в приёмке сканированием, поиск товара на накладной
1) digitsChecksum считал веса слева — для 12-значного тела (EAN-13) чётность
переворачивалась и контрольная цифра была неверной; теперь справа налево
(EAN-8/UPC-A не изменились). 2) SupplyScanPage читал /api/catalog/currencies как
массив, а это PagedResult {items} → список валют пуст (нет KZT). 3) InvoiceReviewPage
слал ?q=, а API ждёт ?search= (PagedRequest.Search).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:11 +05:00
nns 839fcaf9fc fix(inventory): пустая инвентаризация больше не обнуляет непосчитанное
Авто-подтянутые строки создаются как ActualQty=BookQty (Diff=0) вместо
ActualQty=0 (Diff=-stock). Проведение не трогает непересчитанные позиции (в т.ч.
вне выбранной группы); истинный ноль вводится явным ActualQty=0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:11 +05:00
nns 8785fd60d1 fix(money): открытие смены на неактивной/непривязанной точке продаж → отказ
OpenShiftAsync проверяет RetailPoint.IsActive (retail-point-inactive) и привязку
кассира к точке (retail-point-not-assigned; у кого привязок нет — на любой точке).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:11 +05:00
nns aedcd3f83a fix(employees): правка сотрудника с привязкой к точке падала 500 (EF8 nav-collection)
DbUpdateConcurrencyException «0 rows affected» при PUT сотрудника, у которого
есть EmployeeRetailPointAssignment. Замена nav RemoveRange+Clear+Add на
ExecuteDeleteAsync по EmployeeId + DbSet.Add (как в Supplies/Enters/Losses.Update).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:11 +05:00
nns 24646e0649 fix(auth): кассир без модуля «Деньги», кладовщик со складскими правами, ИЛИ-семантика прав
Роль «Кассир» больше не имеет MoneyView (видит только свою смену/Z через
CashShiftOperate); роль «Кладовщик» получает InventoryEdit/EnterEdit/LossEdit
(веб уже показывал эти пункты — API теперь совпадает). PermissionRequirement
поддерживает список прав через запятую (ИЛИ); CashShifts List/Get/Report →
MoneyView,CashShiftOperate. DevDataSeeder: дефолты + backfill существующих орг.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 02:10:11 +05:00
nns 659a749d7f docs(money): пользовательская инструкция docs/money.md + финал прогресс-дока
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
docs/money.md — как открыть смену, оплатить приёмку, смотреть долги/остатки,
права ролей. Прогресс-док: пп.8–9 отмечены, журнал с тремя фиксами по ходу
e2e (back-fill прав, date-only→UTC, список счетов 500). Итог 10/10.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-07 22:49:21 +05:00
nns 4a064de96b fix(money): список счетов 500 на непустых данных (EF.Property xmin в памяти)
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
MoneyAccountsController.List проецировал xmin через EF.Property ПОСЛЕ
ToListAsync на AsNoTracking-сущности → InvalidOperationException (shadow-
свойство вне трекера). С пустым списком не всплывало (нет строк), с данными —
500, и ломались ВСЕ money-страницы, дёргающие useMoneyAccounts (счета/смены/
платежи) — поймал menu-walk на stage. Переносим xmin в server-side Select.
Регресс закрыт: date-only тест теперь ещё и GET-ит список с данными.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-07 22:40:25 +05:00
nns 174cb563bf fix(money): нормализовать date-only даты документов к UTC (Npgsql timestamptz)
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
UI (DateField) шлёт openingDate/date как "YYYY-MM-DD" → DateTime Kind=Unspecified
→ Npgsql не пишет в timestamp with time zone → 500 при создании счёта/платежа/
корректировки. MoneyMath.AsUtc нормализует (Unspecified→UTC as-is дата,
Local→ToUniversalTime, Utc→без изменений); применено в MoneyAccounts/
MoneyTransactions/CounterpartyAdjustments на всех сайтах записи даты.

Интеграционные тесты раньше слали DateTime.UtcNow (Kind=Utc) и баг не ловили —
добавлен Account_create_accepts_date_only_opening_date_from_ui (строго
"2026-10-07"). Money integration 8/8 ✓, unit 25/25 ✓.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-07 22:29:38 +05:00
nns 7e3841ad48 fix(money/seed): back-fill money-прав кассиру и статей расходов для старых орг
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
SeedEmployeeRolesAsync пропускает уже засиженные орги (guard anyRole), поэтому
демо-орга на stage/prod осталась бы без MoneyView/CashShiftOperate у кассира →
403 на /api/money/shifts и красный menu-walk. EnsureMoneyDefaultsAsync
(идемпотентно, во всех env на старте) проставляет эти флаги системной роли
«Кассир» по всем оргам и гарантирует 5 системных статей расходов. Прочие права
кассира сохраняются (in-place мутация owned JSON). DemoSeederIdempotency 2/2 ✓.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-07 22:16:46 +05:00
nns deef65d819 test(money): unit (MoneyMath 25) + integration (7 на Postgres) + MoneyMath refactor
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
- MoneyMath: вынесены чистые формулы (статус оплаты, ожидаемая наличность,
  разница смены, остаток счёта, долг поставщика, защита от переплаты);
  сервис/SuppliesController/MoneyReportsController теперь зовут их.
- UnitTests/MoneyMathTests: 25 кейсов на формулы + money-флаги RolePermissions.
- IntegrationTests/MoneyModuleTests (реальный Postgres, 7 [Fact]):
  мультитенантность (Б не видит счета А), инвариант остатка, частичная→полная
  оплата приёмки, переплата→409, долг поставщика, продажа без смены→409 +
  после open→ok, расчёт expected/difference при закрытии смены.
- ApiActor: helpers CreateRetailPoint/CreateMoneyAccount/CreatePostedSupply.
- tests/e2e/scrape-moysklad.ts — скрейпер для docs/money-moysklad-reference.md.

Прогон: UnitTests 25/25 ✓, IntegrationTests money 7/7 ✓ (33s, Testcontainers).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-07 22:11:19 +05:00
nns 830cd73ee0 feat(money/web): UI раздела «Деньги» — счета, платежи, смены, долги, отчёт (п.7)
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
- Раздел «Деньги» в sidebar: Отчёт/Счета и кассы/Платежи и ордера/Смены/
  Долги поставщикам. Админ — всё; кассир — только смены; кладовщик — ничего.
- Страницы (src/pages/money/): MoneyAccountsPage, ExpenseItemsPage,
  MoneyTransactionsPage (+ переводы), CashShiftsPage (open/close/внесения/
  выплаты/Z-отчёт), SupplierDebtsPage (+ корректировки), MoneyReportPage
  (остатки + движение за период).
- Приёмка: SupplyPaymentSection (статус/оплачено/остаток + «Оплатить»
  наличными/с банка, частичная оплата); в списке приёмок — колонка и фильтр
  статуса оплаты.
- src/lib/money.ts (enum'ы/DTO/лейблы/lookups), типы SupplyDto/SupplyListRow
  +payedSum/+paymentStatus, роуты в App.tsx, i18n ru/en.

Без AdvancedModeGuard — модуль для простого режима. tsc -b + eslint зелёные.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-07 21:59:32 +05:00
nns a25b5b3277 feat(money): бэкенд модуля «Деньги» для простого режима (пп.0–6)
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Сверка с МойСкладом (docs/money-moysklad-reference.md) + домен/инфра/API:

- Счета и кассы (MoneyAccount: Cash/Safe/Bank/Acquiring, начальный остаток,
  привязка к магазину, IsDefault/IsActive, инвариант CurrentBalance).
- Денежные документы (MoneyTransaction: PaymentIn/Out, CashIn/Out, переводы
  парой TransferOut↔TransferIn; статьи расходов ExpenseItem; проведение/отмена
  в Serializable-транзакции через MoneyService).
- Оплата поставщикам: Supply/SupplierReturn.PayedSum + MoneyTransactionLink,
  SuppliesController отдаёт PaymentStatus + фильтр paymentStatus.
- Взаиморасчёты: CounterpartyAdjustment + MoneyReportsController.SupplierDebts.
- Смены кассы: CashShift + CashDrawerOperation (open/close, expected↔actual,
  Z-отчёт), запрет розничной продажи без открытой смены в RetailSalesController.
- Отчёт «Деньги»: balances/movement с проверкой инварианта остатков.

Права: RolePermissions +MoneyView/MoneyEdit/CashShiftOperate; сидер раздаёт
кассиру CashShiftOperate+MoneyView, кладовщику — нет; 5 системных статей
расходов на новую орг. Миграция Phase33a (ручная, с [Migration]+[DbContext]).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-10-07 21:52:04 +05:00
nns e45600df4b feat(invoices+catalog): порт улучшений 06.10.2026 из sklad
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Web / Build + push Web (push) Waiting to run
Docker Web / Deploy Web on stage (push) Blocked by required conditions
Основное:

* Program.cs: SuppressImplicitRequiredAttributeForNonNullableReferenceTypes=true
  + InvalidModelStateResponseFactory → ValidationProblemDetails + Serilog Warning.
  Пустые необязательные строковые поля в InvoiceLine (Note, BarcodeSource и т.п.)
  больше не роняют запрос в 400. humanizeError на фронте уже умеет этот формат.
* InvoiceModels.cs: Name/Source/FilePath → string?.
* Validators.cs: InvoiceSaveLinesValidator (Lines NotNull), InvoiceApplyValidator
  (Guid.Empty на Store/Currency = ошибка, SupplierId опционален).

Служебный «Поставщик не указан» (адаптация sklad §11 под multi-tenant):

* Phase32b миграция добавляет Counterparty.IsPlaceholder bool + partial index
  по IsPlaceholder=true.
* InvoicesController.Apply: supplierId опционален; если не указан —
  ResolvePlaceholderCounterpartyAsync ищет/создаёт одного служебного per org.
  Имя из накладной в комментарий документа НЕ пишется.
* CounterpartiesController: служебный всегда последним в List сортировках,
  Update и Delete при IsPlaceholder → 409 Conflict.
* CounterpartyDto.IsPlaceholder + Mapster-config обновлены.
* Автоподбора/автозаведения контрагентов нигде не было — специально проверили.

Applied-накладная readOnly (§10):

* InvoiceDetailDto: добавлены supplyNumber + processedAt.
* InvoiceReviewPage: applied-режим — плашка «Черновик приёмки № … создан …»
  со ссылкой на приёмку, шапка и строки readOnly, скан-блок и apply-кнопка
  скрыты. После успешного apply — invalidateQueries, экран сразу readOnly.

Текст ошибки apply (§5) и список накладных (§6):

* ApplyDialog: error → detail → title → (код), __silent на axios.
* Invoices list: parseServerDate подшивает «Z» если его нет, «Загружена DD.MM.YY HH:MM»
  в бейдже статуса (видимо в десктоп-таблице и в мобильной карточке — у нас общая).

Тесты + проверки:

* tests/food-market.IntegrationTests/InvoiceApplySklad0610Tests.cs — 5 кейсов:
  SaveLines со всеми null, apply без поставщика с idempotency по placeholder'у,
  Delete/Update placeholder → 409, applied detail содержит processedAt +
  hasFiles=false, apply с Guid.Empty storeId → ValidationProblemDetails.
  Все 5 ✓.
* stage retest на https://test.admin.food-market.kz: upload+SaveLines(null-fields)+
  apply(без поставщика)+apply(с ИП Бегимбаев)+DELETE placeholder → весь flow
  зелёный, служебный один на орг, hasFiles=false после apply.
* quality-watchdog step 9 (menu-walk): 3/3 passed (3.7m).
* Фото-накладная через Claude CLI не гонял — пайплайн apply→DeleteStored
  закрыт через hasFiles=false в тестах и реальный stage smoke.

docs/supply-inventory.md — шаг 7 расписан под необязательного поставщика,
новый шаг 8 (applied → readOnly), миграция Phase32b в таблице «Файлы».

docs/sklad-0610-progress.md — финал 9/9 с подробным журналом решений.

Пред-существующие (не трогал):

* OrgAuditLogTests.Counterparty_update_diff_contains_before_after → 403 от
  [RequiresAdvancedMode] на /api/admin/audit-log (commit 921bca0, s29);
* ApiReferenceDocsJobTests.Scans_endpoints_with_doubly_nested_generic_return —
  регекс-тюнинг доков.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-07 19:50:03 +05:00
nns 99bf6c9f3e fix(seed): DemoTenantSeeder гардит по наличию ЛЮБЫХ товаров в орге
Some checks failed
Auto-tag / Create date-tag (push) Has been cancelled
CI / Backend (.NET 8) (push) Has been cancelled
CI / Web (React + Vite) (push) Has been cancelled
CI / POS (WPF, Windows) (push) Has been cancelled
Docker API / Build + push API (push) Has been cancelled
Docker API / Deploy API on stage (push) Has been cancelled
Старый idempotency-маркер — Product с Article LIKE 'DEMO-%'. После того как
«Демо-магазин» на стенде наполнили реальным каталогом из МойСклада
(артикулы не DEMO-*), маркер срабатывал false и QuickLoginDemoSeeder при
каждом рестарте стенда пытался залить фиктивный каталог заново — падая
на unique-индексе IX_product_barcodes_OrganizationId_Code (23505). В БД
ничего лишнего не попадало (транзакция откатывалась), но лог stage-api
получал 9 ERR в сутки.

Фикс: SeedAsync и PeekAsync считают «уже сидировано» при любом Product в
орге. Поведение из UI (POST /api/admin/seed-demo) не меняется для свежих
org'ов. Прочие стартовые сидеры (OpenIddictClientSeeder,
SystemReferenceSeeder, DevDataSeeder) и HangfireJobsConfigurator — уже
идемпотентны, аудит в docs/seeder-noise-progress.md.

Integration-тест:
- SeedDemo_second_call_on_populated_org_returns_already_seeded
- SeedDemo_on_org_with_imported_catalog_skips_without_duplicate_barcode

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-06 00:50:50 +05:00
nns c4a59d7bf2 docs(prod): репа догоняет новую раскладку postgres на prod-vm
Some checks failed
Auto-tag / Create date-tag (push) Waiting to run
CI / Backend (.NET 8) (push) Waiting to run
CI / Web (React + Vite) (push) Waiting to run
CI / POS (WPF, Windows) (push) Waiting to run
Docker API / Build + push API (push) Waiting to run
Docker API / Deploy API on stage (push) Blocked by required conditions
Docker Public / Build + push Public (test + latest) (push) Has been cancelled
Docker Web / Build + push Web (push) Has been cancelled
Docker Public / Deploy :test → test.food-market.kz (push) Has been cancelled
Docker Web / Deploy Web on stage (push) Has been cancelled
05.10.2026 общий postgres-инстанс с чужими боевыми базами (sklad, purchase,
calcman, calcman_staging, makesales + мусорная старая food_market) вынесен
из compose прода food-market в отдельный compose-проект shared-postgres
(контейнер shared-postgres, порт 5434, том food-market-postgres-data external).
Прод food-market поднимается в собственный контейнер food-market-prod-postgres
(порт 5437, том food-market-prod-postgres-data). Простой при разделении — 12с,
соседи живы. См. docs/shared-postgres-followup-progress.md.

Этот коммит синхронизирует репозиторий, чтобы следующий деплой из main не
воскресил старую раскладку:

- deploy/docker-compose.yml: container_name/port/volume приведены к прод-файлу
  (food-market-prod-postgres, 127.0.0.1:5437, food-market-prod-postgres-data).
- deploy/shared-postgres/ (новое): документационная копия соседнего compose'а,
  с явной пометкой «food-market им не управляет».
- deploy/food-market-backup.sh / anonymize-prod.sh / db-schema-diff.sh:
  defaults FM_PG_CONTAINER / FM_PROD_CONT = food-market-prod-postgres.
- docs/RUNBOOK.md: новый раздел «Postgres на prod-vm» с таблицей трёх
  инстансов и явным запретом трогать shared-postgres из наших скриптов.
- docs/backup-restore.md: контейнер в таблице и примерах — новый.

Guards (не в репе — живут в ~/deploy-stage.sh и ~/quality-watchdog.sh)
расширены симметрично: стенду запрещены shared-postgres, food-market-prod-
postgres[-data], 5434/5437; проду — food-market-postgres-data (чужие данные).
Проверка: docker compose config/ps на prod-vm shared-postgres не упоминают,
grep по репе — ни один скрипт не делает docker exec в shared-postgres.
2026-10-06 00:35:54 +05:00
nns ef29acb0d1 docs(port): stage retest + menu-walk 3/3 зелёный
Some checks are pending
Auto-tag / Create date-tag (push) Waiting to run
Smoke stage:
- POST /purchases/invoices/upload-photos → 400 (не 404) без файлов
- mobile-catalog: 31 269 ШК, JSON 3.44 МБ → gzip 1.75 МБ, ETag работает,
  повтор с If-None-Match → 304
- stage-ui-menu-walk.spec.ts: 3/3 passed, 0 ошибок у admin/keeper/cashier

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