|
|
|
|
using DS.Module.Core;
|
|
|
|
|
using DS.WMS.Core.Op.Dtos;
|
|
|
|
|
using NPOI.SS.Formula.Functions;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
using Logger = NLog.Logger;
|
|
|
|
|
using NLog;
|
|
|
|
|
|
|
|
|
|
namespace DS.WMS.Core.Op.EDI
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// VOLTA EDI 导入截单帮助类
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class VOLTAEdiFileImportHelper
|
|
|
|
|
{
|
|
|
|
|
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
|
|
|
|
|
#region 生成VOLTA申报报文(截单)
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 生成VOLTA申报报文(截单)
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="model">VOLTA申报详情</param>
|
|
|
|
|
/// <returns>返回回执</returns>
|
|
|
|
|
public static EdiDataResult CreateEdiVOLTA(VOLTAEDIBaseModel model)
|
|
|
|
|
{
|
|
|
|
|
var result = new EdiDataResult { Succeeded = false };
|
|
|
|
|
|
|
|
|
|
//日志
|
|
|
|
|
//var logger = Log.CreateLogger(nameof(VOLTAEdiHelper));
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ValidateInput(model);
|
|
|
|
|
|
|
|
|
|
string bno = model.BookingId;
|
|
|
|
|
|
|
|
|
|
string filePath = model.FilePath + "\\" + DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
|
|
|
|
|
|
|
|
|
//预先创建目录
|
|
|
|
|
if (!Directory.Exists(filePath))
|
|
|
|
|
{
|
|
|
|
|
Directory.CreateDirectory(filePath);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string filename = filePath + "\\" + bno + ".txt";
|
|
|
|
|
|
|
|
|
|
//如果是部署linux需要修改路径
|
|
|
|
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
|
|
|
|
filename = filename.Replace("\\", "/");
|
|
|
|
|
|
|
|
|
|
FileStream f = new FileStream(filename, FileMode.Create);
|
|
|
|
|
StreamWriter r = new StreamWriter(f, Encoding.Default);
|
|
|
|
|
|
|
|
|
|
DateTime nowDate = DateTime.Now;
|
|
|
|
|
|
|
|
|
|
r.WriteLine("<FROMSHIPPER>FROMSHIPPER</FROMSHIPPER>");
|
|
|
|
|
//订舱号
|
|
|
|
|
r.WriteLine("<bok>" + model.BookingId + "</bok>");
|
|
|
|
|
//发货人
|
|
|
|
|
r.WriteLine("<spr>" + model.ShpperName + "</spr>");
|
|
|
|
|
//发货人地址
|
|
|
|
|
r.WriteLine("<sad>");
|
|
|
|
|
r.WriteLine(model.ShpperAddr);
|
|
|
|
|
r.WriteLine("</sad>");
|
|
|
|
|
//收货人
|
|
|
|
|
r.WriteLine("<cne>" + model.ConsigneeName + "</cne>");
|
|
|
|
|
//收货人地址
|
|
|
|
|
r.WriteLine("<cad>");
|
|
|
|
|
r.WriteLine(model.ConsigneeAddr);
|
|
|
|
|
r.WriteLine("</cad>");
|
|
|
|
|
//通知人
|
|
|
|
|
r.WriteLine("<nfy>" + model.NotifyName + "</nfy>");
|
|
|
|
|
//通知人地址
|
|
|
|
|
r.WriteLine("<nad>");
|
|
|
|
|
r.WriteLine(model.NotifyAddr);
|
|
|
|
|
r.WriteLine("</nad>");
|
|
|
|
|
//通知人1
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(model.NotifySecondName))
|
|
|
|
|
{
|
|
|
|
|
r.WriteLine("<nf1>" + model.NotifySecondName + "</nf1>");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
r.WriteLine("<nf1></nf1>");
|
|
|
|
|
}
|
|
|
|
|
//通知人1地址
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(model.NotifySecondName))
|
|
|
|
|
{
|
|
|
|
|
r.WriteLine("<na1>");
|
|
|
|
|
r.WriteLine(model.ConsigneeAddr);
|
|
|
|
|
r.WriteLine("</na1>");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
r.WriteLine("<na1>");
|
|
|
|
|
r.WriteLine("");
|
|
|
|
|
r.WriteLine("</na1>");
|
|
|
|
|
}
|
|
|
|
|
//发货地
|
|
|
|
|
r.WriteLine("<Poo>" + model.PlaceOfOrigin + "</Poo>");
|
|
|
|
|
//起运港
|
|
|
|
|
r.WriteLine("<pol>" + model.LoadPort + "</pol>");
|
|
|
|
|
//卸货港
|
|
|
|
|
r.WriteLine("<pod>" + model.DischargePort + "</pod>");
|
|
|
|
|
//最终目的港
|
|
|
|
|
r.WriteLine("<fpd>" + model.FinalDestination + "</fpd>");
|
|
|
|
|
//最终交货地
|
|
|
|
|
r.WriteLine("<pdy>" + model.PlaceOfDelivery + "</pdy>");
|
|
|
|
|
|
|
|
|
|
//PlaceOfReceipt
|
|
|
|
|
r.WriteLine("<por></por>");
|
|
|
|
|
//提单正本份数默认3
|
|
|
|
|
r.WriteLine("<nob>3</nob>");
|
|
|
|
|
//提单状态(默认S) S-SHIPPED ON BOARD;R-RECEIVED FOR SHIPMENT;T-THRO BL
|
|
|
|
|
r.WriteLine("<blt>S</blt>");
|
|
|
|
|
//重量单位(默认1) 1-KGS;2-TON;3-QUINTAL;4-MT;5-CENTIMETER;6-METER;7-INCH
|
|
|
|
|
r.WriteLine("<uom>1</uom>");
|
|
|
|
|
//Payable At
|
|
|
|
|
r.WriteLine("<pat></pat>");
|
|
|
|
|
//Prepaid / Collect(默认P) P-PREPAID;C-COLLECT
|
|
|
|
|
r.WriteLine("<fst>P</fst>");
|
|
|
|
|
//EDNumber
|
|
|
|
|
r.WriteLine("<edn></edn>");
|
|
|
|
|
//货描
|
|
|
|
|
r.WriteLine("<des>");
|
|
|
|
|
r.WriteLine(model.CargoDescription);
|
|
|
|
|
r.WriteLine("</des>");
|
|
|
|
|
//唛头
|
|
|
|
|
r.WriteLine("<cmn>");
|
|
|
|
|
r.WriteLine(model.Marks);
|
|
|
|
|
r.WriteLine("</cmn>");
|
|
|
|
|
//模板版本号
|
|
|
|
|
r.WriteLine("<ver>");
|
|
|
|
|
r.WriteLine(model.TemplateVersion);
|
|
|
|
|
r.WriteLine("</ver>");
|
|
|
|
|
//箱明细
|
|
|
|
|
r.WriteLine("<cnt>");
|
|
|
|
|
r.Write(GetContaInfo(model.ContaList));
|
|
|
|
|
r.WriteLine("</cnt>");
|
|
|
|
|
|
|
|
|
|
r.Close();
|
|
|
|
|
f.Close();
|
|
|
|
|
|
|
|
|
|
result.Succeeded = true;
|
|
|
|
|
result.ExtraData1 = filename;
|
|
|
|
|
result.ExtraData2 = $"截单样本:{model.Vessel} {model.VoyNo} {model.BookingId}";
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
result.Succeeded = false;
|
|
|
|
|
result.Message = ex.Message;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//return result;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 拼接箱明细报文
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 拼接箱明细报文
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="contaList">箱明细</param>
|
|
|
|
|
/// <returns>返回拼接后字符</returns>
|
|
|
|
|
private static string GetContaInfo(List<VOLTAEDIContaModel> contaList)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder txtBuilder = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
////日志
|
|
|
|
|
//var logger = Log.CreateLogger(nameof(VOLTAEdiHelper));
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
contaList.ForEach(ctn =>
|
|
|
|
|
{
|
|
|
|
|
//箱拼接格式:序号~箱号~铅封号~Custom Seal No~毛重~净重~尺码~重量单位~~件数~~~包装
|
|
|
|
|
txtBuilder.AppendLine($"{ctn.SNo}~{ctn.ContaNo}~{ctn.SealNo}~~{ctn.GWt.Value.ToString("0.###")}~{(ctn.NWt.HasValue ? ctn.NWt.Value.ToString("0.###") : "")}~{ctn.CBM.Value.ToString("0.###")}~{ctn.WTUnit}~~{ctn.Qty.Value.ToString("#.###")}~~~{ctn.EdiPkgs}");
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
logger.Info("VOLTA拼接箱明细异常,原因:{0}", ex.Message);
|
|
|
|
|
|
|
|
|
|
throw ex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return txtBuilder.ToString();
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region 校验VOLTA请求参数s
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 校验VOLTA请求参数
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="model">VOLTA请求参数</param>
|
|
|
|
|
public static void ValidateInput(VOLTAEDIBaseModel model)
|
|
|
|
|
{
|
|
|
|
|
StringBuilder msgBuilder = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.BookingId))
|
|
|
|
|
msgBuilder.AppendLine("提单号不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.ShpperName))
|
|
|
|
|
msgBuilder.AppendLine("发货人名称不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.ShpperAddr))
|
|
|
|
|
msgBuilder.AppendLine("发货人地址不能为空");
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(model.ShpperAddr))
|
|
|
|
|
{
|
|
|
|
|
if (model.ShpperAddr.Length > 450)
|
|
|
|
|
msgBuilder.AppendLine("发货人地址不能大于450个字符");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.ConsigneeName))
|
|
|
|
|
msgBuilder.AppendLine("收货人名称不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.ConsigneeAddr))
|
|
|
|
|
msgBuilder.AppendLine("收货人地址不能为空");
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(model.ConsigneeAddr))
|
|
|
|
|
{
|
|
|
|
|
if (model.ConsigneeAddr.Length > 450)
|
|
|
|
|
msgBuilder.AppendLine("收货人地址不能大于450个字符");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.NotifyName))
|
|
|
|
|
msgBuilder.AppendLine("通知人名称不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.NotifyAddr))
|
|
|
|
|
msgBuilder.AppendLine("通知人地址不能为空");
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(model.NotifyAddr))
|
|
|
|
|
{
|
|
|
|
|
if (model.NotifyAddr.Length > 450)
|
|
|
|
|
msgBuilder.AppendLine("通知人地址不能大于450个字符");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(model.NotifySecondName) && string.IsNullOrEmpty(model.NotifySecondAddr))
|
|
|
|
|
msgBuilder.AppendLine("通知人1地址不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.NotifySecondName) && !string.IsNullOrEmpty(model.NotifySecondAddr))
|
|
|
|
|
msgBuilder.AppendLine("通知人1名称不能为空");
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(model.NotifySecondAddr))
|
|
|
|
|
{
|
|
|
|
|
if (model.NotifySecondAddr.Length > 450)
|
|
|
|
|
msgBuilder.AppendLine("通知人1地址不能大于450个字符");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.PlaceOfOrigin))
|
|
|
|
|
msgBuilder.AppendLine("发货地不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.LoadPort))
|
|
|
|
|
msgBuilder.AppendLine("起运港不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.DischargePort))
|
|
|
|
|
msgBuilder.AppendLine("卸货港不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.FinalDestination))
|
|
|
|
|
msgBuilder.AppendLine("最终目的港不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.PlaceOfDelivery))
|
|
|
|
|
msgBuilder.AppendLine("最终交货地不能为空");
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.CargoDescription))
|
|
|
|
|
msgBuilder.AppendLine("品名不能为空");
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(model.CargoDescription))
|
|
|
|
|
{
|
|
|
|
|
if (model.CargoDescription.Length > 3000)
|
|
|
|
|
msgBuilder.AppendLine("品名不能大于3000个字符");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(model.Marks))
|
|
|
|
|
msgBuilder.AppendLine("唛头不能为空");
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(model.Marks))
|
|
|
|
|
{
|
|
|
|
|
if (model.Marks.Length > 1000)
|
|
|
|
|
msgBuilder.AppendLine("唛头不能大于1000个字符");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (model.ContaList == null || model.ContaList.Count == 0)
|
|
|
|
|
msgBuilder.AppendLine("箱明细不能为空");
|
|
|
|
|
|
|
|
|
|
model.ContaList.ForEach(ctn =>
|
|
|
|
|
{
|
|
|
|
|
StringBuilder ctnMsgBuilder = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(ctn.ContaNo))
|
|
|
|
|
{
|
|
|
|
|
ctnMsgBuilder.Append("箱号不能为空;");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (ctn.ContaNo.Length > 11)
|
|
|
|
|
{
|
|
|
|
|
ctnMsgBuilder.Append("箱号长度不能大于11;");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(ctn.SealNo))
|
|
|
|
|
{
|
|
|
|
|
ctnMsgBuilder.Append("铅封号不能为空;");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ctn.GWt.HasValue)
|
|
|
|
|
{
|
|
|
|
|
ctnMsgBuilder.Append("毛重不能为空;");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ctn.CBM.HasValue)
|
|
|
|
|
{
|
|
|
|
|
ctnMsgBuilder.Append("尺寸不能为空;");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ctn.Qty.HasValue)
|
|
|
|
|
{
|
|
|
|
|
ctnMsgBuilder.Append("件数不能为空;");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(ctn.EdiPkgs))
|
|
|
|
|
{
|
|
|
|
|
ctnMsgBuilder.Append("包装不能为空;");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ctnMsgBuilder.Length > 0)
|
|
|
|
|
{
|
|
|
|
|
msgBuilder.AppendLine($"箱【{ctn.SNo}】{ctnMsgBuilder.ToString()}");
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (msgBuilder.Length > 0)
|
|
|
|
|
throw new Exception(msgBuilder.ToString());
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|