ai识别后端支持;后端返回空值处理

dev
cjy 2 weeks ago
parent 34a5f85571
commit 6c7ff4171e

@ -68,7 +68,7 @@ public static class DsAppWebInstall
// 忽略循环引用
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
// 忽略空值
// options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
})
;
//添加FluentValidation验证

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DS.WMS.Core.Op.Dtos.BookingAI
{
public class BookingAIReq
{
/// <summary>
/// 平台代码
/// </summary>
public string Platform { get; set; } = "QWEN";
}
}

@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DS.WMS.Core.Op.Dtos.BookingAI
{
/// <summary>
///
/// </summary>
public class ContainersItemRes
{
/// <summary>
/// 箱量
/// </summary>
public string CartonQuantity { get; set; }
/// <summary>
/// 箱型
/// </summary>
public string BoxPile { get; set; }
/// <summary>
/// 尺寸
/// </summary>
public string Size { get; set; }
/// <summary>
/// 毛重
/// </summary>
public string GrossWeight { get; set; }
/// <summary>
/// 箱皮重
/// </summary>
public string TareWeight { get; set; }
/// <summary>
/// 危品票标示
/// </summary>
public string IODGT { get; set; }
/// <summary>
/// 危品票:等级
/// </summary>
public string IODGTLevel { get; set; }
/// <summary>
/// 冷柜:温度
/// </summary>
public string Temperature { get; set; }
/// <summary>
/// 冷柜:通风
/// </summary>
public string Ventilate { get; set; }
/// <summary>
/// 特殊装载需求
/// </summary>
public string SpecialLoadingRequirement { get; set; }
/// <summary>
/// 提箱场站
/// </summary>
public string SuitcaseTterminal { get; set; }
/// <summary>
/// 提箱时间
/// </summary>
public string SuitcaseTime { get; set; }
/// <summary>
/// 还箱场站
/// </summary>
public string ReturnDepot { get; set; }
}
}

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DS.WMS.Core.Op.Dtos.BookingAI
{
/// <summary>
/// AI识别返回结果
/// </summary>
public class ParseItemRes
{
/// <summary>
/// 响应码
/// </summary>
public int Code { get; set; }
/// <summary>
/// 提示信息
/// </summary>
public string Msg { get; set; }
public List<ParseItemRes_List> Data { get; set; }
}
}

@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DS.WMS.Core.Op.Dtos.BookingAI
{
/// <summary>
///
/// </summary>
public class ParseItemRes_List
{
/// <summary>
/// 订舱单位
/// </summary>
public string BookingParty { get; set; }
/// <summary>
/// 业务类型
/// </summary>
public string BusinessType { get; set; }
/// <summary>
/// 发货人
/// </summary>
public string Shipper { get; set; }
/// <summary>
/// 收货人
/// </summary>
public string Consigner { get; set; }
/// <summary>
/// 通知人
/// </summary>
public string NotifyParty { get; set; }
/// <summary>
/// BC更新次数
/// </summary>
public string BCUpdateTimes { get; set; }
/// <summary>
/// BC更新时间
/// </summary>
public string BCUpdateTime { get; set; }
/// <summary>
/// 提单号
/// </summary>
public string BLNo { get; set; }
/// <summary>
/// 参考号
/// </summary>
public string ReferenceNo { get; set; }
/// <summary>
/// 船名
/// </summary>
public string Vessel { get; set; }
/// <summary>
/// 航次
/// </summary>
public string Voyage { get; set; }
/// <summary>
/// 船公司
/// </summary>
public string ShippingCompany { get; set; }
/// <summary>
/// 收货地
/// </summary>
public string PlaceOfReceipt { get; set; }
/// <summary>
/// 装货港
/// </summary>
public string LoadingPort { get; set; }
/// <summary>
/// 截关时间
/// </summary>
public string ClosingDate { get; set; }
/// <summary>
/// 截VGM时间
/// </summary>
public string VGMCutOffTime { get; set; }
/// <summary>
/// ETA
/// </summary>
public string ETA { get; set; }
/// <summary>
/// ETD
/// </summary>
public string ETD { get; set; }
/// <summary>
/// 卸货港
/// </summary>
public string DischargingPort { get; set; }
/// <summary>
/// 交货地
/// </summary>
public string DeliveryPlace { get; set; }
/// <summary>
/// 目的港ETA
/// </summary>
public string PortOfDestinationETA { get; set; }
/// <summary>
/// 装运方式
/// </summary>
public string ShippingWay { get; set; }
/// <summary>
/// 运输条款
/// </summary>
public string ShippingTerms { get; set; }
/// <summary>
/// 港前运输形态
/// </summary>
public string PreportTransportationMode { get; set; }
/// <summary>
/// 品名
/// </summary>
public string OfTheGoods { get; set; }
/// <summary>
/// 签单地点
/// </summary>
public string SignTheBillLocation { get; set; }
/// <summary>
/// 集港码头
/// </summary>
public string CollectionTerminal { get; set; }
/// <summary>
/// 约号
/// </summary>
public string AboutNo { get; set; }
/// <summary>
/// 预付地点
/// </summary>
public string PlaceInAdvance { get; set; }
/// <summary>
/// 船代
/// </summary>
public string ShipAgency { get; set; }
/// <summary>
/// 货代
/// </summary>
public string FreightForwarder { get; set; }
/// <summary>
/// 场站
/// </summary>
public string Station { get; set; }
/// <summary>
/// 场站联系人
/// </summary>
public string StationContact { get; set; }
/// <summary>
/// 场站联系电话
/// </summary>
public string StationContactNumber { get; set; }
/// <summary>
/// 截单时间
/// </summary>
public string CutSingleTime { get; set; }
/// <summary>
/// 一代客服姓名
/// </summary>
public string FirstCustomerServiceName { get; set; }
/// <summary>
/// 一代客服电话
/// </summary>
public string FirstCustomerServiceNumber { get; set; }
/// <summary>
/// 一代客服邮箱
/// </summary>
public string FirstCustomerServiceEmail { get; set; }
/// <summary>
/// 订舱单位
/// </summary>
public string CYCutOffTime { get; set; }
/// <summary>
/// 备注
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 箱信息
/// </summary>
public List<ContainersItemRes> Containers { get; set; }
}
}

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DS.WMS.Core.Op.Dtos.BookingAI
{
public class SeaExportAIRes : SeaExportRes
{
}
}

@ -297,7 +297,7 @@ public class SeaExportRes
public string ReceiptPlace { get; set; }
/// <summary>
/// 装货港Id
/// 收货地Id
/// </summary>
public long ReceiptPlaceId { get; set; }

@ -0,0 +1,21 @@
using DS.Module.Core;
using DS.WMS.Core.Op.Dtos.BookingAI;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DS.WMS.Core.Op.Interface
{
public interface ISeaExportAIService
{
/// <summary>
/// 获取AI文件解析内容
/// </summary>
/// <param name="file"></param>
/// <returns></returns>
public Task<DataResult<SeaExportAIRes>> GetBookingAIResultAsync(IFormFile file);
}
}

@ -0,0 +1,430 @@
using DS.Module.Core;
using DS.Module.Core.Extensions;
using DS.Module.SqlSugar;
using DS.Module.UserModule;
using DS.WMS.Core.Code.Entity;
using DS.WMS.Core.Info.Entity;
using DS.WMS.Core.Invoice.Dtos;
using DS.WMS.Core.Op.Dtos;
using DS.WMS.Core.Op.Dtos.BookingAI;
using DS.WMS.Core.Op.Interface;
using DS.WMS.Core.Sys.Entity;
using LanguageExt.Pipes;
using MathNet.Numerics;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using NPOI.OpenXmlFormats.Dml.Diagram;
using SqlSugar;
namespace DS.WMS.Core.Op.Method
{
public class SeaExportAIService: ISeaExportAIService
{
private readonly IServiceProvider _serviceProvider;
private readonly ISqlSugarClient db;
private readonly IUser user;
private readonly ISaasDbService saasService;
/// <summary>
///
/// </summary>
/// <param name="serviceProvider"></param>
public SeaExportAIService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
db = _serviceProvider.GetRequiredService<ISqlSugarClient>();
user = _serviceProvider.GetRequiredService<IUser>();
saasService = _serviceProvider.GetRequiredService<ISaasDbService>();
}
public async Task<DataResult<SeaExportAIRes>> GetBookingAIResultAsync(IFormFile file)
{
var tenantDb = saasService.GetBizDbScopeById(user.TenantId);
//未上传文件
if (file == null || file.Length == 0)
{
return await Task.FromResult(DataResult<SeaExportAIRes>.Failed("上传文件不存在!"));
}
var config = await db.Queryable<SysConfig>().Filter(null, true).Where(x => x.Code == "booking_ai_api_url" && x.Status == StatusEnum.Enable).FirstAsync();
if (config.IsNull())
{
return await Task.FromResult(DataResult<SeaExportAIRes>.Failed("booking_ai_api_url接口地址未配置!"));
}
var url = config.Value;
var originalFilename = file.FileName; // 文件原始名称
var ms = new MemoryStream();
await file.CopyToAsync(ms);
//使用HttpClient方式上传文件
ms.Position = 0;
var formData = new MultipartFormDataContent();
formData.Add(new StreamContent(ms, (int)ms.Length), "file", originalFilename);
formData.Add(new StringContent("QWEN"), "platform");
var _httpclient = new HttpClient();
var response = await _httpclient.PostAsync(url, formData);
if (response.IsSuccessStatusCode)
{
var strRtn = response.Content.ReadAsStringAsync().Result;
var res = JsonConvert.DeserializeObject<ParseItemRes>(strRtn);
if (res.Code == 200)
{
Console.WriteLine(res.Data);
var result = await DealAIData(res,tenantDb);
//return await Task.FromResult(DataResult<SeaExportAIRes>.Success(newFile.FileName));
return await Task.FromResult(DataResult<SeaExportAIRes>.Success(result));
}
else
{
return await Task.FromResult(DataResult<SeaExportAIRes>.Failed(res.Msg));
}
}
else
{
return await Task.FromResult(DataResult<SeaExportAIRes>.Failed("请求AI文件解析接口错误请联系管理员!"));
}
}
public async Task<SeaExportAIRes> DealAIData(ParseItemRes req,SqlSugarScopeProvider tenantDb) {
var aiInfo = req.Data[0];
var info = new SeaExportAIRes() {
Id = 0,
ParentId = 0,
BusinessStatus = "Uncommitted",
BusinessStatusName = "未提交",
CustomerNo = "",
MBLNO = aiInfo.BLNo,
BookingNo = aiInfo.ReferenceNo,
Voyno = aiInfo.Voyage,
ClosingDate = String.IsNullOrEmpty(aiInfo.ClosingDate)? null : DateTime.Parse(aiInfo.ClosingDate),
VGMCloseDate = String.IsNullOrEmpty(aiInfo.VGMCutOffTime) ? null : DateTime.Parse(aiInfo.VGMCutOffTime),
ETA = String.IsNullOrEmpty(aiInfo.ETA) ? null : DateTime.Parse(aiInfo.ETA),
ETD = String.IsNullOrEmpty(aiInfo.ETD) ? null : DateTime.Parse(aiInfo.ETD),
CloseDocDate = String.IsNullOrEmpty(aiInfo.CutSingleTime) ? null : DateTime.Parse(aiInfo.CutSingleTime),
Remark = aiInfo.Remark,
Service = aiInfo.ShippingTerms,
ServiceContractNo =aiInfo.AboutNo,
YardATTN = aiInfo.StationContact,
YardTel = aiInfo.StationContactNumber,
//PortOfDestinationETA ShippingWay PreportTransportationMode CollectionTerminal CYCutOffTime
};
//委托单位
if (!String.IsNullOrEmpty(aiInfo.BookingParty))
{
var client = await tenantDb.Queryable<InfoClient>().Where(a => a.Description.Contains(aiInfo.BookingParty) && SqlFunc.Subqueryable<InfoClientAttribute>().Where(
b => b.ClientId == a.Id && b.Value == "isController").Any()).FirstAsync();
if (client.IsNotNull())
{
info.CustomerId = client.Id;
info.CustomerName = client.ShortName;
}
else
{
info.CustomerName = aiInfo.BookingParty;
}
}
//发货人
if (!String.IsNullOrEmpty(aiInfo.Shipper))
{
var client = await tenantDb.Queryable<InfoClient>().Where(a => a.Description.Contains(aiInfo.Shipper) && SqlFunc.Subqueryable<InfoClientAttribute>().Where(
b => b.ClientId == a.Id && b.Value == "isShipper").Any()).FirstAsync();
if (client.IsNotNull())
{
info.ShipperId = client.Id;
info.Shipper = client.ShortName;
}
else
{
info.Shipper = aiInfo.Shipper;
}
}
//收货人
if (!String.IsNullOrEmpty(aiInfo.Consigner))
{
var client = await tenantDb.Queryable<InfoClient>().Where(a => a.Description.Contains(aiInfo.Consigner) && SqlFunc.Subqueryable<InfoClientAttribute>().Where(
b => b.ClientId == a.Id && b.Value == "isConsigner").Any()).FirstAsync();
if (client.IsNotNull())
{
info.ConsigneeId = client.Id;
info.Consignee = client.ShortName;
}
else
{
info.Consignee = aiInfo.Consigner;
}
}
//通知人
if (!String.IsNullOrEmpty(aiInfo.NotifyParty))
{
var client = await tenantDb.Queryable<InfoClient>().Where(a => a.Description.Contains(aiInfo.NotifyParty) && SqlFunc.Subqueryable<InfoClientAttribute>().Where(
b => b.ClientId == a.Id && b.Value == "isNotifyParty").Any()).FirstAsync();
if (client.IsNotNull())
{
info.NotifyPartyId = client.Id;
info.NotifyParty = client.ShortName;
}
else
{
info.NotifyParty = aiInfo.NotifyParty;
}
}
//船名
if (!String.IsNullOrEmpty(aiInfo.Vessel))
{
var vessel = await tenantDb.Queryable<CodeVessel>().Where(a => a.VesselName.Contains(aiInfo.Vessel)).FirstAsync();
if (vessel.IsNotNull())
{
info.VesselId = vessel.Id;
info.Vessel = vessel.VesselName;
}
else
{
info.Vessel = aiInfo.Vessel;
}
}
//船公司
if (!String.IsNullOrEmpty(aiInfo.ShippingCompany))
{
var client = await tenantDb.Queryable<CodeCarrier>().Where(a => a.EnName.Contains(aiInfo.ShippingCompany) ).FirstAsync();
if (client.IsNotNull())
{
info.CarrierId = client.Id;
info.Carrier = client.EdiCode;
}
else
{
info.Carrier = aiInfo.ShippingCompany;
}
}
//收货地
if (!String.IsNullOrEmpty(aiInfo.PlaceOfReceipt))
{
var port = await tenantDb.Queryable<CodePort>().Where(a => a.PortName.Contains(aiInfo.PlaceOfReceipt)).FirstAsync();
if (port.IsNotNull())
{
info.ReceiptPlaceId = port.Id;
info.ReceiptPlace = port.PortName;
info.ReceiptPlaceCode = port.EdiCode;
}
else
{
info.ReceiptPlace = aiInfo.PlaceOfReceipt;
}
}
//装货港
if (!String.IsNullOrEmpty(aiInfo.LoadingPort))
{
var port = await tenantDb.Queryable<CodePort>().Where(a => a.PortName.Contains(aiInfo.LoadingPort)).FirstAsync();
if (port.IsNotNull())
{
info.LoadPortId = port.Id;
info.LoadPort = port.PortName;
info.LoadPortCode = port.EdiCode;
}
else
{
info.LoadPort = aiInfo.LoadingPort;
}
}
//卸货港
if (!String.IsNullOrEmpty(aiInfo.DischargingPort))
{
var port = await tenantDb.Queryable<CodePort>().Where(a => a.PortName.Contains(aiInfo.DischargingPort)).FirstAsync();
if (port.IsNotNull())
{
info.DischargePortId = port.Id;
info.DischargePort = port.PortName;
info.DischargePortCode = port.EdiCode;
}
else
{
info.DischargePort = aiInfo.DischargingPort;
}
}
//交货地
if (!String.IsNullOrEmpty(aiInfo.DeliveryPlace))
{
var port = await tenantDb.Queryable<CodePort>().Where(a => a.PortName.Contains(aiInfo.DeliveryPlace)).FirstAsync();
if (port.IsNotNull())
{
info.DeliveryPlaceId = port.Id;
info.DeliveryPlace = port.PortName;
info.DeliveryPlaceCode = port.EdiCode;
}
else
{
info.DeliveryPlace = aiInfo.DeliveryPlace;
}
}
//品名
if (!String.IsNullOrEmpty(aiInfo.OfTheGoods))
{
var good = await tenantDb.Queryable<CodeGoods>().Where(a => a.GoodName.Contains(aiInfo.OfTheGoods)).FirstAsync();
if (good.IsNotNull())
{
info.GoodsId = good.Id;
info.GoodsName = good.GoodName;
info.HSCode = good.HSCode;
}
else
{
info.GoodsName = aiInfo.OfTheGoods;
}
}
//签单地
if (!String.IsNullOrEmpty(aiInfo.SignTheBillLocation))
{
var port = await tenantDb.Queryable<CodePort>().Where(a => a.PortName.Contains(aiInfo.SignTheBillLocation)).FirstAsync();
if (port.IsNotNull())
{
info.IssuePlaceId = port.Id;
info.IssuePlace = port.PortName;
info.IssuePlaceCode = port.EdiCode;
}
else
{
info.IssuePlace = aiInfo.SignTheBillLocation;
}
}
//预付地
if (!String.IsNullOrEmpty(aiInfo.PlaceInAdvance))
{
var port = await tenantDb.Queryable<CodePort>().Where(a => a.PortName.Contains(aiInfo.PlaceInAdvance)).FirstAsync();
if (port.IsNotNull())
{
info.PayableAtId = port.Id;
info.PayableAt = port.PortName;
info.PayableAtCode = port.EdiCode;
}
else
{
info.PayableAt = aiInfo.PlaceInAdvance;
}
}
//船代
if (!String.IsNullOrEmpty(aiInfo.ShipAgency))
{
var client = await tenantDb.Queryable<InfoClient>().Where(a => a.Description.Contains(aiInfo.ShipAgency) && SqlFunc.Subqueryable<InfoClientAttribute>().Where(
b => b.ClientId == a.Id && b.Value == "isShipAgency").Any()).FirstAsync();
if (client.IsNotNull())
{
info.ShipAgencyId = client.Id;
info.ShipAgency = client.ShortName;
}
else
{
info.ShipAgency = aiInfo.ShipAgency;
}
}
//货代
if (!String.IsNullOrEmpty(aiInfo.FreightForwarder))
{
var client = await tenantDb.Queryable<InfoClient>().Where(a => a.Description.Contains(aiInfo.ShipAgency) && SqlFunc.Subqueryable<InfoClientAttribute>().Where(
b => b.ClientId == a.Id && b.Value == "isBooking").Any()).FirstAsync();
if (client.IsNotNull())
{
info.ForwarderId = client.Id;
info.Forwarder = client.ShortName;
}
else
{
info.Forwarder = aiInfo.FreightForwarder;
}
}
//场站
if (!String.IsNullOrEmpty(aiInfo.Station))
{
var client = await tenantDb.Queryable<InfoClient>().Where(a => a.Description.Contains(aiInfo.Station) && SqlFunc.Subqueryable<InfoClientAttribute>().Where(
b => b.ClientId == a.Id && b.Value == "isYard").Any()).FirstAsync();
if (client.IsNotNull())
{
info.YardId = client.Id;
info.Yard = client.ShortName;
}
else
{
info.Yard = aiInfo.Station;
}
}
//客服
if (!String.IsNullOrEmpty(aiInfo.FirstCustomerServiceName))
{
var service = await db.Queryable<SysUser>().Where(a => a.UserEnName.Contains(aiInfo.FirstCustomerServiceName) ).FirstAsync();
if (service.IsNotNull())
{
info.CustomerService = service.Id;
info.CustomerServiceName = service.UserEnName;
}
else
{
info.CustomerServiceName = aiInfo.FirstCustomerServiceName;
}
}
//集装箱信息
if (aiInfo.Containers.IsNotNull() && aiInfo.Containers.Count>0)
{
var ctnList = new List<OpCtnRes>();
var ctns = await tenantDb.Queryable<CodeCtn>().ToListAsync();
foreach (var item in aiInfo.Containers)
{
var ctnInfo = ctns.FirstOrDefault(x => x.CtnName == item.BoxPile.Replace("'", ""));
if (ctnInfo.IsNotNull()) {
ctnList.Add(new OpCtnRes()
{
Id = 0,
BSNO ="",
CtnId = ctnInfo.Id,
CtnCode = ctnInfo.EdiCode,
Ctn = ctnInfo.CtnName,
CtnNum = int.Parse(item.CartonQuantity),
Size = item.Size,
KGS = !String.IsNullOrEmpty(item.GrossWeight) ? decimal.Parse(item.GrossWeight.Replace(" KGM", "")) :0,
TareWeight = !String.IsNullOrEmpty(item.TareWeight) ? decimal.Parse(item.TareWeight.Replace(" KGM", "")) : 0,
});
}
else
{
ctnList.Add(new OpCtnRes()
{
Id = 0,
BSNO = "",
Ctn = item.BoxPile.Replace("'", ""),
CtnNum = int.Parse(item.CartonQuantity),
Size = item.Size,
KGS = !String.IsNullOrEmpty(item.GrossWeight) ? decimal.Parse(item.GrossWeight.Replace(" KGM", "")) : 0,
TareWeight = !String.IsNullOrEmpty(item.TareWeight) ? decimal.Parse(item.TareWeight.Replace(" KGM", "")) : 0,
});
}
}
info.CtnInfo = ctnList;
}
return info;
}
}
}

@ -0,0 +1,38 @@
using DS.Module.Core;
using DS.WMS.Core.Op.Dtos;
using DS.WMS.Core.Op.Dtos.BookingAI;
using DS.WMS.Core.Op.Interface;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace DS.WMS.OpApi.Controllers
{
/// <summary>
/// AI文件解析-服务
/// </summary>
public class SeaExportAIController : ApiController
{
private readonly ISeaExportAIService _invokeService;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="invokeService"></param>
public SeaExportAIController(ISeaExportAIService invokeService)
{
_invokeService = invokeService;
}
/// <summary>
/// 获取AI文件解析内容
/// </summary>
/// <param name="file">文件信息</param>
/// <returns></returns>
[HttpPost]
[Route("GetBookingAIResult")]
public async Task<DataResult<SeaExportAIRes>> GetBookingAIResultAsync(IFormFile file)
{
return await _invokeService.GetBookingAIResultAsync(file);
}
}
}
Loading…
Cancel
Save