647556386
3 天以前 bfa52edd6a430978873367426da7b379730da411
PLS接口优化
已添加6个文件
已修改19个文件
795 ■■■■■ 文件已修改
项目代码/WMS/WMSServices/WIDESEA_BasicService/Service/MaterielInfoService.cs 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_BasicService/WIDESEA_BasicService.csproj 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_Common/APIEnum/APIEnum.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_Core/AOP/SqlSugarAop.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_DTO/MLS/MLSRequestContent.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_DTO/MLS/ReceiveMLSToken.cs 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_DTO/PLS/MoInboundOrderDTO.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_DTO/PLS/PLSBaseModel.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_DTO/PLS/PLSRequestContent.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_DTO/PLS/PlsResponseContent.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_DTO/PLS/ReturnMoInboundStatuModel.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_DTO/PLS/VMIItemCodeInfo.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_External/IMLSService/IInvokeMLSService.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_External/PLSService/InvokeMLSService.cs 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_External/PLSService/InvokePLSService.cs 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_External/PLSService/MD5Util.cs 462 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_External/WIDESEA_External.csproj 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_IBasicService/IMaterielInfoService.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_IInboundService/IMoInboundOrderService.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_InboundService/MoInboundOrderService.cs 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_Model/Models/Basic/Dt_ApiInfo.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_Model/Models/Inbound/Dt_MoInboundOrder.cs 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_WMSServer/Controllers/Inbound/MoInboundOrderController.cs 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_WMSServer/Controllers/PLS/PlsController.cs 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
项目代码/WMS/WMSServices/WIDESEA_WMSServer/appsettings.json 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_BasicService/Service/MaterielInfoService.cs
@@ -1,17 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_BasicRepository;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Common.MaterielEnum;
using WIDESEA_Common.CommonEnum;
using WIDESEA_Core;
using WIDESEA_Core.BaseServices;
using WIDESEA_Core.Helper;
using WIDESEA_DTO.Basic;
using WIDESEA_DTO;
using WIDESEA_DTO.ERP;
using WIDESEA_DTO.PLS;
using WIDESEA_External.PLSService;
using WIDESEA_IBasicRepository;
using WIDESEA_IBasicService;
using WIDESEA_Model.Models;
@@ -181,9 +175,16 @@
                    return WebResponseContent.Instance.Error("接口传入的物料数据集合不能为空");
                }
                ///签名校验
                bool IsSign = MD5Util.CheckPLSSign(vmiModel);
                if (!IsSign)
                {
                    return WebResponseContent.Instance.Error("签名验证失败,请检查");
                }
                foreach (var itemData in vmiModel.Data)
                {
                    var existMateriel = BaseDal.QueryFirst(x => x.MaterielCode == itemData.ItemCode);
                    var existMateriel = BaseDal.QueryFirst(x => x.MaterielCode == itemData.ItemCode && x.OrgId == itemData.OrgId && x.MaterielInvOrgId == itemData.SupplierCode);
                    if (existMateriel == null)
                    {
@@ -193,22 +194,20 @@
                            OrgId = itemData.OrgId,
                            MaterielInvOrgId = itemData.SupplierCode,
                            PackageQty = itemData.PackageQty,
                            MaterielState = itemData.DeleteFlag == "0" ? EnableEnum.Enable : EnableEnum.Disable,
                            MaterielState = itemData.DeleteFlag == 0 ? EnableEnum.Enable : EnableEnum.Disable,
                            WarehouseId = 0,
                            MaterielSourceType = 0,
                            Creater = itemData.CreateUser,
                            CreateDate = itemData.CreateDate,
                            Modifier = itemData.UpdateUser,
                            ModifyDate = itemData.UpdateDate
                            CreateDate = DateTime.Now,
                        };
                        BaseDal.AddData(addEntity);
                        _basicRepository.MaterielInfoRepository.AddData(addEntity);
                    }
                    else
                    {
                        existMateriel.OrgId = itemData.OrgId;
                        existMateriel.MaterielInvOrgId = itemData.SupplierCode;
                        existMateriel.PackageQty = itemData.PackageQty;
                        existMateriel.MaterielState = itemData.DeleteFlag == "0" ? EnableEnum.Enable : EnableEnum.Disable;
                        existMateriel.MaterielState = itemData.DeleteFlag == 0 ? EnableEnum.Enable : EnableEnum.Disable;
                        existMateriel.Modifier = itemData.UpdateUser;
                        existMateriel.ModifyDate = itemData.UpdateDate;
@@ -225,5 +224,6 @@
                return WebResponseContent.Instance.Error($"VMI物料同步失败:{ex.Message}");
            }
        }
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_BasicService/WIDESEA_BasicService.csproj
@@ -7,6 +7,7 @@
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\WIDESEA_External\WIDESEA_External.csproj" />
    <ProjectReference Include="..\WIDESEA_IBasicService\WIDESEA_IBasicService.csproj" />
    <ProjectReference Include="..\WIDESEA_IRecordService\WIDESEA_IRecordService.csproj" />
    <ProjectReference Include="..\WIDESEA_ISystemRepository\WIDESEA_ISystemRepository.csproj" />
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_Common/APIEnum/APIEnum.cs
@@ -77,6 +77,14 @@
        /// PLS接口调用
        /// </summary>
        [Description("PLS接口调用")]
        InvokePLSApi
        InvokePLSApi,
        /// <summary>
        /// MLS获取token接口调用
        /// </summary>
        [Description("MLS获取token接口调用")]
        InvokeMLSTokenApi
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_Core/AOP/SqlSugarAop.cs
@@ -85,7 +85,7 @@
                    baseEntity.ModifyDate = DateTime.Now;
                }
                //if (App.User?.UserId > 0)
                if (App.User?.UserId > 0)
                {
                    switch (entityInfo.OperationType)
                    {
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_DTO/MLS/MLSRequestContent.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_DTO.MLS
{
    /// <summary>
    /// è°ƒç”¨MLS接口回参
    /// </summary>
    public class MLSRequestContent
    {
        /// <summary>
        /// çŠ¶æ€ç  0-成功,1-失败
        /// </summary>
        public string Code { get; set; }
        /// <summary>
        /// å“åº”信息
        /// </summary>
        public string Msg { get; set; }
        /// <summary>
        /// é”™è¯¯ä¿¡æ¯
        /// </summary>
        public string ErrMsg { get; set; }
        /// <summary>
        /// æ—¶é—´æˆ³
        /// </summary>
        public string Timestamp { get; set; }
        /// <summary>
        /// å“åº”数据
        /// </summary>
        public object Data { get; set; }
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_DTO/MLS/ReceiveMLSToken.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WIDESEA_DTO.MLS
{
    /// <summary>
    /// èŽ·å–token请求实体
    /// </summary>
    public class ReceiveMLSToken
    {
        /// <summary>
        /// MLS提供账号
        /// </summary>
        public string MlsUser { get; set; }
        /// <summary>
        /// MLS提供密码
        /// </summary>
        public string MlsPwd { get; set; }
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_DTO/PLS/MoInboundOrderDTO.cs
@@ -43,7 +43,7 @@
        /// <summary>
        /// VMI物流状态
        /// </summary>
        public string Status { get; set; }
        public int Status { get; set; }
        /// <summary>
        /// å•据号
        /// </summary>
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_DTO/PLS/PLSBaseModel.cs
@@ -14,6 +14,10 @@
        /// <summary>
        /// æ—¶é—´æˆ³
        /// </summary>
        public string AppId { get; set; }
        /// <summary>
        /// æ—¶é—´æˆ³
        /// </summary>
        public long TimeStamp { get; set; }
        /// <summary>
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_DTO/PLS/PLSRequestContent.cs
@@ -7,7 +7,7 @@
namespace WIDESEA_DTO.PLS
{
    /// <summary>
    /// PLS接口响应实体
    /// æŽ¥æ”¶PLS接口响应实体
    /// </summary>
    public class PLSRequestContent
    {
@@ -15,7 +15,7 @@
        /// <summary>
        /// çŠ¶æ€ç  0-成功,1-失败
        /// </summary>
        public int Code { get; set; }
        public string Code { get; set; }
        /// <summary>
        /// å“åº”信息
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_DTO/PLS/PlsResponseContent.cs
@@ -14,7 +14,7 @@
        /// <summary>
        /// çŠ¶æ€ç  0-成功 1-失败
        /// </summary>
        public int Code { get; set; } = 0;
        public string Code { get; set; } = "0";
        /// <summary>
        /// å“åº”信息
@@ -39,7 +39,7 @@
        /// </summary>
        public ApiResponseContent OK(string message = null)
        {
            Code = 0;
            Code = "0";
            Msg = message ?? "成功";
            Data = null??"无";
            return this;
@@ -50,7 +50,7 @@
        /// </summary>
        public ApiResponseContent Error(string message = null)
        {
            Code = 1;
            Code = "1";
            Msg = message ?? "失败";
            Data = null ?? "无";
            return this;
@@ -61,7 +61,7 @@
        /// </summary>
        public ApiResponseContent OK(List<LabelNoData> dataList, string message = null)
        {
            Code = 0;
            Code = "0";
            Msg = message ?? "成功";
            Data = dataList;
            return this;
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_DTO/PLS/ReturnMoInboundStatuModel.cs
@@ -22,7 +22,7 @@
        /// <summary>
        /// VMI物流状态
        /// </summary>
        public string Status { get; set; }
        public int Status { get; set; }
        /// <summary>
        /// å•据号
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_DTO/PLS/VMIItemCodeInfo.cs
@@ -60,7 +60,7 @@
        /// <summary>
        /// æœ‰æ•ˆæ ‡è¯†
        /// </summary>
        public string DeleteFlag { get; set; }
        public int DeleteFlag { get; set; }
        /// <summary>
        /// åˆ›å»ºäºº
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_External/IMLSService/IInvokeMLSService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_DTO.MLS;
namespace WIDESEA_External.IMLSService
{
    public interface IInvokeMLSService
    {
        string ReceiveTokenVoid();
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_External/PLSService/InvokeMLSService.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,73 @@
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_DTO.MLS;
using WIDESEA_External.IMLSService;
using WIDESEA_IBasicRepository;
using WIDESEA_Common.APIEnum;
using WIDESEA_Core.Helper;
using WIDESEA_Model.Models;
namespace WIDESEA_External.PLSService
{
    public class InvokeMLSService : IInvokeMLSService
    {
        private readonly IApiInfoRepository _apiInfoRepository;
        public InvokeMLSService(IApiInfoRepository apiInfoRepository)
        {
            _apiInfoRepository = apiInfoRepository;
        }
        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
        /// <summary>
        /// èŽ·å–token
        /// </summary>
        /// <param name="receiveMLSToken"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public string ReceiveTokenVoid()
        {
            try
            {
                Dt_ApiInfo apiInfo = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.InvokeMLSTokenApi.ToString());
                string MlsPwd = AppSettings.Get("MlsPwd");
                string MlsUser = AppSettings.Get("MlsUser");
                var finalRequest = new
                {
                    mlsUser = MlsUser,
                    mlsPwd = MlsPwd
                };
                string requestJson = JsonConvert.SerializeObject(finalRequest, settings);
                string response = HttpHelper.Post(apiInfo.ApiAddress, requestJson);
                MLSRequestContent mLSRequestContent = response.DeserializeObject<MLSRequestContent>();
                if (mLSRequestContent.Code == "0" && mLSRequestContent.Data!= null)
                {
                    apiInfo.Remark = (string)mLSRequestContent.Data;
                    _apiInfoRepository.UpdateData(apiInfo);
                }
                else
                {
                    return "获取token失败,或返回token值为空";
                }
                return response;
            }
            catch(Exception ex)
            {
                return ex.Message;
            }
        }
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_External/PLSService/InvokePLSService.cs
@@ -27,17 +27,42 @@
        {
            ContractResolver = new CamelCasePropertyNamesContractResolver()
        };
        /// <summary>
        /// èŽ·å–MO票
        /// </summary>
        /// <param name="moInboundStatuModel"></param>
        /// <returns></returns>
        public string InvokeMoInboundStatuApi(ReturnMoInboundStatuModel moInboundStatuModel)
        {
            Dt_ApiInfo apiInfo = _apiInfoRepository.QueryFirst(x => x.ApiCode == APIEnum.InvokePLSApi.ToString());
            PLSBaseModel<ReturnMoInboundStatuModel> model = new PLSBaseModel<ReturnMoInboundStatuModel>()
            string appId = AppSettings.Get("LocalAppId");
            string appSecret = AppSettings.Get("LocalAppSecret");
            var requestModel = new
            {
                Data = moInboundStatuModel,
                TimeStamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                Sign = "RWMS001"
                AppId = appId
            };
            string request = JsonConvert.SerializeObject(model, settings);
            string response = HttpHelper.Post(apiInfo.ApiAddress, request);
            string paramStr = MD5Util.GetParamStr(requestModel);
            string sign = MD5Util.GetMD5_32(paramStr + appSecret);
            var finalRequest = new
            {
                requestModel.Data,
                requestModel.TimeStamp,
                requestModel.AppId,
                Sign = sign
            };
            string requestJson = JsonConvert.SerializeObject(finalRequest, settings);
            string response = HttpHelper.Post(apiInfo.ApiAddress, requestJson);
            return response;
        }
    }
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_External/PLSService/MD5Util.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,462 @@
using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core.Helper;
using Newtonsoft.Json.Serialization;
namespace WIDESEA_External.PLSService
{
    public class MD5Util
    {
        // èŽ·å¾—32位的MD5加密
        public static string GetMD5_32(string input)
        {
            System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
            byte[] data = md5.ComputeHash(Encoding.UTF8.GetBytes(input));
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < data.Length; i++)
            {
                sb.Append(data[i].ToString("x2"));
            }
            return sb.ToString();
        }
        // èŽ·å¾—16位的MD5加密
        public static string GetMD5_16(string input)
        {
            return GetMD5_32(input).Substring(8, 16);
        }
        // èŽ·å¾—8位的MD5加密
        public static string GetMD5_8(string input)
        {
            return GetMD5_32(input).Substring(8, 8);
        }
        // èŽ·å¾—4位的MD5加密
        public static string GetMD5_4(string input)
        {
            return GetMD5_32(input).Substring(8, 4);
        }
        // æ·»åŠ MD5的前缀,便于检查有无篡改
        public static string AddMD5Profix(string input)
        {
            return GetMD5_4(input) + input;
        }
        // ç§»é™¤MD5的前缀
        public static string RemoveMD5Profix(string input)
        {
            return input.Substring(4);
        }
        // éªŒè¯MD5前缀处理的字符串有无被篡改
        public static bool ValidateValue(string input)
        {
            bool res = false;
            if (input.Length >= 4)
            {
                string tmp = input.Substring(4);
                if (input.Substring(0, 4) == GetMD5_4(tmp))
                {
                    res = true;
                }
            }
            return res;
        }
        /// <summary>
        /// å¯¹json得键进行排序
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static string SortJson(string json)
        {
            var tokenType = GetJsonType(json);
            if (tokenType == JTokenType.Object)
            {
                var dic = JsonConvert.DeserializeObject<SortedDictionary<string, object>>(json);
                SortedDictionary<string, object> keyValues = new SortedDictionary<string, object>(dic);
                keyValues.OrderBy(m => m.Key);//升序 æŠŠKey换成Value å°±æ˜¯å¯¹Value进行排序
                                              //keyValues.OrderByDescending(m => m.Key);//降序
                SortedDictionary<string, object> tempKeyValues = new SortedDictionary<string, object>(keyValues);
                foreach (KeyValuePair<string, object> kv in tempKeyValues)
                {
                    // åˆ¤æ–­value是不是JObject类型
                    Type t1 = kv.Value.GetType();
                    if (t1 == typeof(JObject))
                    {
                        // value是JObject类型
                        string jsonItem = JsonConvert.SerializeObject(kv.Value);
                        jsonItem = SortJson(jsonItem);
                        keyValues[kv.Key] = JsonConvert.DeserializeObject<JObject>(jsonItem);
                    }
                    else if (t1 == typeof(JArray))
                    {
                        StringBuilder stringBuilder = new StringBuilder();
                        stringBuilder.Append("[");
                        bool isFirst = true;
                        foreach (JToken item in (JArray)kv.Value)
                        {
                            if (item.Type == JTokenType.Object)
                            {
                                string jsonArrayItem = JsonConvert.SerializeObject(item);
                                jsonArrayItem = SortJson(jsonArrayItem);
                                if (isFirst)
                                {
                                    stringBuilder.Append(jsonArrayItem);
                                }
                                else
                                {
                                    stringBuilder.Append($",{jsonArrayItem}");
                                }
                            }
                            else if (item.Type == JTokenType.Array)
                            {
                                var arrayTmpRes = SortJson(JsonConvert.SerializeObject(item));
                                if (isFirst)
                                {
                                    stringBuilder.Append(arrayTmpRes);
                                }
                                else
                                {
                                    stringBuilder.Append($",{arrayTmpRes}");
                                }
                            }
                            else
                            {
                                string jsonArrayItem = JsonConvert.SerializeObject(item);
                                if (isFirst)
                                {
                                    stringBuilder.Append(jsonArrayItem);
                                }
                                else
                                {
                                    stringBuilder.Append($",{jsonArrayItem}");
                                }
                            }
                            isFirst = false;
                        }
                        stringBuilder.Append("]");
                        var tmpJsonStr = stringBuilder.ToString();
                        keyValues[kv.Key] = JsonConvert.DeserializeObject<JArray>(tmpJsonStr);
                    }
                }
                return JsonConvert.SerializeObject(keyValues);
            }
            else if (tokenType == JTokenType.Array)
            {
                var arraies = JsonConvert.DeserializeObject<JArray>(json);
                StringBuilder stringBuilder2 = new StringBuilder();
                stringBuilder2.Append("[");
                bool isFirst2 = true;
                foreach (JToken item in arraies)
                {
                    if (item.Type == JTokenType.Object)
                    {
                        string jsonArrayItem = JsonConvert.SerializeObject(item);
                        jsonArrayItem = SortJson(jsonArrayItem);
                        if (isFirst2)
                        {
                            stringBuilder2.Append(jsonArrayItem);
                        }
                        else
                        {
                            stringBuilder2.Append($",{jsonArrayItem}");
                        }
                    }
                    else if (item.Type == JTokenType.Array)
                    {
                        var arrayTmpRes = SortJson(JsonConvert.SerializeObject(item));
                        if (isFirst2)
                        {
                            stringBuilder2.Append(arrayTmpRes);
                        }
                        else
                        {
                            stringBuilder2.Append($",{arrayTmpRes}");
                        }
                    }
                    else
                    {
                        string jsonArrayItem = JsonConvert.SerializeObject(item);
                        if (isFirst2)
                        {
                            stringBuilder2.Append(jsonArrayItem);
                        }
                        else
                        {
                            stringBuilder2.Append($",{jsonArrayItem}");
                        }
                    }
                    isFirst2 = false;
                }
                stringBuilder2.Append("]");
                return stringBuilder2.ToString();
            }
            return json;
        }
        /// <summary>
        /// æ ¹æ®json判断json类型
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static JTokenType GetJsonType(string json)
        {
            JToken token = JToken.Parse(json);
            return token.Type;
        }
        #region MD5签名验证
        /// <summary>
        /// å¯¹ç»™å®šæ–‡ä»¶è·¯å¾„的文件加上标签
        /// </summary>
        /// <param name="path">要加密的文件的路径</param>
        /// <returns>标签的值</returns>
        public static bool AddMD5(string path)
        {
            bool IsNeed = true;
            //已进行MD5处理
            if (CheckMD5(path))
                IsNeed = false;
            try
            {
                FileStream fsread = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                byte[] md5File = new byte[fsread.Length];
                // å°†æ–‡ä»¶æµè¯»å–到Buffer中
                fsread.Read(md5File, 0, (int)fsread.Length);
                fsread.Close();
                if (IsNeed)
                {
                    // å¯¹Buffer中的字节内容算MD5
                    string result = MD5Buffer(md5File, 0, md5File.Length);
                    // å°†å­—符串转换成字节数组以便写人到文件中
                    byte[] md5 = System.Text.Encoding.ASCII.GetBytes(result);
                    FileStream fsWrite = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
                    // å°†æ–‡ä»¶ï¼ŒMD5值 é‡æ–°å†™å…¥åˆ°æ–‡ä»¶ä¸­ã€‚
                    fsWrite.Write(md5File, 0, md5File.Length);
                    fsWrite.Write(md5, 0, md5.Length);
                    fsWrite.Close();
                }
                else
                {
                    FileStream fsWrite = new FileStream(path, FileMode.Open, FileAccess.ReadWrite);
                    fsWrite.Write(md5File, 0, md5File.Length);
                    fsWrite.Close();
                }
            }
            catch
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// å¯¹ç»™å®šè·¯å¾„的文件进行验证
        /// </summary>
        /// <param name="path"></param>
        /// <returns>是否加了标签或是否标签值与内容值一致</returns>
        public static bool CheckMD5(string path)
        {
            try
            {
                FileStream get_file = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
                // è¯»å…¥æ–‡ä»¶
                byte[] md5File = new byte[get_file.Length];
                get_file.Read(md5File, 0, (int)get_file.Length);
                get_file.Close();
                // å¯¹æ–‡ä»¶é™¤æœ€åŽ32位以外的字节计算MD5,这个32是因为标签位为32位。
                string result = MD5Buffer(md5File, 0, md5File.Length - 32);
                //读取文件最后32位,其中保存的就是MD5值
                string md5 = Encoding.ASCII.GetString(md5File, md5File.Length - 32, 32);
                return result == md5;
            }
            catch
            {
                return false;
            }
        }
        /// <summary>
        /// è®¡ç®—文件的MD5值
        /// </summary>
        /// <param name="MD5File">MD5签名文件字符数组</param>
        /// <param name="index">计算起始位置</param>
        /// <param name="count">计算终止位置</param>
        /// <returns>计算结果</returns>
        private static string MD5Buffer(byte[] MD5File, int index, int count)
        {
            System.Security.Cryptography.MD5CryptoServiceProvider get_md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
            byte[] hash_byte = get_md5.ComputeHash(MD5File, index, count);
            string result = BitConverter.ToString(hash_byte);
            result = result.Replace("-", "");
            return result;
        }
        #endregion
        //自定义序列化工具类
        public class JsonPropertySortResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
        {
            protected override IList<Newtonsoft.Json.Serialization.JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
            {
                return base.CreateProperties(type, memberSerialization).OrderBy(p => p.PropertyName).ToList();
            }
        }
public class SortedCamelCaseContractResolver : DefaultContractResolver
    {
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            // èŽ·å–æ‰€æœ‰éœ€è¦åºåˆ—åŒ–çš„å±žæ€§ï¼ˆåŸºç±»æ–¹æ³•å·²è¿‡æ»¤å¿½ç•¥å±žæ€§ç­‰ï¼‰
            var properties = base.CreateProperties(type, memberSerialization).ToList();
            // å…ˆå¯¹æ¯ä¸ªå±žæ€§åº”用 CamelCase å‘½åï¼ˆç¡®ä¿æœ€ç»ˆè¾“出的字段名是小驼峰)
            foreach (var prop in properties)
            {
                prop.PropertyName = GetCamelCaseName(prop.UnderlyingName);
            }
            // æŒ‰å±žæ€§åï¼ˆå³å°é©¼å³°åŽçš„名称)字母升序排序
            return properties.OrderBy(p => p.PropertyName).ToList();
        }
        private string GetCamelCaseName(string name)
        {
            if (string.IsNullOrEmpty(name) || char.IsLower(name[0]))
                return name;
            return char.ToLower(name[0]) + name.Substring(1);
        }
}
        //入参加密前置格式化
        public static string GetParamStr<T>(T objectParam)
        {
            // èŽ·å–JSON串,但排除sign字段
            Func<object, string, object, bool> filter = (object obj, string field, object value) => !field.Equals("sign");
            string paramStr = JsonConvert.SerializeObject(objectParam, new JsonSerializerSettings
            {
                ContractResolver = new SortedCamelCaseContractResolver(),
                NullValueHandling = NullValueHandling.Ignore,
                Formatting = Formatting.None,
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                DateFormatString = "yyyy-MM-dd HH:mm:ss",
                DateTimeZoneHandling = DateTimeZoneHandling.Unspecified,
                Converters = new List<JsonConverter> { new DecimalWithoutTrailingZerosConverter() }
            });
            //排序JOSN,得到格式化的串
            return SortJson(paramStr);
        }
        public class DecimalWithoutTrailingZerosConverter : JsonConverter<decimal>
        {
            public override void WriteJson(JsonWriter writer, decimal value, JsonSerializer serializer)
            {
                // åˆ¤æ–­æ˜¯å¦ä¸ºæ•´æ•°ï¼ˆå°¾æ•°ä¸ºé›¶ï¼‰
                if (value == Math.Floor(value))
                {
                    writer.WriteValue(Convert.ToInt64(value));
                }
                else
                {
                    writer.WriteValue(value);
                }
            }
            public override decimal ReadJson(JsonReader reader, Type objectType, decimal existingValue, bool hasExistingValue, JsonSerializer serializer)
            {
                // ååºåˆ—化时直接转换为 decimal,兼容整数和小数
                return Convert.ToDecimal(reader.Value);
            }
        }
        /// <summary>
        /// é€šç”¨PLS接口签名校验
        /// </summary>
        public static bool CheckPLSSign<T>(T model) where T : class
        {
            try
            {
                // å›ºå®šé…ç½®
                string localAppId = AppSettings.Get("LocalAppId");
                string localAppSecret = AppSettings.Get("LocalAppSecret");
                var type = typeof(T);
                object signModel = null;
                // ========== è‡ªåŠ¨èŽ·å–å…¬å…±å­—æ®µ ==========
                var timeStampProp = type.GetProperty("TimeStamp");
                var signProp = type.GetProperty("Sign");
                var dataProp = type.GetProperty("Data");
                if (timeStampProp == null || signProp == null || dataProp == null)
                    return false;
                // èŽ·å–å€¼
                string requestSign = signProp.GetValue(model)?.ToString() ?? "";
                object timeStampVal = timeStampProp.GetValue(model);
                object dataVal = dataProp.GetValue(model);
                //时间戳校验
                long nowTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
                long timeStamp = 0;
                if (timeStampVal is long lng)
                    timeStamp = lng;
                else if (timeStampVal is string str && long.TryParse(str, out long t))
                    timeStamp = t;
                //构建签名对象
                if (localAppId != null)
                {
                    signModel = new
                    {
                        AppId = localAppId,
                        TimeStamp = timeStamp,
                        Data = dataVal
                    };
                }
                else
                {
                    return false;
                }
                string paramStr = GetParamStr(signModel);
                string localSign = GetMD5_32(paramStr + localAppSecret);
                ///签名比对
                return localSign.Equals(requestSign, StringComparison.OrdinalIgnoreCase);
            }
            catch
            {
                return false;
            }
        }
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_External/WIDESEA_External.csproj
@@ -13,4 +13,8 @@
    <ProjectReference Include="..\WIDESEA_IBasicRepository\WIDESEA_IBasicRepository.csproj" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="MLSService\" />
  </ItemGroup>
</Project>
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_IBasicService/IMaterielInfoService.cs
@@ -5,6 +5,7 @@
using System.Threading.Tasks;
using WIDESEA_Core;
using WIDESEA_Core.BaseServices;
using WIDESEA_DTO;
using WIDESEA_DTO.Basic;
using WIDESEA_DTO.ERP;
using WIDESEA_DTO.PLS;
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_IInboundService/IMoInboundOrderService.cs
@@ -4,6 +4,8 @@
using System.Text;
using System.Threading.Tasks;
using WIDESEA_Core.BaseServices;
using WIDESEA_DTO.PLS;
using WIDESEA_DTO;
using WIDESEA_IInboundRepository;
using WIDESEA_Model.Models;
@@ -12,5 +14,12 @@
    public interface IMoInboundOrderService : IService<Dt_MoInboundOrder>
    {
        IMoInboundOrderRepository Repository { get; }
        /// <summary>
        /// æŽ¥æ”¶MO票信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public ApiResponseContent ReceiveMoStatus(MoInboundOrderDTO model);
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_InboundService/MoInboundOrderService.cs
@@ -13,6 +13,8 @@
using WIDESEA_IInboundRepository;
using WIDESEA_IInboundService;
using WIDESEA_Model.Models;
using WIDESEA_External.PLSService;
using WIDESEA_Core;
namespace WIDESEA_InboundService
{
@@ -57,8 +59,15 @@
                            throw new Exception("标签号 LabelNo ä¸èƒ½ä¸ºç©º");
                        }
                        // æŸ¥è¯¢MO票是否已存在
                        var existMo = BaseDal.QueryFirst(x => x.LabelNo == item.LabelNo);
                        ///签名校验
                        bool IsSign = MD5Util.CheckPLSSign(model);
                        if (!IsSign)
                        {
                            return ApiResponseContent.Instance.Error("签名验证失败,请检查");
                        }
                        // æŸ¥è¯¢å”¯ä¸€é”®æ˜¯å¦å·²å­˜åœ¨ï¼ˆorgId+labelNo)
                        var existMo = BaseDal.QueryFirst(x => x.LabelNo == item.LabelNo && x.OrgId == item.OrgId);
                        if (existMo == null)
                        {
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_Model/Models/Basic/Dt_ApiInfo.cs
@@ -37,7 +37,7 @@
        /// <summary>
        /// å¤‡æ³¨
        /// </summary>
        [SugarColumn(IsNullable = true, Length = 50, ColumnDescription = "备注")]
        [SugarColumn(IsNullable = true, Length = 500, ColumnDescription = "备注")]
        public string Remark { get; set; }
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_Model/Models/Inbound/Dt_MoInboundOrder.cs
@@ -40,10 +40,10 @@
        public string BarcodeNumber { get; set; }
        /// <summary>
        /// VMI物流状态(已创建,已备货,已发运,已取消)
        /// VMI物流状态(0-已创建,1-待拣货,2-已备货,3-已发运,4-已取消)
        /// </summary>
        [SugarColumn(IsNullable = false, Length = 10, ColumnDescription = "VMI物流状态(已创建,已备货,已发运,已取消)")]
        public string Status { get; set; }
        [SugarColumn(IsNullable = false, Length = 10, ColumnDescription = "VMI物流状态(0-已创建,1-待拣货,2-已备货,3-已发运,4-已取消)")]
        public int Status { get; set; }
        /// <summary>
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_WMSServer/Controllers/Inbound/MoInboundOrderController.cs
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,31 @@
using Microsoft.AspNetCore.Mvc;
using WIDESEA_Core;
using WIDESEA_Core.BaseController;
using WIDESEA_DTO.PLS;
using WIDESEA_DTO;
using WIDESEA_IInboundService;
using WIDESEA_Model.Models;
using Microsoft.AspNetCore.Authorization;
namespace WIDESEA_WMSServer.Controllers.Inbound
{
    [Route("api/MoInboundOrder")]
    [ApiController]
    public class MoInboundOrderController : ApiBaseController<IMoInboundOrderService, Dt_MoInboundOrder>
    {
        public MoInboundOrderController(IMoInboundOrderService service) : base(service)
        {
        }
        /// <summary>
        /// åŒæ­¥MO票信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost, HttpGet, Route("ReceiveMoStatus"),AllowAnonymous]
        public ApiResponseContent ReceiveMoStatus([FromBody] MoInboundOrderDTO model)
        {
            return Service.ReceiveMoStatus(model);
        }
    }
}
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_WMSServer/Controllers/PLS/PlsController.cs
@@ -13,6 +13,9 @@
namespace WIDESEA_WMSServer.Controllers.PLS
{
    /// <summary>
    /// PLS接口
    /// </summary>
    [Route("api/Pls")]
    [ApiController]
    public class PlsController:ControllerBase
@@ -39,7 +42,7 @@
                return ApiResponseContent.Instance.OK();
            } 
            else {
                return ApiResponseContent.Instance.Error();
                return ApiResponseContent.Instance.Error(content.Message);
            }
        }
ÏîÄ¿´úÂë/WMS/WMSServices/WIDESEA_WMSServer/appsettings.json
@@ -10,6 +10,7 @@
  "AllowedHosts": "*",
  "ConnectionStringsEncryption": false,
  "MainDB": "DB_WIDESEA", //当前项目的主库,所对应的连接字符串的Enabled必须为true
  //连接字符串
  //"ConnectionString": "HTI6FB1H05Krd07mNm9yBCNhofW6edA5zLs9TY~MNthRYW3kn0qKbMIsGp~3yyPDF1YZUCPBQx8U0Jfk4PH~ajNFXVIwlH85M3F~v_qKYQ3CeAz3q1mLVDn8O5uWt1~3Ut2V3KRkEwYHvW2oMDN~QIDXPxDgXN0R2oTIhc9dNu7QNaLEknblqmHhjaNSSpERdDVZIgHnMKejU_SL49tralBkZmDNi0hmkbL~837j1NWe37u9fJKmv91QPb~16JsuI9uu0EvNZ06g6PuZfOSAeFH9GMMIZiketdcJG3tHelo=",
  //"ConnectionString": "Data Source=.;Initial Catalog=WIDESEAWMS_HUAIAN;User ID=sa;Password=P@ssw0rd;Integrated Security=False;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False",
@@ -27,12 +28,18 @@
  },
  "WCS": "http://localhost:9291",
  "LogAopEnable": false,
  "PrintSql": true, //打印SQL语句
  "PrintSql": false, //打印SQL语句
  "ApiName": "WIDESEA",
  "ExpMinutes": 120,
  "QuartzJobAutoStart": true,
  "PDAVersion": "4",
  "WebSocketPort": "9296,",
  "DBSeedEnable": true
  "DBSeedEnable": false,
  //PLS签名账号及密钥
  "LocalAppId": "RWMS",
  "LocalAppSecret": "pW6wny!#3P9nb#68",
  //MLS账号密码
  "MlsUser": "123",
  "MlsPwd": "wewe"
}