You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
BookingHeChuan/Myshipping.Application/Service/BookingCustomerOrder/BookingCustomerOrderService.cs

1995 lines
83 KiB
C#

This file contains ambiguous Unicode characters!

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

using Furion;
using Furion.DependencyInjection;
using Furion.DynamicApiController;
using Furion.EventBus;
using Furion.FriendlyException;
using Furion.RemoteRequest.Extensions;
using Mapster;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Myshipping.Application.ConfigOption;
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 RabbitMQ.Client;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
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;
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)
{
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;
}
#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($"提交失败:{item.GetBooleanValue("message")}", id);
}
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($"取消提交失败:{item.GetBooleanValue("message")}", id);
}
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},审核意见:{recModel.Comment}", id, model.CreatedUserId.Value, model.TenantId.Value, "系统");
long bookingId = 0;
//进入客户订舱系统的订舱台账
if (recModel.Accept)
{
var bkOrder = model.Adapt<BookingOrder>();
bkOrder.Id = YitIdHelper.NextId();
bkOrder.BSSTATUS = "已录入";
bkOrder.ParentId = 0;
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}】,数据内容:【{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
{
"ALL" => BookingOrderSyncTypeEnum.ALL,
"BC" => BookingOrderSyncTypeEnum.BC,
_ => BookingOrderSyncTypeEnum.ALL,
};
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;
}
#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>();
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);
}
//箱信息
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);
}
return rtnList;
}
/// <summary>
/// 审核订舱请求
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/AuditBooking")]
public async Task AuditBooking(long id, bool accept, string comment)
{
var model = _rep.FirstOrDefault(x => x.Id == id);
if (model == null)
{
throw Oops.Bah("未找到业务信息");
}
if (model.BSSTATUS != "已接收")
{
throw Oops.Bah("当前状态不能审核");
}
if (accept)
{
model.BSSTATUS = "已审核";
}
else
{
model.BSSTATUS = "已驳回";
}
//回推回执
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}");
var jobjRtn = JObject.Parse(rtn);
if (jobjRtn.GetIntValue("code") != 200)
{
throw Oops.Bah(jobjRtn.GetStringValue("message"));
}
await _rep.UpdateAsync(model); //回推成功后,存库
//日志动态
SaveAuditLog($"{(accept ? "" : "")},审核意见:{comment}", id);
//进入订舱台账
if (accept)
{
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;
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);
}
}
}
/// <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"));
}
#endregion
#region 私有方法
/// <summary>
/// 保存审核的日志动态(使用当前登录人信息)
/// </summary>
private void SaveAuditLog(string status, long bookId)
{
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;
_repStatuslog.Insert(staLog);
}
/// <summary>
/// 保存审核的日志动态
/// </summary>
private void SaveAuditLog(string status, long bookId, long userId, long tenantId, string userName)
{
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;
_repStatuslog.Insert(staLog);
}
#endregion
#region 外部开放接口
/// <summary>
/// 接收外部调用生成客户订舱需求
/// </summary>
/// <returns></returns>
[HttpPost("/BookingCustomerOrder/ReceiveCustomerOrder"), AllowAnonymous, ApiUser]
public async Task ReceiveCustomerOrder([FromForm] BookingCustomerApiSaveInput input, IFormFile[] files)
{
#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("订舱密码不能为空");
//}
if (string.IsNullOrEmpty(input.CARRIERID) || string.IsNullOrEmpty(input.CARRIER))
{
throw Oops.Bah("船司代码和名称不能为空");
}
if (!input.ETD.HasValue)
{
throw Oops.Bah("开船日期不能为空");
}
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.SERVICE))
{
throw Oops.Bah("运输条款不能为空");
}
if (string.IsNullOrEmpty(input.BLFRT))
{
throw Oops.Bah("付费方式不能为空");
}
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("箱型箱量不能为空");
}
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;
}
//订舱账号、密码
var jobj = new JObject();
if (!string.IsNullOrEmpty(custOrder.ExtendData))
{
jobj = JObject.Parse(custOrder.ExtendData);
}
var jobjBookAcc=new JObject();
jobjBookAcc["Account"] = input.BOOKINGACCOUNT;
jobjBookAcc["Password"] = input.BOOKINGPASSWORD;
jobj["BookingAccount"] = jobjBookAcc;
custOrder.ExtendData = jobjBookAcc.ToJsonString();
var ctns = input.CtnList.Adapt<List<BookingCtn>>();
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
}
}