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.

480 lines
18 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.Application.Entity;
using DS.WMS.Core.Application.Interface;
using DS.WMS.Core.Fee.Dtos;
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>
public class ApplicationService<TEntity> : FeeServiceBase, IApplicationService<TEntity>
where TEntity : ApplicationBase, new()
{
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<TEntity>> SaveAsync(TEntity application)
{
TEntity dbValue = null;
if (application.Id >= 0)
{
//修改需检查申请单状态
dbValue = await TenantDb.Queryable<TEntity>().Where(x => x.Id == application.Id).Select(
x => new TEntity { Status = x.Status, Currency = x.Currency }).FirstAsync();
if (dbValue == null)
return DataResult<TEntity>.Failed("未能获取申请单信息");
}
if (application.Currency.IsNullOrEmpty())
application.ExchangeRate = 1m;
application.Details ??= [];
var result = PreSave(application, dbValue);
if (!result.Succeeded)
return DataResult<TEntity>.Failed(result.Message);
List<FeeRecord> fees = [];
if (application.Details.Count > 0)
{
var ids = application.Details.Select(x => x.RecordId).ToList();
fees = await TenantDb.Queryable<FeeRecord>().Where(x => ids.Contains(x.Id)).Select(x => new FeeRecord
{
Id = x.Id,
BusinessId = x.BusinessId,
BusinessType = x.BusinessType,
FeeId = x.FeeId,
FeeName = x.FeeName,
FeeType = x.FeeType,
CustomerId = x.CustomerId,
CustomerName = x.CustomerName,
Amount = x.Amount,
Currency = x.Currency,
ExchangeRate = x.ExchangeRate,
OrderAmount = x.OrderAmount,
OrderSettlementAmount = x.OrderSettlementAmount,
SettlementAmount = x.SettlementAmount,
}).ToListAsync();
if (application.Id == 0)
{
//填充申请单信息
var fee = fees[0];
application.CustomerId = fee.CustomerId;
application.CustomerName = fee.CustomerName;
}
foreach (var detail in application.Details)
{
var fee = fees.Find(x => x.Id == detail.RecordId);
detail.BusinessId = fee.BusinessId;
detail.BusinessType = fee.BusinessType;
detail.Currency = application.Currency.IsNullOrEmpty() ? fee.Currency : application.Currency;
detail.ExchangeRate = detail.ExchangeRate ?? fee.ExchangeRate;
detail.FeeId = fee.FeeId;
detail.FeeName = fee.FeeName;
detail.FeeType = fee.FeeType;
detail.CustomerName = application.CustomerName;
detail.OriginalCurrency = fee.Currency;
}
result = CalculateAmount(application, fees);
if (!result.Succeeded)
return DataResult<TEntity>.Failed(result.Message);
}
await TenantDb.Ado.BeginTranAsync();
try
{
//关联导航属性插入
if (application.Id == 0)
{
//创建时需要生成申请单编号
var sequence = commonService.Value.GetSequenceNext<PaymentApplication>();
if (!sequence.Succeeded)
{
return DataResult<TEntity>.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();
}
await OnSaveAsync(application, fees);
await TenantDb.Ado.CommitTranAsync();
PostSave(application);
return DataResult<TEntity>.Success(application);
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult<TEntity>.Failed("发生错误,提交失败");
}
}
/// <summary>
/// 提交保存费用申请单
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<TEntity>> SaveAsync(ApplicationRequest<TEntity> request)
{
request.Application ??= new();
request.Application.Details = await GetDetailsAsync(request.Items);
return await SaveAsync(request.Application);
}
/// <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="application">已保存的申请单</param>
/// <param name="fees">需要更新信息的费用记录</param>
/// <returns></returns>
protected virtual Task OnSaveAsync(TEntity application, List<FeeRecord>? fees)
{
return Task.CompletedTask;
}
/// <summary>
/// 在保存完成后调用
/// </summary>
/// <param name="application">申请单</param>
protected virtual void PostSave(TEntity application)
{
}
/// <summary>
/// 获取业务所关联的申请明细
/// </summary>
/// <param name="items"></param>
/// <returns></returns>
protected virtual Task<List<ApplicationDetail>> GetDetailsAsync(IEnumerable<BizItem> items)
{
return Task.FromResult(new List<ApplicationDetail>());
}
#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
}
}