using foodmarket.Domain.Common;
namespace foodmarket.Domain.Organizations;
/// Сотрудник организации. Может быть привязан к учётной записи
/// (UserId), а может существовать без логина (например, кассир, которого
/// добавили в HR, но логин ещё не выдали).
public class Employee : TenantEntity
{
/// FK на Identity-юзера. Заполняется когда сотруднику выдан логин.
/// Null — запись без учётки.
public Guid? UserId { get; set; }
public string LastName { get; set; } = "";
public string FirstName { get; set; } = "";
public string? MiddleName { get; set; }
public string? Position { get; set; }
public string? Email { get; set; }
public string? Phone { get; set; }
/// Оклад в валюте организации, опц.
public decimal? Salary { get; set; }
/// ИИН (12 цифр для физлица в РК), опционально.
public string? TaxNumber { get; set; }
/// Произвольное описание (комментарий HR'а).
public string? Description { get; set; }
/// Аватар сотрудника. URL до файла в общем images-стораж.
public string? ImageUrl { get; set; }
public Guid RoleId { get; set; }
public EmployeeRole Role { get; set; } = null!;
/// Активен ли сотрудник. False — заблокирован, не может логиниться.
/// Двухступенчатое удаление: сначала «Уволить» (IsActive=false + FiredAt),
/// затем «Удалить» (IsDeleted=true + DeletedAt). Физически не удаляем
/// никогда — у сотрудника есть FK из документов (продаж, поставок).
public bool IsActive { get; set; } = true;
public DateTime? FiredAt { get; set; }
/// Soft-delete-флаг. Ставится только из состояния «уволен» (IsActive=false).
/// В UI и связанных документах отображается «Иванов И.И. (удалён)».
/// В списках сотрудников по умолчанию скрыты, доступны через фильтр.
public bool IsDeleted { get; set; }
public DateTime? DeletedAt { get; set; }
public ICollection RetailPointAssignments { get; set; }
= new List();
// ─ Быстрый вход кассира по PIN на зарегистрированном устройстве ─────
/// Хэш PIN-кода (PBKDF2 с солью, base64). null — PIN не задан,
/// вход только по паролю. Задаёт администратор в карточке сотрудника.
/// Брутфорс-защита (5 неверных → блок 5 мин) — на уровне точки (in-memory),
/// т.к. вход по PIN без логина не идентифицирует конкретного сотрудника.
public string? PinHash { get; set; }
}
/// Привязка сотрудника к кассе (для роли Кассир): к каким RetailPoint'ам
/// он может вставать. Если назначений нет — может ко всем (поведение по умолчанию).
public class EmployeeRetailPointAssignment : TenantEntity
{
public Guid EmployeeId { get; set; }
public Employee Employee { get; set; } = null!;
public Guid RetailPointId { get; set; }
}