using AutoMapper; using AutoMapper.QueryableExtensions; using IRaCIS.Application.Interfaces; using IRaCIS.Application.ViewModels; using IRaCIS.Application.ViewModels.Pay; using IRaCIS.Core.Application.Contracts.RequestAndResponse; using IRaCIS.Core.Domain.Share; using IRaCIS.Infra.Data.ExpressionExtend; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using IRaCIS.Core.Domain.Interfaces; using IRaCIS.Core.Domain.Models; using System.Data; using System.Linq.Dynamic.Core; using System.Drawing; namespace IRaCIS.Application.Services { public class CalculateService : ICalculateService { private readonly IPaymentRepository _paymentRepository; private readonly ITrialPaymentPriceRepository _trialPaymentRepository; private readonly IReviewerPayInfoRepository _doctorPayInfoRepository; private readonly ITrialRepository _trialRepository; private readonly IDoctorRepository _doctorRepository; private readonly IWorkloadRepository _doctorWorkloadRepository; private readonly IRankPriceRepository _rankPriceRepository; private readonly IUserTrialRepository _userTrialRepository; private readonly IPaymentDetailRepository _paymentDetailRepository; private readonly IVolumeRewardService _volumeRewardPriceService; private readonly IExchangeRateRepository _exchangeRateRepository; private readonly IPaymentAdjustmentRepository _payAdjustmentRepository; private readonly IEnrollRepository _enrollRepository; private readonly ITrialRevenuesPriceRepository _trialRevenuesPriceRepository; private readonly IMapper _mapper; public CalculateService(IPaymentRepository paymentRepository, ITrialPaymentPriceRepository trialPaymentPriceRepository, IReviewerPayInfoRepository reviewerPayInfoRepository, ITrialRepository trialRepository, IDoctorRepository doctorRepository, IWorkloadRepository workloadRepository, IRankPriceRepository rankPriceRepository, IUserTrialRepository userTrialRepository, IPaymentDetailRepository paymentDetailRepository, IVolumeRewardService volumeRewardService, IExchangeRateRepository exchangeRateRepository, IEnrollRepository enrollRepository, ITrialRevenuesPriceRepository trialRevenuesPriceRepository, IPaymentAdjustmentRepository paymentAdjustmentRepository, IMapper mapper) { _paymentRepository = paymentRepository; _trialPaymentRepository = trialPaymentPriceRepository; _doctorPayInfoRepository = reviewerPayInfoRepository; _trialRepository = trialRepository; _enrollRepository= enrollRepository; _doctorRepository = doctorRepository; _doctorWorkloadRepository = workloadRepository; _rankPriceRepository = rankPriceRepository; this._userTrialRepository = userTrialRepository; _paymentDetailRepository = paymentDetailRepository; _volumeRewardPriceService = volumeRewardService; _exchangeRateRepository = exchangeRateRepository; _payAdjustmentRepository = paymentAdjustmentRepository; _trialRevenuesPriceRepository = trialRevenuesPriceRepository; _mapper = mapper; } /// /// 获取某个月下的某些医生最终确认的工作量,用于计算月度费用 /// private List GetFinalConfirmedWorkloadAndPayPriceList(CalculateDoctorAndMonthDTO calculateFeeParam) { Expression> 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.GetAll() join workLoad in _doctorWorkloadRepository.GetAll().Where(workloadLambda) on doctor.Id equals workLoad.DoctorId join trial in _trialRepository.GetAll() on workLoad.TrialId equals trial.Id join trialPay in _trialPaymentRepository.GetAll() on trial.Id equals trialPay.TrialId into temp from trialPay in temp.DefaultIfEmpty() join doctorPayInfo in _doctorPayInfoRepository.GetAll() on doctor.Id equals doctorPayInfo.DoctorId join rankPrice in _rankPriceRepository.GetAll() on doctorPayInfo.RankId equals rankPrice.Id join trialRevenuesPrice in _trialRevenuesPriceRepository.GetAll() on trial.Id equals trialRevenuesPrice.TrialId into trialRevenuesPricetemp from trialRevenuesPrice in trialRevenuesPricetemp.DefaultIfEmpty() select new CalculatePaymentDTO() { Id = workLoad.Id, DoctorId = workLoad.DoctorId, WorkTime = workLoad.WorkTime, DataFrom = workLoad.DataFrom, TrialId = workLoad.TrialId, TrialCode = trial.Code, 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, AdditionalCharge1 = workLoad.AdditionalCharge1, AdditionalCharge2 = workLoad.AdditionalCharge2, AdditionalCharge3 = workLoad.AdditionalCharge3, Note = trialRevenuesPrice.Note, TrialAdditional = trialPay.TrialAdditional, PersonalAdditional = doctorPayInfo.Additional, AdjustmentMultiple = trialPay.AdjustmentMultiple, IsNewTrial = trialPay.IsNewTrial ?? false, 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, AdditionalCharge1Price = 0, AdditionalCharge2Price = 0, AdditionalCharge3Price = 0 }; return workLoadQueryable.ToList(); } /// /// 计算月度费用,并调用AddOrUpdateMonthlyPayment和AddOrUpdateMonthlyPaymentDetail方法, /// 将费用计算的月度数据及详情保存 /// public IResponseOutput CalculateMonthlyPayment(CalculateDoctorAndMonthDTO param, string token) { var yearMonth = param.CalculateMonth.ToString("yyyy-MM"); var rate = _exchangeRateRepository.FindSingleOrDefault(u => u.YearMonth == yearMonth); decimal exchangeRate = rate?.Rate ?? 0; IResponseOutput result = null; var workLoadAndPayPriceList = GetFinalConfirmedWorkloadAndPayPriceList(param); var volumeRewardPriceList = _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 paymentList = new List(); List reviewerPaymentUSDList = new List(); foreach (var doctor in param.NeedCalculateReviewers) { if (_paymentRepository.GetAll().Any(u => u.DoctorId == doctor && u.YearMonth == yearMonth && u.IsLock)) { break; } List paymentDetailList = new List(); decimal totalNormal = 0; //计算单个医生费用统,并且插入到统计表 var doctorWorkloadAndPayPriceList = workLoadAndPayPriceList.Where(u => u.DoctorId == doctor).ToList(); //阅片数量 计算奖励费用 int readCount = 0; int codeOrder = 0; foreach (var item in doctorWorkloadAndPayPriceList) { if (item.IsNewTrial) { var newPrice = _enrollRepository.GetAll().Where(x => x.TrialId == item.TrialId && x.DoctorId == item.DoctorId).FirstOrDefault(); if (newPrice != null) { item.TrainingPrice = newPrice.Training ?? 0; item.AdjudicationPrice = newPrice.Adjudication ?? 0; item.AdjudicationIn24HPrice = newPrice.Adjudication24H ?? 0; item.AdjudicationIn48HPrice = newPrice.Adjudication48H ?? 0; item.DowntimePrice = newPrice.Downtime ?? 0; item.GlobalPrice = newPrice.Global ?? 0; item.RefresherTrainingPrice = newPrice.RefresherTraining ?? 0; item.TimepointPrice = newPrice.Timepoint ?? 0; item.TimepointIn24HPrice = newPrice.Timepoint24H ?? 0; item.TimepointIn48HPrice = newPrice.Timepoint48H ?? 0; item.AdditionalCharge1Price = newPrice.AdditionalCharge1 ?? 0; item.AdditionalCharge2Price = newPrice.AdditionalCharge2 ?? 0; item.AdditionalCharge3Price = newPrice.AdditionalCharge3 ?? 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; decimal ac1Total = item.AdditionalCharge1 * item.AdditionalCharge1Price; decimal ac2Total = item.AdditionalCharge2 * item.AdditionalCharge2Price; decimal ac3Total = item.AdditionalCharge3 * item.AdditionalCharge3Price; decimal globalTotal = item.Global * (item.GlobalPrice); //项目如果没有添加附加数据 默认为0 decimal timePointTotal = item.Timepoint * item.TimepointPrice; decimal timePointIn24HTotal = item.TimepointIn24H * item.TimepointIn24HPrice; decimal timePointIn48HTotal = item.TimepointIn48H * item.TimepointIn48HPrice; decimal adjudicationTotal = item.Adjudication * item.AdjudicationPrice; decimal adjudicationIn24HTotal = item.AdjudicationIn24H * item.AdjudicationIn24HPrice; decimal adjudicationIn48HTotal = item.AdjudicationIn48H * item.AdjudicationIn48HPrice; totalNormal += (trainingTotal + refresherTrainingTotal + downtimeTotal + globalTotal + timePointTotal + timePointIn24HTotal + timePointIn48HTotal + adjudicationTotal + adjudicationIn24HTotal + adjudicationIn48HTotal + ac1Total + ac2Total + ac3Total); #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 = "Additional Charge 1", Count = item.AdditionalCharge1, BasePrice = item.AdditionalCharge1Price, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 11, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.AdditionalCharge1 * item.AdditionalCharge1Price, PaymentCNY = item.AdditionalCharge1 * item.AdditionalCharge1Price * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Additional Charge 2", Count = item.AdditionalCharge2, BasePrice = item.AdditionalCharge2Price, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 12, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.AdditionalCharge2 * item.AdditionalCharge2Price, PaymentCNY = item.AdditionalCharge2 * item.AdditionalCharge2Price * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Additional Charge 3", Count = item.AdditionalCharge3, BasePrice = item.AdditionalCharge3Price, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 13, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.AdditionalCharge3 * item.AdditionalCharge3Price, PaymentCNY = item.AdditionalCharge3 * item.AdditionalCharge3Price * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Timepoint Regular", Count = item.Timepoint, BasePrice = item.TimepointPrice, PersonalAdditional =0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 4, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.Timepoint * item.TimepointPrice, PaymentCNY = item.Timepoint * item.TimepointPrice * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Timepoint 48-Hour", Count = item.TimepointIn48H, BasePrice = item.TimepointIn48HPrice, PersonalAdditional = 0, TrialAdditional = 0,//48小时不加项目附加 PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 5, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.TimepointIn48H * item.TimepointIn48HPrice, PaymentCNY = item.TimepointIn48H * item.TimepointIn48HPrice * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Timepoint 24-Hour", Count = item.TimepointIn24H, BasePrice = item.TimepointIn24HPrice, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 6, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.TimepointIn24H * item.TimepointIn24HPrice, PaymentCNY = item.TimepointIn24H * item.TimepointIn24HPrice * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Adjudication Regular", Count = item.Adjudication, BasePrice = item.AdjudicationPrice, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 7, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.Adjudication * item.AdjudicationPrice, PaymentCNY = item.Adjudication * item.AdjudicationPrice * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Adjudication 48-Hour", Count = item.AdjudicationIn48H, BasePrice = item.AdjudicationIn48HPrice, PersonalAdditional =0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 8, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.AdjudicationIn48H * item.AdjudicationIn48HPrice, PaymentCNY = item.AdjudicationIn48H * item.AdjudicationIn48HPrice * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Adjudication 24-Hour", Count = item.AdjudicationIn24H, BasePrice = item.AdjudicationIn24HPrice, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 9, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.AdjudicationIn24H * item.AdjudicationIn24HPrice, PaymentCNY = item.AdjudicationIn24H * item.AdjudicationIn24HPrice * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Global", Count = item.Global, BasePrice = item.GlobalPrice, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 10, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.Global * item.GlobalPrice, PaymentCNY = item.Global * item.GlobalPrice * exchangeRate }); #endregion } else { ++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; decimal ac1Total = item.AdditionalCharge1 * item.AdditionalCharge1Price; decimal ac2Total = item.AdditionalCharge2 * item.AdditionalCharge2Price; decimal ac3Total = item.AdditionalCharge3 * item.AdditionalCharge3Price; //规则定义 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 + ac1Total + ac2Total + ac3Total); #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 = "Additional Charge 1", Count = item.AdditionalCharge1, BasePrice = item.AdditionalCharge1Price, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 11, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.AdditionalCharge1 * item.AdditionalCharge1Price, PaymentCNY = item.AdditionalCharge1 * item.AdditionalCharge1Price * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Additional Charge 2", Count = item.AdditionalCharge2, BasePrice = item.AdditionalCharge2Price, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 12, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.AdditionalCharge2 * item.AdditionalCharge2Price, PaymentCNY = item.AdditionalCharge2 * item.AdditionalCharge2Price * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Additional Charge 3", Count = item.AdditionalCharge3, BasePrice = item.AdditionalCharge3Price, PersonalAdditional = 0, TrialAdditional = 0, PaymentId = Guid.Empty, DoctorId = item.DoctorId, TrialId = item.TrialId, ShowTypeOrder = 13, ShowCodeOrder = codeOrder, ExchangeRate = exchangeRate, YearMonth = yearMonth, PaymentUSD = item.AdditionalCharge3 * item.AdditionalCharge3Price, PaymentCNY = item.AdditionalCharge3 * item.AdditionalCharge3Price * exchangeRate }); paymentDetailList.Add(new PaymentDetailCommand { TrialCode = item.TrialCode, PaymentType = "Timepoint Regular", Count = item.Timepoint, BasePrice = item.TimepointPrice, PersonalAdditional = item.PersonalAdditional, TrialAdditional = 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 = item.PersonalAdditional, TrialAdditional = 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 = item.PersonalAdditional, TrialAdditional = 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 = item.PersonalAdditional, TrialAdditional = 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 = item.PersonalAdditional, TrialAdditional = 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 = item.PersonalAdditional, TrialAdditional = 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 = 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,//result.Data, 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 paymentyearMonth = new DateTime(param.CalculateMonth.Year, param.CalculateMonth.Month, 1).ToString("yyyy-MM"); var paymentModel = _paymentRepository.GetAll().FirstOrDefault(t => t.DoctorId == doctor && t.YearMonth == paymentyearMonth); // 计算金额为0 就不插入 if (totalUSD != 0 || paymentModel != null) { result = 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) { detail.PaymentId = result.Data; } AddOrUpdateMonthlyPaymentDetail(paymentDetailList, result.Data); } UpdatePaymentAdjustment(doctor, yearMonth); } return ResponseOutput.Ok(reviewerPaymentUSDList); } // 重新计算调整费用 private void UpdatePaymentAdjustment(Guid reviewerId,string yearMonth) { var adjustList = _payAdjustmentRepository.GetAll().Where(u => u.YearMonth == yearMonth && !u.IsLock&&u.ReviewerId==reviewerId).ToList(); 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) { _paymentRepository.Update(u => u.YearMonth == yearMonth && !u.IsLock && u.DoctorId == reviewer.ReviewerId, t => new Payment() { AdjustmentUSD = reviewer.AdjustUSD, AdjustmentCNY = reviewer.AdjustCNY }); } } /// /// 保存费用计算的月度数据 /// private IResponseOutput AddOrUpdateMonthlyPayment(PaymentCommand addOrUpdateModel) { var success = false; var paymentModel = _paymentRepository.GetAll().FirstOrDefault(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(addOrUpdateModel); //payment.BankTransferCNY = bankTransferCNY; //payment.TaxCNY= taxCNY; //payment.BankTransferCNY = bankTransferCNY; payment.YearMonthDate = DateTime.Parse(payment.YearMonth); var lastpayment = _paymentRepository.GetAll().Where(x => x.DoctorId == addOrUpdateModel.DoctorId && x.YearMonthDate == payment.YearMonthDate.AddMonths(-1)).FirstOrDefault(); payment.PaymentMethod = lastpayment == null ? PaymentMethod.CloudPayment : lastpayment.PaymentMethod; payment = _paymentRepository.Add(payment); success = _paymentRepository.SaveChanges(); return ResponseOutput.Result(success, payment.Id); } else { // 如果是 当月计算的工作量费用 和 调整费用都为0,则删除该行记录 if (addOrUpdateModel.PaymentUSD == 0 && paymentModel.AdjustmentUSD == 0) { success = _paymentRepository.Delete(u => u.Id == paymentModel.Id); //_paymentDetailRepository.Delete(u=>u.PaymentId==paymentModel.Id); } else { success = _paymentRepository.Update(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); } } /// /// 保存费用计算的月度详情 /// private bool AddOrUpdateMonthlyPaymentDetail(List addOrUpdateList, Guid paymentId) { //var paymentDetailIds = addOrUpdateList.Select(t => t.PaymentId).ToList(); _paymentDetailRepository.Delete(t => t.PaymentId == paymentId); _paymentDetailRepository.AddRange(_mapper.Map>(addOrUpdateList)); return _paymentDetailRepository.SaveChanges(); } /// /// 锁定某个月下的某些医生,医生费用结算后调用锁定 /// public IResponseOutput UpdateLockStatus(List reviewerIds, string yearMonth, bool isLock) { var paymentLockSuccess = _paymentRepository.Update(u => reviewerIds.Contains(u.DoctorId) && u.YearMonth == yearMonth, t => new Payment { IsLock = isLock }); var adjustmentLockSuccess = _payAdjustmentRepository.Update( t => t.YearMonth == yearMonth && reviewerIds.Contains(t.ReviewerId), u => new PaymentAdjustment() { IsLock = true }); _doctorWorkloadRepository.Update(u => reviewerIds.Contains(u.DoctorId) && u.YearMonth == yearMonth, t => new Workload { IsLock = true }); return ResponseOutput.Result(paymentLockSuccess || adjustmentLockSuccess); } /// /// 获取待计算费用的Reviewer对应的月份列表 /// public List GetNeedCalculateReviewerList(Guid reviewerId, string yearMonth) { Expression> calculateLambda = u => !u.IsLock; // u => u.IsLock==false && u.DataFrom==(int)WorkLoadFromStatus.FinalConfirm; Expression> workloadLambda = x=>true; if (reviewerId != Guid.Empty) { calculateLambda = calculateLambda.And(u => u.DoctorId == reviewerId); workloadLambda = workloadLambda.And(u => u.DoctorId == reviewerId); } if (!string.IsNullOrWhiteSpace(yearMonth)) { calculateLambda = calculateLambda.And(u => u.YearMonth == yearMonth); workloadLambda = workloadLambda.And(u => u.YearMonth == yearMonth); } var workloadlist = _doctorWorkloadRepository.GetAll().Where(workloadLambda) .Select(x => new CalculateNeededDTO() { DoctorId = x.DoctorId, YearMonth = x.YearMonth, IsLock = x.IsLock, DataFrom=x.DataFrom, }).Distinct().ToList(); var doctorIds = _enrollRepository.GetAll().Select(x => x.DoctorId).Distinct().ToList(); var doctorList = _doctorRepository.GetAll().Where(x=> doctorIds.Contains(x.Id)).Select(x => x.Id).ToList(); doctorList.ForEach(x => { if (!workloadlist.Any(y => y.DoctorId == x)&& yearMonth!=string.Empty) { workloadlist.Add(new CalculateNeededDTO() { DoctorId = x, IsLock = false, YearMonth = yearMonth, DataFrom= (int)WorkLoadFromStatus.FinalConfirm }); } }); workloadlist= workloadlist.Where(u=>u.IsLock == false && u.DataFrom == (int)WorkLoadFromStatus.FinalConfirm).Distinct().ToList(); return workloadlist; // return _paymentRepository.Find(calculateLambda).ProjectTo(_mapper.ConfigurationProvider).ToList(); } /// /// 查询Reviewer某个月的费用是否被锁定 /// public bool IsLock(Guid reviewerId, string yearMonth) { return _paymentRepository.GetAll().Any(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) //} } }