food-market/src/food-market.infrastructure
nns 47a019dc6d feat(demands): оптовая отгрузка контрагенту-юрлицу (P1-5)
Domain Demand+DemandLine - зеркалит RetailSale, но всегда с CustomerId
(обязателен, не nullable), способ оплаты DemandPayment с Credit
(постоплата = дебиторка), без RetailPoint/Cashier.

EF + миграция Phase8a_Demands (idempotent CREATE TABLE).
Контроллер api/sales/demands - CRUD + Post/Unpost. Post создаёт
StockMovement тип WholesaleSale с -Quantity; защита от ухода в минус
(409 со списком конфликтов). Unpost возвращает товар.

ApplyLines пишет в DbSet напрямую (не через nav-collection) и Update
использует ExecuteDelete для старых строк - тот же fix-паттерн что в
RetailSalesController (избегает DbUpdateConcurrency на client-side Id).

Permissions переиспользуют DemandsEdit/DemandsPost (уже в RolePermissions).
Метрики observability: food_market_documents_posted_total{type="demand"}
и documents_error_total{type="demand", reason="serialization"}.

Web: /sales/demands (list+edit) с AsyncSelect контрагентов, способом
оплаты включая Credit, PaidAmount-полем для дебиторки. Сайдбар:
"Оптовые отгрузки" в группе Продажи для Admin.

Тесты: 3 интеграционных (post снижает stock + unpost восстанавливает,
over-stock posting -> 409 без побочных эффектов, tenant-изоляция).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 16:18:49 +05:00
..
Email feat(platform): IEmailSender + MailKit + PlatformSettingsController 2026-05-06 12:39:18 +05:00
Identity feat(roles): три системные роли — Admin/Cashier/Storekeeper 2026-05-06 11:31:15 +05:00
Integrations/MoySklad feat(phase3b): drop IsActive, add ShelfLifeDays, restore PriceType IsSystem/IsRequired 2026-04-25 22:46:34 +05:00
Inventory phase2a: stock foundation (Stock + StockMovement) + OtherSystem counterparty import 2026-04-22 00:51:07 +05:00
Persistence feat(demands): оптовая отгрузка контрагенту-юрлицу (P1-5) 2026-05-28 16:18:49 +05:00
food-market.infrastructure.csproj feat(platform): IEmailSender + MailKit + PlatformSettingsController 2026-05-06 12:39:18 +05:00