From 102b622de947b037c9662ff875b91c8798496ec1 Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sat, 5 Oct 2024 21:19:09 +0500 Subject: [PATCH 01/40] Created Manager and ManagerReview Created Manager and ManagerReview entities Add configuration ManagerReview Edit Employee Configuration -> Add Manager employee Edit CheckDriveDbContext and ICheckDriveDbContext -> Add DbSets Managers and ManagerReviews --- .../CheckDrive.Domain/Entities/CheckPoint.cs | 1 + .../CheckDrive.Domain/Entities/Manager.cs | 11 + .../Entities/ManagerReview.cs | 11 + .../Interfaces/ICheckDriveDbContext.cs | 2 + .../Persistence/CheckDriveDbContext.cs | 2 + .../Configurations/EmployeeConfiguration.cs | 3 +- .../ManagerReviewConfigurations.cs | 32 + ...1211_Add_Manager_ManagerReview.Designer.cs | 1008 +++++++++++++++++ ...0241005161211_Add_Manager_ManagerReview.cs | 117 ++ .../CheckDriveDbContextModelSnapshot.cs | 160 +-- 10 files changed, 1266 insertions(+), 81 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Domain/Entities/Manager.cs create mode 100644 CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.Designer.cs create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.cs diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/CheckPoint.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/CheckPoint.cs index 443380e9..bdaddc9e 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Entities/CheckPoint.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/CheckPoint.cs @@ -15,5 +15,6 @@ public class CheckPoint : EntityBase public virtual OperatorReview? OperatorReview { get; set; } public virtual MechanicAcceptance? MechanicAcceptance { get; set; } public virtual DispatcherReview? DispatcherReview { get; set; } + public virtual ManagerReview? ManagerReview { get; set; } public virtual Debt? Debt { get; set; } } diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/Manager.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/Manager.cs new file mode 100644 index 00000000..01d0670c --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/Manager.cs @@ -0,0 +1,11 @@ +namespace CheckDrive.Domain.Entities; + +public class Manager : Employee +{ + public virtual ICollection<ManagerReview> Reviews { get; set; } + + public Manager() + { + Reviews = new HashSet<ManagerReview>(); + } +} diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs new file mode 100644 index 00000000..937c104b --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs @@ -0,0 +1,11 @@ +using CheckDrive.Domain.Common; + +namespace CheckDrive.Domain.Entities; + +public class ManagerReview : ReviewBase +{ + public int CheckPointId { get; set; } + public required virtual CheckPoint CheckPoint { get; set; } + public int ManagerId { get; set; } + public required virtual Manager Manager { get; set; } +} diff --git a/CheckDrive.Api/CheckDrive.Domain/Interfaces/ICheckDriveDbContext.cs b/CheckDrive.Api/CheckDrive.Domain/Interfaces/ICheckDriveDbContext.cs index e2b4f01b..ca7c15b3 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Interfaces/ICheckDriveDbContext.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Interfaces/ICheckDriveDbContext.cs @@ -13,6 +13,7 @@ public interface ICheckDriveDbContext DbSet<Mechanic> Mechanics { get; set; } DbSet<Operator> Operators { get; set; } DbSet<Dispatcher> Dispatchers { get; set; } + DbSet<Manager> Managers { get; set; } DbSet<Car> Cars { get; set; } DbSet<CheckPoint> CheckPoints { get; set; } DbSet<DoctorReview> DoctorReviews { get; set; } @@ -20,6 +21,7 @@ public interface ICheckDriveDbContext DbSet<OperatorReview> OperatorReviews { get; set; } DbSet<MechanicAcceptance> MechanicAcceptances { get; set; } DbSet<DispatcherReview> DispatcherReviews { get; set; } + DbSet<ManagerReview> ManagerReviews { get; set; } DbSet<Debt> Debts { get; set; } DbSet<OilMark> OilMarks { get; set; } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/CheckDriveDbContext.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/CheckDriveDbContext.cs index 4c4c352a..94394c82 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/CheckDriveDbContext.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/CheckDriveDbContext.cs @@ -16,6 +16,7 @@ public class CheckDriveDbContext : IdentityDbContext, ICheckDriveDbContext public virtual DbSet<Mechanic> Mechanics { get; set; } public virtual DbSet<Operator> Operators { get; set; } public virtual DbSet<Dispatcher> Dispatchers { get; set; } + public virtual DbSet<Manager> Managers { get; set; } public virtual DbSet<Car> Cars { get; set; } public virtual DbSet<CheckPoint> CheckPoints { get; set; } public virtual DbSet<DoctorReview> DoctorReviews { get; set; } @@ -23,6 +24,7 @@ public class CheckDriveDbContext : IdentityDbContext, ICheckDriveDbContext public virtual DbSet<OperatorReview> OperatorReviews { get; set; } public virtual DbSet<MechanicAcceptance> MechanicAcceptances { get; set; } public virtual DbSet<DispatcherReview> DispatcherReviews { get; set; } + public virtual DbSet<ManagerReview> ManagerReviews { get; set; } public virtual DbSet<Debt> Debts { get; set; } public virtual DbSet<OilMark> OilMarks { get; set; } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/EmployeeConfiguration.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/EmployeeConfiguration.cs index 74bd5c6a..7f541735 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/EmployeeConfiguration.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/EmployeeConfiguration.cs @@ -31,7 +31,8 @@ public void Configure(EntityTypeBuilder<Employee> builder) .HasValue<Doctor>(EmployeePosition.Doctor) .HasValue<Mechanic>(EmployeePosition.Mechanic) .HasValue<Operator>(EmployeePosition.Operator) - .HasValue<Dispatcher>(EmployeePosition.Dispatcher); + .HasValue<Dispatcher>(EmployeePosition.Dispatcher) + .HasValue<Manager>(EmployeePosition.Manager); builder .Property(e => e.FirstName) diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs new file mode 100644 index 00000000..558df072 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs @@ -0,0 +1,32 @@ +using CheckDrive.Domain.Entities; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore; + +namespace CheckDrive.Infrastructure.Persistence.Configurations; + +internal class ManagerReviewConfigurations : IEntityTypeConfiguration<ManagerReview> +{ + public void Configure(EntityTypeBuilder<ManagerReview> builder) + { + builder.ToTable(nameof(ManagerReview)); + builder.HasKey(m => m.Id); + + #region Relationships + + builder + .HasOne(mn => mn.CheckPoint) + .WithOne(cp => cp.ManagerReview) + .HasForeignKey<ManagerReview>(mn => mn.CheckPointId) + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + builder + .HasOne(mn => mn.Manager) + .WithMany(d => d.Reviews) + .HasForeignKey(mn => mn.ManagerId) + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + #endregion + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.Designer.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.Designer.cs new file mode 100644 index 00000000..f9cf59df --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.Designer.cs @@ -0,0 +1,1008 @@ +// <auto-generated /> +using System; +using CheckDrive.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(CheckDriveDbContext))] + [Migration("20241005161211_Add_Manager_ManagerReview")] + partial class Add_Manager_ManagerReview + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<decimal>("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<decimal>("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManufacturedYear") + .HasColumnType("int"); + + b.Property<int>("Mileage") + .HasColumnType("int"); + + b.Property<string>("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<string>("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property<decimal>("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<int>("YearlyDistanceLimit") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<int>("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<DateTime>("StartDate") + .HasColumnType("datetime2"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<decimal>("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<decimal>("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.ToTable("Debt", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DispatcherId") + .HasColumnType("int"); + + b.Property<decimal?>("DistanceTravelledAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DispatcherId"); + + b.ToTable("DispatcherReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DoctorId") + .HasColumnType("int"); + + b.Property<int>("DriverId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DoctorId"); + + b.HasIndex("DriverId"); + + b.ToTable("DoctorReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<DateTime>("Birthdate") + .HasColumnType("datetime2"); + + b.Property<string>("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property<int>("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator<int>("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("ManagerId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("ManagerId"); + + b.ToTable("ManagerReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("FinalMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<decimal>("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicAcceptance", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CarId") + .HasColumnType("int"); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("InitialMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicHandover", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("OilMark", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal>("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("OilMarkId") + .HasColumnType("int"); + + b.Property<decimal>("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("OperatorId") + .HasColumnType("int"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("OilMarkId"); + + b.HasIndex("OperatorId"); + + b.ToTable("OperatorReview", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "1eef2d65-63aa-4bd3-ad11-97b05465411a", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }, + new + { + Id = "50732e08-b22e-4d0c-8196-13a14fda4edb", + Name = "Driver", + NormalizedName = "DRIVER" + }, + new + { + Id = "95e28700-5bea-4855-bda5-4fe4660dbaaa", + Name = "Doctor", + NormalizedName = "DOCTOR" + }, + new + { + Id = "b8854b49-d887-4ac9-9ffe-bc391909380c", + Name = "Dispatcher", + NormalizedName = "DISPATCHER" + }, + new + { + Id = "099bbfb1-a22a-48f8-a707-bd954851b749", + Name = "Manager", + NormalizedName = "MANAGER" + }, + new + { + Id = "78333ddd-03ba-4274-ae24-321c3563584a", + Name = "Mechanic", + NormalizedName = "MECHANIC" + }, + new + { + Id = "2f72a51b-f05d-49b5-98fc-c2c1b32219e1", + Name = "Operator", + NormalizedName = "OPERATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<int>("AccessFailedCount") + .HasColumnType("int"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<bool>("EmailConfirmed") + .HasColumnType("bit"); + + b.Property<bool>("LockoutEnabled") + .HasColumnType("bit"); + + b.Property<DateTimeOffset?>("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property<string>("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property<string>("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property<string>("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Name") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserToken", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(5); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(2); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(1); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(6); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(3); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(4); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("Debt") + .HasForeignKey("CheckDrive.Domain.Entities.Debt", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DispatcherReview") + .HasForeignKey("CheckDrive.Domain.Entities.DispatcherReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Dispatcher", "Dispatcher") + .WithMany("Reviews") + .HasForeignKey("DispatcherId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Dispatcher"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DoctorReview") + .HasForeignKey("CheckDrive.Domain.Entities.DoctorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Doctor", "Doctor") + .WithMany("Reviews") + .HasForeignKey("DoctorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Driver", "Driver") + .WithMany("Reviews") + .HasForeignKey("DriverId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Doctor"); + + b.Navigation("Driver"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "Account") + .WithOne() + .HasForeignKey("CheckDrive.Domain.Entities.Employee", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Manager", "Manager") + .WithMany("Reviews") + .HasForeignKey("ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Manager"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicAcceptance") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicAcceptance", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Acceptances") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.HasOne("CheckDrive.Domain.Entities.Car", "Car") + .WithMany("Handovers") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicHandover") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicHandover", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Handovers") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Car"); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("OperatorReview") + .HasForeignKey("CheckDrive.Domain.Entities.OperatorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.OilMark", "OilMark") + .WithMany("Reviews") + .HasForeignKey("OilMarkId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Operator", "Operator") + .WithMany("Reviews") + .HasForeignKey("OperatorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("OilMark"); + + b.Navigation("Operator"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Navigation("Debt"); + + b.Navigation("DispatcherReview"); + + b.Navigation("DoctorReview") + .IsRequired(); + + b.Navigation("ManagerReview"); + + b.Navigation("MechanicAcceptance"); + + b.Navigation("MechanicHandover"); + + b.Navigation("OperatorReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.Navigation("Acceptances"); + + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.Navigation("Reviews"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.cs new file mode 100644 index 00000000..c517398e --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.cs @@ -0,0 +1,117 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace CheckDrive.Infrastructure.Persistence.Migrations; + +/// <inheritdoc /> +public partial class Add_Manager_ManagerReview : Migration +{ + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "17222f04-4d61-48c7-b50b-16287b8f1d70"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "2ff29e6d-a8df-4dcc-af3b-7dfd59a13510"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "6f6835f9-ea44-483e-aa69-97d452868bff"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "89887e6f-24d2-4fc5-a874-af4b4258d7b1"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "b8182f0e-79e3-4c31-b5a2-5c74a8598990"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "c58e9004-eef9-4568-9205-41d84054d234"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "f7d4b7c5-83e1-41ef-aec8-15722f67532a"); + + migrationBuilder.InsertData( + table: "Role", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "099bbfb1-a22a-48f8-a707-bd954851b749", null, "Manager", "MANAGER" }, + { "1eef2d65-63aa-4bd3-ad11-97b05465411a", null, "Administrator", "ADMINISTRATOR" }, + { "2f72a51b-f05d-49b5-98fc-c2c1b32219e1", null, "Operator", "OPERATOR" }, + { "50732e08-b22e-4d0c-8196-13a14fda4edb", null, "Driver", "DRIVER" }, + { "78333ddd-03ba-4274-ae24-321c3563584a", null, "Mechanic", "MECHANIC" }, + { "95e28700-5bea-4855-bda5-4fe4660dbaaa", null, "Doctor", "DOCTOR" }, + { "b8854b49-d887-4ac9-9ffe-bc391909380c", null, "Dispatcher", "DISPATCHER" } + }); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "099bbfb1-a22a-48f8-a707-bd954851b749"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "1eef2d65-63aa-4bd3-ad11-97b05465411a"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "2f72a51b-f05d-49b5-98fc-c2c1b32219e1"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "50732e08-b22e-4d0c-8196-13a14fda4edb"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "78333ddd-03ba-4274-ae24-321c3563584a"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "95e28700-5bea-4855-bda5-4fe4660dbaaa"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "b8854b49-d887-4ac9-9ffe-bc391909380c"); + + migrationBuilder.InsertData( + table: "Role", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "17222f04-4d61-48c7-b50b-16287b8f1d70", null, "Administrator", "ADMINISTRATOR" }, + { "2ff29e6d-a8df-4dcc-af3b-7dfd59a13510", null, "Manager", "MANAGER" }, + { "6f6835f9-ea44-483e-aa69-97d452868bff", null, "Operator", "OPERATOR" }, + { "89887e6f-24d2-4fc5-a874-af4b4258d7b1", null, "Doctor", "DOCTOR" }, + { "b8182f0e-79e3-4c31-b5a2-5c74a8598990", null, "Driver", "DRIVER" }, + { "c58e9004-eef9-4568-9205-41d84054d234", null, "Dispatcher", "DISPATCHER" }, + { "f7d4b7c5-83e1-41ef-aec8-15722f67532a", null, "Mechanic", "MECHANIC" } + }); + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs index 3189cfec..87fb2b3c 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs @@ -22,56 +22,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); - modelBuilder.Entity("CheckDrive.Domain.Common.Employee", b => - { - b.Property<int>("Id") - .ValueGeneratedOnAdd() - .HasColumnType("int"); - - SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); - - b.Property<string>("AccountId") - .IsRequired() - .HasColumnType("nvarchar(450)"); - - b.Property<string>("Address") - .IsRequired() - .HasMaxLength(500) - .HasColumnType("nvarchar(500)"); - - b.Property<DateTime>("Birthdate") - .HasColumnType("datetime2"); - - b.Property<string>("FirstName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("nvarchar(255)"); - - b.Property<string>("LastName") - .IsRequired() - .HasMaxLength(255) - .HasColumnType("nvarchar(255)"); - - b.Property<string>("Passport") - .IsRequired() - .HasMaxLength(20) - .HasColumnType("nvarchar(20)"); - - b.Property<int>("Position") - .HasColumnType("int"); - - b.HasKey("Id"); - - b.HasIndex("AccountId") - .IsUnique(); - - b.ToTable("Employee", (string)null); - - b.HasDiscriminator<int>("Position"); - - b.UseTphMappingStrategy(); - }); - modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => { b.Property<int>("Id") @@ -267,6 +217,56 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("DoctorReview", (string)null); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<DateTime>("Birthdate") + .HasColumnType("datetime2"); + + b.Property<string>("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property<int>("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator<int>("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => { b.Property<int>("Id") @@ -474,43 +474,43 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "17222f04-4d61-48c7-b50b-16287b8f1d70", + Id = "1eef2d65-63aa-4bd3-ad11-97b05465411a", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "b8182f0e-79e3-4c31-b5a2-5c74a8598990", + Id = "50732e08-b22e-4d0c-8196-13a14fda4edb", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "89887e6f-24d2-4fc5-a874-af4b4258d7b1", + Id = "95e28700-5bea-4855-bda5-4fe4660dbaaa", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "c58e9004-eef9-4568-9205-41d84054d234", + Id = "b8854b49-d887-4ac9-9ffe-bc391909380c", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "2ff29e6d-a8df-4dcc-af3b-7dfd59a13510", + Id = "099bbfb1-a22a-48f8-a707-bd954851b749", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "f7d4b7c5-83e1-41ef-aec8-15722f67532a", + Id = "78333ddd-03ba-4274-ae24-321c3563584a", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "6f6835f9-ea44-483e-aa69-97d452868bff", + Id = "2f72a51b-f05d-49b5-98fc-c2c1b32219e1", Name = "Operator", NormalizedName = "OPERATOR" }); @@ -689,55 +689,44 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => { - b.HasBaseType("CheckDrive.Domain.Common.Employee"); + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); - b.HasDiscriminator().HasValue(4); + b.HasDiscriminator().HasValue(5); }); modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => { - b.HasBaseType("CheckDrive.Domain.Common.Employee"); + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); - b.HasDiscriminator().HasValue(1); + b.HasDiscriminator().HasValue(2); }); modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => { - b.HasBaseType("CheckDrive.Domain.Common.Employee"); + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); - b.HasDiscriminator().HasValue(0); + b.HasDiscriminator().HasValue(1); }); modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => { - b.HasBaseType("CheckDrive.Domain.Common.Employee"); + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); - b.HasDiscriminator().HasValue(5); + b.HasDiscriminator().HasValue(6); }); modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => { - b.HasBaseType("CheckDrive.Domain.Common.Employee"); + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); - b.HasDiscriminator().HasValue(2); + b.HasDiscriminator().HasValue(3); }); modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => { - b.HasBaseType("CheckDrive.Domain.Common.Employee"); - - b.HasDiscriminator().HasValue(3); - }); + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); - modelBuilder.Entity("CheckDrive.Domain.Common.Employee", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "Account") - .WithOne() - .HasForeignKey("CheckDrive.Domain.Common.Employee", "AccountId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.Navigation("Account"); + b.HasDiscriminator().HasValue(4); }); modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => @@ -797,6 +786,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Driver"); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "Account") + .WithOne() + .HasForeignKey("CheckDrive.Domain.Entities.Employee", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => { b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") From bf43868e1fcfdad4a0cfa18c9ad46d9e98cd12f7 Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:11:42 +0500 Subject: [PATCH 02/40] Added Manager And ManagerReview --- .../Entities/ManagerReview.cs | 4 + .../ManagerReviewConfigurations.cs | 16 +- ...0241005161211_Add_Manager_ManagerReview.cs | 117 ------------- ...658_Add_Manager_ManagerReview.Designer.cs} | 24 ++- ...0241006100658_Add_Manager_ManagerReview.cs | 161 ++++++++++++++++++ .../CheckDriveDbContextModelSnapshot.cs | 88 +++++++++- 6 files changed, 277 insertions(+), 133 deletions(-) delete mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.cs rename CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/{20241005161211_Add_Manager_ManagerReview.Designer.cs => 20241006100658_Add_Manager_ManagerReview.Designer.cs} (97%) create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.cs diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs index 937c104b..b05c749c 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs @@ -4,8 +4,12 @@ namespace CheckDrive.Domain.Entities; public class ManagerReview : ReviewBase { + public decimal? DebtAmountAdjusment { get; set; } + public decimal? FuelConsumptionAdjustment { get; set; } + public int CheckPointId { get; set; } public required virtual CheckPoint CheckPoint { get; set; } + public int ManagerId { get; set; } public required virtual Manager Manager { get; set; } } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs index 558df072..b188051e 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs @@ -9,7 +9,7 @@ internal class ManagerReviewConfigurations : IEntityTypeConfiguration<ManagerRev public void Configure(EntityTypeBuilder<ManagerReview> builder) { builder.ToTable(nameof(ManagerReview)); - builder.HasKey(m => m.Id); + builder.HasKey(mn => mn.Id); #region Relationships @@ -28,5 +28,19 @@ public void Configure(EntityTypeBuilder<ManagerReview> builder) .IsRequired(); #endregion + + #region Properties + + builder + .Property(mn => mn.DebtAmountAdjusment) + .HasPrecision(18, 2) + .IsRequired(false); + + builder + .Property(mn => mn.FuelConsumptionAdjustment) + .HasPrecision(18, 2) + .IsRequired(false); + + #endregion } } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.cs deleted file mode 100644 index c517398e..00000000 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.cs +++ /dev/null @@ -1,117 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -#nullable disable - -#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional - -namespace CheckDrive.Infrastructure.Persistence.Migrations; - -/// <inheritdoc /> -public partial class Add_Manager_ManagerReview : Migration -{ - /// <inheritdoc /> - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "17222f04-4d61-48c7-b50b-16287b8f1d70"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "2ff29e6d-a8df-4dcc-af3b-7dfd59a13510"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "6f6835f9-ea44-483e-aa69-97d452868bff"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "89887e6f-24d2-4fc5-a874-af4b4258d7b1"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "b8182f0e-79e3-4c31-b5a2-5c74a8598990"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "c58e9004-eef9-4568-9205-41d84054d234"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "f7d4b7c5-83e1-41ef-aec8-15722f67532a"); - - migrationBuilder.InsertData( - table: "Role", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { "099bbfb1-a22a-48f8-a707-bd954851b749", null, "Manager", "MANAGER" }, - { "1eef2d65-63aa-4bd3-ad11-97b05465411a", null, "Administrator", "ADMINISTRATOR" }, - { "2f72a51b-f05d-49b5-98fc-c2c1b32219e1", null, "Operator", "OPERATOR" }, - { "50732e08-b22e-4d0c-8196-13a14fda4edb", null, "Driver", "DRIVER" }, - { "78333ddd-03ba-4274-ae24-321c3563584a", null, "Mechanic", "MECHANIC" }, - { "95e28700-5bea-4855-bda5-4fe4660dbaaa", null, "Doctor", "DOCTOR" }, - { "b8854b49-d887-4ac9-9ffe-bc391909380c", null, "Dispatcher", "DISPATCHER" } - }); - } - - /// <inheritdoc /> - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "099bbfb1-a22a-48f8-a707-bd954851b749"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "1eef2d65-63aa-4bd3-ad11-97b05465411a"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "2f72a51b-f05d-49b5-98fc-c2c1b32219e1"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "50732e08-b22e-4d0c-8196-13a14fda4edb"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "78333ddd-03ba-4274-ae24-321c3563584a"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "95e28700-5bea-4855-bda5-4fe4660dbaaa"); - - migrationBuilder.DeleteData( - table: "Role", - keyColumn: "Id", - keyValue: "b8854b49-d887-4ac9-9ffe-bc391909380c"); - - migrationBuilder.InsertData( - table: "Role", - columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, - values: new object[,] - { - { "17222f04-4d61-48c7-b50b-16287b8f1d70", null, "Administrator", "ADMINISTRATOR" }, - { "2ff29e6d-a8df-4dcc-af3b-7dfd59a13510", null, "Manager", "MANAGER" }, - { "6f6835f9-ea44-483e-aa69-97d452868bff", null, "Operator", "OPERATOR" }, - { "89887e6f-24d2-4fc5-a874-af4b4258d7b1", null, "Doctor", "DOCTOR" }, - { "b8182f0e-79e3-4c31-b5a2-5c74a8598990", null, "Driver", "DRIVER" }, - { "c58e9004-eef9-4568-9205-41d84054d234", null, "Dispatcher", "DISPATCHER" }, - { "f7d4b7c5-83e1-41ef-aec8-15722f67532a", null, "Mechanic", "MECHANIC" } - }); - } -} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.Designer.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.Designer.cs similarity index 97% rename from CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.Designer.cs rename to CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.Designer.cs index f9cf59df..7b57bc78 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241005161211_Add_Manager_ManagerReview.Designer.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.Designer.cs @@ -12,7 +12,7 @@ namespace CheckDrive.Infrastructure.Persistence.Migrations { [DbContext(typeof(CheckDriveDbContext))] - [Migration("20241005161211_Add_Manager_ManagerReview")] + [Migration("20241006100658_Add_Manager_ManagerReview")] partial class Add_Manager_ManagerReview { /// <inheritdoc /> @@ -284,6 +284,14 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Property<DateTime>("Date") .HasColumnType("datetime2"); + b.Property<decimal?>("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + b.Property<int>("ManagerId") .HasColumnType("int"); @@ -477,43 +485,43 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "1eef2d65-63aa-4bd3-ad11-97b05465411a", + Id = "5089a8a9-4e4f-4c6d-848c-23f2b3a3899c", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "50732e08-b22e-4d0c-8196-13a14fda4edb", + Id = "f481030e-c1b1-41fe-a889-119bf9efbe33", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "95e28700-5bea-4855-bda5-4fe4660dbaaa", + Id = "153b479b-2c52-4729-94e0-513fdec3f66e", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "b8854b49-d887-4ac9-9ffe-bc391909380c", + Id = "43e6d885-ec20-4a5a-a94a-8477c8a1fa60", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "099bbfb1-a22a-48f8-a707-bd954851b749", + Id = "bdff891f-f7de-4ad0-9267-a5dda2cc22b9", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "78333ddd-03ba-4274-ae24-321c3563584a", + Id = "18c5b372-b34e-4194-838c-cdc1c64682f2", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "2f72a51b-f05d-49b5-98fc-c2c1b32219e1", + Id = "2d7e1223-bd95-4880-9805-54a68f84d74f", Name = "Operator", NormalizedName = "OPERATOR" }); diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.cs new file mode 100644 index 00000000..d87e13d7 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.cs @@ -0,0 +1,161 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace CheckDrive.Infrastructure.Persistence.Migrations; + +/// <inheritdoc /> +public partial class Add_Manager_ManagerReview : Migration +{ + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "46a46741-5b52-444e-a5f9-169556a44c5b"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "52e9693c-ccc2-453b-bb73-6f1987c60664"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "87ed0262-1d37-4824-ae87-f1a8119c9d50"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "8da8eab2-4243-44e1-bfae-0d7a86135bea"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "bcaf852e-2688-44c1-aa77-4b2d65231832"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "d864ade1-ac59-4ab3-ba59-a6c12f3250e3"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "d907a396-369a-4fde-8f7d-3918e185f554"); + + migrationBuilder.CreateTable( + name: "ManagerReview", + columns: table => new + { + Id = table.Column<int>(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + DebtAmountAdjusment = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), + FuelConsumptionAdjustment = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), + CheckPointId = table.Column<int>(type: "int", nullable: false), + ManagerId = table.Column<int>(type: "int", nullable: false), + Notes = table.Column<string>(type: "nvarchar(max)", nullable: true), + Date = table.Column<DateTime>(type: "datetime2", nullable: false), + Status = table.Column<int>(type: "int", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ManagerReview", x => x.Id); + table.ForeignKey( + name: "FK_ManagerReview_CheckPoint_CheckPointId", + column: x => x.CheckPointId, + principalTable: "CheckPoint", + principalColumn: "Id"); + table.ForeignKey( + name: "FK_ManagerReview_Employee_ManagerId", + column: x => x.ManagerId, + principalTable: "Employee", + principalColumn: "Id"); + }); + + migrationBuilder.InsertData( + table: "Role", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "153b479b-2c52-4729-94e0-513fdec3f66e", null, "Doctor", "DOCTOR" }, + { "18c5b372-b34e-4194-838c-cdc1c64682f2", null, "Mechanic", "MECHANIC" }, + { "2d7e1223-bd95-4880-9805-54a68f84d74f", null, "Operator", "OPERATOR" }, + { "43e6d885-ec20-4a5a-a94a-8477c8a1fa60", null, "Dispatcher", "DISPATCHER" }, + { "5089a8a9-4e4f-4c6d-848c-23f2b3a3899c", null, "Administrator", "ADMINISTRATOR" }, + { "bdff891f-f7de-4ad0-9267-a5dda2cc22b9", null, "Manager", "MANAGER" }, + { "f481030e-c1b1-41fe-a889-119bf9efbe33", null, "Driver", "DRIVER" } + }); + + migrationBuilder.CreateIndex( + name: "IX_ManagerReview_CheckPointId", + table: "ManagerReview", + column: "CheckPointId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ManagerReview_ManagerId", + table: "ManagerReview", + column: "ManagerId"); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ManagerReview"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "153b479b-2c52-4729-94e0-513fdec3f66e"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "18c5b372-b34e-4194-838c-cdc1c64682f2"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "2d7e1223-bd95-4880-9805-54a68f84d74f"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "43e6d885-ec20-4a5a-a94a-8477c8a1fa60"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "5089a8a9-4e4f-4c6d-848c-23f2b3a3899c"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "bdff891f-f7de-4ad0-9267-a5dda2cc22b9"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "f481030e-c1b1-41fe-a889-119bf9efbe33"); + + migrationBuilder.InsertData( + table: "Role", + columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, + values: new object[,] + { + { "46a46741-5b52-444e-a5f9-169556a44c5b", null, "Administrator", "ADMINISTRATOR" }, + { "52e9693c-ccc2-453b-bb73-6f1987c60664", null, "Driver", "DRIVER" }, + { "87ed0262-1d37-4824-ae87-f1a8119c9d50", null, "Manager", "MANAGER" }, + { "8da8eab2-4243-44e1-bfae-0d7a86135bea", null, "Dispatcher", "DISPATCHER" }, + { "bcaf852e-2688-44c1-aa77-4b2d65231832", null, "Mechanic", "MECHANIC" }, + { "d864ade1-ac59-4ab3-ba59-a6c12f3250e3", null, "Doctor", "DOCTOR" }, + { "d907a396-369a-4fde-8f7d-3918e185f554", null, "Operator", "OPERATOR" } + }); + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs index 343190cd..d01b5381 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs @@ -267,6 +267,47 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.UseTphMappingStrategy(); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal?>("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManagerId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("ManagerId"); + + b.ToTable("ManagerReview", (string)null); + }); + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => { b.Property<int>("Id") @@ -441,43 +482,43 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "46a46741-5b52-444e-a5f9-169556a44c5b", + Id = "5089a8a9-4e4f-4c6d-848c-23f2b3a3899c", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "52e9693c-ccc2-453b-bb73-6f1987c60664", + Id = "f481030e-c1b1-41fe-a889-119bf9efbe33", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "d864ade1-ac59-4ab3-ba59-a6c12f3250e3", + Id = "153b479b-2c52-4729-94e0-513fdec3f66e", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "8da8eab2-4243-44e1-bfae-0d7a86135bea", + Id = "43e6d885-ec20-4a5a-a94a-8477c8a1fa60", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "87ed0262-1d37-4824-ae87-f1a8119c9d50", + Id = "bdff891f-f7de-4ad0-9267-a5dda2cc22b9", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "bcaf852e-2688-44c1-aa77-4b2d65231832", + Id = "18c5b372-b34e-4194-838c-cdc1c64682f2", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "d907a396-369a-4fde-8f7d-3918e185f554", + Id = "2d7e1223-bd95-4880-9805-54a68f84d74f", Name = "Operator", NormalizedName = "OPERATOR" }); @@ -675,6 +716,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasDiscriminator().HasValue(1); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(6); + }); + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => { b.HasBaseType("CheckDrive.Domain.Entities.Employee"); @@ -757,6 +805,25 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Account"); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Manager", "Manager") + .WithMany("Reviews") + .HasForeignKey("ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Manager"); + }); + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => { b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") @@ -895,6 +962,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("DoctorReview") .IsRequired(); + b.Navigation("ManagerReview"); + b.Navigation("MechanicAcceptance"); b.Navigation("MechanicHandover"); @@ -922,6 +991,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Reviews"); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.Navigation("Reviews"); + }); + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => { b.Navigation("Acceptances"); From e306d393bc5e243835ba474666e00c9cbdab18d2 Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:37:51 +0500 Subject: [PATCH 03/40] fixed --- .../CheckDrive.Domain/Entities/Debt.cs | 3 ++ .../Entities/ManagerReview.cs | 3 ++ .../ManagerReviewConfigurations.cs | 23 +++++---- ...314_Add_Manager_ManagerReview.Designer.cs} | 38 +++++++++++---- ...241006103314_Add_Manager_ManagerReview.cs} | 47 +++++++++++++------ .../CheckDriveDbContextModelSnapshot.cs | 36 ++++++++++---- 6 files changed, 110 insertions(+), 40 deletions(-) rename CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/{20241006100658_Add_Manager_ManagerReview.Designer.cs => 20241006103314_Add_Manager_ManagerReview.Designer.cs} (96%) rename CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/{20241006100658_Add_Manager_ManagerReview.cs => 20241006103314_Add_Manager_ManagerReview.cs} (77%) diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/Debt.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/Debt.cs index c84cb520..8bde6224 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Entities/Debt.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/Debt.cs @@ -11,4 +11,7 @@ public class Debt : EntityBase public int CheckPointId { get; set; } public required virtual CheckPoint CheckPoint { get; set; } + + public int? ManagerReviewId { get; set; } + public virtual ManagerReview? ManagerReview { get; set; } } diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs index b05c749c..6b6632d6 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs @@ -12,4 +12,7 @@ public class ManagerReview : ReviewBase public int ManagerId { get; set; } public required virtual Manager Manager { get; set; } + + public int? DebtId { get; set; } + public virtual Debt? Debt { get; set; } } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs index b188051e..0b103af4 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs @@ -9,21 +9,28 @@ internal class ManagerReviewConfigurations : IEntityTypeConfiguration<ManagerRev public void Configure(EntityTypeBuilder<ManagerReview> builder) { builder.ToTable(nameof(ManagerReview)); - builder.HasKey(mn => mn.Id); + builder.HasKey(mr => mr.Id); #region Relationships builder - .HasOne(mn => mn.CheckPoint) + .HasOne(mr => mr.CheckPoint) .WithOne(cp => cp.ManagerReview) - .HasForeignKey<ManagerReview>(mn => mn.CheckPointId) + .HasForeignKey<ManagerReview>(mr => mr.CheckPointId) .OnDelete(DeleteBehavior.NoAction) .IsRequired(); builder - .HasOne(mn => mn.Manager) - .WithMany(d => d.Reviews) - .HasForeignKey(mn => mn.ManagerId) + .HasOne(mr => mr.Manager) + .WithMany(m => m.Reviews) + .HasForeignKey(mr => mr.ManagerId) + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + builder + .HasOne(mr => mr.Debt) + .WithOne(d => d.ManagerReview) + .HasForeignKey<ManagerReview>(mr => mr.ManagerId) .OnDelete(DeleteBehavior.NoAction) .IsRequired(); @@ -32,12 +39,12 @@ public void Configure(EntityTypeBuilder<ManagerReview> builder) #region Properties builder - .Property(mn => mn.DebtAmountAdjusment) + .Property(mr => mr.DebtAmountAdjusment) .HasPrecision(18, 2) .IsRequired(false); builder - .Property(mn => mn.FuelConsumptionAdjustment) + .Property(mr => mr.FuelConsumptionAdjustment) .HasPrecision(18, 2) .IsRequired(false); diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.Designer.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.Designer.cs similarity index 96% rename from CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.Designer.cs rename to CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.Designer.cs index 7b57bc78..76a28fdb 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.Designer.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.Designer.cs @@ -12,7 +12,7 @@ namespace CheckDrive.Infrastructure.Persistence.Migrations { [DbContext(typeof(CheckDriveDbContext))] - [Migration("20241006100658_Add_Manager_ManagerReview")] + [Migration("20241006103314_Add_Manager_ManagerReview")] partial class Add_Manager_ManagerReview { /// <inheritdoc /> @@ -124,6 +124,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); + b.Property<int?>("ManagerReviewId") + .HasColumnType("int"); + b.Property<decimal>("PaidAmount") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -288,6 +291,9 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); + b.Property<int?>("DebtId") + .HasColumnType("int"); + b.Property<decimal?>("FuelConsumptionAdjustment") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -306,7 +312,8 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasIndex("CheckPointId") .IsUnique(); - b.HasIndex("ManagerId"); + b.HasIndex("ManagerId") + .IsUnique(); b.ToTable("ManagerReview", (string)null); }); @@ -485,43 +492,43 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "5089a8a9-4e4f-4c6d-848c-23f2b3a3899c", + Id = "d6c0f8c6-b894-44ff-80f9-eb65961d8002", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "f481030e-c1b1-41fe-a889-119bf9efbe33", + Id = "5bd07b96-507a-4b1a-b9ff-b421cfe1d205", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "153b479b-2c52-4729-94e0-513fdec3f66e", + Id = "8b08e145-6325-4046-b55c-77b9906966b5", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "43e6d885-ec20-4a5a-a94a-8477c8a1fa60", + Id = "ed4099e0-601c-414d-b763-f2151a29040d", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "bdff891f-f7de-4ad0-9267-a5dda2cc22b9", + Id = "ee9613ef-226d-4fba-9ab3-9a07d902018b", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "18c5b372-b34e-4194-838c-cdc1c64682f2", + Id = "7fbd87ba-5311-4855-b18f-54b7e711eb82", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "2d7e1223-bd95-4880-9805-54a68f84d74f", + Id = "c9734b82-c84a-43b2-b453-c4ff6eb8c1cf", Name = "Operator", NormalizedName = "OPERATOR" }); @@ -816,6 +823,12 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.NoAction) .IsRequired(); + b.HasOne("CheckDrive.Domain.Entities.Debt", "Debt") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + b.HasOne("CheckDrive.Domain.Entities.Manager", "Manager") .WithMany("Reviews") .HasForeignKey("ManagerId") @@ -824,6 +837,8 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("CheckPoint"); + b.Navigation("Debt"); + b.Navigation("Manager"); }); @@ -974,6 +989,11 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("OperatorReview"); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Navigation("ManagerReview"); + }); + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => { b.Navigation("Reviews"); diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.cs similarity index 77% rename from CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.cs rename to CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.cs index d87e13d7..68c99381 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006100658_Add_Manager_ManagerReview.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.cs @@ -48,6 +48,12 @@ protected override void Up(MigrationBuilder migrationBuilder) keyColumn: "Id", keyValue: "d907a396-369a-4fde-8f7d-3918e185f554"); + migrationBuilder.AddColumn<int>( + name: "ManagerReviewId", + table: "Debt", + type: "int", + nullable: true); + migrationBuilder.CreateTable( name: "ManagerReview", columns: table => new @@ -58,6 +64,7 @@ protected override void Up(MigrationBuilder migrationBuilder) FuelConsumptionAdjustment = table.Column<decimal>(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), CheckPointId = table.Column<int>(type: "int", nullable: false), ManagerId = table.Column<int>(type: "int", nullable: false), + DebtId = table.Column<int>(type: "int", nullable: true), Notes = table.Column<string>(type: "nvarchar(max)", nullable: true), Date = table.Column<DateTime>(type: "datetime2", nullable: false), Status = table.Column<int>(type: "int", nullable: false) @@ -70,6 +77,11 @@ protected override void Up(MigrationBuilder migrationBuilder) column: x => x.CheckPointId, principalTable: "CheckPoint", principalColumn: "Id"); + table.ForeignKey( + name: "FK_ManagerReview_Debt_ManagerId", + column: x => x.ManagerId, + principalTable: "Debt", + principalColumn: "Id"); table.ForeignKey( name: "FK_ManagerReview_Employee_ManagerId", column: x => x.ManagerId, @@ -82,13 +94,13 @@ protected override void Up(MigrationBuilder migrationBuilder) columns: new[] { "Id", "ConcurrencyStamp", "Name", "NormalizedName" }, values: new object[,] { - { "153b479b-2c52-4729-94e0-513fdec3f66e", null, "Doctor", "DOCTOR" }, - { "18c5b372-b34e-4194-838c-cdc1c64682f2", null, "Mechanic", "MECHANIC" }, - { "2d7e1223-bd95-4880-9805-54a68f84d74f", null, "Operator", "OPERATOR" }, - { "43e6d885-ec20-4a5a-a94a-8477c8a1fa60", null, "Dispatcher", "DISPATCHER" }, - { "5089a8a9-4e4f-4c6d-848c-23f2b3a3899c", null, "Administrator", "ADMINISTRATOR" }, - { "bdff891f-f7de-4ad0-9267-a5dda2cc22b9", null, "Manager", "MANAGER" }, - { "f481030e-c1b1-41fe-a889-119bf9efbe33", null, "Driver", "DRIVER" } + { "5bd07b96-507a-4b1a-b9ff-b421cfe1d205", null, "Driver", "DRIVER" }, + { "7fbd87ba-5311-4855-b18f-54b7e711eb82", null, "Mechanic", "MECHANIC" }, + { "8b08e145-6325-4046-b55c-77b9906966b5", null, "Doctor", "DOCTOR" }, + { "c9734b82-c84a-43b2-b453-c4ff6eb8c1cf", null, "Operator", "OPERATOR" }, + { "d6c0f8c6-b894-44ff-80f9-eb65961d8002", null, "Administrator", "ADMINISTRATOR" }, + { "ed4099e0-601c-414d-b763-f2151a29040d", null, "Dispatcher", "DISPATCHER" }, + { "ee9613ef-226d-4fba-9ab3-9a07d902018b", null, "Manager", "MANAGER" } }); migrationBuilder.CreateIndex( @@ -100,7 +112,8 @@ protected override void Up(MigrationBuilder migrationBuilder) migrationBuilder.CreateIndex( name: "IX_ManagerReview_ManagerId", table: "ManagerReview", - column: "ManagerId"); + column: "ManagerId", + unique: true); } /// <inheritdoc /> @@ -112,37 +125,41 @@ protected override void Down(MigrationBuilder migrationBuilder) migrationBuilder.DeleteData( table: "Role", keyColumn: "Id", - keyValue: "153b479b-2c52-4729-94e0-513fdec3f66e"); + keyValue: "5bd07b96-507a-4b1a-b9ff-b421cfe1d205"); migrationBuilder.DeleteData( table: "Role", keyColumn: "Id", - keyValue: "18c5b372-b34e-4194-838c-cdc1c64682f2"); + keyValue: "7fbd87ba-5311-4855-b18f-54b7e711eb82"); migrationBuilder.DeleteData( table: "Role", keyColumn: "Id", - keyValue: "2d7e1223-bd95-4880-9805-54a68f84d74f"); + keyValue: "8b08e145-6325-4046-b55c-77b9906966b5"); migrationBuilder.DeleteData( table: "Role", keyColumn: "Id", - keyValue: "43e6d885-ec20-4a5a-a94a-8477c8a1fa60"); + keyValue: "c9734b82-c84a-43b2-b453-c4ff6eb8c1cf"); migrationBuilder.DeleteData( table: "Role", keyColumn: "Id", - keyValue: "5089a8a9-4e4f-4c6d-848c-23f2b3a3899c"); + keyValue: "d6c0f8c6-b894-44ff-80f9-eb65961d8002"); migrationBuilder.DeleteData( table: "Role", keyColumn: "Id", - keyValue: "bdff891f-f7de-4ad0-9267-a5dda2cc22b9"); + keyValue: "ed4099e0-601c-414d-b763-f2151a29040d"); migrationBuilder.DeleteData( table: "Role", keyColumn: "Id", - keyValue: "f481030e-c1b1-41fe-a889-119bf9efbe33"); + keyValue: "ee9613ef-226d-4fba-9ab3-9a07d902018b"); + + migrationBuilder.DropColumn( + name: "ManagerReviewId", + table: "Debt"); migrationBuilder.InsertData( table: "Role", diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs index d01b5381..dd4e25ab 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs @@ -121,6 +121,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); + b.Property<int?>("ManagerReviewId") + .HasColumnType("int"); + b.Property<decimal>("PaidAmount") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -285,6 +288,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); + b.Property<int?>("DebtId") + .HasColumnType("int"); + b.Property<decimal?>("FuelConsumptionAdjustment") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -303,7 +309,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasIndex("CheckPointId") .IsUnique(); - b.HasIndex("ManagerId"); + b.HasIndex("ManagerId") + .IsUnique(); b.ToTable("ManagerReview", (string)null); }); @@ -482,43 +489,43 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "5089a8a9-4e4f-4c6d-848c-23f2b3a3899c", + Id = "d6c0f8c6-b894-44ff-80f9-eb65961d8002", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "f481030e-c1b1-41fe-a889-119bf9efbe33", + Id = "5bd07b96-507a-4b1a-b9ff-b421cfe1d205", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "153b479b-2c52-4729-94e0-513fdec3f66e", + Id = "8b08e145-6325-4046-b55c-77b9906966b5", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "43e6d885-ec20-4a5a-a94a-8477c8a1fa60", + Id = "ed4099e0-601c-414d-b763-f2151a29040d", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "bdff891f-f7de-4ad0-9267-a5dda2cc22b9", + Id = "ee9613ef-226d-4fba-9ab3-9a07d902018b", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "18c5b372-b34e-4194-838c-cdc1c64682f2", + Id = "7fbd87ba-5311-4855-b18f-54b7e711eb82", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "2d7e1223-bd95-4880-9805-54a68f84d74f", + Id = "c9734b82-c84a-43b2-b453-c4ff6eb8c1cf", Name = "Operator", NormalizedName = "OPERATOR" }); @@ -813,6 +820,12 @@ protected override void BuildModel(ModelBuilder modelBuilder) .OnDelete(DeleteBehavior.NoAction) .IsRequired(); + b.HasOne("CheckDrive.Domain.Entities.Debt", "Debt") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + b.HasOne("CheckDrive.Domain.Entities.Manager", "Manager") .WithMany("Reviews") .HasForeignKey("ManagerId") @@ -821,6 +834,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("CheckPoint"); + b.Navigation("Debt"); + b.Navigation("Manager"); }); @@ -971,6 +986,11 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("OperatorReview"); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Navigation("ManagerReview"); + }); + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => { b.Navigation("Reviews"); From 2aa99f5d2d360d48c7c99c0025925948dce5c516 Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Sun, 6 Oct 2024 15:46:06 +0500 Subject: [PATCH 04/40] changed configuration to sealed --- .../Persistence/Configurations/ManagerReviewConfigurations.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs index 0b103af4..62d6bc9d 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs @@ -4,7 +4,7 @@ namespace CheckDrive.Infrastructure.Persistence.Configurations; -internal class ManagerReviewConfigurations : IEntityTypeConfiguration<ManagerReview> +internal sealed class ManagerReviewConfigurations : IEntityTypeConfiguration<ManagerReview> { public void Configure(EntityTypeBuilder<ManagerReview> builder) { From 251afb1f568ed1ecc5e79f9e441e7ac88830e755 Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Mon, 7 Oct 2024 13:46:18 +0500 Subject: [PATCH 05/40] added assign to role logics to create user account service --- .../Services/AccountService.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs index b4bd538b..ea29321c 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs @@ -1,7 +1,9 @@ using AutoMapper; +using CheckDrive.Application.Constants; using CheckDrive.Application.DTOs.Account; using CheckDrive.Application.Interfaces; using CheckDrive.Domain.Entities; +using CheckDrive.Domain.Enums; using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; using Microsoft.AspNetCore.Identity; @@ -65,6 +67,8 @@ public async Task<AccountDto> CreateAsync(CreateAccountDto account) throw new InvalidOperationException("Could not create user account."); } + await AssignToRoleAsync(user, account.Position); + var employee = _mapper.Map<Employee>(account); employee.AccountId = user.Id; @@ -95,4 +99,25 @@ public async Task DeleteAsync(string id) _context.Users.Remove(account); await _context.SaveChangesAsync(); } + + private async Task AssignToRoleAsync(IdentityUser user,EmployeePosition position) + { + var role = position switch + { + EmployeePosition.Driver => Roles.Driver, + EmployeePosition.Doctor => Roles.Doctor, + EmployeePosition.Mechanic => Roles.Mechanic, + EmployeePosition.Operator => Roles.Operator, + EmployeePosition.Dispatcher => Roles.Dispatcher, + EmployeePosition.Manager => Roles.Manager, + _ => throw new InvalidOperationException("Invalid position for role assignment.") + }; + + var roleResult = await _userManager.AddToRoleAsync(user, role.ToString()); + + if (!roleResult.Succeeded) + { + throw new InvalidOperationException("Could not create user account."); + } + } } From 6ccb86ebfd69a977c4435d8b4aacb6046fbb5ecf Mon Sep 17 00:00:00 2001 From: FirdavsAX <137472686+FirdavsAX@users.noreply.github.com> Date: Mon, 7 Oct 2024 15:36:47 +0500 Subject: [PATCH 06/40] Added Added Manager Create in DatabaseSeeder Fix problem in Database Seeder methods which all employee creators use drivers count instead of themself counts in options Added ManagersCount to DataSeedOptions and appsettings.json s --- .../CheckDrive.Api/Helpers/DatabaseSeeder.cs | 44 +++++++++++++++++-- .../Middlewares/ErrorHandlerMiddleware.cs | 2 +- .../CheckDrive.Api/appsettings.Testing.json | 3 +- .../Configurations/DataSeedOptions.cs | 1 + 4 files changed, 45 insertions(+), 5 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs b/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs index 788e8267..8a9cefc8 100644 --- a/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs +++ b/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs @@ -23,6 +23,7 @@ public static void SeedDatabase( CreateMechanics(context, userManager, options); CreateOperators(context, userManager, options); CreateDispatchers(context, userManager, options); + CreateManagers(context, userManager, options); } private static void CreateCars(ICheckDriveDbContext context, DataSeedOptions options) @@ -144,7 +145,7 @@ private static void CreateMechanics(ICheckDriveDbContext context, UserManager<Id var role = context.Roles.First(x => x.Name == "mechanic"); var uniqueMechanicsByName = new Dictionary<string, Mechanic>(); - for (int i = 0; i < options.DriversCount; i++) + for (int i = 0; i < options.MechanicsCount; i++) { var account = FakeDataGenerator.GetAccount().Generate(); var mechanic = FakeDataGenerator.GetEmployee<Mechanic>().Generate(); @@ -182,7 +183,7 @@ private static void CreateOperators(ICheckDriveDbContext context, UserManager<Id var role = context.Roles.First(x => x.Name == "operator"); var uniqueOperatorsByName = new Dictionary<string, Operator>(); - for (int i = 0; i < options.DriversCount; i++) + for (int i = 0; i < options.OperatorsCount; i++) { var account = FakeDataGenerator.GetAccount().Generate(); var @operator = FakeDataGenerator.GetEmployee<Operator>().Generate(); @@ -220,7 +221,7 @@ private static void CreateDispatchers(ICheckDriveDbContext context, UserManager< var role = context.Roles.First(x => x.Name == "dispatcher"); var uniqueDispatchersByName = new Dictionary<string, Dispatcher>(); - for (int i = 0; i < options.DriversCount; i++) + for (int i = 0; i < options.DispatchersCount; i++) { var account = FakeDataGenerator.GetAccount().Generate(); var dispatcher = FakeDataGenerator.GetEmployee<Dispatcher>().Generate(); @@ -251,6 +252,43 @@ private static void CreateDispatchers(ICheckDriveDbContext context, UserManager< context.SaveChanges(); } + private static void CreateManagers(ICheckDriveDbContext context, UserManager<IdentityUser> userManager, DataSeedOptions options) + { + if (context.Managers.Any()) return; + + var role = context.Roles.First(x => x.Name == "manager"); + var uniqueManagersByName = new Dictionary<string, Manager>(); + + for (int i = 0; i < options.ManagersCount; i++) + { + var account = FakeDataGenerator.GetAccount().Generate(); + var manager = FakeDataGenerator.GetEmployee<Manager>().Generate(); + + if (uniqueManagersByName.TryAdd(manager.FirstName + manager.LastName, manager)) + { + var result = userManager.CreateAsync(account, $"Qwerty-{i}"); + + if (!result.Result.Succeeded) + { + continue; + } + + manager.Account = account; + context.Managers.Add(manager); + } + } + + context.SaveChanges(); + var managers = context.Managers.ToArray(); + + foreach (var manager in managers) + { + var userRole = new IdentityUserRole<string> { RoleId = role.Id, UserId = manager.AccountId }; + context.UserRoles.Add(userRole); + } + + context.SaveChanges(); + } //private static void CreateEmployees(ICheckDriveDbContext context, UserManager<IdentityUser> userManager, DataSeedOptions options) //{ // if (context.Users.Any()) diff --git a/CheckDrive.Api/CheckDrive.Api/Middlewares/ErrorHandlerMiddleware.cs b/CheckDrive.Api/CheckDrive.Api/Middlewares/ErrorHandlerMiddleware.cs index f5a98a32..c7daaa2a 100644 --- a/CheckDrive.Api/CheckDrive.Api/Middlewares/ErrorHandlerMiddleware.cs +++ b/CheckDrive.Api/CheckDrive.Api/Middlewares/ErrorHandlerMiddleware.cs @@ -32,7 +32,7 @@ private async Task HandleAsync(HttpContext context, Exception exception) context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; string message = "Internal server error. Something went wrong, please try again later."; - if (exception is NotFound) + if (exception is EntityNotFoundException) { context.Response.StatusCode = (int)HttpStatusCode.NotFound; message = exception.Message; diff --git a/CheckDrive.Api/CheckDrive.Api/appsettings.Testing.json b/CheckDrive.Api/CheckDrive.Api/appsettings.Testing.json index adc64dd0..31fe450b 100644 --- a/CheckDrive.Api/CheckDrive.Api/appsettings.Testing.json +++ b/CheckDrive.Api/CheckDrive.Api/appsettings.Testing.json @@ -26,6 +26,7 @@ "DoctorsCount": 5, "MechanicsCount": 10, "OperatorsCount": 10, - "DispatchersCount": 10 + "DispatchersCount": 10, + "ManagersCount": 2 } } \ No newline at end of file diff --git a/CheckDrive.Api/CheckDrive.TestDataCreator/Configurations/DataSeedOptions.cs b/CheckDrive.Api/CheckDrive.TestDataCreator/Configurations/DataSeedOptions.cs index 19c2dc80..f68e7116 100644 --- a/CheckDrive.Api/CheckDrive.TestDataCreator/Configurations/DataSeedOptions.cs +++ b/CheckDrive.Api/CheckDrive.TestDataCreator/Configurations/DataSeedOptions.cs @@ -10,6 +10,7 @@ public class DataSeedOptions public int DriversCount { get; set; } public int DoctorsCount { get; set; } public int MechanicsCount { get; set; } + public int ManagersCount { get; set; } public int OperatorsCount { get; set; } public int DispatchersCount { get; set; } } From 5770677ec10bdaebd425df8d7f179965184b813f Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Wed, 23 Oct 2024 13:50:12 +0500 Subject: [PATCH 07/40] add employee filtering by position & enum support for swagger --- .../CheckDrive.Api/CheckDrive.Api.csproj | 1 + .../Controllers/AccountsController.cs | 5 ++-- .../Extensions/DependencyInjection.cs | 13 +++++++---- .../Filters/EnumSchemaFilter.cs | 23 ------------------- .../Interfaces/IAccountService.cs | 3 ++- .../Services/AccountService.cs | 15 ++++++++---- 6 files changed, 24 insertions(+), 36 deletions(-) delete mode 100644 CheckDrive.Api/CheckDrive.Api/Filters/EnumSchemaFilter.cs diff --git a/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj b/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj index 0a76477a..963bfcc6 100644 --- a/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj +++ b/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj @@ -24,6 +24,7 @@ <PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="6.0.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.8.0" /> + <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="6.9.0" /> <PackageReference Include="Syncfusion.XlsIO.Net.Core" Version="27.1.50" /> </ItemGroup> diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/AccountsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/AccountsController.cs index 2b92117f..13a7a01c 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/AccountsController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/AccountsController.cs @@ -1,6 +1,7 @@ using CheckDrive.Application.Constants; using CheckDrive.Application.DTOs.Account; using CheckDrive.Application.Interfaces; +using CheckDrive.Domain.Enums; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; @@ -18,9 +19,9 @@ public AccountsController(IAccountService service) } [HttpGet] - public async Task<ActionResult<List<AccountDto>>> GetAsync() + public async Task<ActionResult<List<AccountDto>>> GetAsync(EmployeePosition? position) { - var accounts = await _service.GetAsync(); + var accounts = await _service.GetAsync(position); return Ok(accounts); } diff --git a/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs index 13f20e57..5e9f884e 100644 --- a/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs @@ -9,7 +9,6 @@ using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using System.Text; -using CheckDrive.Api.Filters; namespace CheckDrive.Api.Extensions; @@ -56,15 +55,19 @@ private static void AddSwagger(IServiceCollection services) .AddSwaggerGen(setup => { setup.SwaggerDoc("v1", new OpenApiInfo { Title = "Check-Drive API", Version = "v1" }); - - setup.SchemaFilter<EnumSchemaFilter>(); - }); + }) + .AddSwaggerGenNewtonsoftSupport(); } private static void AddAuthentication(IServiceCollection services, IConfiguration configuration) { var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get<JwtOptions>(); + if (jwtOptions is null) + { + throw new InvalidOperationException("Could not load JWT configurations."); + } + services .AddAuthentication(options => { @@ -84,7 +87,7 @@ private static void AddAuthentication(IServiceCollection services, IConfiguratio ValidateLifetime = true, ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey( - Encoding.UTF8.GetBytes(jwtOptions!.SecretKey)) + Encoding.UTF8.GetBytes(jwtOptions.SecretKey)) }; options.Events = new JwtBearerEvents diff --git a/CheckDrive.Api/CheckDrive.Api/Filters/EnumSchemaFilter.cs b/CheckDrive.Api/CheckDrive.Api/Filters/EnumSchemaFilter.cs deleted file mode 100644 index 3c1b41f2..00000000 --- a/CheckDrive.Api/CheckDrive.Api/Filters/EnumSchemaFilter.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.OpenApi.Any; -using Microsoft.OpenApi.Models; -using Swashbuckle.AspNetCore.SwaggerGen; - -namespace CheckDrive.Api.Filters; - -public class EnumSchemaFilter : ISchemaFilter -{ - public void Apply(OpenApiSchema schema, SchemaFilterContext context) - { - if (context.Type.IsEnum) - { - // Enum.GetNames returns the names of the enum values - var enumNames = System.Enum.GetNames(context.Type); - - schema.Enum.Clear(); - foreach (var name in enumNames) - { - schema.Enum.Add(new OpenApiString(name)); - } - } - } -} diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/IAccountService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/IAccountService.cs index dc763b81..54a08d63 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/IAccountService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/IAccountService.cs @@ -1,10 +1,11 @@ using CheckDrive.Application.DTOs.Account; +using CheckDrive.Domain.Enums; namespace CheckDrive.Application.Interfaces; public interface IAccountService { - Task<List<AccountDto>> GetAsync(); + Task<List<AccountDto>> GetAsync(EmployeePosition? position); Task<AccountDto> GetByIdAsync(string id); Task<AccountDto> CreateAsync(CreateAccountDto account); Task<AccountDto> UpdateAsync(UpdateAccountDto account); diff --git a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs index ea29321c..2b379ac1 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs @@ -24,13 +24,18 @@ public AccountService(ICheckDriveDbContext context, IMapper mapper, UserManager< _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); } - public async Task<List<AccountDto>> GetAsync() + public async Task<List<AccountDto>> GetAsync(EmployeePosition? position) { - var accounts = await _context.Employees + var query = _context.Employees .AsNoTracking() - .Include(x => x.Account) - .ToListAsync(); + .AsQueryable(); + + if (position.HasValue) + { + query = query.Where(x => x.Position == position.Value); + } + var accounts = await query.ToListAsync(); var dtos = _mapper.Map<List<AccountDto>>(accounts); return dtos; @@ -100,7 +105,7 @@ public async Task DeleteAsync(string id) await _context.SaveChangesAsync(); } - private async Task AssignToRoleAsync(IdentityUser user,EmployeePosition position) + private async Task AssignToRoleAsync(IdentityUser user, EmployeePosition position) { var role = position switch { From bfcdf928469de0662e2a986acc1cfafeb2cdc072 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Fri, 25 Oct 2024 18:24:00 +0500 Subject: [PATCH 08/40] add endpoint to fetch drivers by status --- .../Controllers/DriversController.cs | 26 ++++++++++++++++ .../DTOs/Driver/DriverDto.cs | 3 ++ .../Extensions/DependencyInjection.cs | 1 + .../Interfaces/IDriverService.cs | 9 ++++++ .../Services/DriverService.cs | 31 +++++++++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs new file mode 100644 index 00000000..869bddd6 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs @@ -0,0 +1,26 @@ +using CheckDrive.Application.DTOs.Driver; +using CheckDrive.Application.Interfaces; +using CheckDrive.Domain.Enums; +using Microsoft.AspNetCore.Mvc; + +namespace CheckDrive.Api.Controllers; + +[Route("api/drivers")] +[ApiController] +public class DriversController : ControllerBase +{ + private readonly IDriverService _driverService; + + public DriversController(IDriverService driverService) + { + _driverService = driverService ?? throw new ArgumentNullException(nameof(driverService)); + } + + [HttpGet] + public async Task<ActionResult<List<DriverDto>>> GetAvailableDriversAsync(CheckPointStage? stage) + { + var drivers = await _driverService.GetAvailableDriversAsync(stage ?? CheckPointStage.DoctorReview); + + return Ok(drivers); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs new file mode 100644 index 00000000..0c381da2 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs @@ -0,0 +1,3 @@ +namespace CheckDrive.Application.DTOs.Driver; + +public record DriverDto(int Id, string AccountId, string FullName); diff --git a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs index 6370de63..259e5cf8 100644 --- a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs @@ -28,5 +28,6 @@ private static void AddServices(IServiceCollection services) services.AddScoped<IDispatcherReviewService, DispatcherReviewService>(); services.AddScoped<ICheckPointService, CheckPointService>(); services.AddScoped<IAccountService, AccountService>(); + services.AddScoped<IDriverService, DriverService>(); } } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs new file mode 100644 index 00000000..ae50217d --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs @@ -0,0 +1,9 @@ +using CheckDrive.Application.DTOs.Driver; +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.Interfaces; + +public interface IDriverService +{ + Task<List<DriverDto>> GetAvailableDriversAsync(CheckPointStage stage); +} diff --git a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs new file mode 100644 index 00000000..3ab9be15 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs @@ -0,0 +1,31 @@ +using CheckDrive.Application.DTOs.Driver; +using CheckDrive.Application.Interfaces; +using CheckDrive.Domain.Enums; +using CheckDrive.Domain.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace CheckDrive.Application.Services; + +internal sealed class DriverService : IDriverService +{ + private readonly ICheckDriveDbContext _context; + + public DriverService(ICheckDriveDbContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public async Task<List<DriverDto>> GetAvailableDriversAsync(CheckPointStage stage) + { + var query = _context.Drivers + .AsNoTracking() + .Include(x => x.Account) + .AsQueryable(); + + var drivers = await query + .Select(x => new DriverDto(x.Id, x.AccountId, x.FirstName + " " + x.LastName)) + .ToListAsync(); + + return drivers; + } +} From 09a37d1eb6e4269e23dbc10c7a993de04a66fde3 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Fri, 25 Oct 2024 18:28:24 +0500 Subject: [PATCH 09/40] update JWt token generation to use user Id --- .../DTOs/Account/AccountDto.cs | 1 + .../Interfaces/Auth/IJwtTokenGenerator.cs | 4 ++-- .../Mappings/AccountMappings.cs | 3 ++- .../Services/Auth/AuthService.cs | 17 ++++++++++++----- .../Configurations/JwtOptions.cs | 7 +++++-- .../Helpers/JwtTokenGenerator.cs | 14 +++++++------- 6 files changed, 29 insertions(+), 17 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Account/AccountDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Account/AccountDto.cs index a5f907bf..5f0cbfaf 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/Account/AccountDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Account/AccountDto.cs @@ -4,6 +4,7 @@ namespace CheckDrive.Application.DTOs.Account; public record class AccountDto( string Id, + string AccountId, string Username, string PhoneNumber, string? Email, diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/Auth/IJwtTokenGenerator.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/Auth/IJwtTokenGenerator.cs index a801492f..c4541c2f 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/Auth/IJwtTokenGenerator.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/Auth/IJwtTokenGenerator.cs @@ -1,8 +1,8 @@ -using Microsoft.AspNetCore.Identity; +using CheckDrive.Domain.Entities; namespace CheckDrive.Application.Interfaces.Auth; public interface IJwtTokenGenerator { - string GenerateToken(IdentityUser user, IList<string> roles); + string GenerateToken(Employee employee, IList<string> roles); } diff --git a/CheckDrive.Api/CheckDrive.Application/Mappings/AccountMappings.cs b/CheckDrive.Api/CheckDrive.Application/Mappings/AccountMappings.cs index 500affcb..729f9e46 100644 --- a/CheckDrive.Api/CheckDrive.Application/Mappings/AccountMappings.cs +++ b/CheckDrive.Api/CheckDrive.Application/Mappings/AccountMappings.cs @@ -10,7 +10,8 @@ internal sealed class AccountMappings : Profile public AccountMappings() { CreateMap<Employee, AccountDto>() - .ForCtorParam(nameof(AccountDto.Id), cfg => cfg.MapFrom(e => e.AccountId)) + .ForCtorParam(nameof(AccountDto.Id), cfg => cfg.MapFrom(e => e.Id)) + .ForCtorParam(nameof(AccountDto.AccountId), cfg => cfg.MapFrom(e => e.AccountId)) .ForCtorParam(nameof(AccountDto.Username), cfg => cfg.MapFrom(e => e.Account.UserName)) .ForCtorParam(nameof(AccountDto.PhoneNumber), cfg => cfg.MapFrom(e => e.Account.PhoneNumber)) .ForCtorParam(nameof(AccountDto.Email), cfg => cfg.MapFrom(e => e.Account.Email)) diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs index ca9bb6e0..b3d1146f 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs @@ -1,7 +1,9 @@ using CheckDrive.Application.DTOs.Identity; using CheckDrive.Application.Interfaces.Auth; using CheckDrive.Domain.Exceptions; +using CheckDrive.Domain.Interfaces; using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services.Auth; @@ -9,26 +11,31 @@ internal sealed class AuthService : IAuthService { private readonly IJwtTokenGenerator _jwtTokenGenerator; private readonly UserManager<IdentityUser> _userManager; + private readonly ICheckDriveDbContext _context; - public AuthService(IJwtTokenGenerator jwtTokenGenerator, UserManager<IdentityUser> userManager) + public AuthService( + IJwtTokenGenerator jwtTokenGenerator, + UserManager<IdentityUser> userManager, + ICheckDriveDbContext context) { _jwtTokenGenerator = jwtTokenGenerator ?? throw new ArgumentNullException(nameof(jwtTokenGenerator)); _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); + _context = context ?? throw new ArgumentNullException(nameof(context)); } public async Task<string> LoginAsync(LoginDto request) { ArgumentNullException.ThrowIfNull(request); - var user = await _userManager.FindByNameAsync(request.UserName); + var employee = await _context.Employees.Include(x => x.Account).FirstOrDefaultAsync(x => x.Account.UserName == request.UserName); - if (user is null || !await _userManager.CheckPasswordAsync(user, request.Password)) + if (employee is null || !await _userManager.CheckPasswordAsync(employee.Account, request.Password)) { throw new InvalidLoginAttemptException("Invalid email or password"); } - var roles = await _userManager.GetRolesAsync(user); - var token = _jwtTokenGenerator.GenerateToken(user, roles); + var roles = await _userManager.GetRolesAsync(employee.Account); + var token = _jwtTokenGenerator.GenerateToken(employee, roles); return token; } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Configurations/JwtOptions.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Configurations/JwtOptions.cs index 11e8c240..b81e2659 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Configurations/JwtOptions.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Configurations/JwtOptions.cs @@ -6,7 +6,10 @@ public class JwtOptions { public const string SectionName = nameof(JwtOptions); - [Required(ErrorMessage = "Secret Key is required")] + [Required(ErrorMessage = "Secret Key is required.")] public required string SecretKey { get; init; } - public int ExpiresHours { get; init; } + + [Required(ErrorMessage = "Expiration time is required.")] + [Range(1, int.MaxValue, ErrorMessage = "Expiration time must be greater than 1 hour.")] + public int ExpiresInHours { get; init; } } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Helpers/JwtTokenGenerator.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Helpers/JwtTokenGenerator.cs index bc7e94df..4e256e9a 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Helpers/JwtTokenGenerator.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Helpers/JwtTokenGenerator.cs @@ -1,6 +1,6 @@ using CheckDrive.Application.Interfaces.Auth; +using CheckDrive.Domain.Entities; using CheckDrive.Infrastructure.Configurations; -using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using System.IdentityModel.Tokens.Jwt; @@ -18,15 +18,14 @@ public JwtTokenGenerator(IOptions<JwtOptions> options) _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); } - public string GenerateToken(IdentityUser user, - IList<string> roles) + public string GenerateToken(Employee employee, IList<string> roles) { - var claims = GetClaims(user, roles); + var claims = GetClaims(employee, roles); var signingKey = GetSigningKey(); var securityToken = new JwtSecurityToken( claims: claims, - expires: DateTime.UtcNow.AddHours(_options.ExpiresHours), + expires: DateTime.UtcNow.AddHours(_options.ExpiresInHours), signingCredentials: signingKey); var token = new JwtSecurityTokenHandler().WriteToken(securityToken); @@ -42,11 +41,12 @@ private SigningCredentials GetSigningKey() return signingKey; } - private static List<Claim> GetClaims(IdentityUser user, IList<string> roles) + private static List<Claim> GetClaims(Employee employee, IList<string> roles) { var claims = new List<Claim>() { - new (ClaimTypes.NameIdentifier, user.Id.ToString()), + new (ClaimTypes.PrimarySid, employee.AccountId), + new (ClaimTypes.NameIdentifier, employee.Id.ToString()), }; foreach (var role in roles) From e259616c4871c31f8851f20b12e9df70fab65ee8 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Fri, 25 Oct 2024 18:29:00 +0500 Subject: [PATCH 10/40] integrate SignalR with Doctor Review --- .../Extensions/DependencyInjection.cs | 4 +++ CheckDrive.Api/CheckDrive.Api/Program.cs | 3 +++ .../CheckDrive.Application/Hubs/IReviewHub.cs | 8 ++++++ .../CheckDrive.Application/Hubs/ReviewHub.cs | 26 +++++++++++++++++++ .../Services/Review/DoctorReviewService.cs | 10 +++++-- .../Services/DoctorReviewServiceTests.cs | 6 ++++- 6 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs diff --git a/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs index 5e9f884e..ff3eb848 100644 --- a/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs @@ -20,6 +20,10 @@ public static IServiceCollection ConfigureServices(this IServiceCollection servi services.RegisterInfrastructure(configuration); services.AddSingleton<FileExtensionContentTypeProvider>(); + services.AddSignalR(options => + { + options.EnableDetailedErrors = true; + }); AddControllers(services); AddSwagger(services); diff --git a/CheckDrive.Api/CheckDrive.Api/Program.cs b/CheckDrive.Api/CheckDrive.Api/Program.cs index 2bed574e..139f3049 100644 --- a/CheckDrive.Api/CheckDrive.Api/Program.cs +++ b/CheckDrive.Api/CheckDrive.Api/Program.cs @@ -1,5 +1,6 @@ using CheckDrive.Api.Extensions; using CheckDrive.Api.Helpers; +using CheckDrive.Application.Hubs; using Microsoft.AspNetCore.CookiePolicy; using Serilog; @@ -44,6 +45,8 @@ app.MapControllers(); +app.MapHub<ReviewHub>("/review-hub"); + app.Run(); // For API testing diff --git a/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs b/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs new file mode 100644 index 00000000..3a787470 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs @@ -0,0 +1,8 @@ +using CheckDrive.Application.DTOs.Review; + +namespace CheckDrive.Application.Hubs; + +public interface IReviewHub +{ + Task NotifyNewReviewAsync(ReviewDtoBase review); +} diff --git a/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs new file mode 100644 index 00000000..6e3bf66f --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs @@ -0,0 +1,26 @@ +using CheckDrive.Application.DTOs.Review; +using Microsoft.AspNetCore.SignalR; + +namespace CheckDrive.Application.Hubs; + +public sealed class ReviewHub : Hub<IReviewHub> +{ + public async Task NotifyNewReviewAsync(ReviewDtoBase review) + { + await Clients + .User(review.DriverId.ToString()) + .NotifyNewReviewAsync(review); + } + + public override Task OnConnectedAsync() + { + var s = Context.UserIdentifier; + return base.OnConnectedAsync(); + } + + public override Task OnDisconnectedAsync(Exception? exception) + { + var s = Context.UserIdentifier; + return base.OnDisconnectedAsync(exception); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs index f0f220e8..3421e954 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs @@ -1,10 +1,12 @@ using AutoMapper; using CheckDrive.Application.DTOs.DoctorReview; +using CheckDrive.Application.Hubs; using CheckDrive.Application.Interfaces.Review; using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; +using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services.Review; @@ -13,11 +15,13 @@ internal sealed class DoctorReviewService : IDoctorReviewService { private readonly ICheckDriveDbContext _context; private readonly IMapper _mapper; + private readonly IHubContext<ReviewHub, IReviewHub> _reviewHub; - public DoctorReviewService(ICheckDriveDbContext context, IMapper mapper) + public DoctorReviewService(ICheckDriveDbContext context, IMapper mapper, IHubContext<ReviewHub, IReviewHub> reviewHub) { _context = context ?? throw new ArgumentNullException(nameof(context)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _reviewHub = reviewHub ?? throw new ArgumentNullException(nameof(reviewHub)); } public async Task<DoctorReviewDto> CreateAsync(CreateDoctorReviewDto review) @@ -31,10 +35,12 @@ public async Task<DoctorReviewDto> CreateAsync(CreateDoctorReviewDto review) var reviewEntity = CreateReviewEntity(review, checkPoint, doctor, driver); _context.DoctorReviews.Add(reviewEntity); - await _context.SaveChangesAsync(); + // await _context.SaveChangesAsync(); var dto = _mapper.Map<DoctorReviewDto>(reviewEntity); + await _reviewHub.Clients.User(dto.DriverId.ToString()).NotifyNewReviewAsync(dto); + return dto; } diff --git a/CheckDrive.Api/Tests/CheckDrive.Tests.Unit/Services/DoctorReviewServiceTests.cs b/CheckDrive.Api/Tests/CheckDrive.Tests.Unit/Services/DoctorReviewServiceTests.cs index b33e1bf4..b4428a32 100644 --- a/CheckDrive.Api/Tests/CheckDrive.Tests.Unit/Services/DoctorReviewServiceTests.cs +++ b/CheckDrive.Api/Tests/CheckDrive.Tests.Unit/Services/DoctorReviewServiceTests.cs @@ -1,11 +1,13 @@ using AutoFixture; using AutoMapper; using CheckDrive.Application.DTOs.DoctorReview; +using CheckDrive.Application.Hubs; using CheckDrive.Application.Services.Review; using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; +using Microsoft.AspNetCore.SignalR; using Moq; using Moq.EntityFrameworkCore; @@ -16,12 +18,14 @@ public class DoctorReviewServiceTests : ServiceTestBase private readonly Mock<ICheckDriveDbContext> _mockContext; private readonly Mock<IMapper> _mockMapper; private readonly DoctorReviewService _service; + private readonly Mock<IHubContext<ReviewHub, IReviewHub>> _mockHubContext; public DoctorReviewServiceTests() { _mockContext = new Mock<ICheckDriveDbContext>(); _mockMapper = new Mock<IMapper>(); - _service = new DoctorReviewService(_mockContext.Object, _mockMapper.Object); + _mockHubContext = new Mock<IHubContext<ReviewHub, IReviewHub>>(); + _service = new DoctorReviewService(_mockContext.Object, _mockMapper.Object, _mockHubContext.Object); } [Fact] From 6ba1d4f5e7f4c6e11e7e831af2811e3f4a5fb385 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 26 Oct 2024 23:49:56 +0500 Subject: [PATCH 11/40] add car endpoints --- .../Controllers/CarsController.cs | 25 ++++++++++++++++ .../CheckDrive.Application/DTOs/Car/CarDto.cs | 16 ++++++++++ .../Extensions/DependencyInjection.cs | 1 + .../Interfaces/ICarService.cs | 8 +++++ .../Mappings/CarMappings.cs | 13 +++++++++ .../Services/CarService.cs | 29 +++++++++++++++++++ 6 files changed, 92 insertions(+) create mode 100644 CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Services/CarService.cs diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs new file mode 100644 index 00000000..eb1e3231 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs @@ -0,0 +1,25 @@ +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Application.Interfaces; +using Microsoft.AspNetCore.Mvc; + +namespace CheckDrive.Api.Controllers; + +[Route("api/cars")] +[ApiController] +public class CarsController : ControllerBase +{ + private readonly ICarService _carService; + + public CarsController(ICarService carService) + { + _carService = carService; + } + + [HttpGet] + public async Task<ActionResult<List<CarDto>>> GetAvailableCars() + { + var cars = await _carService.GetAvailableCarsAsync(); + + return Ok(cars); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs new file mode 100644 index 00000000..9dfebbbe --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs @@ -0,0 +1,16 @@ +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.Car; + +public sealed record CarDto( + int Id, + string Model, + string Color, + string Number, + int ManufacturedYear, + int Mileage, + int YearlyDistanceLimit, + decimal AverageFuelConsumption, + decimal FuelCapacity, + decimal RemainingFuel, + CarStatus Status); diff --git a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs index 259e5cf8..e3a8e0cb 100644 --- a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs @@ -29,5 +29,6 @@ private static void AddServices(IServiceCollection services) services.AddScoped<ICheckPointService, CheckPointService>(); services.AddScoped<IAccountService, AccountService>(); services.AddScoped<IDriverService, DriverService>(); + services.AddScoped<ICarService, CarService>(); } } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs new file mode 100644 index 00000000..a812f05f --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs @@ -0,0 +1,8 @@ +using CheckDrive.Application.DTOs.Car; + +namespace CheckDrive.Application.Interfaces; + +public interface ICarService +{ + Task<List<CarDto>> GetAvailableCarsAsync(); +} diff --git a/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs b/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs new file mode 100644 index 00000000..7c920a23 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs @@ -0,0 +1,13 @@ +using AutoMapper; +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Domain.Entities; + +namespace CheckDrive.Application.Mappings; + +public sealed class CarMappings : Profile +{ + public CarMappings() + { + CreateMap<Car, CarDto>(); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs new file mode 100644 index 00000000..89f9e6f0 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs @@ -0,0 +1,29 @@ +using AutoMapper; +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Application.Interfaces; +using CheckDrive.Domain.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace CheckDrive.Application.Services; + +internal sealed class CarService : ICarService +{ + private readonly ICheckDriveDbContext _context; + private readonly IMapper _mapper; + + public CarService(ICheckDriveDbContext context, IMapper mapper) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + } + + public async Task<List<CarDto>> GetAvailableCarsAsync() + { + var cars = await _context.Cars + .ToListAsync(); + + var dtos = _mapper.Map<List<CarDto>>(cars); + + return dtos; + } +} From 4d584ae308c0421839da1c3f9583f4ed611d33cf Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 26 Oct 2024 23:50:18 +0500 Subject: [PATCH 12/40] Update Review Type names --- .../DTOs/DispatcherReview/DispatcherReviewDto.cs | 2 +- .../DTOs/DoctorReview/DoctorReviewDto.cs | 2 +- .../DTOs/OperatorReview/OperatorReviewDto.cs | 2 +- CheckDrive.Api/CheckDrive.Domain/Enums/ReviewType.cs | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/DispatcherReview/DispatcherReviewDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/DispatcherReview/DispatcherReviewDto.cs index 34e2c377..9459d8ba 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/DispatcherReview/DispatcherReviewDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/DispatcherReview/DispatcherReviewDto.cs @@ -23,4 +23,4 @@ public sealed record DispatcherReviewDto( Notes: Notes, Date: Date, Status: Status, - Type: ReviewType.Dispatcher); + Type: ReviewType.DispatcherReview); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/DoctorReview/DoctorReviewDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/DoctorReview/DoctorReviewDto.cs index db025f00..5d67089d 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/DoctorReview/DoctorReviewDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/DoctorReview/DoctorReviewDto.cs @@ -21,4 +21,4 @@ public sealed record DoctorReviewDto( Date: Date, Notes: Notes, Status: Status, - Type: ReviewType.Doctor); + Type: ReviewType.DoctorReview); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/OperatorReview/OperatorReviewDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/OperatorReview/OperatorReviewDto.cs index 65a33968..b7643133 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/OperatorReview/OperatorReviewDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/OperatorReview/OperatorReviewDto.cs @@ -25,4 +25,4 @@ public sealed record OperatorReviewDto( Notes: Notes, Date: Date, Status: Status, - Type: ReviewType.Operator); + Type: ReviewType.OperatorReview); diff --git a/CheckDrive.Api/CheckDrive.Domain/Enums/ReviewType.cs b/CheckDrive.Api/CheckDrive.Domain/Enums/ReviewType.cs index a9c8217b..ff045bd3 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Enums/ReviewType.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Enums/ReviewType.cs @@ -2,9 +2,9 @@ public enum ReviewType { - Doctor, + DoctorReview, MechanicHandover, - Operator, + OperatorReview, MechanicAcceptance, - Dispatcher + DispatcherReview } From d410564708b126467b66c58795d8964a97d24e75 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 26 Oct 2024 23:51:23 +0500 Subject: [PATCH 13/40] add endpoint to fetch current check point for driver --- .../Controllers/CheckPointsController.cs | 8 ++ .../Services/CheckPointService.cs | 111 +++++++++++++++++- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs index 97448bd6..ca6f0fad 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs @@ -23,4 +23,12 @@ public async Task<ActionResult<List<CheckPointDto>>> GetCheckPointsAsync([FromQu return Ok(checkPoints); } + + [HttpGet("drivers/{driverId:int}/current")] + public async Task<ActionResult<DriverCheckPointDto>> GetCurrentCheckPointByDriverIdAsync(int driverId) + { + var checkPoint = await _service.GetCurrentCheckPointByDriverIdAsync(driverId); + + return Ok(checkPoint); + } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs index 03ce4d1c..1b5c6e9b 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using CheckDrive.Application.DTOs.Car; using CheckDrive.Application.DTOs.CheckPoint; using CheckDrive.Application.DTOs.Debt; using CheckDrive.Application.DTOs.DispatcherReview; @@ -10,6 +11,7 @@ using CheckDrive.Application.Interfaces; using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; +using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; using CheckDrive.Domain.QueryParameters; using Microsoft.EntityFrameworkCore; @@ -43,6 +45,40 @@ public Task<CheckPointDto> GetCheckPointsByDriverIdAsync(int driverId) throw new NotImplementedException(); } + public async Task<DriverCheckPointDto> GetCurrentCheckPointByDriverIdAsync(int driverId) + { + var checkPoint = await _context.CheckPoints + .AsNoTracking() + .Where(x => x.DoctorReview != null) + .Where(x => x.DoctorReview.DriverId == driverId) + .Where(x => x.StartDate.Date == DateTime.UtcNow.Date) + .Where(x => x.Status == CheckPointStatus.InProgress) + .Include(x => x.DoctorReview) + .ThenInclude(x => x.Doctor) + .Include(x => x.DoctorReview) + .ThenInclude(x => x.Driver) + .Include(x => x.MechanicHandover) + .ThenInclude(x => x.Mechanic) + .Include(x => x.MechanicHandover) + .ThenInclude(x => x.Car) + .Include(x => x.OperatorReview) + .ThenInclude(x => x.Operator) + .Include(x => x.MechanicAcceptance) + .ThenInclude(x => x.Mechanic) + .Include(x => x.DispatcherReview) + .ThenInclude(x => x.Dispatcher) + .FirstOrDefaultAsync(); + + if (checkPoint is null) + { + throw new EntityNotFoundException($"Driver with id: {driverId} does not have current active Check Point."); + } + + var dto = MapToDto(checkPoint); + + return dto; + } + private IQueryable<CheckPoint> GetQuery(CheckPointQueryParameters queryParameters) { var query = _context.CheckPoints @@ -88,9 +124,13 @@ private IQueryable<CheckPoint> GetQuery(CheckPointQueryParameters queryParameter query = query.Where(x => x.Stage == queryParameters.Stage.Value); } - if (queryParameters.DateFilter.HasValue) + if (queryParameters.Date.HasValue) + { + query = FilterByDate(query, queryParameters.Date.Value); + } + else { - query = FilterByDate(query, queryParameters.DateFilter.Value); + query = FilterByDate(query, DateFilter.Today); } return query; @@ -161,4 +201,71 @@ private List<ReviewDtoBase> GetReviews(CheckPoint checkPoint) return debtDto; } + + private DriverCheckPointDto MapToDto(CheckPoint checkPoint) + { + ArgumentNullException.ThrowIfNull(checkPoint); + + var reviews = new List<DriverReviewDto>(); + CarDto? car = null; + + { + var doctorReview = checkPoint.DoctorReview; + var review = new DriverReviewDto( + doctorReview.Notes, + doctorReview.Doctor.FirstName + " " + doctorReview.Doctor.LastName, + doctorReview.Date, + ReviewType.DoctorReview, + doctorReview.Status); + reviews.Add(review); + } + + if (checkPoint.MechanicHandover is not null) + { + var mechanicReview = checkPoint.MechanicHandover; + var review = new DriverReviewDto( + mechanicReview.Notes, + mechanicReview.Mechanic.FirstName + " " + mechanicReview.Mechanic.LastName, + mechanicReview.Date, + ReviewType.MechanicHandover, + mechanicReview.Status); + reviews.Add(review); + car = _mapper.Map<CarDto>(mechanicReview.Car); + } + + if (checkPoint.OperatorReview is not null) + { + var operatorReview = checkPoint.OperatorReview; + var review = new DriverReviewDto( + operatorReview.Notes, + operatorReview.Operator.FirstName + " " + operatorReview.Operator.LastName, + operatorReview.Date, + ReviewType.OperatorReview, + operatorReview.Status); + reviews.Add(review); + } + + if (checkPoint.MechanicAcceptance is not null) + { + var mechanicReview = checkPoint.MechanicAcceptance; + var review = new DriverReviewDto( + mechanicReview.Notes, + mechanicReview.Mechanic.FirstName + " " + mechanicReview.Mechanic.LastName, + mechanicReview.Date, + ReviewType.MechanicAcceptance, + mechanicReview.Status); + reviews.Add(review); + } + + var checkPointDto = new DriverCheckPointDto( + checkPoint.Id, + checkPoint.StartDate, + checkPoint.Stage, + checkPoint.Status, + checkPoint.DoctorReview.Driver.FirstName + " " + checkPoint.DoctorReview.Driver.LastName, + car, + reviews); + + return checkPointDto; + } } From c4d1212af62c43cdbb5e5b7b80d55894fdf8acc7 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 26 Oct 2024 23:51:44 +0500 Subject: [PATCH 14/40] add confirmation method for SignalR --- CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs | 1 + CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs b/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs index 3a787470..9a278ba9 100644 --- a/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs @@ -5,4 +5,5 @@ namespace CheckDrive.Application.Hubs; public interface IReviewHub { Task NotifyNewReviewAsync(ReviewDtoBase review); + Task SendReviewConfirmationAsync(ReviewConfirmationDto reviewConfirmation); } diff --git a/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs index 6e3bf66f..f73def08 100644 --- a/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs @@ -12,6 +12,11 @@ await Clients .NotifyNewReviewAsync(review); } + public async Task SendReviewConfirmationAsync(ReviewConfirmationDto reviewConfirmation) + { + + } + public override Task OnConnectedAsync() { var s = Context.UserIdentifier; From c4e9f3a1218914d782c12b25509280481aa16ed2 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 26 Oct 2024 23:52:15 +0500 Subject: [PATCH 15/40] publish SignalR message on reviews --- .../Services/Review/DoctorReviewService.cs | 2 +- .../Services/Review/MechanicHandoverService.cs | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs index 3421e954..36e9e2fe 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs @@ -35,7 +35,7 @@ public async Task<DoctorReviewDto> CreateAsync(CreateDoctorReviewDto review) var reviewEntity = CreateReviewEntity(review, checkPoint, doctor, driver); _context.DoctorReviews.Add(reviewEntity); - // await _context.SaveChangesAsync(); + await _context.SaveChangesAsync(); var dto = _mapper.Map<DoctorReviewDto>(reviewEntity); diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs index 05902a9f..c26f10b9 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs @@ -1,10 +1,13 @@ using AutoMapper; using CheckDrive.Application.DTOs.MechanicHandover; +using CheckDrive.Application.DTOs.Review; +using CheckDrive.Application.Hubs; using CheckDrive.Application.Interfaces.Review; using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; +using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services.Review; @@ -13,11 +16,13 @@ internal sealed class MechanicHandoverService : IMechanicHandoverService { private readonly ICheckDriveDbContext _context; private readonly IMapper _mapper; + private readonly IHubContext<ReviewHub, IReviewHub> _hubContext; - public MechanicHandoverService(ICheckDriveDbContext context, IMapper mapper) + public MechanicHandoverService(ICheckDriveDbContext context, IMapper mapper, IHubContext<ReviewHub, IReviewHub> hubContext) { _context = context ?? throw new ArgumentNullException(nameof(context)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext)); } public async Task<MechanicHandoverReviewDto> CreateAsync(CreateMechanicHandoverReviewDto review) @@ -29,7 +34,7 @@ public async Task<MechanicHandoverReviewDto> CreateAsync(CreateMechanicHandoverR var car = await GetAndValidateCarAsync(review.CarId); UpdateCheckPoint(checkPoint, review); - UpdateCar(car, review); + // UpdateCar(car, review); var reviewEntity = CreateReviewEntity(review, mechanic, car, checkPoint); @@ -37,6 +42,14 @@ public async Task<MechanicHandoverReviewDto> CreateAsync(CreateMechanicHandoverR await _context.SaveChangesAsync(); var dto = _mapper.Map<MechanicHandoverReviewDto>(createdReview); + var message = $"{mechanic.FirstName} {mechanic.LastName}dan {car.Color} {car.Model}ni boshlangich {review.InitialMileage} masofa bilan qabul qilishni tasdiqlaysizmi?"; + var reviewConfirmation = new ReviewConfirmationDto( + checkPoint.Id, + ReviewType.MechanicHandover, + message); + + await _hubContext.Clients.User(checkPoint.DoctorReview.DriverId.ToString()) + .SendReviewConfirmationAsync(reviewConfirmation); return dto; } From d6cedb908aead3a601242c2661fe3c77b81c100a Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 26 Oct 2024 23:52:32 +0500 Subject: [PATCH 16/40] update contracts --- .../DTOs/CheckPoint/DriverCheckPointDto.cs | 14 ++++++++++++++ .../DTOs/Driver/DriverDto.cs | 6 +++++- .../DTOs/Driver/DriverReviewConfirmationDto.cs | 9 +++++++++ .../DTOs/Review/DriverReviewDto.cs | 10 ++++++++++ .../DTOs/Review/ReviewConfirmationDto.cs | 8 ++++++++ 5 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/CheckPoint/DriverCheckPointDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverReviewConfirmationDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/Review/DriverReviewDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/Review/ReviewConfirmationDto.cs diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/CheckPoint/DriverCheckPointDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/CheckPoint/DriverCheckPointDto.cs new file mode 100644 index 00000000..508cd3b4 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/CheckPoint/DriverCheckPointDto.cs @@ -0,0 +1,14 @@ +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Application.DTOs.Review; +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.CheckPoint; + +public sealed record DriverCheckPointDto( + int Id, + DateTime StartDate, + CheckPointStage Stage, + CheckPointStatus Status, + string DriverName, + CarDto? Car, + List<DriverReviewDto> Reviews); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs index 0c381da2..a96953af 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs @@ -1,3 +1,7 @@ namespace CheckDrive.Application.DTOs.Driver; -public record DriverDto(int Id, string AccountId, string FullName); +public record DriverDto( + int Id, + string AccountId, + string FullName, + int? checkPointId); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverReviewConfirmationDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverReviewConfirmationDto.cs new file mode 100644 index 00000000..c72efd9f --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverReviewConfirmationDto.cs @@ -0,0 +1,9 @@ +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.Driver; + +public sealed record DriverReviewConfirmationDto( + int CheckPointId, + ReviewType ReviewType, + bool IsAcceptedByDriver, + string? Notes); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Review/DriverReviewDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Review/DriverReviewDto.cs new file mode 100644 index 00000000..c121b63e --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Review/DriverReviewDto.cs @@ -0,0 +1,10 @@ +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.Review; + +public sealed record DriverReviewDto( + string? Notes, + string ReviewerName, + DateTime Date, + ReviewType Type, + ReviewStatus Status); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Review/ReviewConfirmationDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Review/ReviewConfirmationDto.cs new file mode 100644 index 00000000..76b444d6 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Review/ReviewConfirmationDto.cs @@ -0,0 +1,8 @@ +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.Review; + +public sealed record ReviewConfirmationDto( + int CheckPointId, + ReviewType ReviewType, + string Message); From bed6f4ef6454594b14aa5850abd69e8d96bfa066 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 26 Oct 2024 23:52:45 +0500 Subject: [PATCH 17/40] set default values for query parameters --- .../QueryParameters/CheckPointQueryParameters.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs b/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs index accbcbac..c0f60d17 100644 --- a/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs +++ b/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs @@ -6,7 +6,7 @@ namespace CheckDrive.Domain.QueryParameters; public class CheckPointQueryParameters : QueryParametersBase { public int? DriverId { get; set; } - public CheckPointStatus? Status { get; set; } public CheckPointStage? Stage { get; set; } - public DateFilter? DateFilter { get; set; } + public CheckPointStatus? Status { get; set; } + public DateFilter? Date { get; set; } = DateFilter.Today; } From 46f83e764d7548ac031b79ecf3467b1c6518ff8d Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 26 Oct 2024 23:53:02 +0500 Subject: [PATCH 18/40] add endpoint to fetch reviews for driver --- .../Controllers/DriversController.cs | 10 +- .../Interfaces/ICheckPointService.cs | 1 + .../Interfaces/IDriverService.cs | 3 +- .../Services/AccountService.cs | 1 + .../Services/DriverService.cs | 143 +++++++++++++++++- 5 files changed, 153 insertions(+), 5 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs index 869bddd6..23049663 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs @@ -19,8 +19,16 @@ public DriversController(IDriverService driverService) [HttpGet] public async Task<ActionResult<List<DriverDto>>> GetAvailableDriversAsync(CheckPointStage? stage) { - var drivers = await _driverService.GetAvailableDriversAsync(stage ?? CheckPointStage.DoctorReview); + var drivers = await _driverService.GetAvailableDriversAsync(stage); return Ok(drivers); } + + [HttpPost("reviews")] + public async Task<IActionResult> CreateReviewConfirmation(DriverReviewConfirmationDto confirmationDto) + { + await _driverService.CreateReviewConfirmation(confirmationDto); + + return NoContent(); + } } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs index bf33dbf6..09f9c53e 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs @@ -7,4 +7,5 @@ public interface ICheckPointService { Task<List<CheckPointDto>> GetCheckPointsAsync(CheckPointQueryParameters queryParameters); Task<CheckPointDto> GetCheckPointsByDriverIdAsync(int driverId); + Task<DriverCheckPointDto> GetCurrentCheckPointByDriverIdAsync(int driverId); } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs index ae50217d..a0a68207 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs @@ -5,5 +5,6 @@ namespace CheckDrive.Application.Interfaces; public interface IDriverService { - Task<List<DriverDto>> GetAvailableDriversAsync(CheckPointStage stage); + Task<List<DriverDto>> GetAvailableDriversAsync(CheckPointStage? stage); + Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmation); } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs index 2b379ac1..f20b7f29 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs @@ -27,6 +27,7 @@ public AccountService(ICheckDriveDbContext context, IMapper mapper, UserManager< public async Task<List<AccountDto>> GetAsync(EmployeePosition? position) { var query = _context.Employees + .Include(x => x.Account) .AsNoTracking() .AsQueryable(); diff --git a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs index 3ab9be15..71e5f0bb 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs @@ -1,6 +1,8 @@ using CheckDrive.Application.DTOs.Driver; using CheckDrive.Application.Interfaces; +using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; +using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; using Microsoft.EntityFrameworkCore; @@ -15,17 +17,152 @@ public DriverService(ICheckDriveDbContext context) _context = context ?? throw new ArgumentNullException(nameof(context)); } - public async Task<List<DriverDto>> GetAvailableDriversAsync(CheckPointStage stage) + public async Task<List<DriverDto>> GetAvailableDriversAsync(CheckPointStage? stage) { var query = _context.Drivers .AsNoTracking() .Include(x => x.Account) .AsQueryable(); + query = FilterByCheckPointStage(query, stage); + var drivers = await query - .Select(x => new DriverDto(x.Id, x.AccountId, x.FirstName + " " + x.LastName)) + .Include(x => x.Reviews) + .Select(x => new + { + x.Id, + x.AccountId, + FullName = x.FirstName + " " + x.LastName, + x.Reviews + }) .ToListAsync(); - return drivers; + var driversWithCheckPoints = drivers.Select(x => + { + int? checkPointId = x.Reviews.FirstOrDefault(x => x.Date.Date == DateTime.UtcNow.Date)?.CheckPointId; + return new DriverDto(x.Id, x.AccountId, x.FullName, checkPointId); + }).ToList(); + + return driversWithCheckPoints; + } + + public async Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmation) + { + ArgumentNullException.ThrowIfNull(confirmation); + + var checkPoint = await GetAndValidateCheckPointAsync(confirmation.CheckPointId); + + if (!confirmation.IsAcceptedByDriver) + { + checkPoint.Status = CheckPointStatus.InterruptedByDriverRejection; + await _context.SaveChangesAsync(); + return; + } + + if (confirmation.ReviewType == ReviewType.MechanicHandover) + { + await AcceptMechanicHandoverAsync(checkPoint); + } + + if (confirmation.ReviewType == ReviewType.OperatorReview) + { + await AcceptOperatorReviewAsync(checkPoint); + } + + if (confirmation.ReviewType == ReviewType.MechanicAcceptance) + { + await AcceptMechanicAcceptanceAsync(checkPoint); + } + + await _context.SaveChangesAsync(); + } + + private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) + { + var checkPoint = await _context.CheckPoints + .Include(x => x.MechanicHandover) + .Include(x => x.MechanicAcceptance) + .Include(x => x.OperatorReview) + .FirstOrDefaultAsync(x => x.Id == checkPointId); + + if (checkPoint is null) + { + throw new EntityNotFoundException($"Check Point with id: {checkPointId} is not found."); + } + + return checkPoint; + } + + private async Task AcceptMechanicHandoverAsync(CheckPoint checkPoint) + { + if (checkPoint.MechanicHandover is null) + { + throw new InvalidOperationException($"Cannot update car for Check Point without Mechanic Handover Review."); + } + + var car = await _context.Cars.FirstOrDefaultAsync(c => c.Id == checkPoint.MechanicHandover.CarId); + + if (car is null) + { + throw new EntityNotFoundException($"Car with id: {checkPoint.MechanicHandover.CarId}"); + } + + car.Mileage = checkPoint.MechanicHandover.InitialMileage; + checkPoint.MechanicHandover.Status = ReviewStatus.Approved; + checkPoint.Stage = CheckPointStage.OperatorReview; + } + + private async Task AcceptOperatorReviewAsync(CheckPoint checkPoint) + { + if (checkPoint.OperatorReview is null || checkPoint.MechanicHandover is null) + { + throw new InvalidOperationException($"Cannot update car for Check Point without Operator Review."); + } + + var car = await GetAndValidateCarAsync(checkPoint.MechanicHandover.CarId); + car.RemainingFuel += checkPoint.OperatorReview.OilRefillAmount; + + checkPoint.Stage = CheckPointStage.MechanicAcceptance; + checkPoint.OperatorReview.Status = ReviewStatus.Approved; + } + + private async Task AcceptMechanicAcceptanceAsync(CheckPoint checkPoint) + { + if (checkPoint.MechanicHandover is null || checkPoint.MechanicAcceptance is null) + { + throw new InvalidOperationException("Cannot perform Mechanic Acceptance without Mechanic Handover Review."); + } + + var car = await GetAndValidateCarAsync(checkPoint.MechanicHandover.CarId); + car.Mileage = checkPoint.MechanicAcceptance.FinalMileage; + car.RemainingFuel = checkPoint.MechanicAcceptance.RemainingFuelAmount; + + checkPoint.Stage = CheckPointStage.DispatcherReview; + checkPoint.MechanicAcceptance.Status = ReviewStatus.Approved; + } + + private async Task<Car> GetAndValidateCarAsync(int carId) + { + var car = await _context.Cars.FirstOrDefaultAsync(x => x.Id == carId); + + if (car is null) + { + throw new EntityNotFoundException($"Car with id: {carId} is not found."); + } + + return car; + } + + private static IQueryable<Driver> FilterByCheckPointStage(IQueryable<Driver> query, CheckPointStage? stage) + { + switch (stage) + { + case null: + return query.Where(x => !x.Reviews.Any(x => x.Date.Date == DateTime.UtcNow.Date)); + case CheckPointStage.DoctorReview: + return query.Where(x => x.Reviews.Any(r => r.Date.Date == DateTime.UtcNow.Date && r.Status == ReviewStatus.Approved)); + default: + return query; + } } } From 5e6a6fdea84ca71273b11409a042e78f5f4900a3 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Tue, 29 Oct 2024 00:40:34 +0500 Subject: [PATCH 19/40] add default oil marks to db --- .../Configurations/OilMarkConfiguration.cs | 31 + ...027164617_Add_Default_OilMarks.Designer.cs | 1063 +++++++++++++++++ .../20241027164617_Add_Default_OilMarks.cs | 57 + .../CheckDriveDbContextModelSnapshot.cs | 41 +- 4 files changed, 1185 insertions(+), 7 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241027164617_Add_Default_OilMarks.Designer.cs create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241027164617_Add_Default_OilMarks.cs diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/OilMarkConfiguration.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/OilMarkConfiguration.cs index 66ab6a90..55512c35 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/OilMarkConfiguration.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/OilMarkConfiguration.cs @@ -30,5 +30,36 @@ public void Configure(EntityTypeBuilder<OilMark> builder) .IsRequired(); #endregion + + #region Default Data + + builder.HasData( + new OilMark + { + Id = 1, + Name = "80" + }, + new OilMark + { + Id = 2, + Name = "85" + }, + new OilMark + { + Id = 3, + Name = "90" + }, + new OilMark + { + Id = 4, + Name = "95" + }, + new OilMark + { + Id = 5, + Name = "100" + }); + + #endregion } } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241027164617_Add_Default_OilMarks.Designer.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241027164617_Add_Default_OilMarks.Designer.cs new file mode 100644 index 00000000..ec55c7ca --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241027164617_Add_Default_OilMarks.Designer.cs @@ -0,0 +1,1063 @@ +// <auto-generated /> +using System; +using CheckDrive.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(CheckDriveDbContext))] + [Migration("20241027164617_Add_Default_OilMarks")] + partial class Add_Default_OilMarks + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<decimal>("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<decimal>("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManufacturedYear") + .HasColumnType("int"); + + b.Property<int>("Mileage") + .HasColumnType("int"); + + b.Property<string>("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<string>("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property<decimal>("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<int>("YearlyDistanceLimit") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<int>("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<DateTime>("StartDate") + .HasColumnType("datetime2"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<decimal>("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int?>("ManagerReviewId") + .HasColumnType("int"); + + b.Property<decimal>("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.ToTable("Debt", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DispatcherId") + .HasColumnType("int"); + + b.Property<decimal?>("DistanceTravelledAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DispatcherId"); + + b.ToTable("DispatcherReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DoctorId") + .HasColumnType("int"); + + b.Property<int>("DriverId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DoctorId"); + + b.HasIndex("DriverId"); + + b.ToTable("DoctorReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<DateTime>("Birthdate") + .HasColumnType("datetime2"); + + b.Property<string>("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property<int>("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator<int>("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal?>("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int?>("DebtId") + .HasColumnType("int"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManagerId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("ManagerId") + .IsUnique(); + + b.ToTable("ManagerReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("FinalMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<decimal>("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicAcceptance", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CarId") + .HasColumnType("int"); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("InitialMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicHandover", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("OilMark", (string)null); + + b.HasData( + new + { + Id = 1, + Name = "80" + }, + new + { + Id = 2, + Name = "85" + }, + new + { + Id = 3, + Name = "90" + }, + new + { + Id = 4, + Name = "95" + }, + new + { + Id = 5, + Name = "100" + }); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal>("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("OilMarkId") + .HasColumnType("int"); + + b.Property<decimal>("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("OperatorId") + .HasColumnType("int"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("OilMarkId"); + + b.HasIndex("OperatorId"); + + b.ToTable("OperatorReview", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "201cf469-52f4-4d2b-be9e-9709379e0c94", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }, + new + { + Id = "7d0cf0b4-9dfc-446c-8017-fd5f5c487f0f", + Name = "Driver", + NormalizedName = "DRIVER" + }, + new + { + Id = "29e8e9e2-8ae6-4e93-bddf-6dc1f3c8afdb", + Name = "Doctor", + NormalizedName = "DOCTOR" + }, + new + { + Id = "b2e38b16-742e-4b32-b9d1-f83a7e19e343", + Name = "Dispatcher", + NormalizedName = "DISPATCHER" + }, + new + { + Id = "474663af-e7f3-4551-906f-b1bc3af37f58", + Name = "Manager", + NormalizedName = "MANAGER" + }, + new + { + Id = "dd228db7-3ee4-4a01-b84f-1e07b54c1aa4", + Name = "Mechanic", + NormalizedName = "MECHANIC" + }, + new + { + Id = "6e4e5e62-47e9-48fd-91ca-fa2dcef1b604", + Name = "Operator", + NormalizedName = "OPERATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<int>("AccessFailedCount") + .HasColumnType("int"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<bool>("EmailConfirmed") + .HasColumnType("bit"); + + b.Property<bool>("LockoutEnabled") + .HasColumnType("bit"); + + b.Property<DateTimeOffset?>("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property<string>("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property<string>("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property<string>("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Name") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserToken", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(5); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(2); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(1); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(6); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(3); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(4); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("Debt") + .HasForeignKey("CheckDrive.Domain.Entities.Debt", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DispatcherReview") + .HasForeignKey("CheckDrive.Domain.Entities.DispatcherReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Dispatcher", "Dispatcher") + .WithMany("Reviews") + .HasForeignKey("DispatcherId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Dispatcher"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DoctorReview") + .HasForeignKey("CheckDrive.Domain.Entities.DoctorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Doctor", "Doctor") + .WithMany("Reviews") + .HasForeignKey("DoctorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Driver", "Driver") + .WithMany("Reviews") + .HasForeignKey("DriverId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Doctor"); + + b.Navigation("Driver"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "Account") + .WithOne() + .HasForeignKey("CheckDrive.Domain.Entities.Employee", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Debt", "Debt") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Manager", "Manager") + .WithMany("Reviews") + .HasForeignKey("ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Debt"); + + b.Navigation("Manager"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicAcceptance") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicAcceptance", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Acceptances") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.HasOne("CheckDrive.Domain.Entities.Car", "Car") + .WithMany("Handovers") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicHandover") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicHandover", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Handovers") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Car"); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("OperatorReview") + .HasForeignKey("CheckDrive.Domain.Entities.OperatorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.OilMark", "OilMark") + .WithMany("Reviews") + .HasForeignKey("OilMarkId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Operator", "Operator") + .WithMany("Reviews") + .HasForeignKey("OperatorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("OilMark"); + + b.Navigation("Operator"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Navigation("Debt"); + + b.Navigation("DispatcherReview"); + + b.Navigation("DoctorReview") + .IsRequired(); + + b.Navigation("ManagerReview"); + + b.Navigation("MechanicAcceptance"); + + b.Navigation("MechanicHandover"); + + b.Navigation("OperatorReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Navigation("ManagerReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.Navigation("Acceptances"); + + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.Navigation("Reviews"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241027164617_Add_Default_OilMarks.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241027164617_Add_Default_OilMarks.cs new file mode 100644 index 00000000..8ed53838 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241027164617_Add_Default_OilMarks.cs @@ -0,0 +1,57 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + /// <inheritdoc /> + public partial class Add_Default_OilMarks : Migration + { + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.InsertData( + table: "OilMark", + columns: new[] { "Id", "Name" }, + values: new object[,] + { + { 1, "80" }, + { 2, "85" }, + { 3, "90" }, + { 4, "95" }, + { 5, "100" } + }); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DeleteData( + table: "OilMark", + keyColumn: "Id", + keyValue: 1); + + migrationBuilder.DeleteData( + table: "OilMark", + keyColumn: "Id", + keyValue: 2); + + migrationBuilder.DeleteData( + table: "OilMark", + keyColumn: "Id", + keyValue: 3); + + migrationBuilder.DeleteData( + table: "OilMark", + keyColumn: "Id", + keyValue: 4); + + migrationBuilder.DeleteData( + table: "OilMark", + keyColumn: "Id", + keyValue: 5); + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs index dd4e25ab..b61360fa 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs @@ -412,6 +412,33 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); b.ToTable("OilMark", (string)null); + + b.HasData( + new + { + Id = 1, + Name = "80" + }, + new + { + Id = 2, + Name = "85" + }, + new + { + Id = 3, + Name = "90" + }, + new + { + Id = 4, + Name = "95" + }, + new + { + Id = 5, + Name = "100" + }); }); modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => @@ -489,43 +516,43 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "d6c0f8c6-b894-44ff-80f9-eb65961d8002", + Id = "201cf469-52f4-4d2b-be9e-9709379e0c94", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "5bd07b96-507a-4b1a-b9ff-b421cfe1d205", + Id = "7d0cf0b4-9dfc-446c-8017-fd5f5c487f0f", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "8b08e145-6325-4046-b55c-77b9906966b5", + Id = "29e8e9e2-8ae6-4e93-bddf-6dc1f3c8afdb", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "ed4099e0-601c-414d-b763-f2151a29040d", + Id = "b2e38b16-742e-4b32-b9d1-f83a7e19e343", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "ee9613ef-226d-4fba-9ab3-9a07d902018b", + Id = "474663af-e7f3-4551-906f-b1bc3af37f58", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "7fbd87ba-5311-4855-b18f-54b7e711eb82", + Id = "dd228db7-3ee4-4a01-b84f-1e07b54c1aa4", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "c9734b82-c84a-43b2-b453-c4ff6eb8c1cf", + Id = "6e4e5e62-47e9-48fd-91ca-fa2dcef1b604", Name = "Operator", NormalizedName = "OPERATOR" }); From 631805082e304c6e9774ed3e8ad15e933c2c3558 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Tue, 29 Oct 2024 00:40:56 +0500 Subject: [PATCH 20/40] add GET endpoint for oil marks --- .../Controllers/OilMarksController.cs | 25 +++++++++++++++++++ .../DTOs/OilMark/OilMarkDto.cs | 4 +++ .../Extensions/DependencyInjection.cs | 1 + .../Interfaces/IOilMarkService.cs | 8 ++++++ .../Services/OilMarkService.cs | 25 +++++++++++++++++++ 5 files changed, 63 insertions(+) create mode 100644 CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs new file mode 100644 index 00000000..ff6a43ec --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs @@ -0,0 +1,25 @@ +using CheckDrive.Application.DTOs.OilMark; +using CheckDrive.Application.Interfaces; +using Microsoft.AspNetCore.Mvc; + +namespace CheckDrive.Api.Controllers; + +[Route("api/oilMarks")] +[ApiController] +public class OilMarksController : ControllerBase +{ + private readonly IOilMarkService _oilMarkService; + + public OilMarksController(IOilMarkService oilMarkService) + { + _oilMarkService = oilMarkService ?? throw new ArgumentNullException(nameof(oilMarkService)); + } + + [HttpGet] + public async Task<ActionResult<List<OilMarkDto>>> GetAsync() + { + var oilMarks = await _oilMarkService.GetAllAsync(); + + return Ok(oilMarks); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs new file mode 100644 index 00000000..90202b01 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs @@ -0,0 +1,4 @@ +namespace CheckDrive.Application.DTOs.OilMark; +public sealed record OilMarkDto( + int Id, + string Name); diff --git a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs index e3a8e0cb..72f4f158 100644 --- a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs @@ -30,5 +30,6 @@ private static void AddServices(IServiceCollection services) services.AddScoped<IAccountService, AccountService>(); services.AddScoped<IDriverService, DriverService>(); services.AddScoped<ICarService, CarService>(); + services.AddScoped<IOilMarkService, OilMarkService>(); } } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs new file mode 100644 index 00000000..81b97b69 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs @@ -0,0 +1,8 @@ +using CheckDrive.Application.DTOs.OilMark; + +namespace CheckDrive.Application.Interfaces; + +public interface IOilMarkService +{ + Task<List<OilMarkDto>> GetAllAsync(); +} diff --git a/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs b/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs new file mode 100644 index 00000000..03d0ae42 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs @@ -0,0 +1,25 @@ +using CheckDrive.Application.DTOs.OilMark; +using CheckDrive.Application.Interfaces; +using CheckDrive.Domain.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace CheckDrive.Application.Services; + +internal sealed class OilMarkService : IOilMarkService +{ + private readonly ICheckDriveDbContext _context; + + public OilMarkService(ICheckDriveDbContext context) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + } + + public Task<List<OilMarkDto>> GetAllAsync() + { + var oilMarks = _context.OilMarks + .Select(x => new OilMarkDto(x.Id, x.Name)) + .ToListAsync(); + + return oilMarks; + } +} From 793e705eeaa63e81f9716ba20aa176fc57e74bd4 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Thu, 31 Oct 2024 01:05:14 +0500 Subject: [PATCH 21/40] add monthly limit property to Car --- .../CheckDrive.Application/DTOs/Car/CarDto.cs | 1 + .../CheckDrive.Domain/Entities/Car.cs | 1 + .../Configurations/CarConfiguration.cs | 5 +- ...30180522_Add_CarMonthlyMileage.Designer.cs | 1066 +++++++++++++++++ .../20241030180522_Add_CarMonthlyMileage.cs | 31 + .../CheckDriveDbContextModelSnapshot.cs | 17 +- .../FakeDataGenerator.cs | 1 + 7 files changed, 1114 insertions(+), 8 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241030180522_Add_CarMonthlyMileage.Designer.cs create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241030180522_Add_CarMonthlyMileage.cs diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs index 9dfebbbe..f9183bb2 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs @@ -9,6 +9,7 @@ public sealed record CarDto( string Number, int ManufacturedYear, int Mileage, + int CurrentMonthMileage, int YearlyDistanceLimit, decimal AverageFuelConsumption, decimal FuelCapacity, diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs index 2b5d54dd..bf597ae9 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs @@ -10,6 +10,7 @@ public class Car : EntityBase public string Number { get; set; } public int ManufacturedYear { get; set; } public int Mileage { get; set; } + public int CurrentMonthMileage { get; set; } public int YearlyDistanceLimit { get; set; } public decimal AverageFuelConsumption { get; set; } public decimal FuelCapacity { get; set; } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs index 4736ccb1..f0467dbb 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs @@ -39,7 +39,10 @@ public void Configure(EntityTypeBuilder<Car> builder) .IsRequired(); builder.Property(c => c.Mileage) - .IsRequired(); + .IsRequired(); + + builder.Property(c => c.CurrentMonthMileage) + .IsRequired(); builder.Property(c => c.YearlyDistanceLimit) .IsRequired(); diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241030180522_Add_CarMonthlyMileage.Designer.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241030180522_Add_CarMonthlyMileage.Designer.cs new file mode 100644 index 00000000..6cf0f381 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241030180522_Add_CarMonthlyMileage.Designer.cs @@ -0,0 +1,1066 @@ +// <auto-generated /> +using System; +using CheckDrive.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(CheckDriveDbContext))] + [Migration("20241030180522_Add_CarMonthlyMileage")] + partial class Add_CarMonthlyMileage + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<decimal>("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<int>("CurrentMonthMileage") + .HasColumnType("int"); + + b.Property<decimal>("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManufacturedYear") + .HasColumnType("int"); + + b.Property<int>("Mileage") + .HasColumnType("int"); + + b.Property<string>("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<string>("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property<decimal>("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<int>("YearlyDistanceLimit") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<int>("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<DateTime>("StartDate") + .HasColumnType("datetime2"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<decimal>("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int?>("ManagerReviewId") + .HasColumnType("int"); + + b.Property<decimal>("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.ToTable("Debt", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DispatcherId") + .HasColumnType("int"); + + b.Property<decimal?>("DistanceTravelledAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DispatcherId"); + + b.ToTable("DispatcherReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DoctorId") + .HasColumnType("int"); + + b.Property<int>("DriverId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DoctorId"); + + b.HasIndex("DriverId"); + + b.ToTable("DoctorReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<DateTime>("Birthdate") + .HasColumnType("datetime2"); + + b.Property<string>("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property<int>("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator<int>("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal?>("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int?>("DebtId") + .HasColumnType("int"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManagerId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("ManagerId") + .IsUnique(); + + b.ToTable("ManagerReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("FinalMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<decimal>("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicAcceptance", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CarId") + .HasColumnType("int"); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("InitialMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicHandover", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("OilMark", (string)null); + + b.HasData( + new + { + Id = 1, + Name = "80" + }, + new + { + Id = 2, + Name = "85" + }, + new + { + Id = 3, + Name = "90" + }, + new + { + Id = 4, + Name = "95" + }, + new + { + Id = 5, + Name = "100" + }); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal>("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("OilMarkId") + .HasColumnType("int"); + + b.Property<decimal>("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("OperatorId") + .HasColumnType("int"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("OilMarkId"); + + b.HasIndex("OperatorId"); + + b.ToTable("OperatorReview", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "3ad70054-4ee0-416d-929a-6d800fa98941", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }, + new + { + Id = "a6486ce6-0af2-488d-a609-76ac62ba6203", + Name = "Driver", + NormalizedName = "DRIVER" + }, + new + { + Id = "0bbd5156-7c75-4b84-a7d9-5e21910bf14f", + Name = "Doctor", + NormalizedName = "DOCTOR" + }, + new + { + Id = "765d20d4-f255-4553-bb5d-f9f87c4360f5", + Name = "Dispatcher", + NormalizedName = "DISPATCHER" + }, + new + { + Id = "5a9d0f60-922f-405f-8abd-14c9dee446a1", + Name = "Manager", + NormalizedName = "MANAGER" + }, + new + { + Id = "ccc36987-fb1e-4a20-9d0d-acdcc0204baa", + Name = "Mechanic", + NormalizedName = "MECHANIC" + }, + new + { + Id = "b5ea687f-a694-4901-95f0-310000949351", + Name = "Operator", + NormalizedName = "OPERATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<int>("AccessFailedCount") + .HasColumnType("int"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<bool>("EmailConfirmed") + .HasColumnType("bit"); + + b.Property<bool>("LockoutEnabled") + .HasColumnType("bit"); + + b.Property<DateTimeOffset?>("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property<string>("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property<string>("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property<string>("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Name") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserToken", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(5); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(2); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(1); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(6); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(3); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(4); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("Debt") + .HasForeignKey("CheckDrive.Domain.Entities.Debt", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DispatcherReview") + .HasForeignKey("CheckDrive.Domain.Entities.DispatcherReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Dispatcher", "Dispatcher") + .WithMany("Reviews") + .HasForeignKey("DispatcherId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Dispatcher"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DoctorReview") + .HasForeignKey("CheckDrive.Domain.Entities.DoctorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Doctor", "Doctor") + .WithMany("Reviews") + .HasForeignKey("DoctorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Driver", "Driver") + .WithMany("Reviews") + .HasForeignKey("DriverId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Doctor"); + + b.Navigation("Driver"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "Account") + .WithOne() + .HasForeignKey("CheckDrive.Domain.Entities.Employee", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Debt", "Debt") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Manager", "Manager") + .WithMany("Reviews") + .HasForeignKey("ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Debt"); + + b.Navigation("Manager"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicAcceptance") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicAcceptance", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Acceptances") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.HasOne("CheckDrive.Domain.Entities.Car", "Car") + .WithMany("Handovers") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicHandover") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicHandover", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Handovers") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Car"); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("OperatorReview") + .HasForeignKey("CheckDrive.Domain.Entities.OperatorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.OilMark", "OilMark") + .WithMany("Reviews") + .HasForeignKey("OilMarkId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Operator", "Operator") + .WithMany("Reviews") + .HasForeignKey("OperatorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("OilMark"); + + b.Navigation("Operator"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Navigation("Debt"); + + b.Navigation("DispatcherReview"); + + b.Navigation("DoctorReview") + .IsRequired(); + + b.Navigation("ManagerReview"); + + b.Navigation("MechanicAcceptance"); + + b.Navigation("MechanicHandover"); + + b.Navigation("OperatorReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Navigation("ManagerReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.Navigation("Acceptances"); + + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.Navigation("Reviews"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241030180522_Add_CarMonthlyMileage.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241030180522_Add_CarMonthlyMileage.cs new file mode 100644 index 00000000..ec38a7ba --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241030180522_Add_CarMonthlyMileage.cs @@ -0,0 +1,31 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + /// <inheritdoc /> + public partial class Add_CarMonthlyMileage : Migration + { + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn<int>( + name: "CurrentMonthMileage", + table: "Car", + type: "int", + nullable: false, + defaultValue: 0); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CurrentMonthMileage", + table: "Car"); + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs index b61360fa..6a43f3ba 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs @@ -39,6 +39,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(500) .HasColumnType("nvarchar(500)"); + b.Property<int>("CurrentMonthMileage") + .HasColumnType("int"); + b.Property<decimal>("FuelCapacity") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -516,43 +519,43 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "201cf469-52f4-4d2b-be9e-9709379e0c94", + Id = "3ad70054-4ee0-416d-929a-6d800fa98941", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "7d0cf0b4-9dfc-446c-8017-fd5f5c487f0f", + Id = "a6486ce6-0af2-488d-a609-76ac62ba6203", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "29e8e9e2-8ae6-4e93-bddf-6dc1f3c8afdb", + Id = "0bbd5156-7c75-4b84-a7d9-5e21910bf14f", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "b2e38b16-742e-4b32-b9d1-f83a7e19e343", + Id = "765d20d4-f255-4553-bb5d-f9f87c4360f5", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "474663af-e7f3-4551-906f-b1bc3af37f58", + Id = "5a9d0f60-922f-405f-8abd-14c9dee446a1", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "dd228db7-3ee4-4a01-b84f-1e07b54c1aa4", + Id = "ccc36987-fb1e-4a20-9d0d-acdcc0204baa", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "6e4e5e62-47e9-48fd-91ca-fa2dcef1b604", + Id = "b5ea687f-a694-4901-95f0-310000949351", Name = "Operator", NormalizedName = "OPERATOR" }); diff --git a/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs b/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs index 41d3fd87..05babcc2 100644 --- a/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs +++ b/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs @@ -31,6 +31,7 @@ public static class FakeDataGenerator .RuleFor(x => x.Number, f => f.Vehicle.Vin().Substring(0, 10)) .RuleFor(x => x.ManufacturedYear, f => f.Date.Between(DateTime.Now.AddYears(-20), DateTime.Now.AddYears(-2)).Year) .RuleFor(x => x.Mileage, f => f.Random.Number(0, 100_000)) + .RuleFor(x => x.CurrentMonthMileage, f => f.Random.Number(0, 1_000)) .RuleFor(x => x.YearlyDistanceLimit, f => f.Random.Number(1_000, 5_000)) .RuleFor(x => x.FuelCapacity, f => f.Random.Number(50, 70)) .RuleFor(x => x.AverageFuelConsumption, f => f.Random.Number(10, 20)) From a7a9d5291b4a6e1c20206d95e657980fa8730227 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Thu, 31 Oct 2024 01:05:38 +0500 Subject: [PATCH 22/40] add background service for resetting monthly limit --- .../CarMonthlyMileageResetService.cs | 42 +++++++++++++++++++ .../Extensions/DependencyInjection.cs | 3 ++ 2 files changed, 45 insertions(+) create mode 100644 CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs diff --git a/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs b/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs new file mode 100644 index 00000000..1249a822 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs @@ -0,0 +1,42 @@ +using CheckDrive.Domain.Interfaces; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace CheckDrive.Application.BackgroundJobs; + +internal sealed class CarMonthlyMileageResetService : BackgroundService +{ + private readonly IServiceProvider _serviceProvider; + + public CarMonthlyMileageResetService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + DateTime now = DateTime.UtcNow; + + // Check if it's the first day of the month at midnight UTC + if (now.Day == 1 && now.Hour == 0) + { + await ResetCarMonthlyMileage(stoppingToken); + } + + await Task.Delay(TimeSpan.FromHours(1), stoppingToken); + } + } + + private async Task ResetCarMonthlyMileage(CancellationToken stoppingToken) + { + using var scope = _serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService<ICheckDriveDbContext>(); + + await context.Cars.ExecuteUpdateAsync( + x => x.SetProperty(x => x.CurrentMonthMileage, 0), + stoppingToken); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs index 72f4f158..1d24a8f7 100644 --- a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.DependencyInjection; using CheckDrive.Application.Interfaces.Auth; using CheckDrive.Application.Services.Auth; +using CheckDrive.Application.BackgroundJobs; namespace CheckDrive.Application.Extensions; @@ -31,5 +32,7 @@ private static void AddServices(IServiceCollection services) services.AddScoped<IDriverService, DriverService>(); services.AddScoped<ICarService, CarService>(); services.AddScoped<IOilMarkService, OilMarkService>(); + + services.AddHostedService<CarMonthlyMileageResetService>(); } } From c436e07cefb2fe4f7f6f95a13a42f656694d51ec Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Thu, 31 Oct 2024 01:06:03 +0500 Subject: [PATCH 23/40] separate each review method for SignalR --- .../CheckDrive.Application/Hubs/IReviewHub.cs | 11 ++++++++--- .../CheckDrive.Application/Hubs/ReviewHub.cs | 7 +------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs b/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs index 9a278ba9..8c3bd3a2 100644 --- a/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs @@ -1,9 +1,14 @@ -using CheckDrive.Application.DTOs.Review; +using CheckDrive.Application.DTOs.MechanicAcceptance; +using CheckDrive.Application.DTOs.MechanicHandover; +using CheckDrive.Application.DTOs.OperatorReview; +using CheckDrive.Application.DTOs.Review; namespace CheckDrive.Application.Hubs; public interface IReviewHub { - Task NotifyNewReviewAsync(ReviewDtoBase review); - Task SendReviewConfirmationAsync(ReviewConfirmationDto reviewConfirmation); + Task NotifyDoctorReview(ReviewDtoBase review); + Task MechanicHandoverConfirmation(MechanicHandoverReviewDto review); + Task OperatorReviewConfirmation(OperatorReviewDto review); + Task MechanicAcceptanceConfirmation(MechanicAcceptanceReviewDto review); } diff --git a/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs index f73def08..74eccd1c 100644 --- a/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs @@ -9,12 +9,7 @@ public async Task NotifyNewReviewAsync(ReviewDtoBase review) { await Clients .User(review.DriverId.ToString()) - .NotifyNewReviewAsync(review); - } - - public async Task SendReviewConfirmationAsync(ReviewConfirmationDto reviewConfirmation) - { - + .NotifyDoctorReview(review); } public override Task OnConnectedAsync() From 2c836bf28c7dbe8d2005b4c627befd8507934c80 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Thu, 31 Oct 2024 01:56:18 +0500 Subject: [PATCH 24/40] improve code quality and consistency --- .../Controllers/CheckPointsController.cs | 2 +- .../Controllers/DriversController.cs | 5 +- CheckDrive.Api/CheckDrive.Api/Program.cs | 2 +- .../DTOs/Driver/DriverDto.cs | 3 +- .../MechanicHandoverReviewDto.cs | 6 +- .../Interfaces/ICheckPointService.cs | 3 +- .../Interfaces/IDriverService.cs | 3 +- .../Services/Auth/AuthService.cs | 3 +- .../Services/CheckPointService.cs | 165 ++---------------- .../Services/DriverService.cs | 138 ++++++++------- .../Services/Review/DoctorReviewService.cs | 19 +- .../Review/MechanicAcceptanceService.cs | 112 +++--------- .../Review/MechanicHandoverService.cs | 68 +++----- .../Services/Review/OperatorReviewService.cs | 72 ++++---- .../CheckPointQueryParameters.cs | 4 +- 15 files changed, 196 insertions(+), 409 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs index ca6f0fad..d7bcb05b 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs @@ -25,7 +25,7 @@ public async Task<ActionResult<List<CheckPointDto>>> GetCheckPointsAsync([FromQu } [HttpGet("drivers/{driverId:int}/current")] - public async Task<ActionResult<DriverCheckPointDto>> GetCurrentCheckPointByDriverIdAsync(int driverId) + public async Task<ActionResult<CheckPointDto>> GetCurrentCheckPointByDriverIdAsync(int driverId) { var checkPoint = await _service.GetCurrentCheckPointByDriverIdAsync(driverId); diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs index 23049663..ff3a3460 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs @@ -1,6 +1,5 @@ using CheckDrive.Application.DTOs.Driver; using CheckDrive.Application.Interfaces; -using CheckDrive.Domain.Enums; using Microsoft.AspNetCore.Mvc; namespace CheckDrive.Api.Controllers; @@ -17,9 +16,9 @@ public DriversController(IDriverService driverService) } [HttpGet] - public async Task<ActionResult<List<DriverDto>>> GetAvailableDriversAsync(CheckPointStage? stage) + public async Task<ActionResult<List<DriverDto>>> GetAvailableDriversAsync() { - var drivers = await _driverService.GetAvailableDriversAsync(stage); + var drivers = await _driverService.GetAvailableDriversAsync(); return Ok(drivers); } diff --git a/CheckDrive.Api/CheckDrive.Api/Program.cs b/CheckDrive.Api/CheckDrive.Api/Program.cs index 139f3049..e1e21c2a 100644 --- a/CheckDrive.Api/CheckDrive.Api/Program.cs +++ b/CheckDrive.Api/CheckDrive.Api/Program.cs @@ -5,7 +5,7 @@ using Serilog; Log.Logger = new LoggerConfiguration() - .MinimumLevel.Verbose() + .MinimumLevel.Information() .Enrich.FromLogContext() .WriteTo.Console(new CustomJsonFormatter()) .WriteTo.File(new CustomJsonFormatter(), "logs/logs.txt", rollingInterval: RollingInterval.Day) diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs index a96953af..7027e466 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs @@ -3,5 +3,4 @@ public record DriverDto( int Id, string AccountId, - string FullName, - int? checkPointId); + string FullName); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/MechanicHandover/MechanicHandoverReviewDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/MechanicHandover/MechanicHandoverReviewDto.cs index 8f89df4b..c2d362f5 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/MechanicHandover/MechanicHandoverReviewDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/MechanicHandover/MechanicHandoverReviewDto.cs @@ -1,4 +1,5 @@ -using CheckDrive.Application.DTOs.Review; +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Application.DTOs.Review; using CheckDrive.Domain.Enums; namespace CheckDrive.Application.DTOs.MechanicHandover; @@ -12,7 +13,8 @@ public sealed record MechanicHandoverReviewDto( string? Notes, DateTime Date, ReviewStatus Status, - int InitialMileage) + int InitialMileage, + CarDto Car) : ReviewDtoBase( CheckPointId: CheckPointId, ReviewerId: ReviewerId, diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs index 09f9c53e..a8980400 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs @@ -6,6 +6,5 @@ namespace CheckDrive.Application.Interfaces; public interface ICheckPointService { Task<List<CheckPointDto>> GetCheckPointsAsync(CheckPointQueryParameters queryParameters); - Task<CheckPointDto> GetCheckPointsByDriverIdAsync(int driverId); - Task<DriverCheckPointDto> GetCurrentCheckPointByDriverIdAsync(int driverId); + Task<CheckPointDto> GetCurrentCheckPointByDriverIdAsync(int driverId); } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs index a0a68207..ab930b6a 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs @@ -1,10 +1,9 @@ using CheckDrive.Application.DTOs.Driver; -using CheckDrive.Domain.Enums; namespace CheckDrive.Application.Interfaces; public interface IDriverService { - Task<List<DriverDto>> GetAvailableDriversAsync(CheckPointStage? stage); + Task<List<DriverDto>> GetAvailableDriversAsync(); Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmation); } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs index b3d1146f..05ec2c28 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs @@ -34,7 +34,8 @@ public async Task<string> LoginAsync(LoginDto request) throw new InvalidLoginAttemptException("Invalid email or password"); } - var roles = await _userManager.GetRolesAsync(employee.Account); + var user = await _userManager.FindByNameAsync(request.UserName); + var roles = await _userManager.GetRolesAsync(user); var token = _jwtTokenGenerator.GenerateToken(employee, roles); return token; diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs index 1b5c6e9b..2f2b4b6d 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs @@ -1,13 +1,5 @@ using AutoMapper; -using CheckDrive.Application.DTOs.Car; using CheckDrive.Application.DTOs.CheckPoint; -using CheckDrive.Application.DTOs.Debt; -using CheckDrive.Application.DTOs.DispatcherReview; -using CheckDrive.Application.DTOs.DoctorReview; -using CheckDrive.Application.DTOs.MechanicAcceptance; -using CheckDrive.Application.DTOs.MechanicHandover; -using CheckDrive.Application.DTOs.OperatorReview; -using CheckDrive.Application.DTOs.Review; using CheckDrive.Application.Interfaces; using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; @@ -40,33 +32,13 @@ public async Task<List<CheckPointDto>> GetCheckPointsAsync(CheckPointQueryParame return dtos; } - public Task<CheckPointDto> GetCheckPointsByDriverIdAsync(int driverId) + public async Task<CheckPointDto> GetCurrentCheckPointByDriverIdAsync(int driverId) { - throw new NotImplementedException(); - } - - public async Task<DriverCheckPointDto> GetCurrentCheckPointByDriverIdAsync(int driverId) - { - var checkPoint = await _context.CheckPoints - .AsNoTracking() + var checkPoint = await GetQuery() .Where(x => x.DoctorReview != null) .Where(x => x.DoctorReview.DriverId == driverId) .Where(x => x.StartDate.Date == DateTime.UtcNow.Date) .Where(x => x.Status == CheckPointStatus.InProgress) - .Include(x => x.DoctorReview) - .ThenInclude(x => x.Doctor) - .Include(x => x.DoctorReview) - .ThenInclude(x => x.Driver) - .Include(x => x.MechanicHandover) - .ThenInclude(x => x.Mechanic) - .Include(x => x.MechanicHandover) - .ThenInclude(x => x.Car) - .Include(x => x.OperatorReview) - .ThenInclude(x => x.Operator) - .Include(x => x.MechanicAcceptance) - .ThenInclude(x => x.Mechanic) - .Include(x => x.DispatcherReview) - .ThenInclude(x => x.Dispatcher) .FirstOrDefaultAsync(); if (checkPoint is null) @@ -74,12 +46,12 @@ public async Task<DriverCheckPointDto> GetCurrentCheckPointByDriverIdAsync(int d throw new EntityNotFoundException($"Driver with id: {driverId} does not have current active Check Point."); } - var dto = MapToDto(checkPoint); + var dto = _mapper.Map<CheckPointDto>(checkPoint); return dto; } - private IQueryable<CheckPoint> GetQuery(CheckPointQueryParameters queryParameters) + private IQueryable<CheckPoint> GetQuery(CheckPointQueryParameters? queryParameters = null) { var query = _context.CheckPoints .AsNoTracking() @@ -89,15 +61,21 @@ private IQueryable<CheckPoint> GetQuery(CheckPointQueryParameters queryParameter .ThenInclude(x => x.Doctor) .Include(x => x.MechanicHandover) .ThenInclude(x => x.Mechanic) + .Include(x => x.MechanicHandover) + .ThenInclude(x => x.Car) .Include(x => x.OperatorReview) .ThenInclude(x => x.Operator) .Include(x => x.MechanicAcceptance) .ThenInclude(x => x.Mechanic) .Include(x => x.DispatcherReview) .ThenInclude(x => x.Dispatcher) - .Include(x => x.Debt) .AsQueryable(); + if (queryParameters is null) + { + return query; + } + if (!string.IsNullOrWhiteSpace(queryParameters.Search)) { query = query.Where(x => @@ -147,125 +125,4 @@ private static IQueryable<CheckPoint> FilterByDate(IQueryable<CheckPoint> query, _ => throw new ArgumentOutOfRangeException($"Date filter: {dateFilter} is not implemented yet."), }; } - - private List<ReviewDtoBase> GetReviews(CheckPoint checkPoint) - { - ArgumentNullException.ThrowIfNull(checkPoint); - - var reviews = new List<ReviewDtoBase>(); - var doctorReview = _mapper.Map<DoctorReviewDto>(checkPoint.DoctorReview); - reviews.Add(doctorReview); - - if (checkPoint.MechanicHandover is not null) - { - var mechanicHandover = _mapper.Map<MechanicHandoverReviewDto>(checkPoint.MechanicHandover); - reviews.Add(mechanicHandover); - } - - if (checkPoint.OperatorReview is not null) - { - var operatorReview = _mapper.Map<OperatorReviewDto>(checkPoint.OperatorReview); - reviews.Add(operatorReview); - } - - if (checkPoint.MechanicAcceptance is not null) - { - var mechanicAcceptance = _mapper.Map<MechanicAcceptanceReviewDto>(checkPoint.MechanicAcceptance); - reviews.Add(mechanicAcceptance); - } - - if (checkPoint.DispatcherReview is not null) - { - var dispatcherReview = _mapper.Map<DispatcherReviewDto>(checkPoint.DispatcherReview); - reviews.Add(dispatcherReview); - } - - return reviews; - } - - private static DebtDto? GetDebt(CheckPoint checkPoint) - { - ArgumentNullException.ThrowIfNull(checkPoint); - - if (checkPoint.Debt is null) - { - return null; - } - - var debtEntity = checkPoint.Debt; - var debtDto = new DebtDto( - CheckPointId: checkPoint.Id, - FualAmount: debtEntity.FuelAmount, - PaidAmount: debtEntity.PaidAmount, - Status: debtEntity.Status); - - return debtDto; - } - - private DriverCheckPointDto MapToDto(CheckPoint checkPoint) - { - ArgumentNullException.ThrowIfNull(checkPoint); - - var reviews = new List<DriverReviewDto>(); - CarDto? car = null; - - { - var doctorReview = checkPoint.DoctorReview; - var review = new DriverReviewDto( - doctorReview.Notes, - doctorReview.Doctor.FirstName + " " + doctorReview.Doctor.LastName, - doctorReview.Date, - ReviewType.DoctorReview, - doctorReview.Status); - reviews.Add(review); - } - - if (checkPoint.MechanicHandover is not null) - { - var mechanicReview = checkPoint.MechanicHandover; - var review = new DriverReviewDto( - mechanicReview.Notes, - mechanicReview.Mechanic.FirstName + " " + mechanicReview.Mechanic.LastName, - mechanicReview.Date, - ReviewType.MechanicHandover, - mechanicReview.Status); - reviews.Add(review); - car = _mapper.Map<CarDto>(mechanicReview.Car); - } - - if (checkPoint.OperatorReview is not null) - { - var operatorReview = checkPoint.OperatorReview; - var review = new DriverReviewDto( - operatorReview.Notes, - operatorReview.Operator.FirstName + " " + operatorReview.Operator.LastName, - operatorReview.Date, - ReviewType.OperatorReview, - operatorReview.Status); - reviews.Add(review); - } - - if (checkPoint.MechanicAcceptance is not null) - { - var mechanicReview = checkPoint.MechanicAcceptance; - var review = new DriverReviewDto( - mechanicReview.Notes, - mechanicReview.Mechanic.FirstName + " " + mechanicReview.Mechanic.LastName, - mechanicReview.Date, - ReviewType.MechanicAcceptance, - mechanicReview.Status); - reviews.Add(review); - } - - var checkPointDto = new DriverCheckPointDto( - checkPoint.Id, - checkPoint.StartDate, - checkPoint.Stage, - checkPoint.Status, - checkPoint.DoctorReview.Driver.FirstName + " " + checkPoint.DoctorReview.Driver.LastName, - car, - reviews); - - return checkPointDto; - } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs index 71e5f0bb..710ad103 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs @@ -17,33 +17,14 @@ public DriverService(ICheckDriveDbContext context) _context = context ?? throw new ArgumentNullException(nameof(context)); } - public async Task<List<DriverDto>> GetAvailableDriversAsync(CheckPointStage? stage) + public async Task<List<DriverDto>> GetAvailableDriversAsync() { - var query = _context.Drivers - .AsNoTracking() - .Include(x => x.Account) - .AsQueryable(); - - query = FilterByCheckPointStage(query, stage); - - var drivers = await query - .Include(x => x.Reviews) - .Select(x => new - { - x.Id, - x.AccountId, - FullName = x.FirstName + " " + x.LastName, - x.Reviews - }) + var drivers = await _context.Drivers + .Where(x => !x.Reviews.Any(x => x.Date.Date == DateTime.UtcNow.Date)) + .Select(x => new DriverDto(x.Id, x.AccountId, x.FirstName + " " + x.LastName)) .ToListAsync(); - var driversWithCheckPoints = drivers.Select(x => - { - int? checkPointId = x.Reviews.FirstOrDefault(x => x.Date.Date == DateTime.UtcNow.Date)?.CheckPointId; - return new DriverDto(x.Id, x.AccountId, x.FullName, checkPointId); - }).ToList(); - - return driversWithCheckPoints; + return drivers; } public async Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmation) @@ -56,9 +37,16 @@ public async Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmat { checkPoint.Status = CheckPointStatus.InterruptedByDriverRejection; await _context.SaveChangesAsync(); + return; } + await CreateReviewAsync(checkPoint, confirmation); + await _context.SaveChangesAsync(); + } + + private async Task CreateReviewAsync(CheckPoint checkPoint, DriverReviewConfirmationDto confirmation) + { if (confirmation.ReviewType == ReviewType.MechanicHandover) { await AcceptMechanicHandoverAsync(checkPoint); @@ -73,24 +61,6 @@ public async Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmat { await AcceptMechanicAcceptanceAsync(checkPoint); } - - await _context.SaveChangesAsync(); - } - - private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) - { - var checkPoint = await _context.CheckPoints - .Include(x => x.MechanicHandover) - .Include(x => x.MechanicAcceptance) - .Include(x => x.OperatorReview) - .FirstOrDefaultAsync(x => x.Id == checkPointId); - - if (checkPoint is null) - { - throw new EntityNotFoundException($"Check Point with id: {checkPointId} is not found."); - } - - return checkPoint; } private async Task AcceptMechanicHandoverAsync(CheckPoint checkPoint) @@ -100,16 +70,12 @@ private async Task AcceptMechanicHandoverAsync(CheckPoint checkPoint) throw new InvalidOperationException($"Cannot update car for Check Point without Mechanic Handover Review."); } - var car = await _context.Cars.FirstOrDefaultAsync(c => c.Id == checkPoint.MechanicHandover.CarId); - - if (car is null) - { - throw new EntityNotFoundException($"Car with id: {checkPoint.MechanicHandover.CarId}"); - } + var car = await GetAndValidateCarAsync(checkPoint.MechanicHandover.CarId); car.Mileage = checkPoint.MechanicHandover.InitialMileage; + car.Status = CarStatus.Busy; + checkPoint.Stage = CheckPointStage.MechanicHandover; checkPoint.MechanicHandover.Status = ReviewStatus.Approved; - checkPoint.Stage = CheckPointStage.OperatorReview; } private async Task AcceptOperatorReviewAsync(CheckPoint checkPoint) @@ -120,9 +86,9 @@ private async Task AcceptOperatorReviewAsync(CheckPoint checkPoint) } var car = await GetAndValidateCarAsync(checkPoint.MechanicHandover.CarId); - car.RemainingFuel += checkPoint.OperatorReview.OilRefillAmount; - checkPoint.Stage = CheckPointStage.MechanicAcceptance; + car.RemainingFuel = checkPoint.OperatorReview.InitialOilAmount + checkPoint.OperatorReview.OilRefillAmount; + checkPoint.Stage = CheckPointStage.OperatorReview; checkPoint.OperatorReview.Status = ReviewStatus.Approved; } @@ -134,13 +100,50 @@ private async Task AcceptMechanicAcceptanceAsync(CheckPoint checkPoint) } var car = await GetAndValidateCarAsync(checkPoint.MechanicHandover.CarId); + var fuelConsumption = CalculateFuelConsumption( + checkPoint.MechanicHandover.InitialMileage, + checkPoint.MechanicAcceptance.FinalMileage, + car.AverageFuelConsumption); + + if (fuelConsumption > car.RemainingFuel) + { + var debt = CreateDebt( + checkPoint, + fuelConsumption, + car.RemainingFuel, + checkPoint.MechanicAcceptance.RemainingFuelAmount); + _context.Debts.Add(debt); + } + car.Mileage = checkPoint.MechanicAcceptance.FinalMileage; car.RemainingFuel = checkPoint.MechanicAcceptance.RemainingFuelAmount; - - checkPoint.Stage = CheckPointStage.DispatcherReview; + car.CurrentMonthMileage += checkPoint.MechanicHandover.InitialMileage - checkPoint.MechanicAcceptance.FinalMileage; + checkPoint.Stage = CheckPointStage.MechanicAcceptance; checkPoint.MechanicAcceptance.Status = ReviewStatus.Approved; } + private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) + { + var checkPoint = await _context.CheckPoints + .Include(x => x.MechanicHandover) + .Include(x => x.OperatorReview) + .Include(x => x.MechanicAcceptance) + .FirstOrDefaultAsync(x => x.Id == checkPointId); + + if (checkPoint is null) + { + throw new EntityNotFoundException($"Check Point with id: {checkPointId} is not found."); + } + + if (checkPoint.Status != CheckPointStatus.InProgress) + { + throw new InvalidOperationException( + $"Driver can perform review confirmation only for In Progress Check Point. Current check point status: {checkPoint.Status}"); + } + + return checkPoint; + } + private async Task<Car> GetAndValidateCarAsync(int carId) { var car = await _context.Cars.FirstOrDefaultAsync(x => x.Id == carId); @@ -153,16 +156,27 @@ private async Task<Car> GetAndValidateCarAsync(int carId) return car; } - private static IQueryable<Driver> FilterByCheckPointStage(IQueryable<Driver> query, CheckPointStage? stage) + private static decimal CalculateFuelConsumption( + int initialMileage, + int finalMileage, + decimal averageFuelConsumption) + { + var mileageAmount = finalMileage - initialMileage; + var fuelSpent = averageFuelConsumption * mileageAmount; + + return fuelSpent; + } + + private static Debt CreateDebt(CheckPoint checkPoint, decimal fuelSpent, decimal fuelInitialAmount, decimal fuelFinalAmount) { - switch (stage) + var debt = new Debt { - case null: - return query.Where(x => !x.Reviews.Any(x => x.Date.Date == DateTime.UtcNow.Date)); - case CheckPointStage.DoctorReview: - return query.Where(x => x.Reviews.Any(r => r.Date.Date == DateTime.UtcNow.Date && r.Status == ReviewStatus.Approved)); - default: - return query; - } + CheckPoint = checkPoint, + FuelAmount = fuelSpent - fuelInitialAmount - fuelFinalAmount, + PaidAmount = 0, + Status = DebtStatus.Unpaid + }; + + return debt; } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs index 36e9e2fe..8c4c40ab 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs @@ -17,7 +17,10 @@ internal sealed class DoctorReviewService : IDoctorReviewService private readonly IMapper _mapper; private readonly IHubContext<ReviewHub, IReviewHub> _reviewHub; - public DoctorReviewService(ICheckDriveDbContext context, IMapper mapper, IHubContext<ReviewHub, IReviewHub> reviewHub) + public DoctorReviewService( + ICheckDriveDbContext context, + IMapper mapper, + IHubContext<ReviewHub, IReviewHub> reviewHub) { _context = context ?? throw new ArgumentNullException(nameof(context)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); @@ -32,14 +35,16 @@ public async Task<DoctorReviewDto> CreateAsync(CreateDoctorReviewDto review) var driver = await GetAndValidateDriverAsync(review.DriverId); var checkPoint = CreateCheckPoint(review); - var reviewEntity = CreateReviewEntity(review, checkPoint, doctor, driver); + var reviewEntity = CreateReview(review, checkPoint, doctor, driver); _context.DoctorReviews.Add(reviewEntity); await _context.SaveChangesAsync(); var dto = _mapper.Map<DoctorReviewDto>(reviewEntity); - await _reviewHub.Clients.User(dto.DriverId.ToString()).NotifyNewReviewAsync(dto); + await _reviewHub.Clients + .User(dto.DriverId.ToString()) + .NotifyDoctorReview(dto); return dto; } @@ -67,6 +72,8 @@ private async Task<Driver> GetAndValidateDriverAsync(int driverId) throw new EntityNotFoundException($"Driver with id: {driverId} is not found."); } + // TODO: check whether driver does not have any active check point in progress + return driver; } @@ -85,7 +92,11 @@ private static CheckPoint CreateCheckPoint(CreateDoctorReviewDto review) return checkPoint; } - private static DoctorReview CreateReviewEntity(CreateDoctorReviewDto review, CheckPoint checkPoint, Doctor doctor, Driver driver) + private static DoctorReview CreateReview( + CreateDoctorReviewDto review, + CheckPoint checkPoint, + Doctor doctor, + Driver driver) { ArgumentNullException.ThrowIfNull(review); ArgumentNullException.ThrowIfNull(checkPoint); diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicAcceptanceService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicAcceptanceService.cs index 3d1b8e24..bf3ea8f1 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicAcceptanceService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicAcceptanceService.cs @@ -1,10 +1,12 @@ using AutoMapper; using CheckDrive.Application.DTOs.MechanicAcceptance; +using CheckDrive.Application.Hubs; using CheckDrive.Application.Interfaces.Review; using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; +using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services.Review; @@ -13,11 +15,16 @@ internal sealed class MechanicAcceptanceService : IMechanicAcceptanceService { private readonly ICheckDriveDbContext _context; private readonly IMapper _mapper; + private readonly IHubContext<ReviewHub, IReviewHub> _hubContext; - public MechanicAcceptanceService(ICheckDriveDbContext context, IMapper mapper) + public MechanicAcceptanceService( + ICheckDriveDbContext context, + IMapper mapper, + IHubContext<ReviewHub, IReviewHub> hubContext) { _context = context ?? throw new ArgumentNullException(nameof(context)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext)); } public async Task<MechanicAcceptanceReviewDto> CreateAsync(CreateMechanicAcceptanceReviewDto review) @@ -27,37 +34,33 @@ public async Task<MechanicAcceptanceReviewDto> CreateAsync(CreateMechanicAccepta var checkPoint = await GetAndValidateCheckPointAsync(review.CheckPointId); var mechanic = await GetAndValidateMechanicAsync(review.ReviewerId); - using var transaction = _context.BeginTransaction(); - - try + if (!review.IsApprovedByReviewer) { - UpdateCheckPoint(checkPoint, review); - UpdateCar(checkPoint, review); + checkPoint.Stage = CheckPointStage.MechanicAcceptance; + checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; + } - var reviewEntity = CreateReviewEntity(checkPoint, mechanic, review); + var reviewEntity = CreateReview(checkPoint, mechanic, review); - var createdReview = _context.MechanicAcceptances.Add(reviewEntity).Entity; - await _context.SaveChangesAsync(); + _context.MechanicAcceptances.Add(reviewEntity); + await _context.SaveChangesAsync(); - await transaction.CommitAsync(); + var dto = _mapper.Map<MechanicAcceptanceReviewDto>(reviewEntity); - var dto = _mapper.Map<MechanicAcceptanceReviewDto>(createdReview); + await _hubContext.Clients + .User(dto.DriverId.ToString()) + .MechanicAcceptanceConfirmation(dto); - return dto; - } - catch (Exception) - { - await transaction.RollbackAsync(); - throw; - } + return dto; } private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) { var checkPoint = await _context.CheckPoints - .Include(x => x.OperatorReview) + .Include(x => x.DoctorReview) .Include(x => x.MechanicHandover) - .ThenInclude(mh => mh!.Car) + .ThenInclude(x => x.Car) + .Include(x => x.OperatorReview) .FirstOrDefaultAsync(x => x.Id == checkPointId); if (checkPoint is null) @@ -94,7 +97,7 @@ private async Task<Mechanic> GetAndValidateMechanicAsync(int mechanicId) return mechanic; } - private static MechanicAcceptance CreateReviewEntity( + private static MechanicAcceptance CreateReview( CheckPoint checkPoint, Mechanic mechanic, CreateMechanicAcceptanceReviewDto review) @@ -112,71 +115,4 @@ private static MechanicAcceptance CreateReviewEntity( return entity; } - - private static void UpdateCheckPoint(CheckPoint checkPoint, CreateMechanicAcceptanceReviewDto review) - { - ArgumentNullException.ThrowIfNull(checkPoint); - - checkPoint.Stage = CheckPointStage.MechanicAcceptance; - - if (!review.IsApprovedByReviewer) - { - checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; - } - } - - private void UpdateCar(CheckPoint checkPoint, CreateMechanicAcceptanceReviewDto review) - { - if (checkPoint.MechanicHandover is null) - { - throw new InvalidOperationException($"Mechanic Handover in Check Point cannot be null."); - } - - var car = checkPoint.MechanicHandover.Car; - - if (car.FuelCapacity < review.RemainingFuelAmount) - { - throw new FuelAmountExceedsCarCapacityException($"Remaining amount: {review.RemainingFuelAmount} exceeds Capacity: {car.FuelCapacity}."); - } - var fuelSpent = CalculateFuelConsumption(checkPoint.MechanicHandover.InitialMileage, review.FinalMileage, car.AverageFuelConsumption); - - if (fuelSpent > car.RemainingFuel) - { - var debt = CreateDebt(checkPoint, fuelSpent, car.RemainingFuel, review.RemainingFuelAmount); - _context.Debts.Add(debt); - } - car.RemainingFuel = review.RemainingFuelAmount; - - if (review.FinalMileage < car.Mileage) - { - throw new InvalidMileageException( - $"Final mileage ({review.FinalMileage}) cannot be less than the current milea of a car ({car.Mileage})."); - } - car.Mileage = review.FinalMileage; - car.Status = CarStatus.Free; - } - - private static decimal CalculateFuelConsumption( - int initialMileage, - int finalMileage, - decimal averageFuelConsumption) - { - var mileageAmount = finalMileage - initialMileage; - var fuelSpent = averageFuelConsumption * mileageAmount; - - return fuelSpent; - } - - private static Debt CreateDebt(CheckPoint checkPoint, decimal fuelSpent, decimal fuelInitialAmount, decimal fuelFinalAmount) - { - var debt = new Debt - { - CheckPoint = checkPoint, - FuelAmount = fuelSpent - fuelInitialAmount - fuelFinalAmount, - PaidAmount = 0, - Status = DebtStatus.Unpaid - }; - - return debt; - } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs index c26f10b9..4b1e72ba 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs @@ -1,6 +1,5 @@ using AutoMapper; using CheckDrive.Application.DTOs.MechanicHandover; -using CheckDrive.Application.DTOs.Review; using CheckDrive.Application.Hubs; using CheckDrive.Application.Interfaces.Review; using CheckDrive.Domain.Entities; @@ -18,7 +17,10 @@ internal sealed class MechanicHandoverService : IMechanicHandoverService private readonly IMapper _mapper; private readonly IHubContext<ReviewHub, IReviewHub> _hubContext; - public MechanicHandoverService(ICheckDriveDbContext context, IMapper mapper, IHubContext<ReviewHub, IReviewHub> hubContext) + public MechanicHandoverService( + ICheckDriveDbContext context, + IMapper mapper, + IHubContext<ReviewHub, IReviewHub> hubContext) { _context = context ?? throw new ArgumentNullException(nameof(context)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); @@ -33,23 +35,22 @@ public async Task<MechanicHandoverReviewDto> CreateAsync(CreateMechanicHandoverR var mechanic = await GetAndValidateMechanicAsync(review.ReviewerId); var car = await GetAndValidateCarAsync(review.CarId); - UpdateCheckPoint(checkPoint, review); - // UpdateCar(car, review); + if (!review.IsApprovedByReviewer) + { + checkPoint.Stage = CheckPointStage.OperatorReview; + checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; + } - var reviewEntity = CreateReviewEntity(review, mechanic, car, checkPoint); + var reviewEntity = CreateReview(review, checkPoint, mechanic, car); - var createdReview = _context.MechanicHandovers.Add(reviewEntity).Entity; + _context.MechanicHandovers.Add(reviewEntity); await _context.SaveChangesAsync(); - var dto = _mapper.Map<MechanicHandoverReviewDto>(createdReview); - var message = $"{mechanic.FirstName} {mechanic.LastName}dan {car.Color} {car.Model}ni boshlangich {review.InitialMileage} masofa bilan qabul qilishni tasdiqlaysizmi?"; - var reviewConfirmation = new ReviewConfirmationDto( - checkPoint.Id, - ReviewType.MechanicHandover, - message); + var dto = _mapper.Map<MechanicHandoverReviewDto>(reviewEntity); - await _hubContext.Clients.User(checkPoint.DoctorReview.DriverId.ToString()) - .SendReviewConfirmationAsync(reviewConfirmation); + await _hubContext.Clients + .User(dto.DriverId.ToString()) + .MechanicHandoverConfirmation(dto); return dto; } @@ -83,7 +84,7 @@ private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) throw new InvalidOperationException($"Cannot start car handover review when check point stage is not Doctor Review"); } - if (checkPoint.DoctorReview.Status != ReviewStatus.Approved) + if (checkPoint.Status != CheckPointStatus.InProgress) { throw new InvalidOperationException($"Cannot start car handover review when Doctor review is not approved."); } @@ -106,15 +107,20 @@ private async Task<Car> GetAndValidateCarAsync(int carId) throw new UnavailableCarException($"Car with id: {carId} is not available for handover."); } + // TODO: Add logic for checking whether car's yearly/monthly limit is not exceeded + return car; } - private static MechanicHandover CreateReviewEntity( + private static MechanicHandover CreateReview( CreateMechanicHandoverReviewDto review, + CheckPoint checkPoint, Mechanic mechanic, - Car car, - CheckPoint checkPoint) + Car car) { + ArgumentNullException.ThrowIfNull(review); + ArgumentNullException.ThrowIfNull(checkPoint); + var entity = new MechanicHandover() { CheckPoint = checkPoint, @@ -128,30 +134,4 @@ private static MechanicHandover CreateReviewEntity( return entity; } - - private static void UpdateCar(Car car, CreateMechanicHandoverReviewDto review) - { - ArgumentNullException.ThrowIfNull(car); - - if (review.InitialMileage < car.Mileage) - { - throw new InvalidMileageException( - $"Initial mileage ({review.InitialMileage}) cannot be less than current mileage of car: {car.Mileage}."); - } - - car.Mileage = review.InitialMileage; - car.Status = CarStatus.Busy; - } - - private static void UpdateCheckPoint(CheckPoint checkPoint, CreateMechanicHandoverReviewDto review) - { - ArgumentNullException.ThrowIfNull(checkPoint); - - checkPoint.Stage = CheckPointStage.MechanicHandover; - - if (!review.IsApprovedByReviewer) - { - checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; - } - } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/OperatorReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/OperatorReviewService.cs index e40583d1..e52790a3 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/OperatorReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/OperatorReviewService.cs @@ -1,10 +1,12 @@ using AutoMapper; using CheckDrive.Application.DTOs.OperatorReview; +using CheckDrive.Application.Hubs; using CheckDrive.Application.Interfaces.Review; using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; +using Microsoft.AspNetCore.SignalR; using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services.Review; @@ -13,11 +15,16 @@ internal sealed class OperatorReviewService : IOperatorReviewService { private readonly ICheckDriveDbContext _context; private readonly IMapper _mapper; + private readonly IHubContext<ReviewHub, IReviewHub> _hubContext; - public OperatorReviewService(ICheckDriveDbContext context, IMapper mapper) + public OperatorReviewService( + ICheckDriveDbContext context, + IMapper mapper, + IHubContext<ReviewHub, IReviewHub> hubContext) { _context = context ?? throw new ArgumentNullException(nameof(context)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext)); } public async Task<OperatorReviewDto> CreateAsync(CreateOperatorReviewDto review) @@ -27,16 +34,30 @@ public async Task<OperatorReviewDto> CreateAsync(CreateOperatorReviewDto review) var checkPoint = await GetAndValidateCheckPointAsync(review.CheckPointId); var @operator = await GetAndValidateOperatorAsync(review.ReviewerId); var oilMark = await GetAndValidateOilMarkAsync(review.OilMarkId); + var car = checkPoint.MechanicHandover!.Car; - RefillCar(checkPoint.MechanicHandover!.Car, review); - UpdateCheckPoint(checkPoint, review); + if (car.FuelCapacity < review.InitialOilAmount + review.OilRefillAmount) + { + throw new InvalidOperationException( + $"Oil refill amount ({review.InitialOilAmount + review.OilRefillAmount}) exceeds Car's fuel capacity ({car.FuelCapacity})."); + } + + if (!review.IsApprovedByReviewer) + { + checkPoint.Stage = CheckPointStage.OperatorReview; + checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; + } - var reviewEntity = CreateReviewEntity(checkPoint, oilMark, @operator, review); + var reviewEntity = CreateReview(checkPoint, oilMark, @operator, review); - var createdReview = _context.OperatorReviews.Add(reviewEntity).Entity; + _context.OperatorReviews.Add(reviewEntity); await _context.SaveChangesAsync(); - var dto = _mapper.Map<OperatorReviewDto>(createdReview); + var dto = _mapper.Map<OperatorReviewDto>(reviewEntity); + + await _hubContext.Clients + .User(dto.DriverId.ToString()) + .OperatorReviewConfirmation(dto); return dto; } @@ -44,9 +65,10 @@ public async Task<OperatorReviewDto> CreateAsync(CreateOperatorReviewDto review) private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) { var checkPoint = await _context.CheckPoints - .AsTracking() + .Include(x => x.DoctorReview) + .ThenInclude(x => x.Driver) .Include(x => x.MechanicHandover) - .ThenInclude(mh => mh!.Car) + .ThenInclude(x => x!.Car) .FirstOrDefaultAsync(x => x.Id == checkPointId); if (checkPoint is null) @@ -93,39 +115,7 @@ private async Task<OilMark> GetAndValidateOilMarkAsync(int oilMarkId) return oilMark; } - private static void RefillCar(Car car, CreateOperatorReviewDto review) - { - ArgumentNullException.ThrowIfNull(car); - - if (!review.IsApprovedByReviewer) - { - return; - } - - var total = review.InitialOilAmount + review.OilRefillAmount; - - if (car.FuelCapacity < total) - { - throw new FuelAmountExceedsCarCapacityException($"{total} exceeds car fuel capacity: {car.FuelCapacity}."); - } - - car.RemainingFuel = total; - } - - private static void UpdateCheckPoint(CheckPoint checkPoint, CreateOperatorReviewDto review) - { - ArgumentNullException.ThrowIfNull(checkPoint); - ArgumentNullException.ThrowIfNull(review); - - checkPoint.Stage = CheckPointStage.OperatorReview; - - if (!review.IsApprovedByReviewer) - { - checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; - } - } - - private static OperatorReview CreateReviewEntity( + private static OperatorReview CreateReview( CheckPoint checkPoint, OilMark oilMark, Operator @operator, diff --git a/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs b/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs index c0f60d17..21730521 100644 --- a/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs +++ b/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs @@ -7,6 +7,6 @@ public class CheckPointQueryParameters : QueryParametersBase { public int? DriverId { get; set; } public CheckPointStage? Stage { get; set; } - public CheckPointStatus? Status { get; set; } - public DateFilter? Date { get; set; } = DateFilter.Today; + public CheckPointStatus? Status { get; set; } = CheckPointStatus.InProgress; + public DateFilter? Date { get; set; } } From 6fb8c7a4b2570efd2d40398bf1c4bb60dac255ae Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Thu, 31 Oct 2024 02:07:30 +0500 Subject: [PATCH 25/40] remove debug info --- .../CheckDrive.Application/Hubs/ReviewHub.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs index 74eccd1c..f6136d58 100644 --- a/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs @@ -11,16 +11,4 @@ await Clients .User(review.DriverId.ToString()) .NotifyDoctorReview(review); } - - public override Task OnConnectedAsync() - { - var s = Context.UserIdentifier; - return base.OnConnectedAsync(); - } - - public override Task OnDisconnectedAsync(Exception? exception) - { - var s = Context.UserIdentifier; - return base.OnDisconnectedAsync(exception); - } } From cd4970c65fd962edbe5be54edbc195b5800facac Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Thu, 31 Oct 2024 23:04:33 +0500 Subject: [PATCH 26/40] code review fixes --- .../BackgroundJobs/CarMonthlyMileageResetService.cs | 2 +- .../CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs b/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs index 1249a822..1c95acfe 100644 --- a/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs +++ b/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs @@ -11,7 +11,7 @@ internal sealed class CarMonthlyMileageResetService : BackgroundService public CarMonthlyMileageResetService(IServiceProvider serviceProvider) { - _serviceProvider = serviceProvider; + _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs index 90202b01..220c42fd 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs @@ -1,4 +1,5 @@ namespace CheckDrive.Application.DTOs.OilMark; + public sealed record OilMarkDto( int Id, string Name); From 6cee3b9d7009397e3e9518b4761d76f597b03180 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 2 Nov 2024 00:10:48 +0500 Subject: [PATCH 27/40] implement review history service --- .../Reviews/DispatcherReviewsController.cs | 2 +- .../Reviews/ReviewHistoriesController.cs | 52 +++++++ .../DTOs/Review/MechanicReviewHistoryDto.cs | 11 ++ .../Extensions/DependencyInjection.cs | 1 + .../Review/IReviewHistoryService.cs | 14 ++ .../Services/CheckPointService.cs | 4 - .../Services/ReviewHistoryService.cs | 128 ++++++++++++++++++ 7 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/Review/MechanicReviewHistoryDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Interfaces/Review/IReviewHistoryService.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/DispatcherReviewsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/DispatcherReviewsController.cs index 11955e3d..a7b7abb1 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/DispatcherReviewsController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/DispatcherReviewsController.cs @@ -4,7 +4,7 @@ namespace CheckDrive.Api.Controllers.Reviews; -[Route("api/reviews/dispatcher/{dispatcherId:int}")] +[Route("api/reviews/dispatchers/{dispatcherId:int}")] [ApiController] public class DispatcherReviewsController : ControllerBase { diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs new file mode 100644 index 00000000..dafd8ab0 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs @@ -0,0 +1,52 @@ +using CheckDrive.Application.DTOs.CheckPoint; +using CheckDrive.Application.DTOs.DoctorReview; +using CheckDrive.Application.DTOs.OperatorReview; +using CheckDrive.Application.DTOs.Review; +using CheckDrive.Application.Interfaces.Review; +using Microsoft.AspNetCore.Mvc; + +namespace CheckDrive.Api.Controllers.Reviews; + +[Route("api/reviews/histories")] +[ApiController] +public class ReviewHistoriesController : ControllerBase +{ + private readonly IReviewHistoryService _historyService; + + public ReviewHistoriesController(IReviewHistoryService historyService) + { + _historyService = historyService ?? throw new ArgumentNullException(nameof(historyService)); + } + + [HttpGet("drivers/{driverId:int}")] + public async Task<ActionResult<List<CheckPointDto>>> GetDriverHistoriesAsync(int driverId) + { + var reviews = await _historyService.GetDriverHistoriesAsync(driverId); + + return Ok(reviews); + } + + [HttpGet("doctors/{doctorId:int}")] + public async Task<ActionResult<List<DoctorReviewDto>>> GetDoctorHistoriesAsync(int doctorId) + { + var reviews = await _historyService.GetDoctorHistoriesAsync(doctorId); + + return Ok(reviews); + } + + [HttpGet("mechanics/{mechanicId:int}")] + public async Task<ActionResult<List<MechanicReviewHistoryDto>>> GetMechanicHistoriesAsync(int mechanicId) + { + var reviews = await _historyService.GetMechanicHistoriesAsync(mechanicId); + + return Ok(reviews); + } + + [HttpGet("operators/{operatorId:int}")] + public async Task<ActionResult<List<OperatorReviewDto>>> GetOperatorHistoriesAsync(int operatorId) + { + var reviews = await _historyService.GetOperatorHistoriesAsync(operatorId); + + return Ok(reviews); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Review/MechanicReviewHistoryDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Review/MechanicReviewHistoryDto.cs new file mode 100644 index 00000000..37067215 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Review/MechanicReviewHistoryDto.cs @@ -0,0 +1,11 @@ +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.Review; + +public sealed record MechanicReviewHistoryDto( + int ReviewId, + int DriverId, + string DriverName, + string? Notes, + DateTime Date, + ReviewStatus Status); diff --git a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs index 1d24a8f7..44f6248b 100644 --- a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs @@ -32,6 +32,7 @@ private static void AddServices(IServiceCollection services) services.AddScoped<IDriverService, DriverService>(); services.AddScoped<ICarService, CarService>(); services.AddScoped<IOilMarkService, OilMarkService>(); + services.AddScoped<IReviewHistoryService, ReviewHistoryService>(); services.AddHostedService<CarMonthlyMileageResetService>(); } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/Review/IReviewHistoryService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/Review/IReviewHistoryService.cs new file mode 100644 index 00000000..8d65ec60 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/Review/IReviewHistoryService.cs @@ -0,0 +1,14 @@ +using CheckDrive.Application.DTOs.CheckPoint; +using CheckDrive.Application.DTOs.DoctorReview; +using CheckDrive.Application.DTOs.OperatorReview; +using CheckDrive.Application.DTOs.Review; + +namespace CheckDrive.Application.Interfaces.Review; + +public interface IReviewHistoryService +{ + Task<List<CheckPointDto>> GetDriverHistoriesAsync(int driverId); + Task<List<DoctorReviewDto>> GetDoctorHistoriesAsync(int doctorId); + Task<List<MechanicReviewHistoryDto>> GetMechanicHistoriesAsync(int mechanicId); + Task<List<OperatorReviewDto>> GetOperatorHistoriesAsync(int operatorId); +} diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs index 2f2b4b6d..aed29021 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs @@ -106,10 +106,6 @@ private IQueryable<CheckPoint> GetQuery(CheckPointQueryParameters? queryParamete { query = FilterByDate(query, queryParameters.Date.Value); } - else - { - query = FilterByDate(query, DateFilter.Today); - } return query; } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs b/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs new file mode 100644 index 00000000..d2038f5e --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs @@ -0,0 +1,128 @@ +using AutoMapper; +using CheckDrive.Application.DTOs.CheckPoint; +using CheckDrive.Application.DTOs.DoctorReview; +using CheckDrive.Application.DTOs.OperatorReview; +using CheckDrive.Application.DTOs.Review; +using CheckDrive.Application.Interfaces.Review; +using CheckDrive.Domain.Enums; +using CheckDrive.Domain.Interfaces; +using Microsoft.EntityFrameworkCore; + +namespace CheckDrive.Application.Services; + +internal sealed class ReviewHistoryService : IReviewHistoryService +{ + private readonly ICheckDriveDbContext _context; + private readonly IMapper _mapper; + + public ReviewHistoryService(ICheckDriveDbContext context, IMapper mapper) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + } + + public async Task<List<CheckPointDto>> GetDriverHistoriesAsync(int driverId) + { + var checkPoints = await _context.CheckPoints + .AsNoTracking() + .Where(x => x.DoctorReview.DriverId == driverId) + .Where(x => x.Status == CheckPointStatus.Completed || x.Status == CheckPointStatus.AutomaticallyClosed) + .Include(x => x.DoctorReview) + .ThenInclude(x => x.Doctor) + .Include(x => x.MechanicHandover) + .ThenInclude(x => x.Mechanic) + .Include(x => x.MechanicHandover) + .ThenInclude(x => x.Car) + .Include(x => x.OperatorReview) + .ThenInclude(x => x.Operator) + .Include(x => x.OperatorReview) + .ThenInclude(x => x.OilMark) + .Include(x => x.MechanicAcceptance) + .ThenInclude(x => x.Mechanic) + .Include(x => x.DispatcherReview) + .Include(x => x.ManagerReview) + .Include(x => x.Debt) + .AsSplitQuery() + .ToListAsync(); + + var dtos = _mapper.Map<List<CheckPointDto>>(checkPoints); + + return dtos; + + } + + public async Task<List<DoctorReviewDto>> GetDoctorHistoriesAsync(int doctorId) + { + var reviews = await _context.DoctorReviews + .Where(x => x.DoctorId == doctorId) + .ToListAsync(); + + var dtos = _mapper.Map<List<DoctorReviewDto>>(reviews); + + return dtos; + } + + public async Task<List<MechanicReviewHistoryDto>> GetMechanicHistoriesAsync(int mechanicId) + { + var handovers = await _context.MechanicHandovers + .AsNoTracking() + .Where(x => x.MechanicId == mechanicId) + .Include(x => x.CheckPoint) + .ThenInclude(x => x.DoctorReview) + .ThenInclude(x => x.Driver) + .Select(x => new MechanicReviewHistoryDto( + x.Id, + x.CheckPoint.DoctorReview.DriverId, + x.CheckPoint.DoctorReview.Driver.FirstName + " " + x.CheckPoint.DoctorReview.Driver.LastName, + x.Notes, + x.Date, + x.Status)) + .ToListAsync(); + var acceptances = await _context.MechanicAcceptances + .Include(x => x.CheckPoint) + .ThenInclude(x => x.DoctorReview) + .ThenInclude(x => x.Driver) + .Select(x => new MechanicReviewHistoryDto( + x.Id, + x.CheckPoint.DoctorReview.DriverId, + x.CheckPoint.DoctorReview.Driver.FirstName + " " + x.CheckPoint.DoctorReview.Driver.LastName, + x.Notes, + x.Date, + x.Status)) + .ToListAsync(); + + List<MechanicReviewHistoryDto> allReviews = [.. handovers, .. acceptances]; + var orderedReviews = allReviews.OrderByDescending(x => x.Date).ToList(); + + return orderedReviews; + } + + public async Task<List<OperatorReviewDto>> GetOperatorHistoriesAsync(int operatorId) + { + var reviews = await _context.OperatorReviews + .AsNoTracking() + .Where(x => x.OperatorId == operatorId) + .Include(x => x.Operator) + .Include(x => x.OilMark) + .Include(x => x.CheckPoint) + .ThenInclude(x => x.DoctorReview) + .ThenInclude(x => x.Driver) + .AsSplitQuery() + .Select(x => new OperatorReviewDto( + x.CheckPointId, + x.OperatorId, + x.Operator.FirstName + " " + x.Operator.LastName, + x.CheckPoint.DoctorReview.DriverId, + x.CheckPoint.DoctorReview.Driver.FirstName + " " + x.CheckPoint.DoctorReview.Driver.LastName, + x.OilMarkId, + x.OilMark.Name, + x.Notes, + x.Date, + x.Status, + x.InitialOilAmount, + x.OilRefillAmount)) + .ToListAsync(); + + return reviews; + } +} From e9313ca7323ee8f7ac986fac7e80e774fe3f4e2a Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sat, 2 Nov 2024 00:14:06 +0500 Subject: [PATCH 28/40] rename mileage property in dispatcher review --- .../Review/DispatcherReviewService.cs | 2 +- .../Entities/DispatcherReview.cs | 2 +- .../DispatcherReviewConfiguration.cs | 2 +- ...spatcherReview_MileageProperty.Designer.cs | 1066 +++++++++++++++++ ...Rename_DispatcherReview_MileageProperty.cs | 30 + .../CheckDriveDbContextModelSnapshot.cs | 16 +- 6 files changed, 1107 insertions(+), 11 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241101191151_Rename_DispatcherReview_MileageProperty.Designer.cs create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241101191151_Rename_DispatcherReview_MileageProperty.cs diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs index db0d7cf1..6ab22fef 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs @@ -92,7 +92,7 @@ private static DispatcherReview CreateReviewEntity(CheckPoint checkPoint, Dispat Date = DateTime.UtcNow, Status = review.IsApprovedByReviewer ? ReviewStatus.Approved : ReviewStatus.RejectedByReviewer, FuelConsumptionAdjustment = review.FuelConsumptionAdjustment, - DistanceTravelledAdjustment = review.DistanceTravelledAdjustment, + FinalMileageAdjustment = review.DistanceTravelledAdjustment, }; return entity; diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/DispatcherReview.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/DispatcherReview.cs index affa3ab3..789392af 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Entities/DispatcherReview.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/DispatcherReview.cs @@ -5,7 +5,7 @@ namespace CheckDrive.Domain.Entities; public class DispatcherReview : ReviewBase { public decimal? FuelConsumptionAdjustment { get; set; } - public decimal? DistanceTravelledAdjustment { get; set; } + public decimal? FinalMileageAdjustment { get; set; } public int CheckPointId { get; set; } public required virtual CheckPoint CheckPoint { get; set; } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/DispatcherReviewConfiguration.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/DispatcherReviewConfiguration.cs index 52a96ee0..e065ce47 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/DispatcherReviewConfiguration.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/DispatcherReviewConfiguration.cs @@ -37,7 +37,7 @@ public void Configure(EntityTypeBuilder<DispatcherReview> builder) .IsRequired(false); builder - .Property(dr => dr.DistanceTravelledAdjustment) + .Property(dr => dr.FinalMileageAdjustment) .HasPrecision(18, 2) .IsRequired(false); diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241101191151_Rename_DispatcherReview_MileageProperty.Designer.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241101191151_Rename_DispatcherReview_MileageProperty.Designer.cs new file mode 100644 index 00000000..695b4e3e --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241101191151_Rename_DispatcherReview_MileageProperty.Designer.cs @@ -0,0 +1,1066 @@ +// <auto-generated /> +using System; +using CheckDrive.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(CheckDriveDbContext))] + [Migration("20241101191151_Rename_DispatcherReview_MileageProperty")] + partial class Rename_DispatcherReview_MileageProperty + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<decimal>("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<int>("CurrentMonthMileage") + .HasColumnType("int"); + + b.Property<decimal>("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManufacturedYear") + .HasColumnType("int"); + + b.Property<int>("Mileage") + .HasColumnType("int"); + + b.Property<string>("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<string>("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property<decimal>("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<int>("YearlyDistanceLimit") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<int>("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<DateTime>("StartDate") + .HasColumnType("datetime2"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<decimal>("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int?>("ManagerReviewId") + .HasColumnType("int"); + + b.Property<decimal>("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.ToTable("Debt", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DispatcherId") + .HasColumnType("int"); + + b.Property<decimal?>("FinalMileageAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DispatcherId"); + + b.ToTable("DispatcherReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DoctorId") + .HasColumnType("int"); + + b.Property<int>("DriverId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DoctorId"); + + b.HasIndex("DriverId"); + + b.ToTable("DoctorReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<DateTime>("Birthdate") + .HasColumnType("datetime2"); + + b.Property<string>("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property<int>("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator<int>("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal?>("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int?>("DebtId") + .HasColumnType("int"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManagerId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("ManagerId") + .IsUnique(); + + b.ToTable("ManagerReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("FinalMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<decimal>("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicAcceptance", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CarId") + .HasColumnType("int"); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("InitialMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicHandover", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("OilMark", (string)null); + + b.HasData( + new + { + Id = 1, + Name = "80" + }, + new + { + Id = 2, + Name = "85" + }, + new + { + Id = 3, + Name = "90" + }, + new + { + Id = 4, + Name = "95" + }, + new + { + Id = 5, + Name = "100" + }); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal>("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("OilMarkId") + .HasColumnType("int"); + + b.Property<decimal>("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("OperatorId") + .HasColumnType("int"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("OilMarkId"); + + b.HasIndex("OperatorId"); + + b.ToTable("OperatorReview", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "295930c7-eeae-42bd-8312-9fa6856eb180", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }, + new + { + Id = "ea9063eb-e9d0-4206-b1fc-486e4ce04973", + Name = "Driver", + NormalizedName = "DRIVER" + }, + new + { + Id = "d4d28a23-e999-4a29-bd0b-f22031d92696", + Name = "Doctor", + NormalizedName = "DOCTOR" + }, + new + { + Id = "920b29e9-28d2-46ae-a69d-517faf209963", + Name = "Dispatcher", + NormalizedName = "DISPATCHER" + }, + new + { + Id = "1276ec46-c408-4f86-bfb4-6db86e269051", + Name = "Manager", + NormalizedName = "MANAGER" + }, + new + { + Id = "0226a77d-77af-4611-b06b-0b10c1b28c01", + Name = "Mechanic", + NormalizedName = "MECHANIC" + }, + new + { + Id = "ef58c0c1-87ad-4b37-8d22-ec3a94a316c7", + Name = "Operator", + NormalizedName = "OPERATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<int>("AccessFailedCount") + .HasColumnType("int"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<bool>("EmailConfirmed") + .HasColumnType("bit"); + + b.Property<bool>("LockoutEnabled") + .HasColumnType("bit"); + + b.Property<DateTimeOffset?>("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property<string>("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property<string>("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property<string>("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Name") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserToken", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(5); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(2); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(1); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(6); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(3); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(4); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("Debt") + .HasForeignKey("CheckDrive.Domain.Entities.Debt", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DispatcherReview") + .HasForeignKey("CheckDrive.Domain.Entities.DispatcherReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Dispatcher", "Dispatcher") + .WithMany("Reviews") + .HasForeignKey("DispatcherId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Dispatcher"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DoctorReview") + .HasForeignKey("CheckDrive.Domain.Entities.DoctorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Doctor", "Doctor") + .WithMany("Reviews") + .HasForeignKey("DoctorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Driver", "Driver") + .WithMany("Reviews") + .HasForeignKey("DriverId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Doctor"); + + b.Navigation("Driver"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "Account") + .WithOne() + .HasForeignKey("CheckDrive.Domain.Entities.Employee", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Debt", "Debt") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Manager", "Manager") + .WithMany("Reviews") + .HasForeignKey("ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Debt"); + + b.Navigation("Manager"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicAcceptance") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicAcceptance", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Acceptances") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.HasOne("CheckDrive.Domain.Entities.Car", "Car") + .WithMany("Handovers") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicHandover") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicHandover", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Handovers") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Car"); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("OperatorReview") + .HasForeignKey("CheckDrive.Domain.Entities.OperatorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.OilMark", "OilMark") + .WithMany("Reviews") + .HasForeignKey("OilMarkId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Operator", "Operator") + .WithMany("Reviews") + .HasForeignKey("OperatorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("OilMark"); + + b.Navigation("Operator"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Navigation("Debt"); + + b.Navigation("DispatcherReview"); + + b.Navigation("DoctorReview") + .IsRequired(); + + b.Navigation("ManagerReview"); + + b.Navigation("MechanicAcceptance"); + + b.Navigation("MechanicHandover"); + + b.Navigation("OperatorReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Navigation("ManagerReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.Navigation("Acceptances"); + + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.Navigation("Reviews"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241101191151_Rename_DispatcherReview_MileageProperty.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241101191151_Rename_DispatcherReview_MileageProperty.cs new file mode 100644 index 00000000..8f06318b --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241101191151_Rename_DispatcherReview_MileageProperty.cs @@ -0,0 +1,30 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + /// <inheritdoc /> + public partial class Rename_DispatcherReview_MileageProperty : Migration + { + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "DistanceTravelledAdjustment", + table: "DispatcherReview", + newName: "FinalMileageAdjustment"); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "FinalMileageAdjustment", + table: "DispatcherReview", + newName: "DistanceTravelledAdjustment"); + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs index 6a43f3ba..53e52716 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs @@ -161,7 +161,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property<int>("DispatcherId") .HasColumnType("int"); - b.Property<decimal?>("DistanceTravelledAdjustment") + b.Property<decimal?>("FinalMileageAdjustment") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -519,43 +519,43 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "3ad70054-4ee0-416d-929a-6d800fa98941", + Id = "295930c7-eeae-42bd-8312-9fa6856eb180", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "a6486ce6-0af2-488d-a609-76ac62ba6203", + Id = "ea9063eb-e9d0-4206-b1fc-486e4ce04973", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "0bbd5156-7c75-4b84-a7d9-5e21910bf14f", + Id = "d4d28a23-e999-4a29-bd0b-f22031d92696", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "765d20d4-f255-4553-bb5d-f9f87c4360f5", + Id = "920b29e9-28d2-46ae-a69d-517faf209963", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "5a9d0f60-922f-405f-8abd-14c9dee446a1", + Id = "1276ec46-c408-4f86-bfb4-6db86e269051", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "ccc36987-fb1e-4a20-9d0d-acdcc0204baa", + Id = "0226a77d-77af-4611-b06b-0b10c1b28c01", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "b5ea687f-a694-4901-95f0-310000949351", + Id = "ef58c0c1-87ad-4b37-8d22-ec3a94a316c7", Name = "Operator", NormalizedName = "OPERATOR" }); From fdd36de31f1eaef00d3a6f25ef30daac9ee3a3c0 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 22:00:45 +0500 Subject: [PATCH 29/40] include logs folder --- CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj b/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj index 963bfcc6..9ac5645d 100644 --- a/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj +++ b/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj @@ -34,4 +34,8 @@ <ProjectReference Include="..\CheckDrive.TestDataCreator\CheckDrive.TestDataCreator.csproj" /> </ItemGroup> + <ItemGroup> + <Folder Include="logs\" /> + </ItemGroup> + </Project> From d990cf41e78093fed7b71e80667e59436584ffc8 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 22:01:39 +0500 Subject: [PATCH 30/40] implement CRUD operations for Cars Add DTOs, Validators, Controller Endpoints & Service implementations with query parameters --- .../Controllers/CarsController.cs | 42 ++++++++- .../DTOs/Car/CreateCarDto.cs | 13 +++ .../DTOs/Car/UpdateCarDto.cs | 17 ++++ .../Interfaces/ICarService.cs | 6 ++ .../QueryParameters/CarQueryParameters.cs | 7 ++ .../Services/CarService.cs | 91 ++++++++++++++++++- .../Validators/Car/CreateCarValidator.cs | 48 ++++++++++ .../Validators/Car/UpdateCarValidator.cs | 51 +++++++++++ 8 files changed, 272 insertions(+), 3 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/QueryParameters/CarQueryParameters.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs index eb1e3231..62159875 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs @@ -1,5 +1,6 @@ using CheckDrive.Application.DTOs.Car; using CheckDrive.Application.Interfaces; +using CheckDrive.Application.QueryParameters; using Microsoft.AspNetCore.Mvc; namespace CheckDrive.Api.Controllers; @@ -16,10 +17,47 @@ public CarsController(ICarService carService) } [HttpGet] - public async Task<ActionResult<List<CarDto>>> GetAvailableCars() + public async Task<ActionResult<List<CarDto>>> GetAllAsync(CarQueryParameters queryParameters) { - var cars = await _carService.GetAvailableCarsAsync(); + var cars = await _carService.GetAllAsync(queryParameters); return Ok(cars); } + + [HttpGet("{id:int}", Name = "GetCarByIdAsync")] + public async Task<ActionResult<CarDto>> GetByIdAsync(int id) + { + var car = await _carService.GetByIdAsync(id); + + return Ok(car); + } + + [HttpPost] + public async Task<ActionResult<CarDto>> CreateAsync(CreateCarDto car) + { + var createdCar = await _carService.CreateAsync(car); + + return CreatedAtAction("GetCarByIdAsync", createdCar, new { id = createdCar.Id }); + } + + [HttpPut("{id:int}")] + public async Task<ActionResult<CarDto>> UpdateAsync(int id, UpdateCarDto car) + { + if (id != car.Id) + { + return BadRequest($"Route parameter id: {id} does not match with body parameter id: {car.Id}."); + } + + var updatedCar = await _carService.UpdateAsync(car); + + return Ok(updatedCar); + } + + [HttpDelete("{id:int}")] + public async Task<ActionResult> DeleteAsync(int id) + { + await _carService.DeleteAsync(id); + + return NoContent(); + } } diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs new file mode 100644 index 00000000..5a0b8cbf --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs @@ -0,0 +1,13 @@ +namespace CheckDrive.Application.DTOs.Car; + +public record CreateCarDto( + string Model, + string Color, + string Number, + int ManufacturedYear, + int Mileage, + int CurrentMonthMileage, + int YearlyDistanceLimit, + decimal AverageFuelConsumption, + decimal FuelCapacity, + decimal RemainingFuel); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs new file mode 100644 index 00000000..697f11f6 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs @@ -0,0 +1,17 @@ +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.Car; + +public record UpdateCarDto( + int Id, + string Model, + string Color, + string Number, + int ManufacturedYear, + int Mileage, + int CurrentMonthMileage, + int YearlyDistanceLimit, + decimal AverageFuelConsumption, + decimal FuelCapacity, + decimal RemainingFuel, + CarStatus Status); diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs index a812f05f..d7b3b75e 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs @@ -1,8 +1,14 @@ using CheckDrive.Application.DTOs.Car; +using CheckDrive.Application.QueryParameters; namespace CheckDrive.Application.Interfaces; public interface ICarService { + Task<List<CarDto>> GetAllAsync(CarQueryParameters queryParameters); Task<List<CarDto>> GetAvailableCarsAsync(); + Task<CarDto> GetByIdAsync(int id); + Task<CarDto> CreateAsync(CreateCarDto car); + Task<CarDto> UpdateAsync(UpdateCarDto car); + Task DeleteAsync(int id); } diff --git a/CheckDrive.Api/CheckDrive.Application/QueryParameters/CarQueryParameters.cs b/CheckDrive.Api/CheckDrive.Application/QueryParameters/CarQueryParameters.cs new file mode 100644 index 00000000..88aafe59 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/QueryParameters/CarQueryParameters.cs @@ -0,0 +1,7 @@ +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.QueryParameters; + +public record CarQueryParameters( + string? SearchText, + CarStatus? Status); diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs index 89f9e6f0..e4f0db96 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs @@ -1,8 +1,11 @@ using AutoMapper; +using Microsoft.EntityFrameworkCore; using CheckDrive.Application.DTOs.Car; using CheckDrive.Application.Interfaces; using CheckDrive.Domain.Interfaces; -using Microsoft.EntityFrameworkCore; +using CheckDrive.Domain.Exceptions; +using CheckDrive.Domain.Entities; +using CheckDrive.Application.QueryParameters; namespace CheckDrive.Application.Services; @@ -26,4 +29,90 @@ public async Task<List<CarDto>> GetAvailableCarsAsync() return dtos; } + + public async Task<List<CarDto>> GetAllAsync(CarQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.Cars + .AsNoTracking() + .AsQueryable(); + + if (!string.IsNullOrEmpty(queryParameters.SearchText)) + { + query = query.Where(x => x.Model.Contains(queryParameters.SearchText) + || x.Color.Contains(queryParameters.SearchText) + || x.Number.Contains(queryParameters.SearchText)); + } + + if (queryParameters.Status.HasValue) + { + query = query.Where(x => x.Status == queryParameters.Status); + } + + var entities = await query.ToListAsync(); + var dtos = _mapper.Map<List<CarDto>>(entities); + + return dtos; + } + + public async Task<CarDto> GetByIdAsync(int id) + { + var car = await _context.Cars.FirstOrDefaultAsync(x => x.Id == id); + + if (car is null) + { + throw new EntityNotFoundException($"Car with id: {id} is not found."); + } + + var dto = _mapper.Map<CarDto>(car); + + return dto; + } + + public async Task<CarDto> CreateAsync(CreateCarDto car) + { + ArgumentNullException.ThrowIfNull(car); + + var entity = _mapper.Map<Car>(car); + + _context.Cars.Add(entity); + await _context.SaveChangesAsync(); + + var dto = _mapper.Map<CarDto>(entity); + + return dto; + } + + public async Task<CarDto> UpdateAsync(UpdateCarDto car) + { + ArgumentNullException.ThrowIfNull(car); + + if (!await _context.Cars.AnyAsync(x => x.Id == car.Id)) + { + throw new EntityNotFoundException($"Car with id: {car.Id} is not found."); + } + + var entity = _mapper.Map<Car>(car); + + _context.Cars.Update(entity); + await _context.SaveChangesAsync(); + + var dto = _mapper.Map<CarDto>(entity); + + return dto; + } + + public async Task DeleteAsync(int id) + { + var entity = await _context.Cars.FirstOrDefaultAsync(x => x.Id == id); + + if (entity is null) + { + throw new EntityNotFoundException($"Car with id: {id} is not found."); + } + + _context.Cars.Remove(entity); + await _context.SaveChangesAsync(); + } } diff --git a/CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs b/CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs new file mode 100644 index 00000000..6f36c0d1 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs @@ -0,0 +1,48 @@ +using CheckDrive.Application.DTOs.Car; +using FluentValidation; + +namespace CheckDrive.Application.Validators.Car; + +public sealed class CreateCarValidator : AbstractValidator<CreateCarDto> +{ + public CreateCarValidator() + { + RuleFor(x => x.Model) + .NotEmpty() + .WithMessage("Car model must be specified."); + + RuleFor(x => x.Color) + .NotEmpty() + .WithMessage("Car color must be specified."); + + RuleFor(x => x.Number) + .NotEmpty() + .WithMessage("Car number must be specified."); + + RuleFor(x => x.ManufacturedYear) + .GreaterThan(1900) + .LessThan(2026) + .WithMessage(x => $"Invalid manufactured year: {x.ManufacturedYear}."); + + RuleFor(x => x.Mileage) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid mileage valule {x.Mileage}."); + + RuleFor(x => x.YearlyDistanceLimit) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid yearly limit value: {x.YearlyDistanceLimit}."); + + RuleFor(x => x.AverageFuelConsumption) + .GreaterThan(0) + .WithMessage(x => $"Invalid average fuel consumption value: {x.AverageFuelConsumption}."); + + RuleFor(x => x.FuelCapacity) + .GreaterThan(0) + .WithMessage(x => $"Invalid fuel capacity value: {x.FuelCapacity}."); + + RuleFor(x => x.RemainingFuel) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid remaining fuel value: {x.RemainingFuel}."); + + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs b/CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs new file mode 100644 index 00000000..b304b767 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs @@ -0,0 +1,51 @@ +using CheckDrive.Application.DTOs.Car; +using FluentValidation; + +namespace CheckDrive.Application.Validators.Car; + +public sealed class UpdateCarValidator : AbstractValidator<UpdateCarDto> +{ + public UpdateCarValidator() + { + RuleFor(x => x.Id) + .GreaterThanOrEqualTo(1) + .WithMessage(x => $"Invalid car id: {x.Id}."); + + RuleFor(x => x.Model) + .NotEmpty() + .WithMessage("Car model must be specified."); + + RuleFor(x => x.Color) + .NotEmpty() + .WithMessage("Car color must be specified."); + + RuleFor(x => x.Number) + .NotEmpty() + .WithMessage("Car number must be specified."); + + RuleFor(x => x.ManufacturedYear) + .GreaterThan(1900) + .LessThan(2026) + .WithMessage(x => $"Invalid manufactured year: {x.ManufacturedYear}."); + + RuleFor(x => x.Mileage) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid mileage valule {x.Mileage}."); + + RuleFor(x => x.YearlyDistanceLimit) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid yearly limit value: {x.YearlyDistanceLimit}."); + + RuleFor(x => x.AverageFuelConsumption) + .GreaterThan(0) + .WithMessage(x => $"Invalid average fuel consumption value: {x.AverageFuelConsumption}."); + + RuleFor(x => x.FuelCapacity) + .GreaterThan(0) + .WithMessage(x => $"Invalid fuel capacity value: {x.FuelCapacity}."); + + RuleFor(x => x.RemainingFuel) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid remaining fuel value: {x.RemainingFuel}."); + } +} From 50f864ea59571e99cc0220effad36bb8a9e5afac Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 22:02:29 +0500 Subject: [PATCH 31/40] implement CRUD operations for Oil Marks Add Controller endpoints, DTOs, Validators and Service implementations with query parameters. --- .../Controllers/OilMarksController.cs | 42 +++++++++- .../DTOs/OilMark/CreateOilMarkDto.cs | 3 + .../DTOs/OilMark/UpdateOilMarkDto.cs | 3 + .../Interfaces/IOilMarkService.cs | 7 +- .../QueryParameters/OilMarkQueryParameters.cs | 3 + .../Services/OilMarkService.cs | 84 ++++++++++++++++++- .../OilMark/CreateOilMarkValidator.cs | 14 ++++ .../OilMark/UpdateOilMarkValidator.cs | 18 ++++ 8 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/CreateOilMarkDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/UpdateOilMarkDto.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/QueryParameters/OilMarkQueryParameters.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Validators/OilMark/CreateOilMarkValidator.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Validators/OilMark/UpdateOilMarkValidator.cs diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs index ff6a43ec..53c37b78 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs @@ -1,5 +1,6 @@ using CheckDrive.Application.DTOs.OilMark; using CheckDrive.Application.Interfaces; +using CheckDrive.Application.QueryParameters; using Microsoft.AspNetCore.Mvc; namespace CheckDrive.Api.Controllers; @@ -16,10 +17,47 @@ public OilMarksController(IOilMarkService oilMarkService) } [HttpGet] - public async Task<ActionResult<List<OilMarkDto>>> GetAsync() + public async Task<ActionResult<List<OilMarkDto>>> GetAsync(OilMarkQueryParameters queryParameters) { - var oilMarks = await _oilMarkService.GetAllAsync(); + var oilMarks = await _oilMarkService.GetAllAsync(queryParameters); return Ok(oilMarks); } + + [HttpGet("{id:int}", Name = "GetOilMarkById")] + public async Task<ActionResult<OilMarkDto>> GetByIdAsync(int id) + { + var oilMark = await _oilMarkService.GetByIdAsync(id); + + return oilMark; + } + + [HttpPost] + public async Task<ActionResult<OilMarkDto>> CreateAsync(CreateOilMarkDto oilMark) + { + var createdOilMark = await _oilMarkService.CreateAsync(oilMark); + + return CreatedAtAction("GetOilMarkById", oilMark, new { id = createdOilMark.Id }); + } + + [HttpPut("{id:int}")] + public async Task<ActionResult<OilMarkDto>> UpdateAsync(int id, UpdateOilMarkDto oilMark) + { + if (id != oilMark.Id) + { + return BadRequest($"Route parameter id: {id} does not match with body parameter id: {oilMark.Id}."); + } + + var updatedOilMark = await _oilMarkService.UpdateAsync(oilMark); + + return Ok(updatedOilMark); + } + + [HttpDelete("{id:int}")] + public async Task<ActionResult> DeleteAsync(int id) + { + await _oilMarkService.DeleteAsync(id); + + return NoContent(); + } } diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/CreateOilMarkDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/CreateOilMarkDto.cs new file mode 100644 index 00000000..7d6d7de0 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/CreateOilMarkDto.cs @@ -0,0 +1,3 @@ +namespace CheckDrive.Application.DTOs.OilMark; + +public sealed record CreateOilMarkDto(string Name); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/UpdateOilMarkDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/UpdateOilMarkDto.cs new file mode 100644 index 00000000..d6b15722 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/UpdateOilMarkDto.cs @@ -0,0 +1,3 @@ +namespace CheckDrive.Application.DTOs.OilMark; + +public sealed record UpdateOilMarkDto(int Id, string Name); diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs index 81b97b69..74ce90ed 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs @@ -1,8 +1,13 @@ using CheckDrive.Application.DTOs.OilMark; +using CheckDrive.Application.QueryParameters; namespace CheckDrive.Application.Interfaces; public interface IOilMarkService { - Task<List<OilMarkDto>> GetAllAsync(); + Task<List<OilMarkDto>> GetAllAsync(OilMarkQueryParameters queryParameters); + Task<OilMarkDto> GetByIdAsync(int id); + Task<OilMarkDto> CreateAsync(CreateOilMarkDto oilMark); + Task<OilMarkDto> UpdateAsync(UpdateOilMarkDto oilMark); + Task DeleteAsync(int id); } diff --git a/CheckDrive.Api/CheckDrive.Application/QueryParameters/OilMarkQueryParameters.cs b/CheckDrive.Api/CheckDrive.Application/QueryParameters/OilMarkQueryParameters.cs new file mode 100644 index 00000000..f8a0f9e9 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/QueryParameters/OilMarkQueryParameters.cs @@ -0,0 +1,3 @@ +namespace CheckDrive.Application.QueryParameters; + +public sealed record OilMarkQueryParameters(string? SearchText); diff --git a/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs b/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs index 03d0ae42..abfda0ef 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs @@ -1,5 +1,9 @@ -using CheckDrive.Application.DTOs.OilMark; +using AutoMapper; +using CheckDrive.Application.DTOs.OilMark; using CheckDrive.Application.Interfaces; +using CheckDrive.Application.QueryParameters; +using CheckDrive.Domain.Entities; +using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; using Microsoft.EntityFrameworkCore; @@ -8,12 +12,40 @@ namespace CheckDrive.Application.Services; internal sealed class OilMarkService : IOilMarkService { private readonly ICheckDriveDbContext _context; + private readonly IMapper _mapper; - public OilMarkService(ICheckDriveDbContext context) + public OilMarkService(ICheckDriveDbContext context, IMapper mapper) { _context = context ?? throw new ArgumentNullException(nameof(context)); } + public async Task<OilMarkDto> CreateAsync(CreateOilMarkDto oilMark) + { + ArgumentNullException.ThrowIfNull(oilMark); + + var entity = _mapper.Map<OilMark>(oilMark); + + _context.OilMarks.Add(entity); + await _context.SaveChangesAsync(); + + var dto = _mapper.Map<OilMarkDto>(entity); + + return dto; + } + + public async Task DeleteAsync(int id) + { + var entity = await _context.OilMarks.FirstOrDefaultAsync(x => x.Id == id); + + if (entity is null) + { + throw new EntityNotFoundException($"Oil mark with id: {id} is not found."); + } + + _context.OilMarks.Remove(entity); + await _context.SaveChangesAsync(); + } + public Task<List<OilMarkDto>> GetAllAsync() { var oilMarks = _context.OilMarks @@ -22,4 +54,52 @@ public Task<List<OilMarkDto>> GetAllAsync() return oilMarks; } + + public async Task<List<OilMarkDto>> GetAllAsync(OilMarkQueryParameters queryParameters) + { + ArgumentNullException.ThrowIfNull(queryParameters); + + var query = _context.OilMarks.AsNoTracking().AsQueryable(); + + if (!string.IsNullOrEmpty(queryParameters.SearchText)) + { + query = query.Where(x => x.Name.Contains(queryParameters.SearchText)); + } + + var entities = await query.ToListAsync(); + var dtos = _mapper.Map<List<OilMarkDto>>(entities); + + return dtos; + } + + public async Task<OilMarkDto> GetByIdAsync(int id) + { + var entity = await _context.OilMarks.FirstOrDefaultAsync(x => x.Id == id); + + if (entity is null) + { + throw new EntityNotFoundException($"Oil mark with id: {id} is not found."); + } + + var dto = _mapper.Map<OilMarkDto>(entity); + + return dto; + } + + public async Task<OilMarkDto> UpdateAsync(UpdateOilMarkDto oilMark) + { + if (!await _context.OilMarks.AnyAsync(x => x.Id == oilMark.Id)) + { + throw new EntityNotFoundException($"Oil mark with id: {oilMark.Id} is not found."); + } + + var entity = _mapper.Map<OilMark>(oilMark); + + _context.OilMarks.Update(entity); + await _context.SaveChangesAsync(); + + var dto = _mapper.Map<OilMarkDto>(entity); + + return dto; + } } diff --git a/CheckDrive.Api/CheckDrive.Application/Validators/OilMark/CreateOilMarkValidator.cs b/CheckDrive.Api/CheckDrive.Application/Validators/OilMark/CreateOilMarkValidator.cs new file mode 100644 index 00000000..2435c6d0 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Validators/OilMark/CreateOilMarkValidator.cs @@ -0,0 +1,14 @@ +using FluentValidation; +using CheckDrive.Application.DTOs.OilMark; + +namespace CheckDrive.Application.Validators.OilMark; + +public sealed class CreateOilMarkValidator : AbstractValidator<CreateOilMarkDto> +{ + public CreateOilMarkValidator() + { + RuleFor(x => x.Name) + .NotEmpty() + .WithMessage("Oil mark should be specified."); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Validators/OilMark/UpdateOilMarkValidator.cs b/CheckDrive.Api/CheckDrive.Application/Validators/OilMark/UpdateOilMarkValidator.cs new file mode 100644 index 00000000..636b9826 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Validators/OilMark/UpdateOilMarkValidator.cs @@ -0,0 +1,18 @@ +using FluentValidation; +using CheckDrive.Application.DTOs.OilMark; + +namespace CheckDrive.Application.Validators.OilMark; + +public sealed class UpdateOilMarkValidator : AbstractValidator<UpdateOilMarkDto> +{ + public UpdateOilMarkValidator() + { + RuleFor(x => x.Id) + .GreaterThanOrEqualTo(1) + .WithMessage(x => $"Invalid oil mark id: {x.Id}."); + + RuleFor(x => x.Name) + .NotEmpty() + .WithMessage("Oil mark name should be specified."); + } +} From cd8fa491ecce20d174d697a1527a8ef000cf404d Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 22:03:01 +0500 Subject: [PATCH 32/40] minor code quality improvements --- .../Controllers/Reviews/ReviewHistoriesController.cs | 4 ++-- .../DispatcherReview/CreateDispatcherReviewDto.cs | 2 +- .../CheckDrive.Application/Services/AccountService.cs | 11 +++++++---- .../Services/CheckPointService.cs | 2 +- .../CheckDrive.Application/Services/DriverService.cs | 1 + 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs index dafd8ab0..f8d66138 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs @@ -1,9 +1,9 @@ -using CheckDrive.Application.DTOs.CheckPoint; +using Microsoft.AspNetCore.Mvc; +using CheckDrive.Application.DTOs.CheckPoint; using CheckDrive.Application.DTOs.DoctorReview; using CheckDrive.Application.DTOs.OperatorReview; using CheckDrive.Application.DTOs.Review; using CheckDrive.Application.Interfaces.Review; -using Microsoft.AspNetCore.Mvc; namespace CheckDrive.Api.Controllers.Reviews; diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/DispatcherReview/CreateDispatcherReviewDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/DispatcherReview/CreateDispatcherReviewDto.cs index 2420f0b7..b3ef43ab 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/DispatcherReview/CreateDispatcherReviewDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/DispatcherReview/CreateDispatcherReviewDto.cs @@ -8,7 +8,7 @@ public sealed record CreateDispatcherReviewDto( string? Notes, bool IsApprovedByReviewer, decimal? FuelConsumptionAdjustment, - int? DistanceTravelledAdjustment) + int? FinalMileageAdjustment) : CreateReviewDtoBase( ReviewerId: ReviewerId, Notes: Notes, diff --git a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs index f20b7f29..5f0d44f4 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs @@ -1,4 +1,6 @@ using AutoMapper; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; using CheckDrive.Application.Constants; using CheckDrive.Application.DTOs.Account; using CheckDrive.Application.Interfaces; @@ -6,18 +8,19 @@ using CheckDrive.Domain.Enums; using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; -using Microsoft.AspNetCore.Identity; -using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services; internal sealed class AccountService : IAccountService { private readonly ICheckDriveDbContext _context; - private readonly UserManager<IdentityUser> _userManager; private readonly IMapper _mapper; + private readonly UserManager<IdentityUser> _userManager; - public AccountService(ICheckDriveDbContext context, IMapper mapper, UserManager<IdentityUser> userManager) + public AccountService( + ICheckDriveDbContext context, + IMapper mapper, + UserManager<IdentityUser> userManager) { _context = context ?? throw new ArgumentNullException(nameof(context)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs index aed29021..a9bf937e 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs @@ -1,4 +1,5 @@ using AutoMapper; +using Microsoft.EntityFrameworkCore; using CheckDrive.Application.DTOs.CheckPoint; using CheckDrive.Application.Interfaces; using CheckDrive.Domain.Entities; @@ -6,7 +7,6 @@ using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; using CheckDrive.Domain.QueryParameters; -using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services; diff --git a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs index 710ad103..bdf4ed27 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs @@ -118,6 +118,7 @@ private async Task AcceptMechanicAcceptanceAsync(CheckPoint checkPoint) car.Mileage = checkPoint.MechanicAcceptance.FinalMileage; car.RemainingFuel = checkPoint.MechanicAcceptance.RemainingFuelAmount; car.CurrentMonthMileage += checkPoint.MechanicHandover.InitialMileage - checkPoint.MechanicAcceptance.FinalMileage; + checkPoint.Stage = CheckPointStage.MechanicAcceptance; checkPoint.MechanicAcceptance.Status = ReviewStatus.Approved; } From 18a9a88cebe61ad25d2c25fd9c9a24c4da9dc328 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 22:03:11 +0500 Subject: [PATCH 33/40] register validators & mappings --- .../Extensions/DependencyInjection.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs index 44f6248b..989d61a2 100644 --- a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs @@ -1,11 +1,14 @@ -using CheckDrive.Application.Interfaces.Review; +using FluentValidation; +using Microsoft.Extensions.DependencyInjection; +using CheckDrive.Application.Interfaces.Review; using CheckDrive.Application.Interfaces; using CheckDrive.Application.Services; using CheckDrive.Application.Services.Review; -using Microsoft.Extensions.DependencyInjection; using CheckDrive.Application.Interfaces.Auth; using CheckDrive.Application.Services.Auth; using CheckDrive.Application.BackgroundJobs; +using CheckDrive.Application.Validators.Car; +using CheckDrive.Application.Mappings; namespace CheckDrive.Application.Extensions; @@ -13,8 +16,10 @@ public static class DependencyInjection { public static IServiceCollection RegisterApplication(this IServiceCollection services) { + services.AddAutoMapper(typeof(CarMappings).Assembly); + services.AddValidatorsFromAssemblyContaining<CreateCarValidator>(); + AddServices(services); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); return services; } From 605a1aa7781e58bdd667a0eac134c9da3b2c1463 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 22:05:14 +0500 Subject: [PATCH 34/40] Update DispatcherReviewService.cs --- .../Review/DispatcherReviewService.cs | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs index 6ab22fef..19568b3b 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs @@ -27,9 +27,7 @@ public async Task<DispatcherReviewDto> CreateAsync(CreateDispatcherReviewDto rev var checkPoint = await GetAndValidateCheckPointAsync(review.CheckPointId); var dispatcher = await GetAndValidateDispatcherAsync(review.ReviewerId); - UpdateCheckPoint(checkPoint, review); - - var reviewEntity = CreateReviewEntity(checkPoint, dispatcher, review); + var reviewEntity = CreateReview(checkPoint, dispatcher, review); _context.DispatcherReviews.Add(reviewEntity); await _context.SaveChangesAsync(); @@ -80,9 +78,10 @@ private async Task<Dispatcher> GetAndValidateDispatcherAsync(int dispatcherId) return dispatcher; } - private static DispatcherReview CreateReviewEntity(CheckPoint checkPoint, Dispatcher dispatcher, CreateDispatcherReviewDto review) + private static DispatcherReview CreateReview(CheckPoint checkPoint, Dispatcher dispatcher, CreateDispatcherReviewDto review) { ArgumentNullException.ThrowIfNull(checkPoint); + ArgumentNullException.ThrowIfNull(dispatcher); var entity = new DispatcherReview { @@ -92,7 +91,7 @@ private static DispatcherReview CreateReviewEntity(CheckPoint checkPoint, Dispat Date = DateTime.UtcNow, Status = review.IsApprovedByReviewer ? ReviewStatus.Approved : ReviewStatus.RejectedByReviewer, FuelConsumptionAdjustment = review.FuelConsumptionAdjustment, - FinalMileageAdjustment = review.DistanceTravelledAdjustment, + FinalMileageAdjustment = review.FinalMileageAdjustment, }; return entity; @@ -104,18 +103,23 @@ private static void UpdateCheckPoint(CheckPoint checkPoint, CreateDispatcherRevi checkPoint.Stage = CheckPointStage.DispatcherReview; - if (review.FuelConsumptionAdjustment.HasValue || review.DistanceTravelledAdjustment.HasValue) + if (!review.IsApprovedByReviewer) { - checkPoint.Stage = CheckPointStage.ManagerReview; + checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; return; } - if (!review.IsApprovedByReviewer) + if (review.FuelConsumptionAdjustment.HasValue || review.FinalMileageAdjustment.HasValue) { - checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; + checkPoint.Status = CheckPointStatus.PendingManagerReview; return; } checkPoint.Status = CheckPointStatus.Completed; } + + private async Task UpdateCarAsync(CheckPoint checkPoint) + { + ArgumentNullException.ThrowIfNull(checkPoint); + } } From a0db18c92fdfd567bb5a62c0a98764c62549a757 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 22:05:43 +0500 Subject: [PATCH 35/40] eagerly load doctors & driver in history service --- .../CheckDrive.Application/Services/ReviewHistoryService.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs b/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs index d2038f5e..8387484e 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs @@ -29,6 +29,8 @@ public async Task<List<CheckPointDto>> GetDriverHistoriesAsync(int driverId) .Where(x => x.Status == CheckPointStatus.Completed || x.Status == CheckPointStatus.AutomaticallyClosed) .Include(x => x.DoctorReview) .ThenInclude(x => x.Doctor) + .Include(x => x.DoctorReview) + .ThenInclude(x => x.Driver) .Include(x => x.MechanicHandover) .ThenInclude(x => x.Mechanic) .Include(x => x.MechanicHandover) @@ -54,6 +56,7 @@ public async Task<List<CheckPointDto>> GetDriverHistoriesAsync(int driverId) public async Task<List<DoctorReviewDto>> GetDoctorHistoriesAsync(int doctorId) { var reviews = await _context.DoctorReviews + .Include(x => x.Driver) .Where(x => x.DoctorId == doctorId) .ToListAsync(); From 2f03c11229be62a465ae6870a44dd92af76738d9 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 22:32:55 +0500 Subject: [PATCH 36/40] allow cancelling check point --- .../Controllers/CheckPointsController.cs | 8 ++++++ .../Interfaces/ICheckPointService.cs | 1 + .../Services/CheckPointService.cs | 25 +++++++++++++++++++ .../Services/DriverService.cs | 2 +- .../Enums/CheckPointStatus.cs | 2 +- 5 files changed, 36 insertions(+), 2 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs index d7bcb05b..7ed0264b 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs @@ -31,4 +31,12 @@ public async Task<ActionResult<CheckPointDto>> GetCurrentCheckPointByDriverIdAsy return Ok(checkPoint); } + + [HttpPut("{id:int}/cancel")] + public async Task<ActionResult<CheckPointDto>> CancelCheckPoint(int id) + { + await _service.CancelCheckPointAsync(id); + + return NoContent(); + } } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs index a8980400..1c2d1395 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs @@ -7,4 +7,5 @@ public interface ICheckPointService { Task<List<CheckPointDto>> GetCheckPointsAsync(CheckPointQueryParameters queryParameters); Task<CheckPointDto> GetCurrentCheckPointByDriverIdAsync(int driverId); + Task CancelCheckPointAsync(int id); } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs index a9bf937e..4edf3bcd 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs @@ -51,6 +51,19 @@ public async Task<CheckPointDto> GetCurrentCheckPointByDriverIdAsync(int driverI return dto; } + public async Task CancelCheckPointAsync(int id) + { + var checkPoint = await GetAndValidateAsync(id); + + if (checkPoint.Status == CheckPointStatus.Completed || checkPoint.Status == CheckPointStatus.AutomaticallyClosed) + { + throw new InvalidOperationException($"Cannot cancel closed Check Point."); + } + + checkPoint.Status = CheckPointStatus.ClosedByManager; + await _context.SaveChangesAsync(); + } + private IQueryable<CheckPoint> GetQuery(CheckPointQueryParameters? queryParameters = null) { var query = _context.CheckPoints @@ -121,4 +134,16 @@ private static IQueryable<CheckPoint> FilterByDate(IQueryable<CheckPoint> query, _ => throw new ArgumentOutOfRangeException($"Date filter: {dateFilter} is not implemented yet."), }; } + + private async Task<CheckPoint> GetAndValidateAsync(int id) + { + var checkPoint = await _context.CheckPoints.FirstOrDefaultAsync(x => x.Id == id); + + if (checkPoint is null) + { + throw new EntityNotFoundException($"Check Point with id: {id} is not found."); + } + + return checkPoint; + } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs index bdf4ed27..3f109e7e 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs @@ -20,7 +20,7 @@ public DriverService(ICheckDriveDbContext context) public async Task<List<DriverDto>> GetAvailableDriversAsync() { var drivers = await _context.Drivers - .Where(x => !x.Reviews.Any(x => x.Date.Date == DateTime.UtcNow.Date)) + .Where(x => !x.Reviews.Any(x => x.CheckPoint.Status == CheckPointStatus.InProgress)) .Select(x => new DriverDto(x.Id, x.AccountId, x.FirstName + " " + x.LastName)) .ToListAsync(); diff --git a/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs b/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs index 475e27fe..b82defa1 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs @@ -7,5 +7,5 @@ public enum CheckPointStatus InterruptedByReviewerRejection = 2, InterruptedByDriverRejection = 3, AutomaticallyClosed = 4, - PendingManagerReview = 5, + ClosedByManager = 5, } From 9a50d0dfb7ba8d453b5e944e0b83d72e66f3b3c9 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Sun, 10 Nov 2024 23:50:33 +0500 Subject: [PATCH 37/40] remove dead code, fix invalid logics & update mappings --- .../Mappings/CarMappings.cs | 2 + .../Mappings/OilMarkMappings.cs | 15 ++++++ .../Mappings/Reviews/DoctorReviewMappings.cs | 9 +--- .../Reviews/MechanicHandoverMappings.cs | 3 +- .../Services/CarService.cs | 15 +++--- .../Services/DriverService.cs | 43 ++++++++++------- .../Services/EmployeeMappings.cs | 14 ++++++ .../Review/DispatcherReviewService.cs | 47 +++++++------------ .../Services/Review/DoctorReviewService.cs | 13 +++-- .../Review/MechanicHandoverService.cs | 42 +++++++++-------- .../Enums/CheckPointStatus.cs | 3 +- .../CheckDrive.Domain/Enums/DebtStatus.cs | 3 +- .../Exceptions/CarUnavailableException.cs | 7 +++ .../Exceptions/UnavailableCarException.cs | 7 --- 14 files changed, 129 insertions(+), 94 deletions(-) create mode 100644 CheckDrive.Api/CheckDrive.Application/Mappings/OilMarkMappings.cs create mode 100644 CheckDrive.Api/CheckDrive.Application/Services/EmployeeMappings.cs create mode 100644 CheckDrive.Api/CheckDrive.Domain/Exceptions/CarUnavailableException.cs delete mode 100644 CheckDrive.Api/CheckDrive.Domain/Exceptions/UnavailableCarException.cs diff --git a/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs b/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs index 7c920a23..67b1778e 100644 --- a/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs +++ b/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs @@ -9,5 +9,7 @@ public sealed class CarMappings : Profile public CarMappings() { CreateMap<Car, CarDto>(); + CreateMap<CreateCarDto, Car>(); + CreateMap<UpdateCarDto, Car>(); } } diff --git a/CheckDrive.Api/CheckDrive.Application/Mappings/OilMarkMappings.cs b/CheckDrive.Api/CheckDrive.Application/Mappings/OilMarkMappings.cs new file mode 100644 index 00000000..8df8753f --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Mappings/OilMarkMappings.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using CheckDrive.Application.DTOs.OilMark; +using CheckDrive.Domain.Entities; + +namespace CheckDrive.Application.Mappings; + +public sealed class OilMarkMappings : Profile +{ + public OilMarkMappings() + { + CreateMap<OilMark, OilMarkDto>(); + CreateMap<CreateOilMarkDto, OilMark>(); + CreateMap<UpdateOilMarkDto, OilMark>(); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Mappings/Reviews/DoctorReviewMappings.cs b/CheckDrive.Api/CheckDrive.Application/Mappings/Reviews/DoctorReviewMappings.cs index a8917df3..b707cc34 100644 --- a/CheckDrive.Api/CheckDrive.Application/Mappings/Reviews/DoctorReviewMappings.cs +++ b/CheckDrive.Api/CheckDrive.Application/Mappings/Reviews/DoctorReviewMappings.cs @@ -1,7 +1,6 @@ using AutoMapper; using CheckDrive.Application.DTOs.DoctorReview; using CheckDrive.Domain.Entities; -using CheckDrive.Domain.Enums; namespace CheckDrive.Application.Mappings.Reviews; @@ -10,13 +9,7 @@ internal sealed class DoctorReviewMappings : Profile public DoctorReviewMappings() { CreateMap<DoctorReview, DoctorReviewDto>() - .ForCtorParam(nameof(DoctorReviewDto.DriverId), cfg => cfg.MapFrom(e => e.CheckPoint.DoctorReview.DriverId)) - .ForCtorParam(nameof(DoctorReviewDto.DriverName), cfg => cfg.MapFrom(e => $"{e.CheckPoint.DoctorReview.Driver.FirstName} {e.CheckPoint.DoctorReview.Driver.LastName}")) - .ForCtorParam(nameof(DoctorReviewDto.ReviewerId), cfg => cfg.MapFrom(e => e.DoctorId)) + .ForCtorParam(nameof(DoctorReviewDto.DriverName), cfg => cfg.MapFrom(e => $"{e.Driver.FirstName} {e.Driver.LastName}")) .ForCtorParam(nameof(DoctorReviewDto.ReviewerName), cfg => cfg.MapFrom(e => $"{e.Doctor.FirstName} {e.Doctor.LastName}")); - - CreateMap<CreateDoctorReviewDto, DoctorReview>() - .ForMember(x => x.Date, cfg => cfg.MapFrom(_ => DateTime.UtcNow)) - .ForMember(x => x.Status, cfg => cfg.MapFrom(d => d.IsApprovedByReviewer ? ReviewStatus.Approved : ReviewStatus.RejectedByReviewer)); } } diff --git a/CheckDrive.Api/CheckDrive.Application/Mappings/Reviews/MechanicHandoverMappings.cs b/CheckDrive.Api/CheckDrive.Application/Mappings/Reviews/MechanicHandoverMappings.cs index f4910d7a..2c435def 100644 --- a/CheckDrive.Api/CheckDrive.Application/Mappings/Reviews/MechanicHandoverMappings.cs +++ b/CheckDrive.Api/CheckDrive.Application/Mappings/Reviews/MechanicHandoverMappings.cs @@ -10,8 +10,9 @@ internal sealed class MechanicHandoverMappings : Profile public MechanicHandoverMappings() { CreateMap<CreateMechanicHandoverReviewDto, MechanicHandover>() + .ForMember(x => x.MechanicId, cfg => cfg.MapFrom(e => e.ReviewerId)) .ForMember(x => x.Date, cfg => cfg.MapFrom(_ => DateTime.UtcNow)) - .ForMember(x => x.Status, cfg => cfg.MapFrom(x => x.IsApprovedByReviewer ? ReviewStatus.PendingDriverApproval : ReviewStatus.RejectedByReviewer)); + .ForMember(x => x.Status, cfg => cfg.MapFrom(e => e.IsApprovedByReviewer ? ReviewStatus.PendingDriverApproval : ReviewStatus.RejectedByReviewer)); CreateMap<MechanicHandover, MechanicHandoverReviewDto>() .ForCtorParam(nameof(MechanicHandoverReviewDto.DriverId), cfg => cfg.MapFrom(e => e.CheckPoint.DoctorReview.DriverId)) diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs index e4f0db96..dfb77709 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs @@ -6,6 +6,8 @@ using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Entities; using CheckDrive.Application.QueryParameters; +using CheckDrive.Domain.Enums; +using AutoMapper.QueryableExtensions; namespace CheckDrive.Application.Services; @@ -23,11 +25,11 @@ public CarService(ICheckDriveDbContext context, IMapper mapper) public async Task<List<CarDto>> GetAvailableCarsAsync() { var cars = await _context.Cars + .Where(x => x.Status == CarStatus.Free) + .ProjectTo<CarDto>(_mapper.ConfigurationProvider) .ToListAsync(); - var dtos = _mapper.Map<List<CarDto>>(cars); - - return dtos; + return cars; } public async Task<List<CarDto>> GetAllAsync(CarQueryParameters queryParameters) @@ -50,10 +52,11 @@ public async Task<List<CarDto>> GetAllAsync(CarQueryParameters queryParameters) query = query.Where(x => x.Status == queryParameters.Status); } - var entities = await query.ToListAsync(); - var dtos = _mapper.Map<List<CarDto>>(entities); + var cars = await query + .ProjectTo<CarDto>(_mapper.ConfigurationProvider) + .ToListAsync(); - return dtos; + return cars; } public async Task<CarDto> GetByIdAsync(int id) diff --git a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs index 3f109e7e..5351e5fc 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs @@ -1,4 +1,6 @@ -using CheckDrive.Application.DTOs.Driver; +using AutoMapper; +using AutoMapper.QueryableExtensions; +using CheckDrive.Application.DTOs.Driver; using CheckDrive.Application.Interfaces; using CheckDrive.Domain.Entities; using CheckDrive.Domain.Enums; @@ -11,17 +13,19 @@ namespace CheckDrive.Application.Services; internal sealed class DriverService : IDriverService { private readonly ICheckDriveDbContext _context; + private readonly IMapper _mapper; - public DriverService(ICheckDriveDbContext context) + public DriverService(ICheckDriveDbContext context, IMapper mapper) { _context = context ?? throw new ArgumentNullException(nameof(context)); + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } public async Task<List<DriverDto>> GetAvailableDriversAsync() { var drivers = await _context.Drivers .Where(x => !x.Reviews.Any(x => x.CheckPoint.Status == CheckPointStatus.InProgress)) - .Select(x => new DriverDto(x.Id, x.AccountId, x.FirstName + " " + x.LastName)) + .ProjectTo<DriverDto>(_mapper.ConfigurationProvider) .ToListAsync(); return drivers; @@ -47,19 +51,17 @@ public async Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmat private async Task CreateReviewAsync(CheckPoint checkPoint, DriverReviewConfirmationDto confirmation) { - if (confirmation.ReviewType == ReviewType.MechanicHandover) + switch (confirmation.ReviewType) { - await AcceptMechanicHandoverAsync(checkPoint); - } - - if (confirmation.ReviewType == ReviewType.OperatorReview) - { - await AcceptOperatorReviewAsync(checkPoint); - } - - if (confirmation.ReviewType == ReviewType.MechanicAcceptance) - { - await AcceptMechanicAcceptanceAsync(checkPoint); + case ReviewType.MechanicHandover: + await AcceptMechanicHandoverAsync(checkPoint); + break; + case ReviewType.OperatorReview: + await AcceptOperatorReviewAsync(checkPoint); + break; + case ReviewType.MechanicAcceptance: + await AcceptMechanicAcceptanceAsync(checkPoint); + break; } } @@ -82,11 +84,15 @@ private async Task AcceptOperatorReviewAsync(CheckPoint checkPoint) { if (checkPoint.OperatorReview is null || checkPoint.MechanicHandover is null) { - throw new InvalidOperationException($"Cannot update car for Check Point without Operator Review."); + throw new InvalidOperationException($"Cannot update car for Check Point without Operator Review or Mechanic Review."); } var car = await GetAndValidateCarAsync(checkPoint.MechanicHandover.CarId); + // TODO: Add alert check in case the difference between initial oil amount specified by reviewer + // is much larger than what was specified yesterday. For example if at the end of the previoius + // ride of a car there was 10l of oil remaining and now reviewer says that there is 5l or 0l remaining + // rise an alert so that manager reviews and confirm this process car.RemainingFuel = checkPoint.OperatorReview.InitialOilAmount + checkPoint.OperatorReview.OilRefillAmount; checkPoint.Stage = CheckPointStage.OperatorReview; checkPoint.OperatorReview.Status = ReviewStatus.Approved; @@ -133,7 +139,7 @@ private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) if (checkPoint is null) { - throw new EntityNotFoundException($"Check Point with id: {checkPointId} is not found."); + throw new InvalidOperationException($"Check Point with id: {checkPointId} is not found."); } if (checkPoint.Status != CheckPointStatus.InProgress) @@ -147,7 +153,8 @@ private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) private async Task<Car> GetAndValidateCarAsync(int carId) { - var car = await _context.Cars.FirstOrDefaultAsync(x => x.Id == carId); + var car = await _context.Cars + .FirstOrDefaultAsync(x => x.Id == carId); if (car is null) { diff --git a/CheckDrive.Api/CheckDrive.Application/Services/EmployeeMappings.cs b/CheckDrive.Api/CheckDrive.Application/Services/EmployeeMappings.cs new file mode 100644 index 00000000..09d9625b --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/EmployeeMappings.cs @@ -0,0 +1,14 @@ +using AutoMapper; +using CheckDrive.Application.DTOs.Driver; +using CheckDrive.Domain.Entities; + +namespace CheckDrive.Application.Services; + +public sealed class EmployeeMappings : Profile +{ + public EmployeeMappings() + { + CreateMap<Employee, DriverDto>() + .ForMember(x => x.FullName, cfg => cfg.MapFrom(e => $"{e.FirstName} {e.LastName}")); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs index 19568b3b..9a140fd9 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs @@ -27,6 +27,8 @@ public async Task<DispatcherReviewDto> CreateAsync(CreateDispatcherReviewDto rev var checkPoint = await GetAndValidateCheckPointAsync(review.CheckPointId); var dispatcher = await GetAndValidateDispatcherAsync(review.ReviewerId); + UpdateCheckPoint(checkPoint, review); + var reviewEntity = CreateReview(checkPoint, dispatcher, review); _context.DispatcherReviews.Add(reviewEntity); @@ -40,9 +42,6 @@ public async Task<DispatcherReviewDto> CreateAsync(CreateDispatcherReviewDto rev private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) { var checkPoint = await _context.CheckPoints - .Include(x => x.MechanicAcceptance) - .Include(x => x.MechanicHandover) - .ThenInclude(mh => mh!.Car) .FirstOrDefaultAsync(x => x.Id == checkPointId); if (checkPoint is null) @@ -78,6 +77,22 @@ private async Task<Dispatcher> GetAndValidateDispatcherAsync(int dispatcherId) return dispatcher; } + private static void UpdateCheckPoint(CheckPoint checkPoint, CreateDispatcherReviewDto review) + { + ArgumentNullException.ThrowIfNull(checkPoint); + + checkPoint.Stage = CheckPointStage.DispatcherReview; + + if (!review.IsApprovedByReviewer || review.FuelConsumptionAdjustment.HasValue || review.FinalMileageAdjustment.HasValue) + { + checkPoint.Status = CheckPointStatus.PendingManagerReview; + } + else + { + checkPoint.Status = CheckPointStatus.Completed; + } + } + private static DispatcherReview CreateReview(CheckPoint checkPoint, Dispatcher dispatcher, CreateDispatcherReviewDto review) { ArgumentNullException.ThrowIfNull(checkPoint); @@ -96,30 +111,4 @@ private static DispatcherReview CreateReview(CheckPoint checkPoint, Dispatcher d return entity; } - - private static void UpdateCheckPoint(CheckPoint checkPoint, CreateDispatcherReviewDto review) - { - ArgumentNullException.ThrowIfNull(checkPoint); - - checkPoint.Stage = CheckPointStage.DispatcherReview; - - if (!review.IsApprovedByReviewer) - { - checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; - return; - } - - if (review.FuelConsumptionAdjustment.HasValue || review.FinalMileageAdjustment.HasValue) - { - checkPoint.Status = CheckPointStatus.PendingManagerReview; - return; - } - - checkPoint.Status = CheckPointStatus.Completed; - } - - private async Task UpdateCarAsync(CheckPoint checkPoint) - { - ArgumentNullException.ThrowIfNull(checkPoint); - } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs index 8c4c40ab..907451b9 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs @@ -72,7 +72,14 @@ private async Task<Driver> GetAndValidateDriverAsync(int driverId) throw new EntityNotFoundException($"Driver with id: {driverId} is not found."); } - // TODO: check whether driver does not have any active check point in progress + var hasActiveCheckPoint = await _context.CheckPoints + .Where(x => x.DoctorReview.DriverId == driverId) + .AnyAsync(x => x.Status == CheckPointStatus.InProgress); + + if (hasActiveCheckPoint) + { + throw new InvalidOperationException($"Cannot start new Check Point for Driver with active Check Point."); + } return driver; } @@ -104,10 +111,10 @@ private static DoctorReview CreateReview( var doctorReview = new DoctorReview { CheckPoint = checkPoint, - Doctor = doctor, Driver = driver, - Date = DateTime.UtcNow, + Doctor = doctor, Notes = review.Notes, + Date = DateTime.UtcNow, Status = review.IsApprovedByReviewer ? ReviewStatus.Approved : ReviewStatus.RejectedByReviewer }; diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs index 4b1e72ba..db31ff7e 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs @@ -37,7 +37,7 @@ public async Task<MechanicHandoverReviewDto> CreateAsync(CreateMechanicHandoverR if (!review.IsApprovedByReviewer) { - checkPoint.Stage = CheckPointStage.OperatorReview; + checkPoint.Stage = CheckPointStage.MechanicHandover; checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; } @@ -55,28 +55,14 @@ await _hubContext.Clients return dto; } - private async Task<Mechanic> GetAndValidateMechanicAsync(int mechanicId) - { - var mechanic = await _context.Mechanics - .FirstOrDefaultAsync(x => x.Id == mechanicId); - - if (mechanic is null) - { - throw new EntityNotFoundException($"Mechanic with id: {mechanicId} is not found."); - } - - return mechanic; - } - private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) { var checkPoint = await _context.CheckPoints - .Include(x => x.DoctorReview) .FirstOrDefaultAsync(x => x.Id == checkPointId); if (checkPoint == null) { - throw new InvalidOperationException($"Cannot start mechanic review without doctor's review present."); + throw new InvalidOperationException($"Cannot start mechanic review without Doctor Review."); } if (checkPoint.Stage != CheckPointStage.DoctorReview) @@ -86,12 +72,25 @@ private async Task<CheckPoint> GetAndValidateCheckPointAsync(int checkPointId) if (checkPoint.Status != CheckPointStatus.InProgress) { - throw new InvalidOperationException($"Cannot start car handover review when Doctor review is not approved."); + throw new InvalidOperationException($"Cannot start car handover review when Doctor Review is not approved."); } return checkPoint; } + private async Task<Mechanic> GetAndValidateMechanicAsync(int mechanicId) + { + var mechanic = await _context.Mechanics + .FirstOrDefaultAsync(x => x.Id == mechanicId); + + if (mechanic is null) + { + throw new EntityNotFoundException($"Mechanic with id: {mechanicId} is not found."); + } + + return mechanic; + } + private async Task<Car> GetAndValidateCarAsync(int carId) { var car = await _context.Cars @@ -104,10 +103,13 @@ private async Task<Car> GetAndValidateCarAsync(int carId) if (car.Status != CarStatus.Free) { - throw new UnavailableCarException($"Car with id: {carId} is not available for handover."); + throw new CarUnavailableException($"Car with id: {carId} is not available for handover."); } - // TODO: Add logic for checking whether car's yearly/monthly limit is not exceeded + if (car.Mileage >= car.YearlyDistanceLimit) + { + throw new CarUnavailableException($"Car with id: {carId} has reached distance limit and is not available for ride."); + } return car; } @@ -123,10 +125,10 @@ private static MechanicHandover CreateReview( var entity = new MechanicHandover() { + InitialMileage = review.InitialMileage, CheckPoint = checkPoint, Car = car, Mechanic = mechanic, - InitialMileage = review.InitialMileage, Notes = review.Notes, Date = DateTime.UtcNow, Status = review.IsApprovedByReviewer ? ReviewStatus.PendingDriverApproval : ReviewStatus.RejectedByReviewer diff --git a/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs b/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs index b82defa1..c61c615b 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs @@ -7,5 +7,6 @@ public enum CheckPointStatus InterruptedByReviewerRejection = 2, InterruptedByDriverRejection = 3, AutomaticallyClosed = 4, - ClosedByManager = 5, + PendingManagerReview = 5, + ClosedByManager = 6, } diff --git a/CheckDrive.Api/CheckDrive.Domain/Enums/DebtStatus.cs b/CheckDrive.Api/CheckDrive.Domain/Enums/DebtStatus.cs index 8bba2958..b1ba199f 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Enums/DebtStatus.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Enums/DebtStatus.cs @@ -4,5 +4,6 @@ public enum DebtStatus { Paid, Unpaid, - PartiallyPaid + PartiallyPaid, + ClosedByManager } diff --git a/CheckDrive.Api/CheckDrive.Domain/Exceptions/CarUnavailableException.cs b/CheckDrive.Api/CheckDrive.Domain/Exceptions/CarUnavailableException.cs new file mode 100644 index 00000000..b653e37a --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Domain/Exceptions/CarUnavailableException.cs @@ -0,0 +1,7 @@ +namespace CheckDrive.Domain.Exceptions; + +public sealed class CarUnavailableException : Exception +{ + public CarUnavailableException() : base() { } + public CarUnavailableException(string message) : base(message) { } +} diff --git a/CheckDrive.Api/CheckDrive.Domain/Exceptions/UnavailableCarException.cs b/CheckDrive.Api/CheckDrive.Domain/Exceptions/UnavailableCarException.cs deleted file mode 100644 index 803954ab..00000000 --- a/CheckDrive.Api/CheckDrive.Domain/Exceptions/UnavailableCarException.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace CheckDrive.Domain.Exceptions; - -public sealed class UnavailableCarException : Exception -{ - public UnavailableCarException() : base() { } - public UnavailableCarException(string message) : base(message) { } -} From 445de1ee6cec66de94fd437b486c35e1692a6dfa Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Mon, 11 Nov 2024 01:07:35 +0500 Subject: [PATCH 38/40] update car limits & indicators --- .../CheckDrive.Api/Helpers/DatabaseSeeder.cs | 5 +- ...etService.cs => CarMileageResetService.cs} | 28 +- .../CheckDrive.Application/DTOs/Car/CarDto.cs | 6 + .../DTOs/Car/CreateCarDto.cs | 13 +- .../DTOs/Car/UpdateCarDto.cs | 6 + .../Extensions/DependencyInjection.cs | 2 +- .../Services/DriverService.cs | 3 + .../Services/OilMarkService.cs | 1 + .../Validators/Car/CreateCarValidator.cs | 34 +- .../Validators/Car/UpdateCarValidator.cs | 34 +- .../CheckDrive.Domain/Entities/Car.cs | 8 + .../Configurations/CarConfiguration.cs | 49 +- ...0241110190949_UpdateCar_Limits.Designer.cs | 1086 +++++++++++++++++ .../20241110190949_UpdateCar_Limits.cs | 90 ++ .../CheckDriveDbContextModelSnapshot.cs | 34 +- .../FakeDataGenerator.cs | 3 +- 16 files changed, 1357 insertions(+), 45 deletions(-) rename CheckDrive.Api/CheckDrive.Application/BackgroundJobs/{CarMonthlyMileageResetService.cs => CarMileageResetService.cs} (55%) create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241110190949_UpdateCar_Limits.Designer.cs create mode 100644 CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241110190949_UpdateCar_Limits.cs diff --git a/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs b/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs index 8a9cefc8..5777d8bb 100644 --- a/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs +++ b/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs @@ -1,5 +1,4 @@ -using Bogus; -using CheckDrive.Domain.Entities; +using CheckDrive.Domain.Entities; using CheckDrive.Domain.Interfaces; using CheckDrive.TestDataCreator; using CheckDrive.TestDataCreator.Configurations; @@ -9,8 +8,6 @@ namespace CheckDrive.Api.Helpers; public static class DatabaseSeeder { - private static Faker _faker = new Faker(); - public static void SeedDatabase( ICheckDriveDbContext context, UserManager<IdentityUser> userManager, diff --git a/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs b/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMileageResetService.cs similarity index 55% rename from CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs rename to CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMileageResetService.cs index 1c95acfe..14ea295a 100644 --- a/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMonthlyMileageResetService.cs +++ b/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMileageResetService.cs @@ -5,11 +5,11 @@ namespace CheckDrive.Application.BackgroundJobs; -internal sealed class CarMonthlyMileageResetService : BackgroundService +internal sealed class CarMileageResetService : BackgroundService { private readonly IServiceProvider _serviceProvider; - public CarMonthlyMileageResetService(IServiceProvider serviceProvider) + public CarMileageResetService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider)); } @@ -24,6 +24,12 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken) if (now.Day == 1 && now.Hour == 0) { await ResetCarMonthlyMileage(stoppingToken); + + // Check if it's the first month of the year + if (now.Month == 1) + { + await ResetCarYearlyMileage(stoppingToken); + } } await Task.Delay(TimeSpan.FromHours(1), stoppingToken); @@ -38,5 +44,23 @@ private async Task ResetCarMonthlyMileage(CancellationToken stoppingToken) await context.Cars.ExecuteUpdateAsync( x => x.SetProperty(x => x.CurrentMonthMileage, 0), stoppingToken); + + await context.Cars.ExecuteUpdateAsync( + x => x.SetProperty(x => x.CurrentMonthFuelConsumption, 0), + stoppingToken); + } + + private async Task ResetCarYearlyMileage(CancellationToken stoppingToken) + { + using var scope = _serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService<ICheckDriveDbContext>(); + + await context.Cars.ExecuteUpdateAsync( + x => x.SetProperty(x => x.CurrentYearMileage, 0), + stoppingToken); + + await context.Cars.ExecuteUpdateAsync( + x => x.SetProperty(x => x.CurrentYearFuelConsumption, 0), + stoppingToken); } } diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs index f9183bb2..0ff6f67b 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs @@ -10,7 +10,13 @@ public sealed record CarDto( int ManufacturedYear, int Mileage, int CurrentMonthMileage, + int CurrentYearMileage, + int MonthlyDistanceLimit, int YearlyDistanceLimit, + decimal CurrentMonthFuelConsumption, + decimal CurrentYearFuelConsumption, + decimal MonthlyFuelConsumptionLimit, + decimal YearlyFuelConsumptionLimit, decimal AverageFuelConsumption, decimal FuelCapacity, decimal RemainingFuel, diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs index 5a0b8cbf..41e70263 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs @@ -1,4 +1,6 @@ -namespace CheckDrive.Application.DTOs.Car; +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.Car; public record CreateCarDto( string Model, @@ -7,7 +9,14 @@ public record CreateCarDto( int ManufacturedYear, int Mileage, int CurrentMonthMileage, + int CurrentYearMileage, + int MonthlyDistanceLimit, int YearlyDistanceLimit, + decimal CurrentMonthFuelConsumption, + decimal CurrentYearFuelConsumption, + decimal MonthlyFuelConsumptionLimit, + decimal YearlyFuelConsumptionLimit, decimal AverageFuelConsumption, decimal FuelCapacity, - decimal RemainingFuel); + decimal RemainingFuel, + CarStatus Status); diff --git a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs index 697f11f6..b7fb2deb 100644 --- a/CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs @@ -10,7 +10,13 @@ public record UpdateCarDto( int ManufacturedYear, int Mileage, int CurrentMonthMileage, + int CurrentYearMileage, + int MonthlyDistanceLimit, int YearlyDistanceLimit, + decimal CurrentMonthFuelConsumption, + decimal CurrentYearFuelConsumption, + decimal MonthlyFuelConsumptionLimit, + decimal YearlyFuelConsumptionLimit, decimal AverageFuelConsumption, decimal FuelCapacity, decimal RemainingFuel, diff --git a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs index 989d61a2..ce463ed5 100644 --- a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs @@ -39,6 +39,6 @@ private static void AddServices(IServiceCollection services) services.AddScoped<IOilMarkService, OilMarkService>(); services.AddScoped<IReviewHistoryService, ReviewHistoryService>(); - services.AddHostedService<CarMonthlyMileageResetService>(); + services.AddHostedService<CarMileageResetService>(); } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs index 5351e5fc..1686e8dd 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs @@ -124,6 +124,9 @@ private async Task AcceptMechanicAcceptanceAsync(CheckPoint checkPoint) car.Mileage = checkPoint.MechanicAcceptance.FinalMileage; car.RemainingFuel = checkPoint.MechanicAcceptance.RemainingFuelAmount; car.CurrentMonthMileage += checkPoint.MechanicHandover.InitialMileage - checkPoint.MechanicAcceptance.FinalMileage; + car.CurrentYearMileage += checkPoint.MechanicHandover.InitialMileage - checkPoint.MechanicAcceptance.FinalMileage; + car.CurrentMonthFuelConsumption += fuelConsumption; + car.CurrentYearFuelConsumption += fuelConsumption; checkPoint.Stage = CheckPointStage.MechanicAcceptance; checkPoint.MechanicAcceptance.Status = ReviewStatus.Approved; diff --git a/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs b/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs index abfda0ef..b7ddaf93 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs @@ -17,6 +17,7 @@ internal sealed class OilMarkService : IOilMarkService public OilMarkService(ICheckDriveDbContext context, IMapper mapper) { _context = context ?? throw new ArgumentNullException(nameof(context)); + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); } public async Task<OilMarkDto> CreateAsync(CreateOilMarkDto oilMark) diff --git a/CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs b/CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs index 6f36c0d1..298376f4 100644 --- a/CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs +++ b/CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs @@ -11,10 +11,6 @@ public CreateCarValidator() .NotEmpty() .WithMessage("Car model must be specified."); - RuleFor(x => x.Color) - .NotEmpty() - .WithMessage("Car color must be specified."); - RuleFor(x => x.Number) .NotEmpty() .WithMessage("Car number must be specified."); @@ -28,9 +24,37 @@ public CreateCarValidator() .GreaterThanOrEqualTo(0) .WithMessage(x => $"Invalid mileage valule {x.Mileage}."); + RuleFor(x => x.CurrentMonthMileage) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid current month mileage: {x.CurrentMonthMileage}."); + + RuleFor(x => x.CurrentYearMileage) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid current year mileage: {x.CurrentYearMileage}."); + + RuleFor(x => x.MonthlyDistanceLimit) + .GreaterThan(0) + .WithMessage(x => $"Invalid monthly distance limit: {x.MonthlyDistanceLimit}."); + RuleFor(x => x.YearlyDistanceLimit) + .GreaterThan(0) + .WithMessage(x => $"Invalid yearly distance limit: {x.YearlyDistanceLimit}."); + + RuleFor(x => x.CurrentMonthFuelConsumption) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid current month fuel consumption: {x.CurrentMonthFuelConsumption}."); + + RuleFor(x => x.CurrentYearMileage) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid current year fuel consumption: {x.CurrentYearFuelConsumption}."); + + RuleFor(x => x.MonthlyFuelConsumptionLimit) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid monthly fuel consumption limit: {x.MonthlyFuelConsumptionLimit}."); + + RuleFor(x => x.YearlyFuelConsumptionLimit) .GreaterThanOrEqualTo(0) - .WithMessage(x => $"Invalid yearly limit value: {x.YearlyDistanceLimit}."); + .WithMessage(x => $"Invalid yearly fuel consumption limit: {x.YearlyFuelConsumptionLimit}."); RuleFor(x => x.AverageFuelConsumption) .GreaterThan(0) diff --git a/CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs b/CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs index b304b767..9c481081 100644 --- a/CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs +++ b/CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs @@ -15,10 +15,6 @@ public UpdateCarValidator() .NotEmpty() .WithMessage("Car model must be specified."); - RuleFor(x => x.Color) - .NotEmpty() - .WithMessage("Car color must be specified."); - RuleFor(x => x.Number) .NotEmpty() .WithMessage("Car number must be specified."); @@ -32,9 +28,37 @@ public UpdateCarValidator() .GreaterThanOrEqualTo(0) .WithMessage(x => $"Invalid mileage valule {x.Mileage}."); + RuleFor(x => x.CurrentMonthMileage) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid current month mileage: {x.CurrentMonthMileage}."); + + RuleFor(x => x.CurrentYearMileage) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid current year mileage: {x.CurrentYearMileage}."); + + RuleFor(x => x.MonthlyDistanceLimit) + .GreaterThan(0) + .WithMessage(x => $"Invalid monthly distance limit: {x.MonthlyDistanceLimit}."); + RuleFor(x => x.YearlyDistanceLimit) + .GreaterThan(0) + .WithMessage(x => $"Invalid yearly distance limit: {x.YearlyDistanceLimit}."); + + RuleFor(x => x.CurrentMonthFuelConsumption) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid current month fuel consumption: {x.CurrentMonthFuelConsumption}."); + + RuleFor(x => x.CurrentYearMileage) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid current year fuel consumption: {x.CurrentYearFuelConsumption}."); + + RuleFor(x => x.MonthlyFuelConsumptionLimit) + .GreaterThanOrEqualTo(0) + .WithMessage(x => $"Invalid monthly fuel consumption limit: {x.MonthlyFuelConsumptionLimit}."); + + RuleFor(x => x.YearlyFuelConsumptionLimit) .GreaterThanOrEqualTo(0) - .WithMessage(x => $"Invalid yearly limit value: {x.YearlyDistanceLimit}."); + .WithMessage(x => $"Invalid yearly fuel consumption limit: {x.YearlyFuelConsumptionLimit}."); RuleFor(x => x.AverageFuelConsumption) .GreaterThan(0) diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs index bf597ae9..110f0845 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs @@ -3,6 +3,8 @@ namespace CheckDrive.Domain.Entities; +// TODO: Add proper validation for the car with new properties introduced, +// such as monthly, yearly distance and fuel consumption limits public class Car : EntityBase { public string Model { get; set; } @@ -11,7 +13,13 @@ public class Car : EntityBase public int ManufacturedYear { get; set; } public int Mileage { get; set; } public int CurrentMonthMileage { get; set; } + public int CurrentYearMileage { get; set; } + public int MonthlyDistanceLimit { get; set; } public int YearlyDistanceLimit { get; set; } + public decimal CurrentMonthFuelConsumption { get; set; } + public decimal CurrentYearFuelConsumption { get; set; } + public decimal MonthlyFuelConsumptionLimit { get; set; } + public decimal YearlyFuelConsumptionLimit { get; set; } public decimal AverageFuelConsumption { get; set; } public decimal FuelCapacity { get; set; } public decimal RemainingFuel { get; set; } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs index f0467dbb..80c88d05 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs @@ -14,8 +14,7 @@ public void Configure(EntityTypeBuilder<Car> builder) #region Relationships - builder - .HasMany(c => c.Handovers) + builder.HasMany(c => c.Handovers) .WithOne(ch => ch.Car) .HasForeignKey(ch => ch.CarId); @@ -24,19 +23,19 @@ public void Configure(EntityTypeBuilder<Car> builder) #region Properties builder.Property(c => c.Model) - .HasMaxLength(Constants.MAX_STRING_LENGTH) - .IsRequired(); + .HasMaxLength(Constants.MAX_STRING_LENGTH) + .IsRequired(); builder.Property(c => c.Color) - .HasMaxLength(Constants.MAX_STRING_LENGTH) - .IsRequired(); + .HasMaxLength(Constants.MAX_STRING_LENGTH) + .IsRequired(); builder.Property(c => c.Number) - .HasMaxLength(Constants.CAR_NUMBER_LENGTH) - .IsRequired(); + .HasMaxLength(Constants.CAR_NUMBER_LENGTH) + .IsRequired(); builder.Property(c => c.ManufacturedYear) - .IsRequired(); + .IsRequired(); builder.Property(c => c.Mileage) .IsRequired(); @@ -44,24 +43,38 @@ public void Configure(EntityTypeBuilder<Car> builder) builder.Property(c => c.CurrentMonthMileage) .IsRequired(); + builder.Property(c => c.CurrentYearMileage) + .IsRequired(); + + builder.Property(c => c.MonthlyDistanceLimit) + .IsRequired(); + builder.Property(c => c.YearlyDistanceLimit) - .IsRequired(); + .IsRequired(); + + builder.Property(c => c.MonthlyFuelConsumptionLimit) + .HasPrecision(18, 2) + .IsRequired(); + + builder.Property(c => c.YearlyFuelConsumptionLimit) + .HasPrecision(18, 2) + .IsRequired(); builder.Property(c => c.AverageFuelConsumption) - .HasPrecision(18, 2) - .IsRequired(); + .HasPrecision(18, 2) + .IsRequired(); builder.Property(c => c.FuelCapacity) - .HasPrecision(18, 2) - .IsRequired(); + .HasPrecision(18, 2) + .IsRequired(); builder.Property(c => c.RemainingFuel) - .HasPrecision(18, 2) - .IsRequired(); + .HasPrecision(18, 2) + .IsRequired(); builder.Property(c => c.Status) - .HasDefaultValue(CarStatus.Free) - .IsRequired(); + .HasDefaultValue(CarStatus.Free) + .IsRequired(); #endregion } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241110190949_UpdateCar_Limits.Designer.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241110190949_UpdateCar_Limits.Designer.cs new file mode 100644 index 00000000..8871542c --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241110190949_UpdateCar_Limits.Designer.cs @@ -0,0 +1,1086 @@ +// <auto-generated /> +using System; +using CheckDrive.Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + [DbContext(typeof(CheckDriveDbContext))] + [Migration("20241110190949_UpdateCar_Limits")] + partial class UpdateCar_Limits + { + /// <inheritdoc /> + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.8") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<decimal>("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<decimal>("CurrentMonthFuelConsumption") + .HasColumnType("decimal(18,2)"); + + b.Property<int>("CurrentMonthMileage") + .HasColumnType("int"); + + b.Property<decimal>("CurrentYearFuelConsumption") + .HasColumnType("decimal(18,2)"); + + b.Property<int>("CurrentYearMileage") + .HasColumnType("int"); + + b.Property<decimal>("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManufacturedYear") + .HasColumnType("int"); + + b.Property<int>("Mileage") + .HasColumnType("int"); + + b.Property<string>("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<int>("MonthlyDistanceLimit") + .HasColumnType("int"); + + b.Property<decimal>("MonthlyFuelConsumptionLimit") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property<decimal>("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<int>("YearlyDistanceLimit") + .HasColumnType("int"); + + b.Property<decimal>("YearlyFuelConsumptionLimit") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<int>("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property<DateTime>("StartDate") + .HasColumnType("datetime2"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<decimal>("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int?>("ManagerReviewId") + .HasColumnType("int"); + + b.Property<decimal>("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(1); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.ToTable("Debt", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DispatcherId") + .HasColumnType("int"); + + b.Property<decimal?>("FinalMileageAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DispatcherId"); + + b.ToTable("DispatcherReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("DoctorId") + .HasColumnType("int"); + + b.Property<int>("DriverId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("DoctorId"); + + b.HasIndex("DriverId"); + + b.ToTable("DoctorReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property<DateTime>("Birthdate") + .HasColumnType("datetime2"); + + b.Property<string>("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property<string>("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property<int>("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator<int>("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal?>("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int?>("DebtId") + .HasColumnType("int"); + + b.Property<decimal?>("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("ManagerId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("ManagerId") + .IsUnique(); + + b.ToTable("ManagerReview", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("FinalMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<decimal>("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicAcceptance", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CarId") + .HasColumnType("int"); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<int>("InitialMileage") + .HasColumnType("int"); + + b.Property<int>("MechanicId") + .HasColumnType("int"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CarId"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("MechanicId"); + + b.ToTable("MechanicHandover", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("OilMark", (string)null); + + b.HasData( + new + { + Id = 1, + Name = "80" + }, + new + { + Id = 2, + Name = "85" + }, + new + { + Id = 3, + Name = "90" + }, + new + { + Id = 4, + Name = "95" + }, + new + { + Id = 5, + Name = "100" + }); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<int>("CheckPointId") + .HasColumnType("int"); + + b.Property<DateTime>("Date") + .HasColumnType("datetime2"); + + b.Property<decimal>("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<string>("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property<int>("OilMarkId") + .HasColumnType("int"); + + b.Property<decimal>("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property<int>("OperatorId") + .HasColumnType("int"); + + b.Property<int>("Status") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CheckPointId") + .IsUnique(); + + b.HasIndex("OilMarkId"); + + b.HasIndex("OperatorId"); + + b.ToTable("OperatorReview", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("Role", (string)null); + + b.HasData( + new + { + Id = "3b9cced9-80ba-4c29-b984-0ef814ed1e4a", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }, + new + { + Id = "eae91b8a-62a8-4910-a956-f31b3287908f", + Name = "Driver", + NormalizedName = "DRIVER" + }, + new + { + Id = "e13e7081-caef-4e06-8356-845df18805c6", + Name = "Doctor", + NormalizedName = "DOCTOR" + }, + new + { + Id = "d5ef47fb-bd3b-4743-b135-67248f9952ad", + Name = "Dispatcher", + NormalizedName = "DISPATCHER" + }, + new + { + Id = "08318c7a-b4a0-47da-b66f-a07910fb4341", + Name = "Manager", + NormalizedName = "MANAGER" + }, + new + { + Id = "3c126479-5651-4026-816f-42ee1d22a878", + Name = "Mechanic", + NormalizedName = "MECHANIC" + }, + new + { + Id = "472d6cd0-94dd-4294-9c92-b60cb4063398", + Name = "Operator", + NormalizedName = "OPERATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("RoleClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property<string>("Id") + .HasColumnType("nvarchar(450)"); + + b.Property<int>("AccessFailedCount") + .HasColumnType("int"); + + b.Property<string>("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property<string>("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<bool>("EmailConfirmed") + .HasColumnType("bit"); + + b.Property<bool>("LockoutEnabled") + .HasColumnType("bit"); + + b.Property<DateTimeOffset?>("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property<string>("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property<string>("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property<string>("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property<bool>("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property<string>("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("User", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.Property<int>("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id")); + + b.Property<string>("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property<string>("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.Property<string>("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Name") + .HasColumnType("nvarchar(450)"); + + b.Property<string>("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("UserToken", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(5); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(2); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(1); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(6); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(3); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.HasBaseType("CheckDrive.Domain.Entities.Employee"); + + b.HasDiscriminator().HasValue(4); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("Debt") + .HasForeignKey("CheckDrive.Domain.Entities.Debt", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DispatcherReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DispatcherReview") + .HasForeignKey("CheckDrive.Domain.Entities.DispatcherReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Dispatcher", "Dispatcher") + .WithMany("Reviews") + .HasForeignKey("DispatcherId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Dispatcher"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.DoctorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("DoctorReview") + .HasForeignKey("CheckDrive.Domain.Entities.DoctorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Doctor", "Doctor") + .WithMany("Reviews") + .HasForeignKey("DoctorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Driver", "Driver") + .WithMany("Reviews") + .HasForeignKey("DriverId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Doctor"); + + b.Navigation("Driver"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Employee", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", "Account") + .WithOne() + .HasForeignKey("CheckDrive.Domain.Entities.Employee", "AccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Debt", "Debt") + .WithOne("ManagerReview") + .HasForeignKey("CheckDrive.Domain.Entities.ManagerReview", "ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Manager", "Manager") + .WithMany("Reviews") + .HasForeignKey("ManagerId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Debt"); + + b.Navigation("Manager"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicAcceptance", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicAcceptance") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicAcceptance", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Acceptances") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.MechanicHandover", b => + { + b.HasOne("CheckDrive.Domain.Entities.Car", "Car") + .WithMany("Handovers") + .HasForeignKey("CarId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("MechanicHandover") + .HasForeignKey("CheckDrive.Domain.Entities.MechanicHandover", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Mechanic", "Mechanic") + .WithMany("Handovers") + .HasForeignKey("MechanicId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Car"); + + b.Navigation("CheckPoint"); + + b.Navigation("Mechanic"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.HasOne("CheckDrive.Domain.Entities.CheckPoint", "CheckPoint") + .WithOne("OperatorReview") + .HasForeignKey("CheckDrive.Domain.Entities.OperatorReview", "CheckPointId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.OilMark", "OilMark") + .WithMany("Reviews") + .HasForeignKey("OilMarkId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("CheckDrive.Domain.Entities.Operator", "Operator") + .WithMany("Reviews") + .HasForeignKey("OperatorId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("CheckPoint"); + + b.Navigation("OilMark"); + + b.Navigation("Operator"); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Car", b => + { + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Navigation("Debt"); + + b.Navigation("DispatcherReview"); + + b.Navigation("DoctorReview") + .IsRequired(); + + b.Navigation("ManagerReview"); + + b.Navigation("MechanicAcceptance"); + + b.Navigation("MechanicHandover"); + + b.Navigation("OperatorReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Navigation("ManagerReview"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OilMark", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Dispatcher", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Doctor", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Driver", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Manager", b => + { + b.Navigation("Reviews"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Mechanic", b => + { + b.Navigation("Acceptances"); + + b.Navigation("Handovers"); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Operator", b => + { + b.Navigation("Reviews"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241110190949_UpdateCar_Limits.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241110190949_UpdateCar_Limits.cs new file mode 100644 index 00000000..a3ddd02c --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241110190949_UpdateCar_Limits.cs @@ -0,0 +1,90 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace CheckDrive.Infrastructure.Persistence.Migrations +{ + /// <inheritdoc /> + public partial class UpdateCar_Limits : Migration + { + /// <inheritdoc /> + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn<decimal>( + name: "CurrentMonthFuelConsumption", + table: "Car", + type: "decimal(18,2)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn<decimal>( + name: "CurrentYearFuelConsumption", + table: "Car", + type: "decimal(18,2)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn<int>( + name: "CurrentYearMileage", + table: "Car", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn<int>( + name: "MonthlyDistanceLimit", + table: "Car", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn<decimal>( + name: "MonthlyFuelConsumptionLimit", + table: "Car", + type: "decimal(18,2)", + precision: 18, + scale: 2, + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn<decimal>( + name: "YearlyFuelConsumptionLimit", + table: "Car", + type: "decimal(18,2)", + precision: 18, + scale: 2, + nullable: false, + defaultValue: 0m); + } + + /// <inheritdoc /> + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CurrentMonthFuelConsumption", + table: "Car"); + + migrationBuilder.DropColumn( + name: "CurrentYearFuelConsumption", + table: "Car"); + + migrationBuilder.DropColumn( + name: "CurrentYearMileage", + table: "Car"); + + migrationBuilder.DropColumn( + name: "MonthlyDistanceLimit", + table: "Car"); + + migrationBuilder.DropColumn( + name: "MonthlyFuelConsumptionLimit", + table: "Car"); + + migrationBuilder.DropColumn( + name: "YearlyFuelConsumptionLimit", + table: "Car"); + } + } +} diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs index 53e52716..aecb6ca8 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs @@ -39,9 +39,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(500) .HasColumnType("nvarchar(500)"); + b.Property<decimal>("CurrentMonthFuelConsumption") + .HasColumnType("decimal(18,2)"); + b.Property<int>("CurrentMonthMileage") .HasColumnType("int"); + b.Property<decimal>("CurrentYearFuelConsumption") + .HasColumnType("decimal(18,2)"); + + b.Property<int>("CurrentYearMileage") + .HasColumnType("int"); + b.Property<decimal>("FuelCapacity") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -57,6 +66,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(500) .HasColumnType("nvarchar(500)"); + b.Property<int>("MonthlyDistanceLimit") + .HasColumnType("int"); + + b.Property<decimal>("MonthlyFuelConsumptionLimit") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + b.Property<string>("Number") .IsRequired() .HasMaxLength(10) @@ -74,6 +90,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property<int>("YearlyDistanceLimit") .HasColumnType("int"); + b.Property<decimal>("YearlyFuelConsumptionLimit") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + b.HasKey("Id"); b.ToTable("Car", (string)null); @@ -519,43 +539,43 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "295930c7-eeae-42bd-8312-9fa6856eb180", + Id = "3b9cced9-80ba-4c29-b984-0ef814ed1e4a", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "ea9063eb-e9d0-4206-b1fc-486e4ce04973", + Id = "eae91b8a-62a8-4910-a956-f31b3287908f", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "d4d28a23-e999-4a29-bd0b-f22031d92696", + Id = "e13e7081-caef-4e06-8356-845df18805c6", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "920b29e9-28d2-46ae-a69d-517faf209963", + Id = "d5ef47fb-bd3b-4743-b135-67248f9952ad", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "1276ec46-c408-4f86-bfb4-6db86e269051", + Id = "08318c7a-b4a0-47da-b66f-a07910fb4341", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "0226a77d-77af-4611-b06b-0b10c1b28c01", + Id = "3c126479-5651-4026-816f-42ee1d22a878", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "ef58c0c1-87ad-4b37-8d22-ec3a94a316c7", + Id = "472d6cd0-94dd-4294-9c92-b60cb4063398", Name = "Operator", NormalizedName = "OPERATOR" }); diff --git a/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs b/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs index 05babcc2..8d3907e4 100644 --- a/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs +++ b/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs @@ -31,7 +31,8 @@ public static class FakeDataGenerator .RuleFor(x => x.Number, f => f.Vehicle.Vin().Substring(0, 10)) .RuleFor(x => x.ManufacturedYear, f => f.Date.Between(DateTime.Now.AddYears(-20), DateTime.Now.AddYears(-2)).Year) .RuleFor(x => x.Mileage, f => f.Random.Number(0, 100_000)) - .RuleFor(x => x.CurrentMonthMileage, f => f.Random.Number(0, 1_000)) + .RuleFor(x => x.CurrentYearMileage, f => f.Random.Number(5_000, 10_000)) + .RuleFor(x => x.CurrentMonthMileage, (f, x) => f.Random.Number(500, 1_000)) .RuleFor(x => x.YearlyDistanceLimit, f => f.Random.Number(1_000, 5_000)) .RuleFor(x => x.FuelCapacity, f => f.Random.Number(50, 70)) .RuleFor(x => x.AverageFuelConsumption, f => f.Random.Number(10, 20)) From a2229597577aa156131c4de9c735b021e8d14df9 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Mon, 11 Nov 2024 01:08:33 +0500 Subject: [PATCH 39/40] fix auth controller namespace --- .../CheckDrive.Api/Controllers/{Auth => }/AuthController.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename CheckDrive.Api/CheckDrive.Api/Controllers/{Auth => }/AuthController.cs (93%) diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/Auth/AuthController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/AuthController.cs similarity index 93% rename from CheckDrive.Api/CheckDrive.Api/Controllers/Auth/AuthController.cs rename to CheckDrive.Api/CheckDrive.Api/Controllers/AuthController.cs index 7e4e1e16..2659d1e6 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/Auth/AuthController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/AuthController.cs @@ -2,7 +2,7 @@ using CheckDrive.Application.Interfaces.Auth; using Microsoft.AspNetCore.Mvc; -namespace CheckDrive.Api.Controllers.Auth; +namespace CheckDrive.Api.Controllers; [Route("api/auth")] [ApiController] From 97451daefe2b0631d0add7c7990c719c8ea258a1 Mon Sep 17 00:00:00 2001 From: "Miraziz.Khidoyatov" <khidoyatov1997@gmail.com> Date: Mon, 11 Nov 2024 12:35:52 +0500 Subject: [PATCH 40/40] seed database only during testing --- CheckDrive.Api/CheckDrive.Api/Extensions/StartupExtensions.cs | 4 +++- CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs | 1 + CheckDrive.Api/CheckDrive.Api/Program.cs | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CheckDrive.Api/CheckDrive.Api/Extensions/StartupExtensions.cs b/CheckDrive.Api/CheckDrive.Api/Extensions/StartupExtensions.cs index fe0eadbd..65cd1b56 100644 --- a/CheckDrive.Api/CheckDrive.Api/Extensions/StartupExtensions.cs +++ b/CheckDrive.Api/CheckDrive.Api/Extensions/StartupExtensions.cs @@ -1,6 +1,5 @@ using CheckDrive.Api.Helpers; using CheckDrive.Api.Middlewares; -using CheckDrive.Application.Constants; using CheckDrive.Domain.Interfaces; using CheckDrive.TestDataCreator.Configurations; using Microsoft.AspNetCore.Identity; @@ -28,4 +27,7 @@ public static IApplicationBuilder UseDatabaseSeeder(this WebApplication app) return app; } + + public static bool IsTesting(this IHostEnvironment environment) + => environment.IsEnvironment("Testing"); } diff --git a/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs b/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs index 5777d8bb..25a79a98 100644 --- a/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs +++ b/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs @@ -286,6 +286,7 @@ private static void CreateManagers(ICheckDriveDbContext context, UserManager<Ide context.SaveChanges(); } + //private static void CreateEmployees(ICheckDriveDbContext context, UserManager<IdentityUser> userManager, DataSeedOptions options) //{ // if (context.Users.Any()) diff --git a/CheckDrive.Api/CheckDrive.Api/Program.cs b/CheckDrive.Api/CheckDrive.Api/Program.cs index e1e21c2a..71969fd1 100644 --- a/CheckDrive.Api/CheckDrive.Api/Program.cs +++ b/CheckDrive.Api/CheckDrive.Api/Program.cs @@ -20,7 +20,7 @@ var app = builder.Build(); -if (!app.Environment.IsProduction()) +if (app.Environment.IsTesting()) { app.UseDatabaseSeeder(); }