从山证v2.3.0拷贝

This commit is contained in:
吴方海
2024-05-09 14:06:26 +08:00
parent 566ff33259
commit f9d8a256a6
4471 changed files with 1203456 additions and 9 deletions
@@ -0,0 +1,142 @@
using NPOI.SS.Formula.Functions;
using YLErp.DBModels.Consts;
namespace YLErp.Modules.AppModule
{
/// <summary>
/// AppConfigService
/// </summary>
public class AppConfigService : YLBaseService
{
public AppConfigService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// 获取管理密码
/// </summary>
public string GetAdminPwd()
{
return DbContext.AppConfig.Where(n => n.PGroup == ConsAppConfig.System && n.PName == ConsAppConfig.AdminPwd)
.Select(n => n.PValue).FirstOrDefault();
}
/// <summary>
/// 验证管理密码
/// </summary>
public bool ValidateAdminPwd(string pwd)
{
return GetAdminPwd() == pwd;
}
/// <summary>
/// 重置管理密码
/// </summary>
public string ResetAdminPwd()
{
var config = DbContext.AppConfig.FirstOrDefault(n => n.PGroup == ConsAppConfig.System && n.PName == ConsAppConfig.AdminPwd);
if (config == null)
{
config = new AppConfig
{
PGroup = ConsAppConfig.System,
PName = ConsAppConfig.AdminPwd,
CreateTime = DateTime.Now,
PType = "string",
Remark = "系统管理密码"
};
}
config.PValue = Guid.NewGuid().ToString("N") + Guid.NewGuid().ToString("N");
DbContext.SaveChanges();
return config.PValue;
}
/// <summary>
///
/// </summary>
public int SaveOtcFormatConfig(string configValue)
{
var config = DbContext.AppConfig.FirstOrDefault(
n => n.PGroup == ConsAppConfig.ProjectConfig && n.PName == ConsAppConfig.OtcFormatConfig);
if (config == null)
{
config = new AppConfig
{
PGroup = ConsAppConfig.ProjectConfig,
PName = ConsAppConfig.OtcFormatConfig,
CreateTime = DateTime.Now,
PType = "string",
Remark = "OTC格式化配置"
};
DbContext.AppConfig.Add(config);
}
config.PValue = configValue;
return DbContext.SaveChanges();
}
public int SaveYLWebApiConfig(string configValue)
{
using (var db = DbContextFactory.GetYLDbContext())
{
var data = db.AppConfig.FirstOrDefault(n => n.PGroup == ConsAppConfig.ProjectConfig && n.PName == ConsAppConfig.YLErpWebUrlConfig);
if (data == null)
{
data = new AppConfig()
{
PGroup = ConsAppConfig.ProjectConfig,
PName = ConsAppConfig.YLErpWebUrlConfig,
PValue = configValue,
PType = "string",
Remark = "YLErp Web服务地址"
};
db.AppConfig.Add(data);
}
else
{
// 如果已经存在数据就不更新
if (string.IsNullOrEmpty(data.PValue))
{
data.PValue = configValue;
}
}
return db.SaveChanges();
}
}
/// <summary>
/// 如果不存在,则添加为新数据,否则更新
/// </summary>
public int SaveConfig(string pgroup, string pname, string pvalue, string ptype, string remark)
{
if (string.IsNullOrWhiteSpace(pgroup))
{
throw new ArgumentNullException(nameof(pgroup));
}
if (string.IsNullOrWhiteSpace(pname))
{
throw new ArgumentNullException(nameof(pname));
}
var data = DbContext.AppConfig.FirstOrDefault(n => n.PGroup == pgroup && n.PName == pname);
if (data == null)
{
data = new AppConfig
{
CreateTime = DateTime.Now,
PGroup = pgroup,
PName = pname
};
DbContext.AppConfig.Add(data);
}
data.PType = ptype;
data.Remark = remark;
data.PValue = pvalue;
return DbContext.SaveChanges();
}
}
}
@@ -0,0 +1,398 @@
using Autofac;
using DocumentFormat.OpenXml.Spreadsheet;
using Newtonsoft.Json;
using Org.BouncyCastle.Asn1.Ocsp;
using System.Reflection;
using System.Runtime.CompilerServices;
using YieldChain.Commons;
using YieldChain.Helpers;
using YLErp.Cache;
using YLErp.DBModels.Consts;
using YLErp.Models;
namespace YLErp.Modules.AppModule
{
partial class AppInitializer
{
readonly InnerAppConfigService configService;
public AppInitializer()
{
configService = new InnerAppConfigService();
}
/// <summary>
/// 初始化项目配置文件
/// </summary>
public void InitializePsConfig(SmtpConfigHandler smtpConfigHandler)
{
var items = configService.GetAllDatas().Where(a => a.PGroup == "ProjectConfig").ToArray();
var dic = new Dictionary<string, object>();
foreach (var item in items)
{
if (string.IsNullOrWhiteSpace(item.PName) || string.IsNullOrWhiteSpace(item.PValue))
{
continue;
}
var pname = item.PName;
var index = pname.IndexOf('.');
pname = pname.Substring(index + 1).Trim();
if ("bool".Equals(item.PType, StringComparison.OrdinalIgnoreCase))
{
dic[pname] = "true".Equals(item.PValue, StringComparison.OrdinalIgnoreCase);
}
else
{
dic[pname] = item.PValue;
}
}
PS.ResetConfig(Newtonsoft.Json.JsonConvert.SerializeObject(dic));
//邮件发送配置
var smptConfig = configService.GetData("ProjectConfig", "Erp.SendMailConfig");
if (!string.IsNullOrWhiteSpace(smptConfig?.PValue) && smtpConfigHandler != null)
{
smtpConfigHandler.ResetConfig(smptConfig.PValue);
}
}
public void InitialRedisConfig()
{
var cacheConfig =JsonConvert.DeserializeObject<CacheConfig>(configService.GetData("ProjectConfig", "Erp.RedisConfig")?.PValue ?? string.Empty)??new CacheConfig();
YLServiceLocator.ServiceCollection.AddYLCache(opt =>
{
opt.Enable = cacheConfig.Enable;
opt.ConnectionString= cacheConfig.ConnectionString;
opt.DataBaseNum = cacheConfig.DataBaseNum;
opt.CustomPrefix = cacheConfig.CustomPrefix;
if (string.IsNullOrEmpty(opt.CustomPrefix))
{
opt.CustomPrefix = ((int)PS.Config.Company).ToString();
}
});
}
/// <summary>
///
/// </summary>
public string GetOtcFormatConfig()
{
return configService.GetData(ConsAppConfig.ProjectConfig, ConsAppConfig.OtcFormatConfig)?.PValue;
}
/// <summary>
/// 初始化插件
/// </summary>
public static PluginInfo InitializePlugin(out IContainer container)
{
container = null;
var pluginFolder = Environment.GetEnvironmentVariable("AppSettings:PluginFolder");
if (string.IsNullOrEmpty(pluginFolder))
{
if (OtcAppContext.MapPath != null)
{
pluginFolder = OtcAppContext.MapPath("~/App_Plugin");
if (!Directory.Exists(pluginFolder))
{
pluginFolder = Path.Combine(AppContext.BaseDirectory, "App_Plugin");
}
}
}
var info = new PluginInfo
{
PluginFolder = pluginFolder
};
if (!Directory.Exists(pluginFolder))
{
info.LoadMessage = "插件目录不存在!";
return info;
}
Environment.SetEnvironmentVariable("AppSettings:PluginFolder", pluginFolder);
//加载并注册插件
var iocBuilder = new ContainerBuilder();
var dllFiles = Directory.GetFiles(pluginFolder, "YLErp.Plugins.*.dll");
foreach (var dllFile in dllFiles)
{
if (dllFile.LastIndexOf(".Abstract.") < 0)
{
var assembly = Assembly.Load(File.ReadAllBytes(dllFile));
iocBuilder.RegisterAssemblyTypes(assembly).AsImplementedInterfaces();
info.LoadMessage += assembly.FullName + ";";
}
}
if (string.IsNullOrEmpty(info.LoadMessage))
{
info.LoadMessage = "未加载到任何插件!";
}
else
{
info.LoadMessage = "加载插件:" + info.LoadMessage;
}
container = iocBuilder.Build();
return info;
}
/// <summary>
/// 获取 某个配置值
/// </summary>
/// <param name="groupName"></param>
/// <param name="key"></param>
/// <returns></returns>
public string GetConfigValue(string groupName,string key)
{
return configService.GetValue(groupName, key);
}
public void SetConfigValue(string groupName, string key,string value,string remark)
{
configService.AddDataIfNotExists(groupName, key, value,"string", remark,true);
configService.SaveChanges();
}
private static void CopyPluginFiles(string srcDirPath, string destDirPath, int depth = 0)
{
var srcDir = new DirectoryInfo(srcDirPath);
var srcDirs = srcDir.GetDirectories();
if (!Directory.Exists(destDirPath))
{
Directory.CreateDirectory(destDirPath);
}
var srcFiles = srcDir.GetFiles();
foreach (FileInfo file in srcFiles)
{
if (depth == 0 && !file.Name.StartsWith("YLErp.Plugins.", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string destFile = Path.Combine(destDirPath, file.Name);
file.CopyTo(destFile, true);
}
foreach (DirectoryInfo subdir in srcDirs)
{
string destDir = Path.Combine(destDirPath, subdir.Name);
CopyPluginFiles(subdir.FullName, destDir, depth + 1);
}
}
/// <summary>
/// 内部数据访问类
/// </summary>
class InnerAppConfigService : YLBaseService
{
Dictionary<string, AppConfig> configDic;
public InnerAppConfigService() : base(OptUserInfo.SystemUser)
{
}
public Dictionary<string, AppConfig> ConfigDic
{
get
{
configDic ??= DbContext.AppConfig.ToDictionary(n => GetDicKey(n.PGroup, n.PName), StringComparer.OrdinalIgnoreCase);
return configDic;
}
}
/// <summary>
/// 获取所有数据
/// </summary>
public IEnumerable<AppConfig> GetAllDatas()
{
return ConfigDic.Values;
}
/// <summary>
/// 获取数据
/// </summary>
public AppConfig GetData(string group, string name)
{
return ConfigDic.TryGetValue(GetDicKey(group, name), out AppConfig appConfig) ? appConfig : null;
}
/// <summary>
/// 获取数据
/// </summary>
public string GetValue(string group, string name)
{
return ConfigDic.TryGetValue(GetDicKey(group, name), out AppConfig appConfig) ? appConfig?.PValue : null;
}
/// <summary>
/// 添加配置数据
/// </summary>
public void AddData(AppConfig item)
{
if (string.IsNullOrWhiteSpace(item.PGroup))
{
throw new ArgumentNullException("item.PGroup");
}
if (string.IsNullOrWhiteSpace(item.PName))
{
throw new ArgumentNullException("item.PName");
}
item.PGroup = item.PGroup.Trim();
item.PName = item.PName.Trim();
var key = GetDicKey(item.PGroup, item.PName);
if (ConfigDic.ContainsKey(key))
{
throw new ArgumentException("已存在相同主键的数据");
}
DbContext.AppConfig.Add(item);
ConfigDic.Add(key, item);
}
/// <summary>
/// 删除配置数据
/// </summary>
public AppConfig RemoveData(string group, string name)
{
if (string.IsNullOrWhiteSpace(group))
{
throw new ArgumentNullException(nameof(group));
}
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException(nameof(name));
}
var key = GetDicKey(group.Trim(), name.Trim());
if (ConfigDic.TryGetValue(key, out AppConfig config))
{
DbContext.AppConfig.Remove(config);
ConfigDic.Remove(key);
return config;
}
return null;
}
/// <summary>
/// 更新配置数据
/// </summary>
public void UpdateData(string group, string name, string newRemark)
{
if (string.IsNullOrWhiteSpace(group))
{
throw new ArgumentNullException(nameof(group));
}
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException(nameof(name));
}
var key = GetDicKey(group.Trim(), name.Trim());
if (ConfigDic.TryGetValue(key, out AppConfig config))
{
config.Remark = newRemark;
}
}
/// <summary>
/// 更新配置数据(如果不存在则添加),
/// oldItem需要PGroup和PName
/// </summary>
public void UpdateData(AppConfig oldItem, AppConfig newItem)
{
if (string.IsNullOrWhiteSpace(oldItem.PGroup))
{
throw new ArgumentNullException("oldItem.PGroup");
}
if (string.IsNullOrWhiteSpace(oldItem.PName))
{
throw new ArgumentNullException("oldItem.PName");
}
if (string.IsNullOrWhiteSpace(newItem.PGroup))
{
throw new ArgumentNullException("newItem.PGroup");
}
if (string.IsNullOrWhiteSpace(newItem.PName))
{
throw new ArgumentNullException("newItem.PName");
}
ObjectHelper.TrimPropertyValues(oldItem);
ObjectHelper.TrimPropertyValues(newItem);
var oldKey = GetDicKey(oldItem.PGroup, oldItem.PName);
var newKey = GetDicKey(newItem.PGroup, newItem.PName);
if (oldKey.Equals(newKey, StringComparison.OrdinalIgnoreCase) && configDic.TryGetValue(oldKey, out oldItem))
{
UpdateChanges(oldItem, newItem);
}
else
{
configDic.Remove(oldKey);
configDic[newKey] = newItem;
DbContext.AppConfig.Add(newItem);
}
}
/// <summary>
/// 如果不存在,则添加为新数据
/// </summary>
public bool AddDataIfNotExists(string pgroup, string pname, string pvalue, string ptype, string remark,bool modify=false)
{
if (string.IsNullOrWhiteSpace(pgroup))
{
throw new ArgumentNullException(nameof(pgroup));
}
if (string.IsNullOrWhiteSpace(pname))
{
throw new ArgumentNullException(nameof(pname));
}
pgroup = pgroup.Trim();
pname = pname.Trim();
var key = GetDicKey(pgroup, pname);
var appConfig = new AppConfig
{
PGroup = pgroup,
PName = pname,
PValue = pvalue,
PType = ptype,
Remark = remark,
CreateTime = DateTime.Now
};
if (!ConfigDic.ContainsKey(key))
{
DbContext.AppConfig.Add(appConfig);
ConfigDic.Add(key, appConfig);
return true;
}
if (modify)
{
var oldAppconfig = ConfigDic[key];
UpdateChanges(oldAppconfig, appConfig);
ConfigDic[key] = appConfig;
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static string GetDicKey(string group, string name)
{
return string.Concat(group, "\t\f\t", name);
}
public void SaveChanges()
{
DbContext.SaveChanges();
}
}
}
}
+460
View File
@@ -0,0 +1,460 @@
using System.Xml.Linq;
namespace YLErp.Modules.AppModule
{
partial class AppInitializer
{
/// <summary>
/// 系统升级
/// </summary>
public void UpgradSystem(Version appVersion)
{
Task.Run(UpgradeDictionaries);
var versionConfig = configService.GetData("System", "Version");
if (versionConfig == null)
{
versionConfig = new AppConfig
{
PGroup = "System",
PName = "Version",
PValue = "0",
PType = "decimal",
Remark = "系统版本",
CreateTime = DateTime.Now
};
configService.AddData(versionConfig);
}
//解析appconfig表中的程序版本
//Version.TryParse(versionConfig.PValue, out var version);
//升级程序配置
UpgradeAppConfig(configService);
UpgradeAppConfigV2(configService);
versionConfig.PValue = appVersion.ToString();
configService.SaveChanges();
}
/// <summary>
/// 升级配置
/// </summary>
private static void UpgradeAppConfig(InnerAppConfigService configService)
{
configService.AddDataIfNotExists("System", "Guid", Guid.NewGuid().ToString("N"), "string", "系统GUID");
configService.AddDataIfNotExists("System", "AdminPwd", Guid.NewGuid().ToString("N") + Guid.NewGuid().ToString("N"), "string", "系统管理密码");
//-----------------------------------------------
// 1.9
//-----------------------------------------------
configService.AddDataIfNotExists("ProjectConfig", "Client.CanSelectCreditVariety", "false",
"bool", "默认True需要设置限制的交易品种, 如果为false,新增授信页不限制交易品种,不用显示“是否限制交易品种”选项");
configService.AddDataIfNotExists("ProjectConfig", "Client.BankOnlyDropDown", "true", "bool", "银行账户只能在下拉中选择,不可以手动输入");
configService.AddDataIfNotExists("ProjectConfig", "Client.IsCreditLimit", "false", "bool", "授信控制");
configService.AddDataIfNotExists("ProjectConfig", "Erp.AutoGenerateContracts", "true", "bool", "自动生成确认书");
configService.AddDataIfNotExists("ProjectConfig", "Erp.Company", "国泰君安", "CompanyEnum", "");
configService.AddDataIfNotExists("ProjectConfig", "Erp.CompanyAbbreviation", "GTJA", "string", "公司名称缩写");
configService.AddDataIfNotExists("ProjectConfig", "Erp.CompanyName", "国泰君安风险管理有限公司", "string", "公司名称");
configService.AddDataIfNotExists("ProjectConfig", "Erp.CompanyEnName", "ContryGoodBroFine", "string", "公司英文名称");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ComponentVersion", "MarketMaker", "ComponentVersion", "部署组件版本");
configService.AddDataIfNotExists("ProjectConfig", "Erp.CompanyFullName", "国泰君安风险管理有限公司", "string", "机构完整名称");
configService.AddDataIfNotExists("ProjectConfig", "Erp.EodSendMaturityEmail", "true", "bool", "结算完成是,是否发送近期到期交易报告");
configService.AddDataIfNotExists("ProjectConfig", "Erp.IsExportEntryexit", "true", "bool", "是否导出出金单");
configService.AddDataIfNotExists("ProjectConfig", "Erp.IsPVRounded", "false", "bool", "持仓市值是否进行四舍五入处理");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ShowAccruedTotalPnL", "false", "bool", "是否展示已清仓包含累积盈亏的对冲信息");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ShowOtherClientCash", "false", "bool", "资金记录页面是否显示和客户的其他资金往来记录");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseHedgingRule", "true", "bool", "是否在风险对冲页面采用自动对冲策略");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseOldGenerateBook", "true", "bool", "");
configService.AddDataIfNotExists("ProjectConfig", "Erp.VolMode", "TradeVol", "VolModeEnum", "波动率模式,TradeVol(支持平仓开仓波动率) 和 VolSurface");
configService.AddDataIfNotExists("ProjectConfig", "Erp.RealTimeServiceNotifyRoles", "系统管理员,风控,交易员", "string", "RealTime相关信息通知的角色");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ShowRealTimeServiceNotify", "true", "bool", "是否显示RealTime相关信息通知");
configService.AddDataIfNotExists("ProjectConfig", "Erp.SupportEntryExitSimpleVersion", "false", "bool", "是否支持简洁版的出入金导入");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseSingleLogin", "false", "bool", "是否用户登录会相互排斥登录状态");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseOldEodPnLExplainer", "false", "bool", "在收盘时使用老的EodPnLExplainer方法");
configService.AddDataIfNotExists("ProjectConfig", "Erp.AtmQuotePreviousBizDayAdjust", "true", "bool", "平值期权报价,当到期日是非交易日时,是否向前移;如果false,则向后移");
configService.AddDataIfNotExists("ProjectConfig", "Trade.AmendableAfterConfirm", "True", "bool", "是否成交确认后可以修改默认false");
configService.AddDataIfNotExists("ProjectConfig", "Trade.GenerateAmendDoc", "false", "bool", "如果为true,在保存修改信息时,生成一个交易变更确认书文档并下载");
configService.AddDataIfNotExists("ProjectConfig", "Trade.SingleExecutionTemplate", "False", "bool", "美式提前行权是否和到期行权用相同的结算单模板),默认值为True");
configService.AddDataIfNotExists("ProjectConfig", "Trade.ExecuteAfterGeneratedConfirmDoc", "false", "bool", "平仓行权时是否检查确认书是否生成");
//-----------------------------------------------
// 2.0
//-----------------------------------------------
configService.AddDataIfNotExists("ProjectConfig", "Erp.SkewMapVolConstruction", "false", "bool", "是否采用SkewMap的方法构造波动率,目前只有光大光子为true");
configService.AddDataIfNotExists("ProjectConfig", "Erp.PrecisionOfMinuteInQuote", "false", "bool", "在报价中,TTM是否精确到分钟级别");
configService.AddDataIfNotExists("ProjectConfig", "Erp.VolSurfaceKeyDateShift", "None", "VolSurfaceKeyDateShiftEnum", "波动率曲面上的日期节点的shift规则");
configService.AddDataIfNotExists("ProjectConfig", "Erp.VolSurfaceTermExcludeEndDate", "false", "bool", "波动率曲面的期限,是否不包含截止日期");
configService.AddDataIfNotExists("ProjectConfig", "Erp.NonInterBankMarginNetting", "true", "bool", "非同业之前计算预付金时是否有轧差");
configService.AddDataIfNotExists("ProjectConfig", "Erp.TapConsoleWebServer", "", "string", "TapConsoleWebServer");
configService.AddDataIfNotExists("ProjectConfig", "Erp.VolMoreAccurate", "false", "bool", "是否使用更加精确的波动率");
configService.AddDataIfNotExists("ProjectConfig", "Erp.HasClientSide", "false", "bool", "是否包含客户端");
configService.AddDataIfNotExists("ProjectConfig", "Erp.HasClientSign", "false", "bool", "客户端是否可以注册");
configService.AddDataIfNotExists("ProjectConfig", "Erp.TwoSideMargin", "false", "bool", "双向预付金");
configService.AddDataIfNotExists("ProjectConfig", "Erp.NeedShowSpv", "false", "bool", "是否展示计算维持预付金的Spv");
configService.AddDataIfNotExists("ProjectConfig", "Erp.PositionDetialShowMargin", "false", "bool", "结算报告是否显示持仓预付金");
//-----------------------------------------------
// 2.1
//-----------------------------------------------
var config = configService.GetData("ProjectConfig", "Erp.SendMailConfig");
if (config == null)
{
config = new AppConfig
{
PGroup = "ProjectConfig",
PName = "Erp.SendMailConfig",
PType = "text",
PValue = string.Empty,
Remark = "邮件发送配置(格式:&server=192.168.1.1&port=25&userName=test@test.com&password=123456&enableSsl=false|true)",
CreateTime = DateTime.Now
};
configService.AddData(config);
}
//-----------------------------------------------
// 3.4
//-----------------------------------------------
configService.AddDataIfNotExists("ProjectConfig", "Erp.ClientFileAudit", "false", "bool", "客户上传文件审核是否启用");
var str = @"
[{
""Group"": ""资质核实"",
""Titles"": [""营业执照副本复印件"", ""法定代表人身份证复印件"", ""签约代理人身份证复印件(若有)""]
}, {
""Group"": ""开户资料完成情况"",
""Titles"": [""投资者基本信息表(机构)"", ""回访""]
}, {
""Group"": ""专业客户资料审核情况"",
""Titles"": [""协会的复函或经营金融业务许可证""]
}, {
""Group"": ""客户资格审查"",
""Titles"": [""资料是否齐全"", ""资料是否合格"", ""能否参与交易""]
}]
";
configService.AddDataIfNotExists("ProjectConfig", "Erp.ClientFileAuditItems", str, "string", "客户上传文件审核记录");
//-----------------------------------------------
// 3.6
//-----------------------------------------------
str = configService.GetValue("ProjectConfig", "Erp.Company") ?? "公司";
configService.AddDataIfNotExists("ProjectConfig", "Erp.CompanyShortName", str, "string", "公司简称");
configService.AddDataIfNotExists("ProjectConfig", "Erp.CompanyID", str, "string", "公司ID(由镒链分配)");
//-----------------------------------------------
// 3.7
//-----------------------------------------------
configService.AddDataIfNotExists("ProjectConfig", "Erp.CheckPassword", "false", "bool", "是否检查密码符合监管要求");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UnderlyingBlockConfig", "&block1=&block2=&block3=&block4=&block5=", "string", "板块性质别名配置");
//-----------------------------------------------
// 3.9
//-----------------------------------------------
configService.AddDataIfNotExists("ProjectConfig", "Erp.UpperTradeNumber", "true", "bool", "交易编号必须大写");
configService.AddDataIfNotExists("ProjectConfig", "Erp.CanSetTradePremium", "false", "bool", "能否设置和导出成交溢价和了结溢价");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ExchangeOptionSettleByPrice", "false", "bool", "场内期权是否使用行情价收盘");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseStockEqvNotionalMax", "false", "bool", "多标的组合交易时使用单标的最大名义本金");
//-----------------------------------------------
// 3.10
//-----------------------------------------------
configService.AddDataIfNotExists("ProjectConfig", "Erp.QdpParallelDegree", "4", "int", "Qdp计算的并行度,小于等于1时代表不并行;该数字不要超过机器的CPU核数");
//configService.AddDataIfNotExists("ProjectConfig", "Erp.CalculatePnlExplain", "false", "bool", "是否计算盈亏分解指标");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ExternalPricingServiceUrl", "", "string", "外部定价计算服务的Url地址");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ConfirmBookStampStatus", "false", "bool", "确认书用印记录");
configService.AddDataIfNotExists("ProjectConfig", "Erp.CalcAutocallGreeksInRisk", "false", "bool", "是否在实时风险中计算凤凰和雪球的所有greeks");
configService.AddDataIfNotExists("ProjectConfig", "Erp.CanEditTradeNumber", "true", "bool", "交易编号是否允许修改");
//-----------------------------------------------
// 3.11
//-----------------------------------------------
configService.AddDataIfNotExists("PrivateConfig", "快速收盘", "false", "bool", "是否收盘时只结算PV");
configService.AddDataIfNotExists("ProjectConfig", "Erp.IsStockMargin", "false", "bool", "是否是权益类预付金算法");
configService.AddDataIfNotExists("ProjectConfig", "Erp.SecuritiesEnvironment", "false", "bool", "券商环境");
var data = configService.RemoveData("ProjectConfig", "OnlySettlementBoolPage");
configService.AddDataIfNotExists("ProjectConfig", "SettlementPageV2", data?.PValue ?? "false", "bool", "使用结算确认书页面");
data = configService.RemoveData("ProjectConfig", "RemotePath");
configService.AddDataIfNotExists("ProjectConfig", "SAC_RemotePath", data?.PValue ?? "", "string", "远程地址,如果是共享目录,应填ip,例:192.168.1.200;如果是ftp,应填ftp:\\\\192.168.1.200:21");
configService.AddDataIfNotExists("ProjectConfig", "SAC_RemotePath_Outbox", data?.PValue ?? "", "string", "发件箱远程登录地址,不填则使用SAC_RemotePath,如果是共享目录,应填ip,例:192.168.1.200;如果是ftp,应填ftp:\\\\192.168.1.200:21");
data = configService.RemoveData("ProjectConfig", "RemoteUser");
configService.AddDataIfNotExists("ProjectConfig", "SAC_RemoteUser", data?.PValue ?? "", "string", "登录远程地址的用户名,例:administrator");
data = configService.RemoveData("ProjectConfig", "RemotePassword");
configService.AddDataIfNotExists("ProjectConfig", "SAC_RemotePassword", data?.PValue ?? "", "string", "登录远程地址的密码,例:11");
configService.AddDataIfNotExists("ProjectConfig", "SAC_EnableSsl", data?.PValue ?? "false", "bool", "FDEP收发目录如果采用Ftp时,这里要选择FTP是否启用SSL,不确定就选false");
data = configService.RemoveData("ProjectConfig", "FDEPInboxPath");
configService.AddDataIfNotExists("ProjectConfig", "SAC_FDEPInboxPath", data?.PValue ?? "", "string", "FDEP收件箱目录,支持本地目录,内网共享目录和Ftp目录,共享路径例:\\\\192.168.1.200\\share-test\\ ;Ftp目录应填不包含根目录的相对目录例\\share-test\\ 注意:共享路径和ftp模式下,不要忘记最后的\\");
data = configService.RemoveData("ProjectConfig", "FDEPOutboxPath");
configService.AddDataIfNotExists("ProjectConfig", "SAC_FDEPOutboxPath", data?.PValue ?? "", "string", "FDEP发件箱目录,支持本地目录,内网共享目录和Ftp目录,共享路径例:\\\\192.168.1.200\\share-test\\ ;Ftp目录应填不包含根目录的相对目录例\\share-test\\ 注意:共享路径和ftp模式下,不要忘记最后的\\");
data = configService.RemoveData("ProjectConfig", "SACReportDataSource");
configService.AddDataIfNotExists("ProjectConfig", "SAC_ReportDataSource", data?.PValue ?? "3", "int", "证券业报送数据源;1=Db;2=Excel模板;3=Db+Excel模板(该方式中涉及百分比汇总计算时仍使用模板中数据)");
configService.AddDataIfNotExists("ProjectConfig", "SAC_FtpUsePassive", data?.PValue ?? "false", "bool", "FDEP收发目录如果采用Ftp时,这里要选择是否为被动模式,不确定就选false");
data = configService.RemoveData("ProjectConfig", "StrictAuthorize");
configService.AddDataIfNotExists("ProjectConfig", "Erp.StrictAuthorize", data?.PValue ?? "false", "bool", "严格的权限验证");
configService.AddDataIfNotExists("ProjectConfig", "Erp.RiskAccPnl_SumExpiredExchangeTrades", data?.PValue ?? "false", "bool", "风险对冲累积总盈亏是否统计已过期的场内交易");
//-----------------------------------------------
// 3.12
//-----------------------------------------------
var pvalue = "出入金入金=100201012601&出入金出金=224106&借方成交入金=3101030301020101&借方成交出金=224106&贷方成交入金=3101030301020201&贷方成交出金=224106&借方期权费入金=6111060303010101&借方期权费出金=3101030301020201&贷方期权费入金=6111060303010102&贷方期权费出金=3101030301020101&借方终止费入金=224106&借方终止费出金=6111060303010102&贷方终止费入金=224106&贷方终止费出金=6111060303010101";
if (configService.GetValue("ProjectConfig", "Company") == "瑞达")
{
pvalue = "出入金入金=21010101&出入金出金=224101&借方成交入金=21010101&借方成交出金=224101&贷方成交入金=21010101&贷方成交出金=224101&借方期权费入金=6111&借方期权费出金=21010101&贷方期权费入金=6111&贷方期权费出金=21010101&借方终止费入金=224101&借方终止费出金=6111&贷方终止费入金=224101&贷方终止费出金=6111";
}
configService.AddDataIfNotExists("ProjectConfig", "Erp.YongYouKeMuCode", pvalue, "string", "用友科目编码");
configService.AddDataIfNotExists("ProjectConfig", "Erp.TradeOpenVolOff", string.Empty, "string", "成交首日结算波动率扣除比例");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ReportMaxMonth", "12", "int", "证券业报送定期报告最大可报告月");
//-----------------------------------------------
// 3.13
//-----------------------------------------------
data = configService.RemoveData("ProjectConfig", "Erp.InterfaceApproval");
bool.TryParse(data?.PValue, out var temp);
configService.AddDataIfNotExists("ProjectConfig", "Erp.InterfaceApprovalMode", temp ? "1" : "0", "int", "接口审批:0:不开启接口审批;1:仅使用接口审批;2:使用接口审批和系统审批(目前仅控制客户开户管理页面是否显示审批按钮)");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseSettleDataAcquisition", "false", "bool", "收盘时是否执行数据采集相关逻辑");
configService.AddDataIfNotExists("ProjectConfig", "Erp.EodVarPvPercent", "0.99", "double", "EodVar中百分比的默认值,小数点后两位小数,大于零且小于一");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UploadFileAccepts", "", "string", "文件上传允许的文件类型(多个类型用'|'分隔),样例:.xlsx|.docx");
configService.AddDataIfNotExists("ProjectConfig", "Erp.TradePricingCfg", "", "string", "交易定价要素配置(querystring格式)");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseClientStockEqvNotional", "false", "bool", "是否启用客户名义本金规模");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseClientStockEqvNotional", "false", "bool", "是否启用客户名义本金规模");
configService.AddDataIfNotExists("ProjectConfig", "Erp.SmoothingDaycountMode", "TradingDay", "SmoothingDaycountMode", "平滑过渡日历处理模式");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UnderlyingCacheCfg", "", "string", "标的资产信息缓存配置");
configService.AddDataIfNotExists("ProjectConfig", "Erp.RealtimeRisk_SkipTradeTypes", "", "string", "实时风险-跳过特定交易类型的计算");
configService.AddDataIfNotExists("ProjectConfig", "Erp.NeedIsolateSACInfo", data?.PValue ?? "false", "bool", "是否需要隔离报备信息");
configService.AddDataIfNotExists("ProjectConfig", "Erp.DisableAnonymousAccessFiles", "false", "bool", "是否禁止匿名访问文件(比如App_Docs文件夹中的文件)");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ForwardTradePriceModel", "STANDARD", "ForwardTradePriceModel", "远期交易价格模式,支持标准模式和挂钩标的模式;标的模式:标的1现价-标的2现价的差为期初价格;挂钩标的模式:挂钩标的现价+基差的和为期初价格;");
configService.AddDataIfNotExists("ProjectConfig", "Erp.UseDisplayNotional", "false", "bool", "用于控制页面展示和导出只有数量时,默认返回份额还是数量,true:份额;false:数量;默认为false,方顿为true");
configService.AddDataIfNotExists("ProjectConfig", "Erp.IsForwardTradeToBuy", "false", "bool", "产业客户累计转远期多空反向固定为多头");
configService.AddDataIfNotExists("ProjectConfig", "SAC_SubSystemOutboxPath", "", "string", "子系统发件箱目录,只支持本地系统");
configService.AddDataIfNotExists("ProjectConfig", "SAC_SubSystemInboxPath", "", "string", "子系统收件箱目录,只支持本地系统");
configService.AddDataIfNotExists("ProjectConfig", "KingstarViewConnectionString", "", "string", "金仕达视图连接字符串");
configService.AddDataIfNotExists("ProjectConfig", "KingstarViewTableSchema", "", "string", "金仕达视图Schema");
configService.AddDataIfNotExists("ProjectConfig", "KingstarView_RemotePath", "", "string", "金仕达视图附件FTP远程地址,应填ftp:\\\\192.168.1.200:21");
configService.AddDataIfNotExists("ProjectConfig", "KingstarView_RemoteUser", "", "string", "金仕达视图附件FTP远程地址的用户名,例:administrator");
configService.AddDataIfNotExists("ProjectConfig", "KingstarView_RemotePassword", "", "string", "金仕达视图附件FTP登录远程地址的密码,例:11");
configService.AddDataIfNotExists("ProjectConfig", "KingstarView_EnableSsl", "false", "bool", "金仕达视图附件FTP是否启用SSL,不确定就选false");
configService.AddDataIfNotExists("ProjectConfig", "KingstarView_FtpUsePassive", "false", "bool", "金仕达视图附件FTP连接方式是否为被动模式,不确定就选false");
configService.AddDataIfNotExists("ProjectConfig", "KingstarView_LocalViewAttDir", "", "string", "金仕达视图附件本地存放目录");
configService.AddDataIfNotExists("ProjectConfig", "KingstarView_RemoteFileRootPath", "", "string", "金仕达视图附件FTP远程文件服务器存放根路径");
configService.AddDataIfNotExists("ProjectConfig", "Erp.IsCalcRealtimeWarning", "false", "bool", "是否实时预警配置");
configService.AddDataIfNotExists("ProjectConfig", "Erp.TradeMarketReportCfg", "", "string", "结算报告配置(querystring格式)");
//-----------------------------------------------
// 5.3
//-----------------------------------------------
configService.AddDataIfNotExists("ProjectConfig", "Erp.IsAutoSealAndUploadFiles", "false", "bool", "是否使用电子章系统对确认书进行用印并上传用印文件");
configService.AddDataIfNotExists("ProjectConfig", "Erp.SealApi", "", "string", "电子章用印接口地址");
configService.AddDataIfNotExists("ProjectConfig", "Erp.SealKeyWord", "", "string", "电子章用印关键字");
//-----------------------------------------------
// 5.4.1
//-----------------------------------------------
configService.AddDataIfNotExists("ProjectConfig", "Erp.IsAutoSealAfterGeneratedBook", "false", "bool", "确认书生成时是否自动用印(IsAutoSealAndUploadFiles勾选时生效)");
//-----------------------------------------------
// 删除不再使用的
//-----------------------------------------------
RemoveUnUsed(configService);
}
private static void RemoveUnUsed(InnerAppConfigService configService)
{
if (AppManager.Version.Major < 3)
{
configService.RemoveData("ProjectConfig", "Erp.TradeConfirmBookEmailTPL");
configService.RemoveData("ProjectConfig", "Erp.SettleConfirmBookEmailTPL");
configService.RemoveData("ProjectConfig", "Trade.UseTradeProject");
configService.RemoveData("ProjectConfig", "Erp.AutoCalcRisk");
configService.RemoveData("ProjectConfig", "Erp.UseRealTimeRiskCalcV2");
configService.RemoveData("ProjectConfig", "Erp.Enabl eHedgeVol");
configService.RemoveData("ProjectConfig", "Erp.UseSignalR");
}
if (AppManager.Version.Major == 3)
{
configService.RemoveData("ProjectConfig", "Plugin.BaseDirectory");
configService.RemoveData("ProjectConfig", "Erp.SmallLogo");
configService.RemoveData("ProjectConfig", "Erp.LargeLogo");
configService.RemoveData("ProjectConfig", "Erp.ShowStructTrade");
configService.RemoveData("ProjectConfig", "Erp.CanOnlyUnWindAll");
configService.RemoveData("ProjectConfig", "Erp.IsVolMultiImport");
configService.RemoveData("ProjectConfig", "Erp.ShowBusinessLog");
configService.RemoveData("ProjectConfig", "Erp.ShowCapitalTab");
configService.RemoveData("ProjectConfig", "Erp.ShowManager");
configService.RemoveData("ProjectConfig", "Trade.ShowRecordBtnIn_PriceCalc");
configService.RemoveData("ProjectConfig", "Erp.EnableHedgeVol");
configService.RemoveData("ProjectConfig", "Erp.IsHedgingTogether");
configService.RemoveData("ProjectConfig", "Erp.HedgeTradeFromSystem");
configService.RemoveData("ProjectConfig", "Erp.IntradayRiskUseTradeVol");
configService.RemoveData("ProjectConfig", "Erp.UseVarietyVolEod");
configService.RemoveData("ProjectConfig", "Trade.EditStockEqvNotional");
var targetPath = OtcAppContext.MapPath("~/App_Docs/Images/title.png");
if (!File.Exists(targetPath))
{
Directory.CreateDirectory(Path.GetDirectoryName(targetPath));
var filePath = OtcAppContext.MapPath("~/Images/title.png");
if (File.Exists(filePath))
{
File.Copy(filePath, targetPath);
}
}
configService.RemoveData("ProjectConfig", "Erp.StructureUseColorFlag");
configService.RemoveData("ProjectConfig", "Trade.NeedSetMarginRatio");
}
if (AppManager.Version.Major < 4)
{
configService.RemoveData("ProjectConfig", "Erp.SettlementReportCalcMode");
}
configService.RemoveData("ProjectConfig", "Erp.ExternalAPIEnable");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ExternalAPIForCustomCalcEnable", "false", "bool", "是否启用外部API计算自定义交易");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ExternalAPIForCustomCalc", "", "string", "计算自定义交易的api地址,例:http://127.0.0.1/");
configService.AddDataIfNotExists("ProjectConfig", "Erp.ExternalAPIForCustomCalcTimeOut", "15", "int", "计算自定义交易超时时间(秒)");
}
private static void UpgradeAppConfigV2(InnerAppConfigService configService)
{
var root = XElement.Parse(Properties.Resources.appconfig);
var itemsAll = root.Elements().Where(a => new Version(a.Attribute("version").Value) >= AppManager.Version).SelectMany(n => n.Elements());
foreach (var item in itemsAll)
{
var name = item.Attribute("name")?.Value;
if (string.IsNullOrWhiteSpace(name))
{
continue;
}
var group = item.Attribute("group")?.Value.TrimToNull() ?? "ProjectConfig";
switch (item.Name.LocalName)
{
case "add":
{
var type = item.Attribute("type")?.Value ?? "string";
var remark = item.Attribute("remark")?.Value;
var value = item.Value.TrimToNull() ?? item.Attribute("value")?.Value;
configService.AddDataIfNotExists(pgroup: group, pname: name, pvalue: value, ptype: type, remark: remark);
}
break;
case "remove":
configService.RemoveData(group: group, name: name);
break;
case "update":
configService.UpdateData(group: group, name: name, newRemark: item.Attribute("remark")?.Value);
break;
case "replace":
{
var type = item.Attribute("type")?.Value ?? "string";
var remark = item.Attribute("remark")?.Value;
var data = configService.RemoveData(group: group, name: name); ;
configService.AddDataIfNotExists(pgroup: group, pname: name, pvalue: data?.PValue, ptype: type, remark: remark);
}
break;
}
}
}
private static void UpgradeDictionaries()
{
try
{
using var adminDb = DbContextFactory.GetErpBaseContext();
var exists = adminDb.Dictionaries.Select(n => n.Name).ToArray()
.Select(n => n.Trim()).ToHashSet();
var root = XElement.Parse(YLErp.Resources.Properties.Resources.db_dictionaries);
var itemsAll = root.Elements();
foreach (var item in itemsAll)
{
var name = item.Attribute("name")?.Value;
if (string.IsNullOrWhiteSpace(name))
{
continue;
}
name = name.Trim();
if (exists.Contains(name))
{
continue;
}
var catalog = item.Attribute("catalog")?.Value.TrimToEmpty();
adminDb.Dictionaries.Add(new BaseOUDAL.Dictionary
{
Name = name,
Catalog = catalog
});
}
adminDb.SaveChanges();
}
catch (Exception ex)
{
LogFactory.GetLogger("升级字典项").Error(ex);
}
}
}
}
@@ -0,0 +1,157 @@
using System.Text.RegularExpressions;
namespace YLErp.Modules.AppModule
{
/// <summary>
/// 邮件模板服务
/// </summary>
public class EmailTemplateService : YLBaseService
{
public EmailTemplateService(OptUserInfo userInfo) : base(userInfo)
{
}
public EmailTemplateService(YLBaseService baseService) : base(baseService)
{
}
public EmailTemplate GetData(string emailType)
{
return DbContext.EmailTemplate.AsNoTracking().FirstOrDefault(n => n.EmailType == emailType);
}
/// <summary>
/// 保存数据
/// </summary>
public virtual int SaveData(EmailTemplate data)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (string.IsNullOrWhiteSpace(data.EmailType))
{
throw new ServiceException("缺少邮件类型");
}
var dbmodel = DbContext.EmailTemplate.FirstOrDefault(n => n.EmailType == data.EmailType);
if (dbmodel == null)
{
DbContext.EmailTemplate.Add(dbmodel = new EmailTemplate());
}
UpdateChanges(dbmodel, data, "id");
return DbContext.SaveChanges();
}
/// <summary>
/// 生成邮件信息,如果从数据库中取不到模板配置,返回null
/// </summary>
public MailInfoResultModel GenerateMailInfo(string emailType, MailInfoRequestModel reqModel)
{
if (string.IsNullOrEmpty(emailType))
{
throw new ArgumentException("不能为空", nameof(emailType));
}
if (reqModel == null)
{
throw new ArgumentNullException(nameof(reqModel));
}
var template = DbContext.EmailTemplate.AsNoTracking().FirstOrDefault(n => n.EmailType == emailType);
if (template == null)
{
return null;
}
return GenerateMailInfo(template, reqModel);
}
/// <summary>
/// 生成邮件信息,如果template为null,返回null
/// </summary>
public static MailInfoResultModel GenerateMailInfo(EmailTemplate template, MailInfoRequestModel reqModel)
{
if (template is null)
{
return null;
}
if (reqModel == null)
{
throw new ArgumentNullException(nameof(reqModel));
}
string replace(Match m)
{
switch (m.Groups[1].Value)
{
case "客户名称":
return reqModel.ClientName;
case "交易日期":
return reqModel.TradeDate;
case "文档编号":
return reqModel.DocNumber;
case "交易列表":
return reqModel.TradeList;
}
return string.Empty;
}
var pattern = @"\{\{(客户名称|交易日期|文档编号|交易列表)\}\}";
var result = new MailInfoResultModel
{
IsBodyHtml = template.IsBodyHtml,
Title = Regex.Replace(template.TitleTemplate, pattern, replace),
Body = Regex.Replace(template.BodyTemplate, pattern, replace)
};
return result;
}
}
/// <summary>
/// 邮件信息请求Model
/// </summary>
public class MailInfoRequestModel
{
/// <summary>
/// {{客户名称}}
/// </summary>
public string ClientName { get; set; }
/// <summary>
/// {{交易日期}}
/// </summary>
public string TradeDate { get; set; }
/// <summary>
/// {{文档编号}}
/// </summary>
public string DocNumber { get; set; }
/// <summary>
/// {{交易列表}}
/// </summary>
public string TradeList { get; set; }
}
/// <summary>
/// 邮件信息结果Model
/// </summary>
public class MailInfoResultModel
{
public string Title { get; set; } = string.Empty;
public string Body { get; set; } = string.Empty;
public bool IsBodyHtml { get; set; }
}
}
@@ -0,0 +1,261 @@
using BaseOUDAL;
using Newtonsoft.Json;
using Org.BouncyCastle.Crypto.Tls;
using Org.BouncyCastle.Ocsp;
using System.Data;
using YLErp.Abstract;
using YLErp.Commons;
using YLErp.Helpers;
using YLErp.Model;
using YLErp.Modules.ClientModule;
using YLErp.Modules.SwapModule;
namespace YLErp.Modules.AppModule
{
public class EtradingRuleService : YLBaseService
{
KafkaProduceHelper kafkaProduceHelper;
public EtradingRuleService(OptUserInfo userInfo) : base(userInfo)
{
kafkaProduceHelper = new KafkaProduceHelper();
}
public List<string> ImportExcel(Stream streamIn, out int TotalNum, out int SuccessNum)
{
int rowIndex = 0;
List<string> clientNumbers = new List<string>();
var trans = DbContext.Database.BeginTransaction();
try
{
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 1);
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 1)
{
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
}
var table = ds.Tables[0];
var reader = new DataRowReader(table);
rowIndex = 1;
TotalNum = table.Rows.Count;
var tradePositions = new List<EtradingRule>();
foreach (DataRow row in table.Rows.Cast<DataRow>())
{
rowIndex++;
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
{
continue;
}
reader.SetDataRow(row);
var rule = MapRule(reader);
SaveRule(rule);
clientNumbers.Add(rule.ClientNumber_0);
DbContext.SaveChanges();
}
SuccessNum = TotalNum;
trans.Commit();
trans.Dispose();
return clientNumbers;
}
catch (ServiceException se)
{
trans.Rollback();
trans.Dispose();
if (se.Tag != null) throw;
throw new ServiceException($"第{rowIndex}行,发生错误:{se.Message}");
}
catch (Exception ex)
{
trans.Rollback();
trans.Dispose();
LogFactory.GetLogger("TRS用簿记账户设置").Error(ex);
throw new ServiceException($"第{rowIndex}行,发生错误:{ex.Message}", ex);
}
}
private EtradingRule MapRule(DataRowReader reader)
{
//资金流向 对客客户编号 对客簿记账户 对客清算机构 对冲Broker 对冲簿记账户 对冲清算机构
var rule = new EtradingRule();
//var boundeside = reader.GetString("资金流向", false);
rule.BoundSide = BoundSideEnum.; //默认南向
rule.ClientNumber_0 = reader.GetString("对客客户编号", false);
if (string.IsNullOrWhiteSpace(rule.ClientNumber_0))
{
throw new ServiceException("对客客户编号不能为空");
}
rule.AssetAccount_0 = reader.GetString("对客簿记账户", false);
rule.ClearingAgency_0 = reader.GetString("对客清算机构", false);
////rule.ClientNumber_1 = reader.GetString("连接客户编号", false);
////rule.AssetAccount_1 = reader.GetString("连接簿记账户", false);
////rule.ClearingAgency_1 = reader.GetString("连接清算机构", false);
//rule.Trader_2 = reader.GetString("交易员编号", false);
//rule.Broker_2 = reader.GetString("资金账户", false);
//rule.FundAccount_2 = reader.GetString("资金账户2", false);
//rule.AssetAccount_2 = reader.GetString("对冲簿记账户", false);
//rule.ClearingAgency_2 = reader.GetString("对冲清算机构", false);
return rule;
}
public void SaveRule(EtradingRule rule)
{
CheckRule(rule);
DeleteRule(rule.BoundSide, rule.ClientNumber_0);//删除原来的预设
DbContext.Etrading_Rule.Add(rule);//重新保存
DbContext.SaveChanges();
}
private bool CheckRule(EtradingRule rule)
{
var clients = DataCacheProvider.GetClientDataSource().AsQueryable();
if (!string.IsNullOrEmpty(rule.ClientNumber_0) && !clients.Any(o => o.Number == rule.ClientNumber_0))
{
throw new ServiceException("对客端客户不存在");
}
if (!string.IsNullOrWhiteSpace(rule.ClientNumber_0))
{
var client = clients.FirstOrDefault(o => o.Number == rule.ClientNumber_0);
rule.BoundSide = client.BoundSide;
}
else
{
rule.ClientNumber_0 = string.Empty;
}
//if (!string.IsNullOrEmpty(rule.ClientNumber_1) && !clients.Any(o => o.Number == rule.ClientNumber_1))
//{
// throw new ServiceException("连接客户编号不存在");
//}
var assets = DataCacheProvider.GetAssetUnitDataSource().AsQueryable();
if (!string.IsNullOrEmpty(rule.AssetAccount_0) && !assets.Any(o => o.Name == rule.AssetAccount_0))
{
throw new ServiceException("对客簿记账户不存在");
}
//if (!string.IsNullOrEmpty(rule.AssetAccount_1) && !assets.Any(o => o.Name == rule.AssetAccount_1))
//{
// throw new ServiceException("连接簿记账户不存在");
//}
return true;
}
public string DeleteRule(int id)
{
var rule = DbContext.Etrading_Rule.Find(id);
if (rule != null)
{
DbContext.Etrading_Rule.Remove(rule);
DbContext.SaveChanges();
}
return rule.ClientNumber_0;
}
public void DeleteRule(BoundSideEnum? BoundSide, string ClientNumber)
{
if (BoundSide != null)
{
var rule = new EtradingRule();
if (string.IsNullOrEmpty(ClientNumber))
{
rule = DbContext.Etrading_Rule.FirstOrDefault(o => o.BoundSide == BoundSide && string.IsNullOrEmpty(o.ClientNumber_0));
}
else
{
rule = DbContext.Etrading_Rule.FirstOrDefault(o => o.ClientNumber_0 == ClientNumber);
}
if (rule != null)
{
DbContext.Etrading_Rule.Remove(rule);
DbContext.SaveChanges();
}
}
}
/// <summary>
/// 将最新的费率发送到kafka
/// </summary>
/// <param name="clientId"></param>
/// <param name="kafkaProvider"></param>
public void SendEtradingRuleToKafka(string clientNumber)
{
List<Client> clients = new List<Client>();
using (var con = new ClientDBContext())
{
clients = con.client.AsNoTracking().Where(s => s.ProcessStatus == "已开户").ToList();
}
if (!string.IsNullOrEmpty(clientNumber))
{
var client = clients.FirstOrDefault(o => o.Number == clientNumber);
if (client!=null)
{
var asset = GetAssetByClient(clientNumber);
var account = new EtradeAccountService(UserInfo).GetEtradeAccount(asset)?.balance_account_trade;
SendToKafka(client.id, account);
}
}
else
{
SendAllEtradingRuleToKafka();
}
}
private string GetAssetByClient(string clientNumber)
{
var rule= DbContext.Etrading_Rule.FirstOrDefault(x=>x.ClientNumber_0== clientNumber);
if (rule==null)
{
rule = DbContext.Etrading_Rule.FirstOrDefault(x => string.IsNullOrEmpty(x.ClientNumber_0));
}
return rule?.AssetAccount_0;
}
public List<string> GetClientNumers(string asset)
{
List<string> numbers=new List<string>();
if (string.IsNullOrEmpty(asset))
{
numbers = DbContext.Etrading_Rule.AsNoTracking().Select(s => s.ClientNumber_0).ToList();
return numbers;
}
var rules = DbContext.Etrading_Rule.Where(x => x.AssetAccount_0 == asset|| string.IsNullOrEmpty(x.AssetAccount_0)).AsNoTracking();
numbers = rules.Select(s => s.ClientNumber_0).ToList();
return numbers;
}
public void SendAllEtradingRuleToKafka()
{
var etradingRules = DbContext.Etrading_Rule.AsNoTracking().ToList();
List<Client> clients = new List<Client>();
using (var con =new ClientDBContext())
{
clients= con.client.AsNoTracking().Where(s => s.ProcessStatus == "已开户").ToList();
}
foreach (var client in clients)
{
var clientRule = etradingRules.FirstOrDefault(x => x.ClientNumber_0 == client.Number);
var asset = GetAssetByClient(client.Number);
var account = new EtradeAccountService(UserInfo).GetEtradeAccount(asset)?.balance_account_trade;
SendToKafka(client.id, account);
}
}
public void SendToKafka(int clientId, string hedgingAccount)
{
EtradingRuleKafkaModel etradingRuleKafkaModel = new EtradingRuleKafkaModel();
etradingRuleKafkaModel.clientId = clientId;
etradingRuleKafkaModel.hedgingAccount = hedgingAccount;
kafkaProduceHelper.Produce(Environment.GetEnvironmentVariable("KafkaConfig_HedgingAccountTopic"), JsonConvert.SerializeObject(etradingRuleKafkaModel));
}
public EtradingRule GetEtradingRuleAccont(BoundSideEnum boundSide, string clientNumer)
{
var etradingRules = DbContext.Etrading_Rule.AsNoTracking().ToList();
var etradingRule = etradingRules.FirstOrDefault(x => x.ClientNumber_0 == clientNumer);
if (etradingRule == null)
{
etradingRule = etradingRules.FirstOrDefault(x => string.IsNullOrEmpty(x.ClientNumber_0) && x.BoundSide == boundSide);
}
return etradingRule;
}
}
}
@@ -0,0 +1,15 @@
namespace YLErp.Modules.AppModule
{
class InitializeSetting
{
/// <summary>
/// 更新系统,默认false
/// </summary>
public bool UpgradeSystem { get; set; }
/// <summary>
/// 加载插件,默认false
/// </summary>
public bool LoadPlugin { get; set; }
}
}
@@ -0,0 +1,14 @@
using YLErp.MailKit;
namespace YLErp.Modules.AppModule
{
public class SmtpConfigExt : SmtpConfig
{
public IEnumerable<SmtpConfig> OtherUsers { get; set; }
public SmtpConfigExt Clone()
{
return (SmtpConfigExt)MemberwiseClone();
}
}
}
@@ -0,0 +1,132 @@
using System.Collections.Specialized;
using System.Text;
using YieldChain.Helpers;
using YLErp.DBModels.Consts;
using YLErp.MailKit;
namespace YLErp.Modules.AppModule
{
/// <summary>
/// 邮件发送配置处理
/// </summary>
class SmtpConfigHandler
{
readonly SmtpConfigExt _config;
public SmtpConfigHandler(SmtpConfigExt config)
{
_config = config ?? throw new ArgumentNullException(nameof(config));
}
/// <summary>
/// 重置邮件发送配置
/// </summary>
public void ResetConfig(string configText)
{
if (string.IsNullOrWhiteSpace(configText)) return;
var arr = configText.Split(new[] { "[|]" }, StringSplitOptions.RemoveEmptyEntries);
if (arr.Length < 1) return;
var nv = UrlHelper.ParseQueryString(arr[0]) ?? new NameValueCollection();
int.TryParse(nv["port"], out int port);
_config.Server = nv["server"];
_config.Port = port > 0 ? port : 25;
_config.UserName = nv["userName"];
_config.Password = nv["password"];
_config.EnableSsl = "true".Equals(nv["enableSsl"], StringComparison.OrdinalIgnoreCase);
_config.ZipAttach = "true".Equals(nv["zipAttach"], StringComparison.OrdinalIgnoreCase);
_config.Receipt = "true".Equals(nv["receipt"], StringComparison.OrdinalIgnoreCase);
if (arr.Length < 2) return;
var otherUsers = new List<SmtpConfig>(arr.Length - 1);
for (var i = 1; i < arr.Length; i++)
{
nv = UrlHelper.ParseQueryString(arr[i]);
if (nv != null)
{
otherUsers.Add(new SmtpConfig
{
UserName = nv["userName"],
Password = nv["password"],
Receipt = "true".Equals(nv["receipt"], StringComparison.OrdinalIgnoreCase)
});
}
}
_config.OtherUsers = otherUsers.ToArray();
}
/// <summary>
/// 重置邮件发送配置
/// </summary>
public void ResetConfig(SmtpConfigExt newConfig, bool saveIntoDB)
{
if (newConfig is null)
{
throw new ArgumentNullException(nameof(newConfig));
}
if (string.IsNullOrWhiteSpace(newConfig?.Server))
{
throw new ServiceException("主机不能为空");
}
if (string.IsNullOrWhiteSpace(newConfig.UserName) ||
newConfig.OtherUsers != null && newConfig.OtherUsers.Any(n => string.IsNullOrWhiteSpace(n.UserName)))
{
throw new ServiceException("用户不能为空");
}
if (newConfig.OtherUsers != null && newConfig.OtherUsers.Count() + 1 !=
newConfig.OtherUsers.Select(n => n.UserName.Trim()).Concat(new[] { newConfig.UserName.Trim() }).ToHashSet(StringComparer.OrdinalIgnoreCase).Count)
{
throw new ServiceException("用户不能重复");
}
if (saveIntoDB)
{
var sb = new StringBuilder(300);
sb.Append("&server=").Append(newConfig.Server);
sb.Append("&port=").Append(newConfig.Port);
sb.Append("&userName=").Append(newConfig.UserName);
sb.Append("&password=").Append(newConfig.Password);
sb.Append("&enableSsl=").Append(newConfig.EnableSsl);
sb.Append("&zipAttach=").Append(newConfig.ZipAttach);
sb.Append("&receipt=").Append(newConfig.Receipt);
if (newConfig.OtherUsers != null)
{
foreach (var u in newConfig.OtherUsers)
{
sb.Append("[|]");
sb.Append("&userName=").Append(u.UserName);
sb.Append("&password=").Append(u.Password);
sb.Append("&receipt=").Append(u.Receipt);
}
}
var context = DbContextFactory.GetYLDbContext();
var config = context.AppConfig.FirstOrDefault(n => n.PGroup == ConsAppConfig.ProjectConfig && n.PName == ConsAppConfig.SendMailConfig);
if (config == null)
{
config = new AppConfig
{
PGroup = ConsAppConfig.ProjectConfig,
PName = ConsAppConfig.SendMailConfig,
CreateTime = DateTime.Now,
PType = "string",
Remark = "邮件发送配置(格式:&server=192.168.1.1&port=25&userName=test@test.com&password=123456&enableSsl=false|true)"
};
}
config.PValue = sb.ToString();
context.SaveChanges();
}
ObjectHelper.MapValues(_config, newConfig);
}
}
}
@@ -0,0 +1,76 @@
namespace YLErp.Modules.AppModule.UpgradModule
{
/// <summary>
///
/// </summary>
public class DbUpdateResInfo
{
/// <summary>
/// 脚本文件名(不带扩展名)
/// </summary>
public string UpKey { get; set; }
/// <summary>
/// 版本号
/// </summary>
public string Version { get; set; }
/// <summary>
/// 数据库
/// </summary>
public string DbSchema { get; set; }
public override string ToString()
{
return $"upkey:{UpKey},version:{Version},dbschema:{DbSchema}";
}
}
/// <summary>
///
/// </summary>
public class DbUpdateDto : DbUpdateResInfo
{
/// <summary>
/// 更新状态,0:未执行,100:执行成功,101:执行失败
/// </summary>
public int UpState { get; set; }
/// <summary>
/// 执行成功则填写“成功”,失败则填写异常信息或失败原因
/// </summary>
public string UpResult { get; set; }
}
/// <summary>
/// 数据库更新请求
/// </summary>
public class DbUpdateRequest
{
/// <summary>
///
/// </summary>
public IEnumerable<string> UpKeyList { get; set; }
}
/// <summary>
/// 数据库更新执行结果
/// </summary>
public class DbUpdateResult
{
/// <summary>
/// 脚本名称 20220414_admin_01
/// </summary>
public string UpKey { get; set; }
/// <summary>
/// 更新状态,0:未执行,100:执行成功,101:执行失败
/// </summary>
public int UpState { get; set; }
/// <summary>
/// 执行成功则填写“成功”,失败则填写异常信息或失败原因
/// </summary>
public string UpResult { get; set; }
}
}
@@ -0,0 +1,304 @@
using BaseOUDAL;
using YLErp.Commons;
namespace YLErp.Modules.AppModule.UpgradModule
{
/// <summary>
/// 数据库结构及数据升级服务
/// </summary>
public class DbUpdateService
{
const int UpState_Fail = -1;
const int UpState_Done = 1;
const int UpState_Pending = 0;
const string UpType_DbUpdate = "DbUpdate";
const string ResNameSpacePrefix = "YLErp.Resources.DbUpdate.Ver";
#region--------
/// <summary>
/// 获取资源文件列表
/// </summary>
public static List<DbUpdateDto> GetUpdateList()
{
var upList = new List<DbUpdateDto>();
var assembly = typeof(YLErp.Resources.PlaceHolder).Assembly;
foreach (var resName in assembly.GetManifestResourceNames())
{
//YLErp.Resources.DbUpdate.Ver_3._17.prod.sql
if (!resName.StartsWith(ResNameSpacePrefix))
{
continue;
}
var upkey = resName.Substring(ResNameSpacePrefix.Length, resName.Length - ResNameSpacePrefix.Length - 4);
var strArr = upkey.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var version = string.Join(".", strArr.Take(strArr.Length - 1).Select(n => n.Substring(1)).ToArray());
var dto = new DbUpdateDto
{
UpKey = upkey,
Version = version,
DbSchema = strArr[^1],
UpResult = "未执行"
};
upList.Add(dto);
}
var dic = GetLogs();
foreach (var dto in upList)
{
if (dic.TryGetValue(dto.UpKey, out var a))
{
dto.UpState = a.UpState;
dto.UpResult = a.UpResult;
}
}
return upList.OrderByDescending(x => x.Version + ".").ThenBy(n => n.DbSchema).ToList();
}
private static Dictionary<string, InnerDbLog> GetLogs()
{
InnerDbLog[] getLogs(DbSet<SysUpdateLog> dbset)
{
var startDate = DateTime.Today.AddMonths(-6);
var baseQry = from a in dbset
where a.CreateTime > startDate && a.UpType == UpType_DbUpdate
select a;
var groupQry = from a in baseQry
group a by a.UpKey into g
select new { id = g.Max(n => n.id) };
var listQry = from g in groupQry
join a in baseQry on g.id equals a.id
select new InnerDbLog
{
UpKey = a.UpKey,
UpResult = a.UpResult,
UpState = a.UpState
};
return listQry.ToArray();
}
var list = new List<InnerDbLog>(100);
using (var db = DbContextFactory.GetYLDbContext())
{
list.AddRange(getLogs(db.SysUpdateLogs));
}
using (var db = DbContextFactory.GetErpBaseContext())
{
list.AddRange(getLogs(db.SysUpdateLogs));
}
using (var db = DbContextFactory.GetClientDbContext(OptUserInfo.SystemUser))
{
list.AddRange(getLogs(db.SysUpdateLogs));
}
return CollectionHelper.ToDictionary2(list, n => n.UpKey, n => n, StringComparer.OrdinalIgnoreCase, useFirst: true);
}
#endregion
#region--------
/// <summary>
/// 执行数据库脚本升级
/// </summary>
public static List<DbUpdateResult> ExecuteUpdate(IEnumerable<string> upKeyList, bool onlyUpdateDone)
{
var resultList = new List<DbUpdateResult>();
var exelist = upKeyList.OrderBy(n => n.ToLowerInvariant()).ToArray();
foreach (var upkey in exelist)
{
var result = InnerExecuteUpdate(upkey, onlyUpdateDone);
resultList.Add(result);
}
return resultList;
}
/// <summary>
/// 执行单个更新
/// </summary>
private static DbUpdateResult InnerExecuteUpdate(string upkey, bool onlyUpdateDone)
{
var result = new DbUpdateResult { UpKey = upkey, UpState = UpState_Fail };
if (string.IsNullOrEmpty(upkey))
{
result.UpResult = "upkey是空值";
return result;
}
result.UpState = UpState_Pending;
var sqlText = string.Empty;
if (onlyUpdateDone)
{
result.UpState = UpState_Done;
result.UpResult = "手动更新为已执行";
}
else
{
sqlText = GetResourceContent(upkey);
if (sqlText == null)
{
result.UpState = UpState_Fail;
result.UpResult = "没有找到升级脚本";
}
else if (string.IsNullOrWhiteSpace(sqlText))
{
sqlText = string.Empty;
result.UpState = UpState_Done;
result.UpResult = "升级脚本为空";
}
}
using (var db = getDbContext(upkey))
{
if (db == null)
{
result.UpResult = "未从upkey中解析出正确的数据库";
return result;
}
if (result.UpState == UpState_Pending)
{
try
{
var changes = db.Database.ExecuteSqlRaw(sqlText);
result.UpState = UpState_Done;
result.UpResult = "执行成功,受影响的行数:" + changes;
}
catch (Exception ex)
{
result.UpState = UpState_Fail;
result.UpResult = ex.Messages();
}
}
var dblog = new SysUpdateLog()
{
UpKey = upkey,
UpType = UpType_DbUpdate,
UpState = result.UpState,
UpResult = result.UpResult,
CreateTime = DateTime.Now
};
db.SysUpdateLogs.Add(dblog);
db.SaveChanges();
}
return result;
DBContextBase getDbContext(string upkey)
{
var index = upkey.LastIndexOf('.');
var dbSchema = upkey.Substring(index + 1);
return (dbSchema?.ToLowerInvariant()) switch
{
"admin" => DbContextFactory.GetErpBaseContext(),
"client" => DbContextFactory.GetClientDbContext(OptUserInfo.SystemUser),
"prod" => DbContextFactory.GetYLDbContext(),
_ => null,
};
}
}
#endregion
/// <summary>
/// 查看数据库脚本升级内容
/// </summary>
public static string GetUpdateContent(IEnumerable<string> upKeyList)
{
if (upKeyList is null || !upKeyList.Any())
{
return string.Empty;
}
var sb = StringBuilderPool.Acquire();
var exelist = upKeyList.OrderBy(n =>
{
var index = n.LastIndexOf('.');
return n.Substring(0, index + 1);
}).ToArray();
foreach (var upkey in exelist)
{
var sqlText = GetResourceContent(upkey);
sb.AppendLine("-- -----------------------------------------------------------")
.Append("-- V").Append(upkey.Replace("_", "")).AppendLine()
.AppendLine("-- -----------------------------------------------------------");
if (sqlText == null)
{
sb.Append("-- !!!没有找到升级脚本:").Append(upkey).AppendLine();
}
else
{
sb.AppendLine(sqlText);
}
}
return sb.Release();
}
/// <summary>
/// 返回资源文件内容,如果是null表示资源不存在
/// </summary>
private static string GetResourceContent(string upkey)
{
var resName = string.Concat(ResNameSpacePrefix, upkey, ".sql");
var assembly = typeof(Resources.PlaceHolder).Assembly;
using var s = assembly.GetManifestResourceStream(resName);
if (s == null)
{
return null;
}
using var sr = new StreamReader(s);
return sr.ReadToEnd();
}
class InnerDbLog
{
public string UpKey { get; set; }
public string UpResult { get; set; }
public int UpState { get; set; }
}
}
}