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

659 lines
35 KiB
C#

using BaseOUDAL;
using OfficeOpenXml;
using YLErp.Commons;
using YLErp.Helpers;
namespace YLErp.Modules.ClientModule
{
/// <summary>
/// 客户资金导入服务
/// </summary>
public class ClientCashImportService : ClientBaseService
{
readonly ErpBaseContext basedb = new();
public ClientCashImportService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// 从文件导入银行流水信息
/// </summary>
public string ImportBankRecords(string fileName, bool CheckPermission = false)
{
if (PS.Config.Company == Configuration.CompanyEnum.申万)
{
return ImportBankRecordsForSywg(fileName);
}
var clientCashList = new List<ClientCashInCashOut>();
var bankcardList = new List<ClientBankCard>();
var directionList = new List<string> { "出金", "入金", "其他收入", "其他支出" };
//读取文件
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
using var package = new ExcelPackage(fs);
if (package.Workbook.Worksheets.Count > 0)
{
var sheet = package.Workbook.Worksheets[0];
if (null == sheet.Dimension)
{
return "导入的文件不能为空文档!";
}
var serialNumList = new List<string>();
//当低于20列时默认为是简洁版,超过20列默认为是财务版,走财务版的逻辑
if (sheet.Dimension.End.Column - sheet.Dimension.Start.Column <= 20)
{
for (int m = sheet.Dimension.Start.Row + 1, n = sheet.Dimension.End.Row; m <= n; m++)
{
int j = sheet.Dimension.Start.Column, k = sheet.Dimension.End.Column;
DateTime happenDate;
try
{
happenDate = sheet.GetValue<DateTime>(m, j);
if (happenDate == DateTime.MinValue)
{
return "第" + m + "行,发生时间转换格式错误,请检查导入符合要求格式的文件!";
}
if (happenDate > DateTime.Now)
{
return "第" + m + "行,发生时间不能大于当前时间!";
}
}
catch (Exception)
{
return "第" + m + "行,发生时间转换格式错误,请检查导入符合要求格式的文件!";
}
j++;
var clientName = sheet.GetValue(m, j)?.ToString();
if (clientName.IsNullOrWhiteSpace())
{
return "第" + m + "行,客户名称不能为空,请检查导入符合要求格式的文件!";
}
j++;
var openBankCard = sheet.GetValue(m, j)?.ToString();
if (PS.Config.Company == Configuration.CompanyEnum.中粮)
{
if (openBankCard.IsNullOrWhiteSpace())
{
return "第" + m + "行,银行账号不能为空,请检查导入符合要求格式的文件!";
}
}
j++;
var direction = sheet.GetValue(m, j)?.ToString();
if (direction.IsNullOrWhiteSpace())
{
return "第" + m + "行,方向不能为空,请检查导入符合要求格式的文件!";
}
if (!directionList.Contains(direction))
{
return "第" + m + "行,方向不满足可导入方向类型,请检查导入符合要求格式的文件!";
}
j++;
var money = sheet.GetValue(m, j)?.ToString();
if (money.IsNullOrWhiteSpace())
{
return "第" + m + "行,金额不能为空,请检查导入符合要求格式的文件!";
}
j++;
var currencyCode = sheet.GetValue(m, j)?.ToString();
var Currency = DbContextFactory.GetYLDbContext().currency.Find(currencyCode);
var defaultValues = new string[] { "CNY", "USD" };
if (Currency == null && !string.IsNullOrWhiteSpace(currencyCode))
{
throw new Exception($"币种{currencyCode}不存在");
}
if (PS.Config.Company == Configuration.CompanyEnum.中金)
{
if (!defaultValues.Contains(currencyCode))
{
throw new Exception($"出入金币种只能为CNY/USD");
}
}
j++;
var serialNum = sheet.GetValue(m, j)?.ToString();
j++;
var remark = sheet.GetValue(m, j)?.ToString();
if ((yldb.ClientCashInCashOut.Any(x => x.SerialNumber == serialNum) || serialNumList.Any(x => x == serialNum)) && !string.IsNullOrWhiteSpace(serialNum))
{
return string.Format("第{0}行,流水号已经存在,请检查后再导入!", m);
}
var clientCash = new ClientCashInCashOut
{
Direction = direction,
Number = UniqueTimeId.GetStr(),
ClientName = clientName,
Action = "Excel导入",
Money = direction == "其他支出" ? -NumberHelper.ToDouble(money) : NumberHelper.ToDouble(money),
CurrencyCode = currencyCode,
HappenDate = happenDate,
State = "未确认",
OpenBankCard = openBankCard,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now,
CreatorId = UserId,
CreatorName = UserName,
CreateDate = DateTime.Now,
SerialNumber = serialNum,
Comments = remark
};
//客户名称检查
var client = ClientDataQueryService.GetClient(clientName);
if (client != null)
{
if (client.ProcessStatus == "已开户")
{
clientCash.ClientId = client.id;
clientCash.ClientNumber = client.Number;
}
else
{
return string.Format("第{0}行,客户: {1} 尚未开户,请检查后再导入!", m, clientName);
}
}
else
{
return string.Format("第{0}行,客户: {1} 在系统中不存在,请检查后再导入!", m, clientName);
}
if (!string.IsNullOrEmpty(openBankCard))
{
var bankcardModel = DbContext.bankcard.FirstOrDefault(c => c.ApprovalOrder < 1 && client.id == c.ClientId && c.ValidState != "InValid" && c.Card == openBankCard);
if (bankcardModel != null)
{
clientCash.Uses = bankcardModel.Use;
}
else
{
return string.Format("第{0}行,客户: {1} 在系统中不存在此银行卡信息,请检查后再导入!", m, clientName);
}
//中金不填银行卡,银行卡用客户的
if (PS.Config.Company == Configuration.CompanyEnum.中金 && string.IsNullOrEmpty(clientCash.OpenBankCard))
{
var bankCard = DbContext.bankcard.FirstOrDefault(c => c.ApprovalOrder < 1 && client.id == c.ClientId && c.ValidState != "InValid");
if (bankCard != null)
{
openBankCard = bankCard.Card;
clientCash.OpenBankCard = bankCard.Card;
clientCash.OpenBankId = bankCard.id;
clientCash.OpenBank = bankCard.Bank;
}
else
{
return string.Format("第{0}行:客户 {1} 未设置银行卡,请检查后再导入!", m, client.Name);
}
}
//检查银行卡
var bankCardModel = DbContext.bankcard.Where(c => c.ApprovalOrder < 1 &&
openBankCard.Equals(c.Card) && client.id == c.ClientId && c.ValidState != "InValid");
if (CheckPermission)
{
var dictionaryName = CheckCashAccountTypePermission(clientCash.Direction);
if (!bankCardModel.Where(b => dictionaryName.Contains(b.Use) && b.Card == openBankCard).Any())
{
return string.Format("第{0}行,出入金方向和银行卡账号类型不匹配!", m);
}
}
if ("出金".Equals(clientCash.Direction))
{
var bcModel = bankCardModel.FirstOrDefault();
if (bankCardModel.FirstOrDefault() != null)
{
clientCash.OpenBankId = bcModel.id;
clientCash.OpenBank = bcModel.Bank;
}
else
{
return string.Format("第{0}行,银行卡号:{1} 非系统有效银行卡号,请检查后再导入!", m, openBankCard);
}
}
}
else
{
clientCash.Uses = "全部";
var bankcardModel = DbContext.bankcard.FirstOrDefault(c => c.ApprovalOrder < 1 && client.id == c.ClientId && c.ValidState != "InValid" && c.Use=="全部");
if (bankcardModel != null)
{
clientCash.OpenBankCard = bankcardModel.Card;
}
}
serialNumList.Add(serialNum);
clientCashList.Add(clientCash);
}
}
else
{
for (int m = sheet.Dimension.Start.Row + 1, n = sheet.Dimension.End.Row; m <= n; m++)
{
int j = sheet.Dimension.Start.Column, k = sheet.Dimension.End.Column;
var tradeDate = sheet.GetValue(m, j) != null ? sheet.GetValue(m, j).ToString() : "";
DateTime? happenDate = null;
try
{
happenDate = DateTime.ParseExact(tradeDate, "yyyy-MM-dd",
System.Globalization.CultureInfo.CurrentCulture);
}
catch (Exception)
{
return "第" + m + "行,交易日转换格式错误,支持格式:yyyy-MM-dd,请检查导入符合要求格式的文件!";
}
var tradeTime = tradeDate + " " + (sheet.GetValue(m, ++j) != null
? sheet.GetValue(m, j).ToString()
: "");
try
{
happenDate = DateTime.ParseExact(tradeTime, "yyyy-MM-dd HH:mm:ss",
System.Globalization.CultureInfo.CurrentCulture);
if (happenDate > DateTime.Now)
{
return "第" + m + "行,发生时间不能大于当前时间!";
}
}
catch (Exception)
{
return "第" + m + "行,交易时间转换格式错误,支持格式:HH:mm:ss,请检查导入符合要求格式的文件!";
}
j += 2;
var direction =
string.IsNullOrEmpty(sheet.GetValue(m, ++j) != null
? sheet.GetValue(m, j).ToString()
: null)
? "入金"
: "出金";
var money = 0.0;
if (sheet.GetValue(m, j) == null && sheet.GetValue(m, j + 1) == null)
{
return "第" + m + "行,借方金额、贷方金额不能同时为空!";
}
else
{
money = double.Parse(sheet.GetValue(m, j) != null
? sheet.GetValue(m, j).ToString()
: sheet.GetValue(m, j + 1).ToString());
}
if (money < 0)
{
return "第" + m + "行,借方金额、贷方金额不能小于0!";
}
j += 4;
var SerialNumber = sheet.GetValue(m, j) != null ? sheet.GetValue(m, j).ToString() : "";
j += 3;
var uses = sheet.GetValue(m, j)?.ToString();
j += 4;
var clientName = sheet.GetValue(m, ++j) != null ? sheet.GetValue(m, j).ToString() : "";
var openBankCard = sheet.GetValue(m, ++j) != null
? sheet.GetValue(m, j).ToString()
: "";
j++;
var OpenBankName = sheet.GetValue(m, ++j) != null
? sheet.GetValue(m, j).ToString()
: "";
if ((yldb.ClientCashInCashOut.Any(x => x.SerialNumber == SerialNumber) || serialNumList.Any(x => x == SerialNumber)) && !string.IsNullOrWhiteSpace(SerialNumber))
{
return string.Format("第{0}行,流水号已经存在,请检查后再导入!", m);
}
var clientCash = new ClientCashInCashOut
{
Direction = direction,
Number = UniqueTimeId.GetStr(),
ClientName = clientName,
Action = "Excel导入",
Money = money,
HappenDate = happenDate,
State = "未确认",
OpenBankCard = openBankCard,
OpenBank = OpenBankName,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now,
CreatorId = UserId,
CreatorName = UserName,
CreateDate = DateTime.Now,
SerialNumber = SerialNumber,
Uses = uses
};
//客户名称检查
var client = ClientDataQueryService.GetClient(clientName);
if (client != null)
{
if (client.ProcessStatus == "已开户")
{
clientCash.ClientId = client.id;
clientCash.ClientNumber = client.Number;
}
else
{
return string.Format("第{0}行,客户: {1} 尚未开户,请检查后再导入!", m, clientName);
}
}
else
{
return string.Format("第{0}行,客户: {1} 在系统中不存在,请检查后再导入!", m, clientName);
}
if (openBankCard.IsNullOrWhiteSpace())
{
return string.Format("第{0}行,银行卡号不能为空,请检查后再导入!", m);
}
//检查银行卡
var bankCard = DbContext.bankcard.Where(c => c.ApprovalOrder < 1 &&
openBankCard.Equals(c.Card) && client.id == c.ClientId && c.ValidState != "InValid");
if (CheckPermission)
{
var dictionaryName = CheckCashAccountTypePermission(clientCash.Direction);
if (!bankCard.Where(b => dictionaryName.Contains(b.Use) && b.Card == openBankCard).Any())
{
return string.Format("第{0}行,出入金方向和银行卡账号类型不匹配!", m);
}
}
if ("出金".Equals(clientCash.Direction))
{
var bcModel = bankCard.FirstOrDefault();
if (bankCard != null)
{
clientCash.OpenBankId = bcModel.id;
clientCash.OpenBank = bcModel.Bank;
}
else
{
return string.Format("第{0}行,银行卡号:{1} 非系统有效银行卡号,请检查后再导入!", m, openBankCard,
clientName);
}
}
//if ("出金".Equals(clientCash.Direction))
//{
// //当前抵押且确认的抵押品记录(包含抵押确认状态的记录和赎回待确认或者赎回拒绝的记录)
// var entrysExecutedProduct = db.clientcashincashout_product.Where(t =>
// t.ClientId == clientCash.ClientId &&
// (ClientCashInCashOut.已确认.Equals(t.OptStatus) && (Clientcashincashout_productStatusEnum.抵押
// .ToString().Equals(t.Status)) ||
// (t.OptStatus != ClientCashInCashOut.已确认 && (Clientcashincashout_productStatusEnum.赎回.ToString()
// .Equals(t.Status))))).ToList();
// //获取标的信息
// var underlyingIds = entrysExecutedProduct.Select(x => x.UnderlyingId).ToList();
// var underlyings = db.underlying_manager.Where(x => underlyingIds.Contains(x.id));
// //当前客户总的抵押品的金额(赎回的不算)
// var executedMoneyProduct = entrysExecutedProduct.Sum(t =>
// (underlyings.FirstOrDefault(x => x.id == t.UnderlyingId) == null
// ? 0
// : underlyings.FirstOrDefault(x => x.id == t.UnderlyingId).Price) *
// t.ProductAmount * t.Rate);
// //查看当前客户可用资金是否符合出金条件
// var clientbalance = ClientBalanceUtility
// .GetClientBanlances(new List<int> { clientCash.ClientId.Value },
// DateTime.MinValue, DateTime.Now.Date).FirstOrDefault();
// //当日可用资金(除去抵押品部分的价值,默认客户先消费现金,再消费抵押品,所以出金时可用资金要除去抵押品的价值)
// var availableFund = (clientbalance == null ? 0 : clientbalance.AvailableAmount) -
// (executedMoneyProduct ?? 0.0);
// //已存在的该客户的导入出金数据
// var existMoney = clientCashList.Where(x =>
// x.ClientId == clientCash.ClientId && "出金".Equals(x.Direction))
// .Sum(x => x.Money);
// //如果出金大于可用资金则抛出错误
// if ((clientCash.Money ?? 0.0) + (existMoney ?? 0.0) > availableFund)
// {
// return "添加出金失败,客户:" + clientCash.ClientName + " 实际可取出资金:" +
// availableFund.ToString("0.00") + ",当前导入的出金总额超过了该客户可取金额,请检查确认后再进行导入;";
// }
//}
serialNumList.Add(SerialNumber);
clientCashList.Add(clientCash);
}
}
}
else
{
return "表格sheet为空!";
}
}
//保存
if (clientCashList.Count > 0)
{
yldb.ClientCashInCashOut.AddRange(clientCashList);
yldb.SaveChanges();
foreach (var item in clientCashList)
{
var ClientCashLogdata = ClientCashLog(item.id, "导入资金记录");
yldb.clientcash_log.Add(ClientCashLogdata);
}
yldb.SaveChanges();
}
return null;
}
/// <summary>
/// 检测出金(收款账户、全部),入金(付款账户、全部)
/// </summary>
public List<string> CheckCashAccountTypePermission(string direction)
{
var dictionaryName = (from dicItem in basedb.DictionaryItems join dic in basedb.Dictionaries on dicItem.DictId equals dic.Id where dic.Name == "资金用途" && !(direction.Contains("出金") ? "付款账户" : "收款账户").Contains(dicItem.ShortName) select dicItem.Name).ToList();
return dictionaryName;
}
/// <summary>
/// 资金记录导入日志
/// </summary>
/// <param name="CashId"></param>
/// <param name="Type"></param>
public ClientCashLog ClientCashLog(int CashId, string Type)
{
var clientcashlog = new ClientCashLog()
{
CashId = CashId,
OptType = Type,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
};
return clientcashlog;
}
/// <summary>
/// 从文件导入银行流水信息
/// </summary>
public string ImportBankRecordsForSywg(string fileName)
{
var errorMessage = string.Empty;
var clientCashList = new List<ClientCashInCashOut>();
//读取文件
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
using var package = new ExcelPackage(fs);
if (package.Workbook.Worksheets.Count > 0)
{
var sheet = package.Workbook.Worksheets[1];
if (null == sheet.Dimension)
{
return "导入的文件不能为空文档!";
}
if (sheet.Dimension.Start.Row == sheet.Dimension.End.Row)
{
return "导入文件只有标题行!";
}
for (int m = sheet.Dimension.Start.Row + 1, n = sheet.Dimension.End.Row; m <= n; m++)
{
int j = sheet.Dimension.Start.Column, k = sheet.Dimension.End.Column;
var serialNumber = sheet.GetValue(m, j) != null ? sheet.GetValue(m, j).ToString() : "";
j += 6;
var debit = NumberHelper.ToDouble(sheet.GetValue(m, j)?.ToString());
j++;
var credit = NumberHelper.ToDouble(sheet.GetValue(m, j)?.ToString());
if (debit == 0 && credit == 0)
{
errorMessage += "第" + m + "行,借方金额、贷方金额不能同时为0!";
continue;
}
if (debit < 0 || credit < 0)
{
errorMessage += "第" + m + "行,借方金额或贷方金额不能小于0!";
continue;
}
var money = debit == 0 ? credit : debit;
var direction = credit > 0 ? "入金" : "出金";
j++;
var accountBalance = NumberHelper.ToDouble(sheet.GetValue(m, j)?.ToString());
j += 2;
var openBankCard = sheet.GetValue(m, j)?.ToString();
j++;
var clientName = sheet.GetValue(m, j)?.ToString();
j++;
var openBankName = sheet.GetValue(m, j)?.ToString();
j += 2;
var tradeDate = sheet.GetValue(m, j)?.ToString();
DateTime? happenDate = null;
try
{
happenDate = DateTime.ParseExact(tradeDate, "yyyy-MM-dd HH:mm:ss", System.Globalization.CultureInfo.CurrentCulture);
//happenDate = happenDate.Value.Date;
}
catch (Exception)
{
errorMessage += "第" + m + "行,交易日期转换格式错误,请检查导入符合要求格式的文件!";
continue;
}
j++;
var uses = sheet.GetValue(m, j)?.ToString();
var clientCash = new ClientCashInCashOut
{
Direction = direction,
Number = UniqueTimeId.GetStr(),
ClientName = clientName,
Action = "Excel导入",
Money = money,
HappenDate = happenDate,
// 特殊处理:如果是通过资金监控程序读取的申万资金流水文件,State默认为"已确认"
State = UserName == "申万服务出入金操作" ? ClientCashInCashOut.已确认 : ClientCashInCashOut.未确认,
OpenBank = openBankName,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now,
CreatorId = UserId,
CreatorName = UserName,
CreateDate = DateTime.Now,
SerialNumber = serialNumber,
AccountBalance = accountBalance,
Uses = uses
};
//客户名称检查
var client = ClientDataQueryService.GetClient(clientName);
if (client != null)
{
if (client.ProcessStatus == "已开户")
{
clientCash.ClientId = client.id;
clientCash.ClientNumber = client.Number;
}
else
{
errorMessage += string.Format("第{0}行,客户: {1} 尚未开户,请检查后再导入!", m, clientName);
continue;
}
}
else
{
errorMessage += string.Format("第{0}行,客户: {1} 在系统中不存在,请检查后再导入!", m, clientName);
continue;
}
//检查银行卡
var bankCard = DbContext.bankcard.FirstOrDefault(c => c.ApprovalOrder < 1 && openBankCard.Equals(c.Card));
if (bankCard != null)
{
//银行卡是否与绑定客户对应
if (bankCard.ClientId != client.id)
{
errorMessage += string.Format("第{0}行,银行卡号:{1} 与客户:{2} 绑定关系不对应,请检查后再导入!", m, openBankCard, clientName);
continue;
}
else if (bankCard.ValidState == "InValid")
{
errorMessage += string.Format("第{0}行,客户:{1} 银行卡号:{2} 该银行卡状态为无效,请检查后再导入!", m, clientName, openBankCard);
continue;
}
else
{
clientCash.OpenBankId = bankCard.id;
clientCash.OpenBank = bankCard.Bank;
clientCash.OpenBankCard = bankCard.Card;
}
}
else
{
errorMessage += string.Format("第{0}行,银行卡号:{1} 未在系统中登记,请检查后再导入!", m, openBankCard, clientName);
continue;
}
clientCashList.Add(clientCash);
}
}
else
{
return "表格sheet为空!";
}
}
clientCashList = FilterHappnedRecords(clientCashList);
//保存
if (clientCashList.Count > 0)
{
yldb.ClientCashInCashOut.AddRange(clientCashList);
yldb.SaveChanges();
}
return errorMessage;
}
/// <summary>
/// 将数据库里已存在的流水记录过滤掉。
/// 过滤逻辑是按待导入的记录的日期,查询数据库里对应日期的所有流水记录,
/// 如果数据库里已经存在某一流水号,则将该条记录过滤掉
/// </summary>
/// <param name="records">待导入记录</param>
/// <param name="db">数据库</param>
/// <returns>过滤后的记录</returns>
private List<ClientCashInCashOut> FilterHappnedRecords(List<ClientCashInCashOut> records)
{
if (records == null || records.Count == 0)
{
return records;
}
var happenDates = records.Select(x => x.HappenDate).Distinct().ToList();
var happenedSerialNumbers = yldb.ClientCashInCashOut.Where(x => x.HappenDate.HasValue && happenDates.Contains(x.HappenDate.Value)).Select(x => x.SerialNumber).ToList();
return records.Where(x => !happenedSerialNumbers.Contains(x.SerialNumber)).ToList();
}
}
}