zhangxiaofeng 7 months ago
commit ecd062b1a3

@ -501,7 +501,11 @@ namespace Myshipping.Application.EDI
if (string.IsNullOrEmpty(headData.NOTIFYPARTY))
{
error = error + "<br />提单号:" + headData.MBLNO + " 通知人不能为空";
//CMA 订舱时可以不填通知人
if (headData.CARRIEREDICODE != "CMDU")
{
error = error + "<br />提单号:" + headData.MBLNO + " 通知人不能为空";
}
}
else
{

@ -158,7 +158,7 @@ namespace Myshipping.Application.EDI
sailSchedulePriority = template.Priority.Split(',').ToList(),
outboundHaulage = mapServArr[0],
inboundHaulage = mapServArr[1],
searchConditionDate = DateTime.Today.AddDays(startDay).ToString("yyyy-MM-dd"),
searchConditionDate = custOrder.ETD.Value.AddDays(startDay).ToString("yyyy-MM-dd"),
numberOfWeeks = endWeek,
etd = custOrder.ETD.Value.ToString("yyyy-MM-dd"),
};

@ -3,6 +3,7 @@ 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;
@ -28,8 +29,10 @@ 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.Threading.Tasks;
using Yitter.IdGenerator;
@ -63,6 +66,8 @@ namespace Myshipping.Application
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,
@ -71,7 +76,8 @@ namespace Myshipping.Application
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<DjyCustomer> repCustomer, SqlSugarRepository<DjyCustomerParamValue> repCustomerParamValue, SqlSugarRepository<DjyCustomerContact> repCustomerContact,
SqlSugarRepository<BookingFeeRecord> repFeeRecord)
{
this._logger = logger;
this._rep = rep;
@ -92,6 +98,8 @@ namespace Myshipping.Application
this.bookingOrderService = bookingOrderService;
this._repCustomer = repCustomer;
this._repCustomerParamValue = repCustomerParamValue;
this._repCustomerContact = repCustomerContact;
this._repFeeRecord = repFeeRecord;
}
#region 订舱草稿及附件
@ -1839,6 +1847,9 @@ namespace Myshipping.Application
}
//扣费
await FeeSo(model.Id);
}
@ -1969,6 +1980,15 @@ namespace Myshipping.Application
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 私有方法
@ -2007,6 +2027,126 @@ namespace Myshipping.Application
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);
}
else
{
var errMsg = jobjApiRtn.GetValue("message").ToString();
_logger.LogError($"扣费失败:{errMsg}");
SaveAuditLog($"扣费失败", model.Id, model.CreatedUserId.Value, model.TenantId.Value, "系统", remark: errMsg);
}
}
#endregion
#region 外部开放接口

@ -339,6 +339,11 @@ namespace Myshipping.Application
/// </summary>
public string currentNodeCd { get; set; }
/// <summary>
/// 箱型名称
/// </summary>
public string sizeName { get; set; }
/// <summary>
/// 集装箱状态信息
/// </summary>

@ -91,10 +91,11 @@ namespace Myshipping.Application
.Where(t => t.TypeCode.Equals("after_port_trace_ctn_status", StringComparison.OrdinalIgnoreCase)).ToList();
//按顺序取状态配置字典
Dictionary<string, Tuple<string, int>> statusEnumDict = statusDict.Select(a => new { Key = a.Code, Val = new Tuple<string, int>(a.Value, a.Sort), Sort = a.Sort })
Dictionary<string, Tuple<string, string, int>> statusEnumDict = statusDict.Select(a => new { Key = a.Code, Val = new Tuple<string, string,int>(a.Value,a.Remark, a.Sort), Sort = a.Sort })
.OrderBy(a => a.Sort).ToDictionary(a => a.Key, b => b.Val);
string[] skipStatus = new string[] { "GIOI", "LOFV", "FVD", "FVA", "DFFV" };
string[] skipStatus = new string[] { "GIOI", "LOFV", "FVD", "FVA", "DFFV", "LOR", "DFR", "RA", "DIFR", "LOT", "DIFT", "ADI", "DIDI", "CGRL", "RFP","ETD","ETA", "LDI", "CDPOD", "BPOD" };
string[] transferStatus = new string[] { "AIP", "BIP", "ETDIP", "DIIP", "GOIP", "GIIP", "LIP", "EDIP", "DEIP", "EAIP" };
if (queryRlt.code == 200)
{
@ -104,13 +105,25 @@ namespace Myshipping.Application
if (result != null && result.resultData != null)
{
//这里需要翻译一下箱型
var ctnCodeMappingList = _cache.GetAllMappingCtn().GetAwaiter().GetResult().ToList();
Dictionary<string, int> referToCtnDict = new Dictionary<string, int>();
bool isTransfer = false;
if (result.resultData.containerInfoList != null && result.resultData.containerInfoList.Count > 0)
{
result.resultData.containerInfoList.ForEach(s =>
{
if(s.containerStatusInfoList != null && s.containerStatusInfoList.Count > 0)
var ctnMapping = ctnCodeMappingList.FirstOrDefault(t => t.MapCode.Equals(s.size));
if(ctnMapping != null)
{
s.sizeName = ctnMapping.MapName?.Trim();
}
if (s.containerStatusInfoList != null && s.containerStatusInfoList.Count > 0)
{
referToCtnDict.Add(s.containerNo, s.containerStatusInfoList.Count);
@ -126,7 +139,7 @@ namespace Myshipping.Application
{
a.statusCnName = a.statusCd;
}
return a;
}).ToList();
}
@ -134,6 +147,12 @@ namespace Myshipping.Application
});
}
//legType = "T" 标识当票有中转
if (result.resultData.routingInfoList.Any(t => t.legType.Equals("T", StringComparison.OrdinalIgnoreCase)))
{
isTransfer = true;
}
result.embedTraceFlowStatusList = new List<EmbedTraceFlowStatusInfo>();
var ctnNo = referToCtnDict.OrderByDescending(a => a.Value).FirstOrDefault().Key;
@ -177,24 +196,33 @@ namespace Myshipping.Application
return currStatus;
}).ToList();
foreach (KeyValuePair<string, Tuple<string, int>> kvp in statusEnumDict)
foreach (KeyValuePair<string, Tuple<string,string, int>> kvp in statusEnumDict)
{
if(!skipStatus.Contains(kvp.Key))
{
var currStatus = takeList.FirstOrDefault(p => p.statusCd.Equals(kvp.Key, StringComparison.OrdinalIgnoreCase));
if(currStatus == null)
//不是中转的需要把状态节点去掉
if (isTransfer || (!isTransfer && !transferStatus.Contains(kvp.Key)))
{
currStatus = new EmbedTraceFlowStatusInfo
var currStatus = takeList.FirstOrDefault(p => p.statusCd.Equals(kvp.Key, StringComparison.OrdinalIgnoreCase));
if (currStatus == null)
{
statusCd = kvp.Key,
statusCnName = kvp.Value.Item1,
sortNo = kvp.Value.Item2,
statusCtnStatic = $"0/{referToCtnDict.Count}",
};
}
currStatus = new EmbedTraceFlowStatusInfo
{
statusCd = kvp.Key,
statusCnName = !string.IsNullOrWhiteSpace(kvp.Value.Item2)? kvp.Value.Item2 : kvp.Value.Item1,
sortNo = kvp.Value.Item3,
statusCtnStatic = $"0/{referToCtnDict.Count}",
};
}
else
{
if (!string.IsNullOrWhiteSpace(kvp.Value.Item2))
currStatus.statusCnName = kvp.Value.Item2;
}
result.embedTraceFlowStatusList.Add(currStatus);
result.embedTraceFlowStatusList.Add(currStatus);
}
}
}
}

@ -300,40 +300,13 @@ namespace Myshipping.Application
}
if (withDispatchList.Any(a =>
!a.Detail.NOM_STATUS_NOTE.Equals("Load", StringComparison.OrdinalIgnoreCase)))
a.Detail.NOM_STATUS_NOTE.Equals("Load", StringComparison.OrdinalIgnoreCase)))
{
model.PreBillList.AddRange(withDispatchList.Where(a =>
!a.Detail.NOM_STATUS_NOTE.Equals("Load", StringComparison.OrdinalIgnoreCase))
model.LoadDetailList.AddRange(withDispatchList.Where(a =>
a.Detail.NOM_STATUS_NOTE.Equals("Load", StringComparison.OrdinalIgnoreCase))
.Select((a, idx) =>
{
TaskRollingNominationShipPreBillShowDto preBillInfo = new TaskRollingNominationShipPreBillShowDto
{
Bookedby = a.Detail.BOOKED_BY,
ConfirmDate = a.Dispatch?.CONFIRM_DATE,
ConfirmDeadLine = a.Dispatch?.CONFIRM_DEAD_LINE,
CtnStat = $"{a.Detail.CTNALL}*{a.Detail.CTNNUM}",
CustomerId = a.Detail.CUSTOMERID,
CustomerName = a.Detail.CUSTOMERNAME,
ContractualName = a.Detail.CONTRACTUAL_NAME,
CreateShareLinkDate = a.Dispatch?.CREATE_SHARE_LINK_DATE,
DischargePortName = a.Detail.DISCHARGEPORT_NAME,
IsSend = a.Dispatch != null ? a.Dispatch.IS_SEND : false,
IsUserManual = a.Dispatch != null ? a.Dispatch.IS_USER_MANUAL : false,
LoadPortName = a.Detail.LOADPORT_NAME,
PlaceOfDelivery = a.Detail.PLACEOF_DELIVERY,
PlaceOfReceipt = a.Detail.PLACEOF_RECEIPT,
Shipment = a.Detail.SHIPMENT,
Status = a.Dispatch?.STATUS,
ShareLinkKey = a.Dispatch?.SHARE_LINK_KEY,
UserOpinion = a.Dispatch?.USER_OPINION,
UserOpinionTxt = a.Dispatch?.USER_OPINION_TXT,
BatchId = a.Dispatch?.BATCH_ID,
BookingId = a.Detail.BOOKING_ID,
GroupName = a.Detail.CUSTOMERID.HasValue ? $"CUST_{idx + 1}" : "",
CtnNote = !string.IsNullOrWhiteSpace(a.Detail.CTNNOTE) ? a.Detail.CTNNOTE : ""
};
return preBillInfo;
return a.Detail.Adapt<TaskRollingNominationShipDetailShowDto>();
}).ToList());
}

@ -56,8 +56,8 @@
</tr>
<tr class="email-noreply">
<td>
<p class="notice1-val">请您按照更新的ETD在免箱期内用箱以免产生超期箱使费谢谢</p>
<p class="notice2-val">请不要回复此邮箱(自动发送邮箱无人处理邮件),如有疑问,请联系#opname#(邮箱#opemail#,电话#optel#),谢谢!</p>
<p class="notice1-val"><font style="color: #f70f0f; font-weight: 500;">请您按照更新的ETD在免箱期内用箱以免产生超期箱使费谢谢</font></p>
<p class="notice2-val"><font style="color: #4051f0; font-weight: 500;">请不要回复此邮箱(自动发送邮箱无人处理邮件),如有疑问,</font><font style="background-color: #f1de2f; font-weight: 500;">请联系#opname#(邮箱#opemail#,电话#optel#),谢谢!</font></p>
<p class="notice3-val">货物到港后,贵司保证目的港收货人及时提取货物。因货物提取不及时/弃货产生的滞箱费、堆存费、港口费、货物处理费等概由贵司或者目的港收货人承担。如果我司对外承担了上述费用,则贵司应当无条件支付给我司,如果因此给我司造成了经济损失,则贵司还应当赔偿我司所有经济损失,包括但不限于律师费、诉讼费等等。一旦此票提箱出运就视为同意此条款,谢谢配合!</p>
<p class="notice-comp-val"></p>
</td>

@ -49,8 +49,8 @@
<tr class="email-noreply">
<td>
<p class="dynamic-val"></p>
<p class="notice1-val">请您按照更新的ETD在免箱期内用箱以免产生超期箱使费谢谢</p>
<p class="notice2-val">请不要回复此邮箱(自动发送邮箱无人处理邮件),如有疑问,请联系#opname#(邮箱#opemail#,电话#optel#),谢谢!</p>
<p class="notice1-val"><font style="color: #f70f0f; font-weight: 500;">请您按照更新的ETD在免箱期内用箱以免产生超期箱使费谢谢</font></p>
<p class="notice2-val"><font style="color: #4051f0; font-weight: 500;">请不要回复此邮箱(自动发送邮箱无人处理邮件),如有疑问,</font><font style="background-color: #f1de2f; font-weight: 500;">请联系#opname#(邮箱#opemail#,电话#optel#),谢谢!</font></p>
<p class="notice3-val">货物到港后,贵司保证目的港收货人及时提取货物。因货物提取不及时/弃货产生的滞箱费、堆存费、港口费、货物处理费等概由贵司或者目的港收货人承担。如果我司对外承担了上述费用,则贵司应当无条件支付给我司,如果因此给我司造成了经济损失,则贵司还应当赔偿我司所有经济损失,包括但不限于律师费、诉讼费等等。一旦此票提箱出运就视为同意此条款,谢谢配合!</p>
<p class="notice-comp-val"></p>
</td>

Loading…
Cancel
Save