Added Approve task API in task Controller
This commit is contained in:
parent
d8ee5940fd
commit
c113805ff9
3280
Marco.Pms.DataAccess/Migrations/20250614044441_Added_Apporved_By_In_TaskAllocation_Table.Designer.cs
generated
Normal file
3280
Marco.Pms.DataAccess/Migrations/20250614044441_Added_Apporved_By_In_TaskAllocation_Table.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Marco.Pms.DataAccess.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Added_Apporved_By_In_TaskAllocation_Table : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "ApprovedById",
|
||||
table: "TaskAllocations",
|
||||
type: "char(36)",
|
||||
nullable: true,
|
||||
collation: "ascii_general_ci");
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "ApprovedDate",
|
||||
table: "TaskAllocations",
|
||||
type: "datetime(6)",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<Guid>(
|
||||
name: "ReportedById",
|
||||
table: "TaskAllocations",
|
||||
type: "char(36)",
|
||||
nullable: true,
|
||||
collation: "ascii_general_ci");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "TaskStatus",
|
||||
table: "TaskAllocations",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_TaskAllocations_ApprovedById",
|
||||
table: "TaskAllocations",
|
||||
column: "ApprovedById");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_TaskAllocations_ReportedById",
|
||||
table: "TaskAllocations",
|
||||
column: "ReportedById");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_TaskAllocations_Employees_ApprovedById",
|
||||
table: "TaskAllocations",
|
||||
column: "ApprovedById",
|
||||
principalTable: "Employees",
|
||||
principalColumn: "Id");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_TaskAllocations_Employees_ReportedById",
|
||||
table: "TaskAllocations",
|
||||
column: "ReportedById",
|
||||
principalTable: "Employees",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_TaskAllocations_Employees_ApprovedById",
|
||||
table: "TaskAllocations");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_TaskAllocations_Employees_ReportedById",
|
||||
table: "TaskAllocations");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_TaskAllocations_ApprovedById",
|
||||
table: "TaskAllocations");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_TaskAllocations_ReportedById",
|
||||
table: "TaskAllocations");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ApprovedById",
|
||||
table: "TaskAllocations");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ApprovedDate",
|
||||
table: "TaskAllocations");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ReportedById",
|
||||
table: "TaskAllocations");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TaskStatus",
|
||||
table: "TaskAllocations");
|
||||
}
|
||||
}
|
||||
}
|
@ -28,6 +28,12 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<Guid?>("ApprovedById")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<DateTime?>("ApprovedDate")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<Guid>("AssignedBy")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
@ -43,9 +49,15 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
b.Property<double>("PlannedTask")
|
||||
.HasColumnType("double");
|
||||
|
||||
b.Property<Guid?>("ReportedById")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
b.Property<DateTime?>("ReportedDate")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<int>("TaskStatus")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<Guid>("TenantId")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
@ -54,8 +66,12 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ApprovedById");
|
||||
|
||||
b.HasIndex("AssignedBy");
|
||||
|
||||
b.HasIndex("ReportedById");
|
||||
|
||||
b.HasIndex("TenantId");
|
||||
|
||||
b.HasIndex("WorkItemId");
|
||||
@ -2412,12 +2428,20 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
|
||||
modelBuilder.Entity("Marco.Pms.Model.Activities.TaskAllocation", b =>
|
||||
{
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "ApprovedBy")
|
||||
.WithMany()
|
||||
.HasForeignKey("ApprovedById");
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "Employee")
|
||||
.WithMany()
|
||||
.HasForeignKey("AssignedBy")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Employees.Employee", "ReportedBy")
|
||||
.WithMany()
|
||||
.HasForeignKey("ReportedById");
|
||||
|
||||
b.HasOne("Marco.Pms.Model.Entitlements.Tenant", "Tenant")
|
||||
.WithMany()
|
||||
.HasForeignKey("TenantId")
|
||||
@ -2430,8 +2454,12 @@ namespace Marco.Pms.DataAccess.Migrations
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("ApprovedBy");
|
||||
|
||||
b.Navigation("Employee");
|
||||
|
||||
b.Navigation("ReportedBy");
|
||||
|
||||
b.Navigation("Tenant");
|
||||
|
||||
b.Navigation("WorkItem");
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Marco.Pms.Model.Dtos.Activities;
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Projects;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
@ -16,6 +17,8 @@ namespace Marco.Pms.Model.Activities
|
||||
public double PlannedTask { get; set; }
|
||||
public double CompletedTask { get; set; }
|
||||
public DateTime? ReportedDate { get; set; }
|
||||
public DateTime? ApprovedDate { get; set; }
|
||||
public TASK_STATUS TaskStatus { get; set; } = TASK_STATUS.PENDING_UC;
|
||||
|
||||
public string? Description { get; set; }
|
||||
|
||||
@ -29,6 +32,16 @@ namespace Marco.Pms.Model.Activities
|
||||
[ValidateNever]
|
||||
public Employee? Employee { get; set; }
|
||||
|
||||
public Guid? ReportedById { get; set; } //Employee Id
|
||||
[ForeignKey("ReportedById")]
|
||||
[ValidateNever]
|
||||
public Employee? ReportedBy { get; set; }
|
||||
|
||||
public Guid? ApprovedById { get; set; } //Employee Id
|
||||
[ForeignKey("ApprovedById")]
|
||||
[ValidateNever]
|
||||
public Employee? ApprovedBy { get; set; }
|
||||
|
||||
public Guid WorkItemId { get; set; }
|
||||
[ForeignKey("WorkItemId")]
|
||||
[ValidateNever]
|
||||
|
@ -8,5 +8,11 @@
|
||||
public List<Guid>? TaskTeam { get; set; } //Employee Ids
|
||||
public Guid WorkItemId { get; set; }
|
||||
}
|
||||
|
||||
public enum TASK_STATUS
|
||||
{
|
||||
PENDING_UC = 0, APPROVED = 1, SEMI_APPROVED = 2, NCR = 3
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,9 @@ using Marco.Pms.Model.Projects;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Marco.Pms.Model.ViewModels.Activities;
|
||||
using Marco.Pms.Model.ViewModels.Employee;
|
||||
using Marco.Pms.Services.Service;
|
||||
using MarcoBMS.Services.Helpers;
|
||||
using MarcoBMS.Services.Service;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
@ -23,12 +25,18 @@ namespace MarcoBMS.Services.Controllers
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly UserHelper _userHelper;
|
||||
private readonly ILoggingService _logger;
|
||||
private readonly PermissionServices _permissionServices;
|
||||
private readonly Guid Approve_Task;
|
||||
|
||||
|
||||
public TaskController(ApplicationDbContext context, UserHelper userHelper)
|
||||
public TaskController(ApplicationDbContext context, UserHelper userHelper, ILoggingService logger, PermissionServices permissionServices)
|
||||
{
|
||||
_context = context;
|
||||
_userHelper = userHelper;
|
||||
_logger = logger;
|
||||
_permissionServices = permissionServices;
|
||||
Approve_Task = Guid.Parse("db4e40c5-2ba9-4b6d-b8a6-a16a250ff99c");
|
||||
}
|
||||
|
||||
private Guid GetTenantId()
|
||||
@ -84,77 +92,109 @@ namespace MarcoBMS.Services.Controllers
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Task assignned successfully", 200));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Reports progress on a specific task allocation including checklist updates and comments.
|
||||
/// </summary>
|
||||
/// <param name="reportTask">Task progress details submitted by the employee.</param>
|
||||
/// <returns>Returns the updated task report along with checklist and comments.</returns>
|
||||
[HttpPost("report")]
|
||||
public async Task<IActionResult> ReportTaskProgress([FromBody] ReportTaskDto reportTask)
|
||||
{
|
||||
// Validate model
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
var errors = ModelState.Values
|
||||
.SelectMany(v => v.Errors)
|
||||
.Select(e => e.ErrorMessage)
|
||||
.ToList();
|
||||
|
||||
_logger.LogWarning("Invalid model state while reporting task. Errors: {@Errors}", errors);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("Invalid data", errors, 400));
|
||||
|
||||
}
|
||||
|
||||
var tenantId = GetTenantId();
|
||||
var Employee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var employee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
var taskAllocation = await _context.TaskAllocations.Include(t => t.WorkItem).FirstOrDefaultAsync(t => t.Id == reportTask.Id);
|
||||
// Get task allocation and associated work item
|
||||
var taskAllocation = await _context.TaskAllocations
|
||||
.Include(t => t.WorkItem)
|
||||
.FirstOrDefaultAsync(t => t.Id == reportTask.Id);
|
||||
|
||||
var checkListIds = reportTask.CheckList != null ? reportTask.CheckList.Select(c => c.Id).ToList() : new List<Guid>();
|
||||
var checkList = await _context.ActivityCheckLists.Where(c => checkListIds.Contains(c.Id)).ToListAsync();
|
||||
if (taskAllocation == null)
|
||||
{
|
||||
_logger.LogWarning("TaskAllocation not found. TaskId: {TaskId}, EmployeeId: {EmployeeId}", reportTask.Id, employee.Id);
|
||||
return BadRequest(ApiResponse<object>.ErrorResponse("No such task has been allocated.", "No such task has been allocated.", 400));
|
||||
}
|
||||
|
||||
// Update completed work in the work item if applicable
|
||||
if (taskAllocation.WorkItem != null)
|
||||
{
|
||||
if (taskAllocation.CompletedTask != 0)
|
||||
{
|
||||
taskAllocation.WorkItem.CompletedWork -= taskAllocation.CompletedTask;
|
||||
}
|
||||
taskAllocation.ReportedDate = reportTask.ReportedDate;
|
||||
taskAllocation.CompletedTask = reportTask.CompletedTask;
|
||||
|
||||
taskAllocation.WorkItem.CompletedWork += reportTask.CompletedTask;
|
||||
}
|
||||
|
||||
// Update task progress
|
||||
taskAllocation.ReportedDate = reportTask.ReportedDate;
|
||||
taskAllocation.ReportedById = employee.Id;
|
||||
taskAllocation.CompletedTask = reportTask.CompletedTask;
|
||||
|
||||
// Process checklist
|
||||
List<CheckListMappings> checkListMappings = new List<CheckListMappings>();
|
||||
List<CheckListVM> checkListVMs = new List<CheckListVM>();
|
||||
if (reportTask.CheckList != null)
|
||||
|
||||
if (reportTask.CheckList != null && reportTask.CheckList.Any())
|
||||
{
|
||||
var checkListIds = reportTask.CheckList.Select(c => c.Id).ToList();
|
||||
var checkList = await _context.ActivityCheckLists
|
||||
.Where(c => checkListIds.Contains(c.Id))
|
||||
.ToListAsync();
|
||||
|
||||
foreach (var checkDto in reportTask.CheckList)
|
||||
{
|
||||
checkListVMs.Add(checkDto.ToCheckListVMFromReportCheckListDto(taskAllocation.WorkItem != null ? taskAllocation.WorkItem.ActivityId : Guid.Empty));
|
||||
// Map checklist DTO to ViewModel
|
||||
var activityId = taskAllocation.WorkItem?.ActivityId ?? Guid.Empty;
|
||||
checkListVMs.Add(checkDto.ToCheckListVMFromReportCheckListDto(activityId));
|
||||
|
||||
// If checked, prepare mapping
|
||||
if (checkDto.IsChecked)
|
||||
{
|
||||
var check = checkList.Find(c => c.Id == checkDto.Id);
|
||||
var check = checkList.FirstOrDefault(c => c.Id == checkDto.Id);
|
||||
if (check != null)
|
||||
{
|
||||
CheckListMappings checkListMapping = new CheckListMappings
|
||||
checkListMappings.Add(new CheckListMappings
|
||||
{
|
||||
CheckListId = check.Id,
|
||||
TaskAllocationId = reportTask.Id
|
||||
};
|
||||
checkListMappings.Add(checkListMapping);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_context.CheckListMappings.AddRange(checkListMappings);
|
||||
var comment = reportTask.ToCommentFromReportTaskDto(tenantId, Employee.Id);
|
||||
|
||||
_context.CheckListMappings.AddRange(checkListMappings);
|
||||
}
|
||||
|
||||
// Add task comment
|
||||
var comment = reportTask.ToCommentFromReportTaskDto(tenantId, employee.Id);
|
||||
_context.TaskComments.Add(comment);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_logger.LogInfo("Task {TaskId} progress reported by Employee {EmployeeId}", reportTask.Id, employee.Id);
|
||||
|
||||
// Prepare response
|
||||
var response = taskAllocation.ToReportTaskVMFromTaskAllocation();
|
||||
List<TaskComment> comments = await _context.TaskComments.Where(c => c.TaskAllocationId == taskAllocation.Id).ToListAsync();
|
||||
List<CommentVM> resultComments = new List<CommentVM> { };
|
||||
foreach (var result in comments)
|
||||
{
|
||||
resultComments.Add(result.ToCommentVMFromTaskComment());
|
||||
}
|
||||
response.Comments = resultComments;
|
||||
|
||||
var comments = await _context.TaskComments
|
||||
.Where(c => c.TaskAllocationId == taskAllocation.Id)
|
||||
.ToListAsync();
|
||||
|
||||
response.Comments = comments.Select(c => c.ToCommentVMFromTaskComment()).ToList();
|
||||
response.checkList = checkListVMs;
|
||||
|
||||
return Ok(ApiResponse<object>.SuccessResponse(response, "Task reported successfully", 200));
|
||||
}
|
||||
|
||||
@ -300,5 +340,54 @@ namespace MarcoBMS.Services.Controllers
|
||||
|
||||
return NotFound(ApiResponse<object>.ErrorResponse("Task Not Found", "Task not Found", 404));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Approves a task allocation by the logged-in employee.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the task to approve.</param>
|
||||
/// <returns>Returns success or error response based on operation outcome.</returns>
|
||||
[HttpPost("approve/{id}")]
|
||||
public async Task<IActionResult> ApproveTask(Guid id)
|
||||
{
|
||||
// Get the current tenant ID from the logged-in user context
|
||||
Guid tenantId = _userHelper.GetTenantId();
|
||||
|
||||
// Get the currently logged-in employee
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
_logger.LogInfo("Employee {EmployeeId} is attempting to approve Task {TaskId}", loggedInEmployee.Id, id);
|
||||
|
||||
// Fetch the task allocation by ID and tenant
|
||||
var taskAllocation = await _context.TaskAllocations
|
||||
.FirstOrDefaultAsync(t => t.Id == id && t.TenantId == tenantId && t.ReportedDate != null);
|
||||
|
||||
// If the task allocation does not exist
|
||||
if (taskAllocation == null)
|
||||
{
|
||||
_logger.LogWarning("Task {TaskId} not found for Tenant {TenantId} by Employee {EmployeeId}", id, tenantId, loggedInEmployee.Id);
|
||||
return NotFound(ApiResponse<object>.ErrorResponse("Task not found", "Task not found", 404));
|
||||
}
|
||||
|
||||
// Check if the employee has permission to approve the task
|
||||
var hasPermission = await _permissionServices.HasPermission(Approve_Task, loggedInEmployee.Id);
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Employee {EmployeeId} attempted to approve Task {TaskId} without proper permissions", loggedInEmployee.Id, id);
|
||||
return StatusCode(403, ApiResponse<object>.ErrorResponse("You don't have access", "Don't have access to take action", 403));
|
||||
}
|
||||
|
||||
// Update task allocation with approval details
|
||||
taskAllocation.ApprovedById = loggedInEmployee.Id;
|
||||
taskAllocation.ApprovedDate = DateTime.UtcNow;
|
||||
taskAllocation.TaskStatus = TASK_STATUS.APPROVED;
|
||||
|
||||
// Save changes to the database
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
_logger.LogInfo("Employee {EmployeeId} successfully approved Task {TaskId}", loggedInEmployee.Id, id);
|
||||
|
||||
// Return success response
|
||||
return Ok(ApiResponse<object>.SuccessResponse("Task has been approved", "Task has been approved", 200));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user