LSFE/LSFE.Domain/Services/Doctor/DoctorRepo.cs
2026-07-30 10:31:04 +08:00

489 lines
20 KiB
C#

using LSFE.Domain.Contracts.Doctor;
using LSFE.Infrastructure.Database;
using LSFE.Infrastructure.Dto.Doctor;
using LSFE.Infrastructure.Entities.Doctor;
using LSFE.Infrastructure.Model;
using Microsoft.Data.SqlClient;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LSFE.Domain.Services.Doctor
{
public class DoctorRepo : GenericRepository<Infrastructure.Entities.Doctor.Doctor>, IDoctorRepo
{
private readonly LSFEDbContext _context;
public DoctorRepo(LSFEDbContext context) : base(context)
{
_context = context;
}
public async Task<Response> SoftDeleteAsync(int doctorId)
{
var response = new Response();
try
{
var existingDoctor = await GetByIdAsync(doctorId);
if (existingDoctor == null)
{
response.Success = false;
response.Message = $"Doctor with ID {doctorId} not found.";
response.MessCode = 0;
return response;
}
existingDoctor.IsActive = false;
Update(existingDoctor);
await _context.SaveChangesAsync();
response.Success = true;
response.Data = existingDoctor;
response.Message = "Doctor deactivated successfully.";
response.MessCode = 3; // code for delete/soft delete
}
catch (Exception ex)
{
response.Success = false;
response.Message = ex.Message;
response.MessCode = 0;
}
return response;
}
public async Task<List<Infrastructure.Entities.Doctor.Doctor>> GetAllDoctor(DoctorDto dto)
{
var allItems = await _context.Doctors
.FromSqlRaw("EXEC GetAllDoctor @UserId",
new SqlParameter("@UserId", dto.UserId))
.ToListAsync();
return allItems ?? new List<Infrastructure.Entities.Doctor.Doctor>();
}
public async Task<List<DoctorDto>> GetDoctor(DoctorDto dto)
{
var query =
from d in _context.Doctors
join i in _context.Institutions
on d.InstitutionId equals i.InstitutionId into di
from i in di.DefaultIfEmpty()
join s in _context.Specializations
on d.SpecializationId equals s.SpecializationId into si
from s in si.DefaultIfEmpty()
join dis in _context.Districts
on d.DistrictId equals dis.DistrictId into dist
from dis in dist.DefaultIfEmpty()
join fda in _context.ForDoctorApprovals
on d.DoctorId equals fda.DoctorId
join u in _context.Users
on d.UserId equals u.Id
where d.UserId == dto.UserId
&& (dto.DoctorId == 0 || d.DoctorId == dto.DoctorId)
select new DoctorDto
{
DoctorId = d.DoctorId,
FirstName = d.FirstName,
MiddleInitial = d.MiddleInitial,
LastName = d.LastName,
EmailAddress = d.EmailAddress,
PhoneNo = d.PhoneNo,
SpecializationId = d.SpecializationId,
LicenseNo = d.LicenseNo,
Address = d.Address,
BirthDate = d.BirthDate,
MaxVisit = d.MaxVisit,
MedRepName=u.UserName,
Status = fda.Status,
IsTerritorial= d.IsTerritorial,
InstitutionId = fda.InstitutionId,
InstitutionName = i != null ? i.InstitutionName : null,
SpecializationName = s != null ? s.SpecializationName : null,
DistrictId = fda != null ? dis.DistrictId : 0,
DistrictName = dis != null ? dis.DistrictName : null
};
return await query.ToListAsync();
}
public async Task<List<DoctorDto>> GetMyDoctor(DoctorDto dto)
{
var query =
from d in _context.Doctors
join i in _context.Institutions
on d.InstitutionId equals i.InstitutionId into di
from i in di.DefaultIfEmpty()
join s in _context.Specializations
on d.SpecializationId equals s.SpecializationId into si
from s in si.DefaultIfEmpty()
join dis in _context.Districts
on d.DistrictId equals dis.DistrictId into dist
from dis in dist.DefaultIfEmpty()
join u in _context.Users
on d.UserId equals u.Id
where d.UserId == dto.UserId
select new DoctorDto
{
DoctorId = d.DoctorId,
FirstName = d.FirstName,
MiddleInitial = d.MiddleInitial,
LastName = d.LastName,
EmailAddress = d.EmailAddress,
PhoneNo = d.PhoneNo,
SpecializationId = d.SpecializationId,
LicenseNo = d.LicenseNo,
Address = d.Address,
BirthDate = d.BirthDate,
MaxVisit = d.MaxVisit,
Status = d.Status,
MedRepName = u.UserName,
IsTerritorial = d.IsTerritorial,
InstitutionId = d.InstitutionId,
InstitutionName = i != null ? i.InstitutionName : null,
SpecializationName = s != null ? s.SpecializationName : null,
DistrictId = dis != null ? dis.DistrictId : 0,
DistrictName = dis != null ? dis.DistrictName : null
};
return await query.ToListAsync();
}
public async Task<Response> PostPutDoctor(DoctorDto dto)
{
var response = new Response();
try
{
Infrastructure.Entities.Doctor.Doctor? existingDoctor = null;
ForDoctorApproval? existingApproval = null;
// Check if DoctorId exists
if (dto.DoctorId > 0)
{
existingDoctor = await GetByIdAsync(dto.DoctorId);
existingApproval = await _context.ForDoctorApprovals
.FirstOrDefaultAsync(x => x.DoctorId == dto.DoctorId);
}
int doctorId = dto.DoctorId;
// Step 1: Insert/Update in main Doctors table first to get DoctorId
if (existingDoctor == null)
{
// CREATE new doctor in main table with Status = 1 (For DSM Approval)
var newDoctor = MapToNewDoctor(dto);
newDoctor.Status = 1; // Always start with "For DSM Approval"
newDoctor.IsActive = false; // Not active until approved
await AddAsync(newDoctor);
await _context.SaveChangesAsync(); // Save to get DoctorId
doctorId = newDoctor.DoctorId; // Get the auto-generated DoctorId
}
else
{
// UPDATE existing doctor - keep current status, don't change it here
// The doctor table will only be updated when status = 3 (Approved)
// For now, we just ensure it exists
doctorId = existingDoctor.DoctorId;
}
// Step 2: Insert/Update in ForDoctorApproval staging table
if (existingApproval == null)
{
// INSERT into ForDoctorApproval
var newApproval = new ForDoctorApproval
{
ForDoctorApprovalId = Guid.NewGuid(),
DoctorId = doctorId, // Use the DoctorId from main table
FirstName = dto.FirstName,
MiddleInitial = dto.MiddleInitial,
LastName = dto.LastName,
MaxVisit = dto.MaxVisit,
SpecializationId = dto.SpecializationId,
UserId = dto.UserId,
StageLevelId = dto.StageLevelId,
DistrictId = dto.DistrictId,
BirthDate = dto.BirthDate,
EmailAddress = dto.EmailAddress,
Address = dto.Address,
PhoneNo = dto.PhoneNo,
LicenseNo = dto.LicenseNo,
InstitutionId = dto.InstitutionId,
IsTerritorial = dto.IsTerritorial,
Status = 1, // Always "For DSM Approval" when submitted
CreatedDate = DateTime.UtcNow,
UpdatedDate = DateTime.UtcNow,
CreatedBy = dto.UserName
};
await _context.ForDoctorApprovals.AddAsync(newApproval);
await _context.SaveChangesAsync();
return new Response
{
Success = true,
Data = new { DoctorId = doctorId, Approval = newApproval },
Message = "Doctor submitted for approval successfully.",
MessCode = 1
};
}
else
{
// UPDATE existing ForDoctorApproval
existingApproval.FirstName = dto.FirstName;
existingApproval.MiddleInitial = dto.MiddleInitial;
existingApproval.LastName = dto.LastName;
existingApproval.MaxVisit = dto.MaxVisit;
existingApproval.DistrictId = dto.DistrictId;
existingApproval.SpecializationId = dto.SpecializationId;
existingApproval.BirthDate = dto.BirthDate;
existingApproval.EmailAddress = dto.EmailAddress;
existingApproval.Address = dto.Address;
existingApproval.PhoneNo = dto.PhoneNo;
existingApproval.LicenseNo = dto.LicenseNo;
existingApproval.InstitutionId = dto.InstitutionId;
existingApproval.IsTerritorial = dto.IsTerritorial;
existingApproval.UserId = dto.UserId;
existingApproval.StageLevelId = dto.StageLevelId;
existingApproval.Status = 1; // Reset to "For DSM Approval"
existingApproval.UpdatedDate = DateTime.UtcNow;
existingApproval.UpdatedBy = dto.UpdatedBy;
_context.ForDoctorApprovals.Update(existingApproval);
await _context.SaveChangesAsync();
return new Response
{
Success = true,
Data = new { DoctorId = doctorId, Approval = existingApproval },
Message = "Doctor information updated and resubmitted for approval.",
MessCode = 2
};
}
}
catch (Exception ex)
{
return new Response
{
Success = false,
Message = ex.Message,
MessCode = 0
};
}
}
public async Task<Response> ApproveDoctor(int doctorId, byte newStatus, string updatedBy)
{
var response = new Response();
try
{
// Get the approval record from staging table
var approval = await _context.ForDoctorApprovals
.FirstOrDefaultAsync(x => x.DoctorId == doctorId);
if (approval == null)
{
return new Response
{
Success = false,
Message = "Approval record not found for this doctor.",
MessCode = 0
};
}
// Get the doctor from main table
var doctor = await GetByIdAsync(doctorId);
if (doctor == null)
{
return new Response
{
Success = false,
Message = "Doctor not found in main table.",
MessCode = 0
};
}
// Validate status progression
// Status flow: 1 (For DSM) -> 2 (For NSM) -> 3 (Approved) or 0 (Denied at any step)
if (newStatus != 0 && newStatus != 2 && newStatus != 3)
{
return new Response
{
Success = false,
Message = "Invalid status. Use 0 (Denied), 2 (For NSM Approval), or 3 (Approved).",
MessCode = 0
};
}
// Update status in ForDoctorApproval staging table
approval.Status = newStatus;
approval.UpdatedDate = DateTime.UtcNow;
_context.ForDoctorApprovals.Update(approval);
// Handle different status scenarios
if (newStatus==3) // APPROVED - Copy from staging to main table
{
// Apply all changes from ForDoctorApproval to Doctors table
doctor.FirstName = approval.FirstName;
doctor.MiddleInitial = approval.MiddleInitial;
doctor.LastName = approval.LastName;
doctor.MaxVisit = approval.MaxVisit;
doctor.DistrictId = approval.DistrictId;
doctor.SpecializationId = approval.SpecializationId;
doctor.StageLevelId = approval.StageLevelId;
doctor.BirthDate = approval.BirthDate;
doctor.EmailAddress = approval.EmailAddress;
doctor.Address = approval.Address;
doctor.PhoneNo = approval.PhoneNo;
doctor.LicenseNo = approval.LicenseNo;
doctor.InstitutionId = approval.InstitutionId;
doctor.IsTerritorial = approval.IsTerritorial;
doctor.Status = 3;
doctor.IsActive = true; // Activate the doctor
doctor.UpdatedDate = DateTime.UtcNow;
doctor.UpdatedBy = updatedBy;
Update(doctor);
// Optionally, you can delete or archive the approval record
// _context.ForDoctorApprovals.Remove(approval);
}
else if (newStatus == 0) // DENIED
{
// Update doctor status to denied
doctor.Status = 0;
doctor.IsActive = false;
doctor.UpdatedDate= DateTime.UtcNow;
doctor.UpdatedBy = updatedBy;
Update(doctor);
}
else if (newStatus == 2) // FOR NSM APPROVAL
{
// Just update the staging table status, keep doctor status as is
doctor.Status = 2; // Update main table to show it's in NSM review
doctor.UpdatedDate = DateTime.UtcNow;
doctor.UpdatedBy = updatedBy;
Update(doctor);
}
await _context.SaveChangesAsync();
string statusMessage = newStatus switch
{
0 => "denied",
2 => "forwarded to NSM for approval",
3 => "approved and activated in the system",
_ => "updated"
};
return new Response
{
Success = true,
Data = new { Doctor = doctor, Approval = approval },
Message = $"Doctor has been {statusMessage}.",
MessCode = 2
};
}
catch (Exception ex)
{
return new Response
{
Success = false,
Message = ex.Message,
MessCode = 0
};
}
}
public async Task<List<ForDoctorApprovalDto>> GetPendingApprovals(DoctorDto dto)
{
var query =
from fda in _context.ForDoctorApprovals
join d in _context.Doctors
on fda.DoctorId equals d.DoctorId into fdaDoc
from d in fdaDoc.DefaultIfEmpty()
join i in _context.Institutions
on fda.InstitutionId equals i.InstitutionId into fdai
from i in fdai.DefaultIfEmpty()
join dis in _context.Districts
on fda.DistrictId equals dis.DistrictId into fdaDist
from dis in fdaDist.DefaultIfEmpty()
join u in _context.Users
on d.UserId equals u.Id into user
from u in user.DefaultIfEmpty()
where fda.Status == 1 || u.Company == dto.Company
select new ForDoctorApprovalDto
{
ForDoctorApprovalId = fda.ForDoctorApprovalId,
DoctorId = fda.DoctorId,
FirstName = fda.FirstName,
MiddleInitial = fda.MiddleInitial,
LastName = fda.LastName,
EmailAddress = fda.EmailAddress,
PhoneNo = fda.PhoneNo,
SpecializationId = fda.SpecializationId,
LicenseNo = fda.LicenseNo,
Address = fda.Address,
BirthDate = fda.BirthDate,
MaxVisit = fda.MaxVisit,
MedRepName=u.UserName,
Status = fda.Status,
InstitutionId = fda.InstitutionId,
InstitutionName = i != null ? i.InstitutionName : null,
DistrictId = fda.DistrictId,
DistrictName = dis != null ? dis.DistrictName : null,
UserId = fda.UserId,
StageLevelId = fda.StageLevelId,
IsTerritorial = fda.IsTerritorial
};
return await query.ToListAsync();
}
private Infrastructure.Entities.Doctor.Doctor MapToNewDoctor(DoctorDto dto)
{
return new Infrastructure.Entities.Doctor.Doctor
{
FirstName = dto.FirstName,
MiddleInitial = dto.MiddleInitial,
LastName = dto.LastName,
MaxVisit = dto.MaxVisit,
SpecializationId = dto.SpecializationId,
UserId = dto.UserId,
StageLevelId = dto.StageLevelId,
DistrictId = dto.DistrictId,
BirthDate = dto.BirthDate,
EmailAddress = dto.EmailAddress,
Address = dto.Address,
PhoneNo = dto.PhoneNo,
LicenseNo = dto.LicenseNo,
InstitutionId = dto.InstitutionId,
IsTerritorial = dto.IsTerritorial,
Status = dto.Status,
IsActive = true,
CreatedDate = DateTime.UtcNow,
UpdatedDate = DateTime.UtcNow,
CreatedBy = dto.UserName,
UpdatedBy = dto.UserName,
};
}
public async Task<List<DoctorCoverageToday>> GetDoctorCoverageToday(DoctorDto dto)
{
var allItems = await _context.DoctorCoverageTodays
.FromSqlRaw("EXEC GetDoctorCoverageToday @UserId,@MRPlanDate",
new SqlParameter("@UserId", dto.UserId),
new SqlParameter("@MRPlanDate", dto.MRPlanDate))
.ToListAsync();
return allItems ?? new List<DoctorCoverageToday>();
}
}
}