From abf7138d045e5ca47b6d91499d901c2297475e3b Mon Sep 17 00:00:00 2001 From: VishwaJaya01 Date: Sun, 20 Jul 2025 22:53:35 +0530 Subject: [PATCH 1/2] Enhance UserTaskController to include detailed task type counts and improve logging for task overview --- Controllers/UserTaskController.cs | 18 ++++++++++++------ Models/UserTask.cs | 3 +++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/Controllers/UserTaskController.cs b/Controllers/UserTaskController.cs index 4cebd2a..95165a8 100644 --- a/Controllers/UserTaskController.cs +++ b/Controllers/UserTaskController.cs @@ -20,12 +20,18 @@ public ActionResult GetTaskOverview([FromBody] UserTas { var userTasks = _context.UserTasks.Where(t => t.Username == request.Username).ToList(); - var laAssigned = userTasks.Count(t => t.TaskType == "LA"); - var laCompleted = userTasks.Count(t => t.TaskType == "LA" && t.IsCompleted); - var mrAssigned = userTasks.Count(t => t.TaskType == "MR"); - var mrCompleted = userTasks.Count(t => t.TaskType == "MR" && t.IsCompleted); - var lmAssigned = userTasks.Count(t => t.TaskType == "LM"); - var lmCompleted = userTasks.Count(t => t.TaskType == "LM" && t.IsCompleted); + // Debug log: print all userTasks for this user + Console.WriteLine($"UserTasks for {request.Username}: {string.Join(", ", userTasks.Select(t => $"{t.TaskType}:{t.IsCompleted}"))}"); + + var laAssigned = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "LA"); + var laCompleted = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "LA" && t.IsCompleted); + var mrAssigned = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "MR"); + var mrCompleted = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "MR" && t.IsCompleted); + var lmAssigned = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "LM"); + var lmCompleted = userTasks.Count(t => t.TaskType != null && t.TaskType.ToUpper() == "LM" && t.IsCompleted); + + // Debug log: print computed counts + Console.WriteLine($"LA: {laAssigned}, MR: {mrAssigned}, LM: {lmAssigned}, LA Done: {laCompleted}, MR Done: {mrCompleted}, LM Done: {lmCompleted}"); return Ok(new UserTaskOverviewResponse { diff --git a/Models/UserTask.cs b/Models/UserTask.cs index f778c15..b7734aa 100644 --- a/Models/UserTask.cs +++ b/Models/UserTask.cs @@ -1,5 +1,8 @@ +using System.ComponentModel.DataAnnotations.Schema; + namespace ValuationBackend.Models { + [Table("UserTasks")] public class UserTask { public int Id { get; set; } From e26d9116e4c4883cd8a528bd810e42664124e003 Mon Sep 17 00:00:00 2001 From: rithakith Date: Mon, 21 Jul 2025 16:00:45 +0530 Subject: [PATCH 2/2] offices rating card api --- .../iteration2/OfficesRatingCardController.cs | 204 ++++++++++++++++++ Data/AppDbContext.cs | 3 + Extensions/RepositoryExtensions.cs | 3 + Extensions/ServiceExtensions.cs | 2 + Migrations/AddOfficesRatingCardTable.cs | 77 +++++++ .../iteration2/DTOs/OfficesRatingCardDto.cs | 121 +++++++++++ .../RatingCards/OfficesRatingCard.cs | 113 ++++++++++ Profiles/OfficesRatingCardProfile.cs | 38 ++++ .../IOfficesRatingCardRepository.cs | 18 ++ .../iteration2/OfficesRatingCardRepository.cs | 84 ++++++++ .../iteration2/IOfficesRatingCardService.cs | 17 ++ .../iteration2/OfficesRatingCardService.cs | 134 ++++++++++++ 12 files changed, 814 insertions(+) create mode 100644 Controllers/iteration2/OfficesRatingCardController.cs create mode 100644 Migrations/AddOfficesRatingCardTable.cs create mode 100644 Models/iteration2/DTOs/OfficesRatingCardDto.cs create mode 100644 Models/iteration2/RatingCards/OfficesRatingCard.cs create mode 100644 Profiles/OfficesRatingCardProfile.cs create mode 100644 repositories/iteration2/IOfficesRatingCardRepository.cs create mode 100644 repositories/iteration2/OfficesRatingCardRepository.cs create mode 100644 services/iteration2/IOfficesRatingCardService.cs create mode 100644 services/iteration2/OfficesRatingCardService.cs diff --git a/Controllers/iteration2/OfficesRatingCardController.cs b/Controllers/iteration2/OfficesRatingCardController.cs new file mode 100644 index 0000000..65aeb93 --- /dev/null +++ b/Controllers/iteration2/OfficesRatingCardController.cs @@ -0,0 +1,204 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using ValuationBackend.Models.iteration2.DTOs; +using ValuationBackend.services.iteration2; + +namespace ValuationBackend.Controllers.iteration2 +{ + [Route("api/[controller]")] + [ApiController] + public class OfficesRatingCardController : ControllerBase + { + private readonly IOfficesRatingCardService _service; + private readonly ILogger _logger; + + public OfficesRatingCardController( + IOfficesRatingCardService service, + ILogger logger) + { + _service = service; + _logger = logger; + } + + /// + /// Get all offices rating cards + /// + [HttpGet] + public async Task>> GetAll() + { + try + { + var result = await _service.GetAllAsync(); + return Ok(result); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error retrieving all offices rating cards"); + return StatusCode(500, "An error occurred while retrieving offices rating cards."); + } + } + + /// + /// Get offices rating card by ID + /// + [HttpGet("{id}")] + public async Task> GetById(int id) + { + try + { + var result = await _service.GetByIdAsync(id); + return Ok(result); + } + catch (KeyNotFoundException) + { + return NotFound($"OfficesRatingCard with ID {id} not found."); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error retrieving offices rating card with ID {Id}", id); + return StatusCode(500, "An error occurred while retrieving the offices rating card."); + } + } + + /// + /// Get offices rating card by Asset ID + /// + [HttpGet("asset/{assetId}")] + public async Task> GetByAssetId(int assetId) + { + try + { + var result = await _service.GetByAssetIdAsync(assetId); + return Ok(result); + } + catch (KeyNotFoundException) + { + return NotFound($"OfficesRatingCard for Asset ID {assetId} not found."); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error retrieving offices rating card for Asset ID {AssetId}", assetId); + return StatusCode(500, "An error occurred while retrieving the offices rating card."); + } + } + + /// + /// Create a new offices rating card + /// + [HttpPost("asset/{assetId}")] + public async Task> Create(int assetId, [FromBody] CreateOfficesRatingCardDto dto) + { + try + { + if (dto == null) + { + return BadRequest("Invalid offices rating card data."); + } + + // Ensure the assetId from route matches the one in the body + dto.AssetId = assetId; + + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var result = await _service.CreateAsync(dto); + return CreatedAtAction(nameof(GetById), new { id = result.Id }, result); + } + catch (InvalidOperationException ex) + { + return Conflict(ex.Message); + } + catch (KeyNotFoundException ex) + { + return NotFound(ex.Message); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error creating offices rating card for Asset ID {AssetId}", assetId); + return StatusCode(500, "An error occurred while creating the offices rating card."); + } + } + + /// + /// Update an existing offices rating card + /// + [HttpPut("{id}")] + public async Task> Update(int id, [FromBody] UpdateOfficesRatingCardDto dto) + { + try + { + if (dto == null) + { + return BadRequest("Invalid offices rating card data."); + } + + if (!ModelState.IsValid) + { + return BadRequest(ModelState); + } + + var result = await _service.UpdateAsync(id, dto); + return Ok(result); + } + catch (KeyNotFoundException) + { + return NotFound($"OfficesRatingCard with ID {id} not found."); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error updating offices rating card with ID {Id}", id); + return StatusCode(500, "An error occurred while updating the offices rating card."); + } + } + + /// + /// Delete an offices rating card + /// + [HttpDelete("{id}")] + public async Task Delete(int id) + { + try + { + var result = await _service.DeleteAsync(id); + if (!result) + { + return NotFound($"OfficesRatingCard with ID {id} not found."); + } + + return NoContent(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error deleting offices rating card with ID {Id}", id); + return StatusCode(500, "An error occurred while deleting the offices rating card."); + } + } + + /// + /// Get autofill data for offices rating card + /// + [HttpGet("autofill/{assetId}")] + public async Task> GetAutofillData(int assetId) + { + try + { + var result = await _service.GetAutofillDataAsync(assetId); + return Ok(result); + } + catch (KeyNotFoundException) + { + return NotFound($"Asset with ID {assetId} not found."); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error retrieving autofill data for Asset ID {AssetId}", assetId); + return StatusCode(500, "An error occurred while retrieving autofill data."); + } + } + } +} \ No newline at end of file diff --git a/Data/AppDbContext.cs b/Data/AppDbContext.cs index b330b8c..2449d1a 100644 --- a/Data/AppDbContext.cs +++ b/Data/AppDbContext.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using ValuationBackend.Models; +using ValuationBackend.Models.iteration2.RatingCards; namespace ValuationBackend.Data { @@ -55,6 +56,8 @@ public AppDbContext(DbContextOptions options) public DbSet DomesticRatingCards { get; set; } + public DbSet OfficesRatingCards { get; set; } + public DbSet Assets { get; set; } public DbSet PropertyCategories { get; set; } diff --git a/Extensions/RepositoryExtensions.cs b/Extensions/RepositoryExtensions.cs index 35706d3..8792be5 100644 --- a/Extensions/RepositoryExtensions.cs +++ b/Extensions/RepositoryExtensions.cs @@ -1,4 +1,6 @@ using ValuationBackend.Repositories; +using ValuationBackend.repositories; +using ValuationBackend.repositories.iteration2; namespace ValuationBackend.Extensions { @@ -22,6 +24,7 @@ public static IServiceCollection AddRepositories(this IServiceCollection service services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/Extensions/ServiceExtensions.cs b/Extensions/ServiceExtensions.cs index 4e4bf45..6acb236 100644 --- a/Extensions/ServiceExtensions.cs +++ b/Extensions/ServiceExtensions.cs @@ -1,4 +1,5 @@ using ValuationBackend.Services; +using ValuationBackend.services.iteration2; namespace ValuationBackend.Extensions { @@ -15,6 +16,7 @@ public static IServiceCollection AddServices(this IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); services.AddScoped(); services.AddScoped(); services.AddScoped(); diff --git a/Migrations/AddOfficesRatingCardTable.cs b/Migrations/AddOfficesRatingCardTable.cs new file mode 100644 index 0000000..db1a9de --- /dev/null +++ b/Migrations/AddOfficesRatingCardTable.cs @@ -0,0 +1,77 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +namespace ValuationBackend.Migrations +{ + public partial class AddOfficesRatingCardTable : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "OfficesRatingCards", + columns: table => new + { + Id = table.Column(nullable: false) + .Annotation("SqlServer:Identity", "1, 1"), + AssetId = table.Column(nullable: false), + BuildingSelection = table.Column(maxLength: 100, nullable: true), + LocalAuthority = table.Column(maxLength: 200, nullable: true), + LocalAuthorityCode = table.Column(maxLength: 50, nullable: true), + AssessmentNumber = table.Column(maxLength: 50, nullable: true), + NewNumber = table.Column(maxLength: 50, nullable: true), + ObsoleteNumber = table.Column(maxLength: 50, nullable: true), + Owner = table.Column(maxLength: 200, nullable: true), + Description = table.Column(maxLength: 500, nullable: true), + WallType = table.Column(maxLength: 100, nullable: true), + FloorType = table.Column(maxLength: 100, nullable: true), + Conveniences = table.Column(maxLength: 100, nullable: true), + Condition = table.Column(maxLength: 50, nullable: true), + Age = table.Column(nullable: true), + AccessType = table.Column(maxLength: 100, nullable: true), + OfficeGrade = table.Column(maxLength: 50, nullable: true), + ParkingSpace = table.Column(maxLength: 200, nullable: true), + PropertySubCategory = table.Column(maxLength: 100, nullable: true), + PropertyType = table.Column(maxLength: 100, nullable: true), + WardNumber = table.Column(nullable: true), + RoadName = table.Column(maxLength: 200, nullable: true), + Date = table.Column(nullable: true), + Occupier = table.Column(maxLength: 200, nullable: true), + RentPM = table.Column(type: "decimal(18,2)", nullable: true), + Terms = table.Column(maxLength: 500, nullable: true), + FloorNumber = table.Column(nullable: true), + CeilingHeight = table.Column(type: "decimal(18,2)", nullable: true), + OfficeSuite = table.Column(maxLength: 1000, nullable: true), + TotalArea = table.Column(type: "decimal(18,2)", nullable: true), + UsableFloorArea = table.Column(type: "decimal(18,2)", nullable: true), + SuggestedRate = table.Column(type: "decimal(18,2)", nullable: true), + Notes = table.Column(maxLength: 2000, nullable: true), + CreatedAt = table.Column(nullable: false), + UpdatedAt = table.Column(nullable: true), + CreatedBy = table.Column(nullable: true), + UpdatedBy = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_OfficesRatingCards", x => x.Id); + table.ForeignKey( + name: "FK_OfficesRatingCards_Assets_AssetId", + column: x => x.AssetId, + principalTable: "Assets", + principalColumn: "Id", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateIndex( + name: "IX_OfficesRatingCards_AssetId", + table: "OfficesRatingCards", + column: "AssetId", + unique: true); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "OfficesRatingCards"); + } + } +} \ No newline at end of file diff --git a/Models/iteration2/DTOs/OfficesRatingCardDto.cs b/Models/iteration2/DTOs/OfficesRatingCardDto.cs new file mode 100644 index 0000000..ee79418 --- /dev/null +++ b/Models/iteration2/DTOs/OfficesRatingCardDto.cs @@ -0,0 +1,121 @@ +using System; +using System.ComponentModel.DataAnnotations; + +namespace ValuationBackend.Models.iteration2.DTOs +{ + public class OfficesRatingCardDto + { + public int Id { get; set; } + public int AssetId { get; set; } + public string BuildingSelection { get; set; } + public string LocalAuthority { get; set; } + public string LocalAuthorityCode { get; set; } + public string AssessmentNumber { get; set; } + public string NewNumber { get; set; } + public string ObsoleteNumber { get; set; } + public string Owner { get; set; } + public string Description { get; set; } + public string WallType { get; set; } + public string FloorType { get; set; } + public string Conveniences { get; set; } + public string Condition { get; set; } + public int? Age { get; set; } + public string AccessType { get; set; } + public string OfficeGrade { get; set; } + public string ParkingSpace { get; set; } + public string PropertySubCategory { get; set; } + public string PropertyType { get; set; } + public int? WardNumber { get; set; } + public string RoadName { get; set; } + public DateTime? Date { get; set; } + public string Occupier { get; set; } + public decimal? RentPM { get; set; } + public string Terms { get; set; } + public int? FloorNumber { get; set; } + public decimal? CeilingHeight { get; set; } + public string OfficeSuite { get; set; } + public decimal? TotalArea { get; set; } + public decimal? UsableFloorArea { get; set; } + public decimal? SuggestedRate { get; set; } + public string Notes { get; set; } + public DateTime CreatedAt { get; set; } + public DateTime? UpdatedAt { get; set; } + } + + public class CreateOfficesRatingCardDto + { + [Required] + public int AssetId { get; set; } + + public string BuildingSelection { get; set; } + public string LocalAuthority { get; set; } + public string LocalAuthorityCode { get; set; } + public string AssessmentNumber { get; set; } + public string NewNumber { get; set; } + public string ObsoleteNumber { get; set; } + public string Owner { get; set; } + public string Description { get; set; } + public string WallType { get; set; } + public string FloorType { get; set; } + public string Conveniences { get; set; } + public string Condition { get; set; } + public int? Age { get; set; } + public string AccessType { get; set; } + public string OfficeGrade { get; set; } + public string ParkingSpace { get; set; } + public string PropertySubCategory { get; set; } + public string PropertyType { get; set; } + public int? WardNumber { get; set; } + public string RoadName { get; set; } + public DateTime? Date { get; set; } + public string Occupier { get; set; } + public decimal? RentPM { get; set; } + public string Terms { get; set; } + public int? FloorNumber { get; set; } + public decimal? CeilingHeight { get; set; } + public string OfficeSuite { get; set; } + public decimal? TotalArea { get; set; } + public decimal? UsableFloorArea { get; set; } + public decimal? SuggestedRate { get; set; } + public string Notes { get; set; } + } + + public class UpdateOfficesRatingCardDto + { + public string BuildingSelection { get; set; } + public string LocalAuthority { get; set; } + public string LocalAuthorityCode { get; set; } + public string AssessmentNumber { get; set; } + public string ObsoleteNumber { get; set; } + public string WallType { get; set; } + public string FloorType { get; set; } + public string Conveniences { get; set; } + public string Condition { get; set; } + public int? Age { get; set; } + public string AccessType { get; set; } + public string OfficeGrade { get; set; } + public string ParkingSpace { get; set; } + public string PropertySubCategory { get; set; } + public string PropertyType { get; set; } + public int? WardNumber { get; set; } + public string RoadName { get; set; } + public DateTime? Date { get; set; } + public string Occupier { get; set; } + public decimal? RentPM { get; set; } + public string Terms { get; set; } + public int? FloorNumber { get; set; } + public decimal? CeilingHeight { get; set; } + public string OfficeSuite { get; set; } + public decimal? TotalArea { get; set; } + public decimal? UsableFloorArea { get; set; } + public decimal? SuggestedRate { get; set; } + public string Notes { get; set; } + } + + public class OfficesRatingCardAutofillDto + { + public string NewNumber { get; set; } + public string Owner { get; set; } + public string Description { get; set; } + } +} \ No newline at end of file diff --git a/Models/iteration2/RatingCards/OfficesRatingCard.cs b/Models/iteration2/RatingCards/OfficesRatingCard.cs new file mode 100644 index 0000000..eb61a35 --- /dev/null +++ b/Models/iteration2/RatingCards/OfficesRatingCard.cs @@ -0,0 +1,113 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; + +namespace ValuationBackend.Models.iteration2.RatingCards +{ + public class OfficesRatingCard + { + [Key] + public int Id { get; set; } + + [Required] + public int AssetId { get; set; } + + [ForeignKey("AssetId")] + public virtual Asset Asset { get; set; } + + [StringLength(100)] + public string BuildingSelection { get; set; } + + [StringLength(200)] + public string LocalAuthority { get; set; } + + [StringLength(50)] + public string LocalAuthorityCode { get; set; } + + [StringLength(50)] + public string AssessmentNumber { get; set; } + + [StringLength(50)] + public string NewNumber { get; set; } + + [StringLength(50)] + public string ObsoleteNumber { get; set; } + + [StringLength(200)] + public string Owner { get; set; } + + [StringLength(500)] + public string Description { get; set; } + + [StringLength(100)] + public string WallType { get; set; } + + [StringLength(100)] + public string FloorType { get; set; } + + [StringLength(100)] + public string Conveniences { get; set; } + + [StringLength(50)] + public string Condition { get; set; } + + public int? Age { get; set; } + + [StringLength(100)] + public string AccessType { get; set; } + + [StringLength(50)] + public string OfficeGrade { get; set; } + + [StringLength(200)] + public string ParkingSpace { get; set; } + + [StringLength(100)] + public string PropertySubCategory { get; set; } + + [StringLength(100)] + public string PropertyType { get; set; } + + public int? WardNumber { get; set; } + + [StringLength(200)] + public string RoadName { get; set; } + + public DateTime? Date { get; set; } + + [StringLength(200)] + public string Occupier { get; set; } + + [Column(TypeName = "decimal(18,2)")] + public decimal? RentPM { get; set; } + + [StringLength(500)] + public string Terms { get; set; } + + public int? FloorNumber { get; set; } + + [Column(TypeName = "decimal(18,2)")] + public decimal? CeilingHeight { get; set; } + + [StringLength(1000)] + public string OfficeSuite { get; set; } + + [Column(TypeName = "decimal(18,2)")] + public decimal? TotalArea { get; set; } + + [Column(TypeName = "decimal(18,2)")] + public decimal? UsableFloorArea { get; set; } + + [Column(TypeName = "decimal(18,2)")] + public decimal? SuggestedRate { get; set; } + + [StringLength(2000)] + public string Notes { get; set; } + + // Audit fields + public DateTime CreatedAt { get; set; } + public DateTime? UpdatedAt { get; set; } + public string CreatedBy { get; set; } + public string UpdatedBy { get; set; } + } +} \ No newline at end of file diff --git a/Profiles/OfficesRatingCardProfile.cs b/Profiles/OfficesRatingCardProfile.cs new file mode 100644 index 0000000..a9f84b1 --- /dev/null +++ b/Profiles/OfficesRatingCardProfile.cs @@ -0,0 +1,38 @@ +using AutoMapper; +using ValuationBackend.Models.iteration2.DTOs; +using ValuationBackend.Models.iteration2.RatingCards; + +namespace ValuationBackend.Profiles +{ + public class OfficesRatingCardProfile : Profile + { + public OfficesRatingCardProfile() + { + // Entity to DTO + CreateMap(); + + // Create DTO to Entity + CreateMap() + .ForMember(dest => dest.Id, opt => opt.Ignore()) + .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) + .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) + .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) + .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()) + .ForMember(dest => dest.Asset, opt => opt.Ignore()); + + // Update DTO to Entity + CreateMap() + .ForMember(dest => dest.Id, opt => opt.Ignore()) + .ForMember(dest => dest.AssetId, opt => opt.Ignore()) + .ForMember(dest => dest.NewNumber, opt => opt.Ignore()) + .ForMember(dest => dest.Owner, opt => opt.Ignore()) + .ForMember(dest => dest.Description, opt => opt.Ignore()) + .ForMember(dest => dest.CreatedAt, opt => opt.Ignore()) + .ForMember(dest => dest.UpdatedAt, opt => opt.Ignore()) + .ForMember(dest => dest.CreatedBy, opt => opt.Ignore()) + .ForMember(dest => dest.UpdatedBy, opt => opt.Ignore()) + .ForMember(dest => dest.Asset, opt => opt.Ignore()) + .ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null)); + } + } +} \ No newline at end of file diff --git a/repositories/iteration2/IOfficesRatingCardRepository.cs b/repositories/iteration2/IOfficesRatingCardRepository.cs new file mode 100644 index 0000000..a2bb444 --- /dev/null +++ b/repositories/iteration2/IOfficesRatingCardRepository.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ValuationBackend.Models.iteration2.RatingCards; + +namespace ValuationBackend.repositories.iteration2 +{ + public interface IOfficesRatingCardRepository + { + Task> GetAllAsync(); + Task GetByIdAsync(int id); + Task GetByAssetIdAsync(int assetId); + Task CreateAsync(OfficesRatingCard officesRatingCard); + Task UpdateAsync(OfficesRatingCard officesRatingCard); + Task DeleteAsync(int id); + Task ExistsAsync(int id); + Task ExistsByAssetIdAsync(int assetId); + } +} \ No newline at end of file diff --git a/repositories/iteration2/OfficesRatingCardRepository.cs b/repositories/iteration2/OfficesRatingCardRepository.cs new file mode 100644 index 0000000..ec7fb17 --- /dev/null +++ b/repositories/iteration2/OfficesRatingCardRepository.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using ValuationBackend.Data; +using ValuationBackend.Models.iteration2.RatingCards; + +namespace ValuationBackend.repositories.iteration2 +{ + public class OfficesRatingCardRepository : IOfficesRatingCardRepository + { + private readonly AppDbContext _context; + + public OfficesRatingCardRepository(AppDbContext context) + { + _context = context; + } + + public async Task> GetAllAsync() + { + return await _context.OfficesRatingCards + .Include(o => o.Asset) + .ToListAsync(); + } + + public async Task GetByIdAsync(int id) + { + return await _context.OfficesRatingCards + .Include(o => o.Asset) + .FirstOrDefaultAsync(o => o.Id == id); + } + + public async Task GetByAssetIdAsync(int assetId) + { + return await _context.OfficesRatingCards + .Include(o => o.Asset) + .FirstOrDefaultAsync(o => o.AssetId == assetId); + } + + public async Task CreateAsync(OfficesRatingCard officesRatingCard) + { + officesRatingCard.CreatedAt = DateTime.UtcNow; + _context.OfficesRatingCards.Add(officesRatingCard); + await _context.SaveChangesAsync(); + return officesRatingCard; + } + + public async Task UpdateAsync(OfficesRatingCard officesRatingCard) + { + officesRatingCard.UpdatedAt = DateTime.UtcNow; + _context.Entry(officesRatingCard).State = EntityState.Modified; + + // Don't update these fields + _context.Entry(officesRatingCard).Property(x => x.CreatedAt).IsModified = false; + _context.Entry(officesRatingCard).Property(x => x.CreatedBy).IsModified = false; + _context.Entry(officesRatingCard).Property(x => x.AssetId).IsModified = false; + + await _context.SaveChangesAsync(); + return officesRatingCard; + } + + public async Task DeleteAsync(int id) + { + var officesRatingCard = await _context.OfficesRatingCards.FindAsync(id); + if (officesRatingCard == null) + return false; + + _context.OfficesRatingCards.Remove(officesRatingCard); + await _context.SaveChangesAsync(); + return true; + } + + public async Task ExistsAsync(int id) + { + return await _context.OfficesRatingCards.AnyAsync(o => o.Id == id); + } + + public async Task ExistsByAssetIdAsync(int assetId) + { + return await _context.OfficesRatingCards.AnyAsync(o => o.AssetId == assetId); + } + } +} \ No newline at end of file diff --git a/services/iteration2/IOfficesRatingCardService.cs b/services/iteration2/IOfficesRatingCardService.cs new file mode 100644 index 0000000..bdc21d3 --- /dev/null +++ b/services/iteration2/IOfficesRatingCardService.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using ValuationBackend.Models.iteration2.DTOs; + +namespace ValuationBackend.services.iteration2 +{ + public interface IOfficesRatingCardService + { + Task> GetAllAsync(); + Task GetByIdAsync(int id); + Task GetByAssetIdAsync(int assetId); + Task CreateAsync(CreateOfficesRatingCardDto dto); + Task UpdateAsync(int id, UpdateOfficesRatingCardDto dto); + Task DeleteAsync(int id); + Task GetAutofillDataAsync(int assetId); + } +} \ No newline at end of file diff --git a/services/iteration2/OfficesRatingCardService.cs b/services/iteration2/OfficesRatingCardService.cs new file mode 100644 index 0000000..6b85009 --- /dev/null +++ b/services/iteration2/OfficesRatingCardService.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AutoMapper; +using Microsoft.AspNetCore.Http; +using ValuationBackend.Models.iteration2.DTOs; +using ValuationBackend.Models.iteration2.RatingCards; +using ValuationBackend.repositories; +using ValuationBackend.repositories.iteration2; + +namespace ValuationBackend.services.iteration2 +{ + public class OfficesRatingCardService : IOfficesRatingCardService + { + private readonly IOfficesRatingCardRepository _repository; + private readonly IAssetRepository _assetRepository; + private readonly IMapper _mapper; + private readonly IHttpContextAccessor _httpContextAccessor; + + public OfficesRatingCardService( + IOfficesRatingCardRepository repository, + IAssetRepository assetRepository, + IMapper mapper, + IHttpContextAccessor httpContextAccessor) + { + _repository = repository; + _assetRepository = assetRepository; + _mapper = mapper; + _httpContextAccessor = httpContextAccessor; + } + + public async Task> GetAllAsync() + { + var entities = await _repository.GetAllAsync(); + return _mapper.Map>(entities); + } + + public async Task GetByIdAsync(int id) + { + var entity = await _repository.GetByIdAsync(id); + if (entity == null) + throw new KeyNotFoundException($"OfficesRatingCard with ID {id} not found."); + + return _mapper.Map(entity); + } + + public async Task GetByAssetIdAsync(int assetId) + { + var entity = await _repository.GetByAssetIdAsync(assetId); + if (entity == null) + throw new KeyNotFoundException($"OfficesRatingCard for Asset ID {assetId} not found."); + + return _mapper.Map(entity); + } + + public async Task CreateAsync(CreateOfficesRatingCardDto dto) + { + // Check if rating card already exists for this asset + if (await _repository.ExistsByAssetIdAsync(dto.AssetId)) + { + throw new InvalidOperationException($"OfficesRatingCard already exists for Asset ID {dto.AssetId}."); + } + + // Get asset details for auto-generation + var asset = await _assetRepository.GetByIdAsync(dto.AssetId); + if (asset == null) + { + throw new KeyNotFoundException($"Asset with ID {dto.AssetId} not found."); + } + + var entity = _mapper.Map(dto); + + // Auto-generate fields from asset if not provided + if (string.IsNullOrWhiteSpace(entity.NewNumber)) + entity.NewNumber = asset.NewNumber; + + if (string.IsNullOrWhiteSpace(entity.Owner)) + entity.Owner = asset.Owner; + + if (string.IsNullOrWhiteSpace(entity.Description)) + entity.Description = asset.Description; + + // Set audit fields + entity.CreatedBy = GetCurrentUser(); + entity.CreatedAt = DateTime.UtcNow; + + var created = await _repository.CreateAsync(entity); + return _mapper.Map(created); + } + + public async Task UpdateAsync(int id, UpdateOfficesRatingCardDto dto) + { + var entity = await _repository.GetByIdAsync(id); + if (entity == null) + throw new KeyNotFoundException($"OfficesRatingCard with ID {id} not found."); + + _mapper.Map(dto, entity); + + // Set audit fields + entity.UpdatedBy = GetCurrentUser(); + entity.UpdatedAt = DateTime.UtcNow; + + var updated = await _repository.UpdateAsync(entity); + return _mapper.Map(updated); + } + + public async Task DeleteAsync(int id) + { + return await _repository.DeleteAsync(id); + } + + public async Task GetAutofillDataAsync(int assetId) + { + var asset = await _assetRepository.GetByIdAsync(assetId); + if (asset == null) + { + throw new KeyNotFoundException($"Asset with ID {assetId} not found."); + } + + return new OfficesRatingCardAutofillDto + { + NewNumber = asset.NewNumber, + Owner = asset.Owner, + Description = asset.Description + }; + } + + private string GetCurrentUser() + { + return _httpContextAccessor.HttpContext?.User?.Identity?.Name ?? "System"; + } + } +} \ No newline at end of file