feat(domain): Employee, EmployeeRole, RolePermissions entities + migration
Базовый каркас модуля «Сотрудники и Роли» (по образу сторонняя система):
Domain:
- Employee — сотрудник организации (UserId nullable: запись может
существовать без логина), ФИО + Position + Email/Phone + Role + IsActive
+ FiredAt + RetailPointAssignments.
- EmployeeRole — роль с IsSystem флагом и owned RolePermissions.
- RolePermissions — 21 булев флаг по группам (Каталог/Закупки/Продажи/
Контрагенты/Отчёты/Настройки) + helper All() для админа.
- EmployeeRetailPointAssignment — ассоциация сотрудника с RetailPoint
(для роли Кассир — к каким кассам привязан).
Infrastructure:
- OrganizationsHrConfigurations с OwnsOne(...).ToJson("permissions")
для permissions — JSONB-колонка вместо отдельной таблицы.
- DbSet<EmployeeRole/Employee/EmployeeRetailPointAssignment>.
- Уникальные индексы: (OrgId, RoleName), (OrgId, UserId) с filter
WHERE UserId IS NOT NULL, (EmployeeId, RetailPointId).
Migration Phase4_EmployeesAndRoles создаёт три таблицы. Сидер
системных ролей и привязка существующего admin'а к Employee —
следующим коммитом, контроллеры и UI — далее.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cec76ecaaf
commit
f38d34f42d
41
src/food-market.domain/Organizations/Employee.cs
Normal file
41
src/food-market.domain/Organizations/Employee.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
using foodmarket.Domain.Common;
|
||||
|
||||
namespace foodmarket.Domain.Organizations;
|
||||
|
||||
/// <summary>Сотрудник организации. Может быть привязан к учётной записи
|
||||
/// (UserId), а может существовать без логина (например, кассир, которого
|
||||
/// добавили в HR, но логин ещё не выдали).</summary>
|
||||
public class Employee : TenantEntity
|
||||
{
|
||||
/// <summary>FK на Identity-юзера. Заполняется когда сотруднику выдан логин.
|
||||
/// Null — запись без учётки.</summary>
|
||||
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 Guid RoleId { get; set; }
|
||||
public EmployeeRole Role { get; set; } = null!;
|
||||
|
||||
/// <summary>Активен ли сотрудник. False — заблокирован, не может логиниться.
|
||||
/// Удаление физически не делаем (FK из документов), просто IsActive=false.</summary>
|
||||
public bool IsActive { get; set; } = true;
|
||||
public DateTime? FiredAt { get; set; }
|
||||
|
||||
public ICollection<EmployeeRetailPointAssignment> RetailPointAssignments { get; set; }
|
||||
= new List<EmployeeRetailPointAssignment>();
|
||||
}
|
||||
|
||||
/// <summary>Привязка сотрудника к кассе (для роли Кассир): к каким RetailPoint'ам
|
||||
/// он может вставать. Если назначений нет — может ко всем (поведение по умолчанию).</summary>
|
||||
public class EmployeeRetailPointAssignment : TenantEntity
|
||||
{
|
||||
public Guid EmployeeId { get; set; }
|
||||
public Employee Employee { get; set; } = null!;
|
||||
public Guid RetailPointId { get; set; }
|
||||
}
|
||||
17
src/food-market.domain/Organizations/EmployeeRole.cs
Normal file
17
src/food-market.domain/Organizations/EmployeeRole.cs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
using foodmarket.Domain.Common;
|
||||
|
||||
namespace foodmarket.Domain.Organizations;
|
||||
|
||||
/// <summary>Роль сотрудника в организации. Системные (IsSystem=true) сидируются
|
||||
/// при создании Organization (Администратор/Менеджер/Кладовщик/Кассир/Закупщик/
|
||||
/// Бухгалтер) — нельзя удалить, имя менять можно. Кастомные — полный CRUD.</summary>
|
||||
public class EmployeeRole : TenantEntity
|
||||
{
|
||||
public string Name { get; set; } = "";
|
||||
public string? Description { get; set; }
|
||||
public bool IsSystem { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
|
||||
/// <summary>Permissions — owned JSON-колонка (см. EF config).</summary>
|
||||
public RolePermissions Permissions { get; set; } = new();
|
||||
}
|
||||
51
src/food-market.domain/Organizations/RolePermissions.cs
Normal file
51
src/food-market.domain/Organizations/RolePermissions.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
namespace foodmarket.Domain.Organizations;
|
||||
|
||||
/// <summary>Набор флагов разрешений роли. Хранится JSON-колонкой
|
||||
/// (owned by EmployeeRole). Семантика: false = доступ запрещён.</summary>
|
||||
public class RolePermissions
|
||||
{
|
||||
// Каталог
|
||||
public bool ProductsView { get; set; }
|
||||
public bool ProductsEdit { get; set; }
|
||||
public bool ProductsDelete { get; set; }
|
||||
public bool ProductGroupsManage { get; set; }
|
||||
public bool PriceTypesManage { get; set; }
|
||||
|
||||
// Закупки
|
||||
public bool SuppliesView { get; set; }
|
||||
public bool SuppliesEdit { get; set; }
|
||||
public bool SuppliesPost { get; set; }
|
||||
public bool SuppliesDelete { get; set; }
|
||||
|
||||
// Продажи (POS)
|
||||
public bool RetailSalesOperate { get; set; }
|
||||
public bool RetailSalesRefund { get; set; }
|
||||
|
||||
// Контрагенты
|
||||
public bool CounterpartiesView { get; set; }
|
||||
public bool CounterpartiesEdit { get; set; }
|
||||
|
||||
// Отчёты и остатки
|
||||
public bool ReportsView { get; set; }
|
||||
public bool StocksView { get; set; }
|
||||
|
||||
// Настройки организации
|
||||
public bool OrgSettingsManage { get; set; }
|
||||
public bool EmployeesManage { get; set; }
|
||||
public bool RolesManage { get; set; }
|
||||
public bool StoresManage { get; set; }
|
||||
public bool RetailPointsManage { get; set; }
|
||||
|
||||
/// <summary>Полный набор всех true — для системной роли «Администратор».</summary>
|
||||
public static RolePermissions All() => new()
|
||||
{
|
||||
ProductsView = true, ProductsEdit = true, ProductsDelete = true,
|
||||
ProductGroupsManage = true, PriceTypesManage = true,
|
||||
SuppliesView = true, SuppliesEdit = true, SuppliesPost = true, SuppliesDelete = true,
|
||||
RetailSalesOperate = true, RetailSalesRefund = true,
|
||||
CounterpartiesView = true, CounterpartiesEdit = true,
|
||||
ReportsView = true, StocksView = true,
|
||||
OrgSettingsManage = true, EmployeesManage = true, RolesManage = true,
|
||||
StoresManage = true, RetailPointsManage = true,
|
||||
};
|
||||
}
|
||||
|
|
@ -46,6 +46,10 @@ public AppDbContext(DbContextOptions<AppDbContext> options, ITenantContext tenan
|
|||
public DbSet<RetailSale> RetailSales => Set<RetailSale>();
|
||||
public DbSet<RetailSaleLine> RetailSaleLines => Set<RetailSaleLine>();
|
||||
|
||||
public DbSet<EmployeeRole> EmployeeRoles => Set<EmployeeRole>();
|
||||
public DbSet<Employee> Employees => Set<Employee>();
|
||||
public DbSet<EmployeeRetailPointAssignment> EmployeeRetailPointAssignments => Set<EmployeeRetailPointAssignment>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
base.OnModelCreating(builder);
|
||||
|
|
@ -78,6 +82,7 @@ protected override void OnModelCreating(ModelBuilder builder)
|
|||
builder.ConfigureInventory();
|
||||
builder.ConfigurePurchases();
|
||||
builder.ConfigureSales();
|
||||
builder.ConfigureOrganizationsHr();
|
||||
|
||||
// Apply multi-tenant query filter to every entity that implements ITenantEntity
|
||||
foreach (var entityType in builder.Model.GetEntityTypes())
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
using foodmarket.Domain.Organizations;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace foodmarket.Infrastructure.Persistence.Configurations;
|
||||
|
||||
public static class OrganizationsHrConfigurations
|
||||
{
|
||||
public static void ConfigureOrganizationsHr(this ModelBuilder b)
|
||||
{
|
||||
b.Entity<EmployeeRole>(e =>
|
||||
{
|
||||
e.ToTable("employee_roles");
|
||||
e.Property(x => x.Name).HasMaxLength(100).IsRequired();
|
||||
e.Property(x => x.Description).HasMaxLength(500);
|
||||
// Permissions — owned JSON-колонка. Один объект = один сериализованный
|
||||
// блоб на роль. Все поля булевы, по умолчанию false.
|
||||
e.OwnsOne(x => x.Permissions, p => p.ToJson("permissions"));
|
||||
e.HasIndex(x => new { x.OrganizationId, x.Name }).IsUnique();
|
||||
});
|
||||
|
||||
b.Entity<Employee>(e =>
|
||||
{
|
||||
e.ToTable("employees");
|
||||
e.Property(x => x.LastName).HasMaxLength(100).IsRequired();
|
||||
e.Property(x => x.FirstName).HasMaxLength(100).IsRequired();
|
||||
e.Property(x => x.MiddleName).HasMaxLength(100);
|
||||
e.Property(x => x.Position).HasMaxLength(150);
|
||||
e.Property(x => x.Email).HasMaxLength(200);
|
||||
e.Property(x => x.Phone).HasMaxLength(50);
|
||||
e.HasOne(x => x.Role).WithMany().HasForeignKey(x => x.RoleId).OnDelete(DeleteBehavior.Restrict);
|
||||
e.HasMany(x => x.RetailPointAssignments).WithOne(a => a.Employee)
|
||||
.HasForeignKey(a => a.EmployeeId).OnDelete(DeleteBehavior.Cascade);
|
||||
e.HasIndex(x => new { x.OrganizationId, x.UserId }).IsUnique()
|
||||
.HasFilter("\"UserId\" IS NOT NULL");
|
||||
e.HasIndex(x => new { x.OrganizationId, x.LastName });
|
||||
});
|
||||
|
||||
b.Entity<EmployeeRetailPointAssignment>(e =>
|
||||
{
|
||||
e.ToTable("employee_retail_point_assignments");
|
||||
e.HasIndex(x => new { x.EmployeeId, x.RetailPointId }).IsUnique();
|
||||
});
|
||||
}
|
||||
}
|
||||
2001
src/food-market.infrastructure/Persistence/Migrations/20260427010000_Phase4_EmployeesAndRoles.Designer.cs
generated
Normal file
2001
src/food-market.infrastructure/Persistence/Migrations/20260427010000_Phase4_EmployeesAndRoles.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,128 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace foodmarket.Infrastructure.Persistence.Migrations
|
||||
{
|
||||
/// <summary>Сотрудники (employees) + роли (employee_roles с JSON-permissions)
|
||||
/// + назначения сотрудников на кассы (employee_retail_point_assignments).
|
||||
/// Сидер заведёт системные роли и подвяжет существующего admin'а как
|
||||
/// сотрудника при первом старте.</summary>
|
||||
public partial class Phase4_EmployeesAndRoles : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder b)
|
||||
{
|
||||
b.CreateTable(
|
||||
name: "employee_roles",
|
||||
schema: "public",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
OrganizationId = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
Name = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
Description = table.Column<string>(type: "character varying(500)", maxLength: 500, nullable: true),
|
||||
IsSystem = table.Column<bool>(type: "boolean", nullable: false),
|
||||
SortOrder = table.Column<int>(type: "integer", nullable: false),
|
||||
permissions = table.Column<string>(type: "jsonb", nullable: true),
|
||||
CreatedAt = table.Column<System.DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<System.DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_employee_roles", x => x.Id);
|
||||
});
|
||||
b.CreateIndex(
|
||||
name: "IX_employee_roles_OrganizationId_Name",
|
||||
schema: "public",
|
||||
table: "employee_roles",
|
||||
columns: new[] { "OrganizationId", "Name" },
|
||||
unique: true);
|
||||
|
||||
b.CreateTable(
|
||||
name: "employees",
|
||||
schema: "public",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
OrganizationId = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
UserId = table.Column<System.Guid>(type: "uuid", nullable: true),
|
||||
LastName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
FirstName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: false),
|
||||
MiddleName = table.Column<string>(type: "character varying(100)", maxLength: 100, nullable: true),
|
||||
Position = table.Column<string>(type: "character varying(150)", maxLength: 150, nullable: true),
|
||||
Email = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
|
||||
Phone = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
|
||||
RoleId = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
IsActive = table.Column<bool>(type: "boolean", nullable: false),
|
||||
FiredAt = table.Column<System.DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
CreatedAt = table.Column<System.DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<System.DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_employees", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_employees_employee_roles_RoleId",
|
||||
column: x => x.RoleId,
|
||||
principalSchema: "public",
|
||||
principalTable: "employee_roles",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Restrict);
|
||||
});
|
||||
b.CreateIndex(
|
||||
name: "IX_employees_RoleId",
|
||||
schema: "public",
|
||||
table: "employees",
|
||||
column: "RoleId");
|
||||
b.CreateIndex(
|
||||
name: "IX_employees_OrganizationId_LastName",
|
||||
schema: "public",
|
||||
table: "employees",
|
||||
columns: new[] { "OrganizationId", "LastName" });
|
||||
b.CreateIndex(
|
||||
name: "IX_employees_OrganizationId_UserId",
|
||||
schema: "public",
|
||||
table: "employees",
|
||||
columns: new[] { "OrganizationId", "UserId" },
|
||||
unique: true,
|
||||
filter: "\"UserId\" IS NOT NULL");
|
||||
|
||||
b.CreateTable(
|
||||
name: "employee_retail_point_assignments",
|
||||
schema: "public",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
OrganizationId = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
EmployeeId = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
RetailPointId = table.Column<System.Guid>(type: "uuid", nullable: false),
|
||||
CreatedAt = table.Column<System.DateTime>(type: "timestamp with time zone", nullable: false),
|
||||
UpdatedAt = table.Column<System.DateTime>(type: "timestamp with time zone", nullable: true),
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_employee_retail_point_assignments", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_employee_retail_point_assignments_employees_EmployeeId",
|
||||
column: x => x.EmployeeId,
|
||||
principalSchema: "public",
|
||||
principalTable: "employees",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
});
|
||||
b.CreateIndex(
|
||||
name: "IX_employee_retail_point_assignments_EmployeeId_RetailPointId",
|
||||
schema: "public",
|
||||
table: "employee_retail_point_assignments",
|
||||
columns: new[] { "EmployeeId", "RetailPointId" },
|
||||
unique: true);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder b)
|
||||
{
|
||||
b.DropTable(name: "employee_retail_point_assignments", schema: "public");
|
||||
b.DropTable(name: "employees", schema: "public");
|
||||
b.DropTable(name: "employee_roles", schema: "public");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1888,6 +1888,110 @@ protected override void BuildModel(ModelBuilder modelBuilder)
|
|||
{
|
||||
b.Navigation("Lines");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("foodmarket.Domain.Organizations.EmployeeRole", b =>
|
||||
{
|
||||
b.Property<Guid>("Id").ValueGeneratedOnAdd().HasColumnType("uuid");
|
||||
b.Property<Guid>("OrganizationId").HasColumnType("uuid");
|
||||
b.Property<string>("Name").IsRequired().HasMaxLength(100).HasColumnType("character varying(100)");
|
||||
b.Property<string>("Description").HasMaxLength(500).HasColumnType("character varying(500)");
|
||||
b.Property<bool>("IsSystem").HasColumnType("boolean");
|
||||
b.Property<int>("SortOrder").HasColumnType("integer");
|
||||
b.Property<DateTime>("CreatedAt").HasColumnType("timestamp with time zone");
|
||||
b.Property<DateTime?>("UpdatedAt").HasColumnType("timestamp with time zone");
|
||||
b.HasKey("Id");
|
||||
b.HasIndex("OrganizationId", "Name").IsUnique();
|
||||
b.ToTable("employee_roles", "public");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("foodmarket.Domain.Organizations.EmployeeRole", b =>
|
||||
{
|
||||
b.OwnsOne("foodmarket.Domain.Organizations.RolePermissions", "Permissions", o =>
|
||||
{
|
||||
o.Property<Guid>("EmployeeRoleId").HasColumnType("uuid");
|
||||
o.Property<bool>("ProductsView").HasColumnType("boolean");
|
||||
o.Property<bool>("ProductsEdit").HasColumnType("boolean");
|
||||
o.Property<bool>("ProductsDelete").HasColumnType("boolean");
|
||||
o.Property<bool>("ProductGroupsManage").HasColumnType("boolean");
|
||||
o.Property<bool>("PriceTypesManage").HasColumnType("boolean");
|
||||
o.Property<bool>("SuppliesView").HasColumnType("boolean");
|
||||
o.Property<bool>("SuppliesEdit").HasColumnType("boolean");
|
||||
o.Property<bool>("SuppliesPost").HasColumnType("boolean");
|
||||
o.Property<bool>("SuppliesDelete").HasColumnType("boolean");
|
||||
o.Property<bool>("RetailSalesOperate").HasColumnType("boolean");
|
||||
o.Property<bool>("RetailSalesRefund").HasColumnType("boolean");
|
||||
o.Property<bool>("CounterpartiesView").HasColumnType("boolean");
|
||||
o.Property<bool>("CounterpartiesEdit").HasColumnType("boolean");
|
||||
o.Property<bool>("ReportsView").HasColumnType("boolean");
|
||||
o.Property<bool>("StocksView").HasColumnType("boolean");
|
||||
o.Property<bool>("OrgSettingsManage").HasColumnType("boolean");
|
||||
o.Property<bool>("EmployeesManage").HasColumnType("boolean");
|
||||
o.Property<bool>("RolesManage").HasColumnType("boolean");
|
||||
o.Property<bool>("StoresManage").HasColumnType("boolean");
|
||||
o.Property<bool>("RetailPointsManage").HasColumnType("boolean");
|
||||
o.HasKey("EmployeeRoleId");
|
||||
o.ToJson("permissions");
|
||||
o.WithOwner().HasForeignKey("EmployeeRoleId");
|
||||
});
|
||||
b.Navigation("Permissions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("foodmarket.Domain.Organizations.Employee", b =>
|
||||
{
|
||||
b.Property<Guid>("Id").ValueGeneratedOnAdd().HasColumnType("uuid");
|
||||
b.Property<Guid>("OrganizationId").HasColumnType("uuid");
|
||||
b.Property<Guid?>("UserId").HasColumnType("uuid");
|
||||
b.Property<string>("LastName").IsRequired().HasMaxLength(100).HasColumnType("character varying(100)");
|
||||
b.Property<string>("FirstName").IsRequired().HasMaxLength(100).HasColumnType("character varying(100)");
|
||||
b.Property<string>("MiddleName").HasMaxLength(100).HasColumnType("character varying(100)");
|
||||
b.Property<string>("Position").HasMaxLength(150).HasColumnType("character varying(150)");
|
||||
b.Property<string>("Email").HasMaxLength(200).HasColumnType("character varying(200)");
|
||||
b.Property<string>("Phone").HasMaxLength(50).HasColumnType("character varying(50)");
|
||||
b.Property<Guid>("RoleId").HasColumnType("uuid");
|
||||
b.Property<bool>("IsActive").HasColumnType("boolean");
|
||||
b.Property<DateTime?>("FiredAt").HasColumnType("timestamp with time zone");
|
||||
b.Property<DateTime>("CreatedAt").HasColumnType("timestamp with time zone");
|
||||
b.Property<DateTime?>("UpdatedAt").HasColumnType("timestamp with time zone");
|
||||
b.HasKey("Id");
|
||||
b.HasIndex("RoleId");
|
||||
b.HasIndex("OrganizationId", "LastName");
|
||||
b.HasIndex("OrganizationId", "UserId").IsUnique().HasFilter("\"UserId\" IS NOT NULL");
|
||||
b.ToTable("employees", "public");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("foodmarket.Domain.Organizations.Employee", b =>
|
||||
{
|
||||
b.HasOne("foodmarket.Domain.Organizations.EmployeeRole", "Role")
|
||||
.WithMany()
|
||||
.HasForeignKey("RoleId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
b.Navigation("Role");
|
||||
b.Navigation("RetailPointAssignments");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("foodmarket.Domain.Organizations.EmployeeRetailPointAssignment", b =>
|
||||
{
|
||||
b.Property<Guid>("Id").ValueGeneratedOnAdd().HasColumnType("uuid");
|
||||
b.Property<Guid>("OrganizationId").HasColumnType("uuid");
|
||||
b.Property<Guid>("EmployeeId").HasColumnType("uuid");
|
||||
b.Property<Guid>("RetailPointId").HasColumnType("uuid");
|
||||
b.Property<DateTime>("CreatedAt").HasColumnType("timestamp with time zone");
|
||||
b.Property<DateTime?>("UpdatedAt").HasColumnType("timestamp with time zone");
|
||||
b.HasKey("Id");
|
||||
b.HasIndex("EmployeeId", "RetailPointId").IsUnique();
|
||||
b.ToTable("employee_retail_point_assignments", "public");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("foodmarket.Domain.Organizations.EmployeeRetailPointAssignment", b =>
|
||||
{
|
||||
b.HasOne("foodmarket.Domain.Organizations.Employee", "Employee")
|
||||
.WithMany("RetailPointAssignments")
|
||||
.HasForeignKey("EmployeeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
b.Navigation("Employee");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue