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.
928 lines
38 KiB
C#
928 lines
38 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;
|
|
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 Mapster;
|
|
using Masuit.Tools.Systems;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using SqlSugar;
|
|
|
|
namespace DS.WMS.Core.Fee.Method
|
|
{
|
|
/// <summary>
|
|
/// 费用记录实现
|
|
/// </summary>
|
|
public class FeeRecordService : FeeServiceBase, IFeeRecordService
|
|
{
|
|
readonly IClientFlowInstanceService flowService;
|
|
|
|
/// <summary>
|
|
/// 初始化
|
|
/// </summary>
|
|
/// <param name="serviceProvider"></param>
|
|
public FeeRecordService(IServiceProvider serviceProvider) : base(serviceProvider)
|
|
{
|
|
flowService = serviceProvider.GetRequiredService<IClientFlowInstanceService>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 列表
|
|
/// </summary>
|
|
/// <param name="request"></param>
|
|
/// <returns></returns>
|
|
public async Task<DataResult<List<FeeRecordRes>>> GetListByPageAsync(PageRequest request)
|
|
{
|
|
long UserId = long.Parse(User.UserId);
|
|
//序列化查询条件
|
|
var whereList = Db.ConfigQuery.Context.Utilities.JsonToConditionalModels(request.QueryCondition);
|
|
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.ConfigQuery.Context.Utilities.JsonToConditionalModels(query);
|
|
src = src.Where(whereList);
|
|
}
|
|
|
|
var data = await src.ToListAsync();
|
|
return DataResult<List<FeeRecord>>.Success(data);
|
|
}
|
|
|
|
/// <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>
|
|
/// <returns></returns>
|
|
public async Task<DataResult> SaveAsync(IEnumerable<FeeRecord> items)
|
|
{
|
|
var first = items.Select(x => new { x.BusinessType, x.BusinessId }).FirstOrDefault();
|
|
if (await IsFeeLockedAsync(first.BusinessId, first.BusinessType))
|
|
return DataResult.Failed(MultiLanguageConst.FeeLocked);
|
|
|
|
DateTime dtNow = DateTime.Now;
|
|
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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
foreach (var item in items)
|
|
{
|
|
if (string.IsNullOrEmpty(item.LocalCurrency))
|
|
{
|
|
//默认本位币为CNY
|
|
if (item.Id == 0)
|
|
item.LocalCurrency = 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 createList = items.Where(x => x.Id == 0).ToList();
|
|
await TenantDb.Insertable(createList).ExecuteCommandAsync();
|
|
|
|
var updateList = items.Where(x => x.Id > 0).ToList();
|
|
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();
|
|
|
|
await TenantDb.Ado.CommitTranAsync();
|
|
|
|
var list = createList.Union(updateList).Select(x => x.Adapt<FeeRecordRes>());
|
|
return DataResult.Success;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
await ex.LogAsync(Db);
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
}
|
|
finally
|
|
{
|
|
await WriteBackStatusAsync(first.BusinessId, first.BusinessType);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据模板ID创建
|
|
/// </summary>
|
|
/// <param name="bid">业务ID</param>
|
|
/// <param name="businessType">业务类型</param>
|
|
/// <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();
|
|
|
|
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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// 发起审批/申请删除工作流
|
|
/// </summary>
|
|
/// <param name="auditType">审批类型</param>
|
|
/// <param name="remark">备注</param>
|
|
/// <param name="idArray">费用记录ID</param>
|
|
/// <returns></returns>
|
|
public async Task<DataResult> SubmitForApprovalAsync(AuditType auditType, string remark, params long[] idArray)
|
|
{
|
|
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => idArray.Contains(x.Id)).Select(
|
|
x => new FeeRecord
|
|
{
|
|
Id = x.Id,
|
|
FeeName = x.FeeName,
|
|
FeeStatus = x.FeeStatus,
|
|
FlowId = x.FlowId,
|
|
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 (fees.Any(x => x.FlowId.HasValue))
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordIsAuditing));
|
|
|
|
if (fees.Any(x => x.FeeStatus == FeeStatus.PartialSettlement || x.FeeStatus == FeeStatus.SettlementCompleted))
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordIsSettled));
|
|
|
|
DataResult result = DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
try
|
|
{
|
|
if (auditType == AuditType.FeeAudit)
|
|
{
|
|
result = await ApplyAuditAsync(fees);
|
|
}
|
|
else if (auditType == AuditType.FeeDelete)
|
|
{
|
|
result = await ApplyDeleteAsync(fees, remark);
|
|
}
|
|
|
|
if (!result.Succeeded)
|
|
{
|
|
await TenantDb.Ado.RollbackTranAsync();
|
|
return result;
|
|
}
|
|
|
|
await TenantDb.Updateable(fees).UpdateColumns(x => new
|
|
{
|
|
x.Id,
|
|
x.FeeStatus,
|
|
x.SubmitBy,
|
|
x.SubmitDate,
|
|
x.FlowId
|
|
}).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);
|
|
|
|
var template = await FindTemplateAsync(AuditType.FeeAudit);
|
|
if (template == null)
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
|
|
|
|
DateTime dtNow = DateTime.Now;
|
|
foreach (var item in fees)
|
|
{
|
|
var 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;
|
|
item.FlowId = instance.Id;
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
var template = await FindTemplateAsync(AuditType.FeeDelete);
|
|
if (template == null)
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
|
|
|
|
DateTime dtNow = DateTime.Now;
|
|
foreach (var item in fees)
|
|
{
|
|
var 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.ApplyDeletion;
|
|
item.SubmitBy = long.Parse(User.UserId);
|
|
item.SubmitDate = dtNow;
|
|
item.FlowId = instance.Id;
|
|
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);
|
|
|
|
var template = await FindTemplateAsync(AuditType.FeeModify);
|
|
if (template == null)
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
|
|
|
|
DateTime dtNow = DateTime.Now;
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
try
|
|
{
|
|
foreach (var fee in fees)
|
|
{
|
|
var 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.SubmitBy = long.Parse(User.UserId);
|
|
//fee.SubmitDate = dtNow;
|
|
fee.FlowId = instance.Id;
|
|
fee.Reason = items.FirstOrDefault(x => x.FeeRecordId == fee.Id)?.Reason;
|
|
}
|
|
}
|
|
|
|
var list = items.ToList();
|
|
await TenantDb.Insertable(list).ExecuteCommandAsync();
|
|
await TenantDb.Updateable(fees).UpdateColumns(x => new { x.FeeStatus, x.FlowId }).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="idArray">费用记录ID</param>
|
|
/// <returns></returns>
|
|
public async Task<DataResult> WithdrawAsync(params long[] idArray)
|
|
{
|
|
var fees = await TenantDb.Queryable<FeeRecord>().Where(x => idArray.Contains(x.Id)).Select(
|
|
x => new FeeRecord
|
|
{
|
|
Id = x.Id,
|
|
FeeName = x.FeeName,
|
|
FeeStatus = x.FeeStatus,
|
|
FlowId = x.FlowId
|
|
}).ToListAsync();
|
|
|
|
if (fees.Count == 0)
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
|
|
|
|
//未在审批状态中
|
|
var fees2 = fees.FindAll(x => x.FlowId == null).ToList();
|
|
if (fees2.Count > 0)
|
|
{
|
|
string msg = string.Join("; ", fees2.Select(x => $"{x.FeeName}"));
|
|
return DataResult.Failed(string.Format(MultiLanguageConst.NoNeedWithdraw, msg));
|
|
}
|
|
|
|
var flows = fees.Select(x => new FlowInstance { Id = x.FlowId.Value, FlowStatus = FlowStatusEnum.Draft, MakerList = string.Empty }).ToList();
|
|
DateTime dtNow = DateTime.Now;
|
|
await TenantDb.Ado.BeginTranAsync();
|
|
try
|
|
{
|
|
await Db.Updateable(flows).UpdateColumns(x => new { x.FlowStatus, x.MakerList }).ExecuteCommandAsync();
|
|
|
|
foreach (var item in fees)
|
|
{
|
|
switch (item.FeeStatus)
|
|
{
|
|
case FeeStatus.AuditSubmitted:
|
|
item.FeeStatus = FeeStatus.Entering;
|
|
break;
|
|
case FeeStatus.ApplyModification:
|
|
item.FeeStatus = FeeStatus.AuditPassed;
|
|
|
|
//删除暂存数据
|
|
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;
|
|
break;
|
|
}
|
|
|
|
item.SubmitBy = long.Parse(User.UserId);
|
|
item.SubmitDate = dtNow;
|
|
item.FlowId = null;
|
|
}
|
|
|
|
await TenantDb.Updateable(fees).UpdateColumns(x => new { x.Id, x.FeeStatus, x.SubmitBy, x.SubmitDate, x.FlowId }).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>
|
|
/// <returns></returns>
|
|
public async Task<DataResult> SubmitBusinessAuditAsync(long bid, BusinessType type)
|
|
{
|
|
var entity = await TenantDb.Queryable<BusinessFeeStatus>().Where(x => x.BusinessId == bid &&
|
|
x.BusinessType == BusinessType.OceanShippingExport).Select(x => new BusinessFeeStatus
|
|
{
|
|
Id = x.Id,
|
|
BusinessId = x.BusinessId,
|
|
BusinessType = x.BusinessType,
|
|
IsFeeLocking = x.IsFeeLocking,
|
|
BillAuditStatus = x.BillAuditStatus,
|
|
FlowId = x.FlowId
|
|
}).FirstAsync();
|
|
|
|
if (entity == null)
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.BusinessNotFound));
|
|
if (entity.IsFeeLocking.GetValueOrDefault())
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeLocked));
|
|
if (entity.FlowId.HasValue)
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.FeeRecordIsAuditing));
|
|
if (entity.BillAuditStatus == BillAuditStatus.AuditPassed)
|
|
return DataResult.Failed(string.Format(MultiLanguageConst.BusinessStatusError, entity.BillAuditStatus.GetDescription()));
|
|
|
|
var template = await FindTemplateAsync(AuditType.FeeBusiness);
|
|
if (template == null)
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
|
|
|
|
var result = flowService.CreateFlowInstance(new CreateFlowInstanceReq
|
|
{
|
|
BusinessId = entity.Id,
|
|
BusinessType = entity.BusinessType,
|
|
TemplateId = template.Id
|
|
});
|
|
if (result.Succeeded)
|
|
{
|
|
var instance = result.Data as FlowInstance;
|
|
flowService.StartFlowInstance(instance.Id.ToString());
|
|
|
|
//变更状态为提交审核
|
|
entity.BillAuditStatus = BillAuditStatus.AuditSubmitted;
|
|
entity.BillFeeStatusTime = DateTime.Now;
|
|
entity.FlowId = instance.Id;
|
|
|
|
await TenantDb.Updateable(entity).UpdateColumns(x => new
|
|
{
|
|
x.BillAuditStatus,
|
|
x.BillFeeStatusTime,
|
|
x.FlowId
|
|
}).ExecuteCommandAsync();
|
|
|
|
//修改关联费用状态为提交审核
|
|
await TenantDb.Updateable<FeeRecord>().Where(x => x.BusinessId == entity.BusinessId && x.BusinessType == entity.BusinessType)
|
|
.SetColumns(x => x.FeeStatus, FeeStatus.AuditSubmitted).ExecuteCommandAsync();
|
|
|
|
return DataResult.Success;
|
|
}
|
|
|
|
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
|
|
}
|
|
|
|
/// <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="businessType">业务类型</param>
|
|
/// <param name="idArray">费用记录ID</param>
|
|
/// <returns></returns>
|
|
public async Task<DataResult<CostAccountingForm>> GetPrintInfoAsync(BusinessType businessType, params long[] idArray)
|
|
{
|
|
CostAccountingForm form = null;
|
|
switch (businessType)
|
|
{
|
|
case BusinessType.OceanShippingExport:
|
|
form = await GetOceanShippingExportAsync(idArray);
|
|
break;
|
|
case BusinessType.OceanShippingImport:
|
|
|
|
break;
|
|
default:
|
|
return DataResult<CostAccountingForm>.Failed(string.Format(
|
|
MultiLanguageConst.BusinessNotSupported, businessType.GetDescription()));
|
|
}
|
|
|
|
if (form != null)
|
|
{
|
|
long UserId = long.Parse(User.UserId);
|
|
form.Creator = Db.Queryable<SysUser>().Where(x => x.Id == UserId).Select(x => x.NickName).First();
|
|
|
|
form.ReceivableRMB = form.Details.FindAll(x => x.Type == FeeType.Receivable && x.Currency == RMB_CODE).Sum(x => x.Amount);
|
|
form.PayableRMB = form.Details.FindAll(x => x.Type == FeeType.Payable && x.Currency == RMB_CODE).Sum(x => x.Amount);
|
|
form.ReceivableUSD = form.Details.FindAll(x => x.Type == FeeType.Receivable && x.Currency == USD_CODE).Sum(x => x.Amount);
|
|
form.PayableUSD = form.Details.FindAll(x => x.Type == FeeType.Payable && x.Currency == USD_CODE).Sum(x => x.Amount);
|
|
form.ReceivableOther = form.Details.FindAll(x => x.Type == FeeType.Receivable && (x.Currency != RMB_CODE && x.Currency != USD_CODE)).Sum(x => x.Amount);
|
|
form.PayableOther = form.Details.FindAll(x => x.Type == FeeType.Payable && (x.Currency == RMB_CODE && x.Currency != USD_CODE)).Sum(x => x.Amount);
|
|
|
|
//获取美元汇率
|
|
var fees = new List<FeeRecord> {
|
|
new FeeRecord { Currency = USD_CODE, FeeType = FeeType.Receivable },
|
|
new FeeRecord { Currency = USD_CODE, FeeType = FeeType.Payable }
|
|
};
|
|
await FetchExchangeRateAsync(fees);
|
|
form.ExchangeRate = fees[0].ExchangeRate.HasValue ? fees[0].ExchangeRate.Value : 1;
|
|
form.TotalReceivable = Math.Round(form.ReceivableUSD * form.ExchangeRate, 4, MidpointRounding.ToEven) + form.ReceivableRMB + form.ReceivableOther;
|
|
form.TotalPayable = Math.Round(form.PayableUSD * form.ExchangeRate, 4, MidpointRounding.ToEven) + form.PayableRMB + form.PayableOther;
|
|
}
|
|
|
|
return DataResult<CostAccountingForm>.Success(form);
|
|
}
|
|
|
|
//获取海运出口打印数据
|
|
async Task<CostAccountingForm> GetOceanShippingExportAsync(params long[] idArray)
|
|
{
|
|
CostAccountingForm form = null;
|
|
var list = await TenantDb.Queryable<FeeRecord>().InnerJoin<SeaExport>((x, y) => x.BusinessId == y.Id)
|
|
.Where((x, y) => idArray.Contains(x.Id)
|
|
//&& x.FeeStatus == FeeStatus.SettlementCompleted
|
|
).Select((x, y) => new
|
|
{
|
|
x.FeeType,
|
|
x.FeeName,
|
|
x.Currency,
|
|
x.ExchangeRate,
|
|
x.Amount,
|
|
x.CustomerName,
|
|
y.CustomerNo, //业务编号
|
|
y.AccountDate, //会计期间
|
|
y.ETA,
|
|
y.ETD,
|
|
y.Voyno,
|
|
y.MBLNO,
|
|
y.Carrier,
|
|
y.LoadPort,
|
|
y.DischargePort,
|
|
y.CntrTotal, //Volume
|
|
y.IssueType //放单方式
|
|
}).ToListAsync();
|
|
|
|
if (list.Count == 0)
|
|
return form;
|
|
|
|
var item = list[0];
|
|
form = new CostAccountingForm
|
|
{
|
|
BusinessNo = item.CustomerNo,
|
|
AccountingPeriod = item.AccountDate,
|
|
ETA = item.ETA,
|
|
ETD = item.ETD,
|
|
Voy = item.Voyno,
|
|
MBLNo = item.MBLNO,
|
|
Carrier = item.Carrier,
|
|
POL = item.LoadPort,
|
|
POD = item.DischargePort,
|
|
Volume = item.CntrTotal,
|
|
ReleaseType = item.IssueType,
|
|
PrintTime = DateTime.Now,
|
|
Details = list.Select(x => new CostAccountingDetail
|
|
{
|
|
Amount = x.Amount,
|
|
Currency = x.Currency,
|
|
CustomerName = x.CustomerName,
|
|
FeeName = x.FeeName,
|
|
Type = x.FeeType
|
|
}).ToList()
|
|
};
|
|
|
|
return form;
|
|
}
|
|
|
|
/// <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 && x.BusinessType == businessType)
|
|
.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;
|
|
}
|
|
|
|
return billFeeStatus;
|
|
}
|
|
|
|
}
|
|
}
|