Updated CRUD APIs for Activity Management to include functionality for storing Service ID and Activity Group ID as foreign keys.
This commit is contained in:
parent
c5830fb222
commit
083f2c53d5
@ -1,10 +1,13 @@
|
||||
using Marco.Pms.DataAccess.Data;
|
||||
using Marco.Pms.Model.Directory;
|
||||
using Marco.Pms.Model.Dtos.Activities;
|
||||
using Marco.Pms.Model.Dtos.Master;
|
||||
using Marco.Pms.Model.Employees;
|
||||
using Marco.Pms.Model.Entitlements;
|
||||
using Marco.Pms.Model.Mapper;
|
||||
using Marco.Pms.Model.Master;
|
||||
using Marco.Pms.Model.Utilities;
|
||||
using Marco.Pms.Model.ViewModels.Activities;
|
||||
using Marco.Pms.Model.ViewModels.Master;
|
||||
using Marco.Pms.Services.Service;
|
||||
using MarcoBMS.Services.Helpers;
|
||||
@ -405,6 +408,278 @@ namespace Marco.Pms.Services.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------- Activity --------------------------------
|
||||
public async Task<ApiResponse<object>> GetActivitiesMaster()
|
||||
{
|
||||
_logger.LogInfo("GetActivitiesMaster called");
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
// Step 1: Fetch all active activities for the tenant
|
||||
var activities = await _context.ActivityMasters
|
||||
.Include(c => c.ServicesMaster)
|
||||
.Include(c => c.ActivityGroupMaster)
|
||||
.Where(c => c.TenantId == tenantId && c.IsActive)
|
||||
.ToListAsync();
|
||||
|
||||
if (activities.Count == 0)
|
||||
{
|
||||
_logger.LogWarning("No active activities found for tenantId: {TenantId}", tenantId);
|
||||
return ApiResponse<object>.SuccessResponse(new List<ActivityVM>(), "No activity records found", 200);
|
||||
}
|
||||
|
||||
// Step 2: Fetch all checklists for those activities in a single query to avoid N+1
|
||||
var activityIds = activities.Select(a => a.Id).ToList();
|
||||
var checkLists = await _context.ActivityCheckLists
|
||||
.Where(c => c.TenantId == tenantId && activityIds.Contains(c.ActivityId))
|
||||
.ToListAsync();
|
||||
|
||||
// Step 3: Group checklists by activity
|
||||
var groupedChecklists = checkLists
|
||||
.GroupBy(c => c.ActivityId)
|
||||
.ToDictionary(g => g.Key, g => g.ToList());
|
||||
|
||||
// Step 4: Map to ViewModel
|
||||
var activityVMs = activities.Select(activity =>
|
||||
{
|
||||
var checklistForActivity = groupedChecklists.ContainsKey(activity.Id)
|
||||
? groupedChecklists[activity.Id]
|
||||
: new List<ActivityCheckList>();
|
||||
|
||||
var checklistVMs = checklistForActivity
|
||||
.Select(cl => cl.ToCheckListVMFromActivityCheckList(activity.Id, false))
|
||||
.ToList();
|
||||
|
||||
return activity.ToActivityVMFromActivityMaster(checklistVMs, activity.ServicesMaster?.Name, activity.ActivityGroupMaster?.Name);
|
||||
}).ToList();
|
||||
|
||||
_logger.LogInfo("{Count} activity records fetched successfully for tenantId: {TenantId}", activityVMs.Count, tenantId);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(activityVMs, $"{activityVMs.Count} activity records fetched successfully", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error occurred in GetActivitiesMaster: {Error}", ex.Message);
|
||||
return ApiResponse<object>.ErrorResponse("Failed to fetch activity records", ex.Message, 500);
|
||||
}
|
||||
}
|
||||
public async Task<ApiResponse<object>> CreateActivity(CreateActivityMasterDto createActivity)
|
||||
{
|
||||
_logger.LogInfo("CreateActivity called with ActivityName: {Name}", createActivity?.ActivityName ?? "null");
|
||||
|
||||
try
|
||||
{
|
||||
// Step 1: Validate input
|
||||
if (createActivity == null)
|
||||
{
|
||||
_logger.LogWarning("Null request body received in CreateActivity");
|
||||
return ApiResponse<object>.ErrorResponse("Invalid input", "Activity data is required", 400);
|
||||
}
|
||||
|
||||
var activityGroup = await _context.ActivityGroupMasters
|
||||
.Include(ag => ag.ServicesMaster)
|
||||
.FirstOrDefaultAsync(ag => ag.Id == createActivity.ActitvityGroupId && ag.ServiceId == createActivity.ServiceId);
|
||||
if (activityGroup == null)
|
||||
{
|
||||
_logger.LogWarning("User tried to create new activity, but not found activity group");
|
||||
return ApiResponse<object>.ErrorResponse("Invalid input", "Activity data is required", 400);
|
||||
}
|
||||
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
|
||||
// Step 2: Check permissions
|
||||
var hasPermission = await _permissionService.HasPermission(Manage_Master, loggedInEmployee.Id);
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Access denied. EmployeeId: {EmployeeId} does not have Manage_Master permission.", loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to perform this action", 403);
|
||||
}
|
||||
|
||||
// Step 3: Convert DTO to entity and add activity
|
||||
var activityMaster = createActivity.ToActivityMasterFromCreateActivityMasterDto(tenantId);
|
||||
_context.ActivityMasters.Add(activityMaster);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
List<CheckListVM> checkListVMs = new();
|
||||
|
||||
// Step 4: Handle checklist items if present
|
||||
if (createActivity.CheckList?.Any() == true)
|
||||
{
|
||||
var activityCheckLists = createActivity.CheckList
|
||||
.Select(c => c.ToActivityCheckListFromCreateCheckListDto(tenantId, activityMaster.Id))
|
||||
.ToList();
|
||||
|
||||
_context.ActivityCheckLists.AddRange(activityCheckLists);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
checkListVMs = activityCheckLists
|
||||
.Select(c => c.ToCheckListVMFromActivityCheckList(activityMaster.Id, false))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
// Step 5: Prepare final response
|
||||
var activityVM = activityMaster.ToActivityVMFromActivityMaster(checkListVMs, activityGroup.ServicesMaster?.Name, activityGroup.Name);
|
||||
|
||||
_logger.LogInfo("Activity '{Name}' created successfully for tenant {TenantId}", activityMaster.ActivityName, tenantId);
|
||||
return ApiResponse<object>.SuccessResponse(activityVM, "Activity created successfully", 201);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Error occurred while creating activity: {Message}", ex.Message);
|
||||
return ApiResponse<object>.ErrorResponse("An error occurred while creating activity", ex.Message, 500);
|
||||
}
|
||||
}
|
||||
public async Task<ApiResponse<object>> UpdateActivity(Guid id, CreateActivityMasterDto createActivity)
|
||||
{
|
||||
_logger.LogInfo("UpdateActivity called for ActivityId: {ActivityId}", id);
|
||||
|
||||
try
|
||||
{
|
||||
// Step 1: Validate input
|
||||
if (createActivity == null || string.IsNullOrWhiteSpace(createActivity.ActivityName) || string.IsNullOrWhiteSpace(createActivity.UnitOfMeasurement))
|
||||
{
|
||||
_logger.LogWarning("Invalid activity update input for ActivityId: {ActivityId}", id);
|
||||
return ApiResponse<object>.ErrorResponse("Invalid input", "ActivityName and UnitOfMeasurement are required", 400);
|
||||
}
|
||||
|
||||
// Step 2: Check permissions
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var hasPermission = await _permissionService.HasPermission(Manage_Master, loggedInEmployee.Id);
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Access denied for employeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to update activities", 403);
|
||||
}
|
||||
|
||||
// Step 3: Validate service, activity group, and activity existence
|
||||
var activityGroup = await _context.ActivityGroupMasters.Include(ag => ag.ServicesMaster).FirstOrDefaultAsync(ag => ag.Id == createActivity.ActitvityGroupId && ag.IsActive);
|
||||
|
||||
if (activityGroup == null || activityGroup.ServiceId != createActivity.ServiceId)
|
||||
{
|
||||
_logger.LogWarning("User tries to update activity, but cannot able found activity group or service");
|
||||
return ApiResponse<object>.ErrorResponse("Invalid activity group ID or service ID", "Please provide valid activity group ID or service ID to update activity group", 400);
|
||||
}
|
||||
|
||||
var activity = await _context.ActivityMasters
|
||||
.Include(a => a.ServicesMaster)
|
||||
.Include(a => a.ActivityGroupMaster)
|
||||
.FirstOrDefaultAsync(a => a.Id == id && a.IsActive && a.TenantId == tenantId);
|
||||
|
||||
if (activity == null)
|
||||
{
|
||||
_logger.LogError("Activity not found for ActivityId: {ActivityId}, TenantId: {TenantId}", id, tenantId);
|
||||
return ApiResponse<object>.ErrorResponse("Activity not found", "Activity not found", 404);
|
||||
}
|
||||
|
||||
// Step 4: Update activity core data
|
||||
activity.ActivityName = createActivity.ActivityName.Trim();
|
||||
activity.UnitOfMeasurement = createActivity.UnitOfMeasurement.Trim();
|
||||
if (activity.ServiceId == null)
|
||||
{
|
||||
activity.ServiceId = createActivity.ServiceId;
|
||||
}
|
||||
activity.ActitvityGroupId = createActivity.ActitvityGroupId;
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Step 5: Handle checklist updates
|
||||
var existingChecklists = await _context.ActivityCheckLists
|
||||
.AsNoTracking()
|
||||
.Where(c => c.ActivityId == activity.Id)
|
||||
.ToListAsync();
|
||||
|
||||
var updatedChecklistVMs = new List<CheckListVM>();
|
||||
|
||||
if (createActivity.CheckList != null && createActivity.CheckList.Any())
|
||||
{
|
||||
var incomingCheckIds = createActivity.CheckList.Where(c => c.Id != null).Select(c => c.Id!.Value).ToHashSet();
|
||||
|
||||
// Prepare lists
|
||||
var newChecks = createActivity.CheckList.Where(c => c.Id == null);
|
||||
var updates = createActivity.CheckList.Where(c => c.Id != null && existingChecklists.Any(ec => ec.Id == c.Id));
|
||||
var deletes = existingChecklists.Where(ec => !incomingCheckIds.Contains(ec.Id)).ToList();
|
||||
|
||||
var toAdd = newChecks
|
||||
.Select(c => c.ToActivityCheckListFromCreateCheckListDto(tenantId, activity.Id))
|
||||
.ToList();
|
||||
|
||||
var toUpdate = updates
|
||||
.Select(c => c.ToActivityCheckListFromCreateCheckListDto(tenantId, activity.Id))
|
||||
.ToList();
|
||||
|
||||
_context.ActivityCheckLists.AddRange(toAdd);
|
||||
_context.ActivityCheckLists.UpdateRange(toUpdate);
|
||||
_context.ActivityCheckLists.RemoveRange(deletes);
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// Prepare view model
|
||||
updatedChecklistVMs = toAdd.Concat(toUpdate)
|
||||
.Select(c => c.ToCheckListVMFromActivityCheckList(activity.Id, false))
|
||||
.ToList();
|
||||
}
|
||||
else if (existingChecklists.Any())
|
||||
{
|
||||
// If no checklist provided, remove all existing
|
||||
_context.ActivityCheckLists.RemoveRange(existingChecklists);
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
// Step 6: Prepare response
|
||||
var activityVM = activity.ToActivityVMFromActivityMaster(updatedChecklistVMs, activityGroup.ServicesMaster?.Name, activityGroup.Name);
|
||||
|
||||
_logger.LogInfo("Activity updated successfully. ActivityId: {ActivityId}, TenantId: {TenantId}", activity.Id, tenantId);
|
||||
return ApiResponse<object>.SuccessResponse(activityVM, "Activity updated successfully", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Exception in UpdateActivity: {Message}", ex.Message);
|
||||
return ApiResponse<object>.ErrorResponse("Error updating activity", ex.Message, 500);
|
||||
}
|
||||
}
|
||||
public async Task<ApiResponse<object>> DeleteActivity(Guid id, bool isActive)
|
||||
{
|
||||
_logger.LogInfo("DeleteActivity called with ActivityId: {ActivityId}, IsActive: {IsActive}", id, isActive);
|
||||
|
||||
try
|
||||
{
|
||||
// Step 1: Validate permission
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var hasPermission = await _permissionService.HasPermission(Manage_Master, loggedInEmployee.Id);
|
||||
|
||||
if (!hasPermission)
|
||||
{
|
||||
_logger.LogWarning("Access denied for EmployeeId: {EmployeeId}", loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("Access denied", "You don't have permission to delete activities", 403);
|
||||
}
|
||||
|
||||
// Step 2: Fetch the activity
|
||||
var activity = await _context.ActivityMasters
|
||||
.FirstOrDefaultAsync(a => a.Id == id && a.TenantId == tenantId);
|
||||
|
||||
if (activity == null)
|
||||
{
|
||||
_logger.LogWarning("Activity not found. ActivityId: {ActivityId}", id);
|
||||
return ApiResponse<object>.ErrorResponse("Activity not found", "Activity not found or already deleted", 404);
|
||||
}
|
||||
|
||||
// Step 3: Perform soft delete/restore
|
||||
activity.IsActive = isActive;
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
string status = isActive ? "restored" : "deactivated";
|
||||
_logger.LogInfo("Activity {ActivityId} {Status} successfully by EmployeeId: {EmployeeId}", id, status, loggedInEmployee.Id);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(new { }, $"Activity {status} successfully", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError("Unexpected error while deleting activity {ActivityId} : {Error}", id, ex.Message);
|
||||
return ApiResponse<object>.ErrorResponse("Error deleting activity", ex.Message, 500);
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------- Contact Category --------------------------------
|
||||
public async Task<ApiResponse<object>> CreateContactCategory(CreateContactCategoryDto contactCategoryDto)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user