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.

427 lines
15 KiB
C#

using DS.Module.Core;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Application.Entity;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Fee.Method;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using DS.WMS.Core.Flow.Interface;
using DS.WMS.Core.Sys.Interface;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
namespace DS.WMS.Core.Application.Method
{
/// <summary>
/// 申请单基础实现
/// </summary>
/// <typeparam name="TEntity">实体的类型声明</typeparam>
/// <typeparam name="TModel">模型的类型声明</typeparam>
public class ApplicationService<TEntity> : FeeServiceBase
where TEntity : ApplicationBase, new()
//where TModel : ApplicationDto
{
readonly IClientFlowInstanceService flowService;
readonly Lazy<ICommonService> commonService;
/// <summary>
/// 初始化
/// </summary>
/// <param name="serviceProvider">DI容器</param>
public ApplicationService(IServiceProvider serviceProvider) : base(serviceProvider)
{
flowService = serviceProvider.GetRequiredService<IClientFlowInstanceService>();
commonService = new Lazy<ICommonService>(serviceProvider.GetRequiredService<ICommonService>());
}
#region 保存
/// <summary>
/// 提交保存费用申请单
/// </summary>
/// <param name="application">申请单</param>
/// <returns></returns>
public async Task<DataResult> SaveAsync(TEntity application)
{
application.Details ??= [];
if (application.Id > 0)
{
//修改需检查申请单状态
var model = await TenantDb.Queryable<TEntity>().Where(x => x.Id == application.Id).Select(
x => new TEntity { Status = x.Status, Currency = x.Currency }).FirstAsync();
if (model == null)
return DataResult.Failed("未能获取申请单信息");
var result = PreSave(application, model);
if (!result.Succeeded)
return result;
}
List<FeeRecord>? fees = null;
if (application.Details.Count > 0)
{
if (application.Details.GroupBy(x => x.CustomerName).Select(x => x.Key).Count() > 1)
return DataResult.Failed("申请单的结算对象有且只能有一个");
//仅处理新增的明细
var ids = application.Details.FindAll(x => x.Id == 0).Select(x => x.RecordId).ToList();
fees = await TenantDb.Queryable<FeeRecord>().Where(x => ids.Contains(x.Id)).Select(x => new FeeRecord
{
Id = x.Id,
Amount = x.Amount,
OrderAmount = x.OrderAmount,
OrderSettlementAmount = x.OrderSettlementAmount,
SettlementAmount = x.SettlementAmount
}).ToListAsync();
var result = CalculateAmount(application, fees);
if (!result.Succeeded)
return result;
}
if (application.Currency.IsNullOrEmpty())
application.ExchangeRate = 1m;
await TenantDb.Ado.BeginTranAsync();
try
{
//关联导航属性插入
if (application.Id == 0)
{
//创建时需要生成申请单编号
var sequence = commonService.Value.GetSequenceNext<PaymentApplication>();
if (!sequence.Succeeded)
{
return DataResult.Failed(sequence.Message, MultiLanguageConst.SequenceSetNotExist);
}
application.ApplicationNO = sequence.Data;
await TenantDb.InsertNav(application).Include(x => x.Details).ExecuteCommandAsync();
}
else
{
var createList = application.Details.FindAll(x => x.Id == 0);
if (createList.Count > 0)
await TenantDb.Insertable(createList).ExecuteCommandAsync();
await TenantDb.Updateable(application).IgnoreColumns(x => new
{
x.ApplicationNO,
//x.Currency,
x.CreateBy,
x.CreateTime,
x.Deleted,
x.DeleteBy,
x.DeleteTime
}).ExecuteCommandAsync();
}
if (fees != null && fees.Count > 0)
await UpdateFeesAsync(fees);
await TenantDb.Ado.CommitTranAsync();
PostSave(application);
return DataResult.Success;
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.Failed("发生错误,提交失败");
}
}
/// <summary>
/// 在保存执行前调用,用于执行先决条件的检查
/// </summary>
/// <param name="application">提交的申请单</param>
/// <param name="dbValue">数据库值新增时为null</param>
/// <returns></returns>
protected virtual DataResult PreSave(TEntity application, TEntity dbValue)
{
return DataResult.Success;
}
/// <summary>
/// 根据申请单明细,计算费用记录的剩余额度
/// </summary>
/// <param name="application">申请单</param>
/// <param name="fees">费用记录</param>
/// <returns></returns>
protected virtual DataResult CalculateAmount(TEntity application, List<FeeRecord> fees)
{
return DataResult.Success;
}
/// <summary>
/// 更新费用记录时调用
/// </summary>
/// <param name="fees">费用记录</param>
/// <returns></returns>
protected virtual Task UpdateFeesAsync(List<FeeRecord> fees)
{
return Task.CompletedTask;
}
/// <summary>
/// 在保存完成后调用
/// </summary>
/// <param name="application">申请单</param>
protected virtual void PostSave(TEntity application)
{
}
#endregion
#region 删除
/// <summary>
/// 删除申请单明细
/// </summary>
/// <param name="ids">申请单明细ID</param>
/// <returns></returns>
public async Task<DataResult> DeleteDetailAsync(params long[] ids)
{
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.Id)).Select(
x => new ApplicationDetail
{
Id = x.Id,
ApplicationId = x.ApplicationId,
RecordId = x.RecordId,
OriginalAmount = x.OriginalAmount
}).ToListAsync();
var appIds = details.Select(x=>x.ApplicationId).Distinct().ToList();
var apps = await TenantDb.Queryable<TEntity>().Where(x => appIds.Contains(x.Id)).Select(x => new TEntity
{
Id = x.Id,
Status = x.Status
}).ToListAsync();
var result = PreDelete(apps);
if (!result.Succeeded)
return result;
await TenantDb.Ado.BeginTranAsync();
try
{
await OnDeleteDetailAsync(details);
await TenantDb.Deleteable(details).ExecuteCommandAsync();
await TenantDb.Ado.CommitTranAsync();
return DataResult.Success;
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.Failed("删除失败!");
}
}
/// <summary>
/// 在删除申请单或其明细之前调用,用于检查申请单状态
/// </summary>
/// <param name="applications">申请单</param>
/// <returns></returns>
protected virtual DataResult PreDelete(List<TEntity> applications)
{
return DataResult.Success;
}
/// <summary>
/// 在执行删除申请单或其明细时调用
/// </summary>
/// <param name="details">申请单明细</param>
/// <returns></returns>
protected virtual Task OnDeleteDetailAsync(List<ApplicationDetail> details)
{
return Task.CompletedTask;
}
/// <summary>
/// 删除申请单
/// </summary>
/// <param name="ids">申请单ID</param>
/// <returns></returns>
public async Task<DataResult> DeleteAsync(params long[] ids)
{
var apps = await TenantDb.Queryable<TEntity>().Where(x => ids.Contains(x.Id)).Select(x => new TEntity
{
Id = x.Id,
Status = x.Status
}).ToListAsync();
var result = PreDelete(apps);
if (!result.Succeeded)
return result;
var details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.ApplicationId)).Select(
x => new ApplicationDetail
{
Id = x.Id,
RecordId = x.RecordId,
OriginalAmount = x.OriginalAmount
}).ToListAsync();
await TenantDb.Ado.BeginTranAsync();
try
{
await OnDeleteDetailAsync(details);
await TenantDb.DeleteNav<TEntity>(x => ids.Contains(x.Id)).Include(x => x.Details).ExecuteCommandAsync();
await TenantDb.Ado.CommitTranAsync();
return DataResult.Success;
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.Failed("删除失败!");
}
}
#endregion
#region 审批
/// <summary>
/// 提交审批
/// </summary>
/// <param name="auditType">审批类型</param>
/// <param name="remark">审批备注</param>
/// <param name="idArray">申请单ID</param>
/// <returns></returns>
public async Task<DataResult> SubmitApprovalAsync(AuditType auditType, string remark, params long[] idArray)
{
var list = await TenantDb.Queryable<TEntity>().LeftJoin<ApplicationDetail>((x, y) => x.Id == y.ApplicationId)
.GroupBy((x, y) => x.Id)
.Where((x, y) => idArray.Contains(x.Id))
.Select((x, y) => new TEntity
{
Id = x.Id,
Status = x.Status,
DetailCount = SqlFunc.AggregateCount(y.Id)
}).ToListAsync();
if (list.Count == 0)
return DataResult.Failed("未能找到申请单记录");
if (list.Exists(x => x.DetailCount == 0))
return DataResult.Failed("提交审批时必须包含费用明细,请检查");
var result = PreSubmitApproval(list);
if (!result.Succeeded)
return result;
var template = await FindTemplateAsync(auditType);
if (template == null)
return DataResult.Failed("未能找到审批模板");
await TenantDb.Ado.BeginTranAsync();
try
{
var list2 = list.Select(x => new TEntity { Id = x.Id, Status = x.Status }).ToList();
foreach (var item in list2)
{
result = flowService.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = item.Id,
TemplateId = template.Id
});
if (result.Succeeded)
{
var instance = result.Data as FlowInstance;
flowService.StartFlowInstance(instance.Id.ToString());
item.FlowId = instance.Id;
OnSubmitApproval(item);
await TenantDb.Updateable(item).UpdateColumns(x => new { x.Status, x.FlowId }).ExecuteCommandAsync();
}
}
await TenantDb.Ado.CommitTranAsync();
return DataResult.Success;
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.Failed("发生错误,提交失败");
}
}
/// <summary>
/// 在提交审批前调用,用于检查申请单状态
/// </summary>
/// <param name="applications">申请单</param>
/// <returns></returns>
protected virtual DataResult PreSubmitApproval(List<TEntity> applications)
{
return DataResult.Success;
}
/// <summary>
/// 在提交审批时调用,用于更新申请单信息
/// </summary>
/// <param name="application">申请单</param>
/// <returns></returns>
protected virtual void OnSubmitApproval(TEntity application)
{
}
/// <summary>
/// 撤销审批
/// </summary>
/// <param name="ids">申请单ID</param>
/// <returns></returns>
public async Task<DataResult> WithdrawAsync(params long[] ids)
{
var list = await TenantDb.Queryable<TEntity>().Where(x => ids.Contains(x.Id)).Select(
x => new TEntity
{
Id = x.Id,
ApplicationNO = x.ApplicationNO,
Status = x.Status,
FlowId = x.FlowId
}).ToListAsync();
if (list.Count == 0)
return DataResult.Failed("未能找到申请单记录");
//未在审批状态中
var list2 = list.FindAll(x => x.FlowId == null).ToList();
if (list2.Count > 0)
{
string msg = string.Join("; ", list2.Select(x => $"{x.ApplicationNO}"));
return DataResult.Failed($"以下申请单:{msg} 未在审批状态中,无需撤销");
}
var flows = list.Select(x => new FlowInstance { Id = x.FlowId.Value, FlowStatus = (int)FlowStatusEnum.Draft, MakerList = string.Empty }).ToList();
DateTime dtNow = DateTime.Now;
try
{
await Db.Updateable(flows).UpdateColumns(x => new { x.FlowStatus, x.MakerList }).ExecuteCommandAsync();
foreach (var item in list)
{
item.Status = 0;
item.FlowId = null;
}
await TenantDb.Updateable(list).UpdateColumns(x => new { x.Status, x.FlowId }).ExecuteCommandAsync();
await TenantDb.Ado.CommitTranAsync();
return DataResult.Successed("提交成功!");
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.Failed("提交失败!");
}
}
#endregion
}
}