diff --git a/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj b/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj index 0a76477a..9ac5645d 100644 --- a/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj +++ b/CheckDrive.Api/CheckDrive.Api/CheckDrive.Api.csproj @@ -24,6 +24,7 @@ + @@ -33,4 +34,8 @@ + + + + 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>> GetAsync() + public async Task>> GetAsync(EmployeePosition? position) { - var accounts = await _service.GetAsync(); + var accounts = await _service.GetAsync(position); return Ok(accounts); } 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] diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs new file mode 100644 index 00000000..62159875 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/CarsController.cs @@ -0,0 +1,63 @@ +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Application.Interfaces; +using CheckDrive.Application.QueryParameters; +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>> GetAllAsync(CarQueryParameters queryParameters) + { + var cars = await _carService.GetAllAsync(queryParameters); + + return Ok(cars); + } + + [HttpGet("{id:int}", Name = "GetCarByIdAsync")] + public async Task> GetByIdAsync(int id) + { + var car = await _carService.GetByIdAsync(id); + + return Ok(car); + } + + [HttpPost] + public async Task> CreateAsync(CreateCarDto car) + { + var createdCar = await _carService.CreateAsync(car); + + return CreatedAtAction("GetCarByIdAsync", createdCar, new { id = createdCar.Id }); + } + + [HttpPut("{id:int}")] + public async Task> 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 DeleteAsync(int id) + { + await _carService.DeleteAsync(id); + + return NoContent(); + } +} diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs index 97448bd6..7ed0264b 100644 --- a/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/CheckPointsController.cs @@ -23,4 +23,20 @@ public async Task>> GetCheckPointsAsync([FromQu return Ok(checkPoints); } + + [HttpGet("drivers/{driverId:int}/current")] + public async Task> GetCurrentCheckPointByDriverIdAsync(int driverId) + { + var checkPoint = await _service.GetCurrentCheckPointByDriverIdAsync(driverId); + + return Ok(checkPoint); + } + + [HttpPut("{id:int}/cancel")] + public async Task> CancelCheckPoint(int id) + { + await _service.CancelCheckPointAsync(id); + + return NoContent(); + } } diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs new file mode 100644 index 00000000..ff3a3460 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/DriversController.cs @@ -0,0 +1,33 @@ +using CheckDrive.Application.DTOs.Driver; +using CheckDrive.Application.Interfaces; +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>> GetAvailableDriversAsync() + { + var drivers = await _driverService.GetAvailableDriversAsync(); + + return Ok(drivers); + } + + [HttpPost("reviews")] + public async Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmationDto) + { + await _driverService.CreateReviewConfirmation(confirmationDto); + + return NoContent(); + } +} diff --git a/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs b/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs new file mode 100644 index 00000000..53c37b78 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/OilMarksController.cs @@ -0,0 +1,63 @@ +using CheckDrive.Application.DTOs.OilMark; +using CheckDrive.Application.Interfaces; +using CheckDrive.Application.QueryParameters; +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>> GetAsync(OilMarkQueryParameters queryParameters) + { + var oilMarks = await _oilMarkService.GetAllAsync(queryParameters); + + return Ok(oilMarks); + } + + [HttpGet("{id:int}", Name = "GetOilMarkById")] + public async Task> GetByIdAsync(int id) + { + var oilMark = await _oilMarkService.GetByIdAsync(id); + + return oilMark; + } + + [HttpPost] + public async Task> CreateAsync(CreateOilMarkDto oilMark) + { + var createdOilMark = await _oilMarkService.CreateAsync(oilMark); + + return CreatedAtAction("GetOilMarkById", oilMark, new { id = createdOilMark.Id }); + } + + [HttpPut("{id:int}")] + public async Task> 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 DeleteAsync(int id) + { + await _oilMarkService.DeleteAsync(id); + + return NoContent(); + } +} 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..f8d66138 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Api/Controllers/Reviews/ReviewHistoriesController.cs @@ -0,0 +1,52 @@ +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; + +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>> GetDriverHistoriesAsync(int driverId) + { + var reviews = await _historyService.GetDriverHistoriesAsync(driverId); + + return Ok(reviews); + } + + [HttpGet("doctors/{doctorId:int}")] + public async Task>> GetDoctorHistoriesAsync(int doctorId) + { + var reviews = await _historyService.GetDoctorHistoriesAsync(doctorId); + + return Ok(reviews); + } + + [HttpGet("mechanics/{mechanicId:int}")] + public async Task>> GetMechanicHistoriesAsync(int mechanicId) + { + var reviews = await _historyService.GetMechanicHistoriesAsync(mechanicId); + + return Ok(reviews); + } + + [HttpGet("operators/{operatorId:int}")] + public async Task>> GetOperatorHistoriesAsync(int operatorId) + { + var reviews = await _historyService.GetOperatorHistoriesAsync(operatorId); + + return Ok(reviews); + } +} diff --git a/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Api/Extensions/DependencyInjection.cs index 13f20e57..ff3eb848 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; @@ -21,6 +20,10 @@ public static IServiceCollection ConfigureServices(this IServiceCollection servi services.RegisterInfrastructure(configuration); services.AddSingleton(); + services.AddSignalR(options => + { + options.EnableDetailedErrors = true; + }); AddControllers(services); AddSwagger(services); @@ -56,15 +59,19 @@ private static void AddSwagger(IServiceCollection services) .AddSwaggerGen(setup => { setup.SwaggerDoc("v1", new OpenApiInfo { Title = "Check-Drive API", Version = "v1" }); - - setup.SchemaFilter(); - }); + }) + .AddSwaggerGenNewtonsoftSupport(); } private static void AddAuthentication(IServiceCollection services, IConfiguration configuration) { var jwtOptions = configuration.GetSection(nameof(JwtOptions)).Get(); + if (jwtOptions is null) + { + throw new InvalidOperationException("Could not load JWT configurations."); + } + services .AddAuthentication(options => { @@ -84,7 +91,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/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/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.Api/Helpers/DatabaseSeeder.cs b/CheckDrive.Api/CheckDrive.Api/Helpers/DatabaseSeeder.cs index 788e8267..25a79a98 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 userManager, @@ -23,6 +20,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 +142,7 @@ private static void CreateMechanics(ICheckDriveDbContext context, UserManager x.Name == "mechanic"); var uniqueMechanicsByName = new Dictionary(); - 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().Generate(); @@ -182,7 +180,7 @@ private static void CreateOperators(ICheckDriveDbContext context, UserManager x.Name == "operator"); var uniqueOperatorsByName = new Dictionary(); - 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().Generate(); @@ -220,7 +218,7 @@ private static void CreateDispatchers(ICheckDriveDbContext context, UserManager< var role = context.Roles.First(x => x.Name == "dispatcher"); var uniqueDispatchersByName = new Dictionary(); - 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().Generate(); @@ -251,6 +249,44 @@ private static void CreateDispatchers(ICheckDriveDbContext context, UserManager< context.SaveChanges(); } + private static void CreateManagers(ICheckDriveDbContext context, UserManager userManager, DataSeedOptions options) + { + if (context.Managers.Any()) return; + + var role = context.Roles.First(x => x.Name == "manager"); + var uniqueManagersByName = new Dictionary(); + + for (int i = 0; i < options.ManagersCount; i++) + { + var account = FakeDataGenerator.GetAccount().Generate(); + var manager = FakeDataGenerator.GetEmployee().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 { RoleId = role.Id, UserId = manager.AccountId }; + context.UserRoles.Add(userRole); + } + + context.SaveChanges(); + } + //private static void CreateEmployees(ICheckDriveDbContext context, UserManager 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/Program.cs b/CheckDrive.Api/CheckDrive.Api/Program.cs index 2bed574e..71969fd1 100644 --- a/CheckDrive.Api/CheckDrive.Api/Program.cs +++ b/CheckDrive.Api/CheckDrive.Api/Program.cs @@ -1,10 +1,11 @@ using CheckDrive.Api.Extensions; using CheckDrive.Api.Helpers; +using CheckDrive.Application.Hubs; using Microsoft.AspNetCore.CookiePolicy; 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) @@ -19,7 +20,7 @@ var app = builder.Build(); -if (!app.Environment.IsProduction()) +if (app.Environment.IsTesting()) { app.UseDatabaseSeeder(); } @@ -44,6 +45,8 @@ app.MapControllers(); +app.MapHub("/review-hub"); + app.Run(); // For API testing 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.Application/BackgroundJobs/CarMileageResetService.cs b/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMileageResetService.cs new file mode 100644 index 00000000..14ea295a --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/BackgroundJobs/CarMileageResetService.cs @@ -0,0 +1,66 @@ +using CheckDrive.Domain.Interfaces; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace CheckDrive.Application.BackgroundJobs; + +internal sealed class CarMileageResetService : BackgroundService +{ + private readonly IServiceProvider _serviceProvider; + + public CarMileageResetService(IServiceProvider serviceProvider) + { + _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(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); + + // Check if it's the first month of the year + if (now.Month == 1) + { + await ResetCarYearlyMileage(stoppingToken); + } + } + + await Task.Delay(TimeSpan.FromHours(1), stoppingToken); + } + } + + private async Task ResetCarMonthlyMileage(CancellationToken stoppingToken) + { + using var scope = _serviceProvider.CreateScope(); + var context = scope.ServiceProvider.GetRequiredService(); + + 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(); + + 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/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/DTOs/Car/CarDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs new file mode 100644 index 00000000..0ff6f67b --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CarDto.cs @@ -0,0 +1,23 @@ +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 CurrentMonthMileage, + int CurrentYearMileage, + int MonthlyDistanceLimit, + int YearlyDistanceLimit, + decimal CurrentMonthFuelConsumption, + decimal CurrentYearFuelConsumption, + decimal MonthlyFuelConsumptionLimit, + decimal YearlyFuelConsumptionLimit, + decimal AverageFuelConsumption, + decimal FuelCapacity, + decimal RemainingFuel, + CarStatus Status); 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..41e70263 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/CreateCarDto.cs @@ -0,0 +1,22 @@ +using CheckDrive.Domain.Enums; + +namespace CheckDrive.Application.DTOs.Car; + +public record CreateCarDto( + string Model, + string Color, + string Number, + 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, + CarStatus Status); 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..b7fb2deb --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Car/UpdateCarDto.cs @@ -0,0 +1,23 @@ +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 CurrentYearMileage, + int MonthlyDistanceLimit, + int YearlyDistanceLimit, + decimal CurrentMonthFuelConsumption, + decimal CurrentYearFuelConsumption, + decimal MonthlyFuelConsumptionLimit, + decimal YearlyFuelConsumptionLimit, + decimal AverageFuelConsumption, + decimal FuelCapacity, + decimal RemainingFuel, + CarStatus Status); 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 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/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/Driver/DriverDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs new file mode 100644 index 00000000..7027e466 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/Driver/DriverDto.cs @@ -0,0 +1,6 @@ +namespace CheckDrive.Application.DTOs.Driver; + +public record DriverDto( + int Id, + string AccountId, + string FullName); 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/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/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/OilMarkDto.cs b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs new file mode 100644 index 00000000..220c42fd --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/DTOs/OilMark/OilMarkDto.cs @@ -0,0 +1,5 @@ +namespace CheckDrive.Application.DTOs.OilMark; + +public sealed record OilMarkDto( + int Id, + 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/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.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/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/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); diff --git a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs index 6370de63..ce463ed5 100644 --- a/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs +++ b/CheckDrive.Api/CheckDrive.Application/Extensions/DependencyInjection.cs @@ -1,10 +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; @@ -12,8 +16,10 @@ public static class DependencyInjection { public static IServiceCollection RegisterApplication(this IServiceCollection services) { + services.AddAutoMapper(typeof(CarMappings).Assembly); + services.AddValidatorsFromAssemblyContaining(); + AddServices(services); - services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); return services; } @@ -28,5 +34,11 @@ private static void AddServices(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + + services.AddHostedService(); } } diff --git a/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs b/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs new file mode 100644 index 00000000..8c3bd3a2 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/IReviewHub.cs @@ -0,0 +1,14 @@ +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 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 new file mode 100644 index 00000000..f6136d58 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Hubs/ReviewHub.cs @@ -0,0 +1,14 @@ +using CheckDrive.Application.DTOs.Review; +using Microsoft.AspNetCore.SignalR; + +namespace CheckDrive.Application.Hubs; + +public sealed class ReviewHub : Hub +{ + public async Task NotifyNewReviewAsync(ReviewDtoBase review) + { + await Clients + .User(review.DriverId.ToString()) + .NotifyDoctorReview(review); + } +} 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 roles); + string GenerateToken(Employee employee, IList roles); } 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> GetAsync(); + Task> GetAsync(EmployeePosition? position); Task GetByIdAsync(string id); Task CreateAsync(CreateAccountDto account); Task UpdateAsync(UpdateAccountDto account); diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs new file mode 100644 index 00000000..d7b3b75e --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICarService.cs @@ -0,0 +1,14 @@ +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Application.QueryParameters; + +namespace CheckDrive.Application.Interfaces; + +public interface ICarService +{ + Task> GetAllAsync(CarQueryParameters queryParameters); + Task> GetAvailableCarsAsync(); + Task GetByIdAsync(int id); + Task CreateAsync(CreateCarDto car); + Task UpdateAsync(UpdateCarDto car); + Task DeleteAsync(int id); +} diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs index bf33dbf6..1c2d1395 100644 --- a/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/ICheckPointService.cs @@ -6,5 +6,6 @@ namespace CheckDrive.Application.Interfaces; public interface ICheckPointService { Task> GetCheckPointsAsync(CheckPointQueryParameters queryParameters); - Task GetCheckPointsByDriverIdAsync(int driverId); + Task GetCurrentCheckPointByDriverIdAsync(int driverId); + Task CancelCheckPointAsync(int id); } diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs new file mode 100644 index 00000000..ab930b6a --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/IDriverService.cs @@ -0,0 +1,9 @@ +using CheckDrive.Application.DTOs.Driver; + +namespace CheckDrive.Application.Interfaces; + +public interface IDriverService +{ + Task> GetAvailableDriversAsync(); + Task CreateReviewConfirmation(DriverReviewConfirmationDto confirmation); +} diff --git a/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs b/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs new file mode 100644 index 00000000..74ce90ed --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Interfaces/IOilMarkService.cs @@ -0,0 +1,13 @@ +using CheckDrive.Application.DTOs.OilMark; +using CheckDrive.Application.QueryParameters; + +namespace CheckDrive.Application.Interfaces; + +public interface IOilMarkService +{ + Task> GetAllAsync(OilMarkQueryParameters queryParameters); + Task GetByIdAsync(int id); + Task CreateAsync(CreateOilMarkDto oilMark); + Task UpdateAsync(UpdateOilMarkDto oilMark); + Task DeleteAsync(int id); +} 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> GetDriverHistoriesAsync(int driverId); + Task> GetDoctorHistoriesAsync(int doctorId); + Task> GetMechanicHistoriesAsync(int mechanicId); + Task> GetOperatorHistoriesAsync(int operatorId); +} 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() - .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/Mappings/CarMappings.cs b/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs new file mode 100644 index 00000000..67b1778e --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Mappings/CarMappings.cs @@ -0,0 +1,15 @@ +using AutoMapper; +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Domain.Entities; + +namespace CheckDrive.Application.Mappings; + +public sealed class CarMappings : Profile +{ + public CarMappings() + { + CreateMap(); + CreateMap(); + CreateMap(); + } +} 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(); + CreateMap(); + CreateMap(); + } +} 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() - .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() - .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() + .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() .ForCtorParam(nameof(MechanicHandoverReviewDto.DriverId), cfg => cfg.MapFrom(e => e.CheckPoint.DoctorReview.DriverId)) 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/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/AccountService.cs b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs index b4bd538b..5f0d44f4 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/AccountService.cs @@ -1,34 +1,45 @@ using AutoMapper; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; +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; -using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services; internal sealed class AccountService : IAccountService { private readonly ICheckDriveDbContext _context; - private readonly UserManager _userManager; private readonly IMapper _mapper; + private readonly UserManager _userManager; - public AccountService(ICheckDriveDbContext context, IMapper mapper, UserManager userManager) + public AccountService( + ICheckDriveDbContext context, + IMapper mapper, + UserManager userManager) { _context = context ?? throw new ArgumentNullException(nameof(context)); _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); _userManager = userManager ?? throw new ArgumentNullException(nameof(userManager)); } - public async Task> GetAsync() + public async Task> GetAsync(EmployeePosition? position) { - var accounts = await _context.Employees - .AsNoTracking() + var query = _context.Employees .Include(x => x.Account) - .ToListAsync(); + .AsNoTracking() + .AsQueryable(); + if (position.HasValue) + { + query = query.Where(x => x.Position == position.Value); + } + + var accounts = await query.ToListAsync(); var dtos = _mapper.Map>(accounts); return dtos; @@ -65,6 +76,8 @@ public async Task CreateAsync(CreateAccountDto account) throw new InvalidOperationException("Could not create user account."); } + await AssignToRoleAsync(user, account.Position); + var employee = _mapper.Map(account); employee.AccountId = user.Id; @@ -95,4 +108,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."); + } + } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Auth/AuthService.cs index ca9bb6e0..05ec2c28 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,32 @@ internal sealed class AuthService : IAuthService { private readonly IJwtTokenGenerator _jwtTokenGenerator; private readonly UserManager _userManager; + private readonly ICheckDriveDbContext _context; - public AuthService(IJwtTokenGenerator jwtTokenGenerator, UserManager userManager) + public AuthService( + IJwtTokenGenerator jwtTokenGenerator, + UserManager 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 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 user = await _userManager.FindByNameAsync(request.UserName); var roles = await _userManager.GetRolesAsync(user); - var token = _jwtTokenGenerator.GenerateToken(user, roles); + var token = _jwtTokenGenerator.GenerateToken(employee, roles); return token; } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs new file mode 100644 index 00000000..dfb77709 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/CarService.cs @@ -0,0 +1,121 @@ +using AutoMapper; +using Microsoft.EntityFrameworkCore; +using CheckDrive.Application.DTOs.Car; +using CheckDrive.Application.Interfaces; +using CheckDrive.Domain.Interfaces; +using CheckDrive.Domain.Exceptions; +using CheckDrive.Domain.Entities; +using CheckDrive.Application.QueryParameters; +using CheckDrive.Domain.Enums; +using AutoMapper.QueryableExtensions; + +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> GetAvailableCarsAsync() + { + var cars = await _context.Cars + .Where(x => x.Status == CarStatus.Free) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + + return cars; + } + + public async Task> 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 cars = await query + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + + return cars; + } + + public async Task 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(car); + + return dto; + } + + public async Task CreateAsync(CreateCarDto car) + { + ArgumentNullException.ThrowIfNull(car); + + var entity = _mapper.Map(car); + + _context.Cars.Add(entity); + await _context.SaveChangesAsync(); + + var dto = _mapper.Map(entity); + + return dto; + } + + public async Task 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); + + _context.Cars.Update(entity); + await _context.SaveChangesAsync(); + + var dto = _mapper.Map(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/Services/CheckPointService.cs b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs index 03ce4d1c..4edf3bcd 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/CheckPointService.cs @@ -1,18 +1,12 @@ using AutoMapper; +using Microsoft.EntityFrameworkCore; 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; +using CheckDrive.Domain.Exceptions; using CheckDrive.Domain.Interfaces; using CheckDrive.Domain.QueryParameters; -using Microsoft.EntityFrameworkCore; namespace CheckDrive.Application.Services; @@ -38,12 +32,39 @@ public async Task> GetCheckPointsAsync(CheckPointQueryParame return dtos; } - public Task GetCheckPointsByDriverIdAsync(int driverId) + public async Task GetCurrentCheckPointByDriverIdAsync(int driverId) + { + 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) + .FirstOrDefaultAsync(); + + if (checkPoint is null) + { + throw new EntityNotFoundException($"Driver with id: {driverId} does not have current active Check Point."); + } + + var dto = _mapper.Map(checkPoint); + + return dto; + } + + public async Task CancelCheckPointAsync(int id) { - throw new NotImplementedException(); + 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 GetQuery(CheckPointQueryParameters queryParameters) + private IQueryable GetQuery(CheckPointQueryParameters? queryParameters = null) { var query = _context.CheckPoints .AsNoTracking() @@ -53,15 +74,21 @@ private IQueryable 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 => @@ -88,9 +115,9 @@ private IQueryable GetQuery(CheckPointQueryParameters queryParameter query = query.Where(x => x.Stage == queryParameters.Stage.Value); } - if (queryParameters.DateFilter.HasValue) + if (queryParameters.Date.HasValue) { - query = FilterByDate(query, queryParameters.DateFilter.Value); + query = FilterByDate(query, queryParameters.Date.Value); } return query; @@ -108,57 +135,15 @@ private static IQueryable FilterByDate(IQueryable query, }; } - private List GetReviews(CheckPoint checkPoint) + private async Task GetAndValidateAsync(int id) { - ArgumentNullException.ThrowIfNull(checkPoint); - - var reviews = new List(); - var doctorReview = _mapper.Map(checkPoint.DoctorReview); - reviews.Add(doctorReview); + var checkPoint = await _context.CheckPoints.FirstOrDefaultAsync(x => x.Id == id); - if (checkPoint.MechanicHandover is not null) + if (checkPoint is null) { - var mechanicHandover = _mapper.Map(checkPoint.MechanicHandover); - reviews.Add(mechanicHandover); + throw new EntityNotFoundException($"Check Point with id: {id} is not found."); } - if (checkPoint.OperatorReview is not null) - { - var operatorReview = _mapper.Map(checkPoint.OperatorReview); - reviews.Add(operatorReview); - } - - if (checkPoint.MechanicAcceptance is not null) - { - var mechanicAcceptance = _mapper.Map(checkPoint.MechanicAcceptance); - reviews.Add(mechanicAcceptance); - } - - if (checkPoint.DispatcherReview is not null) - { - var dispatcherReview = _mapper.Map(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; + return checkPoint; } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs new file mode 100644 index 00000000..1686e8dd --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/DriverService.cs @@ -0,0 +1,193 @@ +using AutoMapper; +using AutoMapper.QueryableExtensions; +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; + +namespace CheckDrive.Application.Services; + +internal sealed class DriverService : IDriverService +{ + private readonly ICheckDriveDbContext _context; + private readonly IMapper _mapper; + + public DriverService(ICheckDriveDbContext context, IMapper mapper) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + } + + public async Task> GetAvailableDriversAsync() + { + var drivers = await _context.Drivers + .Where(x => !x.Reviews.Any(x => x.CheckPoint.Status == CheckPointStatus.InProgress)) + .ProjectTo(_mapper.ConfigurationProvider) + .ToListAsync(); + + return drivers; + } + + 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; + } + + await CreateReviewAsync(checkPoint, confirmation); + await _context.SaveChangesAsync(); + } + + private async Task CreateReviewAsync(CheckPoint checkPoint, DriverReviewConfirmationDto confirmation) + { + switch (confirmation.ReviewType) + { + case ReviewType.MechanicHandover: + await AcceptMechanicHandoverAsync(checkPoint); + break; + case ReviewType.OperatorReview: + await AcceptOperatorReviewAsync(checkPoint); + break; + case ReviewType.MechanicAcceptance: + await AcceptMechanicAcceptanceAsync(checkPoint); + break; + } + } + + 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 GetAndValidateCarAsync(checkPoint.MechanicHandover.CarId); + + car.Mileage = checkPoint.MechanicHandover.InitialMileage; + car.Status = CarStatus.Busy; + checkPoint.Stage = CheckPointStage.MechanicHandover; + checkPoint.MechanicHandover.Status = ReviewStatus.Approved; + } + + 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 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; + } + + 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); + 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; + 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; + } + + private async Task 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 InvalidOperationException($"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 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 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/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() + .ForMember(x => x.FullName, cfg => cfg.MapFrom(e => $"{e.FirstName} {e.LastName}")); + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs b/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs new file mode 100644 index 00000000..b7ddaf93 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/OilMarkService.cs @@ -0,0 +1,106 @@ +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; + +namespace CheckDrive.Application.Services; + +internal sealed class OilMarkService : IOilMarkService +{ + private readonly ICheckDriveDbContext _context; + private readonly IMapper _mapper; + + public OilMarkService(ICheckDriveDbContext context, IMapper mapper) + { + _context = context ?? throw new ArgumentNullException(nameof(context)); + _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper)); + } + + public async Task CreateAsync(CreateOilMarkDto oilMark) + { + ArgumentNullException.ThrowIfNull(oilMark); + + var entity = _mapper.Map(oilMark); + + _context.OilMarks.Add(entity); + await _context.SaveChangesAsync(); + + var dto = _mapper.Map(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> GetAllAsync() + { + var oilMarks = _context.OilMarks + .Select(x => new OilMarkDto(x.Id, x.Name)) + .ToListAsync(); + + return oilMarks; + } + + public async Task> 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>(entities); + + return dtos; + } + + public async Task 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(entity); + + return dto; + } + + public async Task 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); + + _context.OilMarks.Update(entity); + await _context.SaveChangesAsync(); + + var dto = _mapper.Map(entity); + + return dto; + } +} diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs index db0d7cf1..9a140fd9 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/DispatcherReviewService.cs @@ -29,7 +29,7 @@ public async Task CreateAsync(CreateDispatcherReviewDto rev UpdateCheckPoint(checkPoint, review); - var reviewEntity = CreateReviewEntity(checkPoint, dispatcher, review); + var reviewEntity = CreateReview(checkPoint, dispatcher, review); _context.DispatcherReviews.Add(reviewEntity); await _context.SaveChangesAsync(); @@ -42,9 +42,6 @@ public async Task CreateAsync(CreateDispatcherReviewDto rev private async Task 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) @@ -80,10 +77,27 @@ private async Task GetAndValidateDispatcherAsync(int dispatcherId) return dispatcher; } - private static DispatcherReview CreateReviewEntity(CheckPoint checkPoint, Dispatcher dispatcher, CreateDispatcherReviewDto review) + 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); + ArgumentNullException.ThrowIfNull(dispatcher); + var entity = new DispatcherReview { CheckPoint = checkPoint, @@ -92,30 +106,9 @@ 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.FinalMileageAdjustment, }; return entity; } - - private static void UpdateCheckPoint(CheckPoint checkPoint, CreateDispatcherReviewDto review) - { - ArgumentNullException.ThrowIfNull(checkPoint); - - checkPoint.Stage = CheckPointStage.DispatcherReview; - - if (review.FuelConsumptionAdjustment.HasValue || review.DistanceTravelledAdjustment.HasValue) - { - checkPoint.Stage = CheckPointStage.ManagerReview; - return; - } - - if (!review.IsApprovedByReviewer) - { - checkPoint.Status = CheckPointStatus.InterruptedByReviewerRejection; - return; - } - - checkPoint.Status = CheckPointStatus.Completed; - } } diff --git a/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs b/CheckDrive.Api/CheckDrive.Application/Services/Review/DoctorReviewService.cs index f0f220e8..907451b9 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,16 @@ internal sealed class DoctorReviewService : IDoctorReviewService { private readonly ICheckDriveDbContext _context; private readonly IMapper _mapper; + private readonly IHubContext _reviewHub; - public DoctorReviewService(ICheckDriveDbContext context, IMapper mapper) + public DoctorReviewService( + ICheckDriveDbContext context, + IMapper mapper, + IHubContext 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 CreateAsync(CreateDoctorReviewDto review) @@ -28,13 +35,17 @@ public async Task 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(reviewEntity); + await _reviewHub.Clients + .User(dto.DriverId.ToString()) + .NotifyDoctorReview(dto); + return dto; } @@ -61,6 +72,15 @@ private async Task GetAndValidateDriverAsync(int driverId) throw new EntityNotFoundException($"Driver with id: {driverId} is not found."); } + 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; } @@ -79,7 +99,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); @@ -87,10 +111,10 @@ private static DoctorReview CreateReviewEntity(CreateDoctorReviewDto review, Che 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/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 _hubContext; - public MechanicAcceptanceService(ICheckDriveDbContext context, IMapper mapper) + public MechanicAcceptanceService( + ICheckDriveDbContext context, + IMapper mapper, + IHubContext 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 CreateAsync(CreateMechanicAcceptanceReviewDto review) @@ -27,37 +34,33 @@ public async Task 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(reviewEntity); - var dto = _mapper.Map(createdReview); + await _hubContext.Clients + .User(dto.DriverId.ToString()) + .MechanicAcceptanceConfirmation(dto); - return dto; - } - catch (Exception) - { - await transaction.RollbackAsync(); - throw; - } + return dto; } private async Task 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 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 05902a9f..db31ff7e 100644 --- a/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs +++ b/CheckDrive.Api/CheckDrive.Application/Services/Review/MechanicHandoverService.cs @@ -1,10 +1,12 @@ using AutoMapper; using CheckDrive.Application.DTOs.MechanicHandover; +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 MechanicHandoverService : IMechanicHandoverService { private readonly ICheckDriveDbContext _context; private readonly IMapper _mapper; + private readonly IHubContext _hubContext; - public MechanicHandoverService(ICheckDriveDbContext context, IMapper mapper) + public MechanicHandoverService( + ICheckDriveDbContext context, + IMapper mapper, + IHubContext 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 CreateAsync(CreateMechanicHandoverReviewDto review) @@ -28,41 +35,34 @@ public async Task 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.MechanicHandover; + 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(createdReview); - - return dto; - } - - private async Task GetAndValidateMechanicAsync(int mechanicId) - { - var mechanic = await _context.Mechanics - .FirstOrDefaultAsync(x => x.Id == mechanicId); + var dto = _mapper.Map(reviewEntity); - if (mechanic is null) - { - throw new EntityNotFoundException($"Mechanic with id: {mechanicId} is not found."); - } + await _hubContext.Clients + .User(dto.DriverId.ToString()) + .MechanicHandoverConfirmation(dto); - return mechanic; + return dto; } private async Task 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) @@ -70,14 +70,27 @@ private async Task 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."); + throw new InvalidOperationException($"Cannot start car handover review when Doctor Review is not approved."); } return checkPoint; } + private async Task 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 GetAndValidateCarAsync(int carId) { var car = await _context.Cars @@ -90,24 +103,32 @@ private async Task 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."); + } + + if (car.Mileage >= car.YearlyDistanceLimit) + { + throw new CarUnavailableException($"Car with id: {carId} has reached distance limit and is not available for ride."); } 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() { + 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 @@ -115,30 +136,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 _hubContext; - public OperatorReviewService(ICheckDriveDbContext context, IMapper mapper) + public OperatorReviewService( + ICheckDriveDbContext context, + IMapper mapper, + IHubContext 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 CreateAsync(CreateOperatorReviewDto review) @@ -27,16 +34,30 @@ public async Task 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(createdReview); + var dto = _mapper.Map(reviewEntity); + + await _hubContext.Clients + .User(dto.DriverId.ToString()) + .OperatorReviewConfirmation(dto); return dto; } @@ -44,9 +65,10 @@ public async Task CreateAsync(CreateOperatorReviewDto review) private async Task 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 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.Application/Services/ReviewHistoryService.cs b/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs new file mode 100644 index 00000000..8387484e --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Services/ReviewHistoryService.cs @@ -0,0 +1,131 @@ +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> 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.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.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>(checkPoints); + + return dtos; + + } + + public async Task> GetDoctorHistoriesAsync(int doctorId) + { + var reviews = await _context.DoctorReviews + .Include(x => x.Driver) + .Where(x => x.DoctorId == doctorId) + .ToListAsync(); + + var dtos = _mapper.Map>(reviews); + + return dtos; + } + + public async Task> 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 allReviews = [.. handovers, .. acceptances]; + var orderedReviews = allReviews.OrderByDescending(x => x.Date).ToList(); + + return orderedReviews; + } + + public async Task> 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; + } +} 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..298376f4 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Validators/Car/CreateCarValidator.cs @@ -0,0 +1,72 @@ +using CheckDrive.Application.DTOs.Car; +using FluentValidation; + +namespace CheckDrive.Application.Validators.Car; + +public sealed class CreateCarValidator : AbstractValidator +{ + public CreateCarValidator() + { + RuleFor(x => x.Model) + .NotEmpty() + .WithMessage("Car model 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.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 fuel consumption limit: {x.YearlyFuelConsumptionLimit}."); + + 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..9c481081 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Application/Validators/Car/UpdateCarValidator.cs @@ -0,0 +1,75 @@ +using CheckDrive.Application.DTOs.Car; +using FluentValidation; + +namespace CheckDrive.Application.Validators.Car; + +public sealed class UpdateCarValidator : AbstractValidator +{ + 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.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.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 fuel consumption limit: {x.YearlyFuelConsumptionLimit}."); + + 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/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 +{ + 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 +{ + 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."); + } +} diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/Car.cs index 2b5d54dd..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; } @@ -10,7 +12,14 @@ 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 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.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/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/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.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 Reviews { get; set; } + + public Manager() + { + Reviews = new HashSet(); + } +} diff --git a/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs b/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs new file mode 100644 index 00000000..6b6632d6 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Domain/Entities/ManagerReview.cs @@ -0,0 +1,18 @@ +using CheckDrive.Domain.Common; + +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; } + + public int? DebtId { get; set; } + public virtual Debt? Debt { get; set; } +} diff --git a/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs b/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs index 475e27fe..c61c615b 100644 --- a/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs +++ b/CheckDrive.Api/CheckDrive.Domain/Enums/CheckPointStatus.cs @@ -8,4 +8,5 @@ public enum CheckPointStatus InterruptedByDriverRejection = 3, AutomaticallyClosed = 4, 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/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 } 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) { } -} 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 Mechanics { get; set; } DbSet Operators { get; set; } DbSet Dispatchers { get; set; } + DbSet Managers { get; set; } DbSet Cars { get; set; } DbSet CheckPoints { get; set; } DbSet DoctorReviews { get; set; } @@ -20,6 +21,7 @@ public interface ICheckDriveDbContext DbSet OperatorReviews { get; set; } DbSet MechanicAcceptances { get; set; } DbSet DispatcherReviews { get; set; } + DbSet ManagerReviews { get; set; } DbSet Debts { get; set; } DbSet OilMarks { get; set; } diff --git a/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs b/CheckDrive.Api/CheckDrive.Domain/QueryParameters/CheckPointQueryParameters.cs index accbcbac..21730521 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; } = CheckPointStatus.InProgress; + public DateFilter? Date { get; set; } } 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 options) _options = options?.Value ?? throw new ArgumentNullException(nameof(options)); } - public string GenerateToken(IdentityUser user, - IList roles) + public string GenerateToken(Employee employee, IList 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 GetClaims(IdentityUser user, IList roles) + private static List GetClaims(Employee employee, IList roles) { var claims = new List() { - new (ClaimTypes.NameIdentifier, user.Id.ToString()), + new (ClaimTypes.PrimarySid, employee.AccountId), + new (ClaimTypes.NameIdentifier, employee.Id.ToString()), }; foreach (var role in roles) diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/CheckDriveDbContext.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/CheckDriveDbContext.cs index 1d993af8..1702ca19 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 Mechanics { get; set; } public virtual DbSet Operators { get; set; } public virtual DbSet Dispatchers { get; set; } + public virtual DbSet Managers { get; set; } public virtual DbSet Cars { get; set; } public virtual DbSet CheckPoints { get; set; } public virtual DbSet DoctorReviews { get; set; } @@ -23,6 +24,7 @@ public class CheckDriveDbContext : IdentityDbContext, ICheckDriveDbContext public virtual DbSet OperatorReviews { get; set; } public virtual DbSet MechanicAcceptances { get; set; } public virtual DbSet DispatcherReviews { get; set; } + public virtual DbSet ManagerReviews { get; set; } public virtual DbSet Debts { get; set; } public virtual DbSet OilMarks { get; set; } diff --git a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/CarConfiguration.cs index 4736ccb1..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 builder) #region Relationships - builder - .HasMany(c => c.Handovers) + builder.HasMany(c => c.Handovers) .WithOne(ch => ch.Car) .HasForeignKey(ch => ch.CarId); @@ -24,41 +23,58 @@ public void Configure(EntityTypeBuilder 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(); + .IsRequired(); + + 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/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 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/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 builder) .HasValue(EmployeePosition.Doctor) .HasValue(EmployeePosition.Mechanic) .HasValue(EmployeePosition.Operator) - .HasValue(EmployeePosition.Dispatcher); + .HasValue(EmployeePosition.Dispatcher) + .HasValue(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..62d6bc9d --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Configurations/ManagerReviewConfigurations.cs @@ -0,0 +1,53 @@ +using CheckDrive.Domain.Entities; +using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.EntityFrameworkCore; + +namespace CheckDrive.Infrastructure.Persistence.Configurations; + +internal sealed class ManagerReviewConfigurations : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.ToTable(nameof(ManagerReview)); + builder.HasKey(mr => mr.Id); + + #region Relationships + + builder + .HasOne(mr => mr.CheckPoint) + .WithOne(cp => cp.ManagerReview) + .HasForeignKey(mr => mr.CheckPointId) + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + builder + .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(mr => mr.ManagerId) + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + #endregion + + #region Properties + + builder + .Property(mr => mr.DebtAmountAdjusment) + .HasPrecision(18, 2) + .IsRequired(false); + + builder + .Property(mr => mr.FuelConsumptionAdjustment) + .HasPrecision(18, 2) + .IsRequired(false); + + #endregion + } +} 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 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/20241006103314_Add_Manager_ManagerReview.Designer.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.Designer.cs new file mode 100644 index 00000000..76a28fdb --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.Designer.cs @@ -0,0 +1,1036 @@ +// +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("20241006103314_Add_Manager_ManagerReview")] + partial class Add_Manager_ManagerReview + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManufacturedYear") + .HasColumnType("int"); + + b.Property("Mileage") + .HasColumnType("int"); + + b.Property("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("YearlyDistanceLimit") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerReviewId") + .HasColumnType("int"); + + b.Property("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DispatcherId") + .HasColumnType("int"); + + b.Property("DistanceTravelledAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DoctorId") + .HasColumnType("int"); + + b.Property("DriverId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Birthdate") + .HasColumnType("datetime2"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DebtId") + .HasColumnType("int"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("FinalMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CarId") + .HasColumnType("int"); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.ToTable("OilMark", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.OperatorReview", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OilMarkId") + .HasColumnType("int"); + + b.Property("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("OperatorId") + .HasColumnType("int"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("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 = "d6c0f8c6-b894-44ff-80f9-eb65961d8002", + Name = "Administrator", + NormalizedName = "ADMINISTRATOR" + }, + new + { + Id = "5bd07b96-507a-4b1a-b9ff-b421cfe1d205", + Name = "Driver", + NormalizedName = "DRIVER" + }, + new + { + Id = "8b08e145-6325-4046-b55c-77b9906966b5", + Name = "Doctor", + NormalizedName = "DOCTOR" + }, + new + { + Id = "ed4099e0-601c-414d-b763-f2151a29040d", + Name = "Dispatcher", + NormalizedName = "DISPATCHER" + }, + new + { + Id = "ee9613ef-226d-4fba-9ab3-9a07d902018b", + Name = "Manager", + NormalizedName = "MANAGER" + }, + new + { + Id = "7fbd87ba-5311-4855-b18f-54b7e711eb82", + Name = "Mechanic", + NormalizedName = "MECHANIC" + }, + new + { + Id = "c9734b82-c84a-43b2-b453-c4ff6eb8c1cf", + Name = "Operator", + NormalizedName = "OPERATOR" + }); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("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", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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/20241006103314_Add_Manager_ManagerReview.cs b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.cs new file mode 100644 index 00000000..68c99381 --- /dev/null +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/20241006103314_Add_Manager_ManagerReview.cs @@ -0,0 +1,178 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +#pragma warning disable CA1814 // Prefer jagged arrays over multidimensional + +namespace CheckDrive.Infrastructure.Persistence.Migrations; + +/// +public partial class Add_Manager_ManagerReview : Migration +{ + /// + 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.AddColumn( + name: "ManagerReviewId", + table: "Debt", + type: "int", + nullable: true); + + migrationBuilder.CreateTable( + name: "ManagerReview", + columns: table => new + { + Id = table.Column(type: "int", nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + DebtAmountAdjusment = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), + FuelConsumptionAdjustment = table.Column(type: "decimal(18,2)", precision: 18, scale: 2, nullable: true), + CheckPointId = table.Column(type: "int", nullable: false), + ManagerId = table.Column(type: "int", nullable: false), + DebtId = table.Column(type: "int", nullable: true), + Notes = table.Column(type: "nvarchar(max)", nullable: true), + Date = table.Column(type: "datetime2", nullable: false), + Status = table.Column(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_Debt_ManagerId", + column: x => x.ManagerId, + principalTable: "Debt", + 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[,] + { + { "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( + name: "IX_ManagerReview_CheckPointId", + table: "ManagerReview", + column: "CheckPointId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ManagerReview_ManagerId", + table: "ManagerReview", + column: "ManagerId", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ManagerReview"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "5bd07b96-507a-4b1a-b9ff-b421cfe1d205"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "7fbd87ba-5311-4855-b18f-54b7e711eb82"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "8b08e145-6325-4046-b55c-77b9906966b5"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "c9734b82-c84a-43b2-b453-c4ff6eb8c1cf"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "d6c0f8c6-b894-44ff-80f9-eb65961d8002"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "ed4099e0-601c-414d-b763-f2151a29040d"); + + migrationBuilder.DeleteData( + table: "Role", + keyColumn: "Id", + keyValue: "ee9613ef-226d-4fba-9ab3-9a07d902018b"); + + migrationBuilder.DropColumn( + name: "ManagerReviewId", + table: "Debt"); + + 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/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 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManufacturedYear") + .HasColumnType("int"); + + b.Property("Mileage") + .HasColumnType("int"); + + b.Property("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("YearlyDistanceLimit") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerReviewId") + .HasColumnType("int"); + + b.Property("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DispatcherId") + .HasColumnType("int"); + + b.Property("DistanceTravelledAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DoctorId") + .HasColumnType("int"); + + b.Property("DriverId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Birthdate") + .HasColumnType("datetime2"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DebtId") + .HasColumnType("int"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("FinalMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CarId") + .HasColumnType("int"); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OilMarkId") + .HasColumnType("int"); + + b.Property("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("OperatorId") + .HasColumnType("int"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("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", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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 +{ + /// + public partial class Add_Default_OilMarks : Migration + { + /// + 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" } + }); + } + + /// + 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/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 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("CurrentMonthMileage") + .HasColumnType("int"); + + b.Property("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManufacturedYear") + .HasColumnType("int"); + + b.Property("Mileage") + .HasColumnType("int"); + + b.Property("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("YearlyDistanceLimit") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerReviewId") + .HasColumnType("int"); + + b.Property("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DispatcherId") + .HasColumnType("int"); + + b.Property("DistanceTravelledAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DoctorId") + .HasColumnType("int"); + + b.Property("DriverId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Birthdate") + .HasColumnType("datetime2"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DebtId") + .HasColumnType("int"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("FinalMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CarId") + .HasColumnType("int"); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OilMarkId") + .HasColumnType("int"); + + b.Property("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("OperatorId") + .HasColumnType("int"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("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", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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 +{ + /// + public partial class Add_CarMonthlyMileage : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CurrentMonthMileage", + table: "Car", + type: "int", + nullable: false, + defaultValue: 0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "CurrentMonthMileage", + table: "Car"); + } + } +} 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 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("CurrentMonthMileage") + .HasColumnType("int"); + + b.Property("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManufacturedYear") + .HasColumnType("int"); + + b.Property("Mileage") + .HasColumnType("int"); + + b.Property("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("YearlyDistanceLimit") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Car", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.CheckPoint", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerReviewId") + .HasColumnType("int"); + + b.Property("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DispatcherId") + .HasColumnType("int"); + + b.Property("FinalMileageAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DoctorId") + .HasColumnType("int"); + + b.Property("DriverId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Birthdate") + .HasColumnType("datetime2"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DebtId") + .HasColumnType("int"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("FinalMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CarId") + .HasColumnType("int"); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OilMarkId") + .HasColumnType("int"); + + b.Property("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("OperatorId") + .HasColumnType("int"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("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", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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 +{ + /// + public partial class Rename_DispatcherReview_MileageProperty : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "DistanceTravelledAdjustment", + table: "DispatcherReview", + newName: "FinalMileageAdjustment"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "FinalMileageAdjustment", + table: "DispatcherReview", + newName: "DistanceTravelledAdjustment"); + } + } +} 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 @@ +// +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 + { + /// + 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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AverageFuelConsumption") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Color") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("CurrentMonthFuelConsumption") + .HasColumnType("decimal(18,2)"); + + b.Property("CurrentMonthMileage") + .HasColumnType("int"); + + b.Property("CurrentYearFuelConsumption") + .HasColumnType("decimal(18,2)"); + + b.Property("CurrentYearMileage") + .HasColumnType("int"); + + b.Property("FuelCapacity") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManufacturedYear") + .HasColumnType("int"); + + b.Property("Mileage") + .HasColumnType("int"); + + b.Property("Model") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("MonthlyDistanceLimit") + .HasColumnType("int"); + + b.Property("MonthlyFuelConsumptionLimit") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Number") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("nvarchar(10)"); + + b.Property("RemainingFuel") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("YearlyDistanceLimit") + .HasColumnType("int"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Notes") + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Stage") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.Property("StartDate") + .HasColumnType("datetime2"); + + b.Property("Status") + .ValueGeneratedOnAdd() + .HasColumnType("int") + .HasDefaultValue(0); + + b.HasKey("Id"); + + b.ToTable("CheckPoint", (string)null); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.Debt", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("FuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerReviewId") + .HasColumnType("int"); + + b.Property("PaidAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DispatcherId") + .HasColumnType("int"); + + b.Property("FinalMileageAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DoctorId") + .HasColumnType("int"); + + b.Property("DriverId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AccountId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Address") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)"); + + b.Property("Birthdate") + .HasColumnType("datetime2"); + + b.Property("FirstName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Passport") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("nvarchar(20)"); + + b.Property("Position") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("AccountId") + .IsUnique(); + + b.ToTable("Employee", (string)null); + + b.HasDiscriminator("Position").HasValue(0); + + b.UseTphMappingStrategy(); + }); + + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DebtId") + .HasColumnType("int"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("FinalMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("RemainingFuelAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CarId") + .HasColumnType("int"); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialMileage") + .HasColumnType("int"); + + b.Property("MechanicId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("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("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("InitialOilAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("OilMarkId") + .HasColumnType("int"); + + b.Property("OilRefillAmount") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("OperatorId") + .HasColumnType("int"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("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", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("UserClaim", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("UserLogin", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("UserRole", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("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", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", 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", 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 +{ + /// + public partial class UpdateCar_Limits : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "CurrentMonthFuelConsumption", + table: "Car", + type: "decimal(18,2)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn( + name: "CurrentYearFuelConsumption", + table: "Car", + type: "decimal(18,2)", + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn( + name: "CurrentYearMileage", + table: "Car", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "MonthlyDistanceLimit", + table: "Car", + type: "int", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "MonthlyFuelConsumptionLimit", + table: "Car", + type: "decimal(18,2)", + precision: 18, + scale: 2, + nullable: false, + defaultValue: 0m); + + migrationBuilder.AddColumn( + name: "YearlyFuelConsumptionLimit", + table: "Car", + type: "decimal(18,2)", + precision: 18, + scale: 2, + nullable: false, + defaultValue: 0m); + } + + /// + 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 343190cd..aecb6ca8 100644 --- a/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs +++ b/CheckDrive.Api/CheckDrive.Infrastructure/Persistence/Migrations/CheckDriveDbContextModelSnapshot.cs @@ -39,6 +39,18 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(500) .HasColumnType("nvarchar(500)"); + b.Property("CurrentMonthFuelConsumption") + .HasColumnType("decimal(18,2)"); + + b.Property("CurrentMonthMileage") + .HasColumnType("int"); + + b.Property("CurrentYearFuelConsumption") + .HasColumnType("decimal(18,2)"); + + b.Property("CurrentYearMileage") + .HasColumnType("int"); + b.Property("FuelCapacity") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -54,6 +66,13 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasMaxLength(500) .HasColumnType("nvarchar(500)"); + b.Property("MonthlyDistanceLimit") + .HasColumnType("int"); + + b.Property("MonthlyFuelConsumptionLimit") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + b.Property("Number") .IsRequired() .HasMaxLength(10) @@ -71,6 +90,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("YearlyDistanceLimit") .HasColumnType("int"); + b.Property("YearlyFuelConsumptionLimit") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + b.HasKey("Id"); b.ToTable("Car", (string)null); @@ -121,6 +144,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); + b.Property("ManagerReviewId") + .HasColumnType("int"); + b.Property("PaidAmount") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -155,7 +181,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("DispatcherId") .HasColumnType("int"); - b.Property("DistanceTravelledAdjustment") + b.Property("FinalMileageAdjustment") .HasPrecision(18, 2) .HasColumnType("decimal(18,2)"); @@ -267,6 +293,51 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.UseTphMappingStrategy(); }); + modelBuilder.Entity("CheckDrive.Domain.Entities.ManagerReview", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("CheckPointId") + .HasColumnType("int"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("DebtAmountAdjusment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("DebtId") + .HasColumnType("int"); + + b.Property("FuelConsumptionAdjustment") + .HasPrecision(18, 2) + .HasColumnType("decimal(18,2)"); + + b.Property("ManagerId") + .HasColumnType("int"); + + b.Property("Notes") + .HasColumnType("nvarchar(max)"); + + b.Property("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("Id") @@ -364,6 +435,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 => @@ -441,43 +539,43 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasData( new { - Id = "46a46741-5b52-444e-a5f9-169556a44c5b", + Id = "3b9cced9-80ba-4c29-b984-0ef814ed1e4a", Name = "Administrator", NormalizedName = "ADMINISTRATOR" }, new { - Id = "52e9693c-ccc2-453b-bb73-6f1987c60664", + Id = "eae91b8a-62a8-4910-a956-f31b3287908f", Name = "Driver", NormalizedName = "DRIVER" }, new { - Id = "d864ade1-ac59-4ab3-ba59-a6c12f3250e3", + Id = "e13e7081-caef-4e06-8356-845df18805c6", Name = "Doctor", NormalizedName = "DOCTOR" }, new { - Id = "8da8eab2-4243-44e1-bfae-0d7a86135bea", + Id = "d5ef47fb-bd3b-4743-b135-67248f9952ad", Name = "Dispatcher", NormalizedName = "DISPATCHER" }, new { - Id = "87ed0262-1d37-4824-ae87-f1a8119c9d50", + Id = "08318c7a-b4a0-47da-b66f-a07910fb4341", Name = "Manager", NormalizedName = "MANAGER" }, new { - Id = "bcaf852e-2688-44c1-aa77-4b2d65231832", + Id = "3c126479-5651-4026-816f-42ee1d22a878", Name = "Mechanic", NormalizedName = "MECHANIC" }, new { - Id = "d907a396-369a-4fde-8f7d-3918e185f554", + Id = "472d6cd0-94dd-4294-9c92-b60cb4063398", Name = "Operator", NormalizedName = "OPERATOR" }); @@ -675,6 +773,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 +862,33 @@ 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.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") @@ -895,6 +1027,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("DoctorReview") .IsRequired(); + b.Navigation("ManagerReview"); + b.Navigation("MechanicAcceptance"); b.Navigation("MechanicHandover"); @@ -902,6 +1036,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"); @@ -922,6 +1061,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"); 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; } } diff --git a/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs b/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs index 41d3fd87..8d3907e4 100644 --- a/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs +++ b/CheckDrive.Api/CheckDrive.TestDataCreator/FakeDataGenerator.cs @@ -31,6 +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.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)) 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 _mockContext; private readonly Mock _mockMapper; private readonly DoctorReviewService _service; + private readonly Mock> _mockHubContext; public DoctorReviewServiceTests() { _mockContext = new Mock(); _mockMapper = new Mock(); - _service = new DoctorReviewService(_mockContext.Object, _mockMapper.Object); + _mockHubContext = new Mock>(); + _service = new DoctorReviewService(_mockContext.Object, _mockMapper.Object, _mockHubContext.Object); } [Fact]