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);