You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

967 lines
42 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using DS.Module.Core;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Application.Dtos;
using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Fee.Dtos;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Fee.Interface;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Interface;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Interface.TaskInteraction;
using DS.WMS.Core.Sys.Entity;
using Mapster;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
namespace DS.WMS.Core.Fee.Method
{
/// <summary>
/// 费用审核
/// </summary>
public class FeeAuditService : FeeServiceBase, IFeeAuditService
{
/// <summary>
/// 待审核的状态值
/// </summary>
public static readonly FeeStatus[] AuditStatusArray = [FeeStatus.AuditSubmitted, FeeStatus.ApplyDeletion, FeeStatus.ApplyModification];
//一键审核支持的类型
static readonly TaskBaseTypeEnum[] AuditTypes = [TaskBaseTypeEnum.FEE_AUDIT, TaskBaseTypeEnum.FEE_MODIFY_AUDIT, TaskBaseTypeEnum.FEE_DELETE_AUDIT, TaskBaseTypeEnum.FEE_BUSINESS_AUDIT];
readonly IClientFlowInstanceService flowService;
readonly IFeeRecordService feeService;
readonly ISeaExportTaskService taskService;
/// <summary>
/// 初始化
/// </summary>
/// <param name="serviceProvider"></param>
public FeeAuditService(IServiceProvider serviceProvider) : base(serviceProvider)
{
flowService = serviceProvider.GetRequiredService<IClientFlowInstanceService>();
feeService = serviceProvider.GetRequiredService<IFeeRecordService>();
taskService = serviceProvider.GetRequiredService<ISeaExportTaskService>();
}
/// <summary>
/// 获取费用审核列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<FeeAuditBusiness>>> GetListAsync(PageRequest<bool> request)
{
long[]? ids1 = null;
long[]? ids2 = null;
if (request.OtherQueryCondition)
{
var flows = await GetCurrentFlowsQuery(AuditTypes).Select(x => new
{
x.BusinessId,
x.BusinessType,
x.AuditType
}).ToListAsync();
//没有待审批的列表直接返回不再执行后续查询
if (flows.Count == 0)
return DataResult<List<FeeAuditBusiness>>.PageList(0, null, MultiLanguageConst.DataQuerySuccess);
ids1 = flows.Where(x => x.AuditType != TaskBaseTypeEnum.FEE_BUSINESS_AUDIT).Select(x => x.BusinessId).ToArray();
ids2 = flows.Where(x => x.AuditType == TaskBaseTypeEnum.FEE_BUSINESS_AUDIT).Select(x => x.BusinessId).ToArray();
}
var queryList = CreateQuery(ids1, ids2);
if (!request.QueryCondition.IsNullOrEmpty())
{
var whereList = request.GetConditionalModels(Db);
queryList = queryList.Where(whereList);
}
var result = await queryList.Select<FeeAuditBusiness>().ToQueryPageAsync(request.PageCondition);
if (result.Data.Count > 0)
{
//关联用户名称
var userIds = result.Data.Where(x => x.OperatorId.HasValue).Select(x => x.OperatorId.Value)
.Union(result.Data.Select(x => x.CreateBy))
.Distinct();
var Users = await Db.Queryable<SysUser>().Where(x => userIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToListAsync();
foreach (var item in result.Data)
{
item.CreateByName = Users.Find(x => x.Id == item.CreateBy)?.UserName;
if (item.OperatorId.HasValue)
{
item.Operator = Users.Find(x => x.Id == item.OperatorId.Value)?.UserName;
}
}
}
return result;
}
/// <summary>
/// 创建各项费用数据的查询并集
/// </summary>
/// <param name="ids1">费用ID</param>
/// <param name="ids2">业务ID</param>
/// <returns></returns>
internal ISugarQueryable<FeeAuditBusiness> CreateQuery(long[]? ids1, long[]? ids2)
{
//海运出口
var query1 = TenantDb.Queryable<SeaExport, BusinessFeeStatus, FeeRecord, CodeSource, CodeSourceDetail>((s, b, f, cs, csd) => new JoinQueryInfos(
JoinType.Inner, s.Id == b.BusinessId && b.BusinessType == BusinessType.OceanShippingExport,
JoinType.Inner, s.Id == f.BusinessId && f.BusinessType == BusinessType.OceanShippingExport && AuditStatusArray.Contains(f.FeeStatus),
JoinType.Left, s.SourceId == cs.Id,
JoinType.Left, s.SourceDetailId == csd.Id
))
.WhereIF(ids1 != null && ids1.Length > 0 || ids2 != null && ids2.Length > 0, (s, b, f) => ids1.Contains(f.Id) || ids2.Contains(s.Id))
.GroupBy(s => s.Id)
.Select((s, b, f, cs, csd) => new FeeAuditBusiness
{
Id = s.Id,
AccountDate = s.AccountDate,
APFeeStatus = b.APFeeStatus,
ARFeeStatus = b.ARFeeStatus,
BusinessType = BusinessType.OceanShippingExport,
BusinessStatus = s.BusinessStatusName,
BusinessDate = s.CreateTime,//业务日期
BLType = s.BLType,
CargoId = s.CargoId,
Carrier = s.Carrier,
AgentId = s.AgentId,
CBM = s.CBM,
CntrTotal = s.CntrTotal,
ContractNo = s.ContractNo,
CreateBy = s.CreateBy,
CustomerId = s.CustomerId,
CustomerName = s.CustomerName,//委托单位
CustomerNo = s.CustomerNo,
CustomerService = s.CustomerService,
CustomNo = s.CustomNo,
CustomsNum = s.CustomsNum,
DangerClass = s.DangerClass,
Destination = s.Destination,
DischargePort = s.DischargePort,
Doc = s.Doc,
ETD = s.ETD,
Forwarder = s.Forwarder,
FeeId = f.FeeId,
FeeCustomerId = f.CustomerId,
FeeCustomerName = f.CustomerName,
GoodsName = s.GoodsName,
HBLNO = s.HBLNO,
InvoiceNo = s.InvoiceNo,
IsBusinessLocking = b.IsBusinessLocking,
IsFeeLocking = b.IsFeeLocking,
IssueType = s.IssueType,
KGS = s.KGS,
LoadPort = s.LoadPort,
MBLFrt = s.MBLFrt,
MBLNO = s.MBLNO,
Note = s.Note,
OperatorId = s.OperatorId,
OrderNo = s.OrderNo,
PKGS = s.PKGS,
ReceiptPlace = s.ReceiptPlace,
Remark = s.Remark,
SaleDeptId = s.SaleDeptId,
//SaleDeptName //所属部门
SaleId = s.SaleId,
SaleName = s.Sale,//揽货人
SourceId = s.SourceId,
SourceName = cs.SourceName,
SourceDetailId = s.SourceDetailId,
DetailName = csd.DetailName,
TradeTerm = s.TradeTerm,
TransitTerms = s.Service,//运输条款
Vessel = s.Vessel,//船名
Voyage = s.Voyno,//航次
Yard = s.Yard,
//BusinessUnit = //经营单位
//ChangeOrder //更改单
//ChangeReason //更改单更改原因
//FreightRatio //运杂费比例
//查询:运输类型 (枚举值,暂未建立)
//查询:是否费用提交
//查询:利润减少
}).MergeTable();
//海运进口
//var ids2 = additions?.Where(x => x.BusinessType == BusinessType.OceanShippingImport).Select(x => x.BusinessId).ToArray();
return TenantDb.UnionAll(new List<ISugarQueryable<FeeAuditBusiness>> { query1 });
}
/// <summary>
/// 获取整票审核列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<FeeAuditBusiness>>> GetBizListAsync(PageRequest<bool> request)
{
long[]? ids = null;
if (request.OtherQueryCondition)
{
ids = await GetCurrentFlowsQuery(TaskBaseTypeEnum.FEE_BUSINESS_AUDIT).Select(x => x.BusinessId).Distinct().ToArrayAsync();
//没有待审批的列表直接返回不再执行后续查询
if (ids.Length == 0)
return DataResult<List<FeeAuditBusiness>>.PageList(0, null, MultiLanguageConst.DataQuerySuccess);
}
var queryList = CreateBizQuery(ids);
if (!request.QueryCondition.IsNullOrEmpty())
{
var whereList = Db.ConfigQuery.Context.Utilities.JsonToConditionalModels(request.QueryCondition);
queryList = queryList.Where(whereList);
}
var result = await queryList.Select<FeeAuditBusiness>().ToQueryPageAsync(request.PageCondition);
if (result.Data.Count > 0)
{
//关联用户名称
var UserIds = result.Data.Where(x => x.OperatorId.HasValue).Select(x => x.OperatorId.Value)
.Union(result.Data.Select(x => x.CreateBy))
.Distinct();
var Users = await Db.Queryable<SysUser>().Where(x => UserIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToListAsync();
foreach (var item in result.Data)
{
item.CreateByName = Users.Find(x => x.Id == item.CreateBy)?.UserName;
if (item.OperatorId.HasValue)
{
item.Operator = Users.Find(x => x.Id == item.OperatorId.Value)?.UserName;
}
}
}
return result;
}
//创建各项业务数据的查询并集
internal ISugarQueryable<FeeAuditBusiness> CreateBizQuery(params long[]? feeIds)
{
//海运出口
var query1 = TenantDb.Queryable<SeaExport, BusinessFeeStatus, FeeRecord, CodeSource, CodeSourceDetail>((s, b, f, cs, csd) => new JoinQueryInfos(
JoinType.Inner, s.Id == b.BusinessId && b.BusinessType == BusinessType.OceanShippingExport,
JoinType.Inner, s.Id == f.BusinessId && f.BusinessType == BusinessType.OceanShippingExport && AuditStatusArray.Contains(f.FeeStatus),
JoinType.Left, s.SourceId == cs.Id,
JoinType.Left, s.SourceDetailId == csd.Id
))
.WhereIF(feeIds != null && feeIds.Length > 0, (s, b, f, cs, csd) => feeIds.Contains(f.Id))
.GroupBy(s => s.Id)
.Select((s, b, f, cs, csd) => new FeeAuditBusiness
{
Id = s.Id,
AccountDate = s.AccountDate,
APFeeStatus = b.APFeeStatus,
ARFeeStatus = b.ARFeeStatus,
BusinessType = BusinessType.OceanShippingExport,
BusinessStatus = s.BusinessStatusName,
BusinessDate = s.CreateTime,//业务日期
BLType = s.BLType,
CargoId = s.CargoId,
Carrier = s.Carrier,
AgentId = s.AgentId,
CBM = s.CBM,
CntrTotal = s.CntrTotal,
ContractNo = s.ContractNo,
CreateBy = s.CreateBy,
CustomerId = s.CustomerId,
CustomerName = s.CustomerName,//委托单位
CustomerNo = s.CustomerNo,
CustomerService = s.CustomerService,
CustomNo = s.CustomNo,
CustomsNum = s.CustomsNum,
DangerClass = s.DangerClass,
Destination = s.Destination,
DischargePort = s.DischargePort,
Doc = s.Doc,
ETD = s.ETD,
Forwarder = s.Forwarder,
FeeId = f.FeeId,
FeeCustomerId = f.CustomerId,
FeeCustomerName = f.CustomerName,
GoodsName = s.GoodsName,
HBLNO = s.HBLNO,
InvoiceNo = s.InvoiceNo,
IsBusinessLocking = b.IsBusinessLocking,
IsFeeLocking = b.IsFeeLocking,
IssueType = s.IssueType,
KGS = s.KGS,
LoadPort = s.LoadPort,
MBLFrt = s.MBLFrt,
MBLNO = s.MBLNO,
Note = s.Note,
OperatorId = s.OperatorId,
OrderNo = s.OrderNo,
PKGS = s.PKGS,
ReceiptPlace = s.ReceiptPlace,
Remark = s.Remark,
SaleDeptId = s.SaleDeptId,
//SaleDeptName //所属部门
SaleId = s.SaleId,
SaleName = s.Sale,//揽货人
SourceId = s.SourceId,
SourceName = cs.SourceName,
SourceDetailId = s.SourceDetailId,
DetailName = csd.DetailName,
TradeTerm = s.TradeTerm,
TransitTerms = s.Service,//运输条款
Vessel = s.Vessel,//船名
Voyage = s.Voyno,//航次
Yard = s.Yard
//BusinessUnit = //经营单位
//ChangeOrder //更改单
//ChangeReason //更改单更改原因
//FreightRatio //运杂费比例
//查询:运输类型 (枚举值,暂未建立)
//查询:是否费用提交
//查询:利润减少
});
//海运进口
return TenantDb.UnionAll(new List<ISugarQueryable<FeeAuditBusiness>> { query1 });
}
/// <summary>
/// 根据业务和查询条件获取费用明细
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<PendingAuditFee>> GetFeesAsync(AuditDetailRequest request)
{
var pendingAudit = await TenantDb.Queryable<SeaExport>().Where(x => x.Id == request.Id).Select(x => new PendingAuditFee
{
AccountDate = x.AccountDate,
BusinessType = request.BusinessType,
Carrier = x.Carrier,
CustomerNo = x.CustomerNo,
CustomerName = x.CustomerName,
DischargePort = x.DischargePort,
ETA = x.ETA,
ETD = x.ETD,
LoadPort = x.LoadPort,
MBLNO = x.MBLNO,
Vessel = x.Vessel,
Voyno = x.Voyno
}).FirstAsync();
if (pendingAudit != null)
{
long[] ids1 = [];
long[] ids2 = [];
if (request.AuditOnly)
{
var flows = await GetCurrentFlowsQuery(AuditTypes).Select(x => new
{
x.BusinessId,
x.BusinessType,
x.AuditType
}).ToListAsync();
//没有待审批的列表直接返回不再执行后续查询
if (flows.Count == 0)
return DataResult<PendingAuditFee>.Success(pendingAudit, MultiLanguageConst.DataQuerySuccess);
ids1 = flows.Where(x => x.AuditType != TaskBaseTypeEnum.FEE_BUSINESS_AUDIT).Select(x => x.BusinessId).ToArray();
ids2 = flows.Where(x => x.AuditType == TaskBaseTypeEnum.FEE_BUSINESS_AUDIT).Select(x => x.BusinessId).ToArray();
}
var fees = await TenantDb.Queryable<FeeRecord>().Where(f => f.BusinessId == request.Id && f.BusinessType == request.BusinessType)
.Select(f => new
{
f.FeeType,
f.Amount,
f.ExchangeRate
}).ToListAsync();
pendingAudit.IsPositiveProfit = fees.Where(x => x.FeeType == FeeType.Receivable).Sum(x => x.Amount * (x.ExchangeRate ?? 1))
- fees.Where(x => x.FeeType == FeeType.Payable).Sum(x => x.Amount * (x.ExchangeRate ?? 1)) > 0;
pendingAudit.IsBusinessAudit = await flowService.Exists(TaskBaseTypeEnum.FEE_BUSINESS_AUDIT, request.BusinessType, null, request.Id);
var query1 = TenantDb.Queryable<FeeRecord>().Where(f => f.BusinessId == request.Id && f.BusinessType == request.BusinessType)
.InnerJoin<SeaExport>((f, s) => f.BusinessId == s.Id)
.LeftJoin<InfoClient>((f, s, i) => f.CustomerId == i.Id)
.WhereIF(ids1.Length > 0, (f, s, i) => (ids1.Contains(f.Id) || ids2.Contains(f.BusinessId)) && AuditStatusArray.Contains(f.FeeStatus))
.Select((f, s, i) => new FeeAuditItemQuery
{
Id = f.Id,
BusinessId = f.BusinessId,
BusinessType = f.BusinessType,
FeeStatus = f.FeeStatus,
FeeType = f.FeeType,
FeeId = f.FeeId,
FeeName = f.FeeName,
FeeEnName = f.FeeEnName,
CustomerId = f.CustomerId,
CustomerName = f.CustomerName,
CustomerFullName = i.Description, //结算对象全称
CustomerType = f.CustomerType,
CustomerTypeText = f.CustomerTypeText,
Unit = f.Unit,
UnitText = f.UnitText,
UnitPrice = f.UnitPrice,
TaxUnitPrice = f.TaxUnitPrice,
Quantity = f.Quantity,
TaxRate = f.TaxRate,
NoTaxAmount = f.NoTaxAmount,
Amount = f.Amount,
Currency = f.Currency,
CurrencyText = f.CurrencyText,
ExchangeRate = f.ExchangeRate,
AccTaxRate = f.AccTaxRate,//销项汇率
Remark = f.Remark,
IsAdvancedPay = f.IsAdvancedPay,//是否垫付
IsInvoice = f.IsInvoice, //是否开发票
//FRT
CommissionRate = f.CommissionRate, //佣金比率
CreateBy = f.CreateBy,
CreateTime = f.CreateTime,
SettlementAmount = f.SettlementAmount,//结算金额
InvoiceAmount = f.InvoiceAmount,//开票金额
OrderAmount = f.OrderAmount,//申请金额
InvoiceNO = f.InvoiceNO,//发票号
Tax = f.Tax,//税额
DebitNo = f.DebitNo,//对账编号
SaleOrg = f.SaleOrg,
Reason = f.Reason,
CustomerNo = s.CustomerNo,
Vessel = s.Vessel,
Voyage = s.Voyno,
SaleId = s.SaleId,
ClientId = s.CustomerId,
ClientName = s.CustomerName,
BusinessDate = s.CreateTime,
SourceId = s.SourceId,
AccountDate = s.AccountDate,
OperatorId = s.OperatorId
}).MergeTable();
var queryList = TenantDb.UnionAll(new List<ISugarQueryable<FeeAuditItemQuery>> { query1 });
if (!request.QueryCondition.IsNullOrEmpty())
{
var whereList = Db.ConfigQuery.Context.Utilities.JsonToConditionalModels(request.QueryCondition);
queryList = queryList.Where(whereList);
}
var list = await queryList.Select<AuditItem>().ToListAsync();
if (list.Count > 0)
{
//关联用户名称
var UserIds = list.Select(x => x.CreateBy).Distinct();
var Users = Db.Queryable<SysUser>().Where(x => UserIds.Contains(x.Id)).Select(x => new { x.Id, x.UserName }).ToList();
foreach (var item in list)
{
item.CreateByName = Users.Find(x => x.Id == item.CreateBy)?.UserName;
}
}
//将查询结果组装成按费用分组的结构
pendingAudit.ItemGroups = [];
for (int i = 0; i < list.Count; i++)
{
var item = list[i];
AuditItemGroup? group = pendingAudit.ItemGroups.Find(x => x.FeeName == item.FeeName && x.Items?.Count < 2);
if (group == null)
{
group = new AuditItemGroup
{
FeeName = item.FeeName,
Items = [item]
};
pendingAudit.ItemGroups.Add(group);
}
else if (group.Items.Exists(x => x.FeeType == item.FeeType))
{
group = new AuditItemGroup
{
FeeName = item.FeeName,
Items = [item]
};
pendingAudit.ItemGroups.Add(group);
}
else
{
group.Items.Add(item);
}
}
}
var result = DataResult<PendingAuditFee>.Success(pendingAudit);
return result;
}
/// <summary>
/// 获取业务费用统计
/// </summary>
/// <param name="id">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <param name="feeId">费用ID可空</param>
/// <returns></returns>
public async Task<DataResult<FeeAuditStatistics>> GetStatAsync(long id, BusinessType businessType, long? feeId)
{
List<FeeRecordRes>? list = null;
var feeQuery = TenantDb.Queryable<FeeRecord>().Where(x => x.BusinessId == id && x.BusinessType == businessType)
.WhereIF(feeId.HasValue, x => x.FeeId == feeId.Value);
switch (businessType)
{
case BusinessType.OceanShippingExport:
list = await feeQuery.LeftJoin<SeaExport>((f, s) => f.BusinessId == s.Id).Select((f, s) => new FeeRecordRes
{
BillNO = s.CustomerNo,
CustomerName = s.CustomerName,
FeeType = f.FeeType,
Currency = f.Currency,
LocalCurrency = f.LocalCurrency,
Amount = f.Amount,
NoTaxAmount = f.NoTaxAmount,
ExchangeRate = f.ExchangeRate,
AccTaxRate = f.AccTaxRate,
TaxRate = f.TaxRate
}).ToListAsync();
break;
case BusinessType.OceanShippingImport:
break;
}
FeeAuditStatistics stat = new(list ?? Enumerable.Empty<FeeRecordRes>());
return DataResult<FeeAuditStatistics>.Success(stat);
}
/// <summary>
/// 按费用批量审核
/// </summary>
/// <param name="yesOrNo">审批结果1=通过2=驳回</param>
/// <param name="remark">备注</param>
/// <param name="idArray">待审批的费用ID</param>
/// <returns></returns>
/// <remarks>核心审核方法</remarks>
public async Task<DataResult> AuditAsync(int yesOrNo, string? remark, params long[] idArray)
{
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => idArray.Contains(x.Id)).Select(x => new
{
x.Id,
x.FeeName,
x.FeeStatus,
}).ToListAsync();
if (fees.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
if (fees.Exists(x => !AuditStatusArray.Contains(x.FeeStatus)))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInAudit));
//未在审批状态中
if (!await flowService.Exists(ids: idArray))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInAudit));
List<Tuple<TaskBaseTypeEnum, long>> taskTypes = [];
foreach (var fee in fees)
{
switch (fee.FeeStatus)
{
case FeeStatus.AuditSubmitted:
taskTypes.Add(new Tuple<TaskBaseTypeEnum, long>(TaskBaseTypeEnum.FEE_AUDIT, fee.Id));
break;
case FeeStatus.ApplyModification:
taskTypes.Add(new Tuple<TaskBaseTypeEnum, long>(TaskBaseTypeEnum.FEE_MODIFY_AUDIT, fee.Id));
break;
case FeeStatus.ApplyDeletion:
taskTypes.Add(new Tuple<TaskBaseTypeEnum, long>(TaskBaseTypeEnum.FEE_DELETE_AUDIT, fee.Id));
break;
}
}
DataResult result;
var groups = taskTypes.GroupBy(x => x.Item1);
bool hasAuthorized = await taskService.HasAuthorizedAsync();
foreach (var g in groups)
{
List<string> list = [];
var ids = g.Select(x => x.Item2).ToArray();
if (hasAuthorized)
{
result = await taskService.AuditAsync(new TaskAuditRequest
{
Ids = ids,
Remark = remark,
Result = yesOrNo,
TaskTypeName = g.Key.ToString()
});
if (!result.Succeeded)
list.Add(result.Message);
}
else
{
var instances = await flowService.GetInstanceByBSIdAsync(g.Key, null, ids);
foreach (var item in instances)
{
result = flowService.AuditFlowInstance(new FlowAuditInfo
{
Instance = item,
Status = yesOrNo,
AuditNote = remark
});
if (!result.Succeeded)
list.Add(fees.Find(x => x.Id == item.BusinessId)?.FeeName ?? string.Empty);
}
}
if (list.Count > 0)
return DataResult.Failed(string.Join("、", list));
}
return DataResult.Success;
}
/// <summary>
///一键审核当前登录用户的所有待审核项
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult> AuditAsync(AuditConditionRequest request)
{
var ids = await GetCurrentFlowsQuery(AuditTypes).Select(x => x.BusinessId).ToArrayAsync();
//没有待审批的列表直接返回不再执行后续查询
if (ids.Length == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NoAuditItems));
List<IConditionalModel> whereList = [];
if (!string.IsNullOrEmpty(request.QueryString))
whereList = Db.Utilities.JsonToConditionalModels(request.QueryString);
ids = await TenantDb.Queryable<FeeRecord>().Where(x => ids.Contains(x.Id)).Where(whereList)
.Select(x => x.Id).ToArrayAsync();
return await AuditAsync(request.Result, request.Remark, ids);
}
/// <summary>
/// 按业务批量审核
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult> AuditAsync(BizAuditRequest request)
{
var ids = await GetCurrentFlowsQuery(TaskBaseTypeEnum.FEE_AUDIT).Select(x => x.BusinessId).ToArrayAsync();
var query = CreateQuery(ids, []);
if (!request.QueryCondition.IsNullOrEmpty())
{
var whereList = Db.Utilities.JsonToConditionalModels(request.QueryCondition);
query = query.Where(whereList);
}
var bizList = await query.Select(x => new BizItem { Id = x.Id, BusinessType = x.BusinessType }).ToArrayAsync();
//取所选业务与过滤条件所产生的交集
var intersects = request.Items.Intersect(bizList, BizItem.DefaultComparer).ToList();
if (intersects.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NoAuditItems));
var list1 = intersects.Select(x => x.Id).ToList();
var list2 = intersects.Select(x => x.BusinessType).Distinct();
var recordIds = await TenantDb.Queryable<FeeRecord>().Where(x =>
list1.Contains(x.BusinessId) && list2.Contains(x.BusinessType) && x.FeeStatus == FeeStatus.AuditSubmitted)
.Select(x => x.Id).ToArrayAsync();
//没有待审批的列表直接返回不再执行后续查询
if (recordIds.Length == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NoAuditItems));
return await AuditAsync(request.Result, request.Remark, recordIds);
}
const TaskBaseTypeEnum BIZ_TASK_TYPE = TaskBaseTypeEnum.FEE_BUSINESS_AUDIT;
/// <summary>
/// 整票审核
/// </summary>
/// <param name="request">审批请求</param>
/// <returns></returns>
public async Task<DataResult> AuditBusinessAsync(BizAuditRequest request)
{
DataResult result;
bool hasAuthorized = await taskService.HasAuthorizedAsync();
var gpList = request.Items.GroupBy(x => x.BusinessType).ToList();
foreach (var gp in gpList)
{
var ids = gp.Select(x => x.Id).ToArray();
var bizList = await TenantDb.Queryable<BusinessFeeStatus>().Where(x => ids.Contains(x.BusinessId) && x.BusinessType == gp.Key)
.Select(x => new
{
x.Id,
x.BillAuditStatus,
}).ToListAsync();
if (bizList.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
if (bizList.Any(x => x.BillAuditStatus != BillAuditStatus.AuditSubmitted))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.BusinessAuditStatusError));
if (hasAuthorized)
{
result = await taskService.AuditAsync(new TaskAuditRequest
{
Ids = ids,
Remark = request.Remark,
Result = request.Result,
TaskTypeName = BIZ_TASK_TYPE.ToString()
});
if (!result.Succeeded)
return result;
}
else
{
var flows = await flowService.GetInstanceByBSIdAsync(BIZ_TASK_TYPE, gp.Key, ids);
if (flows.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FlowNotFound));
if (flows.Any(x => !x.MakerList.Contains(User.UserId)))
continue;
foreach (var flow in flows)
{
result = flowService.AuditFlowInstance(new FlowAuditInfo
{
Instance = flow,
Status = request.Result,
AuditNote = request.Remark
});
if (!result.Succeeded)
return result;
}
}
}
return DataResult.Success;
}
/// <summary>
/// 设置业务费用锁定状态
/// </summary>
/// <param name="items">业务信息</param>
/// <returns></returns>
public async Task<DataResult> SetFeeLockingAsync(IEnumerable<BusinessFeeStatus> items)
{
int rows = await TenantDb.Updateable<BusinessFeeStatus>(items)
.WhereColumns(x => new { x.BusinessId, x.BusinessType })
.UpdateColumns(x => new { x.IsFeeLocking })
.ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.Failed(MultiLanguageConst.Operation_Failed);
}
/// <summary>
/// 根据审批结果更新审批状态
/// </summary>
/// <param name="callback">回调信息</param>
/// <returns></returns>
public async Task<DataResult> UpdateStatusAsync(FlowCallback callback)
{
var auditType = callback.AuditType;
FeeRecord? fee = null;
BusinessFeeStatus? biz = null;
if (auditType == TaskBaseTypeEnum.FEE_BUSINESS_AUDIT)
{
biz = await TenantDb.Queryable<BusinessFeeStatus>().Where(x => x.Id == callback.BusinessId && x.BusinessType == callback.BusinessType)
.Select(x => new BusinessFeeStatus
{
Id = x.Id,
BusinessId = x.BusinessId,
BusinessType = x.BusinessType,
BillAuditStatus = x.BillAuditStatus
}).FirstAsync();
if (biz == null)
return DataResult.Failed(MultiLanguageConst.EmptyData);
}
else
{
fee = await TenantDb.Queryable<FeeRecord>().Where(x => x.Id == callback.BusinessId).Select(
x => new FeeRecord
{
Id = x.Id,
FeeStatus = x.FeeStatus,
BusinessId = x.BusinessId,
BusinessType = x.BusinessType
}).FirstAsync();
if (fee == null)
return DataResult.Failed(MultiLanguageConst.EmptyData);
fee.Reason = callback.RejectReason;
}
long UserId = long.Parse(User.UserId);
DateTime dtNow = DateTime.Now;
await TenantDb.Ado.BeginTranAsync();
try
{
switch (auditType)
{
case TaskBaseTypeEnum.FEE_AUDIT:
fee.AuditBy = UserId;
fee.AuditOperator = User.UserName;
fee.AuditDate = dtNow;
if (callback.FlowStatus == FlowStatusEnum.Approve)
{
fee.FeeStatus = FeeStatus.AuditPassed;
fee.Reason = string.Empty;
}
else if (callback.FlowStatus == FlowStatusEnum.Reject)
fee.FeeStatus = FeeStatus.RejectSubmission;
await TenantDb.Updateable(fee).UpdateColumns(x => new
{
x.FeeStatus,
x.AuditBy,
x.AuditOperator,
x.AuditDate,
x.Reason
}).ExecuteCommandAsync();
break;
case TaskBaseTypeEnum.FEE_MODIFY_AUDIT:
//申请修改审核成功需要回填费用信息
if (callback.FlowStatus == FlowStatusEnum.Approve)
{
var fm = await TenantDb.Queryable<FeeModification>().Where(x => x.FeeRecordId == fee.Id).OrderByDescending(x => x.CreateTime).FirstAsync();
if (fm == null)
return DataResult.Failed(MultiLanguageConst.FeeRecordNotExist);
var entity = fm.Adapt<FeeRecord>();
entity.Id = fm.FeeRecordId;
entity.FeeStatus = FeeStatus.AuditPassed;
entity.Reason = callback.RejectReason;
entity.UpdateBy = UserId;
entity.UpdateTime = dtNow;
//全表更新
await TenantDb.Updateable(entity).IgnoreColumns(
x => new { x.AuditBy, x.AuditDate, x.AuditOperator, x.SubmitBy, x.SubmitDate }).ExecuteCommandAsync();
//逻辑删除暂存数据
fm.Deleted = true;
fm.DeleteTime = dtNow;
fm.DeleteBy = UserId;
await TenantDb.Updateable(fm).UpdateColumns(x => new
{
x.DeleteBy,
x.Deleted,
x.DeleteTime
}).ExecuteCommandAsync();
}
else if (callback.FlowStatus == FlowStatusEnum.Reject)
{
fee.FeeStatus = FeeStatus.RejectApplication;
await TenantDb.Updateable(fee).UpdateColumns(x => new
{
x.FeeStatus,
x.Reason
}).ExecuteCommandAsync();
}
break;
case TaskBaseTypeEnum.FEE_DELETE_AUDIT:
if (callback.FlowStatus == FlowStatusEnum.Approve)
{
fee.Deleted = true;
fee.DeleteBy = UserId;
fee.DeleteTime = dtNow;
await TenantDb.Updateable(fee).UpdateColumns(x => new
{
x.DeleteBy,
x.Deleted,
x.DeleteTime,
x.Reason
}).ExecuteCommandAsync();
//TenantDb.Deleteable(fee).ExecuteCommandAsync();
}
else
{
fee.FeeStatus = FeeStatus.RejectApplication;
await TenantDb.Updateable(fee).UpdateColumns(x => new
{
x.FeeStatus,
x.Reason
}).ExecuteCommandAsync();
}
break;
case TaskBaseTypeEnum.FEE_BUSINESS_AUDIT:
FeeStatus status = FeeStatus.RejectSubmission;
if (callback.FlowStatus == FlowStatusEnum.Approve)
{
biz.BillAuditStatus = BillAuditStatus.AuditPassed;
status = FeeStatus.AuditPassed;
}
else if (callback.FlowStatus == FlowStatusEnum.Reject)
{
biz.BillAuditStatus = BillAuditStatus.Rejected;
}
await TenantDb.Updateable(biz).UpdateColumns(x => new
{
x.BillAuditStatus
}).ExecuteCommandAsync();
await TenantDb.Updateable<FeeRecord>()
.SetColumns(x => x.FeeStatus == status)
.SetColumns(x => x.AuditBy == UserId)
.SetColumns(x => x.AuditOperator == User.UserName)
.SetColumns(x => x.AuditDate == dtNow)
.Where(x => x.BusinessId == biz.BusinessId && x.BusinessType == biz.BusinessType &&
x.FeeStatus != FeeStatus.PartialSettlement && x.FeeStatus != FeeStatus.SettlementCompleted).ExecuteCommandAsync();
break;
}
////驳回申请则逻辑删除关联工作流
//if (callback.FlowStatus == FlowStatusEnum.Reject)
//{
// await Db.Updateable(new FlowInstance
// {
// Id = callback.InstanceId,
// Deleted = true,
// DeleteBy = 0,
// DeleteTime = DateTime.Now
// }).UpdateColumns(x => new { x.Deleted, x.DeleteBy, x.DeleteTime }).ExecuteCommandAsync();
//}
await TenantDb.Ado.CommitTranAsync();
if (auditType != TaskBaseTypeEnum.FEE_BUSINESS_AUDIT)
{
await feeService.WriteBackStatusAsync(
auditType == TaskBaseTypeEnum.FEE_BUSINESS_AUDIT ? biz.BusinessId : fee.BusinessId,
auditType == TaskBaseTypeEnum.FEE_BUSINESS_AUDIT ? biz.BusinessType : fee.BusinessType);
}
return DataResult.Success;
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.Failed(MultiLanguageConst.Operation_Failed);
}
}
}
}