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.

597 lines
25 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DS.Module.Core;
using DS.Module.Core.Data;
using DS.Module.Core.Helpers;
using DS.Module.MQ;
using DS.Module.SqlSugar;
using DS.Module.UserModule;
using DS.WMS.Core.Fee.Entity;
using DS.WMS.Core.Flow.Dtos;
using DS.WMS.Core.HangfireJob.Interface;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Op.Entity;
using DS.WMS.Core.Sys.Entity;
using DS.WMS.FeeBillRecvService.Dtos;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPOI.OpenXmlFormats.Wordprocessing;
using Org.BouncyCastle.Ocsp;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using SqlSugar;
namespace DS.WMS.FeeBillRecvService
{
public class RecvFeeBillWorker : BackgroundService
{
private readonly ILogger<RecvFeeBillWorker> _logger;
private IConnection mqConn;
private IModel model;
private readonly IServiceProvider _serviceProvider;
private readonly ISqlSugarClient db;
private readonly IUser user;
private readonly ISaasDbService saasService;
public RecvFeeBillWorker(IServiceProvider serviceProvider,
ILogger<RecvFeeBillWorker> logger)
{
_logger = logger;
_serviceProvider = serviceProvider;
db = _serviceProvider.GetRequiredService<ISqlSugarClient>();
user = _serviceProvider.GetRequiredService<IUser>();
saasService = _serviceProvider.GetRequiredService<ISaasDbService>();
}
protected override Task ExecuteAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("启动账单 ExecuteAsync");
return Task.Run(() =>
{
_logger.LogInformation("BookingAutoService ExecuteAsync RunTask");
//绑定队列
BindMQ();
});
}
private void BindMQ()
{
//string ExchangeName = "billcenter.output.ds7new.444c19c1-0bf5-4709-a08b-c9859ca775e6";
//string QueueName = $"billcenter.output.ds7new.444c19c1-0bf5-4709-a08b-c9859ca775e6";
string ExchangeName = AppSetting.app(new string[] { "FeeSettings", "ExchangeName" });
string QueueName = AppSetting.app(new string[] { "FeeSettings", "QueueName" });
var mqUrl = AppSetting.app(new string[] { "FeeSettings", "MQUrl" });
ConnectionFactory factory = new ConnectionFactory();
//var repoSysCfg = _serviceScope.ServiceProvider.GetService<SqlSugarRepository<SysConfig>>();
//var mqUrl = "amqp://dongsheng8bill:dongsheng8bill@47.104.207.5:12567/billcenter";
//var mqUrl = repoSysCfg.FirstOrDefault(x => x.Code == "DjyBookingAutoMQUrl")?.Value;
if (string.IsNullOrEmpty(mqUrl))
{
_logger.LogError($"接收订舱自动化消息推送所需MQUrl未配置");
}
else
{
_logger.LogInformation($"准备连接订舱自动化消息队列:{mqUrl}");
factory.Uri = new Uri(mqUrl);
mqConn = factory.CreateConnection("东胜8接收账单邮件解析");
model = mqConn.CreateModel();
model.ExchangeDeclare(ExchangeName, ExchangeType.Topic);
model.QueueDeclare(QueueName, false, false, false, null);
model.QueueBind(QueueName, ExchangeName, "*", null);
var consumer = new EventingBasicConsumer(model);
consumer.Received += (obj, arg) =>
{
var body = arg.Body;
var strBody = Encoding.UTF8.GetString(body.ToArray());
_logger.LogInformation($"收到订舱自动化消息队列:{strBody}");
DoWork(strBody);
};
model.BasicConsume(QueueName, true, consumer);
}
}
public override void Dispose()
{
base.Dispose();
//_serviceScope.Dispose();
if (mqConn != null && mqConn.IsOpen)
mqConn.Close();
_logger.LogInformation("BookingAutoService Dispose");
}
private void DoWork(string json)
{
/*
1、反串行化报文转成对象
2、用提单号检索订单信息如果匹配不到订单信息需要生成待办任务。
3、入库费用并写入订单的应付费用表
*/
string msg = string.Empty;
string gid = string.Empty;
try
{
var model = GetInfo(json, out msg);
_logger.LogInformation($"报文转换完成 GID={model.GID} BookingBill={model.BookingBill} 共【{model.DetailList.Count}】条");
//var tenantDb = saasService.GetBizJobDbScopeById(new JobDbInitConfig
//{
// UserId = 1819549542463442944,
// UserName = "东胜8测试",
// TenantId = 1819549542425694208,
// OrgId = 1819557001806614528
//});
var tenantDb = saasService.GetBizJobDbScopeExtById(new JobDbInitConfig
{
//UserId = long.Parse(AppSetting.app(new string[] { "FeeSettings", "UserId" })),
//UserName = AppSetting.app(new string[] { "FeeSettings", "UserName" }),
TenantId = long.Parse(AppSetting.app(new string[] { "FeeSettings", "TenantId" })),
//OrgId = long.Parse(AppSetting.app(new string[] { "FeeSettings", "OrgId" })),
});
_logger.LogInformation($"提取对应租户数据访问完成 GID={model.GID} BookingBill={model.BookingBill}");
string blno = model.BookingBill?.Trim();
gid = model.GID?.Trim();
_logger.LogInformation($"提取订单信息 GID={model.GID} BookingBill={model.BookingBill}");
var booking = tenantDb.Queryable<SeaExport>().ClearFilter(typeof(IOrgId)).First(a => a.MBLNO == blno && a.Deleted == false && (a.IsRefund == null || a.IsRefund.Value == false)
&& (a.IsChangeETD == null || a.IsChangeETD.Value == false));
_logger.LogInformation($"提取订单完成 GID={model.GID} BookingBill={model.BookingBill} Order={JsonConvert.SerializeObject(booking)}");
if (booking != null && booking.IsFeeLocking.HasValue && booking.IsFeeLocking.Value)
{
SendCallBack(new SingleBillReceiveResult
{
ReceiveId = model.GID,
Success = false,
Reason = "订单费用已锁定"
});
_logger.LogInformation($"提取订单完成 GID={model.GID} BookingBill={model.BookingBill} id={booking.Id}");
return;
}
if (booking != null)
{
var ctnList = tenantDb.Queryable<OpCtn>().ClearFilter(typeof(IOrgId)).Where(a => a.BSNO == booking.Id.ToString() && a.Deleted == false).ToList();
DateTime etd = DateTime.MinValue;
if (booking.ETD.HasValue)
etd = booking.ETD.Value;
DateTime nowDate = DateTime.Now;
var custTypeDict = DS.Module.Core.EnumUtil.GetEnumDictionaryWithKey(typeof(CustomerTypeEnum));
var feeUnitDict = DS.Module.Core.EnumUtil.GetEnumDictionaryWithKey(typeof(FeeUnitEnum));
var codeCurrency = tenantDb.Queryable<FeeCurrency>().ToList();
long tenantId = long.Parse(AppSetting.app(new string[] { "FeeSettings", "TenantId" }));
var userInfo = db.Queryable<SysUser>().ClearFilter(typeof(ITenantId)).First(x => x.Id == booking.OperatorId && x.TenantId == tenantId);
List<string> errorMsgList = new List<string>();
int start = 1;
//需要先全部费用跟库匹配,存在不匹配的,终止整个入库
Dictionary<string, Tuple<string, bool>> doResultDict = new Dictionary<string, Tuple<string, bool>>();
var checkFeeArg = model.DetailList.Select(f=>f.CustSysName).Distinct().ToList();
string reason = string.Empty;
bool isStop = false;
bool isNoNotice = false;
if (checkFeeArg.Any(x => string.IsNullOrWhiteSpace(x)))
{
isStop = true;
reason = "费用名称不能为空";
//new EmailNoticeHelper().SendEmailNotice("")
isNoNotice = true;
}
var queryFeeList = tenantDb.Queryable<FeeCode>().Where(x => checkFeeArg.Contains(x.Name) && x.IsSea == true).ToList();
if(queryFeeList.Count == 0)
{
isStop = true;
reason = $"费用名称不存在,{(string.Join(",", checkFeeArg))}";
isNoNotice = true;
}
else
{
var checkRlt = checkFeeArg.GroupJoin(queryFeeList, l => l, r => r.Name, (l, r) =>
{
var currFee = r.FirstOrDefault();
if (currFee == null)
return new { Succ = false, Obj = l };
return new { Succ = true, Obj = l };
}).ToList();
if (checkRlt.Any(b => !b.Succ))
{
isStop = true;
reason = "费用名称不存在," + string.Join(",", checkRlt.Where(b => !b.Succ).Select(b => b.Obj).ToArray());
isNoNotice = true;
}
}
if (!isStop)
{
foreach (var fee in model.DetailList)
{
string qFee = fee.CustSysName?.Trim();
try
{
var feecode = tenantDb.Queryable<FeeCode>().First(x => x.Name == qFee && x.IsSea == true);
if (feecode == null)
{
}
var newfee = new FeeRecord();
newfee.BusinessId = booking.Id;
newfee.FeeId = feecode.Id;
newfee.FeeName = feecode.Name;
newfee.FeeCode = feecode.Code;
newfee.TaxRate = feecode.TaxRate == null ? 0 : (decimal)feecode.TaxRate;
newfee.BusinessType = BusinessType.OceanShippingExport;
string custShortName = string.Empty;
string custType = string.Empty;
if (fee.CustSettleFor.IndexOf("#") >= 0)
{
var currArg = fee.CustSettleFor.Split(new char[] { '#' });
custShortName = currArg[0]?.Trim();
if (currArg.Length == 2)
{
custType = currArg.LastOrDefault().Trim();
}
}
else
{
custShortName = fee.CustSettleFor?.Trim();
}
var customerInfo = tenantDb.Queryable<InfoClient>().ClearFilter(typeof(ISharedOrgId)).First(x => x.ShortName == custShortName);
newfee.CustomerId = customerInfo.Id;
newfee.CustomerName = customerInfo.Description;
if (!string.IsNullOrWhiteSpace(custType))
{
var custTypeKey = custTypeDict.FirstOrDefault(x => x.Value == custType);
newfee.CustomerType = custTypeKey.Key;
newfee.CustomerTypeText = custTypeKey.Value;
}
newfee.FeeType = FeeType.Payable; //租箱月结明细.FeeType;
var feeUnitKey = feeUnitDict.FirstOrDefault(x => x.Value == fee.CustFeeStandard?.Trim());
newfee.Unit = feeUnitKey.Key;
newfee.UnitText = feeUnitKey.Value;
var currCurrCode = codeCurrency.First(a => a.CodeName == fee.CustCurrency);
newfee.Currency = currCurrCode.CodeName;
decimal qty = 0;
if (fee.CustFeeStandard.Equals("箱"))
{
var ctnSumList = ctnList.GroupBy(a => a.Ctn)
.Select(a => new { Key = a.Key, Code = a.ToList().FirstOrDefault().CtnCode, Num = a.Sum(b => b.CtnNum.HasValue ? b.CtnNum.Value : 1) }).ToList();
if (ctnSumList.Count == 1)
{
newfee.Unit = ctnSumList.FirstOrDefault().Code;
newfee.UnitText = ctnSumList.FirstOrDefault().Key;
}
if (!fee.Quantity.HasValue)
{
qty = ctnSumList.Sum(x => x.Num);
}
else
{
qty = fee.Quantity.Value;
}
}
else if (fee.CustFeeStandard.Equals("票"))
{
qty = 1;
}
if (!fee.UnitPrice.HasValue)
{
if (fee.Amount.HasValue)
{
var price = fee.Amount.Value / qty;
newfee.TaxUnitPrice = price;
}
else
{
newfee.TaxUnitPrice = 0;
}
}
else
{
newfee.TaxUnitPrice = fee.UnitPrice.Value;
}
if (newfee.Currency.Equals("RMB", StringComparison.OrdinalIgnoreCase) || newfee.Currency.Equals("CNY", StringComparison.OrdinalIgnoreCase))
{
newfee.ExchangeRate = 1;
}
else
{
if (etd != DateTime.MinValue)
{
var exchangeInfo = tenantDb.Queryable<FeeCurrencyExchange>().ClearFilter(typeof(IOrgId))
.First(x => x.CurrencyCode == newfee.Currency && x.OrgId == booking.OrgId
&& x.StartDate.Value <= etd && x.EndDate.Value >= etd && x.LocalCurrency == "RMB");
if (exchangeInfo == null)
{
exchangeInfo = tenantDb.Queryable<FeeCurrencyExchange>().ClearFilter(typeof(IOrgId))
.First(x => x.CurrencyCode == newfee.Currency && x.StartDate.Value <= etd && x.EndDate.Value >= etd && x.LocalCurrency == "RMB");
}
if (exchangeInfo != null)
{
newfee.ExchangeRate = exchangeInfo.CRValue;
}
}
}
newfee.Quantity = qty;
newfee.Amount = fee.Amount.HasValue ? fee.Amount.Value : 0;
newfee.CreateTime = nowDate;
newfee.CreateBy = userInfo.Id;
newfee.CreateUserName = userInfo.UserName;
newfee.UpdateTime = nowDate;
//2024-11-08 按照董怡含要求,先不要默认审批通过,暂时关闭
//newfee.FeeStatus = FeeStatus.AuditPassed;
newfee.Note = "大简云账单解析";
_logger.LogInformation($"写入账单开始 第【{start}】条 GID={model.GID} BookingBill={model.BookingBill} Order={JsonConvert.SerializeObject(newfee)}");
tenantDb.Insertable<FeeRecord>(newfee).ExecuteCommand();
_logger.LogInformation($"写入账单完成 第【{start}】条 GID={model.GID} BookingBill={model.BookingBill} Order={JsonConvert.SerializeObject(newfee)}");
//入库成功
doResultDict.Add(fee.GID, new Tuple<string, bool>(qFee, true));
}
catch (Exception ex)
{
doResultDict.Add(fee.GID, new Tuple<string, bool>(qFee, false));
_logger.LogInformation($"明细写入产生异常qFee={qFee} 原因:{ex.Message}");
}
//callbackList.Add()
start++;
}
//如果存在失败情况,回执失败
if (doResultDict.Count(b => !b.Value.Item2) > 0)
{
reason = "入库失败," + string.Join(",", doResultDict.Where(b => !b.Value.Item2).ToArray());
SendCallBack(new SingleBillReceiveResult
{
ReceiveId = model.GID,
Success = false,
Reason = reason
});
}
else
{
//全部成功,推送成功回执
SendCallBack(new SingleBillReceiveResult
{
ReceiveId = model.GID,
Success = true,
Reason = string.Empty
});
}
}
else
{
if (!isNoNotice)
{
SendCallBack(new SingleBillReceiveResult
{
ReceiveId = model.GID,
Success = false,
Reason = reason
});
}
}
}
else
{
SendCallBack(new SingleBillReceiveResult
{
ReceiveId = model.GID,
Success = false,
Reason = "当前订单不存在"
});
}
}
catch (Exception ex)
{
_logger.LogInformation($"产生异常,原因:{ex.Message}");
if (!string.IsNullOrWhiteSpace(gid))
{
//SendCallBack(new SingleBillReceiveResult
//{
// ReceiveId = gid,
// Success = false,
// Reason = "当前订单不存在"
//});
}
}
}
private void SendCallBack(SingleBillReceiveResult dto)
{
_logger.LogInformation($"开始准备发送回执MQ json={JsonConvert.SerializeObject(dto)}");
var mqRlt = PublishMessage(new MQPublishMessageReqDto
{
BusinessId = dto.ReceiveId,
IsZip = false,
json = JsonConvert.SerializeObject(dto),
mqUri = AppSetting.app(new string[] { "FeeCallBacSettings", "MQUrl" }),
mqExchangeName = AppSetting.app(new string[] { "FeeCallBacSettings", "ExchangeName" }),
mqQueueName = AppSetting.app(new string[] { "FeeCallBacSettings", "QueueName" })
}).GetAwaiter().GetResult();
_logger.LogInformation($"发送回执MQ完成结果 json={JsonConvert.SerializeObject(mqRlt)}");
}
#region 发送MQ报文
/// <summary>
/// 发送MQ报文
/// </summary>
/// <param name="request">请求参数</param>
/// <returns>true-发送成功 false-发送失败</returns>
public async Task<string> PublishMessage(MQPublishMessageReqDto request)
{
bool isException = false;
string msg = string.Empty;
try
{
ConnectionFactory factory = new ConnectionFactory();
factory.Uri = new Uri(request.mqUri);
using (IConnection conn = factory.CreateConnection())
{
try
{
IModel mqModel = conn.CreateModel();
mqModel.ExchangeDeclare(request.mqExchangeName, ExchangeType.Direct);
//var queueName = $"{MqActionQueueName}.{(item.SubTenantId.HasValue && item.SubTenantId > 0 ? item.SubTenantId.Value : item.TenantId)}";
mqModel.QueueDeclare(request.mqQueueName, false, false, false, null);
mqModel.QueueBind(request.mqQueueName, request.mqExchangeName, request.mqQueueName, null);
byte[] messageBodyBytes = Encoding.UTF8.GetBytes(request.json);
IBasicProperties props = mqModel.CreateBasicProperties();
props.DeliveryMode = 2;
mqModel.BasicPublish(request.mqExchangeName, request.mqQueueName, props, messageBodyBytes);
_logger.LogInformation($"Id:{request.BusinessId},订舱数据回推,已发送数据到消息队列【{request.mqUri}】,队列名称:【{request.mqQueueName}】");
}
catch (Exception inne)
{
_logger.LogInformation($"Id:{request.BusinessId}推送MQ时发生异常原因:{inne.Message}");
msg = $"Id:{request.BusinessId}推送MQ时发生异常原因:{inne.Message}";
isException = true;
}
finally
{
conn.Close();
}
}
}
catch (Exception ex)
{
_logger.LogInformation($"Id:{request.BusinessId},启动推送MQ时发生异常原因:{ex.Message}");
msg = $"Id:{request.BusinessId},启动推送MQ时发生异常原因:{ex.Message}";
isException = true;
}
if (isException)
return msg;
return string.Empty;
}
#endregion
private FeeBillReadDto GetInfo(string json,out string msg)
{
FeeBillReadDto model = null;
msg = string.Empty;
try
{
model = JsonConvert.DeserializeObject<FeeBillReadDto>(json);
}
catch(Exception ex)
{
msg = $"转换报文异常,原因:{ex.Message}";
}
return model;
}
}
}