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
{
///
/// 领星服务接口
///
public class LingXingService : ILingXingService
{
private readonly IHttpClientService _httpClientService;
private readonly ILogger _logger;
private readonly IMemoryCache _memoryCache;
private int hours = 10;//过期时间 默认10小时
private readonly lingXingOptions _option;
public LingXingService(IHttpClientService httpClientService, ILogger logger,
IMemoryCache memoryCache, IOptions option)
{
this._memoryCache = memoryCache;
this._httpClientService = httpClientService;
this._logger = logger;
_option = option?.Value;
}
public async Task> 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(_option.Url + endStr, formData, null);
if (res.code != "200")
{
_logger.LogInformation($"领星获取授权失败:{res.msg}");
return Result.ReFailure(ResultCodes.LingXingTokenError);
}
string token = res.data.access_token;
return Result.ReSuccess(token);
}
///
/// 获取所有仓库
///
///
public async Task>> GetStock()
{
var stock_list = _memoryCache.Get>("lingxing_stock");
if (stock_list != null && stock_list.Count > 0)
return Result>.ReSuccess(stock_list);
//默认获取本地仓库 如果需要海外仓 另外需传参数type
var request = new LingXingRequest();
var resUrl = await GetStr("/erp/sc/data/local_inventory/warehouse", request);
if (!resUrl.IsSuccess) return Result>.ReFailure(ResultCodes.LingXingUrlError);
var res = await _httpClientService.PostAsync(resUrl.Data, JsonConvert.SerializeObject(request), null);
if (res.Code != 0) return Result>.ReFailure(ResultCodes.LingXingDataError);
var list = JsonConvert.DeserializeObject>(res.Data.ToString());
//设置缓存
_memoryCache.Set("lingxing_stock", list, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(DateTimeUtil.GetTotalMinutesTimeSpan())));
return Result>.ReSuccess(list);
}
///
/// 获取所有店铺
///
///
///
public async Task>> GetSeller()
{
var seller_list = _memoryCache.Get>("lingxing_seller");
if (seller_list != null && seller_list.Count > 0)
return Result>.ReSuccess(seller_list);
var request = new LingXingKongRequest();
var resUrl = await GetStr("/erp/sc/data/seller/lists", request);
if (!resUrl.IsSuccess) return Result>.ReFailure(ResultCodes.LingXingUrlError);
var res = await _httpClientService.GetAsync(resUrl.Data);
if (res.Code != 0) return Result>.ReFailure(ResultCodes.LingXingDataError);
var list = JsonConvert.DeserializeObject>(res.Data.ToString());
//设置缓存
_memoryCache.Set("lingxing_seller", list, new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(DateTimeUtil.GetTotalMinutesTimeSpan())));
return Result>.ReSuccess(list);
}
///
/// 获取即使库存
///
///
///
///
public async Task>> GetInventory(LingXingInventoryRequest dto)
{
var resUrl = await GetStr("/erp/sc/routing/data/local_inventory/inventoryDetails", dto);
if (!resUrl.IsSuccess) return Result>.ReFailure(ResultCodes.LingXingUrlError);
List list = new List();
var res = await _httpClientService.PostAsync(resUrl.Data, JsonConvert.SerializeObject(dto), null);
if (res.Code != 0) return Result>.ReFailure(ResultCodes.LingXingDataError);
list.AddRange(JsonConvert.DeserializeObject>(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("/erp/sc/routing/data/local_inventory/inventoryDetails", dto);
if (!resUrl.IsSuccess) return Result>.ReFailure(ResultCodes.LingXingUrlError);
res = await _httpClientService.PostAsync(resUrl.Data, JsonConvert.SerializeObject(dto), null);
if (res.Code != 0) return Result>.ReFailure(ResultCodes.LingXingDataError);
list.AddRange(JsonConvert.DeserializeObject>(res.Data.ToString()));
}
return Result>.ReSuccess(list.Where(w => w.Product_Total > 0 && w.Product_Valid_Num > 0).ToList());
}
#region 基础函数
public async Task> GetStr(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 testParamDics = new Dictionary();
var ssi = GetEntityPropertyToDic(testParamDics, lxSign.GetType().GetProperties(), lxSign);//把签名参数实体转化为键值对
var ssdata = GetEntityPropertyToDic(testParamDics, data.GetType().GetProperties(), data);//把参数实体转化为键值对
// List> list = new List>();
Dictionary list = new Dictionary();
//string[] arrays = new string[data];
foreach (var item in typeof(LxSignInfo).GetProperties())
{
//KeyValueInfo keys = new KeyValueInfo();
//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 keys = new KeyValueInfo();
//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.ReSuccess(ret);
#endregion
}
///
/// 32位MD5加密
///
/// 要加密字符串
/// 是否以小写方式返回
///
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');
}
///
/// AES加密
///
/// 需要加密的字符串
/// 32位密钥
///向量(默认偏移量)
/// 加密后的字符串
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 "";
}
}
///
/// 类实体的属性与值转化成键值对形式
///
///
///
///
///
public static Dictionary GetEntityPropertyToDic(Dictionary 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; }
}
}