irc-netcore-api/IRaCIS.Core.Application/Service/WorkLoad/EnrollService.cs

577 lines
25 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using DocumentFormat.OpenXml.Vml.Spreadsheet;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Service.WorkLoad.DTO;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infra.EFCore.Common;
using Microsoft.AspNetCore.Mvc;
using System.Text.RegularExpressions;
namespace IRaCIS.Core.Application.Service
{
[ApiExplorerSettings(GroupName = "Enroll")]
public class EnrollService(IRepository<Trial> _trialRepository,
IRepository<TrialStatusDetail> _trialDetailRepository,
IRepository<TrialPaymentPrice> _TrialPaymentPriceRepository,
IRepository<Enroll> _enrollRepository,
IRepository<Doctor> _doctorRepository,
IRepository<EnrollDetail> _enrollDetailRepository,
IRepository<Workload> _workloadRepository,
IRepository<User> _userRepository,
IRepository<TrialUser> _trialUserRepository,
IRepository<ReadingQuestionCriterionTrial> _ReadingQuestionCriterionTrialRepository,
IRepository<TrialExperience> _trialExperienceRepository,
IRepository<Dictionary> _dictionaryRepository,
IRepository<TrialExperienceCriteria> _trialExperienceCriteriaRepository,
IMailVerificationService _mailVerificationService, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, IEnrollService
{
/// <summary>
/// 添加或更新项目医生项目价格
/// </summary>
[HttpPost]
public async Task<IResponseOutput> AddOrUpdateEnroll(EnrollCommand addOrUpdateModel)
{
var trialDoctoritem = await _enrollRepository.FirstOrDefaultAsync(u => u.Id == addOrUpdateModel.Id);
if (trialDoctoritem == null)//insert
{
await _enrollRepository.InsertFromDTOAsync(addOrUpdateModel);
}
else//update
{
await _enrollRepository.UpdateFromDTOAsync(addOrUpdateModel);
}
var success = await _enrollRepository.SaveChangesAsync();
return ResponseOutput.Result(success);
}
/// <summary>
/// 获取医生项目列表
/// </summary>
/// <param name="challengeQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<EnrollViewModel>> GetTrialDoctorList(EnrollGetQuery challengeQuery)
{
var costStatisticsQueryable = from enroll in _enrollRepository.Where(t => t.TrialId == challengeQuery.TrialId)
join dociorc in _doctorRepository.Where() on enroll.DoctorId equals dociorc.Id
join price in _TrialPaymentPriceRepository.Where() on enroll.TrialId equals price.TrialId
select new EnrollViewModel()
{
ChineseName = dociorc.ChineseName,
AdjustmentMultiple = enroll.AdjustmentMultiple,
FirstName = dociorc.FirstName,
LastName = dociorc.LastName,
DoctorId = dociorc.Id,
TrialId = challengeQuery.TrialId,
Id = enroll.Id,
Training = enroll.Training,
RefresherTraining = enroll.RefresherTraining,
Timepoint = enroll.Timepoint,
Timepoint48H = enroll.Timepoint48H,
Timepoint24H = enroll.Timepoint24H,
Adjudication = enroll.Adjudication,
Adjudication48H = enroll.Adjudication48H,
Adjudication24H = enroll.Adjudication24H,
Global = enroll.Global,
Code = dociorc.Code,
ReviewerCode = dociorc.ReviewerCode,
Downtime = enroll.Downtime,
};
return await costStatisticsQueryable.ToPagedListAsync(challengeQuery);
//var query2 = _repository.Where<EnrollViewModel>(x => x.TrialId == challengeQuery.TrialId)
// .WhereIf(challengeQuery.TrialId != null, t => t.TrialId == challengeQuery.TrialId)
// .WhereIf(challengeQuery.DoctorId != null, t => t.DoctorId == challengeQuery.DoctorId)
// .ProjectTo<Enroll>(_mapper.ConfigurationProvider);
//var pageList = await query2.ToListAsync();
// return new PageOutput<EnrollViewModel>(challengeQuery.pageIndex, challengeQuery.pageSize,
//costStatisticsQueryable);
}
#region Reviewer 入组审核流程select-submit-approve-confirm
/// <summary> 为项目筛选医生 提交 【select】 </summary>
/// <param name="trialId">项目Id</param>
/// <param name="doctorIdArray">医生Id数组</param>
/// <returns></returns>
[HttpPost("{trialId:guid}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
//[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM)]
public async Task<IResponseOutput> SelectReviewers(Guid trialId, Guid[] doctorIdArray)
{
var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
if (trial == null) return Null404NotFound(trial);
//_trialRepository.Attach(trial);
//更新项目状态
trial.TrialEnrollStatus = (int)TrialEnrollStatus.HasApplyDownLoadResume;
//_trialRepository.Update(trial);
//添加项目状态变化记录
var trialDetail = new TrialStatusDetail()
{
TrialId = trial.Id,
TrialStatus = (int)TrialEnrollStatus.HasApplyDownLoadResume,
};
await _trialDetailRepository.AddAsync(trialDetail);
// 入组表 入组状态跟踪表
foreach (var doctorId in doctorIdArray)
{
await _enrollRepository.AddAsync(new Enroll()
{
DoctorId = doctorId,
TrialId = trialId,
EnrollStatus = EnrollStatus.HasApplyDownloadResume,
DoctorUserId = _userRepository.Where(t => t.DoctorId == doctorId).Select(t => t.Id).FirstOrDefault()
}); ;
await _enrollDetailRepository.AddAsync(new EnrollDetail()
{
DoctorId = doctorId,
TrialId = trialId,
EnrollStatus = EnrollStatus.HasApplyDownloadResume,
OptUserType = (int)SystemUserType.AdminUser,
});
}
return ResponseOutput.Result(await _enrollRepository.SaveChangesAsync());
}
/// <summary>
/// 入组流程-向CRO提交医生[Submit]
/// </summary>
[HttpPost("{trialId:guid}/{commitState:int}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
//[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM)]
public async Task<IResponseOutput> SubmitReviewer(Guid trialId, Guid[] doctorIdArray, int commitState)
{
var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
var hasSPMOrCPM = await _trialUserRepository.Where(t => t.TrialId == trialId).AnyAsync(t => t.User.UserTypeEnum == UserTypeEnum.SPM || t.User.UserTypeEnum == UserTypeEnum.CPM);
var isSPMjoin= trial.IsSPMJoinReviewerSelect && hasSPMOrCPM;
if (trial != null)
{
if (commitState == 1) //确认提交CRO
{
//更新项目状态
trial.TrialEnrollStatus = isSPMjoin ? (int)TrialEnrollStatus.HasCommitCRO : (int)TrialEnrollStatus.HasConfirmedDoctorNames;
//添加项目详细记录
var trialDetail = new TrialStatusDetail()
{
TrialId = trial.Id,
TrialStatus = (int)TrialEnrollStatus.HasCommitCRO
};
await _trialDetailRepository.AddAsync(trialDetail);
//更新入组表 跟踪了 所以不用下面的_enrollRepository.Update(intoGroupItem);
var intoGroupList = await _enrollRepository.Where(t => t.TrialId == trialId, true).ToListAsync();
foreach (var intoGroupItem in intoGroupList)
{
if (doctorIdArray.Contains(intoGroupItem.DoctorId))
{
intoGroupItem.EnrollStatus = isSPMjoin ? EnrollStatus.HasCommittedToCRO : EnrollStatus.InviteIntoGroup;
await _enrollDetailRepository.AddAsync(new EnrollDetail()
{
TrialDetailId = trialDetail.Id,
DoctorId = intoGroupItem.DoctorId,
TrialId = trialId,
EnrollStatus = isSPMjoin ? EnrollStatus.HasCommittedToCRO : EnrollStatus.InviteIntoGroup,
OptUserType = (int)SystemUserType.AdminUser, //后台用户
});
if (!isSPMjoin)
{
await _enrollDetailRepository.AddAsync(new EnrollDetail()
{
TrialDetailId = trialDetail.Id,
DoctorId = intoGroupItem.DoctorId,
TrialId = trialId,
EnrollStatus = EnrollStatus.HasCommittedToCRO,
OptUserType = (int)SystemUserType.AdminUser, //后台用户
});
}
}
}
}
else if (commitState == 0)//回退上一步
{
//更新入组表
var intoGroupList = await _enrollRepository.Where(t => t.TrialId == trialId, true).ToListAsync();
foreach (var intoGroupItem in intoGroupList)
{
if (doctorIdArray.Contains(intoGroupItem.DoctorId))
{
intoGroupItem.EnrollStatus = EnrollStatus.HasApplyDownloadResume;
//_enrollRepository.Update(intoGroupItem);
var deleteItem = await _enrollDetailRepository.FirstOrDefaultAsync(t =>
t.TrialId == trialId && t.DoctorId == intoGroupItem.DoctorId &&
t.EnrollStatus == EnrollStatus.HasCommittedToCRO);
await _enrollDetailRepository.DeleteAsync(deleteItem);
}
}
}
return ResponseOutput.Result(await _enrollRepository.SaveChangesAsync(), new { IsHaveSPMOrCPM = isSPMjoin });
}
//$"Cannot find trial {trialId}"
return ResponseOutput.NotOk(_localizer["Enroll_NotFound", trialId]);
}
/// <summary>
/// 入组流程-CRO确定医生名单 [ Approve]
/// </summary>
[HttpPost("{trialId:guid}/{auditState:int}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
//[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM)]
public async Task<IResponseOutput> ApproveReviewer(Guid trialId, Guid[] doctorIdArray, int auditState)
{
var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
if (trial == null) return Null404NotFound(trial);
if (auditState == 1) //确认入组
{
//var existItem = _trialRepository.FindSingleOrDefault(u => u.Id == trialId && u.TrialStatus >= (int)TrialEnrollStatus.HasConfirmedDoctorNames);
//if (existItem == null)
//{
// trial.TrialStatus = (int)TrialEnrollStatus.HasConfirmedDoctorNames;
// trial.TrialStatusStr = "Approved";
//}
//_trialRepository.Update(trial);
//更新项目状态
trial.TrialEnrollStatus = (int)TrialEnrollStatus.HasConfirmedDoctorNames;
//添加项目详细记录
var trialDetail = new TrialStatusDetail()
{
TrialId = trialId,
TrialStatus = (int)TrialEnrollStatus.HasConfirmedDoctorNames
};
await _trialDetailRepository.AddAsync(trialDetail);
//更新入组表 跟踪方式不用下面的_enrollRepository.Update(intoGroupItem);
var intoGroupList = _enrollRepository.Where(t => t.TrialId == trialId, true).ToList();
foreach (var intoGroupItem in intoGroupList)
{
if (doctorIdArray.Contains(intoGroupItem.DoctorId))
{
intoGroupItem.EnrollStatus = EnrollStatus.InviteIntoGroup;
//_enrollRepository.Update(intoGroupItem);
await _enrollDetailRepository.AddAsync(new EnrollDetail()
{
DoctorId = intoGroupItem.DoctorId,
TrialId = trialId,
EnrollStatus = EnrollStatus.InviteIntoGroup,
OptUserType = (int)SystemUserType.AdminUser, //后台用户
});
}
}
}
else if (auditState == 0)//回退上一步
{
//更新入组表
var intoGroupList = _enrollRepository.Where(t => t.TrialId == trialId, true).ToList();
foreach (var intoGroupItem in intoGroupList)
{
if (doctorIdArray.Contains(intoGroupItem.DoctorId))
{
intoGroupItem.EnrollStatus = EnrollStatus.HasCommittedToCRO;
//_enrollRepository.Update(intoGroupItem);
var deleteItem = await _enrollDetailRepository.FirstOrDefaultAsync(t =>
t.TrialId == trialId && t.DoctorId == intoGroupItem.DoctorId &&
t.EnrollStatus == EnrollStatus.InviteIntoGroup);
await _enrollDetailRepository.DeleteAsync(deleteItem);
}
}
}
return ResponseOutput.Result(await _enrollRepository.SaveChangesAsync());
}
/// <summary>
/// 入组流程-后台确认医生入组[Confirm]
/// </summary>
[HttpPost]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
//[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM_SMM_CMM)]
[UnitOfWork]
public async Task<IResponseOutput> ConfirmReviewer(ConfirmReviewerCommand confirmReviewerCommand,
[FromServices] IRepository<TrialUser> _trialUserRepository,
[FromServices] IRepository<TaskAllocationRule> _taskAllocationRuleRepository)
{
//var trial = _trialRepository.FirstOrDefault(t => t.Id == trialId);
//var existItem = _trialRepository.FindSingleOrDefault(u => u.Id == trialId && u.TrialStatus >= (int)TrialEnrollStatus.HasConfirmedDoctorNames);
//trial.TrialStatusStr = "Reading";
////trial.TrialStatus = (int)TrialStatus.HasConfirmedDoctorNames;
//_trialRepository.Update(trial);
var trialId = confirmReviewerCommand.TrialId;
var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == trialId);
if (trial == null) return Null404NotFound(trial);
//更新入组表
var intoGroupList = await _enrollRepository.Where(t => t.TrialId == trialId, true).ToListAsync();
//验证邮件
var emaiList = await _doctorRepository.Where(t => intoGroupList.Select(t => t.DoctorId).Contains(t.Id))
.Select(t => new { t.EMail, t.FirstName, t.LastName }).ToListAsync();
var errorList = emaiList.Where(t => !Regex.IsMatch(t.EMail, @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"))
.ToList();
if (errorList.Count() > 0)
{
// errorList.Select(c => c.LastName+" / "+c.FirstName)) +"邮箱格式存在问题"
return ResponseOutput.NotOk(string.Join(',', _localizer["Enroll_EmailFormat"], errorList.Select(c => c.LastName + " / " + c.FirstName)));
}
var readingQuestionCriterionTrial = await _ReadingQuestionCriterionTrialRepository.Where(x => x.TrialId == confirmReviewerCommand.TrialId && x.IsConfirm).ToListAsync();
List<TrialExperience> trialExperienceList = new List<TrialExperience>();
// 获取标准字典
var criterionTypeList = await _dictionaryRepository.Where(x => x.Parent.Code == "CriterionType").ToListAsync();
if (confirmReviewerCommand.ConfirmState == 1) //确认入组
{
foreach (var intoGroupItem in intoGroupList)
{
if (confirmReviewerCommand.DoctorIdArray.Contains(intoGroupItem.DoctorId))
{
//当邮件发送没有问题的时候,才修改状态 如果有问题,就当前不做处理
try
{
var userId = await _mailVerificationService.DoctorJoinTrialEmail(trialId, intoGroupItem.DoctorId, confirmReviewerCommand.BaseUrl, confirmReviewerCommand.RouteUrl);
if (!await _trialUserRepository.AnyAsync(t => t.TrialId == trialId && t.UserId == userId, true))
{
await _trialUserRepository.AddAsync(new TrialUser() { TrialId = trialId, UserId = userId, JoinTime = DateTime.Now });
}
await _enrollRepository.BatchUpdateNoTrackingAsync(t => t.Id == intoGroupItem.Id, u => new Enroll() { DoctorUserId = userId });
if (!await _taskAllocationRuleRepository.AnyAsync(t => t.TrialId == trialId && t.DoctorUserId == userId && t.EnrollId == intoGroupItem.Id, true))
{
await _taskAllocationRuleRepository.AddAsync(new TaskAllocationRule() { TrialId = trialId, DoctorUserId = userId, EnrollId = intoGroupItem.Id });
}
await _enrollDetailRepository.AddAsync(new EnrollDetail()
{
DoctorId = intoGroupItem.DoctorId,
TrialId = trialId,
EnrollStatus = EnrollStatus.ConfirmIntoGroup,
OptUserType = (int)SystemUserType.AdminUser, //后台用户
});
intoGroupItem.EnrollStatus = EnrollStatus.ConfirmIntoGroup;
intoGroupItem.EnrollTime = DateTime.Now;
}
catch (Exception)
{
intoGroupItem.EnrollStatus = EnrollStatus.ConfirmIntoGroupFailed;
}
}
}
List<ExperienceDataType> dataTypes = new List<ExperienceDataType>()
{
ExperienceDataType.TrialAuto,
ExperienceDataType.SystemAuto,
};
// 添加临床试验经历
if (trial.TrialType == TrialType.OfficialTrial)
{
foreach (var doctorId in confirmReviewerCommand.DoctorIdArray)
{
foreach (var item in readingQuestionCriterionTrial)
{
foreach (var dataType in dataTypes)
{
trialExperienceList.Add(new TrialExperience()
{
CriterionType = item.CriterionType,
DoctorId = doctorId,
PhaseId = trial.PhaseId,
StartTime = DateTime.Now,
IndicationEnum = trial.IndicationEnum,
IndicationTypeId= trial.IndicationTypeId,
ExperienceDataType = dataType,
TrialId = trial.Id,
OtherCriterion= item.CriterionType.GetEnumInt()=="0"? item.CriterionName:string.Empty,
VisitReadingCount = 0,
ExperienceCriteriaList = new List<TrialExperienceCriteria>() {
new TrialExperienceCriteria()
{
DoctorId=doctorId,
EvaluationCriteriaId=criterionTypeList.Where(x=>x.Code==item.CriterionType.GetEnumInt()).Select(x=>x.Id).FirstOrDefault()
}
}
});
}
}
}
await _trialExperienceRepository.AddRangeAsync(trialExperienceList);
await _trialExperienceRepository.SaveChangesAsync();
}
}
else if (confirmReviewerCommand.ConfirmState == 0)//回退上一步
{
foreach (var intoGroupItem in intoGroupList)
{
if (confirmReviewerCommand.DoctorIdArray.Contains(intoGroupItem.DoctorId))
{
intoGroupItem.EnrollStatus = EnrollStatus.InviteIntoGroup;
intoGroupItem.EnrollTime = null;
var deleteItem = await _enrollDetailRepository.FirstOrDefaultAsync(t =>
t.TrialId == trialId && t.DoctorId == intoGroupItem.DoctorId &&
t.EnrollStatus == EnrollStatus.ConfirmIntoGroup);
await _enrollDetailRepository.DeleteAsync(deleteItem);
}
}
}
await _enrollRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// optType 0表示入组列表没这条数据了 1表示出组需要填写出组时间 废弃
/// </summary>
/// <param name="trialId"></param>
/// <param name="doctorId"></param>
/// <param name="optType"></param>
/// <param name="outEnrollTime"></param>
/// <returns></returns>
[HttpPost("{trialId:guid}/{doctorId:guid}/{optType:int}")]
[TrialGlobalLimit( "AfterStopCannNotOpt" )]
//[Authorize(Policy = IRaCISPolicy.PM_APM_SPM_CPM)]
[Obsolete]
public async Task<IResponseOutput> EnrollBackOrOut(Guid trialId, Guid doctorId, int optType, DateTime? outEnrollTime)
{
var intoGroupItem = await _enrollRepository.FirstOrDefaultAsync(t => t.TrialId == trialId && t.DoctorId == doctorId);
if (optType == 0)
{
var sum = _workloadRepository.Where(t =>
t.TrialId == trialId && t.DoctorId == doctorId &&
t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm)
.Sum(u => u.Adjudication + u.AdjudicationIn24H + u.AdjudicationIn48H + u.Timepoint +
u.TimepointIn24H + u.TimepointIn48H + u.RefresherTraining + u.Training + u.Global +
u.Downtime);
if (sum != 0)
{
//---Reviewers with workload cannot go back
return ResponseOutput.NotOk(_localizer["Enroll_CannotRollback"]);
}
intoGroupItem.EnrollStatus = EnrollStatus.InviteIntoGroup;
intoGroupItem.EnrollTime = null;
var deleteItem = await _enrollDetailRepository.FirstOrDefaultAsync(t =>
t.TrialId == trialId && t.DoctorId == intoGroupItem.DoctorId &&
t.EnrollStatus == EnrollStatus.ConfirmIntoGroup);
await _enrollDetailRepository.DeleteAsync(deleteItem);
}
else if (optType == 1)
{
intoGroupItem.OutEnrollTime = outEnrollTime;
}
return ResponseOutput.Result(await _enrollRepository.SaveChangesAsync());
}
#endregion
}
}