Commit c587198b by Neo Turing

优化

parent 04819511
......@@ -40,79 +40,90 @@ namespace Kivii.Finances
/// <summary>
/// Payment与Invoice产生关联的方法
/// </summary>
/// <param name="invoices"></param>
/// <param name="payments"></param>
/// <returns></returns>
public static List<Invoice> Correlating(this List<Invoice> invoices, List<Payment> payments)
/// <param name="invoices">要关联的发票列表</param>
/// <param name="payments">要关联的支付列表</param>
/// <param name="decimalPrecision">金额计算精度,默认为2</param>
/// <returns>生成的关联发票记录列表</returns>
public static List<Invoice> Correlating(this List<Invoice> invoices, List<Payment> payments, int decimalPrecision = 2)
{
payments.ThrowIfNullOrEmpty("要关联的Payments不能为空!");
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("请选择正确收款进行关联");
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>();
foreach (var payment in payments)
// 使用锁来确保并发安全
lock (typeof(InvoiceExtension))
{
//说明已经建立关联关系的payment 跳过
if (payment.AmountInvoice >= payment.Amount) continue;
foreach (var invoice in invoices)
foreach (var payment in payments)
{
var amountLeave = payment.Amount - payment.AmountInvoice;//可以开票的金额
if (amountLeave <= 0) break;
var amountCorrelating = invoice.Amount - invoice.AmountPayment;//要关联的金额
if (amountCorrelating <= 0) continue;
var amount = amountLeave <= amountCorrelating ? amountLeave : amountCorrelating;
//说明已经建立关联关系的payment 跳过
if (payment.AmountInvoice >= payment.Amount) continue;
foreach (var invoice in invoices)
{
var remainingPaymentAmount = Math.Round(payment.Amount - payment.AmountInvoice, decimalPrecision);//可以开票的金额
if (remainingPaymentAmount <= 0) break;
var remainingInvoiceAmount = Math.Round(invoice.Amount - invoice.AmountPayment, decimalPrecision);//要关联的金额
if (remainingInvoiceAmount <= 0) continue;
var allocatedAmount = remainingPaymentAmount <= remainingInvoiceAmount ? remainingPaymentAmount : remainingInvoiceAmount;
allocatedAmount = Math.Round(allocatedAmount, decimalPrecision); // 确保金额精度一致
invoice.PayedTime = payedTime;
invoice.AddOnlyProperties(o => o.PayedTime);
invoice.AmountPayment += amount;
invoice.AddOnlyProperties(o => o.AmountPayment);
invoice.PayedTime = paymentDateTime;
invoice.AddOnlyProperties(o => o.PayedTime);
invoice.AmountPayment = Math.Round(invoice.AmountPayment + allocatedAmount, decimalPrecision);
invoice.AddOnlyProperties(o => o.AmountPayment);
#region 建立关联关系
var relationInvoice = new Invoice();
relationInvoice.PopulateInstance(invoice);
relationInvoice.SerialNumber = string.Empty;
relationInvoice.Kvid = Guid.NewGuid();
relationInvoice.ParentKvid = invoice.Kvid;
#region 建立关联关系
var invoicePaymentRelation = new Invoice();
invoicePaymentRelation.PopulateInstance(invoice);
invoicePaymentRelation.SerialNumber = string.Empty;
invoicePaymentRelation.Kvid = Guid.NewGuid();
invoicePaymentRelation.ParentKvid = invoice.Kvid;
relationInvoice.BizId = payment.SerialNumber;
relationInvoice.BizKvid = payment.RootKvid;//记录根的Kvid
relationInvoice.BizType = typeof(Payment).FullName;
invoicePaymentRelation.BizId = payment.SerialNumber;
invoicePaymentRelation.BizKvid = payment.RootKvid;//记录根的Kvid
invoicePaymentRelation.BizType = typeof(Payment).FullName;
relationInvoice.Type = "Relation";
invoicePaymentRelation.Type = "Relation";
relationInvoice.PayedTime = payedTime;
relationInvoice.Amount = amount;
relationInvoice.AmountPayment = amount;
//不含税金额
relationInvoice.AmountUntaxed = Math.Round(relationInvoice.Amount / (1 + relationInvoice.TaxRate), 2);
//税
relationInvoice.AmountTax = relationInvoice.Amount - relationInvoice.AmountUntaxed;
relationInvoice.Summary = payment.PayerName;
rtns.Add(relationInvoice);
#endregion
invoicePaymentRelation.PayedTime = paymentDateTime;
invoicePaymentRelation.Amount = allocatedAmount;
invoicePaymentRelation.AmountPayment = allocatedAmount;
//不含税金额,统一使用指定精度
invoicePaymentRelation.AmountUntaxed = Math.Round(invoicePaymentRelation.Amount / (1 + invoicePaymentRelation.TaxRate), decimalPrecision);
//税额,确保税额 + 不含税金额 = 总金
invoicePaymentRelation.AmountTax = Math.Round(invoicePaymentRelation.Amount - invoicePaymentRelation.AmountUntaxed, decimalPrecision);
invoicePaymentRelation.Summary = payment.PayerName;
rtns.Add(invoicePaymentRelation);
#endregion
payment.AmountInvoice += amount;
if (payment.InvoiceTime == null)
{
payment.InvoiceTime = invoice.OperateTime;
payment.AddOnlyProperties(o => o.InvoiceTime);
}
else
{
if (payment.InvoiceTime.Value < invoice.OperateTime)
payment.AmountInvoice = Math.Round(payment.AmountInvoice + allocatedAmount, decimalPrecision);
if (payment.InvoiceTime == null)
{
payment.InvoiceTime = invoice.OperateTime;
payment.AddOnlyProperties(o => o.InvoiceTime);
}
else
{
if (payment.InvoiceTime.Value < invoice.OperateTime)
{
payment.InvoiceTime = invoice.OperateTime;
payment.AddOnlyProperties(o => o.InvoiceTime);
}
}
}
payment.AddOnlyProperties(o => o.AmountInvoice);
if (payment.Metadata.IsNullOrEmpty()) payment.Metadata = new Dictionary<string, string>();
payment.Metadata["InvoiceOperateTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");//记录关联发票的操作日期
payment.AddOnlyProperties(o => o.Metadata);
}
if (payment.Metadata == null) payment.Metadata = new Dictionary<string, string>();
payment.AddOnlyProperties(o => o.AmountInvoice);
if (payment.Metadata.IsNullOrEmpty()) payment.Metadata = new Dictionary<string, string>();
payment.Metadata["InvoiceOperateTiime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");//记录关联发票的操作日期
payment.AddOnlyProperties(o => o.Metadata);
}
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