using CRM.Core.BLL.Application.B; using CRM.Core.BLL.Wx; using CRM.Core.DTO; using CRM.Core.DTO.Bill; using CRM.Core.Model.Entity; using Csv; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Text; using WX.CRM.Common; namespace CRM.Core.BLL.Application.Bill { public class BillService { private static NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); private Bill_Account_BL bill_Account_BL = new Bill_Account_BL(); public string UserName; public BillService(string UserName) { this.UserName = UserName; } public retMsg ImportBillzip(string filename, Stream filestream) { retMsg retMsg = new retMsg() { result = true }; StringBuilder sb = new StringBuilder(); using (ZipArchive archive = new ZipArchive(filestream, ZipArchiveMode.Read, false, Encoding.Default)) { foreach (var item in archive.Entries) { if (item.Length > 0) { var fname = item.Name; var msg = ImportBill(fname, item.Open()); if (msg.result == false) retMsg.result = false; sb.Append($"{fname}:{msg.retmsg}
"); } } } retMsg.retmsg = sb.ToString(); return retMsg; } public retMsg ImportBill(string filename, Stream filestream) { retMsg retMsg = new retMsg() { result = true }; try { Stopwatch stopwatch = Stopwatch.StartNew(); List bill_Accounts = new List(); var file_ext = Path.GetExtension(filename).ToLower(); var name = Path.GetFileNameWithoutExtension(filename); Logger.Info("开始解析"); if (file_ext.Equals(".zip")) { retMsg = ImportBillzip(filename, filestream); return retMsg; } if (file_ext.Equals(".csv")) { if (name.Contains("微信交易账单")) { bill_Accounts = GetBillAccountsFromWX_Business(filestream); } else if (name.Contains("账务")) { bill_Accounts = GetBillAccountsFromAli_csv(filestream); } else { retMsg.result = false; retMsg.retmsg = String.Format("csv文件未找到微信关键字:[微信交易账单]或支付宝关键字:[账务]"); return retMsg; } } else if (file_ext.Equals(".xls") || file_ext.Equals(".xlsx")) { if (name.Contains("东高") || name.Contains("银行")) { bill_Accounts = GetBillAccountsFromBank(filestream, file_ext); } else { retMsg.result = false; retMsg.retmsg = String.Format("excel文件未找到银行关键字:[东高],[银行]"); return retMsg; } } else { retMsg.result = false; retMsg.retmsg = String.Format("非法文件格式,请导入微信支付宝的csv格式或银行xlsx格式文件"); return retMsg; } Logger.Info("解析完成"); // bill_Account_BL.AddList(bill_Accounts); bill_Account_BL.BulkInsertToMysql("Bill_Account", bill_Accounts); Logger.Info("插入完成"); retMsg.retmsg = getbillsMsg(bill_Accounts); stopwatch.Stop(); Logger.Info(string.Format("{0},耗时{1}", retMsg.retmsg, stopwatch.ElapsedMilliseconds)); } catch (Exception ex) { retMsg.result = false; retMsg.retmsg = String.Format("异常:{0}", ex.Message); Logger.Error(ex); } return retMsg; } public string getbillsMsg(List bill_Accounts) { var paybill = bill_Accounts.Where(d => d.trade_type == Bill_TradeType_enum.Pay.ToString()); var refundbill = bill_Accounts.Where(d => d.trade_type == Bill_TradeType_enum.Refund.ToString()); var amount = paybill.Sum(d => d.trade_amount); var feeamount = paybill.Sum(d => d.fee_amount); var refundAmount = refundbill.Sum(d => d.trade_amount); var feeRefundAmount = refundbill.Sum(d => d.fee_amount); return string.Format("交易数:{0},交易金额:{1},退款金额:{2},手续费:{3}", bill_Accounts.Count, amount, refundAmount, feeamount - feeRefundAmount); } public Bill_Account FullBillAccount(Bill_Account bill_Account) { return bill_Account; } public List GetBillAccountsFromWX_Business(Stream filestream) { List result = new List(); foreach (var line in CsvReader.ReadFromStream(filestream)) { //line.Raw=line.Raw.Replace("`", ""); if (line.ColumnCount != line.Headers.Count()) continue; Bill_Account bill_Account = new Bill_Account() { mch = MCH_enum.Wxpay.ToString(), mch_id = line["商户号"].TrimStart('`'), trade_no = line["微信订单号"].TrimStart('`'), out_trade_no = line["商户订单号"].TrimStart('`'), trade_datetime = DateTime.Parse(line["交易时间"].TrimStart('`')), out_mch = line["付款银行"].TrimStart('`'), out_mchid = line["付款银行"].TrimStart('`'), trade_info = line["商品名称"].TrimStart('`'), payer_id = line["用户标识"].TrimStart('`'), creat_id = UserName, creat_datetime = DateTime.Now, last_modify_time = DateTime.Now }; var type = line["交易状态"].TrimStart('`'); if (type.Equals(WX_TradeType_enum.SUCCESS.ToString())) { bill_Account.trade_type = Bill_TradeType_enum.Pay.ToString(); bill_Account.trade_amount = decimal.Parse(line["应结订单金额"].TrimStart('`')); bill_Account.fee_amount = decimal.Parse(line["手续费"].TrimStart('`')); } else if (type.Equals(WX_TradeType_enum.REFUND.ToString())) { bill_Account.trade_type = Bill_TradeType_enum.Refund.ToString(); bill_Account.trade_amount = decimal.Parse(line["退款金额"].TrimStart('`')); bill_Account.fee_amount = Math.Abs(decimal.Parse(line["手续费"].TrimStart('`'))); bill_Account.trade_no = line["微信退款单号"].TrimStart('`'); bill_Account.out_trade_no = line["商户退款单号"].TrimStart('`'); bill_Account.main_trade_no = line["微信订单号"].TrimStart('`'); } result.Add(bill_Account); } return result; } public List GetBillAccountsFromAli_xls(Stream filestream, string file_ext = "xls") { List result = new List(); IWorkbook workBook = null; switch (file_ext) { case "xls": workBook = new HSSFWorkbook(filestream); break; case "xlsx": workBook = new XSSFWorkbook(filestream); break; default: throw new ArgumentException("非法后缀"); } var sheet = workBook.GetSheetAt(0); var row0 = sheet.GetRow(0); var rownum = sheet.LastRowNum; var title = row0.GetCell(0).StringCellValue; var mch_id = ""; if (title.Contains("[")) { mch_id = title.Split('[')[1].Trim(']'); } for (int i = 2; i < rownum; i++) { var row = sheet.GetRow(i); var s = row.Cells[1].RichStringCellValue; } foreach (var line in CsvReader.ReadFromStream(filestream)) { //line.Raw=line.Raw.Replace("`", ""); if (line.ColumnCount != line.Headers.Count()) continue; Bill_Account bill_Account = new Bill_Account() { mch = MCH_enum.Wxpay.ToString(), mch_id = line["商户号"].TrimStart('`'), trade_no = line["微信订单号"].TrimStart('`'), out_trade_no = line["商户订单号"].TrimStart('`'), trade_datetime = DateTime.Parse(line["交易时间"].TrimStart('`')), out_mch = line["付款银行"].TrimStart('`'), out_mchid = line["付款银行"].TrimStart('`'), trade_info = line["商品名称"].TrimStart('`'), payer_id = line["用户标识"].TrimStart('`'), creat_id = UserName, creat_datetime = DateTime.Now, last_modify_time = DateTime.Now }; var type = line["交易状态"].TrimStart('`'); if (type.Equals(WX_TradeType_enum.SUCCESS.ToString())) { bill_Account.trade_type = Bill_TradeType_enum.Pay.ToString(); bill_Account.trade_amount = decimal.Parse(line["应结订单金额"].TrimStart('`')); bill_Account.fee_amount = decimal.Parse(line["手续费"].TrimStart('`')); } else if (type.Equals(WX_TradeType_enum.REFUND.ToString())) { bill_Account.trade_type = Bill_TradeType_enum.Refund.ToString(); bill_Account.trade_amount = decimal.Parse(line["退款金额"].TrimStart('`')); bill_Account.fee_amount = Math.Abs(decimal.Parse(line["手续费"].TrimStart('`'))); bill_Account.trade_no = line["微信退款单号"].TrimStart('`'); bill_Account.out_trade_no = line["商户退款单号"].TrimStart('`'); bill_Account.main_trade_no = line["微信订单号"].TrimStart('`'); } else { continue; } result.Add(bill_Account); } return result; } public List GetBillAccountsFromAli_csv(Stream filestream) { List result = new List(); List FeeRefundList = new List(); Dictionary Feekvs = new Dictionary(); List RefundList = new List(); string csv = new StreamReader(filestream, Encoding.GetEncoding("GB2312")).ReadToEnd(); var top = csv.Substring(1, csv.IndexOf('\n')); var mch_id = ""; if (top.Contains("[")) { mch_id = top.Split('[')[1].Trim('\n').Trim(']'); } foreach (var line in CsvReader.ReadFromText(csv)) { //line.Raw=line.Raw.Replace("`", ""); if (line.ColumnCount != line.Headers.Count()) continue; Bill_Account bill_Account = new Bill_Account() { mch = MCH_enum.Alipay.ToString(), mch_id = mch_id, trade_no = line["支付宝交易号"], out_trade_no = line["商户订单号"], trade_datetime = DateTime.Parse(line["入账时间"]), out_mch = line["支付渠道"], out_mchid = line["支付渠道"], trade_info = line["商品名称"], payer_name = line["对方名称"], payer_id = line["对方账户"], creat_id = UserName, creat_datetime = DateTime.Now, last_modify_time = DateTime.Now }; var type = line["账务类型"].TrimStart('`'); var sr = line["收入(+元)"].Trim(); if (type.Contains("在线支付") || (type.Contains("转账") && !string.IsNullOrEmpty(sr))) { bill_Account.trade_type = Bill_TradeType_enum.Pay.ToString(); bill_Account.trade_amount = decimal.Parse(line["收入(+元)"]); bill_Account.fee_amount = decimal.Parse(line["服务费(元)"]); } else if (type.Contains("退款") || type.Contains("转账")) { bill_Account.trade_type = Bill_TradeType_enum.Refund.ToString(); bill_Account.trade_amount = decimal.Parse(line["支出(-元)"]); bill_Account.fee_amount = Math.Abs(decimal.Parse(line["服务费(元)"])); bill_Account.trade_no = line["支付宝流水号"]; bill_Account.main_trade_no = line["支付宝交易号"]; bill_Account.refund_info = line["备注"]; RefundList.Add(bill_Account); continue; } else if (type.Contains("退费")) { bill_Account.trade_amount = decimal.Parse(line["收入(+元)"]); FeeRefundList.Add(bill_Account); continue; } else if (type.Contains("收费")) { bill_Account.trade_amount = decimal.Parse(line["支出(-元)"]); Feekvs.Add(bill_Account.trade_no, bill_Account.trade_amount); continue; } else { continue; } result.Add(bill_Account); } //更新手续费为收费 foreach (var item in result) { var fee = 0m; if (Feekvs.TryGetValue(item.trade_no, out fee)) { item.fee_amount = fee; } } var rkv = RefundList.ToDictionary(d => d.main_trade_no, d => d); foreach (var fee in FeeRefundList) { rkv[fee.trade_no].fee_amount = fee.trade_amount; } result.AddRange(rkv.Values.ToList()); return result; } public List GetBillAccountsFromBank(Stream filestream, string file_ext = "xls") { List result = new List(); IWorkbook workBook = null; switch (file_ext) { case ".xls": workBook = new HSSFWorkbook(filestream); break; case ".xlsx": workBook = new XSSFWorkbook(filestream); break; default: throw new ArgumentException("非法后缀"); } var sheet = workBook.GetSheetAt(0); var row0 = sheet.GetRow(0); var rownum = sheet.LastRowNum; for (int i = 1; i <= rownum; i++) { try { var row = sheet.GetRow(i); if (row == null) break; var s = row.Cells[1].RichStringCellValue; if (string.IsNullOrEmpty(s.String)) continue; Bill_Account bill_Account = new Bill_Account() { mch = MCH_enum.Bank.ToString(), mch_id = row.Cells[0].StringCellValue, trade_no = row.Cells[11].StringCellValue, out_trade_no = "", trade_datetime = DateTime.ParseExact(String.Format("{0}{1}", row.Cells[3].StringCellValue, row.Cells[4].StringCellValue), "yyyyMMddHHmmss", CultureInfo.InvariantCulture), out_mch = row.Cells[22].StringCellValue, out_mchid = row.Cells[20].StringCellValue, trade_info = row.Cells[10].StringCellValue, payer_name = row.Cells[19].StringCellValue, payer_id = row.Cells[19].StringCellValue, creat_id = UserName, creat_datetime = DateTime.Now, last_modify_time = DateTime.Now }; var type = row.Cells[6].StringCellValue; //if (type.Contains("提回对公户收款")|| type.Contains("IBPS对公提回贷记")) if (row.Cells[7].NumericCellValue == 0) { bill_Account.trade_type = Bill_TradeType_enum.Pay.ToString(); bill_Account.trade_amount = Convert.ToDecimal(row.Cells[8].NumericCellValue); } else if (row.Cells[8].NumericCellValue == 0) { bill_Account.trade_type = Bill_TradeType_enum.Refund.ToString(); bill_Account.trade_amount = Convert.ToDecimal(row.Cells[7].NumericCellValue); bill_Account.refund_info = row.Cells[10].StringCellValue; } else { continue; } result.Add(bill_Account); } catch (Exception ex) { Logger.Error($"异常行:{i}", ex); throw (new Exception($"异常行:{i}", ex)); } } return result; } public List billAccountChecks(List bill_Accounts) { List checks = new List(); if (bill_Accounts.Count == 0) return checks; WX_SzzyOrderDeposit_BL _orderDeposit = new WX_SzzyOrderDeposit_BL(); var bills = bill_Accounts.Where(d => d.trade_type.Equals(Bill_TradeType_enum.Pay.ToString())).ToList(); var mintime = bills.Min(d => d.trade_datetime).Date; var maxtime = bills.Max(d => d.trade_datetime).Date.AddDays(1); var where = PredicateExtensionses.True(); where = where.And(p => p.auditstatus == 1); where = where.And(p => p.paydate >= mintime && p.paydate < maxtime); var depositList = _orderDeposit.GetList(where).ToList(); var depositKVs = new ConcurrentDictionary(); var depositKVsError = new ConcurrentDictionary(); foreach (var item in depositList) { if (!depositKVs.TryAdd(item.payno, item)) { depositKVsError.TryAdd(item.payno, item); } } foreach (var item in bills) { var billcheck = new BillDto.BillAccountCheck() { mch = item.mch, mch_id = item.mch_id, trade_no = item.trade_no, out_trade_no = item.out_trade_no, trade_datetime = item.trade_datetime, trade_type = item.trade_type, trade_amount = item.trade_amount, fee_amount = item.fee_amount, out_mch = item.out_mch, payer_name = item.payer_name, payer_id = item.payer_id, out_mchid = item.out_mchid, trade_info = item.trade_info, }; //微信支付宝识别订单号 if (item.mch.Equals(MCH_enum.Wxpay.ToString()) || item.mch.Equals(MCH_enum.Alipay.ToString())) { WX_SzzyOrderDeposit wX_SzzyOrderDeposit = null; if (depositKVs.TryRemove(item.trade_no, out wX_SzzyOrderDeposit)) { billcheck.id = wX_SzzyOrderDeposit.id; billcheck.resid = wX_SzzyOrderDeposit.resid; billcheck.paytypename = wX_SzzyOrderDeposit.paytypename; billcheck.paydate = wX_SzzyOrderDeposit.paydate; billcheck.payprice = wX_SzzyOrderDeposit.payprice; billcheck.payname = wX_SzzyOrderDeposit.payname; billcheck.payno = wX_SzzyOrderDeposit.payno; if (billcheck.payprice == billcheck.trade_amount) { billcheck.checkStatus = Bill_CheckStatus.Success.ToString(); billcheck.checkResult = "成功"; } else { billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "金额不对"; } if (depositKVsError.ContainsKey(item.trade_no)) { billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "此流水号重复"; } } else { billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "账单未匹配"; } } //银行 if (item.mch.Equals(MCH_enum.Bank.ToString())) { var deposits = depositKVs.Values.ToList(); var deposit = deposits.Where(d => d.payname.Equals(item.payer_name) && d.paydate == item.trade_datetime.Date && d.payprice == item.trade_amount).ToList(); if (deposit.Count == 0) { billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "账单未匹配"; } else { var wX_SzzyOrderDeposit = deposit.FirstOrDefault(); billcheck.id = wX_SzzyOrderDeposit.id; billcheck.resid = wX_SzzyOrderDeposit.resid; billcheck.paytypename = wX_SzzyOrderDeposit.paytypename; billcheck.paydate = wX_SzzyOrderDeposit.paydate; billcheck.payprice = wX_SzzyOrderDeposit.payprice; billcheck.payname = wX_SzzyOrderDeposit.payname; billcheck.payno = wX_SzzyOrderDeposit.payno; if (deposit.Count == 1) { billcheck.checkStatus = Bill_CheckStatus.Success.ToString(); billcheck.checkResult = "成功"; } else { billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "有同用户,同日,同金额多笔交易"; } } } checks.Add(billcheck); } //剩余到账未匹配 var somedeposits = depositKVs.Values.ToList(); List depositIds = checks.Select(d => d.id).ToList(); var NoChcek = somedeposits.Where(d => !depositIds.Contains(d.id)).ToList(); foreach (var wX_SzzyOrderDeposit in NoChcek) { var billcheck = new BillDto.BillAccountCheck(); billcheck.id = wX_SzzyOrderDeposit.id; billcheck.resid = wX_SzzyOrderDeposit.resid; billcheck.paytypename = wX_SzzyOrderDeposit.paytypename; billcheck.paydate = wX_SzzyOrderDeposit.paydate; billcheck.payprice = wX_SzzyOrderDeposit.payprice; billcheck.payname = wX_SzzyOrderDeposit.payname; billcheck.payno = wX_SzzyOrderDeposit.payno; billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "到账未匹配"; checks.Add(billcheck); } return checks; } public List billAccountRefundChecks(List bill_Accounts) { List checks = new List(); if (bill_Accounts.Count == 0) return checks; WX_SzzyOrderRefund_BL wX_SzzyOrderRefund_BL = new WX_SzzyOrderRefund_BL(); var bills = bill_Accounts.Where(d => d.trade_type.Equals(Bill_TradeType_enum.Refund.ToString())).ToList(); var mintime = bills.Min(d => d.trade_datetime).Date; var maxtime = bills.Max(d => d.trade_datetime).Date.AddDays(1); var where = PredicateExtensionses.True(); where = where.And(p => p.auditstatus == 1); where = where.And(p => p.refunddate >= mintime && p.refunddate < maxtime); where = where.And(p => p.isacturalrefund == 1); var refundList = wX_SzzyOrderRefund_BL.GetList(where).ToList(); foreach (var item in bills) { var billcheck = new BillDto.BillRefundCheck() { mch = item.mch, mch_id = item.mch_id, trade_no = item.trade_no, out_trade_no = item.out_trade_no, trade_datetime = item.trade_datetime, trade_type = item.trade_type, trade_amount = item.trade_amount, fee_amount = item.fee_amount, payer_name = item.payer_name, payer_id = item.payer_id, out_mchid = item.out_mchid, trade_info = item.trade_info, refund_info = item.refund_info, main_trade_no = item.main_trade_no }; var refundordierids = billcheck.refund_info.Replace("退款", "").Replace("转账", "") .Replace("+", ",").Replace("/", ",").Replace(" ", ",") .Replace("、", ",").Replace(",", ",").Trim(); billcheck.refund_orderids = refundordierids; var orderids_str = refundordierids.Split(','); List otderids = new List(); foreach (var orderidstr in orderids_str) { var orderid = 0; if (Int32.TryParse(orderidstr, out orderid)) { otderids.Add(orderid); } } int refundtype = 5; switch (item.mch) { case "Alipay": refundtype = 1; break; case "Wxpay": refundtype = 5; break; case "Bank": refundtype = 3; break; default: break; } var refunds = refundList.Where(d => otderids.Contains(d.orderid) && d.refundtype == refundtype).ToList(); if (refunds.Count == 0) { billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "没有找到订单号"; checks.Add(billcheck); } var refundprice = refunds.Sum(d => d.refundprice); var trade_amount = billcheck.trade_amount; foreach (var refund in refunds) { billcheck.id = Convert.ToInt32(refund.id); billcheck.orderid = refund.orderid; billcheck.refundprice = refund.refundprice; billcheck.username = refund.username; billcheck.refundtypename = refund.refundtypename; billcheck.refunddate = refund.refunddate; billcheck.auditorname = refund.auditorname; billcheck.audittime = refund.audittime; if (trade_amount == refundprice) { billcheck.checkStatus = Bill_CheckStatus.Success.ToString(); billcheck.checkResult = "成功"; checks.Add(billcheck); billcheck = new BillDto.BillRefundCheck(); } else { billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "金额不对"; checks.Add(billcheck); billcheck = new BillDto.BillRefundCheck(); } } } //剩余退款未匹配 List checkids = checks.Select(d => d.id).ToList(); var NoChcek = refundList.Where(d => !checkids.Contains(Convert.ToInt32(d.id))).ToList(); foreach (var refund in NoChcek) { var billcheck = new BillDto.BillRefundCheck(); billcheck.id = Convert.ToInt32(refund.id); billcheck.orderid = refund.orderid; billcheck.refundprice = refund.refundprice; billcheck.username = refund.username; billcheck.refundtypename = refund.refundtypename; billcheck.refunddate = refund.refunddate; billcheck.auditorname = refund.auditorname; billcheck.audittime = refund.audittime; billcheck.checkStatus = Bill_CheckStatus.Fail.ToString(); billcheck.checkResult = "退款未匹配"; checks.Add(billcheck); } return checks; } public enum MCH_enum { Wxpay, Alipay, Bank } public enum WX_TradeType_enum { SUCCESS, REFUND } public enum Bill_TradeType_enum { Pay, Refund } public enum Bill_CheckStatus { Success, Fail } } }