diff --git a/src/food-market.infrastructure/Money/MoneyService.cs b/src/food-market.infrastructure/Money/MoneyService.cs index cc46c69..153d10f 100644 --- a/src/food-market.infrastructure/Money/MoneyService.cs +++ b/src/food-market.infrastructure/Money/MoneyService.cs @@ -181,6 +181,33 @@ public async Task UnpostAsync(Guid transactionId, Guid curre return new(MoneyServiceStatus.ShiftAlreadyOpen, null, null, "shift-already-open", "На этой точке уже открыта смена."); + // Точка продаж должна существовать и быть активной — на деактивированной + // точке открывать смену (и, значит, продавать) нельзя. + var rp = await _db.RetailPoints.FirstOrDefaultAsync(r => r.Id == retailPointId, ct); + if (rp is null) + return new(MoneyServiceStatus.ValidationFailed, null, null, + "retail-point-not-found", "Точка продаж не найдена."); + if (!rp.IsActive) + return new(MoneyServiceStatus.ValidationFailed, null, null, + "retail-point-inactive", "Точка продаж деактивирована — открыть смену нельзя."); + + // Привязка кассира к точкам: если у сотрудника настроены привязки к точкам + // продаж, открывать смену он может ТОЛЬКО на закреплённой точке. У кого + // привязок нет (администратор/управляющий) — на любой. + var emp = await _db.Employees.FirstOrDefaultAsync(e => e.UserId == cashierUserId, ct); + if (emp is not null) + { + var hasAnyAssignment = await _db.EmployeeRetailPointAssignments.AnyAsync(a => a.EmployeeId == emp.Id, ct); + if (hasAnyAssignment) + { + var assigned = await _db.EmployeeRetailPointAssignments + .AnyAsync(a => a.EmployeeId == emp.Id && a.RetailPointId == retailPointId, ct); + if (!assigned) + return new(MoneyServiceStatus.ValidationFailed, null, null, + "retail-point-not-assigned", "Вы не закреплены за этой точкой продаж — открыть смену нельзя."); + } + } + var cash = await _db.MoneyAccounts.FirstOrDefaultAsync(a => a.Id == cashAccountId, ct); if (cash is null || cash.Kind != MoneyAccountKind.Cash) return new(MoneyServiceStatus.ValidationFailed, null, null,