using Furion ;
using Furion.DependencyInjection ;
using Furion.DynamicApiController ;
using Furion.EventBus ;
using Furion.FriendlyException ;
using Furion.LinqBuilder ;
using Furion.RemoteRequest.Extensions ;
using Mapster ;
using MathNet.Numerics.LinearAlgebra.Factorization ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Http ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.Extensions.Hosting ;
using Microsoft.Extensions.Logging ;
using MiniExcelLibs ;
using Myshipping.Application.ConfigOption ;
using Myshipping.Application.EDI ;
using Myshipping.Application.Entity ;
using Myshipping.Application.Enum ;
using Myshipping.Application.Service.BookingOrder.Dto ;
using Myshipping.Core ;
using Myshipping.Core.Entity ;
using Myshipping.Core.Extension ;
using Myshipping.Core.Helper ;
using Myshipping.Core.Service ;
using Newtonsoft.Json ;
using Newtonsoft.Json.Linq ;
using NPOI.SS.Formula.PTG ;
using RabbitMQ.Client ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Drawing.Drawing2D ;
using System.IO ;
using System.Linq ;
using System.Net.Http ;
using System.Text ;
using System.Text.RegularExpressions ;
using System.Threading.Tasks ;
using Yitter.IdGenerator ;
namespace Myshipping.Application
{
/// <summary>
/// 客户订舱
/// </summary>
[ApiDescriptionSettings("Application", Name = "BookingCustomerOrder", Order = 1)]
public class BookingCustomerOrderService : IDynamicApiController , ITransient
{
private const string StaLogCateAudit = "cust_audit" ;
private readonly SqlSugarRepository < BookingCustomerOrder > _rep ;
private readonly SqlSugarRepository < BookingCtn > _repCtn ;
private readonly ILogger < BookingOrderService > _logger ;
private readonly ISysCacheService _cache ;
private readonly SqlSugarRepository < BookingFile > _repFile ;
private readonly SqlSugarRepository < BookingStatusLog > _repStatuslog ;
private readonly SqlSugarRepository < BookingStatusLogDetail > _repStatuslogDetail ;
private readonly SqlSugarRepository < BookingServiceItem > _repServiceItem ;
private readonly SqlSugarRepository < BookingOrder > _repOrder ;
private readonly SqlSugarRepository < BookingCustomerOrderTemplate > _repOrderTempl ;
private readonly SqlSugarRepository < BookingEDIExt > _repEdiExt ;
private readonly SqlSugarRepository < BookingGoodsStatus > _goodsStatus ;
private readonly SqlSugarRepository < BookingGoodsStatusConfig > _goodsStatusConfig ;
private readonly IEventPublisher _publisher ;
private readonly SqlSugarRepository < DjyApiAuth > _repApiAuth ;
private readonly SqlSugarRepository < DjyMessage > _repMessage ;
private readonly IBookingOrderService bookingOrderService ;
private readonly SqlSugarRepository < DjyCustomer > _repCustomer ;
private readonly SqlSugarRepository < DjyCustomerParamValue > _repCustomerParamValue ;
private readonly SqlSugarRepository < DjyCustomerContact > _repCustomerContact ;
private readonly SqlSugarRepository < BookingFeeRecord > _repFeeRecord ;
public BookingCustomerOrderService ( SqlSugarRepository < BookingCustomerOrder > rep , SqlSugarRepository < BookingCtn > repCtn ,
ILogger < BookingOrderService > logger , ISysCacheService cache , SqlSugarRepository < BookingFile > repFile ,
SqlSugarRepository < BookingStatusLog > statuslog , SqlSugarRepository < BookingServiceItem > repServiceItem ,
SqlSugarRepository < BookingOrder > repOrder , SqlSugarRepository < BookingStatusLogDetail > repStatuslogDetail ,
SqlSugarRepository < BookingCustomerOrderTemplate > repOrderTempl ,
SqlSugarRepository < BookingEDIExt > repEdiExt , SqlSugarRepository < BookingGoodsStatus > goodsStatus , SqlSugarRepository < BookingGoodsStatusConfig > goodsStatusConfig ,
IEventPublisher publisher , SqlSugarRepository < DjyApiAuth > repApiAuth , SqlSugarRepository < DjyMessage > repMessage , IBookingOrderService bookingOrderService ,
SqlSugarRepository < DjyCustomer > repCustomer , SqlSugarRepository < DjyCustomerParamValue > repCustomerParamValue , SqlSugarRepository < DjyCustomerContact > repCustomerContact ,
SqlSugarRepository < BookingFeeRecord > repFeeRecord )
{
this . _logger = logger ;
this . _rep = rep ;
this . _repCtn = repCtn ;
this . _cache = cache ;
this . _repFile = repFile ;
this . _repStatuslog = statuslog ;
this . _repServiceItem = repServiceItem ;
this . _repOrder = repOrder ;
this . _repStatuslogDetail = repStatuslogDetail ;
this . _repOrderTempl = repOrderTempl ;
this . _repEdiExt = repEdiExt ;
this . _goodsStatus = goodsStatus ;
this . _goodsStatusConfig = goodsStatusConfig ;
this . _publisher = publisher ;
this . _repApiAuth = repApiAuth ;
this . _repMessage = repMessage ;
this . bookingOrderService = bookingOrderService ;
this . _repCustomer = repCustomer ;
this . _repCustomerParamValue = repCustomerParamValue ;
this . _repCustomerContact = repCustomerContact ;
this . _repFeeRecord = repFeeRecord ;
}
#region 订舱草稿及附件
/// <summary>
/// 订舱草稿台账
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/PageData")]
public async Task < SqlSugarPagedList < BookingCustomerOrderListOutput > > PageData ( BookingCustomerOrderQueryInput input )
{
var query = _rep . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > x . TenantId = = UserManager . TENANT_ID )
. Where ( x = > ! x . IsDeleted )
. WhereIF ( input . Id > 0 , x = > x . Id = = input . Id )
. WhereIF ( ! string . IsNullOrEmpty ( input . BOOKINGNO ) , x = > x . BOOKINGNO . Contains ( input . BOOKINGNO ) )
. WhereIF ( ! string . IsNullOrEmpty ( input . VESSEL ) , x = > x . VESSEL . Contains ( input . VESSEL ) )
. WhereIF ( ! string . IsNullOrEmpty ( input . VOYNO ) , x = > x . VOYNO . Contains ( input . VOYNO ) )
. WhereIF ( ! string . IsNullOrEmpty ( input . YARDID ) , x = > x . YARDID = = input . YARDID )
. WhereIF ( ! string . IsNullOrEmpty ( input . YARD ) , x = > x . YARD . Contains ( input . YARD ) )
. WhereIF ( ! string . IsNullOrEmpty ( input . PORTDISCHARGEID ) , x = > x . PORTDISCHARGEID = = input . PORTDISCHARGEID )
. WhereIF ( ! string . IsNullOrEmpty ( input . PORTDISCHARGE ) , x = > x . PORTDISCHARGE . Contains ( input . PORTDISCHARGE ) )
. WhereIF ( ! string . IsNullOrEmpty ( input . CARRIERID ) , x = > x . CARRIERID = = input . CARRIERID )
. WhereIF ( ! string . IsNullOrEmpty ( input . CARRIER ) , x = > x . CARRIER . Contains ( input . CARRIER ) )
. WhereIF ( ! string . IsNullOrEmpty ( input . BookingTenantName ) , x = > x . BookingTenantName . Contains ( input . BookingTenantName ) )
. WhereIF ( input . ETDStart . HasValue , x = > x . ETD > = input . ETDStart )
. WhereIF ( input . ETDEnd . HasValue , x = > x . ETD < input . ETDEnd . Value . Date . AddDays ( 1 ) )
. WhereIF ( input . CreatedTimeStart . HasValue , x = > x . CreatedTime > = input . CreatedTimeStart )
. WhereIF ( input . CreatedTimeEnd . HasValue , x = > x . CreatedTime < input . CreatedTimeEnd . Value . Date . AddDays ( 1 ) )
. WhereIF ( input . UpdateTimeStart . HasValue , x = > x . UpdatedTime > = input . UpdateTimeStart )
. WhereIF ( input . UpdateTimeEnd . HasValue , x = > x . UpdatedTime < input . UpdateTimeEnd . Value . Date . AddDays ( 1 ) )
. WhereIF ( input . BSStatusList ! = null & & input . BSStatusList . Count > 0 , x = > input . BSStatusList . Contains ( x . BSSTATUS ) )
;
if ( ! string . IsNullOrEmpty ( input . SortField ) | | input . MultiSort = = null | | input . MultiSort . Count = = 0 )
{
query = query . OrderBy ( PageInputOrder . OrderBuilder ( input . SortField , input . DescSort ) ) ;
}
else
{
query = query . OrderBy ( PageInputOrder . MultiOrderBuilder ( input . MultiSort ) ) ;
}
var entities = await query . ToPagedListAsync ( input . PageNo , input . PageSize ) ;
var list = entities . Adapt < SqlSugarPagedList < BookingCustomerOrderListOutput > > ( ) ;
//动态日志
var bkIdList = list . Items . Select ( x = > x . Id ) . ToList ( ) ;
var staLogList = _repStatuslog . Where ( x = > bkIdList . Contains ( x . BookingId . Value ) & & x . Category = = StaLogCateAudit ) . ToList ( ) ;
foreach ( var item in list . Items )
{
item . LogList = staLogList . Where ( x = > x . BookingId = = item . Id ) . OrderByDescending ( x = > x . OpTime ) . Adapt < List < BookingCustomerLogDto > > ( ) ;
}
return list ;
}
/// <summary>
/// 保存草稿数据
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/Save")]
public async Task < BookingCustomerOrderSaveOutput > Save ( BookingCustomerOrderSaveInput input )
{
if ( input = = null )
{
throw Oops . Bah ( "请传入正常数据!" ) ;
}
var ms = JsonUtil . TrimFields ( input ) ;
if ( ! string . IsNullOrEmpty ( ms ) )
{
throw Oops . Bah ( ms ) ;
}
BookingCustomerOrder entity = null ;
List < BookingCtn > ctnList = new List < BookingCtn > ( ) ;
if ( input . Id = = 0 )
{
entity = input . Adapt < BookingCustomerOrder > ( ) ;
if ( string . IsNullOrEmpty ( entity . VOYNO ) )
{
entity . VOYNO = entity . VOYNOINNER ;
}
entity . BSSTATUS = "已录入" ;
entity . BOOKINGNO = $"BK{YitIdHelper.NextId()}" ;
await _rep . InsertAsync ( entity ) ;
}
else
{
entity = await _rep . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . Id = = input . Id ) ;
if ( entity . BSSTATUS = = "已提交" )
{
throw Oops . Bah ( "请先撤销提交后再修改" ) ;
}
if ( entity . BSSTATUS = = "已审核" )
{
throw Oops . Bah ( "已审核的数据不允许修改" ) ;
}
entity = input . Adapt ( entity ) ;
await _rep . UpdateAsync ( entity ) ;
await _repCtn . DeleteAsync ( x = > x . BILLID = = input . Id ) ;
}
//箱信息保存
if ( input . CtnList ! = null )
{
foreach ( var item in input . CtnList )
{
var ctnentity = item . Adapt < BookingCtn > ( ) ;
ctnentity . BILLID = entity . Id ;
await _repCtn . InsertAsync ( ctnentity ) ;
ctnList . Add ( ctnentity ) ;
}
var groupList = input . CtnList . Where ( x = > x . CTNNUM > 0 ) . GroupBy ( c = > c . CTNALL ) . Select ( g = > $"{g.Key}*{g.Sum(gg => gg.CTNNUM)}" ) ;
entity . CNTRTOTAL = string . Join ( " / " , groupList ) ;
}
else
{
entity . CNTRTOTAL = "" ;
}
await _rep . UpdateAsync ( entity ) ;
//服务项目
_repServiceItem . Delete ( x = > x . BookingId = = entity . Id ) ;
foreach ( var item in input . ServiceItemList )
{
var bsi = item . Adapt < BookingServiceItem > ( ) ;
bsi . Id = YitIdHelper . NextId ( ) ;
bsi . BookingId = entity . Id ;
await _repServiceItem . InsertAsync ( bsi ) ;
}
//文件
var dbFiles = _repFile . AsQueryable ( ) . Where ( x = > x . BookingId = = entity . Id ) . ToList ( ) ;
var opt = App . GetOptions < BookingAttachOptions > ( ) ;
var dirAbs = string . Empty ;
if ( string . IsNullOrEmpty ( opt . basePath ) )
{
dirAbs = Path . Combine ( App . WebHostEnvironment . WebRootPath , opt . relativePath ) ;
}
else
{
dirAbs = Path . Combine ( opt . basePath , opt . relativePath ) ;
}
if ( ! Directory . Exists ( dirAbs ) )
Directory . CreateDirectory ( dirAbs ) ;
//清除前端已删除的文件
if ( input . Files ! = null & & input . Files . Count ( ) > 0 )
{
var delIds = dbFiles . Where ( x = > ! input . Files . Contains ( x . Id ) ) . Select ( x = > x . Id ) ;
await _repFile . DeleteAsync ( x = > delIds . Contains ( x . Id ) ) ;
}
else
{
await _repFile . DeleteAsync ( x = > x . BookingId = = entity . Id ) ;
}
//临时文件转为正式文件
if ( input . TempFileNames ! = null & & input . TempFileNames . Count ( ) > 0 )
{
var optTempFile = App . GetOptions < TempFileOptions > ( ) . Path ;
foreach ( var tmpFile in input . TempFileNames )
{
var tempPath = Path . Combine ( optTempFile , tmpFile ) ;
if ( File . Exists ( tempPath ) )
{
var saveFileName = $"{DateTime.Now.Ticks}{Path.GetExtension(tmpFile)}" ;
var fileRelaPath = Path . Combine ( opt . relativePath , saveFileName ) . ToLower ( ) ;
var fileAbsPath = Path . Combine ( dirAbs , saveFileName ) . ToLower ( ) ;
File . Copy ( tempPath , fileAbsPath , true ) ;
var newFile = new BookingFile
{
Id = YitIdHelper . NextId ( ) ,
FileName = Path . GetFileName ( tmpFile ) ,
FilePath = fileRelaPath ,
TypeCode = "tuodan" ,
TypeName = "托单文件" ,
BookingId = entity . Id ,
} ;
await _repFile . InsertAsync ( newFile ) ;
}
}
}
//日志动态
SaveAuditLog ( input . Id = = 0 ? "已录入" : "已修改" , entity . Id ) ;
//返回给前端数据
var outModel = entity . Adapt < BookingCustomerOrderSaveOutput > ( ) ;
outModel . CtnList = ctnList . Adapt < List < BookingCustomerCtnDto > > ( ) ;
var dicFile = new Dictionary < long , string > ( ) ;
_repFile . AsQueryable ( ) . Where ( x = > x . BookingId = = entity . Id ) . ForEach ( x = > dicFile . Add ( x . Id , x . FileName ) ) ;
outModel . Files = dicFile ;
outModel . LogList = _repStatuslog . AsQueryable ( ) . Where ( x = > x . BookingId = = entity . Id & & x . Category = = StaLogCateAudit ) . OrderByDescending ( x = > x . OpTime ) . ToList ( ) . Adapt < List < BookingCustomerLogDto > > ( ) ;
outModel . ServiceItemList = _repServiceItem . AsQueryable ( ) . Where ( x = > x . BookingId = = entity . Id ) . ToList ( ) . Adapt < List < BookingServiceItemCustomerDto > > ( ) ;
return outModel ;
}
private async Task SaveData ( BookingCustomerOrder entity , List < BookingCtn > ctns , List < BookingServiceItem > servList , bool ins )
{
if ( ins )
{
if ( string . IsNullOrEmpty ( entity . VOYNO ) )
{
entity . VOYNO = entity . VOYNOINNER ;
}
entity . Id = YitIdHelper . NextId ( ) ;
entity . BSSTATUS = "已录入" ;
entity . BOOKINGNO = $"BK{YitIdHelper.NextId()}" ;
await _rep . InsertAsync ( entity ) ;
}
else
{
if ( entity . BSSTATUS ! = "已录入" & & entity . BSSTATUS ! = "已驳回" )
{
throw Oops . Bah ( "当前状态不允许修改" ) ;
}
if ( string . IsNullOrEmpty ( entity . VOYNO ) )
{
entity . VOYNO = entity . VOYNOINNER ;
}
await _rep . UpdateAsync ( entity ) ;
await _repCtn . DeleteAsync ( x = > x . BILLID = = entity . Id ) ;
}
//箱信息保存
if ( ctns ! = null )
{
foreach ( var ctn in ctns )
{
ctn . Id = YitIdHelper . NextId ( ) ;
ctn . BILLID = entity . Id ;
await _repCtn . InsertAsync ( ctn ) ;
}
var groupList = ctns . Where ( x = > x . CTNNUM > 0 ) . GroupBy ( c = > c . CTNALL ) . Select ( g = > $"{g.Key}*{g.Sum(gg => gg.CTNNUM)}" ) ;
entity . CNTRTOTAL = string . Join ( " / " , groupList ) ;
}
else
{
entity . CNTRTOTAL = "" ;
}
await _rep . UpdateAsync ( entity ) ;
if ( servList = = null | | servList . Count = = 0 )
{
throw Oops . Bah ( "必须选择服务项目" ) ;
}
//服务项目
_repServiceItem . Delete ( x = > x . BookingId = = entity . Id ) ;
foreach ( var srv in servList )
{
srv . Id = YitIdHelper . NextId ( ) ;
srv . BookingId = entity . Id ;
await _repServiceItem . InsertAsync ( srv ) ;
}
}
/// <summary>
/// 获取详情
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/Get")]
public async Task < BookingCustomerOrderSaveOutput > Get ( long id )
{
var entity = await _rep . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . Id = = id ) ;
var outModel = entity . Adapt < BookingCustomerOrderSaveOutput > ( ) ;
outModel . CtnList = _repCtn . Where ( x = > x . BILLID = = id ) . ToList ( ) . Adapt < List < BookingCustomerCtnDto > > ( ) ;
var dicFile = new Dictionary < long , string > ( ) ;
_repFile . AsQueryable ( ) . Where ( x = > x . BookingId = = entity . Id ) . ForEach ( x = > dicFile . Add ( x . Id , x . FileName ) ) ;
outModel . Files = dicFile ;
outModel . LogList = _repStatuslog . AsQueryable ( ) . Where ( x = > x . BookingId = = entity . Id & & x . Category = = StaLogCateAudit ) . OrderByDescending ( x = > x . OpTime ) . ToList ( ) . Adapt < List < BookingCustomerLogDto > > ( ) ;
outModel . ServiceItemList = _repServiceItem . AsQueryable ( ) . Where ( x = > x . BookingId = = entity . Id ) . ToList ( ) . Adapt < List < BookingServiceItemCustomerDto > > ( ) ;
return outModel ;
}
/// <summary>
/// 上传临时文件
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/UploadTempFile")]
public async Task < string > UploadTempFile ( IFormFile file )
{
//未上传文件
if ( file = = null | | file . Length = = 0 )
{
throw Oops . Bah ( "未上传任何文件" ) ;
}
var optTempFile = App . GetOptions < TempFileOptions > ( ) . Path ;
var tempFilePath = $"{DateTime.Now.Ticks}" ; //临时存放目录
var tempSavePath = Path . Combine ( optTempFile , tempFilePath ) ;
Directory . CreateDirectory ( tempSavePath ) ;
var fileFullPath = Path . Combine ( tempSavePath , file . FileName ) ; //服务器路径
using ( var stream = File . Create ( fileFullPath ) )
{
await file . CopyToAsync ( stream ) ;
}
return Path . Combine ( tempFilePath , file . FileName ) ;
}
/// <summary>
/// 下载查看上传的文件
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet("/BookingCustomerOrder/GetFile"), AllowAnonymous]
public async Task < IActionResult > GetFile ( long id )
{
var savedFile = await _repFile . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( u = > u . Id = = id ) ;
if ( savedFile = = null )
{
throw Oops . Oh ( "文件不存在" ) ;
}
var opt = App . GetOptions < BookingAttachOptions > ( ) ;
var dirAbs = opt . basePath ;
if ( string . IsNullOrEmpty ( dirAbs ) )
{
dirAbs = App . WebHostEnvironment . WebRootPath ;
}
var fileFullPath = Path . Combine ( dirAbs , savedFile . FilePath ) ;
if ( ! File . Exists ( fileFullPath ) )
{
throw Oops . Oh ( "文件不存在" ) ;
}
//var fileName = HttpUtility.UrlEncode(savedFile.FileName, Encoding.GetEncoding("UTF-8"));
var result = new FileStreamResult ( new FileStream ( fileFullPath , FileMode . Open ) , "application/octet-stream" ) { FileDownloadName = savedFile . FileName } ;
return result ;
}
/// <summary>
/// 根据文件名称下载查看上传的文件
/// </summary>
/// <param name="fn">文件路径名称</param>
/// <param name="isTemp">是否为临时文件</param>
/// <returns></returns>
[HttpGet("/BookingCustomerOrder/GetFileByName"), AllowAnonymous]
public async Task < IActionResult > GetFileByName ( string fn , bool isTemp = true )
{
var fileFullPath = "" ;
if ( isTemp )
{
var optTempFile = App . GetOptions < TempFileOptions > ( ) . Path ;
fileFullPath = Path . Combine ( optTempFile , fn ) ; //服务器路径
}
else
{
var opt = App . GetOptions < BookingAttachOptions > ( ) ;
if ( string . IsNullOrEmpty ( opt . basePath ) )
{
fileFullPath = Path . Combine ( App . WebHostEnvironment . WebRootPath , fn ) ; //服务器路径
}
else
{
fileFullPath = Path . Combine ( opt . basePath , fn ) ; //服务器路径
}
}
if ( ! File . Exists ( fileFullPath ) )
{
_logger . LogError ( $"未能找到文件:{fileFullPath}" ) ;
throw Oops . Oh ( "文件不存在" ) ;
}
//var fileName = HttpUtility.UrlEncode(savedFile.FileName, Encoding.GetEncoding("UTF-8"));
var result = new FileStreamResult ( new FileStream ( fileFullPath , FileMode . Open ) , "application/octet-stream" ) { FileDownloadName = Path . GetFileName ( fn ) } ;
return result ;
}
/// <summary>
/// 删除
/// </summary>
/// <param name="ids"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/Delete")]
public async Task Delete ( List < long > ids )
{
var list = await _rep . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > ids . Contains ( x . Id ) ) . ToListAsync ( ) ;
var canNotDelList = list . Where ( x = > x . BSSTATUS ! = "已录入" & & x . BSSTATUS ! = "已驳回" ) ;
if ( canNotDelList . Any ( ) )
{
var errMsg = string . Join ( "\r\n" , canNotDelList . Select ( x = > $"{x.BOOKINGNO}的数据当前状态不能删除" ) . ToList ( ) ) ;
throw Oops . Bah ( errMsg ) ;
}
list . ForEach ( x = >
{
x . IsDeleted = true ;
_rep . Update ( x ) ;
} ) ;
}
# endregion
#region 客户端操作与接口
/// <summary>
/// 提交订舱
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/Submit")]
public async Task < string > Submit ( List < long > ids )
{
var recUrl = _cache . GetAllSysConfig ( ) . Result . FirstOrDefault ( x = > x . Code = = "DjyBookingRequestReceiveUrl" ) ;
if ( recUrl = = null | | string . IsNullOrEmpty ( recUrl . Value ) )
{
throw Oops . Bah ( "大简云接收订舱URL地址未配置, 请联系管理员" ) ;
}
var userId = _cache . GetAllSysConfig ( ) . Result . FirstOrDefault ( x = > x . Code = = "DjyBookingReceiveUserId" ) ;
var userSecret = _cache . GetAllSysConfig ( ) . Result . FirstOrDefault ( x = > x . Code = = "DjyBookingReceiveUserSecret" ) ;
if ( userId = = null | | string . IsNullOrEmpty ( userId . Value ) | | userSecret = = null | | string . IsNullOrEmpty ( userSecret . Value ) )
{
throw Oops . Bah ( "大简云接收订舱用户key和秘钥未配置, 请联系管理员" ) ;
}
//构建数据并发送
var orderList = _rep . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > ids . Contains ( x . Id ) ) . ToList ( ) ;
//2023-9-1, 衣国豪: 点击发送订舱时, 最少得填写船公司, 船期, 目的地, 品名, 箱型, 箱量, 重量, 如果以上信息没填, 允许保存, 但是发送订舱时给出提示: XXX不能为空, 请补充后重新发送
var emptyCarrList = orderList . Where ( x = > string . IsNullOrEmpty ( x . CARRIERID ) ) . Select ( x = > x . BOOKINGNO ) . ToList ( ) ;
if ( emptyCarrList . Any ( ) )
{
throw Oops . Bah ( $"船公司不能为空:\r\n{string.Join(" \ r \ n ", emptyCarrList)}\r\n请补充后重新发送" ) ;
}
var emptyETD = orderList . Where ( x = > ! x . ETD . HasValue ) . Select ( x = > x . BOOKINGNO ) . ToList ( ) ;
if ( emptyETD . Any ( ) )
{
throw Oops . Bah ( $"船期不能为空:\r\n{string.Join(" \ r \ n ", emptyETD)}\r\n请补充后重新发送" ) ;
}
var emptyDischarge = orderList . Where ( x = > string . IsNullOrEmpty ( x . PORTDISCHARGEID ) ) . Select ( x = > x . BOOKINGNO ) . ToList ( ) ;
if ( emptyDischarge . Any ( ) )
{
throw Oops . Bah ( $"目的地不能为空:\r\n{string.Join(" \ r \ n ", emptyDischarge)}\r\n请补充后重新发送" ) ;
}
var emptyDescrip = orderList . Where ( x = > string . IsNullOrEmpty ( x . DESCRIPTION ) ) . Select ( x = > x . BOOKINGNO ) . ToList ( ) ;
if ( emptyDescrip . Any ( ) )
{
throw Oops . Bah ( $"品名不能为空:\r\n{string.Join(" \ r \ n ", emptyDescrip)}\r\n请补充后重新发送" ) ;
}
var emptyKgs = orderList . Where ( x = > ! x . KGS . HasValue ) . Select ( x = > x . BOOKINGNO ) . ToList ( ) ;
if ( emptyKgs . Any ( ) )
{
throw Oops . Bah ( $"重量不能为空:\r\n{string.Join(" \ r \ n ", emptyKgs)}\r\n请补充后重新发送" ) ;
}
var ordIdList = orderList . Select ( o = > o . Id ) . ToList ( ) ;
var ctnList = _repCtn . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > ordIdList . Contains ( x . BILLID . Value ) ) . ToList ( ) ;
//2023-9-1, 衣国豪: 点击发送订舱时, 最少得填写船公司, 船期, 目的地, 品名, 箱型, 箱量, 重量, 如果以上信息没填, 允许保存, 但是发送订舱时给出提示: XXX不能为空, 请补充后重新发送
var emptyCtn = ctnList . Where ( x = > string . IsNullOrEmpty ( x . CTNALL ) | | ! x . CTNNUM . HasValue ) . Select ( x = > x . BILLID ) . Distinct ( ) . ToList ( ) ;
if ( emptyCtn . Any ( ) )
{
var emptyCtnOrd = orderList . Where ( x = > emptyCtn . Contains ( x . Id ) ) . Select ( x = > x . BOOKINGNO ) . ToList ( ) ;
throw Oops . Bah ( $"箱型箱量不能为空:\r\n{string.Join(" \ r \ n ", emptyCtnOrd)}\r\n请补充后重新发送" ) ;
}
var fileList = _repFile . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > ordIdList . Contains ( x . BookingId ) ) . ToList ( ) ;
var serviceItemList = _repServiceItem . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > ordIdList . Contains ( x . BookingId . Value ) ) . ToList ( ) ;
var sendList = new List < BookingCustomerSubmitDto > ( ) ;
var opt = App . GetOptions < BookingAttachOptions > ( ) ;
var dirAbs = opt . basePath ;
if ( string . IsNullOrEmpty ( dirAbs ) )
{
dirAbs = App . WebHostEnvironment . WebRootPath ;
}
//当前系统的url
var sysUrlCfg = _cache . GetAllSysConfig ( ) . Result . FirstOrDefault ( x = > x . Code = = "SystemUrl" ) ;
var sysUrl = sysUrlCfg . Value ;
if ( ! sysUrl . EndsWith ( "/" ) )
{
sysUrl + = "/" ;
}
//接收回推数据的接口key和秘钥 RecBookingFeedback
var apiAuth = _repApiAuth . AsQueryable ( ) . Filter ( null , true ) . First ( x = > x . ApiCode = = "RecBookingFeedback" & & x . TenantId = = UserManager . TENANT_ID ) ;
if ( apiAuth = = null )
{
throw Oops . Bah ( "回推数据接收接口授权未配置" ) ;
}
foreach ( var order in orderList )
{
if ( order . BSSTATUS ! = "已录入" & & order . BSSTATUS ! = "已驳回" )
{
throw Oops . Bah ( $"{order.BOOKINGNO} 当前状态为{order.BSSTATUS},不能提交" ) ;
}
var dto = order . Adapt < BookingCustomerSubmitDto > ( ) ;
dto . BookingTenantId = UserManager . TENANT_ID ;
dto . BookingTenantName = UserManager . TENANT_NAME ;
dto . BookingCompanyId = UserManager . DjyCompanyId ;
dto . BookingUserId = UserManager . UserId ;
dto . BookingUserName = UserManager . Name ;
dto . BookingDjyUserId = UserManager . DjyUserId ;
dto . FeedbackUrl = $"{sysUrl}BookingCustomerOrder/RecBookingFeedback" ;
dto . FeedbackKey = apiAuth . ApiKey ;
dto . FeedbackSecret = apiAuth . ApiSecret ;
dto . CtnList = ctnList . Where ( x = > x . BILLID = = order . Id ) . ToList ( ) . Adapt < List < BookingCustomerCtnDto > > ( ) ;
dto . ServiceItemList = serviceItemList . Where ( x = > x . BookingId = = order . Id ) . ToList ( ) . Adapt < List < BookingServiceItemCustomerDto > > ( ) ;
dto . Files = fileList . Where ( x = > x . BookingId = = order . Id ) . ToList ( ) . Adapt < List < BookingFileSyncCustomerDto > > ( ) ;
sendList . Add ( dto ) ;
}
//构建完整url
var submitUrl = recUrl . Value ;
// 如果当前环境为开发环境,则请求本机运营端程序的接口地址,来进行调试
if ( App . HostEnvironment . IsDevelopment ( ) )
{
submitUrl = "http://localhost:5130" ;
// 更改回推接收地址
sendList . ForEach ( x = > x . FeedbackUrl = $"{App.Configuration[" Url "]}/BookingCustomerOrder/RecBookingFeedback" ) ;
}
if ( ! submitUrl . EndsWith ( "/" ) )
{
submitUrl + = "/" ;
}
submitUrl + = "BookingCustomerOrder/ReceiveBooking" ;
_logger . LogInformation ( $"提交订舱数据({submitUrl}, {userId.Value}, {userSecret.Value}) : {JsonConvert.SerializeObject(sendList)}" ) ;
var rtn = await submitUrl
. SetHeaders ( new Dictionary < string , object > {
{ CommonConst . API_USER_HEADER_KEY , userId . Value } ,
{ CommonConst . API_USER_HEADER_SECRET , userSecret . Value }
} )
. SetBody ( sendList )
. PostAsStringAsync ( ) ;
_logger . LogInformation ( $"返回数据:{rtn}" ) ;
var resultText = new StringBuilder ( ) ;
var jobjRtn = JObject . Parse ( rtn ) ;
if ( jobjRtn . GetIntValue ( "code" ) ! = 200 )
{
throw Oops . Bah ( jobjRtn . GetStringValue ( "message" ) ) ;
}
else
{
var arrData = jobjRtn . GetJArrayValue ( "data" ) ;
foreach ( JObject item in arrData )
{
var id = item . GetLongValue ( "id" ) ;
var bookingno = item . GetStringValue ( "bookingno" ) ;
var message = item . GetStringValue ( "message" ) ;
var succ = item . GetBooleanValue ( "success" ) ;
if ( succ )
{
var model = _rep . AsQueryable ( ) . Filter ( null , true ) . First ( x = > x . Id = = id ) ;
model . BSSTATUS = "已提交" ;
await _rep . UpdateAsync ( model ) ;
//日志动态
SaveAuditLog ( "已提交" , id ) ;
}
else
{
//日志动态
SaveAuditLog ( $"提交失败" , id , remark : item . GetStringValue ( "message" ) ) ;
}
resultText . AppendLine ( $"{bookingno}: {message}" ) ;
}
return resultText . ToString ( ) ;
}
}
/// <summary>
/// 取消提交订舱
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/CancelSubmit")]
public async Task < string > CancelSubmit ( List < long > ids )
{
var recUrl = _cache . GetAllSysConfig ( ) . Result . FirstOrDefault ( x = > x . Code = = "DjyBookingRequestReceiveUrl" ) ;
if ( recUrl = = null | | string . IsNullOrEmpty ( recUrl . Value ) )
{
throw Oops . Bah ( "大简云接收订舱URL地址未配置, 请联系管理员" ) ;
}
var userId = _cache . GetAllSysConfig ( ) . Result . FirstOrDefault ( x = > x . Code = = "DjyBookingReceiveUserId" ) ;
var userSecret = _cache . GetAllSysConfig ( ) . Result . FirstOrDefault ( x = > x . Code = = "DjyBookingReceiveUserSecret" ) ;
if ( userId = = null | | string . IsNullOrEmpty ( userId . Value ) | | userSecret = = null | | string . IsNullOrEmpty ( userSecret . Value ) )
{
throw Oops . Bah ( "大简云接收订舱用户key和秘钥未配置, 请联系管理员" ) ;
}
var orderList = _rep . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > ids . Contains ( x . Id ) ) . ToList ( ) ;
var noSubmitList = orderList . Where ( x = > x . BSSTATUS ! = "已提交" ) . Select ( x = > x . BOOKINGNO ) . ToList ( ) ;
if ( noSubmitList . Count > 0 )
{
throw Oops . Bah ( $"编号为 {string.Join(" , ", noSubmitList)} 的状态不能取消订舱" ) ;
}
var sendList = orderList . Select ( x = > new BookingCustomerCancelSubmitDto ( )
{
Id = x . Id . ToString ( ) ,
BOOKINGNO = x . BOOKINGNO
} ) . ToList ( ) ;
//构建完整url
var submitUrl = recUrl . Value ;
if ( ! submitUrl . EndsWith ( "/" ) )
{
submitUrl + = "/" ;
}
submitUrl + = "BookingCustomerOrder/CancelBooking" ;
_logger . LogInformation ( $"取消提交订舱数据({submitUrl}, {userId.Value}, {userSecret.Value}) : {JsonConvert.SerializeObject(sendList)}" ) ;
var rtn = await submitUrl
. SetHeaders ( new Dictionary < string , object > {
{ CommonConst . API_USER_HEADER_KEY , userId . Value } ,
{ CommonConst . API_USER_HEADER_SECRET , userSecret . Value }
} )
. SetBody ( sendList )
. PostAsStringAsync ( ) ;
_logger . LogInformation ( $"返回数据:{rtn}" ) ;
var resultText = new StringBuilder ( ) ;
var jobjRtn = JObject . Parse ( rtn ) ;
if ( jobjRtn . GetIntValue ( "code" ) ! = 200 )
{
throw Oops . Bah ( jobjRtn . GetStringValue ( "message" ) ) ;
}
else
{
var arrData = jobjRtn . GetJArrayValue ( "data" ) ;
foreach ( JObject item in arrData )
{
var id = item . GetLongValue ( "id" ) ;
var bookingno = item . GetStringValue ( "bookingno" ) ;
var message = item . GetStringValue ( "message" ) ;
var succ = item . GetBooleanValue ( "success" ) ;
if ( succ )
{
var model = _rep . AsQueryable ( ) . Filter ( null , true ) . First ( x = > x . Id = = id ) ;
model . BSSTATUS = "已录入" ;
await _rep . UpdateAsync ( model ) ;
//日志动态
SaveAuditLog ( $"取消提交" , id ) ;
}
else
{
//日志动态
SaveAuditLog ( $"取消提交失败" , id , remark : item . GetStringValue ( "message" ) ) ;
}
resultText . AppendLine ( $"{bookingno}: {message}" ) ;
}
return resultText . ToString ( ) ;
}
}
#region 客户订舱模板
/// <summary>
/// 客户订舱模板列表
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/OrderTemplateList")]
public async Task < SqlSugarPagedList < BookingCustomerTemplateQueryOutput > > OrderTemplateList ( BookingCustomerTemplateQueryInput input )
{
var query = _repOrderTempl . AsQueryable ( )
. Where ( t = > t . CreatedUserId = = UserManager . UserId )
. WhereIF ( ! string . IsNullOrEmpty ( input . Title ) , t = > t . Title . Contains ( input . Title ) )
. Select ( t = > new BookingCustomerTemplateQueryOutput ( )
{
Id = t . Id ,
Title = t . Title ,
} ) ;
if ( ! string . IsNullOrEmpty ( input . SortField ) | | input . MultiSort = = null | | input . MultiSort . Count = = 0 )
{
query = query . OrderBy ( PageInputOrder . OrderBuilder ( input . SortField , input . DescSort ) ) ;
}
else
{
query = query . OrderBy ( PageInputOrder . MultiOrderBuilder ( input . MultiSort ) ) ;
}
return await query . ToPagedListAsync ( input . PageNo , input . PageSize ) ;
}
/// <summary>
/// 客户订舱模板删除
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/OrderTemplateDel")]
public async Task OrderTemplateDel ( long id )
{
await _repOrderTempl . DeleteAsync ( id ) ;
}
/// <summary>
/// 客户订舱模板保存
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/OrderTemplateSave")]
public async Task OrderTemplateSave ( BookingCustomerTemplateSaveInput model )
{
if ( string . IsNullOrEmpty ( model . Title ) )
{
throw Oops . Bah ( "请输入模板名称" ) ;
}
var template = model . Adapt < BookingCustomerOrderTemplate > ( ) ;
await _repOrderTempl . InsertAsync ( template ) ;
}
/// <summary>
/// 客户订舱模板内容
/// </summary>
/// <returns></returns>
[HttpGet("/BookingCustomerOrder/GetOrderTemplate")]
public async Task < string > GetOrderTemplate ( long id )
{
var objTemp = await _repOrderTempl . FirstOrDefaultAsync ( x = > x . Id = = id ) ;
if ( objTemp = = null )
{
throw Oops . Bah ( "模板未找到" ) ;
}
return objTemp . JsonContent ;
}
# endregion
//[HttpPost("/BookingCustomerOrder/FeedbackTest"), AllowAnonymous]
//public async Task FeedbackTest(string json)
//{
//}
/// <summary>
/// 接收订舱回推统一接口
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/RecBookingFeedback"), AllowAnonymous, ApiUser(ApiCode = "RecBookingFeedback")]
public async Task < dynamic > RecBookingFeedback ( string feedbackType , string jsonContent , string syncType )
{
_logger . LogInformation ( $"收到订舱回推数据, feedbackType: {feedbackType}, jsonContent: {jsonContent}, syncType: {syncType}" ) ;
if ( string . IsNullOrEmpty ( feedbackType ) | | string . IsNullOrEmpty ( jsonContent ) )
{
throw Oops . Bah ( "参数有误" ) ;
}
#region 审核反馈
if ( feedbackType = = BookingFeedbackType . Audit . ToString ( ) )
{
var recModel = JsonConvert . DeserializeObject < BookingCustomerRecAduitFeedbackDto > ( jsonContent ) ;
var id = Convert . ToInt64 ( recModel . Id ) ;
var model = _rep . AsQueryable ( ) . Filter ( null , true ) . First ( x = > x . Id = = id ) ;
if ( model = = null )
{
throw Oops . Bah ( "未找到数据" ) ;
}
//if (model.BSSTATUS != "已提交")
//{
// throw Oops.Bah("当前状态不能接受审核回推");
//}
if ( recModel . Accept )
{
model . BSSTATUS = "已审核" ;
}
else
{
model . BSSTATUS = "已驳回" ;
}
await _rep . UpdateAsync ( model ) ;
//日志动态
SaveAuditLog ( $"{model.BSSTATUS}" , id , model . CreatedUserId . Value , model . TenantId . Value , "系统" , remark : $"审核意见:{recModel.Comment}" ) ;
long bookingId = 0 ;
//进入客户订舱系统的订舱台账
if ( recModel . Accept )
{
var bkOrder = model . Adapt < BookingOrder > ( ) ;
bkOrder . Id = YitIdHelper . NextId ( ) ;
bkOrder . BSSTATUS = "已录入" ;
bkOrder . ParentId = 0 ;
bkOrder . LANENAME = bkOrder . LANECODE ;
await _repOrder . InsertAsync ( bkOrder ) ;
model . BookingId = bkOrder . Id ; //客户订舱数据与订舱台账数据关联
bookingId = bkOrder . Id ;
await _rep . UpdateAsync ( model ) ;
var bkEdiExt = new BookingEDIExt ( ) ;
bkEdiExt . Id = YitIdHelper . NextId ( ) ;
bkEdiExt . BookingId = bkOrder . Id ;
bkEdiExt . SalerCode = model . SaleCode ;
await _repEdiExt . InsertAsync ( bkEdiExt ) ;
var ctnList = await _repCtn . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > x . BILLID = = model . Id ) . ToListAsync ( ) ;
foreach ( var ctn in ctnList )
{
ctn . Id = YitIdHelper . NextId ( ) ;
ctn . BILLID = bkOrder . Id ;
await _repCtn . InsertAsync ( ctn ) ;
}
//服务项目
var servList = await _repServiceItem . Where ( x = > x . BookingId = = model . Id ) . ToListAsync ( ) ;
foreach ( var serv in servList )
{
serv . Id = YitIdHelper . NextId ( ) ;
serv . BookingId = bkOrder . Id ;
await _repServiceItem . InsertAsync ( serv ) ;
}
//附件
var files = await _repFile . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > x . BookingId = = model . Id & & x . IsDeleted = = false ) . ToListAsync ( ) ;
foreach ( var file in files )
{
file . Id = YitIdHelper . NextId ( ) ;
file . BookingId = bkOrder . Id ;
await _repFile . InsertAsync ( file ) ;
}
}
// 接收到订舱需求审核后推送东胜
_ = Task . Run ( ( ) = >
{
try
{
string json = null ;
if ( recModel . Accept )
{
var body = new
{
Type = "CustOrderStatusAccept" ,
Data = new
{
model . BSNO ,
BSSTATUS = "已审核" ,
BookingOrderId = bookingId
}
} ;
json = body . ToJsonString ( ) ;
}
else
{
var body = new
{
Type = "CustOrderStatusReject" ,
Data = new
{
model . BSNO ,
BSSTATUS = "已驳回" ,
COMMENT = recModel . Comment
}
} ;
json = body . ToJsonString ( ) ;
}
var mqUrl = _cache . GetAllSysConfig ( ) . Result . FirstOrDefault ( x = > x . Code = = "AuditBookingMqUrl" ) ? . Value ? ? throw new Exception ( "需配置接收订舱需求审核后推送东胜MQ连接串: [AuditBookingMqUrl]" ) ;
const string MqActionExchangeName = "amq.direct" ;
const string MqActionQueueName = "auditbooking.output.ds" ;
ConnectionFactory factory = new ConnectionFactory ( ) ;
factory . Uri = new Uri ( mqUrl ) ;
using ( IConnection conn = factory . CreateConnection ( ) )
using ( IModel mqModel = conn . CreateModel ( ) )
{
mqModel . ExchangeDeclare ( MqActionExchangeName , ExchangeType . Direct , true ) ;
var queueName = $"{MqActionQueueName}.{model.TenantId}" ;
mqModel . QueueDeclare ( queueName , false , false , false , null ) ;
mqModel . QueueBind ( queueName , MqActionExchangeName , queueName , null ) ;
IBasicProperties props = mqModel . CreateBasicProperties ( ) ;
props . DeliveryMode = 2 ;
byte [ ] messageBodyBytes = Encoding . UTF8 . GetBytes ( SharpZipLib . Compress ( json ) ) ;
mqModel . BasicPublish ( MqActionExchangeName , queueName , props , messageBodyBytes ) ;
conn . Close ( ) ;
_logger . LogInformation ( $"接收到订舱需求审核后推送东胜,已发送数据到消息队列【{mqUrl}】,队列名称:【{queueName}】,数据内容:【{json}】" ) ;
}
}
catch ( Exception ex )
{
_logger . LogError ( ex , "接收到订舱需求审核后推送东胜时发生异常" ) ;
}
} ) ;
if ( recModel . Accept )
{
return bookingId ;
}
else
{
return 0 ;
}
}
# endregion
#region 订舱完整数据
else if ( feedbackType = = BookingFeedbackType . BookingAll . ToString ( ) )
{
var recModel = JsonConvert . DeserializeObject < BookingCustomerRecDataFeedbackDto > ( jsonContent ) ;
var dbOrder = await _repOrder . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > ! x . IsDeleted & & x . Id = = recModel . Order . Id ) ;
if ( dbOrder = = null )
{
throw Oops . Bah ( $"未找到id为{recModel.Order.Id}的数据" ) ;
}
if ( ! string . IsNullOrEmpty ( dbOrder . MBLNO ) ) //提单号不覆盖
{
recModel . Order . MBLNO = dbOrder . MBLNO ;
}
//保存主表
recModel . Order . Adapt ( dbOrder ) ;
await _repOrder . UpdateAsync ( dbOrder ) ;
//更新箱信息
await _repCtn . DeleteAsync ( x = > x . BILLID = = recModel . Order . Id ) ;
foreach ( var ctn in recModel . Ctns )
{
var saveCtn = ctn . Adapt < BookingCtn > ( ) ;
saveCtn . BILLID = recModel . Order . Id ;
saveCtn . CreatedUserId = dbOrder . CreatedUserId ;
saveCtn . CreatedUserName = "系统" ;
saveCtn . CreatedTime = DateTime . Now ;
saveCtn . TenantId = dbOrder . TenantId ;
await _repCtn . InsertAsync ( saveCtn ) ;
}
//货运动态
foreach ( var sta in recModel . StatusLogs )
{
await _repStatuslogDetail . DeleteAsync ( x = > x . PId = = sta . Id ) ;
await _repStatuslog . DeleteAsync ( x = > x . Id = = sta . Id ) ;
var insStaLog = sta . Adapt < BookingStatusLog > ( ) ;
insStaLog . BookingId = recModel . Order . Id ;
await _repStatuslog . InsertAsync ( insStaLog ) ;
foreach ( var staDetail in sta . Details )
{
var insStaDetail = staDetail . Adapt < BookingStatusLogDetail > ( ) ;
insStaDetail . PId = insStaLog . Id ;
await _repStatuslogDetail . InsertAsync ( insStaDetail ) ;
}
}
//文件
//var opt = App.GetOptions<BookingAttachOptions>();
//var dirAbs = string.Empty;
//if (string.IsNullOrEmpty(opt.basePath))
//{
// dirAbs = Path.Combine(App.WebHostEnvironment.WebRootPath, opt.relativePath);
//}
//else
//{
// dirAbs = Path.Combine(opt.basePath, opt.relativePath);
//}
//if (!Directory.Exists(dirAbs))
// Directory.CreateDirectory(dirAbs);
var dbFiles = await _repFile . AsQueryable ( ) . Filter ( null , true ) . Where ( f = > f . BookingId = = recModel . Order . Id ) . ToListAsync ( ) ;
foreach ( var file in recModel . Files )
{
if ( dbFiles . Count ( ff = > ff . Id = = file . Id ) = = 0 ) //新文件
{
var insFile = file . Adapt < BookingFile > ( ) ;
insFile . BookingId = recModel . Order . Id ;
insFile . CreatedUserId = dbOrder . CreatedUserId ;
insFile . CreatedUserName = "系统" ;
insFile . CreatedTime = DateTime . Now ;
insFile . TenantId = dbOrder . TenantId ;
//var saveFileName = $"{DateTime.Now.Ticks}{Path.GetExtension(file.FileName)}";
//var fileRelaPath = Path.Combine(opt.relativePath, saveFileName).ToLower();
//var fileAbsPath = Path.Combine(dirAbs, saveFileName).ToLower();
//insFile.FilePath = fileRelaPath;
//File.WriteAllBytes(fileAbsPath, file.FileContent);
await _repFile . InsertAsync ( insFile ) ;
}
}
BookingOrderSyncTypeEnum ? syncTypeEnum = syncType switch
{
"BC" = > BookingOrderSyncTypeEnum . BC ,
"CC" = > BookingOrderSyncTypeEnum . CC ,
//"FILE" => BookingOrderSyncTypeEnum.FILE,
_ = > null ,
} ;
await bookingOrderService . SendBookingOrder ( new long [ ] { dbOrder . Id } , syncTypeEnum ) ;
}
# endregion
#region 订舱货物状态回推
else if ( feedbackType = = BookingFeedbackType . GoodsStatus . ToString ( ) )
{
var recModel = JsonConvert . DeserializeObject < GoodsStatusSyncDto > ( jsonContent ) ;
var dbOrder = await _repOrder . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > ! x . IsDeleted & & x . Id = = recModel . Id ) ;
if ( dbOrder = = null )
{
throw Oops . Bah ( $"未找到id为{recModel.Id}的数据" ) ;
}
var gsCfg = await _goodsStatusConfig . AsQueryable ( ) . Filter ( null , true )
. FirstAsync ( x = > x . CreatedUserId = = dbOrder . CreatedUserId
& & x . IsDeleted = = false
& & x . SystemCode = = recModel . Code ) ;
if ( gsCfg = = null )
{
throw Oops . Bah ( $"用户{dbOrder.CreatedUserName}的货物状态配置数据未找到:{recModel.Code}" ) ;
}
if ( recModel . IsCancel ) //取消货物状态
{
_logger . LogInformation ( $"取消货物状态{gsCfg.SystemCode} {dbOrder.Id}" ) ;
await _goodsStatus . DeleteAsync ( x = > x . ConfigId = = gsCfg . Id
& & x . bookingId = = dbOrder . Id
& & x . CreatedUserId = = dbOrder . CreatedUserId ) ;
}
else
{
var gs = await _goodsStatus . AsQueryable ( ) . Filter ( null , true )
. FirstAsync ( x = > x . ConfigId = = gsCfg . Id
& & x . bookingId = = dbOrder . Id
& & x . CreatedUserId = = dbOrder . CreatedUserId
& & x . IsDeleted = = false ) ;
if ( gs = = null )
{
gs = new BookingGoodsStatus ( ) ;
gs . Id = YitIdHelper . NextId ( ) ;
gs . bookingId = dbOrder . Id ;
gs . ConfigId = gsCfg . Id ;
gs . TenantId = dbOrder . TenantId ;
gs . CreatedUserId = dbOrder . CreatedUserId ;
gs . CreatedUserName = dbOrder . CreatedUserName ;
gs . FinishUserId = dbOrder . CreatedUserId ;
gs . FinishUser = "系统" ;
gs . FinishTime = string . IsNullOrEmpty ( recModel . FinishTime ) ? DateTime . Now : Convert . ToDateTime ( recModel . FinishTime ) ;
await _goodsStatus . InsertAsync ( gs ) ;
}
else
{
gs . FinishUserId = dbOrder . CreatedUserId ;
gs . FinishUser = "系统" ;
gs . FinishTime = string . IsNullOrEmpty ( recModel . FinishTime ) ? DateTime . Now : Convert . ToDateTime ( recModel . FinishTime ) ;
await _goodsStatus . UpdateAsync ( gs ) ;
}
await _publisher . PublishAsync ( new ChannelEventSource ( "GoodsStatusSubscribeNotify:Book" , new { BookingId = dbOrder . Id , StatusCode = gsCfg . SystemCode , StatusName = gsCfg . StatusName } ) ) ;
}
}
# endregion
#region 服务项目审核回推
else if ( feedbackType = = BookingFeedbackType . ServiceItemAudit . ToString ( ) )
{
var recModel = JsonConvert . DeserializeObject < ChangeServiceItemResponseDto > ( jsonContent ) ;
var ordId = Convert . ToInt64 ( recModel . Dto . Id ) ;
var order = await _repOrder . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . Id = = ordId ) ;
if ( recModel . IsReject ) //驳回
{
if ( recModel . Dto . IsCancel ) //申请的是取消,需要恢复服务项目显示
{
var servItm = await _repServiceItem . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . BookingId = = ordId & & x . Code = = recModel . Dto . ServiceCode ) ;
if ( servItm = = null )
{
servItm = new BookingServiceItem ( ) ;
servItm . Id = YitIdHelper . NextId ( ) ;
servItm . BookingId = Convert . ToInt64 ( recModel . Dto . Id ) ;
servItm . Code = recModel . Dto . ServiceCode ;
servItm . Value = recModel . Dto . ServiceName ;
await _repServiceItem . InsertAsync ( servItm ) ;
}
}
else //申请的是新增,则删掉服务项目
{
await _repServiceItem . DeleteAsync ( x = > x . BookingId = = ordId & & x . Code = = recModel . Dto . ServiceCode ) ;
}
}
else //通过
{
if ( ! recModel . Dto . IsCancel ) //申请的新增,将未确认状态置为确认
{
var servItm = await _repServiceItem . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . BookingId = = ordId & & x . Code = = recModel . Dto . ServiceCode ) ;
if ( servItm ! = null )
{
servItm . UnConfirm = false ;
await _repServiceItem . UpdateAsync ( servItm ) ;
}
}
}
var serItm = _cache . GetAllDictData ( ) . Result . FirstOrDefault ( x = > x . TypeCode = = "booking_service_item" & & x . Code = = recModel . Dto . ServiceCode ) ;
var mess = new DjyMessage ( ) ;
mess . Module = MessageModule . Booking . ToString ( ) ;
mess . TypeCode = MessageType . ChangeServiceItem . ToString ( ) ;
mess . TypeName = EnumHelper . GetDescription ( typeof ( MessageType ) , mess . TypeCode ) ;
mess . RelativeId = ordId ;
mess . RelativeCode = order . BOOKINGNO ;
if ( recModel . IsReject )
{
mess . Content = $"{recModel.AuditName} 退回了您{(recModel.Dto.IsCancel ? " 取 消 " : " 新 增 ")}服务项目 {serItm.Value},原因是:{recModel.ProcResult}" ;
}
else
{
mess . Content = $"{recModel.AuditName} 同意了您{(recModel.Dto.IsCancel ? " 取 消 " : " 新 增 ")}服务项目 {serItm.Value}" ;
}
mess . FromName = "大简云" ;
mess . ProcStatus = MessageProcessStatus . UnProcess . ToString ( ) ;
await this . _repMessage . InsertAsync ( mess ) ;
await _publisher . PublishAsync ( new ChannelEventSource ( "Message:NotifyReceiveNew" ) ) ;
}
# endregion
#region 服务项目手工修改通知回推
else if ( feedbackType = = BookingFeedbackType . ServiceItemChange . ToString ( ) )
{
var recModel = JsonConvert . DeserializeObject < DjyChangeServiceItemDto > ( jsonContent ) ;
var ordId = Convert . ToInt64 ( recModel . Id ) ;
var order = await _repOrder . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . Id = = ordId ) ;
var serItm = _cache . GetAllDictData ( ) . Result . FirstOrDefault ( x = > x . TypeCode = = "booking_service_item" & & x . Code = = recModel . ServiceCode ) ;
if ( recModel . IsCancel )
{
await _repServiceItem . DeleteAsync ( x = > x . BookingId = = ordId & & x . Code = = recModel . ServiceCode ) ;
}
else
{
var servItm = await _repServiceItem . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . BookingId = = ordId & & x . Code = = recModel . ServiceCode ) ;
if ( servItm ! = null )
{
servItm . UnConfirm = false ;
await _repServiceItem . UpdateAsync ( servItm ) ;
}
else
{
servItm = new BookingServiceItem ( ) ;
servItm . Id = YitIdHelper . NextId ( ) ;
servItm . BookingId = ordId ;
servItm . Code = recModel . ServiceCode ;
servItm . Value = serItm . Value ;
await _repServiceItem . InsertAsync ( servItm ) ;
}
}
var mess = new DjyMessage ( ) ;
mess . Module = MessageModule . Booking . ToString ( ) ;
mess . TypeCode = MessageType . ChangeServiceItem . ToString ( ) ;
mess . TypeName = EnumHelper . GetDescription ( typeof ( MessageType ) , mess . TypeCode ) ;
mess . RelativeId = ordId ;
mess . RelativeCode = order . BOOKINGNO ;
mess . Content = $"{recModel.UserName} {(recModel.IsCancel ? " 取 消 " : " 新 增 ")}服务项目 {serItm.Value},原因是:{recModel.Remark}" ;
mess . FromName = "大简云" ;
mess . ProcStatus = MessageProcessStatus . UnProcess . ToString ( ) ;
await this . _repMessage . InsertAsync ( mess ) ;
await _publisher . PublishAsync ( new ChannelEventSource ( "Message:NotifyReceiveNew" ) ) ;
}
# endregion
#region 单证补料审核通知回推
else if ( feedbackType = = BookingFeedbackType . DocSupplementAudit . ToString ( ) )
{
var recModel = JsonConvert . DeserializeObject < DocSupplementResponseDto > ( jsonContent ) ;
var ordId = Convert . ToInt64 ( recModel . Dto . Id ) ;
var order = await _repOrder . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . Id = = ordId ) ;
if ( ! recModel . IsReject ) //审核通过,挂载附件
{
//进入订舱附件
foreach ( var ff in recModel . Dto . FileList )
{
var fileSuffix = Path . GetFileName ( ff . FileName ) ;
var newFile = new BookingFile
{
Id = ff . Id ,
FileName = ff . FileName ,
FilePath = ff . FilePath ,
TypeCode = ff . TypeCode ,
TypeName = ff . TypeName ,
BookingId = ordId ,
TenantId = order . TenantId ,
TenantName = order . TenantName ,
} ;
await _repFile . InsertAsync ( newFile ) ;
}
}
var mess = new DjyMessage ( ) ;
mess . Module = MessageModule . Booking . ToString ( ) ;
mess . TypeCode = MessageType . DocSupplement . ToString ( ) ;
mess . TypeName = EnumHelper . GetDescription ( typeof ( MessageType ) , mess . TypeCode ) ;
mess . RelativeId = ordId ;
mess . RelativeCode = order . BOOKINGNO ;
if ( recModel . IsReject )
{
mess . Content = $"{recModel.AuditName} 退回了提交的 {recModel.Dto.DocTypeName},原因是:{recModel.ProcResult}" ;
}
else
{
mess . Content = $"{recModel.AuditName} 通过了提交的 {recModel.Dto.DocTypeName}" ;
}
mess . FromName = "大简云" ;
mess . ProcStatus = MessageProcessStatus . UnProcess . ToString ( ) ;
await this . _repMessage . InsertAsync ( mess ) ;
await _publisher . PublishAsync ( new ChannelEventSource ( "Message:NotifyReceiveNew" ) ) ;
}
# endregion
return null ;
}
/// <summary>
/// 导入
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ImportBooking")]
public async Task ImportBooking ( IFormFile file , [ FromForm ] string carrierId )
{
//未上传文件
if ( file = = null | | file . Length = = 0 )
{
throw Oops . Bah ( "未上传任何文件" ) ;
}
var ms = new MemoryStream ( ) ;
await file . CopyToAsync ( ms ) ;
ms . Position = 0 ;
var dicIns = new Dictionary < BookingCustomerOrder , List < BookingCtn > > ( ) ;
if ( carrierId = = "COSCO" )
{
var data = MiniExcel . QueryAsDataTable ( ms ) ;
var colNames = new string [ ] { "COSCO账号" , "密码" , "约号" , "船名" , "航次" , "航线" , "ETD" , "运输条款" , "付费方式" , "品名" , "起运港" , "卸货港" , "目的地" , "货物类型" , "箱型箱量" , "单箱重量" , "订舱备注" , "放舱通知邮箱" , "航管" } ;
//DataRow drHead = data.Rows[0];
foreach ( var cn in colNames )
{
if ( ! data . Columns . Contains ( cn ) )
{
throw Oops . Bah ( $"文件格式有误,未找到列:{cn}" ) ;
}
}
var carrList = await _cache . GetAllCodeCarrier ( ) ;
var portLoadList = await _cache . GetAllCodePortLoad ( ) ;
var portDestList = await _cache . GetAllCodePort ( ) ;
var serviceList = await _cache . GetAllCodeService ( ) ;
var frtList = await _cache . GetAllCodeFrt ( ) ;
var ctnList = await _cache . GetAllCodeCtn ( ) ;
var errList = new List < string > ( ) ;
for ( var idx = 0 ; idx < data . Rows . Count ; idx + + )
{
var custOrder = new BookingCustomerOrder ( ) ;
custOrder . CARRIERID = carrierId ;
custOrder . CARRIER = carrierId ;
custOrder . CONTRACTNO = data . Rows [ idx ] [ "约号" ] . ToString ( ) ;
custOrder . VESSEL = data . Rows [ idx ] [ "船名" ] . ToString ( ) ;
custOrder . VOYNO = data . Rows [ idx ] [ "航次" ] . ToString ( ) ;
custOrder . LANECODE = data . Rows [ idx ] [ "航线" ] . ToString ( ) ;
var strETD = data . Rows [ idx ] [ "ETD" ] . ToString ( ) ;
if ( DateTime . TryParse ( strETD , out DateTime etd ) )
{
custOrder . ETD = etd ;
}
else
{
errList . Add ( $"第{idx + 1}行, 未能识别ETD: {strETD}" ) ;
}
var serCode = data . Rows [ idx ] [ "运输条款" ] . ToString ( ) ;
var service = serviceList . FirstOrDefault ( x = > x . Code = = serCode ) ;
if ( service = = null )
{
errList . Add ( $"第{idx + 1}行,未找到运输条款:{serCode}" ) ;
}
else
{
custOrder . SERVICECODE = service . Code ;
custOrder . SERVICE = service . Name ;
}
var frtCode = data . Rows [ idx ] [ "付费方式" ] . ToString ( ) ;
var frt = frtList . FirstOrDefault ( x = > x . Code = = frtCode ) ;
if ( frt = = null )
{
errList . Add ( $"第{idx + 1}行,未找到付费方式:{frtCode}" ) ;
}
else
{
custOrder . FRTCODE = frt . Code ;
custOrder . BLFRT = frt . EnName ;
}
custOrder . DESCRIPTION = data . Rows [ idx ] [ "品名" ] . ToString ( ) ;
var portLoadCode = data . Rows [ idx ] [ "起运港" ] . ToString ( ) ;
var portLoad = portLoadList . FirstOrDefault ( x = > x . Code = = portLoadCode ) ;
if ( portLoad = = null )
{
errList . Add ( $"第{idx + 1}行,未找到起运港:{portLoadCode}" ) ;
}
else
{
custOrder . PORTLOADID = portLoad . EdiCode ;
custOrder . PORTLOAD = portLoad . EnName ;
custOrder . PORTLOADCODE = portLoad . Code ;
}
var portCode = data . Rows [ idx ] [ "卸货港" ] . ToString ( ) ;
var portDest = portDestList . FirstOrDefault ( x = > x . Code = = portCode ) ;
if ( portLoad = = null )
{
errList . Add ( $"第{idx + 1}行,未找到卸货港:{portCode}" ) ;
}
else
{
custOrder . PORTDISCHARGEID = portLoad . EdiCode ;
custOrder . PORTDISCHARGE = portLoad . EnName ;
custOrder . PORTDISCHARGECODE = portLoad . Code ;
}
var destina = data . Rows [ idx ] [ "目的地" ] . ToString ( ) ;
var destinaFind = portDestList . FirstOrDefault ( x = > x . Code = = destina ) ;
if ( portLoad = = null )
{
errList . Add ( $"第{idx + 1}行,未找到卸货港:{portCode}" ) ;
}
else
{
custOrder . DESTINATIONID = portLoad . EdiCode ;
custOrder . DESTINATION = portLoad . EnName ;
custOrder . DESTINATIONCODE = portLoad . Code ;
}
var cargoId = data . Rows [ idx ] [ "货物类型" ] . ToString ( ) ;
custOrder . CARGOID = cargoId . Substring ( 0 , 1 ) ;
custOrder . SOREMARK = data . Rows [ idx ] [ "订舱备注" ] . ToString ( ) ;
custOrder . SaleCode = data . Rows [ idx ] [ "航管" ] . ToString ( ) ;
//订舱账号、密码
var jobj = new JObject ( ) ;
jobj [ "Account" ] = data . Rows [ idx ] [ "COSCO账号" ] . ToString ( ) ;
jobj [ "Password" ] = data . Rows [ idx ] [ "密码" ] . ToString ( ) ;
jobj [ "OpMail" ] = data . Rows [ idx ] [ "放舱通知邮箱" ] . ToString ( ) ;
custOrder . ExtendData = jobj . ToJsonString ( ) ;
//箱信息
var ctnStr = data . Rows [ idx ] [ "箱型箱量" ] . ToString ( ) ;
var arrCtn = ctnStr . Split ( "*" . ToCharArray ( ) , StringSplitOptions . RemoveEmptyEntries ) ;
var ctns = new List < BookingCtn > ( ) ;
if ( arrCtn . Length = = 2 )
{
var ctn = ctnList . FirstOrDefault ( x = > x . Code = = arrCtn [ 0 ] ) ;
if ( ctn = = null )
{
errList . Add ( $"第{idx + 1}行,未找到箱型:{arrCtn[0]}" ) ;
}
else if ( int . TryParse ( arrCtn [ 1 ] , out int num ) )
{
var ctnAdd = new BookingCtn ( )
{
CTNALL = ctn . Name ,
CTNNUM = num ,
CTNCODE = ctn . Code
} ;
ctns . Add ( ctnAdd ) ;
var ctnKGS = data . Rows [ idx ] [ "单箱重量" ] . ToString ( ) ;
if ( decimal . TryParse ( ctnKGS , out decimal cw ) )
{
ctnAdd . KGS = cw ;
}
}
}
dicIns . Add ( custOrder , ctns ) ;
}
if ( errList . Count > 0 )
{
throw Oops . Bah ( string . Join ( "\r\n" , errList ) ) ;
}
}
else if ( carrierId = = "EMC" )
{
var data = MiniExcel . QueryAsDataTable ( ms ) ;
var colNames = new string [ ] { "EMC账号" , "EMC密码" , "POL" , "卸货港" , "交货地" , "运送方式" , "运送型态" , "SIZE" , "WEIGHT( 单箱) " , "description of goods" , "合约类型" , "合约号" , "运费付款方式" , "船名" , "航次" , "航线" , "ETD" , "联系人" , "联系电话" , "订舱确认邮箱" , "备注 (其它注意事项)" } ;
//DataRow drHead = data.Rows[0];
foreach ( var cn in colNames )
{
if ( ! data . Columns . Contains ( cn ) )
{
throw Oops . Bah ( $"文件格式有误,未找到列:{cn}" ) ;
}
}
var carrList = await _cache . GetAllCodeCarrier ( ) ;
var portLoadList = await _cache . GetAllCodePortLoad ( ) ;
var portDestList = await _cache . GetAllCodePort ( ) ;
var serviceList = await _cache . GetAllCodeService ( ) ;
var frtList = await _cache . GetAllCodeFrt ( ) ;
var ctnList = await _cache . GetAllCodeCtn ( ) ;
var errList = new List < string > ( ) ;
for ( var idx = 0 ; idx < data . Rows . Count ; idx + + )
{
var custOrder = new BookingCustomerOrder ( ) ;
custOrder . CARRIERID = carrierId ;
custOrder . CARRIER = carrierId ;
custOrder . CONTRACTNO = data . Rows [ idx ] [ "合约号" ] . ToString ( ) ;
custOrder . VESSEL = data . Rows [ idx ] [ "船名" ] . ToString ( ) ;
custOrder . VOYNO = data . Rows [ idx ] [ "航次" ] . ToString ( ) ;
custOrder . LANECODE = data . Rows [ idx ] [ "航线" ] . ToString ( ) ;
var strETD = data . Rows [ idx ] [ "ETD" ] . ToString ( ) ;
if ( Regex . IsMatch ( strETD , "^\\d+$" ) )
{
custOrder . ETD = DateTime . FromOADate ( Convert . ToDouble ( strETD ) ) ;
}
else
{
if ( DateTime . TryParse ( strETD , out DateTime etd ) )
{
custOrder . ETD = etd ;
}
else
{
errList . Add ( $"第{idx + 1}行, 未能识别ETD: {strETD}" ) ;
}
}
//var serCode = data.Rows[idx]["运送方式"].ToString();
//var service = serviceList.FirstOrDefault(x => x.Code == serCode);
//if (service == null)
//{
// errList.Add($"第{idx + 1}行,未找到运输条款:{serCode}");
//}
//else
//{
// custOrder.SERVICECODE = service.Code;
// custOrder.SERVICE = service.Name;
//}
var frtCode = data . Rows [ idx ] [ "运费付款方式" ] . ToString ( ) ;
var frt = frtList . FirstOrDefault ( x = > x . Code = = frtCode ) ;
if ( frt = = null )
{
errList . Add ( $"第{idx + 1}行,未找到付费方式:{frtCode}" ) ;
}
else
{
custOrder . FRTCODE = frt . Code ;
custOrder . BLFRT = frt . EnName ;
}
custOrder . DESCRIPTION = data . Rows [ idx ] [ "description of goods" ] . ToString ( ) ;
var portLoadCode = data . Rows [ idx ] [ "POL" ] . ToString ( ) ;
var portLoad = portLoadList . FirstOrDefault ( x = > x . Code = = portLoadCode | | x . EnName = = portLoadCode ) ;
if ( portLoad = = null )
{
errList . Add ( $"第{idx + 1}行,未找到起运港:{portLoadCode}" ) ;
}
else
{
custOrder . PORTLOADID = portLoad . EdiCode ;
custOrder . PORTLOAD = portLoad . EnName ;
custOrder . PORTLOADCODE = portLoad . Code ;
}
var portCode = data . Rows [ idx ] [ "卸货港" ] . ToString ( ) ;
var portDest = portDestList . FirstOrDefault ( x = > x . Code = = portCode | | x . EnName = = portCode ) ;
if ( portLoad = = null )
{
errList . Add ( $"第{idx + 1}行,未找到卸货港:{portCode}" ) ;
}
else
{
custOrder . PORTDISCHARGEID = portLoad . EdiCode ;
custOrder . PORTDISCHARGE = portLoad . EnName ;
custOrder . PORTDISCHARGECODE = portLoad . Code ;
}
var destina = data . Rows [ idx ] [ "交货地" ] . ToString ( ) ;
var destinaFind = portDestList . FirstOrDefault ( x = > x . Code = = destina | | x . EnName = = destina ) ;
if ( portLoad = = null )
{
errList . Add ( $"第{idx + 1}行,未找到交货地:{destina}" ) ;
}
else
{
custOrder . DESTINATIONID = portLoad . EdiCode ;
custOrder . DESTINATION = portLoad . EnName ;
custOrder . DESTINATIONCODE = portLoad . Code ;
}
//var cargoId = data.Rows[idx]["货物类型"].ToString();
//custOrder.CARGOID = cargoId.Substring(0, 1);
custOrder . SOREMARK = data . Rows [ idx ] [ "备注 (其它注意事项)" ] . ToString ( ) ;
//订舱账号、密码
var jobj = new JObject ( ) ;
jobj [ "Account" ] = data . Rows [ idx ] [ "EMC账号" ] . ToString ( ) ;
jobj [ "Password" ] = data . Rows [ idx ] [ "EMC密码" ] . ToString ( ) ;
jobj [ "OpMail" ] = data . Rows [ idx ] [ "订舱确认邮箱" ] . ToString ( ) ;
jobj [ "ContactName" ] = data . Rows [ idx ] [ "联系人" ] . ToString ( ) ;
jobj [ "ContactTel" ] = data . Rows [ idx ] [ "联系电话" ] . ToString ( ) ;
jobj [ "YSFS" ] = data . Rows [ idx ] [ "运送方式" ] . ToString ( ) ;
jobj [ "YSXT" ] = data . Rows [ idx ] [ "运送型态" ] . ToString ( ) ;
jobj [ "ContractType" ] = data . Rows [ idx ] [ "合约类型" ] . ToString ( ) ;
custOrder . ExtendData = jobj . ToJsonString ( ) ;
//箱信息
var ctnStr = data . Rows [ idx ] [ "SIZE" ] . ToString ( ) ;
var arrCtn = ctnStr . Split ( "*" . ToCharArray ( ) , StringSplitOptions . RemoveEmptyEntries ) ;
var ctns = new List < BookingCtn > ( ) ;
if ( arrCtn . Length = = 2 )
{
var ctn = ctnList . FirstOrDefault ( x = > x . Code = = arrCtn [ 0 ] | | x . Name = = arrCtn [ 0 ] ) ;
if ( ctn = = null )
{
errList . Add ( $"第{idx + 1}行,未找到箱型:{arrCtn[0]}" ) ;
}
else if ( int . TryParse ( arrCtn [ 1 ] , out int num ) )
{
var ctnAdd = new BookingCtn ( )
{
CTNALL = ctn . Name ,
CTNNUM = num ,
CTNCODE = ctn . Code
} ;
ctns . Add ( ctnAdd ) ;
var ctnKGS = data . Rows [ idx ] [ "WEIGHT( 单箱) " ] . ToString ( ) ;
if ( decimal . TryParse ( ctnKGS , out decimal cw ) )
{
ctnAdd . KGS = cw ;
}
}
}
dicIns . Add ( custOrder , ctns ) ;
}
if ( errList . Count > 0 )
{
throw Oops . Bah ( string . Join ( "\r\n" , errList ) ) ;
}
}
else
{
throw Oops . Bah ( "当前不支持的该船司" ) ;
}
foreach ( var k in dicIns )
{
await SaveData ( k . Key , k . Value , new List < BookingServiceItem > ( ) { new BookingServiceItem ( ) { Code = "dingcang" , Value = "订舱" } } , true ) ;
}
}
# endregion
#region 运营端操作与接口
/// <summary>
/// 接收客户订舱系统提交的数据
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ReceiveBooking"), AllowAnonymous, ApiUser(ApiCode = "DjyBookingReceiveApi")]
public async Task < List < BookingSubmitResultModel > > ReceiveBooking ( List < BookingCustomerSubmitDto > list )
{
_logger . LogInformation ( $"收到提交的订舱数据:{JsonConvert.SerializeObject(list)}" ) ;
var rtnList = new List < BookingSubmitResultModel > ( ) ;
var ordIdList = new List < long > ( ) ;
foreach ( var item in list )
{
var strId = item . Id . ToString ( ) ;
var order = await _rep . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . TenantId = = UserManager . TENANT_ID & & x . BSNO = = strId ) ;
if ( order = = null )
{
order = item . Adapt < BookingCustomerOrder > ( ) ;
order . BSNO = order . Id . ToString ( ) ; //客户订舱系统中的id
order . Id = YitIdHelper . NextId ( ) ;
order . BSSTATUS = "待审核" ;
await _rep . InsertAsync ( order ) ;
}
else
{
if ( order . BSSTATUS = = "已审核" )
{
rtnList . Add ( new BookingSubmitResultModel ( )
{
Id = item . Id ,
Success = false ,
BOOKINGNO = item . BOOKINGNO ,
Message = $"数据已审核,不能重复提交"
} ) ; ;
continue ;
}
var idBackup = order . Id ; //防止覆盖
var bsnoBackup = order . BSNO ; //防止覆盖
order = item . Adapt ( order ) ;
order . Id = idBackup ;
order . BSNO = bsnoBackup ;
order . BSSTATUS = "待审核" ;
order . IsDeleted = false ;
await _rep . UpdateAsync ( order ) ;
}
ordIdList . Add ( order . Id ) ;
//箱信息
await _repCtn . DeleteAsync ( x = > x . BILLID = = order . Id ) ;
foreach ( var ctn in item . CtnList )
{
var bkCtn = ctn . Adapt < BookingCtn > ( ) ;
bkCtn . Id = YitIdHelper . NextId ( ) ;
bkCtn . BILLID = order . Id ;
await _repCtn . InsertAsync ( bkCtn ) ;
}
//服务项目
await _repServiceItem . DeleteAsync ( x = > x . BookingId = = order . Id ) ;
foreach ( var serv in item . ServiceItemList )
{
var bkServ = serv . Adapt < BookingServiceItem > ( ) ;
bkServ . Id = YitIdHelper . NextId ( ) ;
bkServ . BookingId = order . Id ;
await _repServiceItem . InsertAsync ( bkServ ) ;
}
//文件
await _repFile . DeleteAsync ( x = > x . BookingId = = order . Id ) ;
foreach ( var file in item . Files )
{
var bkFile = file . Adapt < BookingFile > ( ) ;
bkFile . Id = YitIdHelper . NextId ( ) ;
bkFile . BookingId = order . Id ;
await _repFile . InsertAsync ( bkFile ) ;
}
rtnList . Add ( new BookingSubmitResultModel ( )
{
Id = item . Id ,
Success = true ,
BOOKINGNO = item . BOOKINGNO ,
Message = $"提交成功"
} ) ;
//日志动态
SaveAuditLog ( $"待审核" , order . Id ) ;
}
_logger . LogInformation ( $"rtnList:{rtnList.ToJsonString()}" ) ;
//全部成功后,才能自动订舱和审核
if ( rtnList . Count ( x = > x . Success = = false ) = = 0 )
{
var tCustId = list . First ( ) . BookingTenantId ;
_logger . LogInformation ( $"提交成功,准备自动订舱和审核" ) ;
//自动订舱和自动审核
var cust = await _repCustomer . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . CustSysId = = tCustId ) ;
if ( cust ! = null )
{
_logger . LogInformation ( $"找到客户端租户对应客户:{cust.FullName}" ) ;
var paraCallApiAuditAuto = await _repCustomerParamValue . AsQueryable ( ) . FirstAsync ( x = > x . CustomerId = = cust . Id & & x . ParaCode = = "BookingCallApiAndAuditAuto" ) ;
if ( paraCallApiAuditAuto ! = null & & paraCallApiAuditAuto . ItemCode = = "YES" )
{
foreach ( var ordId in ordIdList )
{
var succ = false ;
try
{
_logger . LogInformation ( $"自动订舱:{ordId}" ) ;
await PostApiSO ( ordId ) ;
succ = true ;
}
catch ( Exception ex )
{
_logger . LogWarning ( $"自动订舱失败:{ordId},错误信息:{ex.Message}" ) ;
await AuditBooking ( ordId , false , ex . Message , notFeedback : true ) ;
throw ex ;
}
if ( succ )
{
_logger . LogInformation ( $"自动审核:{ordId}" ) ;
await AuditBooking ( ordId , true , "系统自动审核" ) ;
}
}
}
}
else
{
_logger . LogWarning ( $"未找到客户, CustSysId: {tCustId}" ) ;
}
}
return rtnList ;
}
/// <summary>
/// 审核订舱请求
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/AuditBooking")]
public async Task AuditBooking ( long id , bool accept , string comment , bool notFeedback = false )
{
var model = await _rep . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . Id = = id ) ;
if ( model = = null )
{
throw Oops . Bah ( "未找到业务信息" ) ;
}
if ( model . BSSTATUS ! = "待审核" )
{
throw Oops . Bah ( "当前状态不能审核" ) ;
}
if ( accept )
{
model . BSSTATUS = "已审核" ;
}
else
{
model . BSSTATUS = "已驳回" ;
}
JObject jobjRtn = null ;
if ( ! notFeedback )
{
//回推回执
var feedbackData = new BookingCustomerRecAduitFeedbackDto ( )
{
Id = model . BSNO ,
Accept = accept ,
Comment = comment
} ;
var feedbackObj = new BookingFeedbackDto ( BookingFeedbackType . Audit . ToString ( ) ) ;
feedbackObj . JsonContent = feedbackData . ToJsonString ( ) ;
_logger . LogInformation ( $"回推审核数据:{JsonConvert.SerializeObject(feedbackObj)}, URL: {model.FeedbackUrl}" ) ;
var rtn = await model . FeedbackUrl
. SetHeaders ( new Dictionary < string , object > {
{ CommonConst . API_USER_HEADER_KEY , model . FeedbackKey } ,
{ CommonConst . API_USER_HEADER_SECRET , model . FeedbackSecret }
} )
. SetBody ( feedbackObj , "application/x-www-form-urlencoded" )
. PostAsStringAsync ( ) ;
_logger . LogInformation ( $"回推审核返回:{rtn}" ) ;
jobjRtn = JObject . Parse ( rtn ) ;
if ( jobjRtn . GetIntValue ( "code" ) ! = 200 )
{
throw Oops . Bah ( jobjRtn . GetStringValue ( "message" ) ) ;
}
}
await _rep . UpdateAsync ( model ) ; //回推成功后,存库
//日志动态
SaveAuditLog ( $"{(accept ? " 审 核 通 过 " : " 审 核 驳 回 ")}" , id , remark : $"审核意见:{comment}" ) ;
//进入订舱台账
if ( accept & & jobjRtn ! = null )
{
var custBookId = jobjRtn . GetStringValue ( "data" ) ; //返回的客户订舱系统的订舱数据id
var bkOrder = model . Adapt < BookingOrder > ( ) ;
bkOrder . Id = YitIdHelper . NextId ( ) ;
bkOrder . BSNO = custBookId ;
bkOrder . BSSTATUS = "已录入" ;
bkOrder . CUSTOMERNAME = model . BookingTenantName ;
bkOrder . ParentId = 0 ;
bkOrder . LANENAME = bkOrder . LANECODE ;
bkOrder . OPID = UserManager . UserId . ToString ( ) ;
bkOrder . OP = UserManager . Name ;
await _repOrder . InsertAsync ( bkOrder ) ;
var bkEdiExt = new BookingEDIExt ( ) ;
bkEdiExt . Id = YitIdHelper . NextId ( ) ;
bkEdiExt . BookingId = bkOrder . Id ;
bkEdiExt . SalerCode = model . SaleCode ;
await _repEdiExt . InsertAsync ( bkEdiExt ) ;
model . BookingId = bkOrder . Id ; //客户订舱数据与订舱台账数据关联
await _rep . UpdateAsync ( model ) ;
var ctnList = await _repCtn . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > x . BILLID = = model . Id ) . ToListAsync ( ) ;
foreach ( var ctn in ctnList )
{
ctn . Id = YitIdHelper . NextId ( ) ;
ctn . BILLID = bkOrder . Id ;
await _repCtn . InsertAsync ( ctn ) ;
}
//服务项目
var servList = await _repServiceItem . Where ( x = > x . BookingId = = model . Id ) . ToListAsync ( ) ;
foreach ( var serv in servList )
{
serv . Id = YitIdHelper . NextId ( ) ;
serv . BookingId = bkOrder . Id ;
await _repServiceItem . InsertAsync ( serv ) ;
}
//附件
var files = await _repFile . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > x . BookingId = = model . Id & & x . IsDeleted = = false ) . ToListAsync ( ) ;
foreach ( var file in files )
{
file . Id = YitIdHelper . NextId ( ) ;
file . BookingId = bkOrder . Id ;
await _repFile . InsertAsync ( file ) ;
}
}
//扣费
await FeeSo ( model . Id ) ;
}
/// <summary>
/// 接收客户订舱系统取消提交的数据
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/CancelBooking"), AllowAnonymous, ApiUser(ApiCode = "DjyBookingReceiveApi")]
public async Task < List < BookingSubmitResultModel > > CancelBooking ( List < BookingCustomerCancelSubmitDto > list )
{
_logger . LogInformation ( $"收到提交的订舱数据:{JsonConvert.SerializeObject(list)}" ) ;
var rtnList = new List < BookingSubmitResultModel > ( ) ;
foreach ( var item in list )
{
var strId = item . Id . ToString ( ) ;
var order = await _rep . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . TenantId = = UserManager . TENANT_ID & & ! x . IsDeleted & & x . BSNO = = strId ) ;
if ( order = = null )
{
rtnList . Add ( new BookingSubmitResultModel ( )
{
Id = item . Id ,
Success = false ,
BOOKINGNO = item . BOOKINGNO ,
Message = $"未找到订舱数据"
} ) ;
}
else
{
if ( order . BSSTATUS ! = "待审核" )
{
rtnList . Add ( new BookingSubmitResultModel ( )
{
Id = item . Id ,
Success = false ,
BOOKINGNO = item . BOOKINGNO ,
Message = $"当前状态不能取消"
} ) ;
continue ;
}
order . IsDeleted = true ;
await _rep . UpdateAsync ( order ) ;
rtnList . Add ( new BookingSubmitResultModel ( )
{
Id = item . Id ,
Success = true ,
BOOKINGNO = item . BOOKINGNO ,
Message = $"已成功取消"
} ) ;
//日志动态
SaveAuditLog ( $"取消提交" , order . Id ) ;
}
}
return rtnList ;
}
/// <summary>
/// 接收客户端修改服务项目
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ChangeServiceItem"), AllowAnonymous, ApiUser(ApiCode = "DjyBookingReceiveApi")]
public async Task ChangeServiceItem ( ChangeServiceItemDto dto )
{
var model = await _rep . AsQueryable ( ) . Filter ( null , true )
. InnerJoin ( _repOrder . AsQueryable ( ) . Filter ( null , true ) , ( custOrd , ord ) = > custOrd . BookingId = = ord . Id )
. Where ( ( custOrd , ord ) = > custOrd . BookingTenantName = = dto . CompanyName & & ord . BSNO = = dto . Id )
. Select ( ( custOrd , ord ) = > new { ord , custOrd } )
. FirstAsync ( ) ;
if ( model = = null )
{
throw Oops . Bah ( "未找到业务数据" ) ;
}
var serItm = _cache . GetAllDictData ( ) . Result . FirstOrDefault ( x = > x . TypeCode = = "booking_service_item" & & x . Code = = dto . ServiceCode ) ;
var mess = new DjyMessage ( ) ;
mess . Module = MessageModule . Booking . ToString ( ) ;
mess . TypeCode = MessageType . ChangeServiceItem . ToString ( ) ;
mess . TypeName = EnumHelper . GetDescription ( typeof ( MessageType ) , mess . TypeCode ) ;
mess . RelativeId = model . ord . Id ;
mess . RelativeCode = model . ord . BOOKINGNO ;
mess . Content = $"{dto.UserName} {(dto.IsCancel ? " 取 消 " : " 增 加 ")}了服务项目:{serItm.Value}" ;
mess . ExtData = new ChangeServiceItemExtModel ( ) { Dto = dto , OrderId = model . ord . Id , CustomerOrderId = model . custOrd . Id } . ToJsonString ( ) ;
mess . FromName = dto . CompanyName ;
mess . ProcStatus = MessageProcessStatus . UnProcess . ToString ( ) ;
await this . _repMessage . InsertAsync ( mess ) ;
await _publisher . PublishAsync ( new ChannelEventSource ( "Message:NotifyReceiveNew" ) ) ;
}
/// <summary>
/// 接收客户端提交的单证补料
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/RecDocSupplement"), AllowAnonymous, ApiUser(ApiCode = "DjyBookingReceiveApi")]
public async Task RecDocSupplement ( DocSupplementSubmitDto dto )
{
var model = await _rep . AsQueryable ( ) . Filter ( null , true )
. InnerJoin ( _repOrder . AsQueryable ( ) . Filter ( null , true ) , ( custOrd , ord ) = > custOrd . BookingId = = ord . Id )
. Where ( ( custOrd , ord ) = > custOrd . BookingTenantName = = dto . CompanyName & & ord . BSNO = = dto . Id )
. Select ( ( custOrd , ord ) = > new { ord , custOrd } )
. FirstAsync ( ) ;
if ( model = = null )
{
throw Oops . Bah ( "未找到业务数据" ) ;
}
var mess = new DjyMessage ( ) ;
mess . Module = MessageModule . Booking . ToString ( ) ;
mess . TypeCode = MessageType . DocSupplement . ToString ( ) ;
mess . TypeName = EnumHelper . GetDescription ( typeof ( MessageType ) , mess . TypeCode ) ;
mess . RelativeId = model . ord . Id ;
mess . RelativeCode = model . ord . BOOKINGNO ;
mess . Content = $"{dto.UserName} 增加了 {dto.DocTypeName}" ;
mess . ExtData = new DocSupplementExtModel ( ) { Dto = dto , OrderId = model . ord . Id , CustomerOrderId = model . custOrd . Id } . ToJsonString ( ) ;
mess . FromName = dto . CompanyName ;
mess . ProcStatus = MessageProcessStatus . UnProcess . ToString ( ) ;
await this . _repMessage . InsertAsync ( mess ) ;
await _publisher . PublishAsync ( new ChannelEventSource ( "Message:NotifyReceiveNew" ) ) ;
}
/// <summary>
/// 扣费
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/DoFee")]
public async Task DoFee ( long custOrdId )
{
await FeeSo ( custOrdId ) ;
}
# endregion
#region 私有方法
/// <summary>
/// 保存审核的日志动态(使用当前登录人信息)
/// </summary>
private void SaveAuditLog ( string status , long bookId , string remark = null )
{
var staLog = new BookingStatusLog ( ) ;
staLog . Status = status ;
staLog . CreatedUserId = UserManager . UserId ;
staLog . CreatedUserName = UserManager . Name ;
staLog . CreatedTime = DateTime . Now ;
staLog . OpTime = DateTime . Now ;
staLog . BookingId = bookId ;
staLog . Category = StaLogCateAudit ;
staLog . Remark = remark ;
_repStatuslog . Insert ( staLog ) ;
}
/// <summary>
/// 保存审核的日志动态
/// </summary>
private void SaveAuditLog ( string status , long bookId , long userId , long tenantId , string userName , string remark = null )
{
var staLog = new BookingStatusLog ( ) ;
staLog . Status = status ;
staLog . CreatedUserId = userId ;
staLog . CreatedUserName = userName ;
staLog . CreatedTime = DateTime . Now ;
staLog . OpTime = DateTime . Now ;
staLog . BookingId = bookId ;
staLog . Category = StaLogCateAudit ;
staLog . TenantId = tenantId ;
staLog . Remark = remark ;
_repStatuslog . Insert ( staLog ) ;
}
/// <summary>
/// 订舱审核后自动扣费
/// </summary>
/// <returns></returns>
private async Task FeeSo ( long id )
{
var model = await _rep . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . Id = = id ) ;
var cust = await _repCustomer . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . CustSysId = = model . BookingTenantId ) ;
var custParaList = await _repCustomerParamValue . AsQueryable ( ) . Filter ( null , true ) . Where ( x = > x . CustomerId = = cust . Id & & ( x . ParaCode = = "DjyFeeApiUserId" | | x . ParaCode = = "DjyFeeApiUserSecret" ) ) . ToListAsync ( ) ;
var bsType = 32 ;
var sendType = 0 ;
var typeStr = $"{bsType}_{sendType}" ;
var sysCfg = await _cache . GetAllSysConfig ( ) ;
var feeUrl = sysCfg . FirstOrDefault ( x = > x . Code = = "djyFeeApiUrl" ) ;
if ( feeUrl = = null | | string . IsNullOrEmpty ( feeUrl . Value ) )
{
var errMsg = "大简云扣费URL未配置" ;
_logger . LogError ( errMsg ) ;
SaveAuditLog ( $"扣费失败" , model . Id , model . CreatedUserId . Value , model . TenantId . Value , "系统" , remark : errMsg ) ;
return ;
}
//扣费接口用户id和key
var feeUserId = custParaList . FirstOrDefault ( x = > x . ParaCode = = "DjyFeeApiUserId" ) ? . ItemCode ;
var feeUserKey = custParaList . FirstOrDefault ( x = > x . ParaCode = = "DjyFeeApiUserSecret" ) ? . ItemCode ;
if ( string . IsNullOrEmpty ( feeUserId ) | | string . IsNullOrEmpty ( feeUserKey ) )
{
var errMsg = $"未找到{model.BOOKINGNO}({model.Id})所在客户的授权userid和key, 无法调用扣费" ;
_logger . LogError ( errMsg ) ;
SaveAuditLog ( $"扣费失败" , model . Id , model . CreatedUserId . Value , model . TenantId . Value , "系统" , remark : "未找到扣费接口授权信息" ) ;
return ;
}
//判断重复扣费
var c = _repFeeRecord . AsQueryable ( ) . Filter ( null , true ) . Count ( x = > x . TenantId = = model . BookingTenantId & & x . MBLNO = = model . BOOKINGNO ) ;
if ( c > 0 )
{
_logger . LogInformation ( $"已存在扣费记录, id: {model.Id},订舱号:{model.BOOKINGNO},租户:{model.BookingTenantId}" ) ;
return ;
}
//客户联系人
var contact = await _repCustomerContact . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . CustSysId = = model . BookingUserId ) ;
if ( contact = = null )
{
var errMsg = $"未找到{model.BOOKINGNO}({model.Id})的客户联系人" ;
_logger . LogError ( errMsg ) ;
SaveAuditLog ( $"扣费失败" , model . Id , model . CreatedUserId . Value , model . TenantId . Value , "系统" , remark : "未找到客户联系人" ) ;
return ;
}
//扣费dto
var seconds = DateTime . Now . ToTimeStamp ( ) ;
var runId = Guid . NewGuid ( ) . ToString ( ) ;
var srcBeforMD5 = $"{runId}{feeUserId}expend{bsType}{sendType}{model.Id}{model.BOOKINGNO}{seconds}{feeUserKey}" ;
var postObj = new
{
runId ,
userId = feeUserId ,
module = "expend" , //固定
bsType = $"{bsType}" ,
sendType = $"{sendType}" ,
timestamp = seconds , //秒级时间戳
md5 = srcBeforMD5 . ToMd5 ( ) , // 加密字符串小写 RunId + UserId + Module + BsType + SendType+Timestamp+ Key
Data = new
{
BSNO = model . Id . ToString ( ) ,
MBLNO = model . BOOKINGNO ,
CtnrInfo = "" ,
CtnrCount = 1 ,
IsCredit = 0 , //是否是信用支付 1 信用支付 0不允许信用支付默认值为0,
LURURENID = contact . DjyGid ,
SENDUSERID = contact . DjyGid ,
VESSEL = model . VESSEL ,
VOYNO = model . VOYNO ,
ETD = model . ETD ,
CARRIER = model . CARRIER
}
} ;
_logger . LogInformation ( $"调用扣费:{postObj.ToJsonString()}" ) ;
var apiRtn = await feeUrl . Value
. SetHttpMethod ( HttpMethod . Post )
. SetBody ( postObj )
. SetRetryPolicy ( 3 , 5000 )
. OnException ( ( c , m , errMsg ) = >
{
_logger . LogError ( $"扣费失败:{errMsg}" ) ;
SaveAuditLog ( $"扣费失败" , model . Id , model . CreatedUserId . Value , model . TenantId . Value , "系统" , remark : errMsg ) ;
} )
. SendAsStringAsync ( ) ;
_logger . LogInformation ( $"调用扣费返回:{apiRtn}" ) ;
var jobjApiRtn = JObject . Parse ( apiRtn ) ;
var code = jobjApiRtn . GetIntValue ( "code" ) ;
var jobjApiRtnData = jobjApiRtn . GetValue ( "data" ) as JObject ;
if ( code = = 200 | | code = = 450 )
{
var jobjApiRtnDataPayInfo = jobjApiRtnData . GetValue ( "payInfo" ) as JObject ;
var price = Convert . ToDecimal ( jobjApiRtnDataPayInfo . GetValue ( "price" ) . ToString ( ) ) ;
var total = Convert . ToDecimal ( jobjApiRtnDataPayInfo . GetValue ( "total" ) . ToString ( ) ) ;
//记录扣费
var fr = new BookingFeeRecord ( ) ;
fr . Id = YitIdHelper . NextId ( ) ;
fr . BillId = model . Id ;
fr . MBLNO = model . BOOKINGNO ;
fr . TenantId = model . BookingTenantId ;
fr . Type = typeStr ;
fr . Amount = total ;
await _repFeeRecord . InsertAsync ( fr ) ;
SaveAuditLog ( $"扣费成功" , model . Id , model . CreatedUserId . Value , model . TenantId . Value , "系统" , remark : "" ) ;
}
else
{
var errMsg = jobjApiRtn . GetValue ( "message" ) . ToString ( ) ;
_logger . LogError ( $"扣费失败:{errMsg}" ) ;
SaveAuditLog ( $"扣费失败" , model . Id , model . CreatedUserId . Value , model . TenantId . Value , "系统" , remark : errMsg ) ;
}
}
# endregion
#region 外部开放接口
/// <summary>
/// 接收外部调用生成客户订舱需求
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ReceiveCustomerOrder"), AllowAnonymous, ApiUser]
public async Task ReceiveCustomerOrder ( [ FromForm ] BookingCustomerApiSaveInput input , IFormFile [ ] files )
{
var carrList = await _cache . GetAllCodeCarrier ( ) ;
var portLoadList = await _cache . GetAllCodePortLoad ( ) ;
var portDestList = await _cache . GetAllCodePort ( ) ;
var serviceList = await _cache . GetAllCodeService ( ) ;
var frtList = await _cache . GetAllCodeFrt ( ) ;
var ctnList = await _cache . GetAllCodeCtn ( ) ;
#region 校验
/ *
1. 必 填 字 段 : 船 公 司 , 开 船 日 期 , 起 运 港 , 目 的 港 , 箱 型 箱 量 , 服 务 项 目 , 运 输 条 款 , 付 费 方 式 , 件 数 , 毛 重 , 包 装 , 货 物 标 识 , 品 名 , HSCODE 。
2. 条 件 字 段 1 : 若 货 物 标 识 为 冻 柜 , 温 度 , 通 风 , 湿 度 必 填 。
3. 条 件 字 段 2 : 若 货 物 标 识 为 危 险 品 , 危 险 品 编 号 , 危 险 品 等 级 , 联 系 人 , 电 话 , HSCODE 必 填 。
* /
/ *
必 填 字 段 : 去 掉 件 数 、 包 装 、 HSCODE , 增 加 合 约 号 , 订 舱 账 号 , 订 舱 密 码
* /
if ( string . IsNullOrEmpty ( input . BSNO ) )
{
throw Oops . Bah ( "未提供业务ID" ) ;
}
if ( string . IsNullOrEmpty ( input . CONTRACTNO ) )
{
throw Oops . Bah ( "合约号不能为空" ) ;
}
//if (string.IsNullOrEmpty(input.BOOKINGACCOUNT))
//{
// throw Oops.Bah("订舱账号不能为空");
//}
//if (string.IsNullOrEmpty(input.BOOKINGPASSWORD))
//{
// throw Oops.Bah("订舱密码不能为空");
//}
//2024-4-2, 为保证后面自动化订舱需要, 船司、港口、箱型等信息改为传公共库中的唯一代码
if ( string . IsNullOrEmpty ( input . CARRIERID ) )
{
throw Oops . Bah ( "船司代码不能为空" ) ;
}
var carr = carrList . FirstOrDefault ( x = > x . Code = = input . CARRIERID ) ;
if ( carr = = null )
{
throw Oops . Bah ( $"未找到匹配的船司代码:{input.CARRIERID}" ) ;
}
// 2024-4-9: 中远约号最长8位
if ( input . CARRIERID = = "COSCO" & & input . CONTRACTNO . Length > 8 )
{
throw Oops . Bah ( $"约号超长, 【中远】约号最长8位, 请检查" ) ;
}
if ( ! input . ETD . HasValue )
{
throw Oops . Bah ( "开船日期不能为空" ) ;
}
//2024-4-2, 为保证后面自动化订舱需要, 船司、港口、箱型等信息改为传公共库中的唯一代码, 名称和五字码根据唯一代码匹配写入, 无需传递
//if (string.IsNullOrEmpty(input.PORTLOADID) || string.IsNullOrEmpty(input.PORTLOAD))
//{
// throw Oops.Bah("起运港代码和名称不能为空");
//}
//if (string.IsNullOrEmpty(input.PORTDISCHARGEID) || string.IsNullOrEmpty(input.PORTDISCHARGE))
//{
// throw Oops.Bah("目的港代码和名称不能为空");
//}
//起运港校验
if ( string . IsNullOrEmpty ( input . PORTLOADCODE ) )
{
throw Oops . Bah ( "起运港代码不能为空" ) ;
}
var portLoad = portLoadList . FirstOrDefault ( x = > x . Code = = input . PORTLOADCODE ) ;
if ( portLoad = = null )
{
throw Oops . Bah ( $"未找到匹配的起运港:{input.PORTLOADCODE}" ) ;
}
//目的港校验
if ( string . IsNullOrEmpty ( input . PORTDISCHARGECODE ) )
{
throw Oops . Bah ( "目的港代码不能为空" ) ;
}
var portDest = portDestList . FirstOrDefault ( x = > x . Code = = input . PORTDISCHARGECODE ) ;
if ( portDest = = null )
{
throw Oops . Bah ( $"未找到匹配的目的港:{input.PORTDISCHARGECODE}" ) ;
}
////收货地校验
//if (string.IsNullOrEmpty(input.PLACERECEIPTCODE))
//{
// throw Oops.Bah("收货地代码不能为空");
//}
var placereceipt = portLoadList . FirstOrDefault ( x = > x . Code = = input . PLACERECEIPTCODE ) ;
//if (placereceipt == null)
//{
// throw Oops.Bah($"未找到匹配的收货地:{input.PLACERECEIPTCODE}");
//}
//目的地校验
if ( string . IsNullOrEmpty ( input . DESTINATIONCODE ) )
{
throw Oops . Bah ( "目的地代码不能为空" ) ;
}
var destination = portDestList . FirstOrDefault ( x = > x . Code = = input . DESTINATIONCODE ) ;
if ( destination = = null )
{
throw Oops . Bah ( $"未找到匹配的目的地:{input.DESTINATIONCODE}" ) ;
}
if ( string . IsNullOrEmpty ( input . SERVICECODE ) )
{
throw Oops . Bah ( "运输条款代码不能为空" ) ;
}
var service = serviceList . FirstOrDefault ( x = > x . Code = = input . SERVICECODE ) ;
if ( service = = null )
{
throw Oops . Bah ( $"未找到匹配的运输条款:{input.SERVICECODE}" ) ;
}
if ( string . IsNullOrEmpty ( input . FRTCODE ) )
{
throw Oops . Bah ( "付费方式代码不能为空" ) ;
}
var frt = frtList . FirstOrDefault ( x = > x . Code = = input . FRTCODE ) ;
if ( frt = = null )
{
throw Oops . Bah ( $"未找到匹配的付费方式:{input.FRTCODE}" ) ;
}
if ( ! input . KGS . HasValue )
{
throw Oops . Bah ( "重量不能为空" ) ;
}
if ( string . IsNullOrEmpty ( input . CARGOID ) )
{
throw Oops . Bah ( "货物标识不能为空" ) ;
}
if ( input . CARGOID = = "R" )
{
if ( string . IsNullOrEmpty ( input . TEMPSET ) )
{
throw Oops . Bah ( "货物标识为冻柜的情况下,温度不能为空" ) ;
}
if ( string . IsNullOrEmpty ( input . REEFERF ) )
{
throw Oops . Bah ( "货物标识为冻柜的情况下,通风度不能为空" ) ;
}
if ( string . IsNullOrEmpty ( input . HUMIDITY ) )
{
throw Oops . Bah ( "货物标识为冻柜的情况下,湿度不能为空" ) ;
}
}
else if ( input . CARGOID = = "D" )
{
if ( string . IsNullOrEmpty ( input . DUNNO ) )
{
throw Oops . Bah ( "货物标识为危险品的情况下,危险品编号不能为空" ) ;
}
if ( string . IsNullOrEmpty ( input . DCLASS ) )
{
throw Oops . Bah ( "货物标识为危险品的情况下,危险品等级不能为空" ) ;
}
if ( string . IsNullOrEmpty ( input . LINKMAN ) )
{
throw Oops . Bah ( "货物标识为危险品的情况下,危险品联系人不能为空" ) ;
}
if ( string . IsNullOrEmpty ( input . DTEL ) )
{
throw Oops . Bah ( "货物标识为危险品的情况下,危险品联系电话不能为空" ) ;
}
}
if ( string . IsNullOrEmpty ( input . DESCRIPTION ) )
{
throw Oops . Bah ( "品名不能为空" ) ;
}
if ( input . CtnList = = null | | input . CtnList . Count = = 0 )
{
throw Oops . Bah ( "箱信息不能为空" ) ;
}
var notExistCode = input . CtnList . Where ( x = > ctnList . Count ( y = > y . Code = = x . CTNCODE ) = = 0 ) . Select ( x = > x . CTNCODE ) . ToList ( ) ;
if ( notExistCode . Any ( ) )
{
throw Oops . Bah ( $"未找到箱型:{string.Join(" , ", notExistCode)}" ) ;
}
if ( input . ServiceItemList = = null | | input . ServiceItemList . Count = = 0 )
{
throw Oops . Bah ( "服务项目不能为空" ) ;
}
# endregion
var custOrder = await _rep . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . TenantId = = UserManager . TENANT_ID & & x . BSNO = = input . BSNO ) ;
var ins = false ;
if ( custOrder ! = null )
{
if ( custOrder . BSSTATUS = = "已审核" )
{
throw Oops . Bah ( "已审核的数据不能修改" ) ;
}
if ( custOrder . BSSTATUS = = "已提交" )
{
await CancelSubmit ( new List < long > ( ) { custOrder . Id } ) ;
custOrder = await _rep . AsQueryable ( ) . Filter ( null , true ) . FirstAsync ( x = > x . Id = = custOrder . Id ) ; //取消后重新拉取一遍数据
}
input . Id = custOrder . Id ;
input . Adapt ( custOrder ) ;
}
else
{
custOrder = input . Adapt < BookingCustomerOrder > ( ) ;
ins = true ;
}
//赋值根据唯一代码匹配后的代码、名称等信息
custOrder . CARRIER = carr . EnName ;
custOrder . PORTLOAD = portLoad . EnName ;
custOrder . PORTLOADID = portLoad . EdiCode ;
custOrder . PORTDISCHARGE = portDest . EnName ;
custOrder . PORTDISCHARGEID = portDest . EdiCode ;
custOrder . SERVICE = service . Name ;
custOrder . PLACERECEIPT = placereceipt ? . EnName ;
custOrder . PLACERECEIPTID = placereceipt ? . EdiCode ;
custOrder . DESTINATION = destination . EnName ;
custOrder . DESTINATIONID = destination . EdiCode ;
custOrder . BLFRT = frt . EnName ;
//2024年4月19日, 将分拆的收发通拼接到大文本的收发通中
if ( string . IsNullOrEmpty ( custOrder . SHIPPER ) & & ! string . IsNullOrEmpty ( custOrder . ShipperName ) )
{
custOrder . SHIPPER = @ $ "{custOrder.ShipperName}
{ custOrder . ShipperAddress }
{ custOrder . ShipperCountry } { custOrder . ShipperProvince } { custOrder . ShipperCity } { custOrder . ShipperCounty } { custOrder . ShipperPostCode }
{ custOrder . ShipperLastName } { custOrder . ShipperFirstName } { custOrder . ShipperPhoneCountryCode } { custOrder . ShipperPhoneCode } { custOrder . ShipperPhone } ".ToUpper();
}
if ( string . IsNullOrEmpty ( custOrder . CONSIGNEE ) & & ! string . IsNullOrEmpty ( custOrder . ConsigneeName ) )
{
custOrder . CONSIGNEE = @ $ "{custOrder.ConsigneeName}
{ custOrder . ConsigneeAddress }
{ custOrder . ConsigneeCountry } { custOrder . ConsigneeProvince } { custOrder . ConsigneeCity } { custOrder . ConsigneeCounty } { custOrder . ConsigneePostCode }
{ custOrder . ConsigneeLastName } { custOrder . ConsigneeFirstName } { custOrder . ConsigneePhoneCountryCode } { custOrder . ConsigneePhoneCode } { custOrder . ConsigneePhone } ".ToUpper();
}
if ( string . IsNullOrEmpty ( custOrder . NOTIFYPARTY ) & & ! string . IsNullOrEmpty ( custOrder . NotifypartName ) )
{
custOrder . NOTIFYPARTY = @ $ "{custOrder.NotifypartName}
{ custOrder . NotifypartAddress }
{ custOrder . NotifypartCountry } { custOrder . NotifypartProvince } { custOrder . NotifypartCity } { custOrder . NotifypartCounty } { custOrder . NotifypartPostCode }
{ custOrder . NotifypartLastName } { custOrder . NotifypartFirstName } { custOrder . NotifypartPhoneCountryCode } { custOrder . NotifypartPhoneCode } { custOrder . NotifypartPhone } ".ToUpper();
}
//订舱账号、密码
var jobj = new JObject ( ) ;
if ( ! string . IsNullOrEmpty ( custOrder . ExtendData ) )
{
jobj = JObject . Parse ( custOrder . ExtendData ) ;
}
jobj [ "Account" ] = input . BOOKINGACCOUNT ;
jobj [ "Password" ] = input . BOOKINGPASSWORD ;
jobj [ "OpMail" ] = input . OPMAIL ;
jobj [ "PolPortName" ] = input . PolPortName ;
jobj [ "PodPortName" ] = input . PodPortName ;
custOrder . ExtendData = jobj . ToJsonString ( ) ;
var ctns = input . CtnList . Adapt < List < BookingCtn > > ( ) ;
foreach ( var ctn in ctns )
{
ctn . CTNALL = ctnList . First ( x = > x . Code = = ctn . CTNCODE ) . Name ;
}
var servList = input . ServiceItemList . Adapt < List < BookingServiceItem > > ( ) ;
await SaveData ( custOrder , ctns , servList , ins ) ;
#region 处理附件
var dbFiles = _repFile . AsQueryable ( ) . Where ( x = > x . BookingId = = custOrder . Id ) . ToList ( ) ;
var opt = App . GetOptions < BookingAttachOptions > ( ) ;
var dirAbs = string . Empty ;
if ( string . IsNullOrEmpty ( opt . basePath ) )
{
dirAbs = Path . Combine ( App . WebHostEnvironment . WebRootPath , opt . relativePath ) ;
}
else
{
dirAbs = Path . Combine ( opt . basePath , opt . relativePath ) ;
}
if ( ! Directory . Exists ( dirAbs ) )
Directory . CreateDirectory ( dirAbs ) ;
foreach ( var upFile in files )
{
var extName = Path . GetExtension ( upFile . FileName ) ;
if ( opt . fileType . Contains ( extName . ToLower ( ) ) )
{
throw Oops . Bah ( $"不允许的文件类型:{extName}" ) ;
}
var dbFile = dbFiles . FirstOrDefault ( x = > x . BookingId = = custOrder . Id & & x . FileName = = upFile . FileName ) ;
if ( dbFile = = null )
{
var saveFileName = $"{DateTime.Now.Ticks}{extName}" ;
var fileRelaPath = Path . Combine ( opt . relativePath , saveFileName ) . ToLower ( ) ;
var fileAbsPath = Path . Combine ( dirAbs , saveFileName ) . ToLower ( ) ;
using ( var stream = File . Create ( fileAbsPath ) )
{
await upFile . CopyToAsync ( stream ) ;
}
var newFile = new BookingFile
{
Id = YitIdHelper . NextId ( ) ,
FileName = Path . GetFileName ( upFile . FileName ) ,
FilePath = fileRelaPath ,
TypeCode = "tuodan" ,
TypeName = "托单文件" ,
BookingId = custOrder . Id ,
} ;
await _repFile . InsertAsync ( newFile ) ;
}
else
{
var fileFullPath = Path . Combine ( dirAbs , dbFile . FilePath ) ;
using ( var stream = File . Create ( fileFullPath ) )
{
await upFile . CopyToAsync ( stream ) ;
}
await _repFile . UpdateAsync ( dbFile ) ;
}
}
# endregion
await Submit ( new List < long > { custOrder . Id } ) ;
}
# endregion
#region 发送订舱
/// <summary>
/// 发送Api订舱, 目前只有中远
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/PostApiSO")]
public async Task PostApiSO ( long id )
{
var rtn = await ZhongYuanSoApiHelper . DoPost ( id ) ;
if ( ! rtn . Key )
{
SaveAuditLog ( "发送订舱" , id , remark : rtn . Value ) ;
throw Oops . Bah ( rtn . Value ) ;
}
SaveAuditLog ( "发送订舱" , id , remark : rtn . Value ) ;
}
# endregion
}
}