Files
zszq-trs/YLErpDAL/Modules/TradeModule/TradeChangeUtil.cs
T
2024-05-09 14:06:26 +08:00

440 lines
16 KiB
C#

using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using YLErp.DBModels.Attributes;
namespace YLErp.Modules.TradeModule
{
/// <summary>
/// 交易变更比对处理
/// </summary>
public static class TradeChangeUtil
{
static readonly IEnumerable<PropInfo>[] _propInfoArr;
static TradeChangeUtil()
{
_propInfoArr = new IEnumerable<PropInfo>[20];
_propInfoArr[0] = GetPropInfos(typeof(trade));
}
/// <summary>
/// 获取交易数据变更信息(包含扩展数据)
/// </summary>
public static List<TradeChangeInfo> GetAllChanges(trade oldData, trade newData)
{
if (oldData is null)
{
throw new ArgumentNullException(nameof(oldData));
}
if (newData is null)
{
throw new ArgumentNullException(nameof(newData));
}
var changeList = GetChanges(0, oldData, newData);
var changeListExt = GetExtendChanges(oldData, newData);
changeList.AddRange(changeListExt);
return changeList;
}
/// <summary>
/// 获取基础交易数据变更信息(仅针对trade自身)
/// </summary>
public static List<TradeChangeInfo> GetBasicChanges(trade oldData, trade newData)
{
if (oldData is null)
{
throw new ArgumentNullException(nameof(oldData));
}
if (newData is null)
{
throw new ArgumentNullException(nameof(newData));
}
return GetChanges(0, oldData, newData);
}
/// <summary>
/// 获取交易数据变更信息(包含扩展数据)
/// </summary>
public static IEnumerable<TradeChangeInfo> GetExtendChanges(trade oldData, trade newData)
{
if (oldData is null)
{
throw new ArgumentNullException(nameof(oldData));
}
if (newData is null)
{
throw new ArgumentNullException(nameof(newData));
}
//交易类型一致时才比较扩展数据
if (newData.TradeType == oldData.TradeType)
{
var index = 0;
object oldDataExt = null, newDataExt = null;
switch (oldData.TradeType)
{
case "香草期权":
return Enumerable.Empty<TradeChangeInfo>();
case "障碍期权":
index = 1;
oldDataExt = oldData.trade_barrier_option;
newDataExt = newData.trade_barrier_option;
break;
case "二元期权":
index = 2;
oldDataExt = oldData.trade_binary_option;
newDataExt = newData.trade_binary_option;
break;
case "亚式期权":
index = 3;
oldDataExt = oldData.trade_asian_option;
newDataExt = newData.trade_asian_option;
break;
case "彩虹期权":
index = 4;
oldDataExt = oldData.trade_rainbow_option;
newDataExt = newData.trade_rainbow_option;
break;
case "价差期权":
index = 5;
oldDataExt = oldData.trade_spread_option;
newDataExt = newData.trade_spread_option;
break;
case "合成价差期权":
index = 6;
break;
case "双鲨期权":
index = 7;
oldDataExt = oldData.trade_double_sharkfin_option;
newDataExt = newData.trade_double_sharkfin_option;
break;
case "区间累积期权":
index = 8;
oldDataExt = oldData.trade_rangeaccrual;
newDataExt = newData.trade_rangeaccrual;
break;
case "收益增强结构":
index = 9;
oldDataExt = oldData.trade_underlying_enhance;
newDataExt = newData.trade_underlying_enhance;
break;
case "气囊结构":
index = 10;
oldDataExt = oldData.trade_airbag;
newDataExt = newData.trade_airbag;
break;
case "凤凰期权":
index = 11;
oldDataExt = oldData.trade_autocall;
newDataExt = newData.trade_autocall;
break;
case "雪球期权":
index = 12;
oldDataExt = oldData.trade_snowball;
newDataExt = newData.trade_snowball;
break;
case "远期":
index = 13;
oldDataExt = oldData.trade_forward;
newDataExt = newData.trade_forward;
break;
case "收益互换":
index = 14;
oldDataExt = oldData.trade_swap;
newDataExt = newData.trade_swap;
break;
case "现金流交易":
index = 15;
oldDataExt = oldData.trade_cashflow;
newDataExt = newData.trade_cashflow;
break;
case "Risky期权":
index = 16;
oldDataExt = oldData.trade_risky_option;
newDataExt = newData.trade_risky_option;
break;
}
if (oldDataExt != null && newDataExt != null)
{
return GetChanges(index, oldDataExt, newDataExt);
}
return new TradeChangeInfo[] {
new TradeChangeInfo {
PropName = string.Empty,
DisplayName = $"扩展数据({oldData.TradeType})",
NewValue = newDataExt == null ? "不存在" : "存在",
OldValue = newDataExt == null ? "不存在" : "存在"
}
};
}
return new TradeChangeInfo[] {
new TradeChangeInfo {
PropName = string.Empty,
DisplayName ="扩展数据",
NewValue = newData.TradeType,
OldValue = oldData.TradeType
}
};
}
//比较旧数据和新数据并返回更改
private static List<TradeChangeInfo> GetChanges(int index, object oldData, object newData)
{
var propInfos = _propInfoArr[index];
if (propInfos == null)
{
propInfos = GetPropInfos(oldData.GetType());
}
var changeList = new List<TradeChangeInfo>();
foreach (var p in propInfos)
{
double GetMin(string so, string sn)
{
var min = 1e-5;
var mstr = so.Length < sn.Length ? so : sn;
var pow = mstr.Length - mstr.IndexOf('.') - 1;
if (pow < mstr.Length && pow > 5)
{
min = 0.55 / Math.Pow(10, pow);
}
return min;
}
var xold = p.GetValue(oldData);
var xnew = p.GetValue(newData);
var sold = (xold ?? string.Empty).ToString().Trim();
var snew = (xnew ?? string.Empty).ToString().Trim();
if (sold != snew)
{
if (p.TypeFalg > 0 && sold.Length != snew.Length)
{
if (p.TypeFalg == 1)
{
var min = GetMin(sold, snew);
if (Math.Abs((double)xold - (double)xnew) < min) continue;
}
else if (p.TypeFalg == 2)
{
var x = ((double?)xold) ?? 0;
var y = ((double?)xnew) ?? 0;
var min = GetMin(sold, snew);
if (Math.Abs(x - y) < min) continue;
}
}
changeList.Add(new TradeChangeInfo
{
NewValue = snew,
OldValue = sold,
PropName = p.PropName,
AuditFlag = p.AuditFlag,
DisplayName = p.DisplayName
});
}
}
return changeList;
}
//获取反射的属性数据
private static IEnumerable<PropInfo> GetPropInfos(Type type)
{
var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var list = new List<PropInfo>(props.Length);
foreach (var p in props)
{
if (!p.CanWrite) continue;
var custAttrs = p.GetCustomAttributes();
var auditAttr = custAttrs.OfType<TradeAuditAttribute>().FirstOrDefault();
if (auditAttr != null && auditAttr.Flag == TradeAuditFlag.exclude) continue;
if (auditAttr != null || !custAttrs.OfType<NotMappedAttribute>().Any())
{
var displayAttr = custAttrs.OfType<DisplayNameAttribute>().FirstOrDefault();
var propInfo = new PropInfo
{
PropName = p.Name,
GetValue = p.GetValue,
AuditFlag = auditAttr != null ? auditAttr.Flag : TradeAuditFlag.changed,
DisplayName = auditAttr != null ? auditAttr.DisplayName
: displayAttr != null ? displayAttr.DisplayName : p.Name
};
if (p.PropertyType == typeof(double))
{
propInfo.TypeFalg = 1;
}
else if (p.PropertyType == typeof(double?))
{
propInfo.TypeFalg = 2;
}
list.Add(propInfo);
}
}
list.TrimExcess();
return list;
}
/// <summary>
/// 序列化变更信息
/// </summary>
public static string SerializeChanges(IEnumerable<TradeChangeInfo> changeInfos, out TradeAuditFlag flag)
{
flag = TradeAuditFlag.changed;
if (changeInfos == null || !changeInfos.Any()) return string.Empty;
var list = new List<string>(changeInfos.Count());
foreach (var ci in changeInfos)
{
if (ci == null) continue;
var arr = new[] { ci.PropName, ci.DisplayName, ci.NewValue, ci.OldValue, ci.IsChangeMsg ? "1" : "0" };
var json = JsonHelper.Serialize(arr);
list.Add(json);
flag |= ci.AuditFlag;
}
return string.Join(Environment.NewLine, list);
}
/// <summary>
/// 反序列化变更信息
/// </summary>
public static IEnumerable<TradeChangeInfo> DeserializeChanges(string changInfo)
{
if (string.IsNullOrWhiteSpace(changInfo))
return Array.Empty<TradeChangeInfo>();
var list = new List<TradeChangeInfo>();
var sr = new StringReader(changInfo);
while (sr.Peek() > 0)
{
var line = sr.ReadLine().Trim();
if (line.Length > 0)
{
var dataArr = JsonHelper.Deserialize<string[]>(line);
var changeInfo = new TradeChangeInfo
{
PropName = dataArr[0],
DisplayName = dataArr[1],
NewValue = dataArr[2],
OldValue = dataArr[3]
};
list.Add(changeInfo);
if (dataArr.Length > 4)
{
changeInfo.AuditFlag = dataArr[4] == "1" ? TradeAuditFlag.changMsg : TradeAuditFlag.changed;
}
}
}
return list;
}
/// <summary>
/// 合并两个changes集合,实现同一个属性从最初值到最新值的合并
/// </summary>
public static IEnumerable<TradeChangeInfo> MergeChanges(IEnumerable<TradeChangeInfo> ltChangeInfos, IEnumerable<TradeChangeInfo> rtChangeInfos)
{
if (ltChangeInfos is null)
{
return rtChangeInfos;
}
if (rtChangeInfos is null)
{
return ltChangeInfos;
}
var dic = ltChangeInfos.ToDictionary(n => n.PropName);
foreach (var item in rtChangeInfos)
{
if (dic.TryGetValue(item.PropName, out var change))
{
change.NewValue = item.NewValue;
}
else
{
dic[item.PropName] = item;
}
}
return dic.Values;
}
/// <summary>
///
/// </summary>
public static string GetChangeMsg(IEnumerable<TradeChangeInfo> changes)
{
if (changes is null || !changes.Any())
{
return string.Empty;
}
return string.Join(string.Empty, changes.Select(n => string.Concat(n.DisplayName, "由", n.OldValue, "变更为", n.NewValue, ";\r\n")));
}
class PropInfo
{
public string PropName;
public string DisplayName;
public Func<object, object> GetValue;
public TradeAuditFlag AuditFlag;
public int TypeFalg;//1:double,2:double?
public override string ToString()
{
return PropName + "--" + DisplayName;
}
}
}
/// <summary>
/// 交易变更信息
/// </summary>
public class TradeChangeInfo
{
/// <summary>
/// 字段名称
/// </summary>
public string PropName { get; set; }
/// <summary>
/// 显示名称
/// </summary>
public string DisplayName { get; set; }
/// <summary>
/// 新值
/// </summary>
public string NewValue { get; set; }
/// <summary>
/// 旧值
/// </summary>
public string OldValue { get; set; }
/// <summary>
/// 审查选项
/// </summary>
public TradeAuditFlag AuditFlag { get; set; }
public bool IsChangeMsg => (AuditFlag & TradeAuditFlag.changed) == TradeAuditFlag.changMsg;
public override string ToString()
{
return $"{PropName}--{DisplayName}--new:{NewValue},old:{OldValue}";
}
}
}