470 lines
22 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|