Commit 40c38680 by Neo Turing

增加发票申请及流程审批,发票关联到账等功能

parent c63f4bf2
...@@ -4,3 +4,4 @@ ...@@ -4,3 +4,4 @@
/.vs /.vs
/Src/obj /Src/obj
/Src/bin/Debug
using Kivii.Finances.Entities;
using Kivii.Linq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kivii.Finances
{
public static class ApplyExtension
{
public static void ExcuteCompleted(this List<InvoiceApply> allApplys, IDbConnection conn = null)
{
if (allApplys.IsNullOrEmpty()) return;
var applys = allApplys.Where(o => o.AmountInvoice < o.Amount).ToList();
if (applys.IsNullOrEmpty()) return;
var applyKvids = applys.ConvertAll(p => p.Kvid);
bool useTransaction = conn == null;//是否启用事务,如果外部未传入conn,启用内部事务
if (conn == null) conn = KiviiContext.GetOpenedDbConnection<InvoiceApply>();
var queryInvoices = conn.From<Invoice>();
queryInvoices.Where(o => o.OffsetKvid == Guid.Empty && o.RootKvid == o.Kvid && Sql.In(o.ApplyKvid, applyKvids));
queryInvoices.Select(o => new { o.Kvid, o.Amount, o.ApplyKvid });
var invoices = conn.Select(queryInvoices);
if (invoices.IsNullOrEmpty()) return;
var relations = conn.Select<InvoiceApply>(o => o.OffsetKvid == Guid.Empty && o.OperateType == InvoiceApplyType.Related && Sql.In(o.ParentKvid, applyKvids));
List<InvoiceApply> preUpdates = new List<InvoiceApply>();
foreach (var apply in applys)
{
if (apply.AmountInvoice == apply.Amount) continue;
var currentInvoices = invoices.Where(o => o.ApplyKvid == apply.Kvid).ToList();
if (currentInvoices.IsNullOrEmpty()) continue;
var amountSum = currentInvoices.Sum(o => o.Amount);
List<InvoiceApply> applyRelations = null;
if (!relations.IsNullOrEmpty()) applyRelations = relations.Where(o => o.ParentKvid == apply.Kvid).ToList();
if (amountSum != apply.Amount) throw new Exception($"{apply.PayerName}:发票金额{currentInvoices.Sum(o => o.Amount)}和申请金额{apply.Amount}不一致");
apply.AmountInvoice = amountSum;
apply.AddOnlyProperties(o => o.AmountInvoice);
if (apply.AmountInvoice == apply.Amount)
{
apply.Status = (int)InvoiceApplyStatus.Completed;
apply.AddOnlyProperties(o => o.Status);
}
preUpdates.Add(apply);
if (!applyRelations.IsNullOrEmpty())
{
foreach (var item in applyRelations)
{
item.AmountInvoice = item.Amount;
item.AddOnlyProperties(o => o.AmountInvoice);
if (item.AmountInvoice == item.Amount)
{
item.Status = (int)InvoiceApplyStatus.Completed;
item.AddOnlyProperties(o => o.Status);
}
preUpdates.Add(item);
}
}
}
if (preUpdates.IsNullOrEmpty()) return;
IDbTransaction trans = null;//事务,如果外部来了Connection,不生成事务
if (useTransaction) trans = conn.OpenTransaction();
try
{
if (!preUpdates.IsNullOrEmpty())
{
foreach (var item in preUpdates)
{
if (!item.OnlyProperties.IsNullOrEmpty()) conn.UpdateOnly(item);
}
}
trans?.Commit();
}
catch (Exception ex)
{
trans?.Rollback();
throw ex;
}
}
}
}
...@@ -59,11 +59,13 @@ ...@@ -59,11 +59,13 @@
<Compile Include="Entities\InvoiceDetail.cs" /> <Compile Include="Entities\InvoiceDetail.cs" />
<Compile Include="Entities\InvoiceTitle.cs" /> <Compile Include="Entities\InvoiceTitle.cs" />
<Compile Include="Entities\Payment.cs" /> <Compile Include="Entities\Payment.cs" />
<Compile Include="Extensions\ApplyExtension.cs" />
<Compile Include="Extensions\Extension.cs" /> <Compile Include="Extensions\Extension.cs" />
<Compile Include="Extensions\InvoiceExtension.cs" /> <Compile Include="Extensions\InvoiceExtension.cs" />
<Compile Include="Extensions\PaymentExtension.cs" /> <Compile Include="Extensions\PaymentExtension.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Transforms\RestfulAccount.cs" /> <Compile Include="Transforms\RestfulAccount.cs" />
<Compile Include="Transforms\RestfulApply.cs" />
<Compile Include="Transforms\RestfulInvoice.cs" /> <Compile Include="Transforms\RestfulInvoice.cs" />
<Compile Include="Transforms\RestfulInvoiceDetail.cs" /> <Compile Include="Transforms\RestfulInvoiceDetail.cs" />
<Compile Include="Transforms\RestfulInvoiceTitle.cs" /> <Compile Include="Transforms\RestfulInvoiceTitle.cs" />
......
...@@ -37,5 +37,5 @@ using System.Runtime.InteropServices; ...@@ -37,5 +37,5 @@ using System.Runtime.InteropServices;
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示: //通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")] // [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("5.4.2025.5070")] [assembly: AssemblyVersion("5.4.2025.5220")]
[assembly: AssemblyFileVersion("5.4.2025.5070")] [assembly: AssemblyFileVersion("5.4.2025.5220")]
using Kivii.Finances.Entities;
using Kivii.Linq;
using Kivii.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kivii.Finances.Transforms
{
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyQuery : RestfulExecution<InvoiceApply>
{
#region QueryArgs
public virtual int? Skip { get; set; }
public virtual int? Take { get; set; }
public virtual string OrderBy { get; set; }
public string OrderByDesc { get; set; }
public virtual string Include { get; set; }
public virtual string Fields { get; set; }
public string QueryKeys { get; set; }
public string QueryValues { get; set; }
#endregion
public DateTime BeginTime { get; set; }
public DateTime EndTime { get; set; }
public override object OnExecution(IRequest req, IResponse res)
{
if (EndTime < BeginTime) throw new Exception("查询结束日期不可小于开始日期!");
var conn = KiviiContext.GetOpenedDbConnection<InvoiceApply>();
var dynamicParams = Request.GetRequestParams();
var autoQuery = Request.TryResolve<IAutoQueryDb>();
autoQuery.IncludeTotal = true;
var request = new RestfulQuery<InvoiceApply>();
request = request.PopulateWith(this);
var sqlExpress = autoQuery.CreateQuery(Request, conn, request, dynamicParams);
sqlExpress.Where(o => o.OperateType != InvoiceApplyType.Related);
if (BeginTime != DateTime.MinValue) sqlExpress.Where(o => o.OperateTime >= BeginTime);
if (EndTime != DateTime.MinValue) sqlExpress.And(o => o.OperateTime < EndTime);
var rtns = autoQuery.Execute(Request, conn, request, sqlExpress);
return rtns;
}
}
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyRead : RestfulRead<InvoiceApply>
{
}
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyUpdate : RestfulUpdate<InvoiceApply>
{
}
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyDelete : RestfulDelete<InvoiceApply>
{
}
#region 申请开票相关
[Api(Description = "开票申请")]
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyApply : RestfulExecution<InvoiceApply>
{
public InvoiceApply Item { get; set; }
public List<Guid> PaymentKvids { get; set; }
//发票开具最大额度限制 默认10万
public decimal Limit { get; set; } = 100000;
public override object OnExecution(IRequest req, IResponse res)
{
Item.ThrowIfNull("请传入要申请的内容!");
if (Item.PayerName.IsNullOrEmpty()) throw new Exception("请输入发票抬头!");
if (Item.Currency == CurrencyUnit.Unsupported) throw new Exception("不支持的货币单位!");
if (Item.Amount <= 0) throw new Exception("申请金额不能小于0!");
if (Item.Details.IsNullOrEmpty()) throw new Exception("请传入申请明细!");
if (Item.Amount != Item.Details.Sum(o => o.Amount)) throw new Exception("总金额和明细总额不一致!");
if (Item.Details.Exists(o => o.GoodsFullName.IsNullOrEmpty())) throw new Exception("明细名称存在空值!");
if (Item.Details.Exists(o => o.TaxRate < 0) || Item.Details.Exists(o => o.TaxRate > 1)) throw new Exception("存在明细税率设置范围不在0-1之间!");
if (Item.Details.Exists(o => o.Quantity <= 0)) throw new Exception("请填写数量!");
if (Item.Details.Count > 1)
{
var group = Item.Details.GroupBy(o => o.GoodsId);
foreach (var kv in group)
{
var sum = kv.Sum(o => o.Amount);
if (sum > Limit) throw new Exception($"组别:{kv.Key},总额:{sum}元,金额总和不能超过限额{Limit}元!");
}
}
if (Item.OperateType != InvoiceApplyType.Debit) PaymentKvids.ThrowIfNullOrEmpty("请先选择相应收款!");
//申请人为当前登录人
Item.OperatorName = KiviiContext.CurrentMember.FullName;
Item.OperatorKvid = KiviiContext.CurrentMember.Kvid;
//申请所属部门
Item.OwnerKvid = KiviiContext.CurrentMember.DepartmentKvid;
Item.OwnerName = KiviiContext.CurrentMember.DepartmentName;
#region 计算(不根据前端传来)
foreach (var detail in Item.Details)
{
detail.AmountUntaxed = Math.Round(detail.Amount / (1 + detail.TaxRate), 2);
detail.AmountTax = detail.Amount - detail.AmountUntaxed;
detail.QuantityUnitPriceUntaxed = Math.Round(detail.AmountUntaxed / detail.Quantity, 2);
detail.QuantityUnitPrice = Math.Round(detail.Amount / detail.Quantity, 2);
}
#endregion
var rtns = new RestfulQueryResponse<InvoiceApply>();
rtns.Results = new List<InvoiceApply>();
var conn = KiviiContext.GetOpenedDbConnection<InvoiceApply>();
if (Item.OperateType == InvoiceApplyType.Debit)
{
var trans = conn.OpenTransaction();
try
{
var applyKvid = Guid.NewGuid();
foreach (var detail in Item.Details)
{
detail.ApplyKvid = applyKvid;
conn.Insert(detail);
}
Item.RootKvid = applyKvid;
Item.ParentKvid = Guid.Empty;
//Item.AmountUsed = 0;
Item.OperateTime = DateTime.Now;
Item.Status = (int)InvoiceApplyStatus.FinancialExecute;
Item.Kvid = applyKvid;
conn.Insert(Item);
rtns.Results.Add(Item);
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}
else
{
var paymentKvidsDistinct = PaymentKvids.Distinct().ToList();
var payments = conn.Select<Payment>(o => Sql.In(o.Kvid, paymentKvidsDistinct));
(payments.Count <= 0 || payments.Count != paymentKvidsDistinct.Count).ThrowIfTrue("收款信息与所选项目不一致!");
(payments.Exists(o => o.Type != PaymentType.Bank && o.Type != PaymentType.Split && o.Type != PaymentType.AliPay && o.Type != PaymentType.Pos && o.Type != PaymentType.WeChat && o.Type != PaymentType.Cash)).ThrowIfTrue("请选择正确的收款信息进行申请!");
(payments.Exists(o => o.Amount <= o.AmountInvoice)).ThrowIfTrue("存在已开票的到账!无法重复申请!");
if (Item.Amount != payments.Sum(o => o.Amount - o.AmountInvoice)) throw new Exception("申请金额与所选到账金额不一致!");
var paymentKvids = payments.ConvertAll(o => o.Kvid);
(conn.Exists<InvoiceApply>(o => o.OperateType == InvoiceApplyType.Related && o.OffsetKvid == Guid.Empty && Sql.In(o.BizKvid, paymentKvids))).ThrowIfTrue("已有申请开票中的到账!");
var trans = conn.OpenTransaction();
try
{
var applyKvid = Guid.NewGuid();
foreach (var detail in Item.Details)
{
detail.ApplyKvid = applyKvid;
conn.Insert(detail);
}
Item.RootKvid = applyKvid;
Item.ParentKvid = Guid.Empty;
//Item.AmountUsed = Item.Amount;
Item.OperateTime = DateTime.Now;
Item.Status = (int)InvoiceApplyStatus.FinancialExecute;
Item.Kvid = applyKvid;
conn.Insert(Item);
rtns.Results.Add(Item);
foreach (var item in payments)
{
var relation = new InvoiceApply();
relation.PopulateWith(Item);
relation.BizId = item.SerialNumber;
relation.BizKvid = item.Kvid;
relation.BizType = typeof(Payment).FullName;
relation.Kvid = Guid.NewGuid();
relation.RootKvid = applyKvid;
relation.ParentKvid = applyKvid;
relation.SerialNumber = string.Empty;
relation.OperateType = InvoiceApplyType.Related;
relation.Type = Item.OperateType.ToString();
relation.Amount = item.Amount - item.AmountInvoice;
relation.OperatorName = KiviiContext.CurrentMember.FullName;
relation.OperatorKvid = KiviiContext.CurrentMember.Kvid;
relation.AmountInvoice = 0;
//relation.AmountUsed = relation.Amount;
conn.Insert(relation);
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
}
rtns.Total = rtns.Results.Count();
return rtns;
}
}
[Api(Description = "批量借票申请")]
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyMultiApply : RestfulExecution<InvoiceApply>
{
public InvoiceApply Item { get; set; }
public List<InvoiceApply> Items { get; set; }
public override object OnExecution(IRequest req, IResponse res)
{
(Item == null && Items.IsNullOrEmpty()).ThrowIfTrue("请传入要借票信息!");
if (Items.IsNullOrEmpty()) Items = new List<InvoiceApply>();
if (Item != null) Items.Add(Item);
if (Items.Exists(o => o.PayerName.IsNullOrEmpty())) throw new Exception("存在发票抬头为空!");
if (Items.Exists(o => o.PayerTaxNumber.IsNullOrEmpty())) throw new Exception("存在税号为空!");
if (Items.Exists(o => o.Currency == CurrencyUnit.Unsupported)) throw new Exception("存在不支持的货币单位!");
if (Items.Exists(o => o.Amount <= 0)) throw new Exception("申请金额不能小于0!");
if (Items.Exists(o => o.OperateType != InvoiceApplyType.Debit)) throw new Exception("此接口仅针对借票申请开票!");
var rtns = new RestfulQueryResponse<InvoiceApply>();
rtns.Results = new List<InvoiceApply>();
var conn = KiviiContext.GetOpenedDbConnection<InvoiceApply>();
foreach (var item in Items)
{
#region 创建借票申请
var applyKvid = Guid.NewGuid();
item.OperateType = InvoiceApplyType.Debit;
//申请人为当前登录人
item.OperatorName = KiviiContext.CurrentMember.FullName;
item.OperatorKvid = KiviiContext.CurrentMember.Kvid;
//申请所属部门
item.OwnerKvid = KiviiContext.CurrentMember.DepartmentKvid;
item.OwnerName = KiviiContext.CurrentMember.DepartmentName;
item.RootKvid = applyKvid;
item.ParentKvid = Guid.Empty;
//item.AmountUsed = 0;
item.OperateTime = DateTime.Now;
item.Status = (int)InvoiceApplyStatus.FinancialApproval;
item.Kvid = applyKvid;
conn.Insert(item);
#endregion
rtns.Results.Add(item);
}
rtns.Total = rtns.Results.Count();
return rtns;
}
}
#endregion
#region 审批过程
/// <summary>
/// 财务通过申请
/// </summary>
[Api(Description = "财务审批申请开票通过")]
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyAgree : RestfulExecution<InvoiceApply>
{
public List<Guid> ApplyKvids { get; set; }
public override object OnExecution(IRequest req, IResponse res)
{
var rtns = new List<InvoiceApply>();
var conn = KiviiContext.GetOpenedDbConnection<InvoiceApply>();
var applys = conn.Select<InvoiceApply>(o => Sql.In(o.Kvid, ApplyKvids));
if (applys == null) throw new Exception("无相关申请!");
foreach (var item in applys)
{
if (item.Status >= (int)InvoiceApplyStatus.FinancialApproval) continue;
//流程还未走完的申请跳过
if (item.Status < (int)InvoiceApplyStatus.ProcessAdoption) continue;
item.Status = (int)InvoiceApplyStatus.FinancialApproval;
item.AddOnlyProperties(o => o.Status);
conn.UpdateOnly(item);
item.RemoveAllOnlyProperties();
rtns.Add(item);
}
return new RestfulUpdateResponse<InvoiceApply>
{
Results = rtns
};
}
}
[Api(Description = "申请驳回")]
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyReject : RestfulExecution<InvoiceApply>
{
public List<Guid> ApplyKvids { get; set; }
public string Summary { get; set; }
public override object OnExecution(IRequest req, IResponse res)
{
var conn = KiviiContext.GetOpenedDbConnection<InvoiceApply>();
var applys = conn.Select<InvoiceApply>(o => Sql.In(o.Kvid, ApplyKvids) && o.OperateType != InvoiceApplyType.Related);
if (applys == null) throw new Exception("无相关申请!");
var applyRelations = conn.Select<InvoiceApply>(o => Sql.In(o.ParentKvid, applys.ConvertAll(p => p.Kvid)) && o.OperateType == InvoiceApplyType.Related);
var rtns = new RestfulExecutionResponse<InvoiceApply>();
rtns.Results = new List<InvoiceApply>();
var trans = conn.OpenTransaction();
try
{
foreach (var apply in applys)
{
#region apply驳回
//进入开票状态后不可驳回
(apply.Status > (int)InvoiceApplyStatus.FinancialExecute).ThrowIfTrue("撤销失败,当前申请已进入开票列队或已完成开票!");
apply.Status = (int)InvoiceApplyStatus.ApplyReject;
apply.AddOnlyProperties(o => o.Status);
//apply.AmountUsed = 0;
//apply.AddOnlyProperties(o => o.AmountUsed);
apply.Summary += " (驳回原因:" + Summary + ")";
apply.AddOnlyProperties(o => o.Summary);
conn.UpdateOnly(apply);
apply.RemoveAllOnlyProperties();
rtns.Results.Add(apply);
if (applyRelations.IsNullOrEmpty()) continue;
var relations = applyRelations.Where(o => o.ParentKvid == apply.Kvid).ToList();
if (relations.IsNullOrEmpty()) continue;
#endregion
#region 关联apply 删除
foreach (var item in relations)
{
item.Status = -1;
item.AddOnlyProperties(o => o.Status);
conn.UpdateOnly(item);
}
#endregion
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
return rtns;
}
}
[Api(Description = "执行开票")]
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyExecute : RestfulExecution<InvoiceApply>
{
public Guid Kvid { get; set; }
public List<Guid> Kvids { get; set; }
public override object OnExecution(IRequest req, IResponse res)
{
(Kvid == Guid.Empty && Kvids.IsNullOrEmpty()).ThrowIfTrue("Need Kvid Or Kvids!");
if (Kvids.IsNullOrEmpty()) Kvids = new List<Guid>();
if (Kvid != Guid.Empty) Kvids.Add(Kvid);
if (Kvids.IsNullOrEmpty()) throw new Exception("请先选择申请条目!");
var conn = KiviiContext.GetOpenedDbConnection<InvoiceApply>();
var applys = conn.SelectByIds<InvoiceApply>(Kvids);
if (applys.IsNullOrEmpty()) throw new Exception("不存在的申请!");
(applys.Exists(o => o.OperateType == InvoiceApplyType.Related)).ThrowIfTrue("申请类型不正确!");
if (applys.Exists(o => o.Status >= (int)InvoiceApplyStatus.FinancialExecute)) throw new Exception("请勿重复申请开票!");
if (applys.Exists(o => o.Status < (int)InvoiceApplyStatus.ProcessAdoption)) throw new Exception("此申请还在审批中...");
var existDetails = conn.Select<InvoiceApplyDetail>(o => Sql.In(o.ApplyKvid, applys.ConvertAll(p => p.Kvid)));
existDetails.ThrowIfNullOrEmpty("未查到相关申请明细!");
if (applys.Sum(o => o.Amount) != existDetails.Sum(p => p.Amount)) throw new Exception("总金额和明细总额不一致!");
var applyRelations = conn.Select<InvoiceApply>(o => Sql.In(o.ParentKvid, applys.ConvertAll(p => p.Kvid)) && o.OperateType == InvoiceApplyType.Related && o.OffsetKvid == Guid.Empty);
var payments = conn.Select<Payment>(o => Sql.In(o.Kvid, applyRelations.ConvertAll(p => p.BizKvid)));//Type:Split,Pos,Cash,WeChat...
(conn.Exists<Invoice>(o => o.OffsetKvid == Guid.Empty && Sql.In(o.BizKvid, payments.ConvertAll(p => p.RootKvid)))).ThrowIfTrue("已有开票的到账,无法重复开票,请驳回!");
var rtns = new RestfulExecutionResponse<InvoiceApply>();
rtns.Results = new List<InvoiceApply>();
var trans = conn.OpenTransaction();
try
{
#region 申请状态进入开票状态
foreach (var item in applys)
{
item.Status = (int)InvoiceApplyStatus.FinancialExecute;
item.AddOnlyProperties(o => o.Status);
conn.UpdateOnly(item);
rtns.Results.Add(item);
}
#endregion
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
return rtns;
}
}
#endregion
[Api(Description = "录入发票结果")]
[RequiresAnyRole(MemberRoles.Everyone)]
public class InvoiceApplyExcuteResult : RestfulExecution<InvoiceApply>
{
public List<Invoice> Invoices { get; set; }
public override object OnExecution(IRequest req, IResponse res)
{
Invoices.ThrowIfNullOrEmpty("请传入发票信息");
Invoices.Exists(o => o.ApplyKvid == Guid.Empty).ThrowIfTrue("缺少申请信息");
var applyKvids = Invoices.ConvertAll(o => o.ApplyKvid).Distinct().ToList();
var conn = KiviiContext.GetOpenedDbConnection<InvoiceApply>();
var applys = conn.SelectByIds<InvoiceApply>(applyKvids);
applys.ThrowIfNullOrEmpty("未找到对应申请信息");
applys.Exists(o => o.OperateType == InvoiceApplyType.Related).ThrowIfTrue("申请信息错误");
applys.Exists(o => o.Status < (int)InvoiceApplyStatus.ProcessAdoption).ThrowIfTrue("此申请还在审批中");
(applys.Count != applyKvids.Count).ThrowIfTrue("申请与发票对应数量不一致");
var relations = conn.Select<InvoiceApply>(o => Sql.In(o.ParentKvid, applyKvids) && o.OperateType == InvoiceApplyType.Related && o.OffsetKvid == Guid.Empty);
var existDetails = conn.Select<InvoiceApplyDetail>(o => Sql.In(o.ApplyKvid, applyKvids));
var rtns = new RestfulUpdateResponse<InvoiceApply>();
rtns.Results = new List<InvoiceApply>();
var trans = conn.OpenTransaction();
try
{
foreach (var apply in applys)
{
List<InvoiceApply> applyRelations = null;
List<InvoiceApplyDetail> applyDetails = null;
if (!relations.IsNullOrEmpty()) applyRelations = relations.Where(o => o.ParentKvid == apply.Kvid).ToList();
if (!existDetails.IsNullOrEmpty()) applyDetails = existDetails.Where(o => o.ApplyKvid == apply.Kvid).ToList();
var currentInvoices = Invoices.Where(o => o.ApplyKvid == apply.Kvid).ToList();
if (currentInvoices.IsNullOrEmpty()) continue;
if (currentInvoices.Sum(o => o.Amount) != apply.Amount) throw new Exception($"{apply.PayerName}:发票金额{currentInvoices.Sum(o => o.Amount)}和申请金额{apply.Amount}不一致");
#region 处理申请明细
if (!existDetails.IsNullOrEmpty())
{
foreach (var exist in existDetails)
{
exist.Status = -1;
exist.AddOnlyProperties(o => o.Status);
conn.UpdateOnly(exist);
}
}
var detail = new InvoiceApplyDetail();
detail.ApplyKvid = apply.Kvid;
detail.GoodsFullName = currentInvoices[0].SerialNumber;
detail.TaxRate = currentInvoices[0].TaxRate;
detail.Amount = currentInvoices.Sum(o => o.Amount);
detail.Quantity = 1;
detail.AmountUntaxed = Math.Round(detail.Amount / (1 + detail.TaxRate), 2);
detail.AmountTax = detail.Amount - detail.AmountUntaxed;
detail.QuantityUnitPriceUntaxed = Math.Round(detail.AmountUntaxed / detail.Quantity, 2);
detail.QuantityUnitPrice = Math.Round(detail.Amount / detail.Quantity, 2);
conn.Insert(detail);
#endregion
#region 处理发票
foreach (var invoice in currentInvoices)
{
var invoiceKvid = Guid.NewGuid();
invoice.RootKvid = invoiceKvid;
invoice.Kvid = invoiceKvid;
invoice.AmountPayment = 0;
invoice.AmountUsed = 0;
invoice.AmountUntaxed = Math.Round(invoice.Amount / (1 + invoice.TaxRate), 2);
invoice.AmountTax = invoice.Amount - invoice.AmountUntaxed;
invoice.Type = apply.Type;//"增值税普通发票";
invoice.OwnerKvid = apply.OwnerKvid;
invoice.OwnerName = apply.OwnerName;
invoice.Currency = apply.Currency;
invoice.PayeeKvid = invoice.PayeeKvid == Guid.Empty ? apply.PayeeKvid : invoice.PayeeKvid;
invoice.PayeeName = invoice.PayeeName.IsNullOrEmpty() ? apply.PayeeName : invoice.PayeeName;
invoice.PayeeTaxNumber = invoice.PayeeTaxNumber.IsNullOrEmpty() ? apply.PayeeTaxNumber : invoice.PayeeTaxNumber;
invoice.PayeeCompanyAddress = invoice.PayeeCompanyAddress.IsNullOrEmpty() ? apply.PayeeCompanyAddress : invoice.PayeeCompanyAddress;
invoice.PayeePhone = invoice.PayeePhone.IsNullOrEmpty() ? apply.PayeePhone : invoice.PayeePhone;
invoice.PayeeRegisteredBank = invoice.PayeeRegisteredBank.IsNullOrEmpty() ? apply.PayeeRegisteredBank : invoice.PayeeRegisteredBank;
invoice.PayeeBankAccount = invoice.PayeeBankAccount.IsNullOrEmpty() ? apply.PayeeBankAccount : invoice.PayeeBankAccount;
invoice.PayerKvid = invoice.PayerKvid == Guid.Empty ? apply.PayerKvid : invoice.PayerKvid;
invoice.PayerName = invoice.PayerName.IsNullOrEmpty() ? apply.PayerName : invoice.PayerName;
invoice.PayerTaxNumber = invoice.PayerTaxNumber.IsNullOrEmpty() ? apply.PayerTaxNumber : invoice.PayerTaxNumber;
invoice.PayerCompanyAddress = invoice.PayerCompanyAddress.IsNullOrEmpty() ? apply.PayerCompanyAddress : invoice.PayerCompanyAddress;
invoice.PayerPhone = invoice.PayerPhone.IsNullOrEmpty() ? apply.PayerPhone : invoice.PayerPhone;
invoice.PayerRegisteredBank = invoice.PayerRegisteredBank.IsNullOrEmpty() ? apply.PayerRegisteredBank : invoice.PayerRegisteredBank;
invoice.PayerBankAccount = invoice.PayerBankAccount.IsNullOrEmpty() ? apply.PayerBankAccount : invoice.PayerBankAccount;
invoice.OperatorName = apply.OperatorName;
//invoice.Remark = apply.Remark;
conn.Insert(invoice);
#region 插入发票明细
if (invoice.Details.IsNullOrEmpty())
{
var invoiceDetail = new InvoiceDetail();
invoiceDetail.InvoiceKvid = invoiceKvid;
invoiceDetail.GoodsFullName = invoice.SerialNumber;
//invoiceDetail.GoodsSpecifications = invoice.GoodsSpecifications;
invoiceDetail.Quantity = 1;
invoiceDetail.QuantityUnitPriceUntaxed = 1;// quantityUnitPriceUntaxed;
invoiceDetail.AmountUntaxed = invoice.AmountUntaxed;
invoiceDetail.Amount = invoice.Amount;
invoiceDetail.AmountTax = invoice.AmountTax;
invoiceDetail.TaxRate = invoice.TaxRate;
conn.Insert(invoiceDetail);
}
else
{
foreach (var invoiceDetail in invoice.Details)
{
invoiceDetail.InvoiceKvid = invoiceKvid;
conn.Insert(invoiceDetail);
}
}
#endregion
#region 更新申请状态
if (!applyRelations.IsNullOrEmpty())
{
foreach (var item in applyRelations)
{
//无需更新
if (item.AmountInvoice >= item.Amount) continue;
var relationAmount = item.Amount - item.AmountInvoice;
var amountRelation = relationAmount <= invoice.Amount ? relationAmount : invoice.Amount;
item.AmountInvoice += amountRelation;
item.AddOnlyProperties(o => o.AmountInvoice);
if (item.AmountInvoice == item.Amount)
{
item.Status = (int)InvoiceApplyStatus.Completed;
item.AddOnlyProperties(o => o.Status);
}
conn.UpdateOnly(item);
}
}
apply.AmountInvoice += invoice.Amount;
apply.AddOnlyProperties(o => o.AmountInvoice);
if (apply.AmountInvoice == apply.Amount)
{
apply.Status = (int)InvoiceApplyStatus.Completed;
apply.AddOnlyProperties(o => o.Status);
}
conn.UpdateOnly(apply);
rtns.Results.Add(apply);
#endregion
}
#endregion
//apply.Relation(conn);
}
trans.Commit();
}
catch (Exception ex)
{
trans.Rollback();
throw ex;
}
return rtns;
}
}
}
...@@ -55,7 +55,6 @@ namespace Kivii.Finances.Transforms ...@@ -55,7 +55,6 @@ namespace Kivii.Finances.Transforms
(Payments.Exists(o => o.Amount <= 0)).ThrowIfTrue("未指定到账开票金额!"); (Payments.Exists(o => o.Amount <= 0)).ThrowIfTrue("未指定到账开票金额!");
(Payments.Sum(o => o.Amount) != Items.Sum(o => o.Amount)).ThrowIfTrue("到账开票金额和发票金额不一致!"); (Payments.Sum(o => o.Amount) != Items.Sum(o => o.Amount)).ThrowIfTrue("到账开票金额和发票金额不一致!");
} }
#region 启用缓存,将当前人创建批次数据存入,处理完毕或者接口报错后清除,确保不会重复创建 #region 启用缓存,将当前人创建批次数据存入,处理完毕或者接口报错后清除,确保不会重复创建
var cache = KiviiContext.GetCacheClient(); var cache = KiviiContext.GetCacheClient();
var cacheKey = KiviiContext.GetUrnKey($"{this.GetType().FullName}_Request_{KiviiContext.CurrentMember.FullName}_{KiviiContext.CurrentMember.Kvid}"); var cacheKey = KiviiContext.GetUrnKey($"{this.GetType().FullName}_Request_{KiviiContext.CurrentMember.FullName}_{KiviiContext.CurrentMember.Kvid}");
...@@ -72,6 +71,10 @@ namespace Kivii.Finances.Transforms ...@@ -72,6 +71,10 @@ namespace Kivii.Finances.Transforms
// 数据库连接初始化(移到外层以确保异常时能正确关闭) // 数据库连接初始化(移到外层以确保异常时能正确关闭)
var conn = KiviiContext.GetOpenedDbConnection<Invoice>(); var conn = KiviiContext.GetOpenedDbConnection<Invoice>();
var applyKvids = Items.ConvertAll(o => o.ApplyKvid).Distinct().ToList();
var applys = conn.SelectByIds<InvoiceApply>(applyKvids);
var trans = null as IDbTransaction; var trans = null as IDbTransaction;
var lockAcquired = false; var lockAcquired = false;
var lockName = $"invoice_lock_{KiviiContext.CurrentMember.Kvid}"; var lockName = $"invoice_lock_{KiviiContext.CurrentMember.Kvid}";
...@@ -144,7 +147,7 @@ namespace Kivii.Finances.Transforms ...@@ -144,7 +147,7 @@ namespace Kivii.Finances.Transforms
var invoice = new Invoice(); var invoice = new Invoice();
invoice.RootKvid = invoiceKvid; invoice.RootKvid = invoiceKvid;
invoice.Kvid = invoiceKvid; invoice.Kvid = invoiceKvid;
//invoice.ApplyKvid = ApplyKvid; invoice.ApplyKvid = info.ApplyKvid;
invoice.OwnerKvid = info.OwnerKvid; invoice.OwnerKvid = info.OwnerKvid;
invoice.OwnerName = info.OwnerName; invoice.OwnerName = info.OwnerName;
if (invoice.OwnerKvid == Guid.Empty && invoice.OwnerName.IsNullOrEmpty()) if (invoice.OwnerKvid == Guid.Empty && invoice.OwnerName.IsNullOrEmpty())
...@@ -320,7 +323,21 @@ namespace Kivii.Finances.Transforms ...@@ -320,7 +323,21 @@ namespace Kivii.Finances.Transforms
// 缓存清理失败仅记录警告 // 缓存清理失败仅记录警告
KiviiContext.Logger.Warn($"缓存清理失败: {cacheEx.Message}"); KiviiContext.Logger.Warn($"缓存清理失败: {cacheEx.Message}");
} }
if (!applys.IsNullOrEmpty())
{
try
{
var th = KiviiContext.NewThread("发票申请标记完成", () =>
{
applys.ExcuteCompleted();
});
th.Start();
}
catch(Exception ex)
{
throw ex;
}
}
return rtns; return rtns;
} }
catch (Exception ex) catch (Exception ex)
......
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