@ -76,6 +76,7 @@ using Myshipping.Application.Service.DataSync.Dto;
using RabbitMQ.Client ;
using System.Configuration ;
using System.Collections ;
using System.Security.Principal ;
namespace Myshipping.Application
{
@ -118,12 +119,16 @@ namespace Myshipping.Application
private readonly SqlSugarRepository < BookingTemplate > _bookingTemplate ;
private readonly SqlSugarRepository < ParaGoodsInfo > _paraGoodsInfoRepository ;
private readonly SqlSugarRepository < ParaContractNoInfo > _paraContractNoInfoRepository ;
private readonly SqlSugarRepository < DjyWebsiteAccountConfig > _djyWebsiteAccountConfigRepository ;
private readonly IHttpContextAccessor _httpContextAccessor ;
private readonly IBookingGoodsStatusConfigService _GoodsConfig ;
const string CONST_MAPPING_MODULE = "BOOK_OR_CLOSING" ;
const string CONST_MAPPING_MODULE_ROUTE = "BOOK_OR_CLOSING_RT" ;
private const string PrintRecentListTypeKey = "booking_print_recent_list" ;
const string CONST_TSL_EDI_URL = "tsl_edi_declare_url" ;
const string CONST_TSL_TYPE_CODE = "TslWeb" ;
public BookingOrderService ( SqlSugarRepository < BookingOrder > rep , SqlSugarRepository < BookingCtn > repCtn , SqlSugarRepository < BookingCtnDetail > ctndetailrep ,
SqlSugarRepository < BookingLog > bookinglog , SqlSugarRepository < BookingLogDetail > bookinglogdetail , SqlSugarRepository < BookingRemark > bookingremark ,
SqlSugarRepository < BookingFile > bookingfile , SqlSugarRepository < DjyUserConfig > repUserConfig , SqlSugarRepository < BookingPrintTemplate > repPrint ,
@ -133,7 +138,7 @@ namespace Myshipping.Application
SqlSugarRepository < BookingOrderUrl > repOrderUrl , SqlSugarRepository < BookingOrderContact > repOrderContact , SqlSugarRepository < BookingSampleBill > repSampleBill , SqlSugarRepository < DjyCustomer > djycustomer ,
SqlSugarRepository < BookingExcelTemplate > excelrep , SqlSugarRepository < DjyUserMailAccount > repUserMail , SqlSugarRepository < BookingGoodsStatus > goodsStatus , SqlSugarRepository < BookingGoodsStatusConfig > goodsStatusConfig ,
SqlSugarRepository < SysTenant > repTenant , SqlSugarRepository < BookingStatus > repBookingStatus , SqlSugarRepository < BookingEDIExt > bookingEDIExt , SqlSugarRepository < BookingServiceItem > serviceItem ,
SqlSugarRepository < ParaContractNoInfo > paraContractNoInfoRepository , IHttpContextAccessor httpContextAccessor , IBookingGoodsStatusConfigService GoodsConfig )
SqlSugarRepository < ParaContractNoInfo > paraContractNoInfoRepository , IHttpContextAccessor httpContextAccessor , IBookingGoodsStatusConfigService GoodsConfig , SqlSugarRepository < DjyWebsiteAccountConfig > djyWebsiteAccountConfigRepository )
{
this . _logger = logger ;
this . _rep = rep ;
@ -170,6 +175,8 @@ namespace Myshipping.Application
this . _paraContractNoInfoRepository = paraContractNoInfoRepository ;
_httpContextAccessor = httpContextAccessor ;
_GoodsConfig = GoodsConfig ;
_djyWebsiteAccountConfigRepository = djyWebsiteAccountConfigRepository ;
}
#region 主表和箱信息
@ -3946,6 +3953,31 @@ namespace Myshipping.Application
if ( ediSOSICfg = = null | | string . IsNullOrWhiteSpace ( ediSOSICfg . MapCode ) )
throw Oops . Bah ( $"CARRIERID={order.CARRIERID} 发送SO(SI)的船公司EDI代码未找到" ) ;
string postSpiderUrl = string . Empty ;
DjyWebsiteAccountConfig userWebAccountConfig = null ;
if ( ediRouteEnum = = EDIRouteEnum . TSL & & model . send )
{
if ( model . sendType . Equals ( "E" , StringComparison . OrdinalIgnoreCase ) )
throw Oops . Oh ( $"暂未提供TSL的截单发送" ) ;
postSpiderUrl = _cache . GetAllDictData ( ) . GetAwaiter ( ) . GetResult ( )
. FirstOrDefault ( x = > x . TypeCode = = "url_set" & & x . Code = = CONST_TSL_EDI_URL ) ? . Value ;
if ( string . IsNullOrWhiteSpace ( postSpiderUrl ) )
throw Oops . Bah ( $"字典未配置 url_set->{CONST_TSL_EDI_URL} 请联系管理员" ) ;
//获取个人对应的账户,这里GetAccountConfig逻辑优先取个人, 个人没有配置取公司对应配置
userWebAccountConfig = GetAccountConfig ( CONST_TSL_TYPE_CODE , UserManager . UserId , UserManager . TENANT_ID ) . GetAwaiter ( )
. GetResult ( ) ;
_logger . LogInformation ( "批次={no} 获取获取网站的账户完成, result={Num}" , batchNo , JSON . Serialize ( userWebAccountConfig ) ) ;
if ( userWebAccountConfig = = null )
throw Oops . Oh ( $" 未配置个人或公司网站账户,网站{CONST_TSL_TYPE_CODE}" ) ;
}
var ediModel = new EDIBaseModel ( ) ;
//2023-03-06 修改读取EDI配置方法, 所有提取配置必须是已启用的EnableFlag=true, 并且要根据SendType匹配发送类型, SendType=""表示使用订舱和截单, SO-订舱 SI-截单
@ -4280,23 +4312,23 @@ namespace Myshipping.Application
}
}
//运输条款EDI
var baseServiceList = _cache . GetAllCodeService ( ) . GetAwaiter ( ) . GetResult ( ) ;
if ( ! string . IsNullOrWhiteSpace ( order . SERVICE ) )
{
//运输条款EDI
var baseServiceList = _cache . GetAllCodeService ( ) . GetAwaiter ( ) . GetResult ( ) ;
var baseServiceInfo = baseServiceList . FirstOrDefault ( t = >
t . Name . Equals ( order . SERVICE , StringComparison . OrdinalIgnoreCase ) ) ;
var baseServiceInfo = baseServiceList . FirstOrDefault ( t = >
t . Name . Equals ( order . SERVICE , StringComparison . OrdinalIgnoreCase ) ) ;
if ( baseServiceInfo = = null )
throw Oops . Bah ( $"运输条款{order.SERVICE}的基础代码未找到" ) ;
if ( baseServiceInfo = = null )
throw Oops . Bah ( $"运输条款{order.SERVICE}的基础代码未找到" ) ;
//运输条款映射
var ediServiceList = _cache . GetAllMappingService ( ) . GetAwaiter ( ) . GetResult ( )
. Where ( t = > t . Module . Equals ( CONST_MAPPING_MODULE , StringComparison . OrdinalIgnoreCase )
& & ! string . IsNullOrWhiteSpace ( t . CarrierCode ) & & t . CarrierCode . Equals ( order . CARRIERID , StringComparison . OrdinalIgnoreCase )
) . ToList ( ) ;
//运输条款映射
var ediServiceList = _cache . GetAllMappingService ( ) . GetAwaiter ( ) . GetResult ( )
. Where ( t = > t . Module . Equals ( CONST_MAPPING_MODULE , StringComparison . OrdinalIgnoreCase )
& & ! string . IsNullOrWhiteSpace ( t . CarrierCode ) & & t . CarrierCode . Equals ( order . CARRIERID , StringComparison . OrdinalIgnoreCase )
) . ToList ( ) ;
if ( ! string . IsNullOrWhiteSpace ( order . SERVICE ) )
{
var currServiceInfo = ediServiceList . FirstOrDefault ( t = > t . Code . Equals ( baseServiceInfo . Code , StringComparison . OrdinalIgnoreCase ) ) ;
if ( currServiceInfo = = null )
@ -4305,22 +4337,23 @@ namespace Myshipping.Application
primaryModel . SERVICEEDICODE = currServiceInfo . MapCode ? . Trim ( ) ;
}
//签单方式EDI
var baseIssueTypeList = _cache . GetAllCodeIssueType ( ) . GetAwaiter ( ) . GetResult ( ) ;
var baseIssueTypeInfo = baseIssueTypeList . FirstOrDefault ( t = >
t . EnName . Equals ( order . ISSUETYPE , StringComparison . OrdinalIgnoreCase ) ) ;
if ( ! string . IsNullOrWhiteSpace ( order . ISSUETYPE ) )
{
//签单方式EDI
var baseIssueTypeList = _cache . GetAllCodeIssueType ( ) . GetAwaiter ( ) . GetResult ( ) ;
if ( baseIssueTypeInfo = = null )
throw Oops . Bah ( $"签单方式{order.ISSUETYPE}的基础代码未找到" ) ;
var baseIssueTypeInfo = baseIssueTypeList . FirstOrDefault ( t = >
t . EnName . Equals ( order . ISSUETYPE , StringComparison . OrdinalIgnoreCase ) ) ;
//签单方式映射
var ediIssueTypeList = _cache . GetAllMappingIssueType ( ) . GetAwaiter ( ) . GetResult ( )
. Where ( t = > t . Module . Equals ( CONST_MAPPING_MODULE , StringComparison . OrdinalIgnoreCase )
) . ToList ( ) ;
if ( baseIssueTypeInfo = = null )
throw Oops . Bah ( $"签单方式{order.ISSUETYPE}的基础代码未找到" ) ;
//签单方式映射
var ediIssueTypeList = _cache . GetAllMappingIssueType ( ) . GetAwaiter ( ) . GetResult ( )
. Where ( t = > t . Module . Equals ( CONST_MAPPING_MODULE , StringComparison . OrdinalIgnoreCase )
) . ToList ( ) ;
if ( ! string . IsNullOrWhiteSpace ( order . ISSUETYPE ) )
{
var currIssueTypeInfo = ediIssueTypeList . FirstOrDefault ( t = > ! string . IsNullOrWhiteSpace ( t . CarrierCode )
& & t . CarrierCode . Equals ( order . CARRIERID , StringComparison . OrdinalIgnoreCase )
& & t . Code . Equals ( baseIssueTypeInfo . Code , StringComparison . OrdinalIgnoreCase ) ) ;
@ -4536,6 +4569,10 @@ namespace Myshipping.Application
if ( model . send )
{
/ *
2023 - 05 - 24 这 里 新 增 TSL 的 判 断 , 如 果 是 走 TSL 则 默 认 走 吴 广 的 外 挂 , 需 要 提 供 个 人 账 户
* /
string currFilePath = string . Empty ;
if ( RuntimeInformation . IsOSPlatform ( OSPlatform . Linux ) )
@ -4563,40 +4600,48 @@ namespace Myshipping.Application
DateTime bDate = DateTime . Now ;
//上传FTP
CommonWebApiResult sendStatus = null ;
//是否发送邮件, EDI这里主要分2种通道发送 默认是FTP, 如果配置里指定了接收接收邮箱, 就需要推送邮件
bool isSendEmail = false ;
//是订舱并且FTP配置了订舱接收邮箱则触发邮箱发送
if ( ftpSet . SendType . Equals ( "SO" , StringComparison . OrdinalIgnoreCase )
& & model . sendType . Equals ( "B" , StringComparison . OrdinalIgnoreCase )
& & ! string . IsNullOrWhiteSpace ( ftpSet . RECEIVEEMAIL ) )
{
isSendEmail = true ;
}
else if ( ftpSet . SendType . Equals ( "SI" , StringComparison . OrdinalIgnoreCase )
& & model . sendType . Equals ( "E" , StringComparison . OrdinalIgnoreCase )
& & ! string . IsNullOrWhiteSpace ( ftpSet . RECEIVEEMAIL ) )
{
isSendEmail = true ;
}
else if ( string . IsNullOrWhiteSpace ( ftpSet . SendType )
& & ! string . IsNullOrWhiteSpace ( ftpSet . RECEIVEEMAIL ) )
{
isSendEmail = true ;
}
//上传FTP
CommonWebApiResult sendStatus = null ;
if ( isSendEmail )
//TSL单独走接口
if ( ediRouteEnum = = EDIRouteEnum . TSL )
{
//推送订舱邮件
sendStatus = await InnerSendBookingOrClosingEDIToEmail ( order , result . extra . ToString ( ) ,
model . sendType , result . extra2 . ToString ( ) , ftpSet ) ;
sendStatus = await InnerSendBookingOrClosingEDIToPOST ( result . extra . ToString ( ) , postSpiderUrl , userWebAccountConfig ) ;
}
else
{
sendStatus = await InnerSendBookingOrClosingEDIToFTP ( result . extra . ToString ( ) , ftpSet ) ;
//是订舱并且FTP配置了订舱接收邮箱则触发邮箱发送
if ( ftpSet . SendType . Equals ( "SO" , StringComparison . OrdinalIgnoreCase )
& & model . sendType . Equals ( "B" , StringComparison . OrdinalIgnoreCase )
& & ! string . IsNullOrWhiteSpace ( ftpSet . RECEIVEEMAIL ) )
{
isSendEmail = true ;
}
else if ( ftpSet . SendType . Equals ( "SI" , StringComparison . OrdinalIgnoreCase )
& & model . sendType . Equals ( "E" , StringComparison . OrdinalIgnoreCase )
& & ! string . IsNullOrWhiteSpace ( ftpSet . RECEIVEEMAIL ) )
{
isSendEmail = true ;
}
else if ( string . IsNullOrWhiteSpace ( ftpSet . SendType )
& & ! string . IsNullOrWhiteSpace ( ftpSet . RECEIVEEMAIL ) )
{
isSendEmail = true ;
}
if ( isSendEmail )
{
//推送订舱邮件
sendStatus = await InnerSendBookingOrClosingEDIToEmail ( order , result . extra . ToString ( ) ,
model . sendType , result . extra2 . ToString ( ) , ftpSet ) ;
}
else
{
sendStatus = await InnerSendBookingOrClosingEDIToFTP ( result . extra . ToString ( ) , ftpSet ) ;
}
}
DateTime eDate = DateTime . Now ;
@ -4615,12 +4660,23 @@ namespace Myshipping.Application
CreatedUserName = UserManager . Name
} ) ;
string sendTypeName = "FTP" ;
if ( isSendEmail )
{
sendTypeName = "邮件" ;
}
else if ( ediRouteEnum = = EDIRouteEnum . TSL )
{
sendTypeName = "POST" ;
}
await _bookinglogdetail . InsertReturnSnowflakeIdAsync ( new BookingLogDetail
{
PId = logId ,
Field = String . Empty ,
OldValue = String . Empty ,
NewValue = $"发送 {order.CARRIERID} EDI 类型={model.sendType} 通过{(isSendEmail ? " 邮 件 " : " FTP ")} {(sendStatus.succ ? " 成 功 " : " 失 败 ")}" ,
NewValue = $"发送 {order.CARRIERID} EDI 类型={model.sendType} 通过{ sendTypeName } {(sendStatus.succ ? "成 功 " : " 失 败 ")}" ,
} ) ;
if ( ! sendStatus . succ )
@ -4654,6 +4710,28 @@ namespace Myshipping.Application
}
# endregion
/// <summary>
/// 获取个人或公司网站账户配置
/// </summary>
/// <param name="typeCode">账户类型代码</param>
/// <param name="userId">用户ID</param>
/// <param name="tendId">租户ID</param>
/// <returns>返回账户配置</returns>
private async Task < DjyWebsiteAccountConfig > GetAccountConfig ( string typeCode , long userId , long tendId )
{
DjyWebsiteAccountConfig accountConfig = new DjyWebsiteAccountConfig ( ) ;
accountConfig = await _djyWebsiteAccountConfigRepository . EntityContext . CopyNew ( ) . Queryable < DjyWebsiteAccountConfig > ( )
. FirstAsync ( x = > x . TypeCode = = typeCode & & x . CreatedUserId = = userId ) ;
if ( accountConfig = = null )
{
accountConfig = await _djyWebsiteAccountConfigRepository . EntityContext . CopyNew ( ) . Queryable < DjyWebsiteAccountConfig > ( )
. FirstAsync ( x = > x . TypeCode = = typeCode & & x . TenantId = = tendId & & x . IsTenant = = true ) ;
}
return accountConfig ;
}
#region 下载订舱、截单EDI
/// <summary>
/// 下载订舱、截单EDI
@ -4780,6 +4858,74 @@ namespace Myshipping.Application
}
# endregion
/// <summary>
/// EDI发送POST请求
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="url">请求URL</param>
/// <param name="accountConfig">配置账户</param>
/// <returns>返回回执</returns>
private async Task < CommonWebApiResult > InnerSendBookingOrClosingEDIToPOST ( string filePath , string url , DjyWebsiteAccountConfig accountConfig )
{
CommonWebApiResult result = new CommonWebApiResult { succ = true } ;
CancellationTokenSource cts = new CancellationTokenSource ( ) ;
NameValueCollection par = new NameValueCollection ( ) ;
par . Add ( "user_key" , App . Configuration [ "BCOrDraftUserKey" ] ) ;
par . Add ( "user_secret" , App . Configuration [ "BCOrDraftUserSecret" ] ) ;
par . Add ( "web_user" , accountConfig . Account ? . Trim ( ) ) ;
par . Add ( "web_psw" , accountConfig . Password ? . Trim ( ) ) ;
_logger . LogInformation ( $"准备请求发送POST: {url} ,参数:{JSON.Serialize(par)},文件:{filePath}" ) ;
System . IO . FileStream file = new System . IO . FileStream ( filePath , FileMode . Open , FileAccess . Read ) ;
int SplitSize = 5242880 ; //5M分片长度
int index = 1 ; //序号 第几片
long StartPosition = 5242880 * ( index - 1 ) ;
long lastLens = file . Length - StartPosition ; //真不知道怎么起命了,就这样吧
if ( lastLens < 5242880 )
{
SplitSize = ( int ) lastLens ;
}
byte [ ] heByte = new byte [ SplitSize ] ;
file . Seek ( StartPosition , SeekOrigin . Begin ) ;
//第一个参数是 起始位置
file . Read ( heByte , 0 , SplitSize ) ;
//第三个参数是 读取长度(剩余长度)
file . Close ( ) ;
string strJoin = System . IO . File . ReadAllText ( filePath ) ;
DateTime bDate = DateTime . Now ;
_logger . LogInformation ( "POST 开始上传" ) ;
var res = FTPHelper . TransmitFtpFile ( url , par , new
{
file = "file" ,
fileName = Path . GetFileName ( filePath ) ,
fileBytes = heByte
} ) ;
DateTime eDate = DateTime . Now ;
TimeSpan ts = eDate . Subtract ( bDate ) ;
var timeDiff = ts . TotalMilliseconds ;
_logger . LogInformation ( $"请求POST 上传完成 上传文件大小:{heByte.Length} 用时:{timeDiff}ms.,{strJoin}" ) ;
_logger . LogInformation ( $"发送POST返回: {res}" ) ;
var jobjRetn = JObject . Parse ( res ) ;
if ( jobjRetn . GetStringValue ( "code" ) ! = "200" )
{
result . succ = false ;
result . msg = jobjRetn . GetStringValue ( "msg" ) ;
}
return result ;
}
#region 上传邮件
/// <summary>
/// 上传邮件