Files
zszq-trs/YLErpDAL/Modules/SwapModule/SwapRateService.cs
T
2025-12-26 14:00:19 +08:00

470 lines
22 KiB
C#

using BaseOUDAL;
using Org.BouncyCastle.Ocsp;
using Qdp.Pricing.Library.Base.Utilities;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Linq.Dynamic.Core;
using YLErp.Helpers;
using YLErp.Model;
using YLErp.Office;
using Newtonsoft.Json;
using OfficeOpenXml;
using YieldChain.Commons;
using YLErp.Abstract;
using Microsoft.Extensions.DependencyInjection;
namespace YLErp.Modules.SwapModule
{
public class SwapRateService : YLBaseService
{
IKafkaProduce kafkaProduceHelper;
public SwapRateService(OptUserInfo userInfo) : base(userInfo)
{
kafkaProduceHelper = YLServiceLocator.ServiceProvider.GetService<IKafkaProduce>();
}
/// <summary>
/// 查询阶梯费率
/// </summary>
public SearchListResult<SwapRate> SearchList(SwapRateSearchRequest req)
{
var predicate = PredicateBuilder.Create<SwapRate>(n => 1 == 1);
if (req.OptDateStart.HasValue)
{
predicate = predicate.And(n => n.opt_time >= req.OptDateStart.Value);
}
if (req.OptDateEnd.HasValue)
{
predicate = predicate.And(n => n.opt_time <= req.OptDateEnd.Value);
}
if (req.ClientIds.Count > 0)
{
predicate = predicate.And(n => req.ClientIds.Contains(n.ClientId));
}
if (!string.IsNullOrEmpty(req.ClientNumber))
{
predicate = predicate.And(x => x.ClientNumber.Contains(req.ClientNumber.Trim()));
}
if (req.TakeEffectDate.HasValue)
{
predicate = predicate.And(n => n.TakeEffectDate == req.TakeEffectDate);
}
if (!string.IsNullOrEmpty(req.OptName))
{
predicate = predicate.And(n => n.opt_name == req.OptName);
}
var rateQuery = DbContext.swap_rate.Where(predicate);
var clientQuery = DataCacheProvider.GetClientDataSource().AsQueryable();
if (string.IsNullOrEmpty(req.sidx))
{
req.sidx = "create_time";
req.sord = "desc";
}
var retListResult = rateQuery.ToSearchList(req);
foreach (var item in retListResult.rows)
{
var client = clientQuery.FirstOrDefault(x => x.id == item.ClientId);
item.ClientName = client?.Name;
}
return retListResult;
}
/// <summary>
/// 保存互换费率
/// </summary>
/// <param name="req"></param>
/// <exception cref="Exception"></exception>
public void SaveSwapRate(SwapRate req)
{
var changeClient = DataCacheProvider.GetClientDataSource().GetData(req.ClientId);
req.ClientNumber = changeClient?.Number;
req.ClientName = changeClient?.Name;
ValidateSwapRate(req);
string changeStr = string.Empty;
string changeTitle = "新增";
if (req.id > 0)
{
var swapRate = DbContext.swap_rate.Find(req.id);
if (swapRate == null)
{
throw new ServiceException("未找到该阶梯费率");
}
var client = DataCacheProvider.GetClientDataSource().GetData(swapRate.ClientId);
swapRate.ClientNumber = client?.Number;
swapRate.ClientName = client?.Name;
var changeList = DataChangeHelper.GetDataChanges(swapRate, req);
changeStr = changeList.ToJson();
changeTitle = "编辑";
swapRate.ClientId = req.ClientId;
swapRate.ClientNumber = req.ClientNumber;
swapRate.TakeEffectDate = req.TakeEffectDate;
swapRate.TempRateIsPercent = req.TempRateIsPercent;
swapRate.TempRate = req.TempRate;
swapRate.BaseRate = req.BaseRate;
swapRate.BaseRateIsPercent = req.BaseRateIsPercent;
swapRate.DiscountAccDown = req.DiscountAccDown;
swapRate.DiscountRateIsPercent = req.DiscountRateIsPercent;
swapRate.DiscountRate = req.DiscountRate;
swapRate.FrontDeskCharge = req.FrontDeskCharge;
swapRate.FrontDeskChargeIsPercent = req.FrontDeskChargeIsPercent;
swapRate.BackDeskCharge = req.BackDeskCharge;
swapRate.BackDeskChargeIsPercent = req.BackDeskChargeIsPercent;
swapRate.OfflineRate = req.OfflineRate;
swapRate.SetOpt(UserId, UserName);
}
else
{
req.SetCreator(UserId, UserName);
req.SetOpt(UserId, UserName);
DbContext.swap_rate.Add(req);
}
DbContext.SaveChanges();
new SwapRateLogService(UserInfo).AddSwapRateLog(0, req.id, changeTitle, changeStr, null);
}
/// <summary>
/// 校验数据
/// </summary>
/// <param name="req"></param>
/// <exception cref="ServiceException"></exception>
private void ValidateSwapRate(SwapRate req)
{
if (req.BaseRate == null && req.TempRate == null)
{
throw new ServiceException("临时费率或基础费率不能为空");
}
if (req.DiscountRate.HasValue && req.DiscountAccDown == null)
{
throw new ServiceException("优惠累计量下限不能为空");
}
if (!req.DiscountRate.HasValue && req.DiscountAccDown.HasValue)
{
throw new ServiceException("优惠累计量下限有值的情况,优惠汇率不能为空");
}
if (DbContext.swap_rate.Any(x => x.ClientId == req.ClientId && x.id != req.id && x.TakeEffectDate == req.TakeEffectDate))
{
throw new ServiceException($"该客户在{req.TakeEffectDate:D}已经存在阶梯费率");
}
}
/// <summary>
/// 删除阶梯费率
/// </summary>
/// <param name="id"></param>
/// <exception cref="Exception"></exception>
public int DeleteSwapRate(int id)
{
var swapRate = DbContext.swap_rate.Find(id);
if (swapRate == null)
{
throw new ServiceException("未找到该阶梯费率");
}
DbContext.swap_rate.Remove(swapRate);
DbContext.SaveChanges();
return swapRate.ClientId;
}
/// <summary>
/// 获取详细
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <exception cref="ServiceException"></exception>
public SwapRate GetSwapRate(int id)
{
var swapRate = DbContext.swap_rate.Find(id);
if (swapRate == null)
{
throw new ServiceException("未找到该阶梯费率");
}
var client = DataCacheProvider.GetClientDataSource().GetData(swapRate.ClientId);
swapRate.ClientName = client?.Name;
swapRate.ClientNumber = client?.Number;
return swapRate;
}
/// <summary>
/// 阶梯费率导入 excel
/// </summary>
/// <param name="streamIn">上传的文件</param>
/// <param name="totalNum">总条数</param>
/// <param name="successNum">成功条数</param>
public List<int> ImportSwapRateFromExcel(Stream streamIn, out int totalNum, out int successNum)
{
totalNum = 0;
successNum = 0;
var rowIndex = 0;
List<int> clientIds = new List<int>();
var trans = DbContext.Database.BeginTransaction();
try
{
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
{
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
}
var table = ds.Tables[0];
var reader = new DataRowReaderHelper(table);
rowIndex = 1;
totalNum = table.Rows.Count - rowIndex;
var clientList = DataCacheProvider.GetClientDataSource().AsQueryable().ToList();
foreach (var row in table.Rows.Cast<DataRow>().Skip(rowIndex))
{
rowIndex++;
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
{
totalNum--;
continue;
}
reader.SetDataRow(row, rowIndex);
var swapRate = new SwapRate();
swapRate.ClientNumber = reader.GetString("客户编号", true);
swapRate.TakeEffectDate = reader.GetDate("生效日期", true).Value;
var client = clientList.FirstOrDefault(x => x.Number == swapRate.ClientNumber);
if (client == null)
{
throw new ServiceException($"找不到客户编号为{swapRate.ClientNumber}的客户");
}
swapRate.ClientId = client.id;
clientIds.Add(client.id);
var tempRate = reader.GetString("临时费率");
if (!string.IsNullOrEmpty(tempRate))
{
decimal rate = 0;
if (tempRate.EndsWith("%"))
{
swapRate.TempRateIsPercent = true;
tempRate = tempRate.Replace("%", "");
decimal.TryParse(tempRate, out rate);
rate = rate / 100;
}
else
{
swapRate.TempRateIsPercent = false;
decimal.TryParse(tempRate, out rate);
}
swapRate.TempRate = rate;
}
var baseRate = reader.GetString("基础费率");
if (!string.IsNullOrEmpty(baseRate))
{
decimal rate = 0;
if (baseRate.EndsWith("%"))
{
swapRate.BaseRateIsPercent = true;
baseRate = baseRate.Replace("%", "");
decimal.TryParse(baseRate, out rate);
rate = rate / 100;
}
else
{
swapRate.BaseRateIsPercent = false;
decimal.TryParse(baseRate, out rate);
}
swapRate.BaseRate = rate;
}
var disAccRate = reader.GetString("优惠费率");
if (!string.IsNullOrEmpty(disAccRate))
{
decimal rate = 0;
if (disAccRate.EndsWith("%"))
{
swapRate.DiscountRateIsPercent = true;
disAccRate = disAccRate.Replace("%", "");
decimal.TryParse(disAccRate, out rate);
rate = rate / 100;
}
else
{
swapRate.DiscountRateIsPercent = false;
decimal.TryParse(disAccRate, out rate);
}
swapRate.DiscountRate = rate;
}
var frontRate = reader.GetString("现券对冲交易费用");
if (!string.IsNullOrEmpty(frontRate))
{
if (frontRate.EndsWith("‱"))
{
swapRate.FrontDeskChargeIsPercent = true;
frontRate = frontRate.Replace("‱", "");
}
decimal.TryParse(frontRate, out var rate);
swapRate.FrontDeskCharge = rate * 0.0001m;
}
var backRate = reader.GetString("现券对冲结算费用");
if (!string.IsNullOrEmpty(backRate))
{
if (backRate.EndsWith("‱"))
{
swapRate.BackDeskChargeIsPercent = true;
backRate = backRate.Replace("‱", "");
}
decimal.TryParse(backRate, out var rate);
swapRate.BackDeskCharge = rate * 0.0001m;
}
swapRate.DiscountAccDown = reader.GetDecimal("优惠累计量下限");
ValidateSwapRate(swapRate);
swapRate.SetCreator(UserId, UserName);
swapRate.SetOpt(UserId, UserName);
DbContext.swap_rate.Add(swapRate);
DbContext.SaveChanges();
new SwapRateLogService(UserInfo).AddSwapRateLog(0, swapRate.id, "新增", null, "导入");
successNum++;
}
trans.Commit();
trans.Dispose();
return clientIds;
}
catch (Exception ex)
{
trans.Rollback();
trans.Dispose();
LogFactory.GetLogger("导入阶梯费率").Error(ex);
throw new ServiceException($"第{rowIndex}行,发生错误:{ex.Message}");
}
}
/// <summary>
/// 阶梯费率导出
/// </summary>
/// <param name="req"></param>
/// <returns></returns>
/// <exception cref="ServiceException"></exception>
public byte[] exprotSwapRateExcel(SwapRateSearchRequest req)
{
//获取数据
var ret = SearchList(req);
List<SwapRateExportModel> list = new List<SwapRateExportModel>();
foreach (var item in ret.rows)
{
SwapRateExportModel exportModel = new SwapRateExportModel();
exportModel.ClientNumber = item.ClientNumber;
exportModel.ClientName = item.ClientName;
exportModel.TakeEffectDate = item.TakeEffectDate.OtcFormatDate();
exportModel.BaseRate = item.BaseRateIsPercent ? item.BaseRate.OtcFormatPercent(4) : item.BaseRate.OtcFormatMoney(true);
exportModel.TempRate = item.TempRateIsPercent ? item.TempRate.OtcFormatPercent(4) : item.TempRate.OtcFormatMoney(true);
exportModel.DiscountRate = item.DiscountRateIsPercent ? item.DiscountRate.OtcFormatPercent(4) : item.DiscountRate.OtcFormatMoney(true);
exportModel.DiscountAccDown = item.DiscountAccDown.OtcFormatMoney(true);
exportModel.FrontDeskCharge = item.FrontDeskChargeIsPercent == true ? item.FrontDeskCharge.OtcFormatTenThousandsPercent(4) : item.FrontDeskCharge.OtcFormatMoney(true);
exportModel.BackDeskCharge = item.BackDeskChargeIsPercent == true ? item.BackDeskCharge.OtcFormatTenThousandsPercent(4) : item.BackDeskCharge.OtcFormatMoney(true);
exportModel.OfflineRate = item.OfflineRate.OtcFormatTenThousandsPercent(4);
list.Add(exportModel);
}
var tplFilePath = OtcAppContext.MapPath("/App_Docs");
var sourceFileName = Path.Combine(tplFilePath, "导出模板", "阶梯费率导出模板.xlsx");
var modelDict = new Dictionary<string, object>();
var model = new { list = list };
modelDict.Add("Sheet1", model);
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
return new ExcelTemplateGenerator().SetTemplateFile(sourceFileName).SetTemplateData(modelDict).Output();
}
/// <summary>
/// 将最新的费率发送到kafka
/// </summary>
/// <param name="clientId"></param>
/// <param name="kafkaProvider"></param>
public void SendSwapRateToKafka(int clientId)
{
var swapRate = GetClientSwapRate(clientId);
if (swapRate == null)
{
swapRate = new SwapRate()
{
ClientId = clientId,
};
}
var monthStart = GetMonthStart();
var clientPosiNotional = DbContext.trade.Where(x => x.TradeDate >= monthStart
&& x.ValidState != ConsGlobal.InValid
&& x.TradeType == "收益互换"
&& x.ClientId == clientId
&& ConsTrade.TradeStatusCustomexport.Contains(x.TradeStatus)).ToList().Sum(s => s.OriginalStockEqvNotional ?? 0);
SendToKafka(swapRate, clientPosiNotional);
}
public void SendAllSwapRateToKafka()
{
var swapRates = DbContext.swap_rate.Where(x => x.TakeEffectDate <= DateTime.Now.Date).ToList().GroupBy(g => g.ClientId).Select(g => g.OrderByDescending(o => o.TakeEffectDate).FirstOrDefault()).ToList();
var swapRateAll = DbContext.swap_rate
.Where(x => x.ClientId == 0 && x.TakeEffectDate <= DateTime.Now.Date)
.OrderByDescending(o => o.TakeEffectDate)
.FirstOrDefault();
var monthStart = GetMonthStart();
// 预计算客户持仓总额(在数据库端完成聚合)
var posiNotionalValues = DbContext.trade
.Where(x => x.TradeDate >= monthStart &&
x.ValidState != ConsGlobal.InValid &&
x.TradeType == "收益互换" &&
ConsTrade.TradeStatusCustomexport.Contains(x.TradeStatus))
.GroupBy(x => x.ClientId)
.Select(g => new
{
ClientId = g.Key,
Total = g.Sum(s => s.OriginalStockEqvNotional ?? 0)
})
.AsNoTracking()
.ToDictionary(x => x.ClientId, x => x.Total);
using ClientDBContext clientDBContext = new ClientDBContext();
var clients = clientDBContext.client.Where(x => x.ProcessStatus == "已开户").AsQueryable().ToList();
foreach (var client in clients)
{
SwapRate swapRate = swapRates.FirstOrDefault(s => s.ClientId == client.id);
if (swapRate == null)
{
swapRate = swapRateAll;
}
if (swapRate == null)
{
swapRate = new SwapRate() { ClientId = client.id };
}
else
{
swapRate.ClientId= client.id;
}
posiNotionalValues.TryGetValue(client.id, out var clientPosiNotional);
SendToKafka(swapRate,clientPosiNotional);
}
}
/// <summary>
/// 获取月初
/// </summary>
/// <returns></returns>
private DateTime GetMonthStart()
{
DateTime currentDate = DateTime.Today; // 获取当前日期(包括当前年月日)
DateTime monthStart = new DateTime(currentDate.Year, currentDate.Month, 1);
return monthStart;
}
private void SendToKafka(SwapRate swapRate, double clientPosiNotional)
{
SwapRateKafkaModel swapRateKafkaModel = new SwapRateKafkaModel();
swapRateKafkaModel.clientId = swapRate.ClientId;
swapRateKafkaModel.frontDeskCharge = swapRate.FrontDeskCharge ?? 0;
swapRateKafkaModel.isFrontDeskChargePercent = swapRate.FrontDeskChargeIsPercent ?? true;
swapRateKafkaModel.backDeskCharge = swapRate.BackDeskCharge ?? 0;
swapRateKafkaModel.isBackDeskChargePercent = swapRate.BackDeskChargeIsPercent ?? true;
if (swapRate.TempRate.HasValue)
{
swapRateKafkaModel.isRate = swapRate.TempRateIsPercent;
swapRateKafkaModel.rate = swapRate.TempRate ?? 0;
}
else
{
swapRateKafkaModel.isRate = swapRate.BaseRateIsPercent;
swapRateKafkaModel.rate = swapRate.BaseRate ?? 0;
swapRateKafkaModel.disRateDown = swapRate.DiscountAccDown ?? 0;
if (swapRate.DiscountAccDown.HasValue && Convert.ToDecimal(clientPosiNotional) >= swapRateKafkaModel.disRateDown)
{
swapRateKafkaModel.isDisRate = swapRate.DiscountRateIsPercent;
swapRateKafkaModel.disRate = swapRate.DiscountRate ?? 0;
swapRateKafkaModel.rate = swapRateKafkaModel.disRate;
}
}
kafkaProduceHelper.Produce(Environment.GetEnvironmentVariable("KafkaConfig_ClientRateTopic"), JsonConvert.SerializeObject(swapRateKafkaModel));
}
private SwapRate GetClientSwapRate(int clientId)
{
return DbContext.swap_rate.Where(x => x.ClientId == clientId && x.TakeEffectDate <= DateTime.Now.Date).OrderByDescending(o => o.TakeEffectDate).FirstOrDefault();
}
}
}