|
|
|
|
using DS.Module.Core;
|
|
|
|
|
using DS.Module.Core.Enums;
|
|
|
|
|
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.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.Invoice.Dtos;
|
|
|
|
|
using DS.WMS.Core.Sys.Interface;
|
|
|
|
|
using DS.WMS.Core.TaskInteraction.Dtos;
|
|
|
|
|
using DS.WMS.Core.TaskInteraction.Interface;
|
|
|
|
|
using Masuit.Tools.Systems;
|
|
|
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
|
|
|
using SqlSugar;
|
|
|
|
|
|
|
|
|
|
namespace DS.WMS.Core.Application.Method
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 申请单基础实现
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <typeparam name="TEntity">实体的类型声明</typeparam>
|
|
|
|
|
public abstract class ApplicationService<TEntity> : FeeServiceBase, IApplicationService<TEntity>
|
|
|
|
|
where TEntity : ApplicationForm, new()
|
|
|
|
|
{
|
|
|
|
|
internal static readonly DetailCategory[] detailCategories = [
|
|
|
|
|
DetailCategory.InvoiceSettlement, DetailCategory.InvoiceIssuance,
|
|
|
|
|
DetailCategory.ChargeApplicationSettlement,DetailCategory.PaidApplicationSettlement];
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 适用于当前申请单的审核类型
|
|
|
|
|
/// </summary>
|
|
|
|
|
public abstract TaskBaseTypeEnum AuditType { get; }
|
|
|
|
|
|
|
|
|
|
readonly IClientFlowInstanceService flowService;
|
|
|
|
|
readonly Lazy<ICommonService> commonService;
|
|
|
|
|
readonly IAuditTaskService taskService;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="serviceProvider">DI容器</param>
|
|
|
|
|
public ApplicationService(IServiceProvider serviceProvider) : base(serviceProvider)
|
|
|
|
|
{
|
|
|
|
|
flowService = serviceProvider.GetRequiredService<IClientFlowInstanceService>();
|
|
|
|
|
commonService = new Lazy<ICommonService>(serviceProvider.GetRequiredService<ICommonService>());
|
|
|
|
|
taskService = serviceProvider.GetRequiredService<IAuditTaskService>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 根据业务编号及类型获取该票业务的币别
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="inquiry">业务ID与业务类型</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult<List<FeeClient>>> GetCurrenciesAsync(DetailInquiry inquiry)
|
|
|
|
|
{
|
|
|
|
|
var bizIds = inquiry.Items.Select(x => x.Id).Distinct();
|
|
|
|
|
var types = inquiry.Items.Select(x => x.BusinessType).Distinct();
|
|
|
|
|
var cIds = inquiry.Items.Select(x => x.CustomerId).Distinct();
|
|
|
|
|
|
|
|
|
|
var list = await TenantDb.Queryable<FeeRecord>()
|
|
|
|
|
.Where(f => bizIds.Contains(f.BusinessId) && types.Contains(f.BusinessType) && cIds.Contains(f.CustomerId)
|
|
|
|
|
&& f.FeeStatus == FeeStatus.AuditPassed)
|
|
|
|
|
.Select(f => new
|
|
|
|
|
{
|
|
|
|
|
f.BusinessId,
|
|
|
|
|
f.BusinessType,
|
|
|
|
|
f.CustomerId,
|
|
|
|
|
f.Currency
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
|
|
|
|
|
var currencies = list.GroupBy(x => new { x.BusinessId, x.BusinessType, x.CustomerId }).Select(x => new FeeClient
|
|
|
|
|
{
|
|
|
|
|
Id = x.Key.BusinessId,
|
|
|
|
|
BusinessType = x.Key.BusinessType,
|
|
|
|
|
CustomerId = x.Key.CustomerId,
|
|
|
|
|
ExchangeRates = x.GroupBy(y => y.Currency).Select(y => new CurrencyExchangeRate
|
|
|
|
|
{
|
|
|
|
|
Currency = y.Key
|
|
|
|
|
}).ToList()
|
|
|
|
|
}).ToList();
|
|
|
|
|
|
|
|
|
|
return DataResult<List<FeeClient>>.Success(currencies);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region 保存
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 提交保存费用申请单
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="application">申请单</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public async Task<DataResult<TEntity>> SaveAsync(TEntity application)
|
|
|
|
|
{
|
|
|
|
|
TEntity? dbValue = null;
|
|
|
|
|
if (application.Id > 0)
|
|
|
|
|
{
|
|
|
|
|
application.BuildOption = BuildOption.Update;
|
|
|
|
|
|
|
|
|
|
//修改需检查申请单状态
|
|
|
|
|
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>.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var result = EnsureApplication(application, dbValue);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return DataResult<TEntity>.Failed(result.Message, result.MultiCode);
|
|
|
|
|
|
|
|
|
|
List<FeeRecord> fees = [];
|
|
|
|
|
if (application.Details.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
application.Details = application.Details.FindAll(x => x.Id == 0);
|
|
|
|
|
|
|
|
|
|
if (application.Details.GroupBy(x => x.CustomerName).Select(x => x.Key).Count() > 1)
|
|
|
|
|
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.DetailCustomerOnlyOne));
|
|
|
|
|
|
|
|
|
|
if (application.Details.GroupBy(x => x.RecordId).Where(g => g.Count() > 1).Select(x => x.Key).Count() > 0)
|
|
|
|
|
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.ApplicationRecordOnlyOne));
|
|
|
|
|
|
|
|
|
|
//申请金额禁止为0
|
|
|
|
|
if (application.Details.Any(x => x.ApplyAmount == 0))
|
|
|
|
|
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.AmountCannotBeZero));
|
|
|
|
|
|
|
|
|
|
var ids = application.Details.Select(x => x.RecordId).Distinct();
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
detail.ApplicationId = application.Id;
|
|
|
|
|
var fee = fees.Find(x => x.Id == detail.RecordId);
|
|
|
|
|
detail.ExchangeRate = detail.ExchangeRate ?? fee.ExchangeRate;
|
|
|
|
|
detail.FeeId = fee.FeeId;
|
|
|
|
|
detail.FeeName = fee.FeeName;
|
|
|
|
|
detail.FeeType = fee.FeeType;
|
|
|
|
|
detail.CustomerName = detail.CustomerName ?? application.CustomerName;
|
|
|
|
|
|
|
|
|
|
//原币申请
|
|
|
|
|
if (application.Currency.IsNullOrEmpty())
|
|
|
|
|
{
|
|
|
|
|
detail.OriginalAmount = detail.ApplyAmount;
|
|
|
|
|
|
|
|
|
|
if (detail.OriginalCurrency.IsNullOrEmpty())
|
|
|
|
|
detail.OriginalCurrency = fee.Currency;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = CalculateAmount(application, fees);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return DataResult<TEntity>.Failed(result.Message, result.MultiCode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await PreSaveAsync(application);
|
|
|
|
|
|
|
|
|
|
//关联导航属性插入
|
|
|
|
|
if (application.Id == 0)
|
|
|
|
|
{
|
|
|
|
|
//创建时需要生成申请单编号
|
|
|
|
|
var sequence = commonService.Value.GetSequenceNext<TEntity>();
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
if (application.Details.Count > 0)
|
|
|
|
|
await TenantDb.Insertable(application.Details).ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await OnSaveAsync(application, fees);
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
|
|
|
|
|
var postResult = await PostSaveAsync(application);
|
|
|
|
|
return postResult;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult<TEntity>.FailedWithDesc(nameof(MultiLanguageConst.Operation_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);
|
|
|
|
|
if (!string.IsNullOrEmpty(request.Application.Currency)) //非原币申请
|
|
|
|
|
{
|
|
|
|
|
var details = request.Application.Details.FindAll(x => x.Currency != request.Application.Currency);
|
|
|
|
|
foreach (var detail in details)
|
|
|
|
|
{
|
|
|
|
|
var fc = request.Items.Find(x => x.Id == detail.BusinessId && x.BusinessType == x.BusinessType);
|
|
|
|
|
var exchange = fc?.ExchangeRates?.Find(x => x.Currency == detail.Currency);
|
|
|
|
|
if (exchange == null)
|
|
|
|
|
return DataResult<TEntity>.Failed($"非原币申请必须传入费用原币与申请币别 {detail.Currency} 之间的汇率信息");
|
|
|
|
|
|
|
|
|
|
detail.ExchangeRate = exchange.ExchangeRate;
|
|
|
|
|
detail.ApplyAmount = Math.Round(detail.OriginalAmount * (exchange.ExchangeRate == null ? 1 : exchange.ExchangeRate.Value),
|
|
|
|
|
2, MidpointRounding.AwayFromZero);
|
|
|
|
|
detail.Currency = request.Application.Currency;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await SaveAsync(request.Application);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 用于申请单的状态检查
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="application">提交的申请单</param>
|
|
|
|
|
/// <param name="dbValue">数据库值,新增时为null</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual DataResult EnsureApplication(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>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual Task PreSaveAsync(TEntity application)
|
|
|
|
|
{
|
|
|
|
|
return Task.CompletedTask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在提交事务前,保存时调用
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="application">已保存的申请单</param>
|
|
|
|
|
/// <param name="fees">需要更新信息的费用记录</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual async Task OnSaveAsync(TEntity application, List<FeeRecord>? fees)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Updateable(application).IgnoreColumns(x => new
|
|
|
|
|
{
|
|
|
|
|
x.ApplicationNO,
|
|
|
|
|
x.Status,
|
|
|
|
|
x.CreateBy,
|
|
|
|
|
x.CreateTime,
|
|
|
|
|
x.Deleted,
|
|
|
|
|
x.DeleteBy,
|
|
|
|
|
x.DeleteTime
|
|
|
|
|
}).ExecuteCommandAsync();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在保存完成后调用
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="application">申请单</param>
|
|
|
|
|
protected virtual Task<DataResult<TEntity>> PostSaveAsync(TEntity application)
|
|
|
|
|
{
|
|
|
|
|
return Task.FromResult(DataResult<TEntity>.Success(application));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 获取业务所关联的申请明细
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="request"></param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected abstract Task<List<ApplicationDetail>> GetDetailsAsync(ApplicationRequest<TEntity> request);
|
|
|
|
|
|
|
|
|
|
#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();
|
|
|
|
|
|
|
|
|
|
foreach (var app in apps)
|
|
|
|
|
app.Details = details.FindAll(x => x.ApplicationId == app.Id);
|
|
|
|
|
|
|
|
|
|
var result = PreDelete(apps);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await OnDeleteDetailAsync(apps, DeleteOption.DetailOnly);
|
|
|
|
|
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.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在删除申请单或其明细之前调用,用于检查申请单状态
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="applications">申请单</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual DataResult PreDelete(List<TEntity> applications)
|
|
|
|
|
{
|
|
|
|
|
var ids = applications.Select(x => x.Id);
|
|
|
|
|
bool exists = TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.ApplicationId))
|
|
|
|
|
.InnerJoin<ApplicationDetail>((d1, d2) => d1.Id == d2.DetailId)
|
|
|
|
|
.Where((d1, d2) => d1.DetailId.HasValue && detailCategories.Contains(d2.Category.Value))
|
|
|
|
|
.Any();
|
|
|
|
|
if (exists)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationIsUsed));
|
|
|
|
|
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在执行删除申请单或其明细时调用
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="applications">申请单及其明细</param>
|
|
|
|
|
/// <param name="deleteOption">删除选项</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual Task OnDeleteDetailAsync(List<TEntity> applications, DeleteOption deleteOption)
|
|
|
|
|
{
|
|
|
|
|
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 details = await TenantDb.Queryable<ApplicationDetail>().Where(x => ids.Contains(x.ApplicationId)).Select(
|
|
|
|
|
x => new ApplicationDetail
|
|
|
|
|
{
|
|
|
|
|
Id = x.Id,
|
|
|
|
|
ApplicationId = x.ApplicationId,
|
|
|
|
|
RecordId = x.RecordId,
|
|
|
|
|
OriginalAmount = x.OriginalAmount
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
|
|
|
|
|
foreach (var app in apps)
|
|
|
|
|
app.Details = details.FindAll(x => x.ApplicationId == app.Id); await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
|
|
|
|
|
var result = PreDelete(apps);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
await OnDeleteDetailAsync(apps, DeleteOption.Entire);
|
|
|
|
|
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.FailedWithDesc(nameof(MultiLanguageConst.Operation_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(TaskBaseTypeEnum 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,
|
|
|
|
|
ApplicationNO = x.ApplicationNO,
|
|
|
|
|
Status = x.Status,
|
|
|
|
|
DetailCount = SqlFunc.AggregateCount(y.Id)
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
|
|
|
|
|
if (list.Count == 0)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
|
|
|
|
|
|
|
|
|
|
if (list.Exists(x => x.DetailCount == 0))
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ApplicationMustHaveDetail));
|
|
|
|
|
|
|
|
|
|
var result = PreSubmitApproval(list);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
List<TEntity> entities = new(idArray.Length);
|
|
|
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (await taskService.HasAuthorizedAsync())
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < list.Count; i++)
|
|
|
|
|
{
|
|
|
|
|
var item = list[i];
|
|
|
|
|
var req = new TaskCreationRequest
|
|
|
|
|
{
|
|
|
|
|
BusinessId = item.Id,
|
|
|
|
|
TaskTypeName = auditType.ToString(),
|
|
|
|
|
TaskTitle = $"【{auditType.GetDescription()}】{item.ApplicationNO}"
|
|
|
|
|
};
|
|
|
|
|
result = await taskService.CreateTaskAsync(req);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
var entity = new TEntity { Id = req.BusinessId };
|
|
|
|
|
OnSubmitApproval(entity);
|
|
|
|
|
entities.Add(entity);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
var template = await FindTemplateAsync(auditType);
|
|
|
|
|
if (template == null)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
|
|
|
|
|
OnSubmitApproval(item);
|
|
|
|
|
entities.Add(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await TenantDb.Updateable(entities).UpdateColumns(x => new { x.Status }).ExecuteCommandAsync();
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_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
|
|
|
|
|
}).ToListAsync();
|
|
|
|
|
|
|
|
|
|
if (list.Count == 0)
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
|
|
|
|
|
|
|
|
|
|
//未在审批状态中
|
|
|
|
|
if (!await flowService.Exists(ids: ids))
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInAudit));
|
|
|
|
|
|
|
|
|
|
DataResult result;
|
|
|
|
|
bool hasAuthorized = await taskService.HasAuthorizedAsync();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (hasAuthorized)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in list)
|
|
|
|
|
{
|
|
|
|
|
result = await taskService.WithdrawAsync(new TaskRequest
|
|
|
|
|
{
|
|
|
|
|
BusinessId = item.Id,
|
|
|
|
|
TaskTypeName = AuditType.ToString()
|
|
|
|
|
}, false);
|
|
|
|
|
|
|
|
|
|
OnWithdraw(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result = await flowService.WithdrawAsync(ids);
|
|
|
|
|
if (!result.Succeeded)
|
|
|
|
|
return result;
|
|
|
|
|
|
|
|
|
|
foreach (var item in list)
|
|
|
|
|
{
|
|
|
|
|
OnWithdraw(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await TenantDb.Updateable(list).UpdateColumns(x => new { x.Status }).ExecuteCommandAsync();
|
|
|
|
|
|
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
|
return DataResult.Success;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
|
|
|
await ex.LogAsync(Db);
|
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 在撤销审批时调用,用于更新申请单信息
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="application">申请单</param>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
protected virtual void OnWithdraw(TEntity application)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|