714 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C#
		
	
	
			
		
		
	
	
			714 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			C#
		
	
	
| using AutoMapper;
 | ||
| using IRaCIS.Application.Interfaces;
 | ||
| using IRaCIS.Application.Contracts;
 | ||
| using IRaCIS.Application.Contracts.Pay;
 | ||
| using IRaCIS.Core.Domain.Share;
 | ||
| using System.Linq.Expressions;
 | ||
| using IRaCIS.Core.Infra.EFCore;
 | ||
| using IRaCIS.Core.Domain.Models;
 | ||
| using IRaCIS.Core.Infrastructure.Extention;
 | ||
| using Panda.DynamicWebApi.Attributes;
 | ||
| 
 | ||
| namespace IRaCIS.Application.Services
 | ||
| {
 | ||
|     public class CalculateService : ICalculateService
 | ||
|     {
 | ||
|         private readonly IRepository<Payment> _paymentRepository;
 | ||
|         private readonly IRepository<TrialPaymentPrice> _trialPaymentRepository;
 | ||
|         private readonly IRepository<ReviewerPayInformation> _doctorPayInfoRepository;
 | ||
|         private readonly IRepository<Trial> _trialRepository;
 | ||
|         private readonly IRepository<Doctor> _doctorRepository;
 | ||
|         private readonly IRepository<Workload> _doctorWorkloadRepository;
 | ||
|         private readonly IRepository<RankPrice> _rankPriceRepository;
 | ||
|         private readonly IRepository<PaymentDetail> _paymentDetailRepository;
 | ||
|         private readonly IVolumeRewardService _volumeRewardPriceService;
 | ||
|         private readonly IRepository<ExchangeRate> _exchangeRateRepository;
 | ||
|         private readonly IRepository<PaymentAdjustment> _payAdjustmentRepository;
 | ||
|         private readonly IRepository<Enroll> _enrollRepository;
 | ||
|         private readonly IMapper _mapper;
 | ||
| 
 | ||
|         public CalculateService(IRepository<Payment> paymentRepository, IRepository<TrialPaymentPrice> trialPaymentPriceRepository,
 | ||
|             IRepository<ReviewerPayInformation> reviewerPayInfoRepository,
 | ||
|             IRepository<Trial> trialRepository,
 | ||
|             IRepository<Doctor> doctorRepository,
 | ||
|             IRepository<Workload> workloadRepository,
 | ||
|             IRepository<RankPrice> rankPriceRepository,
 | ||
|             IRepository<PaymentDetail> paymentDetailRepository,
 | ||
|             IVolumeRewardService volumeRewardService,
 | ||
|             IRepository<ExchangeRate> exchangeRateRepository,
 | ||
|             IRepository<Enroll> EnrollRepository,
 | ||
|             IRepository<PaymentAdjustment> paymentAdjustmentRepository, IMapper mapper)
 | ||
|         {
 | ||
|             _paymentRepository = paymentRepository;
 | ||
|             _trialPaymentRepository = trialPaymentPriceRepository;
 | ||
|             _doctorPayInfoRepository = reviewerPayInfoRepository;
 | ||
|             _trialRepository = trialRepository;
 | ||
|             _doctorRepository = doctorRepository;
 | ||
|             _doctorWorkloadRepository = workloadRepository;
 | ||
|             _rankPriceRepository = rankPriceRepository;
 | ||
|             _paymentDetailRepository = paymentDetailRepository;
 | ||
|             _volumeRewardPriceService = volumeRewardService;
 | ||
|             _exchangeRateRepository = exchangeRateRepository;
 | ||
|             _payAdjustmentRepository = paymentAdjustmentRepository;
 | ||
|             this._enrollRepository = EnrollRepository;
 | ||
|             _mapper = mapper;
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取某个月下的某些医生最终确认的工作量,用于计算月度费用
 | ||
|         /// </summary>
 | ||
|         private async Task< List<CalculatePaymentDTO>> GetFinalConfirmedWorkloadAndPayPriceList(CalculateDoctorAndMonthDTO calculateFeeParam)
 | ||
|         {
 | ||
|             Expression<Func<Workload, bool>> workloadLambda = x => true;
 | ||
| 
 | ||
|             DateTime bTime = new DateTime(calculateFeeParam.CalculateMonth.Year, calculateFeeParam.CalculateMonth.Month, 1);
 | ||
|             var eTime = bTime.AddMonths(1);
 | ||
|             workloadLambda = workloadLambda.And(t =>
 | ||
|                 t.WorkTime >= bTime && t.WorkTime < eTime);
 | ||
| 
 | ||
|             workloadLambda = workloadLambda.And(t => calculateFeeParam.NeedCalculateReviewers.Contains(t.DoctorId) && t.DataFrom == (int)WorkLoadFromStatus.FinalConfirm);
 | ||
|             var workLoadQueryable = from doctor in _doctorRepository.AsQueryable()
 | ||
|                                     join workLoad in _doctorWorkloadRepository.Where(workloadLambda) on
 | ||
|                                         doctor.Id equals workLoad.DoctorId
 | ||
|                                     join trial in _trialRepository.AsQueryable() on workLoad.TrialId equals trial.Id
 | ||
|                                     join trialPay in _trialPaymentRepository.AsQueryable() on trial.Id equals trialPay.TrialId
 | ||
|                                     into temp
 | ||
|                                     from trialPay in temp.DefaultIfEmpty()
 | ||
|                                     join doctorPayInfo in _doctorPayInfoRepository.AsQueryable() on doctor.Id equals doctorPayInfo.DoctorId
 | ||
|                                     join rankPrice in _rankPriceRepository.AsQueryable() on doctorPayInfo.RankId equals rankPrice.Id
 | ||
|                                     select new CalculatePaymentDTO()
 | ||
|                                     {
 | ||
|                                         Id = workLoad.Id,
 | ||
|                                         DoctorId = workLoad.DoctorId,
 | ||
|                                         WorkTime = workLoad.WorkTime,
 | ||
|                                         DataFrom = workLoad.DataFrom,
 | ||
|                                         TrialId = workLoad.TrialId,
 | ||
|                                         TrialCode = trial.TrialCode,
 | ||
| 
 | ||
|                                         Timepoint = workLoad.Timepoint,
 | ||
|                                         TimepointIn24H = workLoad.TimepointIn24H,
 | ||
|                                         TimepointIn48H = workLoad.TimepointIn48H,
 | ||
|                                         Global = workLoad.Global,
 | ||
|                                         Adjudication = workLoad.Adjudication,
 | ||
|                                         AdjudicationIn24H = workLoad.AdjudicationIn24H,
 | ||
|                                         AdjudicationIn48H = workLoad.AdjudicationIn48H,
 | ||
|                                         Training = workLoad.Training,
 | ||
|                                         RefresherTraining = workLoad.RefresherTraining,
 | ||
|                                         Downtime = workLoad.Downtime,
 | ||
| 
 | ||
|                                         TrialAdditional = trialPay.TrialAdditional,
 | ||
|                                         PersonalAdditional = doctorPayInfo.Additional,
 | ||
|                                         AdjustmentMultiple = trialPay.AdjustmentMultiple,
 | ||
| 
 | ||
|                                         TimepointPrice = rankPrice.Timepoint,
 | ||
|                                         TimepointIn24HPrice = rankPrice.TimepointIn24H,
 | ||
|                                         TimepointIn48HPrice = rankPrice.TimepointIn48H,
 | ||
|                                         AdjudicationPrice = rankPrice.Adjudication,
 | ||
|                                         AdjudicationIn24HPrice = rankPrice.AdjudicationIn24H,
 | ||
|                                         AdjudicationIn48HPrice = rankPrice.AdjudicationIn48H,
 | ||
|                                         DowntimePrice = rankPrice.Downtime,
 | ||
|                                         GlobalPrice = rankPrice.Global,
 | ||
|                                         TrainingPrice = rankPrice.Training,
 | ||
|                                         RefresherTrainingPrice = rankPrice.RefresherTraining
 | ||
|                                     };
 | ||
| 
 | ||
|             return await workLoadQueryable.ToListAsync();
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 计算月度费用,并调用AddOrUpdateMonthlyPayment和AddOrUpdateMonthlyPaymentDetail方法,
 | ||
|         /// 将费用计算的月度数据及详情保存
 | ||
|         /// </summary>
 | ||
|         [NonDynamicMethod]
 | ||
|         public async Task<IResponseOutput> CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param, string token)
 | ||
|         {
 | ||
|             var yearMonth = param.CalculateMonth.ToString("yyyy-MM");
 | ||
|             var rate = await _exchangeRateRepository.FirstOrDefaultAsync(u => u.YearMonth == yearMonth);
 | ||
| 
 | ||
|             decimal exchangeRate = rate?.Rate ?? 0;
 | ||
| 
 | ||
|             var workLoadAndPayPriceList = await GetFinalConfirmedWorkloadAndPayPriceList(param);
 | ||
|             var volumeRewardPriceList = await _volumeRewardPriceService.GetVolumeRewardPriceList();
 | ||
| 
 | ||
|             #region 奖励数据校验
 | ||
|             for (int i = 0; i < volumeRewardPriceList.Count; i++)
 | ||
|             {
 | ||
|                 if (i == 0 && volumeRewardPriceList[i].Min != 0)
 | ||
|                 {
 | ||
|                     return ResponseOutput.NotOk("Volume reward data error.");
 | ||
|                 }
 | ||
|                 if (i > 0)
 | ||
|                 {
 | ||
|                     if (volumeRewardPriceList[i - 1].Max + 1 != volumeRewardPriceList[i].Min)
 | ||
|                         return ResponseOutput.NotOk("Volume reward data error.");
 | ||
|                 }
 | ||
|             }
 | ||
| 
 | ||
| 
 | ||
|             #endregion
 | ||
| 
 | ||
| 
 | ||
|             List<PaymentModel> paymentList = new List<PaymentModel>();
 | ||
|             List<ReviewerPaymentUSD> reviewerPaymentUSDList = new List<ReviewerPaymentUSD>();
 | ||
| 
 | ||
|             // 获取所有医生费用   一次从数据库里面全部取出来
 | ||
| 
 | ||
|             var allDoctorList = workLoadAndPayPriceList.Where(x => param.NeedCalculateReviewers.Contains(x.DoctorId)).ToList();
 | ||
|             var allDoctorIds = allDoctorList.Select(x => x.DoctorId).Distinct().ToList();
 | ||
|             var listTrialId = allDoctorList.Select(x => x.TrialId).Distinct().ToList();
 | ||
| 
 | ||
|             var trialDoctorlist= await (from enroll in _enrollRepository.Where(x=> listTrialId.Contains(x.TrialId)|| allDoctorIds.Contains(x.DoctorId))
 | ||
|                                   join price in _trialPaymentRepository.Where() on enroll.TrialId equals price.TrialId
 | ||
|                                   select new DoctorPrice()
 | ||
|                                   {
 | ||
|                                       IsNewTrial = price.IsNewTrial,
 | ||
|                                       AdjustmentMultiple = enroll.AdjustmentMultiple,
 | ||
|                                       TrialId=enroll.TrialId,
 | ||
|                                       DoctorId = enroll.DoctorId,
 | ||
|                                       Training=enroll.Training,
 | ||
|                                       Adjudication=enroll.Adjudication, 
 | ||
|                                       Adjudication24H=enroll.Adjudication24H,
 | ||
|                                       Adjudication48H=  enroll.Adjudication48H,
 | ||
|                                       Downtime=enroll.Downtime,
 | ||
|                                       Global=enroll.Global,
 | ||
|                                       RefresherTraining=enroll.RefresherTraining,
 | ||
|                                       Timepoint= enroll.Timepoint,
 | ||
|                                       Timepoint24H=enroll.Timepoint24H,
 | ||
|                                       Timepoint48H=enroll.Timepoint48H,
 | ||
|                                   }).ToListAsync();
 | ||
| 
 | ||
| 
 | ||
|             foreach (var doctor in param.NeedCalculateReviewers)
 | ||
|             {
 | ||
|                 if (await _paymentRepository.AnyAsync(u => u.DoctorId == doctor && u.YearMonth == yearMonth && u.IsLock))
 | ||
|                 {
 | ||
|                     break;
 | ||
|                 }
 | ||
|                 List<PaymentDetailCommand> paymentDetailList = new List<PaymentDetailCommand>();
 | ||
|                 decimal totalNormal = 0;
 | ||
| 
 | ||
|                 //计算单个医生费用统,并且插入到统计表
 | ||
|                 var doctorWorkloadAndPayPriceList = workLoadAndPayPriceList.Where(u => u.DoctorId == doctor).ToList();
 | ||
| 
 | ||
|                 //阅片数量 计算奖励费用
 | ||
|                 int readCount = 0;
 | ||
| 
 | ||
|                 int codeOrder = 0;
 | ||
| 
 | ||
|                 //这里需要改
 | ||
| 
 | ||
|                 foreach (var item in doctorWorkloadAndPayPriceList)
 | ||
|                 {
 | ||
|                     var doctordata = trialDoctorlist.Where(x => x.IsNewTrial ?? false && x.Training == item.Training && x.DoctorId == item.DoctorId).FirstOrDefault();
 | ||
| 
 | ||
|                     if (doctordata != null)
 | ||
|                     {
 | ||
|                         item.Training = doctordata.Training??0;
 | ||
|                         item.Adjudication = doctordata.Adjudication??0;
 | ||
|                         item.AdjudicationIn24H = doctordata.Adjudication24H??0;
 | ||
|                         item.AdjudicationIn48H = doctordata.Adjudication48H??0;
 | ||
|                         item.Downtime = doctordata.Downtime??0;
 | ||
|                         item.Global = doctordata.Global??0;
 | ||
|                         item.RefresherTraining = doctordata.RefresherTraining??0;
 | ||
|                         item.Timepoint = doctordata.Timepoint??0;
 | ||
|                         item.TimepointIn24H = doctordata.Timepoint24H??0;
 | ||
|                         item.TimepointIn48H = doctordata.Timepoint48H??0;
 | ||
|                         item.PersonalAdditional = 0;
 | ||
|                     }
 | ||
|                     ++codeOrder;
 | ||
|                     readCount += (item.Timepoint + item.TimepointIn24H + item.TimepointIn48H
 | ||
|                     + item.Adjudication + item.AdjudicationIn24H + item.AdjudicationIn48H);
 | ||
|                     decimal trainingTotal = item.Training * item.TrainingPrice;
 | ||
|                     decimal refresherTrainingTotal = item.RefresherTraining * item.RefresherTrainingPrice;
 | ||
|                     decimal downtimeTotal = item.Downtime * item.DowntimePrice;
 | ||
|                     //规则定义  global 的价格是Tp和个人附加的一半
 | ||
|                     decimal globalTotal = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2);
 | ||
| 
 | ||
|                     //项目如果没有添加附加数据 默认为0
 | ||
|                     decimal timePointTotal = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional));
 | ||
| 
 | ||
|                     decimal timePointIn24HTotal = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + item.PersonalAdditional);
 | ||
|                     decimal timePointIn48HTotal = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional);
 | ||
|                     decimal adjudicationTotal = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional));
 | ||
|                     decimal adjudicationIn24HTotal = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + item.PersonalAdditional);
 | ||
|                     decimal adjudicationIn48HTotal = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional);
 | ||
| 
 | ||
|                     totalNormal += (trainingTotal + refresherTrainingTotal + downtimeTotal + globalTotal + timePointTotal + timePointIn24HTotal
 | ||
|                         + timePointIn48HTotal + adjudicationTotal + adjudicationIn24HTotal + adjudicationIn48HTotal);
 | ||
| 
 | ||
|                     #region 统计明细信息
 | ||
| 
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Training",
 | ||
|                         Count = item.Training,
 | ||
|                         BasePrice = item.TrainingPrice,
 | ||
|                         PersonalAdditional = 0,
 | ||
|                         TrialAdditional = 0,
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 1,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.Training * item.TrainingPrice,
 | ||
|                         PaymentCNY = item.Training * item.TrainingPrice * exchangeRate
 | ||
|                     });
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Refresher Training",
 | ||
|                         Count = item.RefresherTraining,
 | ||
|                         BasePrice = item.RefresherTrainingPrice,
 | ||
|                         PersonalAdditional = 0,
 | ||
|                         TrialAdditional = 0,
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 2,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.RefresherTraining * item.RefresherTrainingPrice,
 | ||
|                         PaymentCNY = item.RefresherTraining * item.RefresherTrainingPrice * exchangeRate
 | ||
|                     });
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Downtime",
 | ||
|                         Count = item.Downtime,
 | ||
|                         BasePrice = item.DowntimePrice,
 | ||
|                         PersonalAdditional = 0,
 | ||
|                         TrialAdditional = 0,
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 3,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.Downtime * item.DowntimePrice,
 | ||
|                         PaymentCNY = item.Downtime * item.DowntimePrice * exchangeRate
 | ||
|                     });
 | ||
| 
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Timepoint Regular",
 | ||
|                         Count = item.Timepoint,
 | ||
|                         BasePrice = item.TimepointPrice,
 | ||
|                         PersonalAdditional = doctordata!=null?0: item.PersonalAdditional,
 | ||
|                         TrialAdditional = doctordata != null ? 0 : item.TimepointPrice * (item.AdjustmentMultiple - 1) + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional),
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 4,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)),
 | ||
|                         PaymentCNY = item.Timepoint * (item.TimepointPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)) * exchangeRate
 | ||
|                     });
 | ||
| 
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Timepoint 48-Hour",
 | ||
|                         Count = item.TimepointIn48H,
 | ||
|                         BasePrice = item.TimepointIn48HPrice,
 | ||
|                         PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
 | ||
|                         TrialAdditional = doctordata != null ? 0 : item.TimepointIn48HPrice * (item.AdjustmentMultiple - 1) + 0,//48小时不加项目附加
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 5,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional),
 | ||
|                         PaymentCNY = item.TimepointIn48H * (item.TimepointIn48HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate
 | ||
|                     });
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Timepoint 24-Hour",
 | ||
|                         Count = item.TimepointIn24H,
 | ||
|                         BasePrice = item.TimepointIn24HPrice,
 | ||
|                         PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
 | ||
|                         TrialAdditional = doctordata != null ? 0 : item.TimepointIn24HPrice * (item.AdjustmentMultiple - 1) + 0,
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 6,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional),
 | ||
|                         PaymentCNY = item.TimepointIn24H * (item.TimepointIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate
 | ||
|                     });
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Adjudication Regular",
 | ||
|                         Count = item.Adjudication,
 | ||
|                         BasePrice = item.AdjudicationPrice,
 | ||
|                         PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
 | ||
|                         TrialAdditional = doctordata != null ? 0 : item.AdjudicationPrice * (item.AdjustmentMultiple - 1) + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional),
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 7,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)),
 | ||
|                         PaymentCNY = item.Adjudication * (item.AdjudicationPrice * item.AdjustmentMultiple + item.PersonalAdditional + (item.TrialAdditional == null ? 0 : (decimal)item.TrialAdditional)) * exchangeRate
 | ||
|                     });
 | ||
| 
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Adjudication 48-Hour",
 | ||
|                         Count = item.AdjudicationIn48H,
 | ||
|                         BasePrice = item.AdjudicationIn48HPrice,
 | ||
|                         PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
 | ||
|                         TrialAdditional = doctordata != null ? 0 : item.AdjudicationIn48HPrice * (item.AdjustmentMultiple - 1) + 0,
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 8,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional + 0),
 | ||
|                         PaymentCNY = item.AdjudicationIn48H * (item.AdjudicationIn48HPrice * item.AdjustmentMultiple + item.PersonalAdditional + 0) * exchangeRate
 | ||
|                     });
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Adjudication 24-Hour",
 | ||
|                         Count = item.AdjudicationIn24H,
 | ||
|                         BasePrice = item.AdjudicationIn24HPrice,
 | ||
|                         PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional,
 | ||
|                         TrialAdditional = doctordata != null ? 0 : item.AdjudicationIn24HPrice * (item.AdjustmentMultiple - 1) + 0,
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 9,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional),
 | ||
|                         PaymentCNY = item.AdjudicationIn24H * (item.AdjudicationIn24HPrice * item.AdjustmentMultiple + 0 + item.PersonalAdditional) * exchangeRate
 | ||
|                     });
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = item.TrialCode,
 | ||
|                         PaymentType = "Global",
 | ||
|                         Count = item.Global,
 | ||
|                         BasePrice = item.TimepointPrice / 2,//item.GlobalPrice,
 | ||
|                         PersonalAdditional = doctordata != null ? 0 : item.PersonalAdditional / 2,
 | ||
|                         TrialAdditional = 0,
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = item.DoctorId,
 | ||
|                         TrialId = item.TrialId,
 | ||
|                         ShowTypeOrder = 10,
 | ||
|                         ShowCodeOrder = codeOrder,
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2),
 | ||
|                         PaymentCNY = item.Global * (item.TimepointPrice / 2 + item.PersonalAdditional / 2) * exchangeRate
 | ||
|                     });
 | ||
|                     #endregion
 | ||
|                 }
 | ||
| 
 | ||
|                 int typeOrder = 0;
 | ||
|                 if (readCount > 0)
 | ||
|                 {
 | ||
|                     paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                     {
 | ||
|                         TrialCode = "Volume Reward",
 | ||
|                         PaymentType = "Total TP & AD",
 | ||
|                         Count = readCount,
 | ||
|                         BasePrice = 0,
 | ||
|                         PersonalAdditional = 0,
 | ||
|                         TrialAdditional = 0,
 | ||
|                         PaymentId = Guid.Empty,
 | ||
|                         DoctorId = doctor,
 | ||
|                         TrialId = Guid.Empty,
 | ||
|                         ShowTypeOrder = typeOrder,
 | ||
|                         ShowCodeOrder = (++codeOrder),
 | ||
|                         ExchangeRate = exchangeRate,
 | ||
|                         YearMonth = yearMonth,
 | ||
|                         PaymentUSD = 0,
 | ||
|                         PaymentCNY = 0
 | ||
|                     });
 | ||
| 
 | ||
|                     foreach (var awardItem in volumeRewardPriceList)
 | ||
|                     {
 | ||
|                         ++typeOrder;
 | ||
|                         if ((readCount - awardItem.Min + 1) < 0)
 | ||
|                         {
 | ||
|                             break;
 | ||
|                         }
 | ||
|                         if (awardItem.Min == 0)
 | ||
|                         {
 | ||
|                             paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                             {
 | ||
|                                 TrialCode = "Volume Reward",
 | ||
|                                 PaymentType = awardItem.Min + "-" + awardItem.Max,
 | ||
|                                 Count = readCount >= awardItem.Max ?
 | ||
|                             (awardItem.Max - awardItem.Min) : (readCount - awardItem.Min),
 | ||
|                                 BasePrice = awardItem.Price,
 | ||
|                                 PersonalAdditional = 0,
 | ||
|                                 TrialAdditional = 0,
 | ||
|                                 PaymentId = Guid.Empty,//result.Data,
 | ||
|                                 DoctorId = doctor,
 | ||
|                                 TrialId = Guid.Empty,
 | ||
|                                 ShowTypeOrder = typeOrder,
 | ||
|                                 ShowCodeOrder = (++codeOrder),
 | ||
|                                 ExchangeRate = exchangeRate,
 | ||
|                                 YearMonth = yearMonth,
 | ||
|                                 PaymentUSD = (readCount >= awardItem.Max ?
 | ||
|                             (awardItem.Max - awardItem.Min) : (readCount - awardItem.Min)) * awardItem.Price,
 | ||
|                                 PaymentCNY = (readCount >= awardItem.Max ?
 | ||
|                             (awardItem.Max - awardItem.Min) : (readCount - awardItem.Min)) * awardItem.Price * exchangeRate
 | ||
|                             });
 | ||
|                         }
 | ||
|                         else
 | ||
|                         {
 | ||
|                             paymentDetailList.Add(new PaymentDetailCommand
 | ||
|                             {
 | ||
|                                 TrialCode = "Volume Reward",
 | ||
|                                 PaymentType = awardItem.Min + "-" + awardItem.Max,
 | ||
|                                 Count = readCount >= awardItem.Max ?
 | ||
|                                 (awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1),
 | ||
|                                 BasePrice = awardItem.Price,
 | ||
|                                 PersonalAdditional = 0,
 | ||
|                                 TrialAdditional = 0,
 | ||
|                                 PaymentId = Guid.Empty,
 | ||
|                                 DoctorId = doctor,
 | ||
|                                 TrialId = Guid.Empty,
 | ||
|                                 ShowTypeOrder = typeOrder,
 | ||
|                                 ShowCodeOrder = (++codeOrder),
 | ||
|                                 ExchangeRate = exchangeRate,
 | ||
|                                 YearMonth = yearMonth,
 | ||
|                                 PaymentUSD = (readCount >= awardItem.Max ?
 | ||
|                                 (awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1)) * awardItem.Price,
 | ||
|                                 PaymentCNY = (readCount >= awardItem.Max ?
 | ||
|                                 (awardItem.Max - awardItem.Min + 1) : (readCount - awardItem.Min + 1)) * awardItem.Price * exchangeRate
 | ||
|                             });
 | ||
|                         }
 | ||
|                     }
 | ||
| 
 | ||
|                 }
 | ||
|                 decimal award = 0;
 | ||
|                 volumeRewardPriceList = volumeRewardPriceList.OrderBy(u => u.Min).ToList();
 | ||
| 
 | ||
|                 var levelTemp = -1; //用来计算属于哪一个挡位
 | ||
|                 foreach (var awarPriceitem in volumeRewardPriceList)
 | ||
|                 {
 | ||
|                     if (awarPriceitem.Min == 0)
 | ||
|                     {
 | ||
|                         if (readCount > awarPriceitem.Max)
 | ||
|                         {
 | ||
|                             ++levelTemp;
 | ||
|                             award += (awarPriceitem.Max - awarPriceitem.Min) * awarPriceitem.Price;
 | ||
|                         }
 | ||
|                         if (awarPriceitem.Min < readCount && readCount < awarPriceitem.Max)
 | ||
|                         {
 | ||
|                             ++levelTemp;
 | ||
|                             award += (readCount - awarPriceitem.Min) * awarPriceitem.Price;
 | ||
|                             break; ;
 | ||
|                         }
 | ||
|                     }
 | ||
|                     else
 | ||
|                     {
 | ||
|                         if (readCount > awarPriceitem.Max)
 | ||
|                         {
 | ||
|                             ++levelTemp;
 | ||
|                             award += (awarPriceitem.Max - awarPriceitem.Min + 1) * awarPriceitem.Price;
 | ||
|                         }
 | ||
|                         if (awarPriceitem.Min < readCount && readCount < awarPriceitem.Max)
 | ||
|                         {
 | ||
|                             ++levelTemp;
 | ||
|                             award += (readCount - awarPriceitem.Min + 1) * awarPriceitem.Price;
 | ||
|                             break; ;
 | ||
|                         }
 | ||
|                     }
 | ||
|                 }
 | ||
|                 decimal totalUSD = award + totalNormal;//总费用
 | ||
| 
 | ||
|                 var result = await AddOrUpdateMonthlyPayment(new PaymentCommand
 | ||
|                 {
 | ||
|                     DoctorId = doctor,
 | ||
|                     Year = param.CalculateMonth.Year,
 | ||
|                     Month = param.CalculateMonth.Month,
 | ||
|                     PaymentUSD = totalUSD,
 | ||
|                     CalculateUser = token,
 | ||
|                     CalculateTime = DateTime.Now,
 | ||
|                     ExchangeRate = exchangeRate,
 | ||
|                     PaymentCNY = exchangeRate * totalUSD,
 | ||
|                 });
 | ||
| 
 | ||
| 
 | ||
|                 reviewerPaymentUSDList.Add(new ReviewerPaymentUSD { DoctorId = doctor, PaymentUSD = totalUSD, RecordId = result.Data });
 | ||
|                 foreach (var detail in paymentDetailList)
 | ||
|                 {
 | ||
|                     //var data = trialDoctorlist.FirstOrDefault(x => x.DoctorId == detail.DoctorId && x.TrialId == detail.TrialId && x.IsNewTrial == true && (x.AdjustmentMultiple??0) != 0);
 | ||
|                     //if (data != null)
 | ||
|                     //{
 | ||
|                     //    detail.BasePrice = data.AdjustmentMultiple??0;
 | ||
|                     //    detail.PersonalAdditional = 0;
 | ||
|                     //    detail.TrialAdditional = 0;
 | ||
|                     //}
 | ||
|                         
 | ||
|                     detail.PaymentId = result.Data;
 | ||
|                 }
 | ||
|                 await AddOrUpdateMonthlyPaymentDetail(paymentDetailList, result.Data);
 | ||
| 
 | ||
|                 await UpdatePaymentAdjustment(doctor, yearMonth);
 | ||
|             }
 | ||
|             return ResponseOutput.Ok(reviewerPaymentUSDList);
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         // 重新计算调整费用
 | ||
| 
 | ||
|         private async Task UpdatePaymentAdjustment(Guid reviewerId, string yearMonth)
 | ||
|         {
 | ||
|             var adjustList = await _payAdjustmentRepository.Where(u => u.YearMonth == yearMonth &&
 | ||
|                                                                           !u.IsLock && u.ReviewerId == reviewerId).ToListAsync();
 | ||
| 
 | ||
| 
 | ||
|             var needUpdatePayment = adjustList.GroupBy(t => t.ReviewerId).Select(g => new
 | ||
|             {
 | ||
|                 ReviewerId = g.Key,
 | ||
|                 AdjustCNY = g.Sum(t => t.AdjustmentCNY),
 | ||
|                 AdjustUSD = g.Sum(t => t.AdjustmentUSD)
 | ||
|             });
 | ||
| 
 | ||
|             foreach (var reviewer in needUpdatePayment)
 | ||
|             {
 | ||
|                await  _paymentRepository.BatchUpdateNoTrackingAsync(u => u.YearMonth == yearMonth &&
 | ||
|                                                !u.IsLock && u.DoctorId == reviewer.ReviewerId, t => new Payment()
 | ||
|                                                {
 | ||
|                                                    AdjustmentUSD = reviewer.AdjustUSD,
 | ||
|                                                    AdjustmentCNY = reviewer.AdjustCNY
 | ||
| 
 | ||
|                                                });
 | ||
|             }
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 保存费用计算的月度数据
 | ||
|         /// </summary>
 | ||
|         private async Task<IResponseOutput<Guid>> AddOrUpdateMonthlyPayment(PaymentCommand addOrUpdateModel)
 | ||
|         {
 | ||
|             var success = false;
 | ||
|             var paymentModel = await _paymentRepository.FirstOrDefaultAsync(t =>
 | ||
|                 t.DoctorId == addOrUpdateModel.DoctorId && t.YearMonth == addOrUpdateModel.YearMonth);
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|             //var taxCNY = GetTax(addOrUpdateModel.PaymentCNY);
 | ||
|             //var actuallyPaidCNY = addOrUpdateModel.PaymentCNY - taxCNY;
 | ||
|             //var bankTransferCNY = addOrUpdateModel.PaymentCNY - taxCNY;
 | ||
| 
 | ||
|             if (paymentModel == null)
 | ||
|             {
 | ||
|                 var payment = _mapper.Map<Payment>(addOrUpdateModel);
 | ||
| 
 | ||
|                 //payment.BankTransferCNY = bankTransferCNY;
 | ||
|                 //payment.TaxCNY= taxCNY;
 | ||
|                 //payment.BankTransferCNY = bankTransferCNY;
 | ||
|                 payment.YearMonthDate = DateTime.Parse(payment.YearMonth);
 | ||
| 
 | ||
|                 payment =await _paymentRepository.AddAsync(payment);
 | ||
|                 success =await _paymentRepository.SaveChangesAsync();
 | ||
|                 return ResponseOutput.Result(success, payment.Id);
 | ||
|             }
 | ||
|             else
 | ||
|             {
 | ||
|                 // 如果是 当月计算的工作量费用 和 调整费用都为0,则删除该行记录
 | ||
|                 if (addOrUpdateModel.PaymentUSD == 0 && paymentModel.AdjustmentUSD == 0)
 | ||
|                 {
 | ||
|                     success =await _paymentRepository.BatchDeleteNoTrackingAsync(u => u.Id == paymentModel.Id);
 | ||
|                     //_paymentDetailRepository.Delete(u=>u.PaymentId==paymentModel.Id);
 | ||
|                 }
 | ||
|                 else
 | ||
|                 {
 | ||
|                     success = await _paymentRepository.BatchUpdateNoTrackingAsync(t => t.Id == paymentModel.Id, u => new Payment()
 | ||
|                     {
 | ||
|                         PaymentUSD = addOrUpdateModel.PaymentUSD,
 | ||
|                         CalculateTime = addOrUpdateModel.CalculateTime,
 | ||
|                         CalculateUser = addOrUpdateModel.CalculateUser,
 | ||
|                         //TaxCNY = taxCNY,
 | ||
|                         //ActuallyPaidCNY = actuallyPaidCNY,
 | ||
|                         //BankTransferCNY = bankTransferCNY,
 | ||
|                         PaymentCNY = addOrUpdateModel.PaymentCNY,
 | ||
|                         ExchangeRate = addOrUpdateModel.ExchangeRate
 | ||
|                     });
 | ||
|                 }
 | ||
| 
 | ||
|                 return ResponseOutput.Result(success, paymentModel.Id);
 | ||
|             }
 | ||
| 
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 保存费用计算的月度详情
 | ||
|         /// </summary>
 | ||
|         private async Task<bool> AddOrUpdateMonthlyPaymentDetail(List<PaymentDetailCommand> addOrUpdateList, Guid paymentId)
 | ||
|         {
 | ||
|             //var paymentDetailIds = addOrUpdateList.Select(t => t.PaymentId).ToList();
 | ||
|             await _paymentDetailRepository.BatchDeleteNoTrackingAsync(t => t.PaymentId == paymentId);
 | ||
|             await _paymentDetailRepository.AddRangeAsync(_mapper.Map<List<PaymentDetail>>(addOrUpdateList));
 | ||
|             return await _paymentDetailRepository.SaveChangesAsync();
 | ||
|         }
 | ||
| 
 | ||
| 
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 获取待计算费用的Reviewer对应的月份列表
 | ||
|         /// </summary>
 | ||
|         public async Task<List<CalculateNeededDTO>> GetNeedCalculateReviewerList(Guid reviewerId, string yearMonth)
 | ||
|         {
 | ||
|             Expression<Func<Payment, bool>> calculateLambda = u => !u.IsLock;
 | ||
|             if (reviewerId != Guid.Empty)
 | ||
|             {
 | ||
|                 calculateLambda = calculateLambda.And(u => u.DoctorId == reviewerId);
 | ||
|             }
 | ||
|             if (!string.IsNullOrWhiteSpace(yearMonth))
 | ||
|             {
 | ||
|                 calculateLambda = calculateLambda.And(u => u.YearMonth == yearMonth);
 | ||
|             }
 | ||
|             return await _paymentRepository.Where(calculateLambda).ProjectTo<CalculateNeededDTO>(_mapper.ConfigurationProvider).ToListAsync();
 | ||
|         }
 | ||
| 
 | ||
|         /// <summary>
 | ||
|         /// 查询Reviewer某个月的费用是否被锁定
 | ||
|         /// </summary>
 | ||
|         public async Task<bool> IsLock(Guid reviewerId, string yearMonth)
 | ||
|         {
 | ||
|             return await _paymentRepository.AnyAsync(u => u.DoctorId == reviewerId && u.YearMonth == yearMonth && u.IsLock);
 | ||
|         }
 | ||
| 
 | ||
|         //public bool ResetMonthlyPayment(Guid reviewerId, Guid trialId, string yearMonth)
 | ||
|         //{
 | ||
|         //    var payment = _paymentRepository.FindSingleOrDefault(u => u.DoctorId == reviewerId && u.YearMonth == yearMonth);
 | ||
|         //    payment.PaymentCNY = 0;
 | ||
|         //    payment.PaymentUSD = 0;
 | ||
|         //    _paymentRepository.Update(payment);
 | ||
|         //    _paymentDetailRepository.Delete(u=>u.DoctorId==reviewerId && u.TrialId==trial)
 | ||
|         //}
 | ||
|     }
 | ||
| }
 |