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.

547 lines
24 KiB
C#

using DS.Module.Core;
using DS.Module.Core.Constants;
using DS.Module.Core.Data;
using DS.Module.Core.Extensions;
using DS.WMS.Core.Check.Entity;
using DS.WMS.Core.Fee.Dtos;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.Flow.Entity;
using DS.WMS.Core.Flow.Interface;
using DS.WMS.Core.Info.Dtos;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Info.Interface;
using DS.WMS.Core.Op.Dtos.TaskInteraction;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Op.Interface.TaskInteraction;
using DS.WMS.Core.Sys.Entity;
using Fasterflect;
using Mapster;
using Masuit.Tools.Systems;
using Microsoft.Extensions.DependencyInjection;
using SqlSugar;
namespace DS.WMS.Core.Info.Method;
/// <summary>
/// 往来单位服务
/// </summary>
public class ClientInfoService : ServiceBase, IClientInfoService
{
const TaskBaseTypeEnum INFO_CLIENT_TASK = TaskBaseTypeEnum.INFO_CLIENT_AUDIT;
Lazy<IClientFlowInstanceService> flowService;
Lazy<ITaskService> taskService;
/// <summary>
/// 初始化
/// </summary>
/// <param name="serviceProvider"></param>
public ClientInfoService(IServiceProvider serviceProvider) : base(serviceProvider)
{
flowService = new Lazy<IClientFlowInstanceService>(serviceProvider.GetRequiredService<IClientFlowInstanceService>());
taskService = new Lazy<ITaskService>(serviceProvider.GetRequiredService<ITaskService>());
}
#region 审核
/// <summary>
/// 提交审核
/// </summary>
/// <param name="idModel"></param>
/// <returns></returns>
public async Task<DataResult> SubmitAuditAsync(IdModel idModel)
{
var list = await TenantDb.Queryable<InfoClient>().Where(x => idModel.Ids.Contains(x.Id)).Select(x => new
{
x.Id,
x.AuditStatus,
x.CodeName,
x.ShortName,
x.EnShortName
}).ToListAsync();
if (list.Exists(x => x.AuditStatus == AuditStatusEnum.Auditing))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ItemsAreAuditing));
var queryable = TenantDb.Queryable<InfoClientContact>().Where(x => idModel.Ids.Contains(x.ClientId));
if (await queryable.AnyAsync(x => (SqlFunc.IsNullOrEmpty(x.Tel) && SqlFunc.IsNullOrEmpty(x.Mobile)) || (SqlFunc.IsNullOrEmpty(x.Email) && SqlFunc.IsNullOrEmpty(x.QQ))))
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ClientInfoIncomplete));
if (await taskService.Value.HasAuthorizedAsync())
{
var requests = list.Select(x => new TaskCreationRequest
{
BusinessId = x.Id,
TaskTypeName = INFO_CLIENT_TASK.ToString(),
TaskTitle = $"【{INFO_CLIENT_TASK.GetDescription()}】{x.CodeName} {x.ShortName}"
});
await TenantDb.Ado.BeginTranAsync();
try
{
DataResult result;
foreach (var request in requests)
{
result = await taskService.Value.CreateTaskAsync(request, false);
if (!result.Succeeded)
return result;
}
await TenantDb.Updateable<InfoClient>().Where(x => idModel.Ids.Contains(x.Id))
.SetColumns(x => x.AuditStatus == AuditStatusEnum.Auditing).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));
}
}
var template = await FindTemplateAsync(INFO_CLIENT_TASK);
if (template == null)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.TemplateNotFound));
for (int i = 0; i < idModel.Ids.Length; i++)
{
var id = idModel.Ids[i];
var result = flowService.Value.CreateFlowInstance(new CreateFlowInstanceReq
{
BusinessId = id,
TemplateId = template.Id
});
if (!result.Succeeded || result.Data is not FlowInstance instance)
return result;
result = flowService.Value.StartFlowInstance(instance.Id.ToString());
if (!result.Succeeded)
return result;
}
var rows = await TenantDb.Updateable<InfoClient>().Where(x => idModel.Ids.Contains(x.Id))
.SetColumns(x => x.AuditStatus == AuditStatusEnum.Auditing).ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
/// <summary>
/// 执行审核
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult> AuditAsync(AuditRequest request)
{
if (await taskService.Value.HasAuthorizedAsync())
{
return await taskService.Value.AuditAsync(new TaskAuditRequest
{
Ids = request.Ids,
Remark = request.Remark,
Result = request.Result,
TaskTypeName = INFO_CLIENT_TASK.ToString()
});
}
var list = await flowService.Value.GetInstanceByBSIdAsync(INFO_CLIENT_TASK, ids: request.Ids);
if (list.Count != request.Ids.Length)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInAudit));
foreach (var item in list)
{
var result = flowService.Value.AuditFlowInstance(new FlowAuditInfo
{
AuditNote = request.Remark,
Status = request.Result,
Instance = item
});
if (!result.Succeeded)
return result;
}
return DataResult.Success;
}
/// <summary>
/// 撤销审核
/// </summary>
/// <param name="idModel"></param>
/// <returns></returns>
public async Task<DataResult> WithdrawAsync(IdModel idModel)
{
DataResult result;
if (await taskService.Value.HasAuthorizedAsync())
{
await TenantDb.Ado.BeginTranAsync();
try
{
for (int i = 0; i < idModel.Ids.Length; i++)
{
result = await taskService.Value.WithdrawAsync(new TaskRequest
{
BusinessId = idModel.Ids[i],
TaskTypeName = INFO_CLIENT_TASK.ToString()
}, false);
if (!result.Succeeded)
{
return result;
}
}
await TenantDb.Updateable<InfoClient>().Where(x => idModel.Ids.Contains(x.Id))
.SetColumns(x => x.AuditStatus == AuditStatusEnum.NoAudit)
.SetColumns(x => x.AuditTime == null)
.SetColumns(x => x.AuditNote == null)
.ExecuteCommandAsync();
await TenantDb.Ado.CommitTranAsync();
return DataResult.Success;
}
catch
{
await TenantDb.Ado.RollbackTranAsync();
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
}
var list = await flowService.Value.GetInstanceByBSIdAsync(INFO_CLIENT_TASK, ids: idModel.Ids);
if (list.Count != idModel.Ids.Length)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NotInAudit));
result = await flowService.Value.WithdrawAsync(idModel.Ids);
if (!result.Succeeded)
return result;
int rows = await TenantDb.Updateable<InfoClient>().Where(x => idModel.Ids.Contains(x.Id))
.SetColumns(x => x.AuditStatus == AuditStatusEnum.NoAudit).ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
/// <summary>
/// 审核完成回调
/// </summary>
/// <param name="callback">回调信息</param>
/// <returns></returns>
public async Task<DataResult> AuditCallbackAsync(FlowCallback callback)
{
if (callback.AuditType != INFO_CLIENT_TASK)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.NoAuditItems));
InfoClient infoClient = new()
{
Id = callback.BusinessId,
AuditNote = callback.RejectReason,
AuditTime = DateTime.Now,
AuditStatus = callback.FlowStatus == FlowStatusEnum.Approve ? AuditStatusEnum.Approve : AuditStatusEnum.Reject,
Status = callback.FlowStatus == FlowStatusEnum.Approve ? 0 : 1
};
int rows = await TenantDb.Updateable(infoClient).UpdateColumns(x => new
{
x.AuditNote,
x.AuditTime,
x.AuditStatus,
x.Status
}).ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
#endregion
/// <summary>
/// 列表
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public async Task<DataResult<List<ClientInfoRes>>> GetListAsync(PageRequest<ClientQuery> request)
{
//序列化查询条件
var whereList = request.GetConditionalModels(Db);
var query = TenantDb.Queryable<InfoClient>()
.LeftJoin<InfoClientContact>((c, c1) => c.Id == c1.ClientId)
.LeftJoin<InfoClientContract>((c, c1, c2) => c.Id == c2.ClientId)
.InnerJoinIF<InfoClientTag>(request.OtherQueryCondition?.ClientTag != null, (c, c1, c2, ct) => c.Id == ct.ClientId)
.GroupBy((c, c1, c2) => c.Id);
if (!string.IsNullOrEmpty(request.OtherQueryCondition?.ContactInfo))
query = query.Where((c, c1, c2) => c1.Tel.Contains(request.OtherQueryCondition.ContactInfo) ||
c1.Mobile.Contains(request.OtherQueryCondition.ContactInfo) || c1.Email.Contains(request.OtherQueryCondition.ContactInfo));
if (request.OtherQueryCondition != null && request.OtherQueryCondition.IsContractExpired.GetValueOrDefault())
query = query.Where((c, c1, c2) => SqlFunc.GetDate() > c2.EndDate);
if (request.OtherQueryCondition?.ClientTag != null)
{
//合并到主查询条件
var props = Array.FindAll(request.OtherQueryCondition.ClientTag.GetType().GetProperties(), x => x.Name.StartsWith("Is") && x.PropertyType == typeof(bool));
List<IConditionalModel> list = [];
foreach (var prop in props)
{
object val = prop.Get(request.OtherQueryCondition.ClientTag);
if (val != null && val is bool value && value)
{
list.Add(new ConditionalModel
{
ConditionalType = ConditionalType.Equal,
FieldName = "ct." + prop.Name,
FieldValue = "1"
});
}
}
query = query.Where(list);
}
var result = await query.Select((c, c1, c2, ct) => new ClientInfoRes
{
CodeName = c.CodeName,
Name = c.Name,
ShortName = c.ShortName,
EnShortName = c.EnShortName,
EnFullName = c.EnFullName
}, true).MergeTable().Where(whereList).ToQueryPageAsync(request.PageCondition);
if (result.Data?.Count > 0)
{
var ids = result.Data.Select(x => x.Id);
var contacts = TenantDb.Queryable<InfoClientContact>().Where(x => ids.Contains(x.ClientId) && x.IsDefault)
.Select<ClientContactRes>().ToList();
var accountDates = TenantDb.Queryable<InfoClientAccountDate>().Where(x => ids.Contains(x.ClientId) && x.Id ==
SqlFunc.Subqueryable<InfoClientAccountDate>().Where(y => y.Id == x.Id).Select(y => SqlFunc.AggregateMax(y.Id))
).Select<ClientAccountDateRes>().ToList();
var ids2 = result.Data.SelectMany(x => x.SaleOrgIdList).Distinct();
var orgs = Db.Queryable<SysOrg>().Where(x => ids2.Contains(x.Id)).Select(x => new { x.Id, x.OrgName }).ToList();
foreach (var item in result.Data)
{
item.DefaultContact = contacts.Find(x => x.ClientId == item.Id);
item.LastAccountDate = accountDates.Find(x => x.ClientId == item.Id);
var list = orgs.FindAll(x => item.SaleOrgIdList.Contains(x.Id));
item.SaleOrgNames = string.Join(",", list.Select(x => x.OrgName));
}
}
return result;
}
/// <summary>
/// 确定往来单位是否已使用
/// </summary>
/// <param name="ids">往来单位ID</param>
/// <returns></returns>
public async Task<DataResult<List<ClientUsage>>> GetUsageAsync(params long[] ids)
{
var list = await TenantDb.Queryable<InfoClient>().Where(x => ids.Contains(x.Id))
.Select(c => new ClientUsage
{
Id = c.Id,
Name = c.ShortName,
IsUsed = SqlFunc.Subqueryable<SeaExport>().Where(s => c.Id == s.CustomerId || c.Id == s.ForwarderId ||
c.Id == s.YardId || c.Id == s.ShipperCnId || c.Id == s.ContractClientId || c.Id == s.TruckerId ||
c.Id == s.AgentId || c.Id == s.ShipAgencyId || c.Id == s.CustomserId || c.Id == s.WareHouseId).Any() &&
SqlFunc.Subqueryable<FeeRecord>().Where(f => c.Id == f.CustomerId).Any() &&
SqlFunc.Subqueryable<CheckBill>().Where(f => c.Id == f.CustomerId).Any() &&
SqlFunc.Subqueryable<CheckBillAuto>().Where(f => c.Id == f.CustomerId).Any()
}).ToListAsync();
var result = DataResult<List<ClientUsage>>.Success(list);
result.Count = list.Count;
return result;
}
/// <summary>
/// 编辑
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
public async Task<DataResult> EditAsync(ClientInfoReq req)
{
var data = req.Adapt<InfoClient>();
data.Status = (int)StatusEnum.Disable;
data.AuditStatus = AuditStatusEnum.NoAudit;
data.OrgId = User.OrgId;
if (string.IsNullOrEmpty(data.CodeName))
data.CodeName = PinYinUtil.GetFristLetter(data.ShortName); //助记码
if (req.ServiceItemCodes?.Length > 0)
data.ServiceItem = string.Join(",", req.ServiceItemCodes);
if (req.Id == 0)
{
if (TenantDb.Queryable<InfoClient>().Where(x => (x.ShortName == req.ShortName.Trim() || x.Description == req.Description.Trim() || x.TaxNo == req.TaxNo.Trim())).Any())
return DataResult.Failed("客户信息已存在,请检查客户全称、简称或社会信用代码是否重复!", MultiLanguageConst.ClientInfoExist);
var tag = req.ClientTag.Adapt<InfoClientTag>();
var entity = await TenantDb.Insertable(data).ExecuteReturnEntityAsync();
tag.ClientId = entity.Id;
await TenantDb.Insertable(tag).RemoveDataCache($"{SqlSugarCacheConst.InfoClient}{User.TenantId}").ExecuteCommandAsync();
return DataResult.Successed("添加成功!", entity.Id, MultiLanguageConst.DataCreateSuccess);
}
else
{
var model = await TenantDb.Queryable<InfoClient>().Where(x => x.Id == req.Id).Select(x => new
{
x.Status,
x.AuditStatus
}).FirstAsync();
if (model != null && model.AuditStatus == AuditStatusEnum.Auditing)
return DataResult.FailedWithDesc(nameof(MultiLanguageConst.ItemsAreAuditing));
var tag = TenantDb.Queryable<InfoClientTag>().Where(x => x.ClientId == req.Id).First();
if (TenantDb.Queryable<InfoClient>().Where(x => x.Id != data.Id && (x.ShortName == req.ShortName.Trim() || x.Description == req.Description.Trim() || x.TaxNo == req.TaxNo.Trim())).Any())
return DataResult.Failed("请检查客户全称、简称或社会信用代码是否重复!", MultiLanguageConst.ClientInfoExist);
tag = req.ClientTag.Adapt(tag);
data.ServiceItem = data.ServiceItem ?? string.Empty;
var updateable = TenantDb.Updateable(data).RemoveDataCache($"{SqlSugarCacheConst.InfoClient}{User.TenantId}")
.IgnoreColumns(ignoreAllNullColumns: true)
.IgnoreColumns(x => new { x.Status, x.ETD, x.AuditStatus, x.AuditNote, x.AuditTime });
var list = (await GetUsageAsync(req.Id))?.Data;
if (list != null && list.Exists(x => x.Id == req.Id && x.IsUsed))
updateable = updateable.IgnoreColumns(x => x.ShortName);
await updateable.ExecuteCommandAsync();
await TenantDb.Updateable(tag).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync();
return DataResult.Successed("更新成功!", MultiLanguageConst.DataUpdateSuccess);
}
}
/// <summary>
/// 详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<DataResult<ClientInfoRes>> GetAsync(string id)
{
var entity = await TenantDb.Queryable<InfoClient>()
.Where(a => a.Id == long.Parse(id))
.FirstAsync();
if (entity == null)
return DataResult<ClientInfoRes>.Success(null);
var data = entity.Adapt<ClientInfoRes>();
data.ServiceItemCodes = entity.ServiceItem?.Split(',', StringSplitOptions.RemoveEmptyEntries);
var tag = await TenantDb.Queryable<InfoClientTag>().Select<ClientTagRes>()
.FirstAsync(a => a.ClientId == long.Parse(id));
data.ClientTag = tag;
data.InvoiceHeaders ??= await TenantDb.Queryable<InvoiceHeader>().Where(x => x.RelativeId == data.Id).ToListAsync();
return DataResult<ClientInfoRes>.Success(data, MultiLanguageConst.DataQuerySuccess);
}
/// <summary>
/// 批量删除发票抬头
/// </summary>
/// <param name="idModel"></param>
/// <returns></returns>
public async Task<DataResult> DeleteInvoiceHeaderAsync(IdModel idModel)
{
int rows = await TenantDb.Deleteable<InvoiceHeader>().Where(x => idModel.Ids.Contains(x.Id)).ExecuteCommandAsync();
return rows > 0 ? DataResult.Success : DataResult.FailedWithDesc(nameof(MultiLanguageConst.Operation_Failed));
}
/// <summary>
/// 批量删除
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
public async Task<DataResult> DeleteAsync(IdModel req)
{
await TenantDb.Ado.BeginTranAsync();
try
{
var result = await GetUsageAsync(req.Ids);
if (result.Data != null && result.Data.Exists(x => x.IsUsed))
return DataResult.FailedWithDesc(MultiLanguageConst.ClientIsUsed);
//银行信息
await TenantDb.Deleteable<InfoClientBank>().Where(x => req.Ids.Contains(x.ClientId)).ExecuteCommandAsync();
//联系人
await TenantDb.Deleteable<InfoClientContact>().Where(x => req.Ids.Contains(x.ClientId)).ExecuteCommandAsync();
//合同信息
await TenantDb.Deleteable<InfoClientContract>().Where(x => req.Ids.Contains(x.ClientId)).ExecuteCommandAsync();
//账期
await TenantDb.Deleteable<InfoClientAccountDate>().Where(x => req.Ids.Contains(x.ClientId)).ExecuteCommandAsync();
//收发货人
await TenantDb.Deleteable<InfoClientShipper>().Where(x => req.Ids.Contains(x.ClientId)).ExecuteCommandAsync();
//删除客户信息
await TenantDb.Deleteable<InfoClient>().RemoveDataCache($"{SqlSugarCacheConst.InfoClient}{User.TenantId}").Where(x => req.Ids.Contains(x.Id)).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));
}
}
#region 获取往来单位详情(含有联系人列表)
/// <summary>
/// 获取往来单位详情(含有联系人列表)
/// </summary>
/// <param name="query">查询往来单位</param>
/// <returns>返回往来单位详情</returns>
public async Task<DataResult<ClientInfoRes>> GetClientInfoWithContact(QueryClientInfo query)
{
var data = await TenantDb.Queryable<InfoClient>().InnerJoin<InfoClientTag>((c, t) => c.Id == t.ClientId)
.Where((c, t) => c.Id == query.ClientId)
.WhereIF(query.IsController, (c, t) => t.IsController.HasValue && t.IsController.HasValue)
.WhereIF(query.IsCarrier, (c, t) => t.IsCarrier.HasValue && t.IsCarrier.HasValue)
.WhereIF(query.IsBooking, (c, t) => t.IsBooking.HasValue && t.IsBooking.HasValue)
.WhereIF(query.IsYard, (c, t) => t.IsYard.HasValue && t.IsYard.HasValue)
.WhereIF(query.IsTruck, (c, t) => t.IsTruck.HasValue && t.IsTruck.HasValue)
.WhereIF(query.IsController, (c, t) => t.IsController.HasValue && t.IsController.HasValue)
.WhereIF(query.IsCustom, (c, t) => t.IsCustom.HasValue && t.IsCustom.HasValue)
.WhereIF(query.IsAgent, (c, t) => t.IsAgent.HasValue && t.IsAgent.HasValue)
.WhereIF(query.IsAgentCn, (c, t) => t.IsAgentCn.HasValue && t.IsAgentCn.HasValue)
.WhereIF(query.IsExpress, (c, t) => t.IsExpress.HasValue && t.IsExpress.HasValue)
.WhereIF(query.IsAirLines, (c, t) => t.IsAirLines.HasValue && t.IsAirLines.HasValue)
.WhereIF(query.IsShipper, (c, t) => t.IsShipper.HasValue && t.IsShipper.HasValue)
.WhereIF(query.IsConsignee, (c, t) => t.IsConsignee.HasValue && t.IsConsignee.HasValue)
.WhereIF(query.IsNotifyParty, (c, t) => t.IsNotifyParty.HasValue && t.IsNotifyParty.HasValue)
.WhereIF(query.IsWareHouse, (c, t) => t.IsWareHouse.HasValue && t.IsWareHouse.HasValue)
.WhereIF(query.IsWharf, (c, t) => t.IsWharf.HasValue && t.IsWharf.HasValue)
.WhereIF(query.IsInsurer, (c, t) => t.IsInsurer.HasValue && t.IsInsurer.HasValue)
.WhereIF(query.IsLeasing, (c, t) => t.IsLeasing.HasValue && t.IsLeasing.HasValue)
.WhereIF(query.IsTradingAgency, (c, t) => t.IsTradingAgency.HasValue && t.IsTradingAgency.HasValue)
.WhereIF(query.IsOther, (c, t) => t.IsOther.HasValue && t.IsOther.HasValue)
.WhereIF(!string.IsNullOrWhiteSpace(query.Others), (c, t) => t.Others == query.Others)
.WhereIF(query.IsShipAgency, (c, t) => t.IsShipAgency.HasValue && t.IsShipAgency.HasValue)
.WhereIF(query.IsEnterprise, (c, t) => t.IsEnterprise.HasValue && t.IsEnterprise.HasValue)
.Select((c, t) => new { Client = c, tag = t })
.FirstAsync();
var clientInfo = data.Client.Adapt<ClientInfoRes>();
clientInfo.ClientTag = data.tag.Adapt<ClientTagRes>();
var contactList = TenantDb.Queryable<InfoClientContact>()
.Where(a => a.ClientId == clientInfo.Id && a.Status == StatusEnum.Enable).ToList();
if (contactList.Count > 0)
clientInfo.ClientContactList = contactList.Adapt<List<ClientContactRes>>();
if (clientInfo == null)
return DataResult<ClientInfoRes>.FailedData(clientInfo);
return DataResult<ClientInfoRes>.Success(clientInfo);
}
#endregion
}