food-market/src/food-market.domain/Purchases/Enter.cs
nns e392bf8ae9 feat(enters): оприходование товара без поставщика (P1-1)
Domain Enter+EnterLine (мирорит Supply, но без SupplierId и без cost rollup).
EF-конфигурация, миграция Phase6a_Enters (idempotent CREATE TABLE).
Контроллер api/inventory/enters: CRUD + Post/Unpost. Post создаёт
StockMovement тип Enter; Unpost блокируется, если остаток ушёл бы в минус.
Web: /inventory/enters (list + edit), пункт «Оприходования» в сайдбаре
Admin/Storekeeper.

Тесты: 4 интеграционных (post раздаёт stock, unpost откатывает, double
post→409, tenant-изоляция A/B, unpost блокируется при минусе после продажи).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-28 09:18:13 +05:00

63 lines
2.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using foodmarket.Domain.Catalog;
using foodmarket.Domain.Common;
namespace foodmarket.Domain.Purchases;
public enum EnterStatus
{
Draft = 0,
Posted = 1,
}
/// <summary>Оприходование: документ постановки товара на склад БЕЗ поставщика.
/// Используется для начальных остатков (при запуске учёта), излишка по
/// результату инвентаризации, возврата товара из подразделения и т.п.
///
/// Отличается от <see cref="Supply"/>: нет SupplierId; total — не сумма закупки,
/// а сумма по UnitCost (стоимость оприходованного товара по балансовой цене).
/// При Post создаёт <see cref="Inventory.StockMovement"/> с типом
/// <see cref="Inventory.MovementType.Enter"/>.</summary>
public class Enter : TenantEntity
{
/// <summary>Уникальный в рамках организации номер документа (например "О-2026-000001").</summary>
public string Number { get; set; } = "";
public DateTime Date { get; set; } = DateTime.UtcNow;
public EnterStatus Status { get; set; } = EnterStatus.Draft;
public Guid StoreId { get; set; }
public Store Store { get; set; } = null!;
public Guid CurrencyId { get; set; }
public Currency Currency { get; set; } = null!;
public string? Notes { get; set; }
/// <summary>Сумма по строкам = Σ Quantity·UnitCost.</summary>
public decimal Total { get; set; }
public DateTime? PostedAt { get; set; }
public Guid? PostedByUserId { get; set; }
public ICollection<EnterLine> Lines { get; set; } = new List<EnterLine>();
}
public class EnterLine : TenantEntity
{
public Guid EnterId { get; set; }
public Enter Enter { get; set; } = null!;
public Guid ProductId { get; set; }
public Product Product { get; set; } = null!;
public decimal Quantity { get; set; }
/// <summary>Балансовая цена единицы (по которой товар ставится на учёт).
/// Не пересчитывает <c>Product.Cost</c> — оприходование не образует
/// себестоимости (в отличие от приёмки).</summary>
public decimal UnitCost { get; set; }
public decimal LineTotal { get; set; }
public int SortOrder { get; set; }
}