using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using YLErp.DBModels; namespace YLErp.Modules.SwapModule { public class SwapEventService : SwapTradeBaseService { public SwapEventService(OptUserInfo optUser) : base(optUser) { } public SwapEventService(YLBaseService baseService) : base(baseService) { } /// /// 生成事件 /// /// 日期 /// 互换交易码 /// 事件类型 /// json数据 /// 是否保存 /// /// /// 是否无效 /// public swap_event AddSwapEventDate(DateTime tradeDate, int tradeId, int eventType, string data, int clientCashId, bool save = false,string eventRession="",bool invalid=false) { var swap_Event = new swap_event() { EventType = eventType, EventData = data, EventReason= eventRession, SwapTradeId = tradeId, ClientCashId = clientCashId, Invalid = invalid, ValueDate = tradeDate, }; UpdateDbOption(swap_Event); DbContext.swap_event.Add(swap_Event); if (save) { DbContext.SaveChanges(); } return swap_Event; } public swap_event UpdateSwapEvent() { var swapEvent= DbContext.swap_event.Where(x=>x.EventType== (int)SwapEventTypeEnum.新增交易 || x.EventType == (int)SwapEventTypeEnum.修改交易).OrderByDescending(o=>o.id).FirstOrDefault(); if (swapEvent!=null) { swapEvent.Invalid= false; DbContext.SaveChanges(); } return swapEvent; } /// /// 获取上一日终归档日期 /// /// 当前清算日期 /// public DateTime GetSwapEventDate(DateTime tradeDate, int tradeId, int? eventType) { Expression> expression = x => x.SwapTradeId == tradeId && x.ValueDate < tradeDate && !x.Invalid; if (eventType.HasValue) { expression = expression.And(x => x.EventType == eventType); } var swapEvent = DbContext.swap_event.Where(expression).OrderByDescending(o => o.ValueDate).FirstOrDefault(); if (swapEvent != null) { return swapEvent.ValueDate;//上一日终归档日期 } else//不存在归档日期 { return tradeDate; } } /// /// 保存展期信息 /// /// /// /// public swap_event SaveExtensionTime(swap_event swap_Event) { var obj = DbContext.swap_event.Where(O => O.id == swap_Event.id).FirstOrDefault(); var trade = DbContext.trade.Where(O => O.id == swap_Event.SwapTradeId).FirstOrDefault(); if (trade == null) { throw new ServiceException("未找到交易,请刷新页面后再次尝试!"); } var oldMaturityDate = trade.ExerciseDate.Value; if (obj != null && !string.IsNullOrEmpty(obj.EventData)) { oldMaturityDate = JsonConvert.DeserializeObject(obj.EventData).OldMaturityDate; } if (swap_Event.extenstionData.NewMaturityDate <= oldMaturityDate) { throw new ServiceException("新到期日应晚于原到期日!"); } if (obj != null && obj.ValueDate >= swap_Event.ValueDate) { throw new ServiceException("新展期日应晚于原展期日!"); } if (swap_Event.extenstionData.NewMaturityDate< trade.StartDate) { throw new ServiceException("新到期日不应早于交易开始日期!"); } swap_Event.extenstionData.OldMaturityDate = oldMaturityDate; string data = JsonConvert.SerializeObject(swap_Event.extenstionData); if (obj != null) { obj.Invalid = true; } swap_Event.EventReason = "交易展期"; trade.ExerciseDate = swap_Event.extenstionData.NewMaturityDate; //修改互换观察日到期日 new SwapTradeService(this).UpdateObservationDay(trade.id, swap_Event.extenstionData.OldMaturityDate, trade.ExerciseDate.Value); swap_Event = AddSwapEventDate(swap_Event.ValueDate, swap_Event.SwapTradeId, (int)SwapEventTypeEnum.展期, data, 0,false, swap_Event.EventReason); DbContext.SaveChanges(); return swap_Event; } /// /// 删除 展期 /// /// /// public void DeleteExtensionTime(long id) { var obj = DbContext.swap_event.Where(O => O.id == id).FirstOrDefault(); if (obj==null) { throw new ServiceException("未找到展期记录,请刷新页面后再次尝试!"); } var trade = DbContext.trade.Where(O => O.id == obj.SwapTradeId).FirstOrDefault(); obj.Invalid = true; obj.EventReason = "交易展期撤销"; if (!string.IsNullOrEmpty(obj.EventData)) { obj.extenstionData = JsonConvert.DeserializeObject(obj.EventData); //修改到期日,互换观察日 new SwapTradeService(this).UpdateObservationDay(trade.id, trade.ExerciseDate.Value, obj.extenstionData.OldMaturityDate); trade.ExerciseDate = obj.extenstionData.OldMaturityDate; } DbContext.SaveChanges(); } /// /// 获取当前展期记录 /// /// /// public swap_event GetExtensionTime(int tradeId) { var trade = DbContext.trade.Where(O => O.id == tradeId).FirstOrDefault(); if (trade == null) { throw new ServiceException("未找到交易,请刷新页面后再次尝试!"); } var extension = DbContext.swap_event.Where(x => !x.Invalid && x.SwapTradeId == tradeId && x.EventType == (int)SwapEventTypeEnum.展期).FirstOrDefault(); if (extension==null) { extension = new swap_event(); extension.SwapTradeId = tradeId; extension.ValueDate = DateTime.Now; extension.extenstionData = new ExtenstionData() { OldMaturityDate = trade.ExerciseDate.Value, NewMaturityDate=DateTime.Now }; } else { if (!string.IsNullOrEmpty(extension.EventData)) { extension.extenstionData = JsonConvert.DeserializeObject(extension.EventData); } } extension.SwapTradeNumber = trade.TradeNumber; return extension; } /// /// 获取历史展期信息 /// /// /// public List GetExtenstionTimeEvents(int tradeId) { var events= DbContext.swap_event.Where(x => x.Invalid && x.SwapTradeId == tradeId&&x.EventType==(int)SwapEventTypeEnum.展期).OrderByDescending(o => o.ValueDate).ToList(); events.ForEach(x => { if (!string.IsNullOrEmpty(x.EventData)) { x.extenstionData = JsonConvert.DeserializeObject(x.EventData); } }); return events; } /// /// 获取交易操作历史。登记日创建但尚未到 EffectiveDate 的公司行为事件也保留, /// 由 EventData.Applied=false 表示“待生效”,保证审计日志完整可追溯。 /// /// 交易id /// public List GetOpreationHistorys(int tradeId) { List list = DbContext.swap_event .Where(x => x.SwapTradeId == tradeId) .OrderByDescending(o => o.id) .ToList(); return list; } /// /// 将 swap_event.EventData 安全反序列化为公司行为快照。事件为空、EventData /// 为空白或 JSON 格式不匹配时返回 false 并将 data 置 null,调用方据此保留旧格式记录。 /// public static bool TryDeserializeCorporateActionEventData( swap_event swapEvent, out CorporateActionEventData data) { data = null; if (swapEvent == null || string.IsNullOrWhiteSpace(swapEvent.EventData)) { return false; } try { data = JsonConvert.DeserializeObject(swapEvent.EventData); return data != null; } catch (JsonException) { return false; } } /// /// 公司行为说明使用稳定的键值格式,完整保留调整前后名义本金、价格、数量、 /// 待实现分红和现金流变化,操作历史无需重新计算即可核对。 /// public static string BuildCorporateActionEventReason(CorporateActionEventData data) { if (data == null) { return "公司行为快照为空"; } // 使用 InvariantCulture 固定小数与日期格式,说明文本不随服务器区域设置变化。 string D(decimal value) => value.ToString(CultureInfo.InvariantCulture); string Date(DateTime? value) => value.HasValue ? value.Value.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) : ""; return string.Join("; ", new[] { $"公司行为[{data.UnderlyingCode}]", $"ExDividendDate={Date(data.ExDividendDate)}", $"EffectiveDate={Date(data.EffectiveDate)}", $"ExDividendInfoId={data.ExDividendInfoId}", $"PositionId={data.PositionId}", $"GiveCashAmount={D(data.GiveCashAmount)}", $"GiveShareAmount={D(data.GiveShareAmount)}", $"Split={(data.Split.HasValue ? D(data.Split.Value) : "")}", $"RationedSharesAmount={D(data.RationedSharesAmount)}", $"RationedSharesPrice={D(data.RationedSharesPrice)}", "调整前", $"BeforeNotional={D(data.BeforeNotional)}", $"BeforePrice={D(data.BeforePrice)}", $"BeforeQuantity={D(data.BeforeQuantity)}", $"BeforePendingDividend={D(data.BeforePendingDividend)}", "调整后", $"AfterNotional={D(data.AfterNotional)}", $"AfterPrice={D(data.AfterPrice)}", $"AfterQuantity={D(data.AfterQuantity)}", $"AfterPendingDividend={D(data.AfterPendingDividend)}", $"CashFlowChange={D(data.CashFlowChange)}", $"Applied={data.Applied}" }); } public void DeleteEvent(int tradeId) { var events = DbContext.swap_event.Where(x => x.Invalid && x.SwapTradeId == tradeId).ToList(); var flowEvents= DbContext.swap_flow_event.Where(x => x.DataState>0 && x.SwapTradeId == tradeId).ToList(); events.ForEach((x) => { x.Invalid = true; }); flowEvents.ForEach((x) => { x.DataState = (int)SwapFlowDateStateEnum.废弃; }); DbContext.SaveChanges(); } } }