using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Reflection; using System.Text; using UFIDA.U9.Base.PropertyTypes; using UFIDA.U9.CBO.UIHelper; using UFIDA.U9.FI.AR.ARMaintenanceUIModel; using UFSoft.UBF.UI.ControlModel; using UFSoft.UBF.UI.IView; using UFSoft.UBF.UI.WebControlAdapter; namespace UFIDA.U9.SH.LSUIPlugIn { /// /// 应收单 /// public class ARMainUIFormUIPlugIn : UFSoft.UBF.UI.Custom.ExtendedPartBase { private ARMainUIFormWebPart curPart = null; public override void AfterInit(IPart Part, EventArgs args) { base.AfterInit(Part, args); curPart = Part as ARMainUIFormWebPart; if (curPart == null) return; //实例化按钮 IUFButton btn1 = new UFWebButtonAdapter(); btn1.Text = "折扣分摊"; btn1.ID = "BtnDistributeDiscounts"; btn1.AutoPostBack = true; //加入Card容器 IUFCard card = (IUFCard)this.curPart.GetUFControlByName(this.curPart.TopLevelContainer, "Card0"); card.Controls.Add(btn1); Common.CommonFunction.Layout(card, btn1, 14, 0); //设置按钮事件 btn1.Click += new EventHandler(BtnDistributeDiscounts_Click); } private void BtnDistributeDiscounts_Click(object sender, EventArgs e) { var headRecord = curPart.Model.ARBillHead.FocusedRecord; if (headRecord == null || headRecord.DocStatus > 1) return; // 开立跟核准中才计算 curPart.DataCollect(); // 数据收集 if (string.IsNullOrEmpty(headRecord.DescFlexField_PrivateDescSeg17)) { curPart.CurrentSessionState["DiscountCalcMsg"] = $"表头私有段17s整单折扣金额为空,无法折扣分摊!"; return; } decimal.TryParse(headRecord.DescFlexField_PrivateDescSeg17, out decimal totalDisMoney); if (totalDisMoney != 0) { DistributeDiscounts(totalDisMoney, headRecord); } else { curPart.CurrentSessionState["DiscountCalcMsg"] = $"表头私有段17s整单折扣金额等于0,无法折扣分摊!"; } } private void DistributeDiscounts(decimal totalDiscount, ARBillHeadRecord headRecord) { var records = curPart.Model.ARBillHead_ARBillLines.Records; if (records.Count == 0) { curPart.CurrentSessionState["DiscountCalcMsg"] = $"没有明细可以用来进行折扣分摊!"; return; } // 核币金额精度 var ACMoney = new RoundHelper(headRecord.AC_MoneyRound_Precision, (RoundTypeEnumData)headRecord.AC_MoneyRound_RoundType, headRecord.AC_MoneyRound_RoundValue.GetValueOrDefault()); // 核币单价精度 var ACPrice = new RoundHelper(headRecord.AC_PriceRound_Precision, (RoundTypeEnumData)headRecord.AC_PriceRound_RoundType, headRecord.AC_PriceRound_RoundValue.GetValueOrDefault()); var lineRecords = records.Cast(); decimal totalAmount = 0; decimal taxPrice; decimal beforDisMoney; decimal ocMoneyPriceTaxSum; foreach (var lineRecord in lineRecords) { taxPrice = lineRecord.TaxPrice; // 含税单价 ocMoneyPriceTaxSum = lineRecord.AROCMoneyPriceTaxSum.GetValueOrDefault(); // 价税合计 decimal.TryParse(lineRecord.DescFlexField_PrivateDescSeg8, out decimal beforDisPrice); // 8s折扣前含税单价 if (lineRecord.FreeType == 0) { // 出货赠品,跳过 if (taxPrice == 0) continue; //// 出货不是赠品,应收行是赠品(具体表现为,8s折扣前含税单价来源于出货单行有值,但是应收单行勾选了赠品) //decimal.TryParse(lineRecord.DescFlexField_PrivateDescSeg6, out decimal disMoney0); // 6s折扣金额 //totalDiscount -= disMoney0; // 折扣总金额需要减去当前赠品行的折扣金额 //continue; } if (beforDisPrice == 0) { curPart.CurrentSessionState["DiscountCalcMsg"] = $"行:{lineRecord.LineNum},8s折扣前含税单价为空或0,无法进行折扣分摊!"; return; // 8s折扣前含税单价为0,不计算 } // 当前单价不等于[8s折扣前含税单价],根据[8s折扣前含税单价]进行价税合计还原 if (taxPrice != beforDisPrice) { // 根据[8s折扣前含税单价]进行价税合计还原 SetBatchPasteData(lineRecord, "TaxPrice", beforDisPrice + "", ACMoney, ACPrice, new List() { lineRecord.ID }, headRecord.IsTaxPrice, headRecord); } beforDisMoney = lineRecord.AROCMoneyPriceTaxSum.GetValueOrDefault(); // 价税合计必须大于0.01才能分摊 if (beforDisMoney > 0.01m) { lineRecord.DescFlexField_PrivateDescSeg3 = lineRecord.AROCMoney_TotalMoney.ToString(); // 3s折扣前价税合计 lineRecord.DescFlexField_PrivateDescSeg4 = lineRecord.AROCMoney_NonTax.ToString(); // 4s折扣前未税金额 lineRecord.DescFlexField_PrivateDescSeg5 = lineRecord.AROCMoney_GoodsTax.ToString(); // 5s折扣前税额 totalAmount += beforDisMoney; } if (taxPrice != beforDisPrice) { // 获取到正确的价税合计之后,需要按照原来的价税合计还原回去(按照单价还原可能存在单价未除尽的情况) SetBatchPasteData(lineRecord, "AROCMoneyPriceTaxSum", ocMoneyPriceTaxSum + "", ACMoney, ACPrice, new List() { lineRecord.ID }, headRecord.IsTaxPrice, headRecord); } } if (totalAmount == 0) { curPart.CurrentSessionState["DiscountCalcMsg"] = $"所有非赠品行的行明细价税合计之和等于0,无法进行折扣分摊!"; return; } if (Math.Abs(totalDiscount) >= Math.Abs(totalAmount)) { curPart.CurrentSessionState["DiscountCalcMsg"] = $"整单折扣金额必需小于所有非赠品行的明细行价税合计之和,才能进行折扣分摊!"; return; } // 累计折扣金额和 decimal accumulatedDiscount = 0; decimal disMoney = 0; // 遍历子实体计算折扣金额 List calcLineRecords = new List(); decimal rate; foreach (var lineRecord in lineRecords) { if (lineRecord.FreeType == 0) continue; // 赠品,跳过 // 计算当前子实体的折扣金额 taxPrice = lineRecord.TaxPrice; // 含税单价 decimal.TryParse(lineRecord.DescFlexField_PrivateDescSeg3, out beforDisMoney); // 3s折扣前价税合计 decimal.TryParse(lineRecord.DescFlexField_PrivateDescSeg8, out decimal beforDisPrice); // 8s折扣前含税单价 if (beforDisMoney <= 0.01m) continue; // 3s折扣前价税合计小于等于0.01,跳过(会导致价税合计=0) rate = beforDisMoney / totalAmount; disMoney = ACMoney.GetRoundValue(totalDiscount * rate); // 为0就给一分钱 if (disMoney == 0m) { if (beforDisMoney > 0) disMoney = 0.01m; else if ((beforDisMoney < 0)) disMoney = -0.01m; // 折扣前价税合计为负数,那就是负一分钱 } // 累计折扣金额 accumulatedDiscount += disMoney; lineRecord.DescFlexField_PrivateDescSeg6 = disMoney + ""; // 6s折扣金额 lineRecord.DescFlexField_PrivateDescSeg7 = Math.Round(taxPrice / beforDisPrice, 4) + ""; // 7s折扣率 ocMoneyPriceTaxSum = ACMoney.GetRoundValue(beforDisMoney - disMoney); // 价税合计 // 价税合计 SetBatchPasteData(lineRecord, "AROCMoneyPriceTaxSum", ocMoneyPriceTaxSum + "", ACMoney, ACPrice, new List() { lineRecord.ID }, headRecord.IsTaxPrice, headRecord); calcLineRecords.Add(lineRecord); } // 有尾差 if (totalDiscount - accumulatedDiscount != 0) { // 尾差分配给最后一个子实体 var lastLine = calcLineRecords.Last(); taxPrice = lastLine.TaxPrice; // 含税单价 decimal.TryParse(lastLine.DescFlexField_PrivateDescSeg8, out decimal beforDisPrice); // 8s折扣前含税单价 decimal.TryParse(lastLine.DescFlexField_PrivateDescSeg3, out beforDisMoney); // 3s折扣前价税合计 decimal.TryParse(lastLine.DescFlexField_PrivateDescSeg6, out decimal lstMny); // 6s折扣金额 disMoney = lstMny + (totalDiscount - accumulatedDiscount); lastLine.DescFlexField_PrivateDescSeg6 = disMoney + ""; lastLine.DescFlexField_PrivateDescSeg7 = Math.Round(taxPrice / beforDisPrice, 4) + ""; ocMoneyPriceTaxSum = ACMoney.GetRoundValue(beforDisMoney - disMoney); // 价税合计 SetBatchPasteData(lastLine, "AROCMoneyPriceTaxSum", ocMoneyPriceTaxSum + "", ACMoney, ACPrice, new List() { lastLine.ID }, headRecord.IsTaxPrice, headRecord); } // 重算本币金额 CalcFCMoneyFromACMoney(headRecord, true); // 分摊完直接保存 curPart.Action.SaveClick(null, null); curPart.CurrentSessionState["IsDiscountCalc"] = true; // 标记已经计算过了 curPart.CurrentSessionState["DiscountCalcMsg"] = $"折扣分摊成功,请核实折扣后金额是否准确!"; } public override void BeforeEventProcess(IPart Part, string eventName, object sender, EventArgs args, out bool executeDefault) { UFWebButton4ToolbarAdapter adapter = sender as UFWebButton4ToolbarAdapter; //监听事件 if ((adapter != null) && (adapter.Text == "保存")) { executeDefault = BeforeSave(Part); } base.BeforeEventProcess(Part, eventName, sender, args, out executeDefault); } public override void AfterRender(IPart Part, EventArgs args) { base.AfterRender(Part, args); curPart = Part as ARMainUIFormWebPart; if (curPart != null && curPart.CurrentSessionState.ContainsKey("DiscountCalcMsg")) { string msg = ""; if (curPart.CurrentSessionState["DiscountCalcMsg"] != null) { msg = curPart.CurrentSessionState["DiscountCalcMsg"]?.ToString(); } curPart.CurrentSessionState["DiscountCalcMsg"] = null; if (curPart.Model.ErrorMessage.hasErrorMessage) { return; } if (!string.IsNullOrEmpty(msg)) { var headRecord = curPart.Model.ARBillHead.FocusedRecord; if (headRecord.ID > 0) { msg = $"单号:{headRecord.DocNo},{msg}"; } curPart.ShowWindowStatus(msg, true); } } } private bool BeforeSave(IPart Part) { curPart = Part as ARMainUIFormWebPart; if (curPart == null) return true; if (curPart != null && curPart.CurrentSessionState.ContainsKey("IsDiscountCalc") && curPart.CurrentSessionState["IsDiscountCalc"] != null) { if ((bool)curPart.CurrentSessionState["IsDiscountCalc"]) { curPart.CurrentSessionState["IsDiscountCalc"] = null; return true; } } DiscountCalc(); return true; } /// /// 折扣计算 /// private void DiscountCalc() { var headRecord = curPart.Model.ARBillHead.FocusedRecord; if (headRecord == null || headRecord.DocStatus > 1) return; // 开立跟核准中才计算 curPart.DataCollect(); // 数据收集 // 核币金额精度 var ACMoney = new RoundHelper(headRecord.AC_MoneyRound_Precision, (RoundTypeEnumData)headRecord.AC_MoneyRound_RoundType, headRecord.AC_MoneyRound_RoundValue.GetValueOrDefault()); // 核币单价精度 var ACPrice = new RoundHelper(headRecord.AC_PriceRound_Precision, (RoundTypeEnumData)headRecord.AC_PriceRound_RoundType, headRecord.AC_PriceRound_RoundValue.GetValueOrDefault()); // 进行折扣计算的行号 List calcLineNums = new List(); foreach (ARBillHead_ARBillLinesRecord rec in curPart.Model.ARBillHead_ARBillLines.Records) { if (rec.DataRecordState == DataRowState.Deleted) continue; if (DiscountCalc(rec, headRecord, ACMoney, ACPrice)) { calcLineNums.Add(rec.LineNum); } } if (calcLineNums.Count > 0) { // 重算本币金额 CalcFCMoneyFromACMoney(headRecord, true); curPart.CurrentSessionState["DiscountCalcMsg"] = $"行:{string.Join(",", calcLineNums)},进行了折扣计算,请核实折扣后金额是否准确!"; // 直接保存 //curPart.Action.SaveClick(null, null); } } private bool DiscountCalc(ARBillHead_ARBillLinesRecord lineRecord, ARBillHeadRecord headRecord, RoundHelper ACMoney, RoundHelper ACPrice) { decimal.TryParse(lineRecord.DescFlexField_PrivateDescSeg8, out decimal beforDisPrice); // 8s折扣前含税单价 if (beforDisPrice == 0) return false; // 8s折扣前含税单价为0,不计算 bool lineIsAdd = lineRecord.ID <= 0; // 是否新增行 bool hasCalc = false; // 是否需要计算 bool isChangeDisMoney = false; // 是否改变6s折扣金额 bool isChangeDisTax = false; // 是否改变7s折扣率 decimal.TryParse(lineRecord.DescFlexField_PrivateDescSeg3, out decimal beforDisMoney); // 3s折扣前价税合计 decimal.TryParse(lineRecord.DescFlexField_PrivateDescSeg6, out decimal disMoney); // 6s折扣金额 decimal.TryParse(lineRecord.DescFlexField_PrivateDescSeg7, out decimal disTax); // 7s折扣率 decimal taxPrice = lineRecord.TaxPrice; // 含税单价 decimal amount = lineRecord.PUAmount.GetValueOrDefault(); // 数量 decimal ocMoneyPriceTaxSum = lineRecord.AROCMoneyPriceTaxSum.GetValueOrDefault(); // 价税合计 if (lineIsAdd) { isChangeDisMoney = disMoney != 0; isChangeDisTax = disTax > 0; } else { isChangeDisMoney = lineRecord.DescFlexField_PrivateDescSeg6 != lineRecord.OriginalValue["DescFlexField_PrivateDescSeg6"]?.ToString(); isChangeDisTax = lineRecord.DescFlexField_PrivateDescSeg7 != lineRecord.OriginalValue["DescFlexField_PrivateDescSeg7"]?.ToString(); } bool isRestoreByTaxPrice = false; decimal beforTotalMoney = ACMoney.GetRoundValue(amount * beforDisPrice); // 根据数量 * 8s折扣前含税单价 计算出来的折扣前价税合计 // 当前单价不等于[8s折扣前含税单价],根据[8s折扣前含税单价]进行价税合计还原 if (beforTotalMoney != beforDisMoney && taxPrice != beforDisPrice) { SetBatchPasteData(lineRecord, "TaxPrice", beforDisPrice + "", ACMoney, ACPrice, new List() { lineRecord.ID }, headRecord.IsTaxPrice, headRecord); isRestoreByTaxPrice = true; } if (isRestoreByTaxPrice) { // 还原后重新赋值[3s折扣前价税合计]、[4s折扣前未税金额]、[5s折扣前税额] beforDisMoney = lineRecord.AROCMoneyPriceTaxSum.GetValueOrDefault(); lineRecord.DescFlexField_PrivateDescSeg3 = lineRecord.AROCMoney_TotalMoney.ToString(); // 3s折扣前价税合计 lineRecord.DescFlexField_PrivateDescSeg4 = lineRecord.AROCMoney_NonTax.ToString(); // 4s折扣前未税金额 lineRecord.DescFlexField_PrivateDescSeg5 = lineRecord.AROCMoney_GoodsTax.ToString(); // 5s折扣前税额 } else if (string.IsNullOrEmpty(lineRecord.DescFlexField_PrivateDescSeg3) && taxPrice == beforDisPrice) { beforDisMoney = lineRecord.AROCMoneyPriceTaxSum.GetValueOrDefault(); lineRecord.DescFlexField_PrivateDescSeg3 = lineRecord.AROCMoney_TotalMoney.ToString(); // 3s折扣前价税合计 lineRecord.DescFlexField_PrivateDescSeg4 = lineRecord.AROCMoney_NonTax.ToString(); // 4s折扣前未税金额 lineRecord.DescFlexField_PrivateDescSeg5 = lineRecord.AROCMoney_GoodsTax.ToString(); // 5s折扣前税额 } if (isChangeDisMoney && disMoney != 0) { ocMoneyPriceTaxSum = ACMoney.GetRoundValue(beforDisMoney - disMoney); taxPrice = ocMoneyPriceTaxSum / amount; // 含税单价=(折扣前金额-6s折扣金额)/数量 disTax = Math.Round(taxPrice / beforDisPrice, 4); // 7s折扣率 = 含税单价/8s折扣前含税单价 hasCalc = true; } else if (isChangeDisTax && disTax > 0 && disTax <= 1) // 大于1的不是打折,小于0的白送钱 { disMoney = ACMoney.GetRoundValue((1 - disTax) * beforDisMoney); // 6s折扣金额=(1-7s折扣率)*折扣前金额 ocMoneyPriceTaxSum = ACMoney.GetRoundValue(beforDisMoney - disMoney); taxPrice = ocMoneyPriceTaxSum / amount; // 含税单价=(折扣前金额-6s折扣金额)/数量 hasCalc = true; } else { if (lineIsAdd) { // 行新增,如果是单价发生了变化,表示需要进行折扣 if (taxPrice != beforDisPrice) { disMoney = beforDisMoney - ocMoneyPriceTaxSum; // 6s折扣金额=折扣前金额-价税合计 disTax = Math.Round(taxPrice / beforDisPrice, 4); // 7s折扣率 = 含税单价/8s折扣前含税单价 hasCalc = true; } } else { // 假如当前[6s折扣金额]不等于[折扣前价税合计]-[当前价税合计],且[6s折扣金额][7s折扣率]没有变化 // 那就表示是数量、单价联动了价税合计变价,或者直接改变了价税合计 if (disMoney != beforDisMoney - ocMoneyPriceTaxSum) { disMoney = beforDisMoney - ocMoneyPriceTaxSum; // 6s折扣金额=折扣前金额-价税合计 disTax = Math.Round(taxPrice / beforDisPrice, 4); // 7s折扣率 = 含税单价/8s折扣前含税单价 hasCalc = true; } } } if (hasCalc) { lineRecord.DescFlexField_PrivateDescSeg6 = ACMoney.GetRoundValue(disMoney) + ""; lineRecord.DescFlexField_PrivateDescSeg7 = disTax + ""; // 价税合计 SetBatchPasteData(lineRecord, "AROCMoneyPriceTaxSum", ocMoneyPriceTaxSum + "", ACMoney, ACPrice, new List() { lineRecord.ID }, headRecord.IsTaxPrice, headRecord); } else if (isRestoreByTaxPrice) { // 没有进行折扣计算,需要按照原来的价税合计还原回去(按照单价还原可能存在单价未除尽的情况) SetBatchPasteData(lineRecord, "AROCMoneyPriceTaxSum", ocMoneyPriceTaxSum + "", ACMoney, ACPrice, new List() { lineRecord.ID }, headRecord.IsTaxPrice, headRecord); } return hasCalc; } /// /// 通过调用批量粘贴值的方法,达到值变化的目的 /// /// 粘贴的行 /// PUAmount、TaxPrice、NonTaxPrice、AROCMoney_NonTax、AROCMoneyPriceTaxSum、AROCMoney_GoodsTax /// 值 /// 核币金额精度 /// 核币单价精度 /// 要同步修改的行ID集合 /// 是否含税 /// 应收单头 private void SetBatchPasteData(ARBillHead_ARBillLinesRecord line, string srcColumnField, string Pastevalue, RoundHelper roundHelperACMoney, RoundHelper roundHelperACPrice, List modifiedLineIds, bool isTaxPrice, ARBillHeadRecord head) { // 获取类型 Type type = curPart.GetType(); // 定义参数类型数组 Type[] parameterTypes = new Type[] { typeof(ARBillHead_ARBillLinesRecord), typeof(string), typeof(string), typeof(RoundHelper), typeof(RoundHelper), typeof(List), typeof(bool), typeof(ARBillHeadRecord), typeof(AR.ARBill.ARItemInfoDTOData) }; // 获取方法信息 MethodInfo methodInfo = type.GetMethod("SetBatchPasteData", BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null); if (methodInfo == null) throw new Exception("SetBatchPasteData未找到"); // 调用方法,传递参数 methodInfo.Invoke(curPart, new object[] { line, srcColumnField, Pastevalue, roundHelperACMoney, roundHelperACPrice, modifiedLineIds, isTaxPrice, head, null }); } /// /// 根据核币金额计算本币金额 /// /// 应收单头 /// 是否重算全部行 private void CalcFCMoneyFromACMoney(ARBillHeadRecord head, bool allLineCalc) { // 获取类型 Type type = curPart.Action.GetType(); // 定义参数类型数组 Type[] parameterTypes = new Type[] { typeof(ARBillHeadRecord), typeof(bool) }; // 获取方法信息 MethodInfo methodInfo = type.GetMethod("CalcFCMoneyFromACMoney", BindingFlags.NonPublic | BindingFlags.Instance, null, parameterTypes, null); if (methodInfo == null) throw new Exception("CalcFCMoneyFromACMoney未找到"); // 调用方法,传递参数 methodInfo.Invoke(curPart.Action, new object[] { head, allLineCalc }); } } }