Added the project branch in job ticket table

This commit is contained in:
ashutosh.nehete 2025-11-19 18:11:54 +05:30
parent dad135571d
commit 4108915b92
12 changed files with 9060 additions and 16 deletions

View File

@ -1286,8 +1286,8 @@ namespace Marco.Pms.DataAccess.Data
new JobStatus { Id = Guid.Parse("32d76a02-8f44-4aa0-9b66-c3716c45a918"), Name = "New", DisplayName = "New", Level = 1 }, new JobStatus { Id = Guid.Parse("32d76a02-8f44-4aa0-9b66-c3716c45a918"), Name = "New", DisplayName = "New", Level = 1 },
new JobStatus { Id = Guid.Parse("cfa1886d-055f-4ded-84c6-42a2a8a14a66"), Name = "Assigned", DisplayName = "Assigned", Level = 2 }, new JobStatus { Id = Guid.Parse("cfa1886d-055f-4ded-84c6-42a2a8a14a66"), Name = "Assigned", DisplayName = "Assigned", Level = 2 },
new JobStatus { Id = Guid.Parse("5a6873a5-fed7-4745-a52f-8f61bf3bd72d"), Name = "In Progress", DisplayName = "In Progress", Level = 3 }, new JobStatus { Id = Guid.Parse("5a6873a5-fed7-4745-a52f-8f61bf3bd72d"), Name = "In Progress", DisplayName = "In Progress", Level = 3 },
new JobStatus { Id = Guid.Parse("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"), Name = "Review", DisplayName = "Review", Level = 4 }, new JobStatus { Id = Guid.Parse("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"), Name = "Work Done", DisplayName = "Work Done", Level = 4 },
new JobStatus { Id = Guid.Parse("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"), Name = "Done", DisplayName = "Done", Level = 5 }, new JobStatus { Id = Guid.Parse("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"), Name = "Review Done", DisplayName = "Review Done", Level = 5 },
new JobStatus { Id = Guid.Parse("3ddeefb5-ae3c-4e10-a922-35e0a452bb69"), Name = "Closed", DisplayName = "Closed", Level = 6 }, new JobStatus { Id = Guid.Parse("3ddeefb5-ae3c-4e10-a922-35e0a452bb69"), Name = "Closed", DisplayName = "Closed", Level = 6 },
new JobStatus { Id = Guid.Parse("75a0c8b8-9c6a-41af-80bf-b35bab722eb2"), Name = "On Hold", DisplayName = "On Hold", Level = 7 } new JobStatus { Id = Guid.Parse("75a0c8b8-9c6a-41af-80bf-b35bab722eb2"), Name = "On Hold", DisplayName = "On Hold", Level = 7 }
); );

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,78 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Marco.Pms.DataAccess.Migrations
{
/// <inheritdoc />
public partial class Added_ProjectBranch_As_ForignKey_In_JobTickets_Table : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<Guid>(
name: "ProjectBranchId",
table: "JobTickets",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
migrationBuilder.UpdateData(
table: "JobStatus",
keyColumn: "Id",
keyValue: new Guid("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"),
columns: new[] { "DisplayName", "Name" },
values: new object[] { "Work Done", "Work Done" });
migrationBuilder.UpdateData(
table: "JobStatus",
keyColumn: "Id",
keyValue: new Guid("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"),
columns: new[] { "DisplayName", "Name" },
values: new object[] { "Review Done", "Review Done" });
migrationBuilder.CreateIndex(
name: "IX_JobTickets_ProjectBranchId",
table: "JobTickets",
column: "ProjectBranchId");
migrationBuilder.AddForeignKey(
name: "FK_JobTickets_ProjectBranches_ProjectBranchId",
table: "JobTickets",
column: "ProjectBranchId",
principalTable: "ProjectBranches",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_JobTickets_ProjectBranches_ProjectBranchId",
table: "JobTickets");
migrationBuilder.DropIndex(
name: "IX_JobTickets_ProjectBranchId",
table: "JobTickets");
migrationBuilder.DropColumn(
name: "ProjectBranchId",
table: "JobTickets");
migrationBuilder.UpdateData(
table: "JobStatus",
keyColumn: "Id",
keyValue: new Guid("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"),
columns: new[] { "DisplayName", "Name" },
values: new object[] { "Review", "Review" });
migrationBuilder.UpdateData(
table: "JobStatus",
keyColumn: "Id",
keyValue: new Guid("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"),
columns: new[] { "DisplayName", "Name" },
values: new object[] { "Done", "Done" });
}
}
}

View File

@ -5261,16 +5261,16 @@ namespace Marco.Pms.DataAccess.Migrations
new new
{ {
Id = new Guid("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"), Id = new Guid("aab71020-2fb8-44d9-9430-c9a7e9bf33b0"),
DisplayName = "Review", DisplayName = "Work Done",
Level = 4, Level = 4,
Name = "Review" Name = "Work Done"
}, },
new new
{ {
Id = new Guid("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"), Id = new Guid("ed10ab57-dbaa-4ca5-8ecd-56745dcbdbd7"),
DisplayName = "Done", DisplayName = "Review Done",
Level = 5, Level = 5,
Name = "Done" Name = "Review Done"
}, },
new new
{ {
@ -5494,6 +5494,9 @@ namespace Marco.Pms.DataAccess.Migrations
b.Property<bool>("IsActive") b.Property<bool>("IsActive")
.HasColumnType("tinyint(1)"); .HasColumnType("tinyint(1)");
b.Property<Guid?>("ProjectBranchId")
.HasColumnType("char(36)");
b.Property<Guid>("ProjectId") b.Property<Guid>("ProjectId")
.HasColumnType("char(36)"); .HasColumnType("char(36)");
@ -5527,6 +5530,8 @@ namespace Marco.Pms.DataAccess.Migrations
b.HasIndex("CreatedById"); b.HasIndex("CreatedById");
b.HasIndex("ProjectBranchId");
b.HasIndex("ProjectId"); b.HasIndex("ProjectId");
b.HasIndex("StatusId"); b.HasIndex("StatusId");
@ -8478,6 +8483,10 @@ namespace Marco.Pms.DataAccess.Migrations
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
.IsRequired(); .IsRequired();
b.HasOne("Marco.Pms.Model.ServiceProject.ProjectBranch", "ProjectBranch")
.WithMany()
.HasForeignKey("ProjectBranchId");
b.HasOne("Marco.Pms.Model.ServiceProject.ServiceProject", "Project") b.HasOne("Marco.Pms.Model.ServiceProject.ServiceProject", "Project")
.WithMany() .WithMany()
.HasForeignKey("ProjectId") .HasForeignKey("ProjectId")
@ -8504,6 +8513,8 @@ namespace Marco.Pms.DataAccess.Migrations
b.Navigation("Project"); b.Navigation("Project");
b.Navigation("ProjectBranch");
b.Navigation("Status"); b.Navigation("Status");
b.Navigation("Tenant"); b.Navigation("Tenant");

View File

@ -8,6 +8,7 @@ namespace Marco.Pms.Model.Dtos.ServiceProject
public required string Title { get; set; } public required string Title { get; set; }
public required string Description { get; set; } public required string Description { get; set; }
public required Guid ProjectId { get; set; } public required Guid ProjectId { get; set; }
public Guid? ProjectBranchId { get; set; }
public List<BasicEmployeeDto>? Assignees { get; set; } public List<BasicEmployeeDto>? Assignees { get; set; }
public required DateTime StartDate { get; set; } public required DateTime StartDate { get; set; }
public required DateTime DueDate { get; set; } public required DateTime DueDate { get; set; }

View File

@ -7,7 +7,6 @@ namespace Marco.Pms.Model.Dtos.ServiceProject
{ {
public string? Title { get; set; } public string? Title { get; set; }
public string? Description { get; set; } public string? Description { get; set; }
public Guid ProjectId { get; set; }
public Guid StatusId { get; set; } public Guid StatusId { get; set; }
public List<BasicEmployeeDto>? Assignees { get; set; } public List<BasicEmployeeDto>? Assignees { get; set; }
public DateTime StartDate { get; set; } public DateTime StartDate { get; set; }

View File

@ -17,6 +17,11 @@ namespace Marco.Pms.Model.ServiceProject
[ValidateNever] [ValidateNever]
[ForeignKey("ProjectId")] [ForeignKey("ProjectId")]
public ServiceProject? Project { get; set; } public ServiceProject? Project { get; set; }
public Guid? ProjectBranchId { get; set; }
[ValidateNever]
[ForeignKey("ProjectBranchId")]
public ProjectBranch? ProjectBranch { get; set; }
public Guid StatusId { get; set; } public Guid StatusId { get; set; }
[ValidateNever] [ValidateNever]

View File

@ -0,0 +1,9 @@
namespace Marco.Pms.Model.ViewModels.ServiceProject
{
public class BasicProjectBranchVM
{
public Guid Id { get; set; }
public string? BranchName { get; set; }
public string? BranchType { get; set; } // HQ, ATMs, Bank Branches, Overcounter desk
}
}

View File

@ -6,8 +6,5 @@
public string? Name { get; set; } public string? Name { get; set; }
public string? ShortName { get; set; } public string? ShortName { get; set; }
public DateTime AssignedDate { get; set; } public DateTime AssignedDate { get; set; }
public string? ContactName { get; set; }
public string? ContactPhone { get; set; }
public string? ContactEmail { get; set; }
} }
} }

View File

@ -11,6 +11,7 @@ namespace Marco.Pms.Model.ViewModels.ServiceProject
public string? Description { get; set; } public string? Description { get; set; }
public string? JobTicketUId { get; set; } public string? JobTicketUId { get; set; }
public BasicServiceProjectVM? Project { get; set; } public BasicServiceProjectVM? Project { get; set; }
public BasicProjectBranchVM? ProjectBranch { get; set; }
public List<BasicEmployeeVM>? Assignees { get; set; } public List<BasicEmployeeVM>? Assignees { get; set; }
public JobStatus? Status { get; set; } public JobStatus? Status { get; set; }
public DateTime StartDate { get; set; } public DateTime StartDate { get; set; }

View File

@ -204,6 +204,7 @@ namespace Marco.Pms.Services.MappingProfiles
CreateMap<ProjectBranchDto, ProjectBranch>(); CreateMap<ProjectBranchDto, ProjectBranch>();
CreateMap<ProjectBranch, ProjectBranchVM>(); CreateMap<ProjectBranch, ProjectBranchVM>();
CreateMap<ProjectBranch, ProjectBranchDetailsVM>(); CreateMap<ProjectBranch, ProjectBranchDetailsVM>();
CreateMap<ProjectBranch, BasicProjectBranchVM>();
#endregion #endregion
//#region ======================================================= Talking Points ======================================================= //#region ======================================================= Talking Points =======================================================

View File

@ -96,7 +96,8 @@ namespace Marco.Pms.Services.Service
{ {
var normalizedSearch = searchString.Trim().ToLowerInvariant(); var normalizedSearch = searchString.Trim().ToLowerInvariant();
serviceProjectQuery = serviceProjectQuery serviceProjectQuery = serviceProjectQuery
.Where(sp => sp.Name.ToLower().Contains(normalizedSearch)); .Where(sp => sp.Name.ToLower().Contains(normalizedSearch) ||
(!string.IsNullOrWhiteSpace(sp.ShortName) && sp.ShortName.ToLower().Contains(normalizedSearch)));
} }
// Calculate total count and pages for pagination metadata // Calculate total count and pages for pagination metadata
@ -756,7 +757,7 @@ namespace Marco.Pms.Services.Service
// Validate existence of related service project for given tenant // Validate existence of related service project for given tenant
var serviceProject = await _context.ServiceProjects var serviceProject = await _context.ServiceProjects
.AsNoTracking() .AsNoTracking()
.FirstOrDefaultAsync(sp => sp.Id == model.ProjectId && sp.TenantId == tenantId); .FirstOrDefaultAsync(sp => sp.Id == model.ProjectId && sp.TenantId == tenantId && sp.IsActive);
if (serviceProject == null) if (serviceProject == null)
{ {
@ -1533,6 +1534,7 @@ namespace Marco.Pms.Services.Service
.Include(jt => jt.Status) .Include(jt => jt.Status)
.Include(jt => jt.Project) .Include(jt => jt.Project)
.Include(jt => jt.CreatedBy).ThenInclude(e => e!.JobRole) .Include(jt => jt.CreatedBy).ThenInclude(e => e!.JobRole)
.Include(jt => jt.ProjectBranch)
.AsNoTracking() .AsNoTracking()
.FirstOrDefaultAsync(jt => .FirstOrDefaultAsync(jt =>
jt.Id == id && jt.Id == id &&
@ -1730,6 +1732,40 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.ErrorResponse("Service project not found", "Service project not found or inactive", 404); return ApiResponse<object>.ErrorResponse("Service project not found", "Service project not found or inactive", 404);
} }
if (model.ProjectBranchId.HasValue)
{
// Log the attempt to fetch project branch
_logger.LogInfo("Attempting to fetch project branch with ID: {ProjectBranchId}, Project ID: {ProjectId}, Tenant ID: {TenantId}",
model.ProjectBranchId, serviceProject.Id, tenantId);
// Query project branch with all necessary filters
var projectBranch = await _context.ProjectBranches
.AsNoTracking()
.FirstOrDefaultAsync(pb =>
pb.Id == model.ProjectBranchId.Value &&
pb.ProjectId == serviceProject.Id &&
pb.TenantId == tenantId &&
pb.IsActive);
// Check if project branch exists
if (projectBranch == null)
{
// Log the failure to find project branch
_logger.LogWarning("Project branch not found for ID: {ProjectBranchId}, Project ID: {ProjectId}, Tenant ID: {TenantId}",
model.ProjectBranchId, serviceProject.Id, tenantId);
// Return a structured error response
return ApiResponse<object>.ErrorResponse(
"Project branch not found",
"The specified project branch does not exist or is not active for the given project and tenant.",
404);
}
// Log successful retrieval
_logger.LogInfo("Successfully retrieved project branch with ID: {ProjectBranchId}", model.ProjectBranchId);
}
var hasAssignees = model.Assignees?.Any(a => a.IsActive) ?? false; var hasAssignees = model.Assignees?.Any(a => a.IsActive) ?? false;
string uIDPrefix = $"JT/{DateTime.Now:MMyy}"; string uIDPrefix = $"JT/{DateTime.Now:MMyy}";
@ -1990,7 +2026,7 @@ namespace Marco.Pms.Services.Service
var projectTask = Task.Run(async () => var projectTask = Task.Run(async () =>
{ {
await using var context = await _dbContextFactory.CreateDbContextAsync(); await using var context = await _dbContextFactory.CreateDbContextAsync();
return await context.ServiceProjects.FirstOrDefaultAsync(sp => sp.Id == model.ProjectId && sp.TenantId == tenantId && sp.IsActive); return await context.ServiceProjects.FirstOrDefaultAsync(sp => sp.Id == jobTicket.ProjectId && sp.TenantId == tenantId && sp.IsActive);
}); });
var statusTask = Task.Run(async () => var statusTask = Task.Run(async () =>
{ {
@ -2003,7 +2039,7 @@ namespace Marco.Pms.Services.Service
// Validate existence of foreign entities // Validate existence of foreign entities
if (projectTask.Result == null) if (projectTask.Result == null)
{ {
_logger.LogWarning("Service project not found during job ticket update. ProjectId: {ProjectId}, TenantId: {TenantId}", model.ProjectId, tenantId); _logger.LogWarning("Service project not found during job ticket update. ProjectId: {ProjectId}, TenantId: {TenantId}", jobTicket.ProjectId, tenantId);
return ApiResponse<object>.ErrorResponse("Service project not found", "Service project not found", 404); return ApiResponse<object>.ErrorResponse("Service project not found", "Service project not found", 404);
} }
if (statusTask.Result == null) if (statusTask.Result == null)
@ -2197,13 +2233,13 @@ namespace Marco.Pms.Services.Service
{ {
await transaction.RollbackAsync(); await transaction.RollbackAsync();
_logger.LogError(dbEx, "Database error while updating job ticket for project {ProjectId} by employee {EmployeeId} in tenant {TenantId}", _logger.LogError(dbEx, "Database error while updating job ticket for project {ProjectId} by employee {EmployeeId} in tenant {TenantId}",
model.ProjectId, loggedInEmployee.Id, tenantId); jobTicket.ProjectId, loggedInEmployee.Id, tenantId);
return ApiResponse<object>.ErrorResponse("Database Error", "An error occurred while saving data to the database.", 500); return ApiResponse<object>.ErrorResponse("Database Error", "An error occurred while saving data to the database.", 500);
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Unhandled exception while updating job ticket for project {ProjectId} by employee {EmployeeId} in tenant {TenantId}", _logger.LogError(ex, "Unhandled exception while updating job ticket for project {ProjectId} by employee {EmployeeId} in tenant {TenantId}",
model.ProjectId, loggedInEmployee.Id, tenantId); jobTicket.ProjectId, loggedInEmployee.Id, tenantId);
return ApiResponse<object>.ErrorResponse("Internal Server Error", "An unexpected error occurred.", 500); return ApiResponse<object>.ErrorResponse("Internal Server Error", "An unexpected error occurred.", 500);
} }
} }