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.

1245 lines
51 KiB
C#

using System.Text;
using DS.Module.Core;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Fee.Dtos;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Fee.Interface;
7 months ago
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using DS.WMS.Core.Flow.Interface;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Sys.Entity;
using DS.WMS.Core.TaskInteraction.Dtos;
using DS.WMS.Core.TaskInteraction.Interface;
using Mapster;
using Masuit.Tools.Systems;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
namespace DS.WMS.Core.Fee.Method
{
/// <summary>
/// 费用记录实现
/// </summary>
public class FeeRecordService : FeeServiceBase, IFeeRecordService
{
const int BATCH_SIZE = 300;
7 months ago
readonly IClientFlowInstanceService flowService;
1 month ago
readonly IFeeTaskService feeTaskService;
readonly IFeeBillTaskService billService;
/// <summary>
/// 初始化
/// </summary>
/// <param name="serviceProvider"></param>
public FeeRecordService(IServiceProvider serviceProvider) : base(serviceProvider)
{
flowService = serviceProvider.GetRequiredService<IClientFlowInstanceService>();
1 month ago
feeTaskService = serviceProvider.GetRequiredService<IFeeTaskService>();
billService = serviceProvider.GetRequiredService<IFeeBillTaskService>();
}
/// <summary>
/// 列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<FeeRecordRes>>> GetListAsync(PageRequest request)
{
long UserId = long.Parse(User.UserId);
//序列化查询条件
var whereList = request.GetConditionalModels(Db);
//传递业务查询条件检测
string? bsId = null;
foreach (var item in whereList)
{
if (item is ConditionalModel conditionModel && string.Equals(conditionModel.FieldName, nameof(FeeRecord.BusinessId), StringComparison.OrdinalIgnoreCase))
{
bsId = conditionModel.FieldValue;
break;
}
}
//未指定业务ID返回空
if (string.IsNullOrEmpty(bsId))
return DataResult<List<FeeRecordRes>>.Success([]);
var data = await TenantDb.Queryable<FeeRecord>()
.Where(x => x.IsOpen || (!x.IsOpen && x.CreateBy == UserId))
.Where(whereList)
.Select<FeeRecordRes>()
.ToQueryPageAsync(request.PageCondition);
//关联用户名称
var UserIds = data.Data.Where(x => x.UpdateBy.HasValue).Select(x => x.UpdateBy.Value)
.Union(data.Data.Where(x => x.SubmitBy.HasValue).Select(x => x.SubmitBy.Value))
.Union(data.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 data.Data)
{
item.CreateByName = Users.Find(x => x.Id == item.CreateBy)?.UserName;
if (item.UpdateBy.HasValue)
item.UpdateByName = Users.Find(x => x.Id == item.UpdateBy.Value)?.UserName;
if (item.SubmitBy.HasValue)
item.SubmitByName = Users.Find(x => x.Id == item.SubmitBy.Value)?.UserName;
}
return data;
}
/// <summary>
/// 根据查询条件获取费用数据
/// </summary>
/// <param name="query"></param>
/// <returns></returns>
public async Task<DataResult<List<FeeRecord>>> GetListAsync(string query)
{
long UserId = long.Parse(User.UserId);
var src = TenantDb.Queryable<FeeRecord>().Where(x => x.IsOpen || (!x.IsOpen && x.CreateBy == UserId));
if (!query.IsNullOrEmpty())
{
//序列化查询条件
var whereList = Db.Utilities.JsonToConditionalModels(query);
src = src.Where(whereList);
}
var data = await src.ToListAsync();
return DataResult<List<FeeRecord>>.Success(data);
}
/// <summary>
/// 获取费用统计对象
/// </summary>
/// <param name="bsId">业务ID</param>
/// <param name="bsType">业务类型</param>
/// <returns></returns>
public async Task<FeeStatistics> GetFeeStatisticsAsync(long bsId, BusinessType bsType)
{
var list = await TenantDb.Queryable<FeeRecord>()
.Where(x => x.BusinessId == bsId && x.BusinessType == bsType).ToListAsync();
return new FeeStatistics(list);
}
/// <summary>
/// 获取已申请修改的费用记录值
/// </summary>
/// <param name="id">费用记录ID</param>
/// <returns></returns>
public async Task<DataResult<FeeModification>> GetModifyValue(long id)
{
var fm = await TenantDb.Queryable<FeeModification>().Where(x => x.FeeRecordId == id)
.OrderByDescending(x => x.CreateTime).Take(1).FirstAsync();
return DataResult<FeeModification>.Success(fm);
}
/// <summary>
/// 检查业务是否已费用锁定
/// </summary>
/// <param name="bid">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <param name="type">锁定范围</param>
/// <returns></returns>
internal async Task<bool> IsFeeLockedAsync(long bid, BusinessType businessType, FeeType type = FeeType.All)
{
bool? isFeeLocking = null;
switch (type)
{
case FeeType.Receivable:
break;
case FeeType.Payable:
break;
case FeeType.All:
isFeeLocking = await TenantDb.Queryable<BusinessFeeStatus>().Where(
x => x.BusinessId == bid && x.BusinessType == businessType).Select(x => x.IsFeeLocking).FirstAsync();
break;
}
return isFeeLocking.GetValueOrDefault();
}
/// <summary>
/// 费用提交
/// </summary>
/// <param name="items">要提交的费用记录</param>
/// <param name="excludeZeroFee">是否排除总价为零的费用</param>
/// <param name="useTransaction">是否使用事务</param>
/// <returns></returns>
public async Task<DataResult> SaveAsync(List<FeeRecord> items, bool excludeZeroFee = false, bool useTransaction = true)
{
4 months ago
ArgumentNullException.ThrowIfNull(items, nameof(items));
if (items.GroupBy(x => new { x.BusinessId, x.BusinessType }).Count() > 1)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeBusinessIdOnlyOne));
var first = items.Select(x => new { x.BusinessType, x.BusinessId }).FirstOrDefault();
if (await IsFeeLockedAsync(first.BusinessId, first.BusinessType))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeLocked));
var order = await TenantDb.Queryable<SeaExport>().Where(x => x.Id == first.BusinessId).Select(x => new
{
x.TEU,
x.KGS, //毛重
x.PKGS, //件数
x.CBM //尺码
}).FirstAsync();
if (order == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
//获取订单箱型箱量
string bsNo = first.BusinessId.ToString();
var ctns = await TenantDb.Queryable<OpCtn>().Where(y => y.BSNO == bsNo).Select(x => new
{
x.CtnCode,
x.CtnNum
}).ToListAsync();
4 months ago
foreach (var item in items)
{
if (item.Quantity == 0)
{
//逐个判定处理标准
switch (item.Unit)
{
case "HOUR": //小时
goto case "P";
case "GE": //个
goto case "P";
case "DAY": //天
goto case "P";
//case "XX": //箱型
// goto default;
case "JJZL": //计价重量
goto case "Z";
case "ZJ": //总价
goto case "P";
case "JZ": //净重
item.Quantity = 0;
break;
case "TEU": //TEU
item.Quantity = order.TEU;
break;
case "JF": //计费吨
item.Quantity = order.KGS.GetValueOrDefault() / 1000 > order.CBM.GetValueOrDefault() ? order.KGS.GetValueOrDefault() : order.CBM.GetValueOrDefault();
break;
case "J": //件数
item.Quantity = order.PKGS.GetValueOrDefault();
break;
case "C": //尺码
item.Quantity = order.CBM.GetValueOrDefault();
break;
case "Z": //重量
item.Quantity = order.KGS.GetValueOrDefault();
break;
case "P": //单票
item.Quantity = 1;
break;
default: //查找箱型标准
var ctn = ctns.Find(x => x.CtnCode == item.Unit);
item.Quantity = ctn == null ? 0 : ctn.CtnNum.GetValueOrDefault();
break;
}
}
//计算税费
4 months ago
item.SetTax();
}
if (excludeZeroFee) //过滤掉数量为0的费用
items = items.FindAll(x => x.Amount != 0);
4 months ago
DateTime dtNow = DateTime.Now;
if (useTransaction)
await TenantDb.Ado.BeginTranAsync();
try
{
List<FeeRecord>? fees = null;
var feeIds = items.Where(x => x.Id > 0).Select(x => x.Id).ToArray();
//包含修改的项,需要检测费用状态再修改
if (feeIds.Length > 0)
{
fees = await TenantDb.Queryable<FeeRecord>().Where(x => feeIds.Contains(x.Id)).Select(x => new FeeRecord
{
Id = x.Id,
FeeName = x.FeeName,
FeeStatus = x.FeeStatus
}).ToListAsync();
StringBuilder sb = new StringBuilder();
foreach (var fe in fees)
{
7 months ago
if (fe.FeeStatus != FeeStatus.Entering && fe.FeeStatus != FeeStatus.RejectSubmission)
{
2 months ago
sb.AppendFormat(MultiLanguageConst.GetDescription(MultiLanguageConst.FeeRecordStatus), fe.FeeName);
continue;
}
}
if (sb.Length > 0)
return DataResult.Failed(sb.ToString(), MultiLanguageConst.Operation_Failed);
}
4 months ago
var localCurrency = await Db.Queryable<SysOrg>().Where(x => x.Id == User.OrgId).Select(x => x.LocalCurrency).FirstAsync();
foreach (var item in items)
{
if (string.IsNullOrEmpty(item.LocalCurrency))
{
4 months ago
//默认本位币为机构本位币或CNY
if (item.Id == 0)
item.LocalCurrency = localCurrency ?? FeeCurrency.RMB_CODE;
else
item.LocalCurrency = fees?.Find(x => x.Id == item.Id)?.LocalCurrency;
}
if (item.LocalCurrency == item.Currency)
item.ExchangeRate = 1m;
}
//若计价货币单位不等于本位币则尝试获取最新汇率
await FetchExchangeRateAsync(items);
var updateList = items.Where(x => x.Id > 0).ToList();
if (updateList.Count > 0)
await TenantDb.Updateable(updateList).IgnoreColumns(x => new
{
x.FeeStatus,
x.BusinessId,
x.BusinessType,
x.CreateBy,
x.CreateTime,
x.DeleteBy,
x.Deleted,
x.DeleteTime,
x.SubmitDate,
x.SubmitBy,
x.AuditBy,
x.AuditOperator,
x.AuditDate
}).ExecuteCommandAsync();
var createList = items.Where(x => x.Id == 0).ToList();
if (createList.Count > 0)
{
if (createList.Count >= BATCH_SIZE)
{
await TenantDb.Fastest<FeeRecord>().BulkCopyAsync(createList);
}
else
{
await TenantDb.Insertable(createList).ExecuteCommandAsync();
}
}
if (useTransaction)
await TenantDb.Ado.CommitTranAsync();
var list = createList.Union(updateList).Select(x => x.Adapt<FeeRecordRes>());
var result = DataResult.Success;
result.Data = list.Select(x => x.Id);
await WriteBackStatusAsync(first.BusinessId, first.BusinessType);
return result;
}
catch (Exception ex)
{
if (useTransaction)
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
/// <summary>
/// 费用保存后提交审核
/// </summary>
/// <param name="items">要提交的费用记录</param>
/// <param name="excludeZeroFee">是否排除总价为零的费用</param>
/// <param name="useTransaction">是否使用事务</param>
/// <returns></returns>
public async Task<DataResult> SaveAndSubmitAsync(List<FeeRecord> items, bool excludeZeroFee = false, bool useTransaction = true)
{
var result = await SaveAsync(items, excludeZeroFee, useTransaction);
if (!result.Succeeded)
return result;
var ids = items.Select(x => x.Id).ToArray();
ids = await TenantDb.Queryable<FeeRecord>().Where(x => ids.Contains(x.Id) && (x.FeeStatus == FeeStatus.Entering || x.FeeStatus == FeeStatus.RejectSubmission || x.FeeStatus == FeeStatus.RejectApplication)).Select(x => x.Id).ToArrayAsync();
if (ids.Length > 0)
result = await SubmitForApprovalAsync(TaskBaseTypeEnum.FEE_AUDIT, string.Empty, ids);
return result;
}
/// <summary>
/// 根据模板ID创建
/// </summary>
/// <param name="bid">业务ID</param>
7 months ago
/// <param name="businessType">业务类型</param>
7 months ago
/// <param name="tidArray">模板ID</param>
/// <returns></returns>
public async Task<DataResult> CreateByTemplateAsync(long bid, BusinessType businessType, params long[] tidArray)
{
bool hasExists = TenantDb.Queryable<FeeRecord>().LeftJoin<FeeTemplateDetail>((x, y) =>
x.FeeId == y.FeeId && x.FeeType == y.FeeType).Any(
(x, y) => x.BusinessId == bid && x.BusinessType == businessType && tidArray.Contains(y.TemplateId));
if (hasExists)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordExist));
var details = await TenantDb.Queryable<FeeTemplateDetail>().Where(x => tidArray.Contains(x.TemplateId) && !x.Deleted).Select(x => new
{
x.FeeType,
x.FeeId,
x.FeeCode,
x.FeeName,
x.FeeFrt,
x.FeeGroup,
x.CustomerName,
x.CustomerType,
x.CustomerId,
x.Unit,
x.UnitPrice,
x.Currency,
x.ExchangeRate,
x.Tax,
x.TaxRate,
x.AccTaxRate,
x.IsAdvancedPay,
x.IsInvoice,
x.SaleOrgId,
x.Note
}).ToListAsync();
7 months ago
List<FeeRecord> records = new List<FeeRecord>(details.Count);
foreach (var item in details)
{
var record = item.Adapt<FeeRecord>();
record.BusinessId = bid;
record.SubmitDate = DateTime.Now;
records.Add(record);
}
//若计价货币单位不等于默认货币则尝试获取最新汇率
await FetchExchangeRateAsync(records);
int result = await TenantDb.Insertable(records).ExecuteCommandAsync();
await WriteBackStatusAsync(bid, businessType);
return result > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
/// <summary>
/// 删除
/// </summary>
/// <param name="ids">费用记录ID</param>
/// <returns></returns>
public async Task<DataResult> DeleteAsync(params long[] ids)
{
var model = await TenantDb.Queryable<FeeRecord>().Where(x => ids.Contains(x.Id)).Select(x => new { x.BusinessId, x.BusinessType }).FirstAsync();
if (await IsFeeLockedAsync(model.BusinessId, model.BusinessType))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeLocked));
if (await TenantDb.Queryable<FeeRecord>().AnyAsync(x => ids.Contains(x.Id) && (x.FeeStatus != FeeStatus.Entering && x.FeeStatus != FeeStatus.RejectSubmission)))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordDelete));
int result = await TenantDb.Deleteable<FeeRecord>(x => ids.Contains(x.Id)).ExecuteCommandAsync();
await WriteBackStatusAsync(model.BusinessId, model.BusinessType);
return result > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
7 months ago
}
1 month ago
#region 审核相关
7 months ago
/// <summary>
/// 发起审批/申请删除工作流
7 months ago
/// </summary>
/// <param name="auditType">审批类型</param>
/// <param name="remark">备注</param>
/// <param name="ids">费用记录ID</param>
7 months ago
/// <returns></returns>
public async Task<DataResult> SubmitForApprovalAsync(TaskBaseTypeEnum auditType, string remark, params long[] ids)
7 months ago
{
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => ids.Contains(x.Id)).Select(
7 months ago
x => new FeeRecord
{
Id = x.Id,
FeeName = x.FeeName,
FeeStatus = x.FeeStatus,
BusinessId = x.BusinessId,
BusinessType = x.BusinessType
}).ToListAsync();
if (fees.IsNullOrEmpty())
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordNotExist));
var bid = fees[0].BusinessId;
var bType = fees[0].BusinessType;
//业务状态检测
if (await IsFeeLockedAsync(bid, bType))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeLocked));
if (await flowService.IsRunning(auditType, null, ids))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordIsAuditing));
7 months ago
if (fees.Any(x => x.FeeStatus == FeeStatus.PartialSettlement || x.FeeStatus == FeeStatus.SettlementCompleted))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordIsSettled));
DataResult result = DataResult.Success;
await TenantDb.Ado.BeginTranAsync();
try
{
if (auditType == TaskBaseTypeEnum.FEE_AUDIT)
{
result = await ApplyAuditAsync(fees);
}
else if (auditType == TaskBaseTypeEnum.FEE_DELETE_AUDIT)
{
result = await ApplyDeleteAsync(fees, remark);
}
if (!result.Succeeded)
return result;
await TenantDb.Updateable(fees).UpdateColumns(x => new
{
x.Id,
x.FeeStatus,
x.SubmitBy,
x.SubmitDate
}).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));
}
}
//录入->提交审核
async Task<DataResult> ApplyAuditAsync(List<FeeRecord> fees)
{
StringBuilder sb = new StringBuilder();
foreach (var fe in fees)
{
if (fe.FeeStatus != FeeStatus.Entering && fe.FeeStatus != FeeStatus.RejectSubmission)
{
sb.AppendFormat(MultiLanguageConst.FeeRecordStatus, fe.FeeName);
continue;
}
}
if (sb.Length > 0)
return DataResult.Failed(sb.ToString(), MultiLanguageConst.Operation_Failed);
DataResult result;
DateTime dtNow = DateTime.Now;
1 month ago
if (await feeTaskService.HasAuthorizedAsync())
{
var requests = fees.Select(x => new TaskCreationRequest
{
BusinessId = x.Id,
TaskTypeName = TaskBaseTypeEnum.FEE_AUDIT.ToString(),
TaskTitle = $"【{TaskBaseTypeEnum.FEE_AUDIT.GetDescription()}】{x.FeeName}"
});
foreach (var request in requests)
{
1 month ago
result = await feeTaskService.CreateTaskAsync(request, false);
if (!result.Succeeded)
return result;
var fee = fees.Find(x => x.Id == request.BusinessId);
//变更状态为提交审核
fee.FeeStatus = FeeStatus.AuditSubmitted;
fee.SubmitBy = long.Parse(User.UserId);
fee.SubmitDate = dtNow;
}
return DataResult.Success;
}
var template = await FindTemplateAsync(TaskBaseTypeEnum.FEE_AUDIT);
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
foreach (var item in fees)
{
result = flowService.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = item.Id,
BusinessType = item.BusinessType,
TemplateId = template.Id
});
if (result.Succeeded)
{
var instance = result.Data as FlowInstance;
flowService.StartFlowInstance(instance.Id.ToString());
//变更状态为提交审核
item.FeeStatus = FeeStatus.AuditSubmitted;
item.SubmitBy = long.Parse(User.UserId);
item.SubmitDate = dtNow;
}
}
return DataResult.Success;
}
//审核通过->申请删除
async Task<DataResult> ApplyDeleteAsync(List<FeeRecord> fees, string reason)
{
StringBuilder sb = new StringBuilder();
foreach (var fe in fees)
{
if (fe.FeeStatus != FeeStatus.AuditPassed && fe.FeeStatus != FeeStatus.RejectApplication)
{
sb.AppendFormat(MultiLanguageConst.FeeRecordStatus, fe.FeeName);
continue;
}
}
if (sb.Length > 0)
return DataResult.Failed(sb.ToString(), MultiLanguageConst.Operation_Failed);
DataResult result;
DateTime dtNow = DateTime.Now;
1 month ago
if (await feeTaskService.HasAuthorizedAsync())
{
var requests = fees.Select(x => new TaskCreationRequest
{
BusinessId = x.Id,
TaskTypeName = TaskBaseTypeEnum.FEE_AUDIT.ToString(),
TaskTitle = $"【{TaskBaseTypeEnum.FEE_AUDIT.GetDescription()}】{x.FeeName}"
});
foreach (var request in requests)
{
1 month ago
result = await feeTaskService.CreateTaskAsync(request, false);
if (!result.Succeeded)
return result;
var fee = fees.Find(x => x.Id == request.BusinessId);
//变更状态为申请删除
fee.FeeStatus = FeeStatus.ApplyDeletion;
fee.SubmitBy = long.Parse(User.UserId);
fee.SubmitDate = dtNow;
fee.Reason = reason;
}
return DataResult.Success;
}
var template = await FindTemplateAsync(TaskBaseTypeEnum.FEE_DELETE_AUDIT);
7 months ago
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
7 months ago
foreach (var item in fees)
7 months ago
{
result = flowService.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = item.Id,
BusinessType = item.BusinessType,
TemplateId = template.Id
});
7 months ago
if (result.Succeeded)
{
var instance = result.Data as FlowInstance;
flowService.StartFlowInstance(instance.Id.ToString());
//变更状态为申请删除
item.FeeStatus = FeeStatus.ApplyDeletion;
item.SubmitBy = long.Parse(User.UserId);
item.SubmitDate = dtNow;
6 months ago
item.Reason = reason;
}
}
return DataResult.Success;
}
/// <summary>
/// 发起费用修改申请
/// </summary>
/// <param name="items">费用修改信息</param>
/// <returns></returns>
public async Task<DataResult> SubmitForModificationAsync(IEnumerable<FeeModification> items)
{
var idList = items.Select(x => x.FeeRecordId).Distinct().ToList();
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => idList.Contains(x.Id)).Select(x => new FeeRecord
{
Id = x.Id,
FeeName = x.FeeName,
FeeStatus = x.FeeStatus
}).ToListAsync();
if (fees.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordNotExist));
StringBuilder sb = new StringBuilder();
foreach (var fe in fees)
{
if (fe.FeeStatus != FeeStatus.AuditPassed && fe.FeeStatus != FeeStatus.RejectApplication)
{
sb.AppendFormat(MultiLanguageConst.FeeRecordStatus, fe.FeeName);
continue;
}
}
if (sb.Length > 0)
return DataResult.Failed(sb.ToString(), MultiLanguageConst.Operation_Failed);
DataResult result;
DateTime dtNow = DateTime.Now;
await TenantDb.Ado.BeginTranAsync();
try
{
1 month ago
if (await feeTaskService.HasAuthorizedAsync())
{
var requests = fees.Select(x => new TaskCreationRequest
{
BusinessId = x.Id,
TaskTypeName = TaskBaseTypeEnum.FEE_AUDIT.ToString(),
TaskTitle = $"【{TaskBaseTypeEnum.FEE_AUDIT.GetDescription()}】{x.FeeName}"
});
foreach (var request in requests)
{
1 month ago
result = await feeTaskService.CreateTaskAsync(request, false);
if (!result.Succeeded)
return result;
var fee = fees.Find(x => x.Id == request.BusinessId);
//变更状态为申请修改
fee.FeeStatus = FeeStatus.ApplyModification;
6 months ago
fee.Reason = items.FirstOrDefault(x => x.FeeRecordId == fee.Id)?.Reason;
}
7 months ago
}
else
{
var template = await FindTemplateAsync(TaskBaseTypeEnum.FEE_MODIFY_AUDIT);
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
foreach (var fee in fees)
{
result = flowService.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = fee.Id,
BusinessType = fee.BusinessType,
TemplateId = template.Id
});
if (result.Succeeded)
{
var instance = result.Data as FlowInstance;
flowService.StartFlowInstance(instance.Id.ToString());
//变更状态为申请修改
fee.FeeStatus = FeeStatus.ApplyModification;
fee.Reason = items.FirstOrDefault(x => x.FeeRecordId == fee.Id)?.Reason;
}
}
}
7 months ago
var list = items.ToList();
await TenantDb.Insertable(list).ExecuteCommandAsync();
await TenantDb.Updateable(fees).UpdateColumns(x => new { x.FeeStatus }).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="ids">费用记录ID</param>
/// <returns></returns>
public async Task<DataResult> WithdrawAsync(params long[] ids)
{
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => ids.Contains(x.Id)).Select(
7 months ago
x => new FeeRecord
{
Id = x.Id,
BusinessId = x.BusinessId,
BusinessType = x.BusinessType,
7 months ago
FeeName = x.FeeName,
FeeStatus = x.FeeStatus
}).ToListAsync();
if (fees.Count == 0)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
DataResult result;
List<Tuple<TaskBaseTypeEnum, long>> taskTypes = [];
DateTime dtNow = DateTime.Now;
await TenantDb.Ado.BeginTranAsync();
try
{
foreach (var item in fees)
{
switch (item.FeeStatus)
{
case FeeStatus.AuditSubmitted:
item.FeeStatus = FeeStatus.Entering;
taskTypes.Add(new Tuple<TaskBaseTypeEnum, long>(TaskBaseTypeEnum.FEE_AUDIT, item.Id));
break;
case FeeStatus.ApplyModification:
item.FeeStatus = FeeStatus.AuditPassed;
taskTypes.Add(new Tuple<TaskBaseTypeEnum, long>(TaskBaseTypeEnum.FEE_MODIFY_AUDIT, item.Id));
//删除暂存数据
var entity = await TenantDb.Queryable<FeeModification>().OrderByDescending(
x => x.CreateTime).Select(x => new { x.Id, x.FeeRecordId }).FirstAsync(x => x.FeeRecordId == item.Id);
if (entity != null)
await TenantDb.Deleteable<FeeModification>().Where(x => x.Id == entity.Id).ExecuteCommandAsync();
break;
case FeeStatus.ApplyDeletion:
item.FeeStatus = FeeStatus.AuditPassed;
taskTypes.Add(new Tuple<TaskBaseTypeEnum, long>(TaskBaseTypeEnum.FEE_DELETE_AUDIT, item.Id));
break;
}
item.SubmitBy = null;
item.SubmitDate = null;
}
var groups = taskTypes.GroupBy(x => x.Item1);
1 month ago
if (await feeTaskService.HasAuthorizedAsync())
{
foreach (var group in groups)
{
foreach (var item in group)
{
1 month ago
result = await feeTaskService.WithdrawAsync(new TaskRequest
{
BusinessId = item.Item2,
TaskTypeName = item.Item1.ToString(),
ExtraData = fees.Find(x => x.Id == item.Item2)
}, false);
if (!result.Succeeded)
return result;
}
}
}
else
{
//未在审批状态中
if (!await flowService.Exists(ids: ids))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInAudit));
foreach (var g in groups)
{
result = await flowService.WithdrawAsync(g.Key, g.Select(x => x.Item2).ToArray());
if (!result.Succeeded)
return result;
}
}
await TenantDb.Updateable(fees).UpdateColumns(x => new { x.FeeStatus, x.SubmitBy, x.SubmitDate }).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));
}
7 months ago
}
/// <summary>
/// 整票审核
/// </summary>
/// <param name="bid">业务ID</param>
/// <param name="type">业务类型</param>
/// <param name="taskType">任务类型</param>
/// <returns></returns>
public async Task<DataResult> SubmitBillAuditAsync(long bid, BusinessType type, TaskBaseTypeEnum taskType)
{
var entity = await TenantDb.Queryable<BusinessFeeStatus>().Where(x => x.BusinessId == bid && x.BusinessType == type)
.Select(x => new BusinessFeeStatus
{
Id = x.Id,
IsFeeLocking = x.IsFeeLocking,
BillAuditStatus = x.BillAuditStatus
}).FirstAsync();
if (entity == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.BusinessNotFound));
if (entity.IsFeeLocking.GetValueOrDefault())
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeLocked));
if (taskType == TaskBaseTypeEnum.BILL_RECV_AUDIT)
{
if (entity.BillAuditStatus != BillAuditStatus.Pending && entity.BillAuditStatus != BillAuditStatus.RecvRejected)
1 month ago
return DataResult.Failed(string.Format(
MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BillFeeStatusError)), entity.BillAuditStatus.GetDescription()));
}
else if (taskType == TaskBaseTypeEnum.BILL_PAY_AUDIT)
{
if (entity.BillAuditStatus != BillAuditStatus.RecvPassed && entity.BillAuditStatus != BillAuditStatus.PayRejected)
1 month ago
return DataResult.Failed(string.Format(
MultiLanguageConst.GetDescription(nameof(MultiLanguageConst.BillFeeStatusError)), entity.BillAuditStatus.GetDescription()));
}
else
{
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskNotSupported));
}
if (await flowService.IsRunning(taskType, type, bid))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordIsAuditing));
DataResult result;
await TenantDb.Ado.BeginTranAsync();
try
{
if (await billService.HasAuthorizedAsync())
{
string? bizNo = null;
switch (type)
{
case BusinessType.OceanShippingExport:
bizNo = await TenantDb.Queryable<SeaExport>().Where(x => x.Id == bid).Select(x => x.CustomerNo).FirstAsync();
break;
}
result = await billService.CreateTaskAsync(new TaskCreationRequest
{
BusinessId = bid,
BusinessType = type,
TaskTypeName = taskType.ToString(),
TaskTitle = $"【{taskType.GetDescription()}】【{type.GetDescription()}】{bizNo}"
}, false);
}
else
{
var template = await FindTemplateAsync(taskType);
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
result = flowService.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = entity.Id,
BusinessType = entity.BusinessType,
TemplateId = template.Id
});
var instance = result.Data as FlowInstance;
flowService.StartFlowInstance(instance.Id.ToString());
}
if (!result.Succeeded)
return result;
//变更状态为提交审核
if (taskType == TaskBaseTypeEnum.BILL_RECV_AUDIT)
entity.BillAuditStatus = BillAuditStatus.RecvSubmitted;
else if (taskType == TaskBaseTypeEnum.BILL_PAY_AUDIT)
entity.BillAuditStatus = BillAuditStatus.PaySubmitted;
await TenantDb.Updateable(entity).UpdateColumns(x => new
{
x.BillAuditStatus
}).ExecuteCommandAsync();
//修改关联费用状态为提交审核
await TenantDb.Updateable<FeeRecord>().Where(x => x.BusinessId == entity.BusinessId && x.BusinessType == entity.BusinessType &&
(x.FeeStatus == FeeStatus.Entering || x.FeeStatus == FeeStatus.Withdraw || x.FeeStatus == FeeStatus.RejectSubmission))
.SetColumns(x => x.FeeStatus == FeeStatus.AuditSubmitted).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="bid">业务ID</param>
/// <param name="type">业务类型</param>
/// <param name="taskType">任务类型</param>
/// <returns></returns>
public async Task<DataResult> WithdrawBillAsync(long bid, BusinessType type, TaskBaseTypeEnum taskType)
{
var entity = await TenantDb.Queryable<BusinessFeeStatus>().Where(x => x.BusinessId == bid && x.BusinessType == type)
.Select(x => new BusinessFeeStatus
{
Id = x.Id,
IsFeeLocking = x.IsFeeLocking,
BillAuditStatus = x.BillAuditStatus
}).FirstAsync();
if (entity == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.BusinessNotFound));
if (entity.IsFeeLocking.GetValueOrDefault())
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeLocked));
if (taskType == TaskBaseTypeEnum.BILL_RECV_AUDIT)
{
if (entity.BillAuditStatus != BillAuditStatus.RecvSubmitted)
return DataResult.Failed(string.Format(MultiLanguageConst.BusinessStatusError, entity.BillAuditStatus.GetDescription()));
}
else if (taskType == TaskBaseTypeEnum.BILL_PAY_AUDIT)
{
if (entity.BillAuditStatus != BillAuditStatus.PaySubmitted)
return DataResult.Failed(string.Format(MultiLanguageConst.BusinessStatusError, entity.BillAuditStatus.GetDescription()));
}
else
{
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TaskNotSupported));
}
await TenantDb.Ado.BeginTranAsync();
try
{
DataResult result = DataResult.Success;
if (await billService.HasAuthorizedAsync())
{
await billService.WithdrawAsync(new TaskRequest
{
BusinessId = bid,
BusinessType = type,
TaskTypeName = taskType.ToString()
}, false);
}
else
{
//未在审批状态中
if (!await flowService.Exists(type: taskType, businessType: type, ids: [bid]))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInAudit));
result = await flowService.WithdrawAsync(taskType, [bid], type);
if (!result.Succeeded)
return result;
}
//变更状态为提交审核
if (taskType == TaskBaseTypeEnum.BILL_RECV_AUDIT)
entity.BillAuditStatus = BillAuditStatus.Pending;
else if (taskType == TaskBaseTypeEnum.BILL_PAY_AUDIT)
entity.BillAuditStatus = BillAuditStatus.RecvPassed;
await TenantDb.Updateable(entity).UpdateColumns(x => new
{
x.BillAuditStatus
}).ExecuteCommandAsync();
await TenantDb.Ado.CommitTranAsync();
return result;
}
catch (Exception ex)
{
await TenantDb.Ado.RollbackTranAsync();
await ex.LogAsync(Db);
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
1 month ago
#endregion
/// <summary>
/// 设置发票启用状态
/// </summary>
/// <param name="enabled">是否启用</param>
/// <param name="idArray">费用记录ID</param>
/// <returns></returns>
public async Task<DataResult> SetInvoiceEnabledAsync(bool enabled, params long[] idArray)
{
var list = idArray.Select(x => new FeeRecord { Id = x, IsInvoice = enabled }).ToList();
int rows = await TenantDb.Updateable(list).UpdateColumns(x => new { x.IsInvoice }).ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
/// <summary>
/// 设置费用对象
/// </summary>
/// <param name="customerId">费用对象ID</param>
/// <param name="customerType">客户类别</param>
/// <param name="idArray">费用记录ID</param>
/// <returns></returns>
public async Task<DataResult> SetCustomerAsync(long customerId, string customerType, params long[] idArray)
{
var model = await TenantDb.Queryable<InfoClient>().Where(x => x.Id == customerId).Select(x => new
{
Id = customerId,
x.CodeName,
x.Name
}).FirstAsync();
if (model == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.EmptyData));
var list = idArray.Select(x => new FeeRecord
{
Id = x,
CustomerId = customerId,
CustomerCode = model.CodeName,
CustomerName = model.Name,
CustomerType = customerType
}).ToList();
int rows = await TenantDb.Updateable(list).UpdateColumns(x => new { x.CustomerId, x.CustomerCode, x.CustomerName, x.CustomerType }).ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
//// <summary>
/// 获取费用打印信息
/// </summary>
/// <param name="providerName">数据提供程序</param>
/// <param name="bsId">业务ID</param>
/// <param name="bsType">业务类型</param>
/// <param name="ids">费用记录ID</param>
/// <returns></returns>
public async Task<DataResult<dynamic>> GetPrintInfoAsync(string providerName, long bsId, BusinessType bsType, params long[] ids)
{
Type type = Type.GetType(providerName, false);
if (type == null)
return DataResult<dynamic>.Failed("未能找到数据提供程序:" + providerName);
var provider = Fasterflect.ConstructorExtensions.CreateInstance(type) as IReportProvider;
if (provider == null)
return DataResult<dynamic>.Failed("未能找到数据提供程序:" + providerName);
var context = new ReportContext
{
BusinessId = bsId,
BusinessType = bsType,
Ids = ids,
Db = Db,
TenantDb = TenantDb,
User = User,
ServiceProvider = ServiceProvider
};
var data = await provider.GetDataAsync(context);
if (context.ErrorResult == null)
return DataResult<dynamic>.Success(data);
return DataResult<dynamic>.Failed(context.ErrorResult.Message, context.ErrorResult.MultiCode);
}
/// <summary>
/// 回写业务表费用状态
/// </summary>
/// <param name="businessId">业务ID</param>
/// <param name="businessType">业务类型</param>
/// <returns></returns>
public async Task WriteBackStatusAsync(long businessId, BusinessType businessType)
{
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => x.BusinessId == businessId)
.Select(x => new FeeRecord
{
FeeType = x.FeeType,
FeeStatus = x.FeeStatus
}).ToListAsync();
if (fees.IsNullOrEmpty())
return;
var arFeeStatus = DetermineStatus(fees.FindAll(x => x.FeeType == FeeType.Receivable));
var apFeeStatus = DetermineStatus(fees.FindAll(x => x.FeeType == FeeType.Payable));
if (arFeeStatus != null || apFeeStatus != null)
{
var upt = TenantDb.Updateable<BusinessFeeStatus>();
if (arFeeStatus != null)
{
upt = upt.SetColumns(x => x.ARFeeStatus == arFeeStatus);
}
if (apFeeStatus != null)
{
upt = upt.SetColumns(x => x.APFeeStatus == apFeeStatus);
}
try
{
await upt.Where(x => x.BusinessType == businessType && x.BusinessId == businessId).ExecuteCommandAsync();
}
catch (Exception ex)
{
await ex.LogAsync(Db);
}
}
}
//业务表费用状态判定
static BillFeeStatus? DetermineStatus(List<FeeRecord> fees)
{
BillFeeStatus? billFeeStatus = null;
if (fees.Count == 0)
{
billFeeStatus = BillFeeStatus.NotEntered;
}
//全状态
else if (fees.All(x => x.FeeStatus == FeeStatus.Entering))
{
billFeeStatus = BillFeeStatus.Entering;
}
else if (fees.All(x => x.FeeStatus == FeeStatus.AuditSubmitted))
{
billFeeStatus = BillFeeStatus.AuditSubmitted;
}
else if (fees.All(x => x.FeeStatus == FeeStatus.AuditPassed))
{
billFeeStatus = BillFeeStatus.AuditPassed;
}
else if (fees.All(x => x.FeeStatus == FeeStatus.RejectSubmission))
{
billFeeStatus = BillFeeStatus.RejectSubmission;
}
else if (fees.All(x => x.FeeStatus == FeeStatus.PartialSettlement))
{
billFeeStatus = BillFeeStatus.PartialSettlement;
}
else if (fees.All(x => x.FeeStatus == FeeStatus.SettlementCompleted))
{
billFeeStatus = BillFeeStatus.SettlementCompleted;
}
//部分状态
else if (fees.Any(x => x.FeeStatus == FeeStatus.Entering))
{
billFeeStatus = BillFeeStatus.PartialEntering;
}
else if (fees.Any(x => x.FeeStatus == FeeStatus.AuditSubmitted))
{
billFeeStatus = BillFeeStatus.PartialSubmitted;
}
else if (fees.Any(x => x.FeeStatus == FeeStatus.AuditPassed))
{
billFeeStatus = BillFeeStatus.PartialAudited;
}
else if (fees.Any(x => x.FeeStatus == FeeStatus.PartialSettlement || x.FeeStatus == FeeStatus.SettlementCompleted))
{
billFeeStatus = BillFeeStatus.PartialSettlement;
}
return billFeeStatus;
}
}
}