using foodmarket.Domain.Money; namespace foodmarket.Application.Money; /// Единый API модуля «Деньги». Контроллеры дёргают только эти /// методы — внутри сервиса сидит вся бизнес-логика: пересчёт /// Supply.PayedSum, парная проводка переводов, расчёт expected /// cash для смены, применение статусов. Все методы Serializable-safe /// (транзакция внутри — одна на операцию). public interface IMoneyService { /// Провести готовый документ: смена Status Draft→Posted, /// пересчёт PayedSum на связанных документах. Пустой список /// Links допустим (аналог noClosingDocs=true). Для TransferOut /// — атомарно создаёт/проводит парный TransferIn. Task PostAsync(Guid transactionId, Guid currentUserId, CancellationToken ct); /// Отменить проведение. Пересчёт PayedSum в сторону уменьшения. /// После Unpost документ можно удалить или снова отредактировать и /// провести заново. Task UnpostAsync(Guid transactionId, Guid currentUserId, CancellationToken ct); /// Открыть смену на точке. Падает 409 если на RetailPoint /// уже есть открытая смена. Task OpenShiftAsync(Guid retailPointId, Guid cashAccountId, Guid? acquiringAccountId, decimal openingFloat, Guid cashierUserId, CancellationToken ct); /// Закрыть смену: вычислить snapshot'ы продаж/возвратов, /// expected cash, разницу. Запрещено если уже закрыта. Task CloseShiftAsync(Guid shiftId, decimal actualCash, Guid closedByUserId, string? notes, CancellationToken ct); /// Добавить внесение/выплату внутри открытой смены. Task AddDrawerOperationAsync(Guid shiftId, CashDrawerDirection direction, decimal amount, string reason, Guid byUserId, CancellationToken ct); } public enum MoneyServiceStatus { Ok = 0, NotFound = 1, AlreadyPosted = 2, AlreadyDraft = 3, ValidationFailed = 4, Conflict = 5, ShiftNotOpen = 6, ShiftAlreadyOpen = 7, OverpaidDocument = 8, LinkedSumMismatch = 9, WrongCurrency = 10, AccountInactive = 11, InsufficientFunds = 12, } public record MoneyServiceResult(MoneyServiceStatus Status, string? ErrorCode = null, string? Message = null) { public static MoneyServiceResult Ok() => new(MoneyServiceStatus.Ok); public static MoneyServiceResult Fail(MoneyServiceStatus s, string code, string msg) => new(s, code, msg); } public record CashShiftOpenResult(MoneyServiceStatus Status, Guid? ShiftId, string? Number, string? ErrorCode, string? Message); public record CashShiftCloseResult(MoneyServiceStatus Status, decimal ExpectedCash, decimal CashDifference, string? ErrorCode, string? Message); public record CashDrawerOperationResult(MoneyServiceStatus Status, Guid? OperationId, string? ErrorCode, string? Message);