Commit c587198b by Neo Turing

优化

parent 04819511
...@@ -40,60 +40,71 @@ namespace Kivii.Finances ...@@ -40,60 +40,71 @@ namespace Kivii.Finances
/// <summary> /// <summary>
/// Payment与Invoice产生关联的方法 /// Payment与Invoice产生关联的方法
/// </summary> /// </summary>
/// <param name="invoices"></param> /// <param name="invoices">要关联的发票列表</param>
/// <param name="payments"></param> /// <param name="payments">要关联的支付列表</param>
/// <returns></returns> /// <param name="decimalPrecision">金额计算精度,默认为2</param>
public static List<Invoice> Correlating(this List<Invoice> invoices, List<Payment> payments) /// <returns>生成的关联发票记录列表</returns>
public static List<Invoice> Correlating(this List<Invoice> invoices, List<Payment> payments, int decimalPrecision = 2)
{ {
payments.ThrowIfNullOrEmpty("要关联的Payments不能为空!"); payments.ThrowIfNullOrEmpty("要关联的Payments不能为空!");
invoices.ThrowIfNullOrEmpty("要关联的Invoices不能为空!"); invoices.ThrowIfNullOrEmpty("要关联的Invoices不能为空!");
(payments.Exists(o => o.Type != PaymentType.Bank && o.Type != PaymentType.AliPay && o.Type != PaymentType.Cash && o.Type != PaymentType.Pos && o.Type != PaymentType.Split && o.Type != PaymentType.WeChat)).ThrowIfTrue("请选择正确收款进行关联"); (payments.Exists(o => o.Type != PaymentType.Bank && o.Type != PaymentType.AliPay && o.Type != PaymentType.Cash && o.Type != PaymentType.Pos && o.Type != PaymentType.Split && o.Type != PaymentType.WeChat)).ThrowIfTrue("请选择正确收款进行关联");
var payedTime = payments.Max(o => o.OperateTime);
// 检查货币类型是否一致
var paymentCurrencies = payments.Select(p => p.Currency).Distinct().ToList();
var invoiceCurrencies = invoices.Select(i => i.Currency).Distinct().ToList();
if (paymentCurrencies.Count > 1 || invoiceCurrencies.Count > 1) throw new InvalidOperationException("不同货币类型的支付或发票不能同时关联");
if (paymentCurrencies.FirstOrDefault() != invoiceCurrencies.FirstOrDefault()) throw new InvalidOperationException($"支付货币类型({paymentCurrencies.FirstOrDefault()})与发票货币类型({invoiceCurrencies.FirstOrDefault()})不匹配");
var paymentDateTime = payments.Max(o => o.OperateTime);
var rtns = new List<Invoice>(); var rtns = new List<Invoice>();
// 使用锁来确保并发安全
lock (typeof(InvoiceExtension))
{
foreach (var payment in payments) foreach (var payment in payments)
{ {
//说明已经建立关联关系的payment 跳过 //说明已经建立关联关系的payment 跳过
if (payment.AmountInvoice >= payment.Amount) continue; if (payment.AmountInvoice >= payment.Amount) continue;
foreach (var invoice in invoices) foreach (var invoice in invoices)
{ {
var amountLeave = payment.Amount - payment.AmountInvoice;//可以开票的金额 var remainingPaymentAmount = Math.Round(payment.Amount - payment.AmountInvoice, decimalPrecision);//可以开票的金额
if (amountLeave <= 0) break; if (remainingPaymentAmount <= 0) break;
var amountCorrelating = invoice.Amount - invoice.AmountPayment;//要关联的金额 var remainingInvoiceAmount = Math.Round(invoice.Amount - invoice.AmountPayment, decimalPrecision);//要关联的金额
if (amountCorrelating <= 0) continue; if (remainingInvoiceAmount <= 0) continue;
var amount = amountLeave <= amountCorrelating ? amountLeave : amountCorrelating; var allocatedAmount = remainingPaymentAmount <= remainingInvoiceAmount ? remainingPaymentAmount : remainingInvoiceAmount;
allocatedAmount = Math.Round(allocatedAmount, decimalPrecision); // 确保金额精度一致
invoice.PayedTime = payedTime; invoice.PayedTime = paymentDateTime;
invoice.AddOnlyProperties(o => o.PayedTime); invoice.AddOnlyProperties(o => o.PayedTime);
invoice.AmountPayment += amount; invoice.AmountPayment = Math.Round(invoice.AmountPayment + allocatedAmount, decimalPrecision);
invoice.AddOnlyProperties(o => o.AmountPayment); invoice.AddOnlyProperties(o => o.AmountPayment);
#region 建立关联关系 #region 建立关联关系
var relationInvoice = new Invoice(); var invoicePaymentRelation = new Invoice();
relationInvoice.PopulateInstance(invoice); invoicePaymentRelation.PopulateInstance(invoice);
relationInvoice.SerialNumber = string.Empty; invoicePaymentRelation.SerialNumber = string.Empty;
relationInvoice.Kvid = Guid.NewGuid(); invoicePaymentRelation.Kvid = Guid.NewGuid();
relationInvoice.ParentKvid = invoice.Kvid; invoicePaymentRelation.ParentKvid = invoice.Kvid;
relationInvoice.BizId = payment.SerialNumber; invoicePaymentRelation.BizId = payment.SerialNumber;
relationInvoice.BizKvid = payment.RootKvid;//记录根的Kvid invoicePaymentRelation.BizKvid = payment.RootKvid;//记录根的Kvid
relationInvoice.BizType = typeof(Payment).FullName; invoicePaymentRelation.BizType = typeof(Payment).FullName;
relationInvoice.Type = "Relation"; invoicePaymentRelation.Type = "Relation";
relationInvoice.PayedTime = payedTime; invoicePaymentRelation.PayedTime = paymentDateTime;
relationInvoice.Amount = amount; invoicePaymentRelation.Amount = allocatedAmount;
relationInvoice.AmountPayment = amount; invoicePaymentRelation.AmountPayment = allocatedAmount;
//不含税金额 //不含税金额,统一使用指定精度
relationInvoice.AmountUntaxed = Math.Round(relationInvoice.Amount / (1 + relationInvoice.TaxRate), 2); invoicePaymentRelation.AmountUntaxed = Math.Round(invoicePaymentRelation.Amount / (1 + invoicePaymentRelation.TaxRate), decimalPrecision);
//税 //税额,确保税额 + 不含税金额 = 总金
relationInvoice.AmountTax = relationInvoice.Amount - relationInvoice.AmountUntaxed; invoicePaymentRelation.AmountTax = Math.Round(invoicePaymentRelation.Amount - invoicePaymentRelation.AmountUntaxed, decimalPrecision);
relationInvoice.Summary = payment.PayerName; invoicePaymentRelation.Summary = payment.PayerName;
rtns.Add(relationInvoice); rtns.Add(invoicePaymentRelation);
#endregion #endregion
payment.AmountInvoice += amount; payment.AmountInvoice = Math.Round(payment.AmountInvoice + allocatedAmount, decimalPrecision);
if (payment.InvoiceTime == null) if (payment.InvoiceTime == null)
{ {
payment.InvoiceTime = invoice.OperateTime; payment.InvoiceTime = invoice.OperateTime;
...@@ -108,12 +119,12 @@ namespace Kivii.Finances ...@@ -108,12 +119,12 @@ namespace Kivii.Finances
} }
} }
} }
if (payment.Metadata == null) payment.Metadata = new Dictionary<string, string>();
payment.AddOnlyProperties(o => o.AmountInvoice); payment.AddOnlyProperties(o => o.AmountInvoice);
if (payment.Metadata.IsNullOrEmpty()) payment.Metadata = new Dictionary<string, string>(); if (payment.Metadata.IsNullOrEmpty()) payment.Metadata = new Dictionary<string, string>();
payment.Metadata["InvoiceOperateTiime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");//记录关联发票的操作日期 payment.Metadata["InvoiceOperateTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");//记录关联发票的操作日期
payment.AddOnlyProperties(o => o.Metadata); payment.AddOnlyProperties(o => o.Metadata);
} }
}
return rtns; return rtns;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment