350 lines
15 KiB
C#
350 lines
15 KiB
C#
using Microsoft.Extensions.Caching.Memory;
|
||
using Microsoft.Extensions.Logging;
|
||
using Microsoft.Extensions.Options;
|
||
using Newtonsoft.Json;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using WMS.Web.Core.Dto;
|
||
using WMS.Web.Domain.IService.Public;
|
||
using WMS.Web.Domain.Options;
|
||
using WMS.Web.Core.Internal.Results;
|
||
using WMS.Web.Core.Dto.LingXing;
|
||
using System.Json;
|
||
using System.Net.Http;
|
||
using NPOI.POIFS.Crypt.Dsig;
|
||
using NPOI.SS.Formula.Functions;
|
||
using System.Configuration;
|
||
using System.Linq;
|
||
using System.Net;
|
||
using System.Text.RegularExpressions;
|
||
using System.Security.Cryptography;
|
||
using System.Reflection;
|
||
using WMS.Web.Core.Help;
|
||
using static System.Net.WebRequestMethods;
|
||
using WMS.Web.Domain.Values;
|
||
using WMS.Web.Core.Dto.JuShuiTan;
|
||
|
||
namespace WMS.Web.Domain.Services.Public
|
||
{
|
||
/// <summary>
|
||
/// 领星服务接口
|
||
/// </summary>
|
||
public class LingXingService : ILingXingService
|
||
{
|
||
private readonly IHttpClientService _httpClientService;
|
||
private readonly ILogger<LingXingService> _logger;
|
||
private readonly IMemoryCache _memoryCache;
|
||
private int hours = 10;//过期时间 默认10小时
|
||
private readonly lingXingOptions _option;
|
||
|
||
public LingXingService(IHttpClientService httpClientService, ILogger<LingXingService> logger,
|
||
IMemoryCache memoryCache, IOptions<lingXingOptions> option)
|
||
{
|
||
this._memoryCache = memoryCache;
|
||
this._httpClientService = httpClientService;
|
||
this._logger = logger;
|
||
_option = option?.Value;
|
||
}
|
||
|
||
public async Task<Result<string>> Login()
|
||
{
|
||
string endStr = "/api/auth-server/oauth/access-token";
|
||
|
||
var formData = new MultipartFormDataContent();
|
||
formData.Add(new StringContent(_option.AppId), "appId");
|
||
formData.Add(new StringContent(_option.AppSecret), "appSecret");
|
||
|
||
var res = await _httpClientService.PostAsync<dynamic>(_option.Url + endStr, formData, null);
|
||
|
||
if (res.code != "200")
|
||
{
|
||
_logger.LogInformation($"领星获取授权失败:{res.msg}");
|
||
return Result<string>.ReFailure(ResultCodes.LingXingTokenError);
|
||
}
|
||
string token = res.data.access_token;
|
||
return Result<string>.ReSuccess(token);
|
||
}
|
||
/// <summary>
|
||
/// 获取所有仓库
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public async Task<Result<List<LingXingStockResponse>>> GetStock()
|
||
{
|
||
var stock_list = _memoryCache.Get<List<LingXingStockResponse>>("lingxing_stock");
|
||
if (stock_list != null && stock_list.Count > 0)
|
||
return Result<List<LingXingStockResponse>>.ReSuccess(stock_list);
|
||
|
||
//默认获取本地仓库 如果需要海外仓 另外需传参数type
|
||
var request = new LingXingRequest();
|
||
var resUrl = await GetStr<LingXingRequest>("/erp/sc/data/local_inventory/warehouse", request);
|
||
if (!resUrl.IsSuccess) return Result<List<LingXingStockResponse>>.ReFailure(ResultCodes.LingXingUrlError);
|
||
|
||
var res = await _httpClientService.PostAsync<LingXingResponse>(resUrl.Data, JsonConvert.SerializeObject(request), null);
|
||
if (res.Code != 0) return Result<List<LingXingStockResponse>>.ReFailure(ResultCodes.LingXingDataError);
|
||
|
||
var list = JsonConvert.DeserializeObject<List<LingXingStockResponse>>(res.Data.ToString());
|
||
//设置缓存
|
||
_memoryCache.Set("lingxing_stock", list, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(DateTimeUtil.GetTotalMinutesTimeSpan())));
|
||
|
||
return Result<List<LingXingStockResponse>>.ReSuccess(list);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取所有店铺
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<Result<List<LingXingSellerResponse>>> GetSeller()
|
||
{
|
||
var seller_list = _memoryCache.Get<List<LingXingSellerResponse>>("lingxing_seller");
|
||
if (seller_list != null && seller_list.Count > 0)
|
||
return Result<List<LingXingSellerResponse>>.ReSuccess(seller_list);
|
||
|
||
var request = new LingXingKongRequest();
|
||
var resUrl = await GetStr<LingXingKongRequest>("/erp/sc/data/seller/lists", request);
|
||
if (!resUrl.IsSuccess) return Result<List<LingXingSellerResponse>>.ReFailure(ResultCodes.LingXingUrlError);
|
||
|
||
var res = await _httpClientService.GetAsync<LingXingResponse>(resUrl.Data);
|
||
if (res.Code != 0) return Result<List<LingXingSellerResponse>>.ReFailure(ResultCodes.LingXingDataError);
|
||
|
||
var list = JsonConvert.DeserializeObject<List<LingXingSellerResponse>>(res.Data.ToString());
|
||
//设置缓存
|
||
_memoryCache.Set("lingxing_seller", list, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(DateTimeUtil.GetTotalMinutesTimeSpan())));
|
||
|
||
return Result<List<LingXingSellerResponse>>.ReSuccess(list);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取即使库存
|
||
/// </summary>
|
||
/// <param name="dto"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
public async Task<Result<List<LingXingInventoryResponse>>> GetInventory(LingXingInventoryRequest dto)
|
||
{
|
||
var resUrl = await GetStr<LingXingInventoryRequest>("/erp/sc/routing/data/local_inventory/inventoryDetails", dto);
|
||
if (!resUrl.IsSuccess) return Result<List<LingXingInventoryResponse>>.ReFailure(ResultCodes.LingXingUrlError);
|
||
List<LingXingInventoryResponse> list = new List<LingXingInventoryResponse>();
|
||
var res = await _httpClientService.PostAsync<LingXingResponse>(resUrl.Data, JsonConvert.SerializeObject(dto), null);
|
||
if (res.Code != 0) return Result<List<LingXingInventoryResponse>>.ReFailure(ResultCodes.LingXingDataError);
|
||
list.AddRange(JsonConvert.DeserializeObject<List<LingXingInventoryResponse>>(res.Data.ToString()));
|
||
|
||
int num = res.Total / 800;
|
||
for (int i = 1; i <= num; i++)
|
||
{
|
||
dto.offset = i;
|
||
if (i == num) dto.length = res.Total - (num * 800);
|
||
resUrl = await GetStr<LingXingInventoryRequest>("/erp/sc/routing/data/local_inventory/inventoryDetails", dto);
|
||
if (!resUrl.IsSuccess) return Result<List<LingXingInventoryResponse>>.ReFailure(ResultCodes.LingXingUrlError);
|
||
res = await _httpClientService.PostAsync<LingXingResponse>(resUrl.Data, JsonConvert.SerializeObject(dto), null);
|
||
if (res.Code != 0) return Result<List<LingXingInventoryResponse>>.ReFailure(ResultCodes.LingXingDataError);
|
||
list.AddRange(JsonConvert.DeserializeObject<List<LingXingInventoryResponse>>(res.Data.ToString()));
|
||
}
|
||
return Result<List<LingXingInventoryResponse>>.ReSuccess(list.Where(w => w.Product_Total > 0 && w.Product_Valid_Num > 0).ToList());
|
||
}
|
||
#region 基础函数
|
||
public async Task<Result<string>> GetStr<T>(string urlStr, T data)
|
||
{
|
||
var res = await Login();
|
||
if (!res.IsSuccess) return res;
|
||
|
||
LxSignInfo lxSign = new LxSignInfo();
|
||
|
||
lxSign.access_token = res.Data;
|
||
lxSign.app_key = _option.AppId;
|
||
lxSign.timestamp = DateTime.Now.DateTimeToTimeStamp().ToString();
|
||
|
||
#region ASCII排序
|
||
Dictionary<string, object> testParamDics = new Dictionary<string, object>();
|
||
var ssi = GetEntityPropertyToDic(testParamDics, lxSign.GetType().GetProperties(), lxSign);//把签名参数实体转化为键值对
|
||
var ssdata = GetEntityPropertyToDic(testParamDics, data.GetType().GetProperties(), data);//把参数实体转化为键值对
|
||
|
||
// List<KeyValueInfo<string, string>> list = new List<KeyValueInfo<string, string>>();
|
||
Dictionary<string, string> list = new Dictionary<string, string>();
|
||
//string[] arrays = new string[data];
|
||
|
||
foreach (var item in typeof(LxSignInfo).GetProperties())
|
||
{
|
||
//KeyValueInfo<string, string> keys = new KeyValueInfo<string, string>();
|
||
//keys.Key = item.Name;
|
||
//keys.Value = ssi[$"{item.Name}"].ToString();
|
||
//list.Add(keys);
|
||
list.Add(item.Name, ssi[$"{item.Name}"].ToString());
|
||
}
|
||
|
||
foreach (var item in typeof(T).GetProperties())
|
||
{
|
||
//KeyValueInfo<string, string> keys = new KeyValueInfo<string, string>();
|
||
//keys.Key = item.Name;
|
||
//keys.Value = JsonConvert.SerializeObject(ssdata[$"{item.Name}"]);
|
||
|
||
//if (ssdata[$"{item.Name}"] == null) { list.Add(keys); continue; }
|
||
//if (string.IsNullOrEmpty(ssdata[$"{item.Name}"].ToString()))
|
||
//{
|
||
// continue;//跳过值为NULL的
|
||
//}
|
||
|
||
if (ssdata[$"{item.Name}"] == null) { list.Add(item.Name, JsonConvert.SerializeObject(ssdata[$"{item.Name}"])); continue; }
|
||
if (string.IsNullOrEmpty(ssdata[$"{item.Name}"].ToString()))
|
||
{
|
||
continue;//跳过值为NULL的
|
||
}
|
||
|
||
list.Add(item.Name, JsonConvert.SerializeObject(ssdata[$"{item.Name}"]));
|
||
}
|
||
|
||
string[] arrays = new string[list.Count];
|
||
|
||
int i = 0;
|
||
foreach (var item in list)
|
||
{
|
||
arrays[i] = item.Key;
|
||
|
||
i++;
|
||
}
|
||
|
||
Array.Sort(arrays, string.CompareOrdinal); //ASCII排序
|
||
|
||
string sig = null;
|
||
int j = 0;
|
||
foreach (var item in arrays)
|
||
{
|
||
string key = list.Where(a => a.Key == item).ToList()[0].Key.ToString();
|
||
string value = list.Where(a => a.Key == item).ToList()[0].Value.ToString();
|
||
|
||
#region 清除嵌套外的字段值的双引号
|
||
if (value.IndexOf("{", StringComparison.OrdinalIgnoreCase) > -1) { }
|
||
else
|
||
{
|
||
value = Regex.Replace(value, @"[\""]+", "");//去掉双引号
|
||
}
|
||
#endregion
|
||
|
||
if (j == i - 1)
|
||
{
|
||
sig += $"{key}={value}";
|
||
}
|
||
else
|
||
{
|
||
sig += $"{key}={value}&";
|
||
}
|
||
|
||
j++;
|
||
}
|
||
#endregion
|
||
|
||
#region MD5加密转大写+AES/ECB/PKCS5PADDING加密
|
||
//sig = Regex.Replace(sig, @"[\""]+", "");//去掉双引号
|
||
var md5 = MD5Encrypt(sig, false);
|
||
var signs = Encrypt(md5, lxSign.app_key);
|
||
#endregion
|
||
|
||
#region 字符转义
|
||
|
||
signs = WebUtility.UrlEncode(signs);
|
||
#endregion
|
||
|
||
#region 形成签名地址
|
||
var url = _option.Url + urlStr;
|
||
var ret = $"{url}?app_key={lxSign.app_key}&access_token={lxSign.access_token}×tamp={lxSign.timestamp}&sign={signs}";
|
||
return Result<string>.ReSuccess(ret);
|
||
#endregion
|
||
}
|
||
|
||
/// <summary>
|
||
/// 32位MD5加密
|
||
/// </summary>
|
||
/// <param name="strText">要加密字符串</param>
|
||
/// <param name="IsLower">是否以小写方式返回</param>
|
||
/// <returns></returns>
|
||
public static string MD5Encrypt(string strText, bool IsLower = true)
|
||
{
|
||
MD5 md5 = new MD5CryptoServiceProvider();
|
||
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(strText);
|
||
bytes = md5.ComputeHash(bytes);
|
||
md5.Clear();
|
||
|
||
string ret = "";
|
||
for (int i = 0; i < bytes.Length; i++)
|
||
{
|
||
ret += Convert.ToString(bytes[i], 16).PadLeft(2, '0');
|
||
|
||
}
|
||
if (IsLower == false) { return ret.PadLeft(32, '0').ToUpper(); }
|
||
return ret.PadLeft(32, '0');
|
||
}
|
||
/// <summary>
|
||
/// AES加密
|
||
/// </summary>
|
||
/// <param name="str">需要加密的字符串</param>
|
||
/// <param name="key">32位密钥</param>
|
||
///<param name="lv">向量(默认偏移量)</param>
|
||
/// <returns>加密后的字符串</returns>
|
||
public static string Encrypt(string str, string key)
|
||
{
|
||
try
|
||
{
|
||
|
||
Byte[] keyArray = System.Text.Encoding.UTF8.GetBytes(key);
|
||
Byte[] toEncryptArray = System.Text.Encoding.UTF8.GetBytes(str);
|
||
var rijndael = new System.Security.Cryptography.RijndaelManaged();
|
||
rijndael.Key = keyArray;
|
||
rijndael.Mode = System.Security.Cryptography.CipherMode.ECB;
|
||
rijndael.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
|
||
rijndael.IV = System.Text.Encoding.UTF8.GetBytes(key);
|
||
System.Security.Cryptography.ICryptoTransform cTransform = rijndael.CreateEncryptor();
|
||
Byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
|
||
return Convert.ToBase64String(resultArray, 0, resultArray.Length);
|
||
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
//YellowJLog("调用AES加密方法异常,异常原因:" + ex.Message, "加密异常");
|
||
return "";
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 类实体的属性与值转化成键值对形式
|
||
/// </summary>
|
||
/// <typeparam name="T"></typeparam>
|
||
/// <param name="inParam"></param>
|
||
/// <param name="infos"></param>
|
||
/// <param name="Entity"></param>
|
||
public static Dictionary<string, object> GetEntityPropertyToDic<T>(Dictionary<string, object> inParam, PropertyInfo[] infos, T Entity)
|
||
{
|
||
foreach (var info in infos)
|
||
{
|
||
var itemTpe = info.PropertyType;
|
||
//实体中有嵌套类的处理
|
||
if (itemTpe.IsClass && !itemTpe.Name.Equals("String", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
//if (info.GetValue(Entity) == null) continue;
|
||
//GetEntityPropertyToDic(inParam, itemTpe.GetProperties(), info.GetValue(Entity));
|
||
//inParam.Add(info.Name, info.GetValue(JsonConvert.SerializeObject(Entity), null));
|
||
inParam.Add(info.Name, info.GetValue(Entity, null));
|
||
}
|
||
else
|
||
{
|
||
|
||
inParam.Add(info.Name, info.GetValue(Entity, null));
|
||
//sig = Regex.Replace(sig, @"[\""]+", "");//去掉双引号
|
||
}
|
||
}
|
||
|
||
return inParam;
|
||
}
|
||
|
||
|
||
#endregion
|
||
}
|
||
public class LxSignInfo
|
||
{
|
||
public string access_token { get; set; }
|
||
public string app_key { get; set; }
|
||
public string timestamp { get; set; }
|
||
}
|
||
}
|