DS7/DSWeb/Areas/Account/DAL/Chfee_invoice_HangXin/RYTHelper.cs

771 lines
25 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using DSWeb.EntityDA;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Web;
using System.Linq;
using System.Text.RegularExpressions;
using log4net;
using Newtonsoft.Json.Linq;
using DSWeb.Areas.Account.DAL.Chfee_Invoice_HangXin;
using DSWeb.MvcShipping.DAL.MsCompanysDAL;
using DSWeb.MvcShipping.DAL.MsSysParamSet;
namespace DSWeb.Common.Helper
{
public class RYTHelper
{
private const string apiUrlTest = "https://www.chinaeinv.com:943/igs/api/invoiceApi.jspa";//测试环境
private const string apiUrl = "https://www.chinaeinv.com/igs/api/invoiceApi.jspa";//正式环境
public RYTHelper()
{
}
/// <summary>
/// 开启测试模式(使用测试环境)
/// </summary>
private bool IsTestMode = false;
#region 对象属性
private string AppCode
{
get
{
if (IsTestMode)
{
return "PTTEST17";
}
else
{
return "PT000147";
}
}
}
private string KeyStore
{
get
{
if (IsTestMode)
{
return "PTTEST17.pfx";
}
else
{
return "PT000147.pfx";
}
}
}
private string KeyStorePsw
{
get
{
if (IsTestMode)
{
return "PTTEST17";
}
else
{
return "vfrsedazsed";
}
}
}
private string ApiUrl
{
get
{
if (IsTestMode)
{
return apiUrlTest;
}
else
{
return apiUrl;
}
}
}
#endregion
#region 公共方法
#region 开票
/// <summary>
/// 开票
/// </summary>
/// <param name="strParams"></param>
/// <returns></returns>
public string PostInvoice(string strParams)
{
//logger.Debug($"瑞宏开票:{strParams}");
var rtn = DoPostData(strParams, "chinaeinv.api.invoice.v3.kp_async");
//logger.Debug($"瑞宏开票返回:{rtn}");
return rtn;
}
/// <summary>
/// 开票
/// </summary>
/// <param name="strParams"></param>
/// <returns></returns>
public string PostInvoice(RuihongPostModel postModel)
{
var strJson = JsonConvert.SerializeObject(postModel);
if (postModel.notices == null || postModel.notices.Count == 0)
{
JObject jobj = JObject.Parse(strJson);
jobj.Remove("notices");
strJson = jobj.ToString();
}
return PostInvoice(strJson);
}
/// <summary>
/// 开票
/// </summary>
/// <param name="invId"></param>
/// <returns></returns>
//public bool PostInvoiceRecord(string invId, out string msg)
//{
// var inv = ChinvoiceDAL.GetData("cm.GID='" + invId + "'");
// var invItems = ChinvoiceDAL.GetDetailList("PID='" + invId + "'");
// RYTInvoiceModel postModel = new RYTInvoiceModel();
// postModel.SerialNo = DateTime.Now.ToString("yyyyMMddHHmmssfff") + "000001";
// postModel.CustomerCode = inv.CUSTRATENO;
// postModel.CustomerName = inv.INVOICECUSTNAME;
// postModel.CustomerAddress = inv.CUSTADDR;
// postModel.CustomerTel = inv.CUSTTEL;
// for (int idx = inv.CUSTBANK.Length - 1; idx >= 0; idx--)
// {
// var idxStr = inv.CUSTBANK[idx].ToString();
// if (Regex.IsMatch(idxStr, "[0-9\\s-]{1}"))
// {
// continue;
// }
// postModel.CustomerBankName = inv.CUSTBANK.Substring(0, idx + 1);
// postModel.CustomerBankAccount = inv.CUSTBANK.Substring(idx + 1);
// break;
// }
// for (int idx = inv.ACCOUNT.Length - 1; idx >= 0; idx--)
// {
// var idxStr = inv.ACCOUNT[idx].ToString();
// if (Regex.IsMatch(idxStr, "[0-9\\s-]{1}"))
// {
// continue;
// }
// postModel.PartnerBankName = inv.ACCOUNT.Substring(0, idx + 1);
// postModel.PartnerBankAccount = inv.ACCOUNT.Substring(idx + 1);
// break;
// }
// postModel.Drawer = inv.OPERATORNAME;
// postModel.Reviewer = inv.CHECKER;
// postModel.Payee = inv.PAYEE;
// postModel.Currency = "RMB";
// postModel.RemarkType = 1;
// postModel.Remark = inv.REMARK;
// postModel.Email = inv.PUSHEMAIL;
// postModel.InvoiceDrawType = "10";
// postModel.Details = new List<RYTInvoiceItemModel>();
// foreach (var item in invItems)
// {
// var goodsCode = item.GOODCODE == null ? string.Empty : item.GOODCODE;
// goodsCode = goodsCode.PadRight(19, '0');
// postModel.Details.Add(new RYTInvoiceItemModel()
// {
// Type =0,
// GoodsName = item.GOODSNAMEREF,
// Code=item.GOODCODE,
// Spec = item.SPEC,
// Unit = item.UNIT,
// Quantity = item.PKGS,
// TaxRate = item.TAXRATE,
// Amount = item.AMOUNT,
// Price = item.PRICE,
// CatalogCode = goodsCode,
// ZeroTaxrateFlag = item.ZTAXTYPE
// });
// }
// string rtn = PostInvoice(postModel);
// var rtnObj = JsonConvert.DeserializeObject<RuihongRespCommon>(rtn);
// if (rtnObj.code == "0")
// {
// T_ALL_DA T_ALL_DA = new EntityDA.T_ALL_DA();
// var blUpSQL = "update ch_fee_invoice set INVOICESERIALNUM='" + rtnObj.serialNo + "',EINVOICESTATE='1' where GID='" + invId + "' ";
// bool bl = T_ALL_DA.GetExecuteSqlCommand(blUpSQL);
// //inv.SerialNo = rtnObj.serialNo;
// //inv.Status = InvoiceRecord.StatusPost;
// //invDB.SaveChanges();
// msg = rtnObj.message;
// return true;
// }
// else
// {
// msg = rtnObj.message;
// return false;
// }
//}
#endregion
#region 查票
/// <summary>
/// 查票
/// </summary>
/// <param name="strParams"></param>
/// <returns></returns>
public string QueryInvoice(string strParams)
{
//logger.Debug($"瑞宏查票:{strParams}");
var rtn = DoPostData(strParams, "chinaeinv.api.invoice.v3.cx");
//logger.Debug($"瑞宏查票返回:{rtn}");
return rtn;
}
/// <summary>
/// 根据操作流水号单个查询
/// </summary>
/// <param name="strParams">单个操作流水号</param>
/// <returns></returns>
public string QueryInvoiceSerialNo(params string[] serNO)
{
if (serNO == null || serNO.Length == 0)
{
return null;
}
RuihongQueryModel reqModel = new RuihongQueryModel();
reqModel.serialNo = Guid.NewGuid().ToString();
reqModel.postTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
reqModel.criteria = new List<RuihongQueryInner>();
foreach (var item in serNO)
{
reqModel.criteria.Add(new RuihongQueryInner()
{
name = "singlesSerialNo",
value = item
});
}
return QueryInvoice(JsonConvert.SerializeObject(reqModel));
}
/// <summary>
/// 查询发票开出
/// </summary>
/// <param name="invId"></param>
/// <param name="msg"></param>
/// <returns></returns>
public bool QueryInvoiceRecord(string invId,string INVOICESERIALNUM, out string msg)
{
//var inv = ChinvoiceDAL.GetData("cm.GID='" + invId + "'");
if (string.IsNullOrEmpty(INVOICESERIALNUM))
{
msg = "还未成功进行平台开票,无可读数据";
return false;
}
string rtn = QueryInvoiceSerialNo(INVOICESERIALNUM);
var rtnObj = JsonConvert.DeserializeObject<RuihongRespQuery>(rtn);
if (rtnObj.code == "0")
{
var InvCode = rtnObj.invoices[0].code.Substring(0, 12);
var InvNum = rtnObj.invoices[0].code.Substring(12);
var PdfUrl = rtnObj.invoices[0].pdfUnsignedUrl;
PdfUrl = PdfUrl.Replace("Unsigned", "");
var PictureUrl = rtnObj.invoices[0].viewUrl;
var InvoiceDate = Convert.ToDateTime(rtnObj.invoices[0].generateTime).ToString("yyyy-MM-dd");
var needautolock = MsSysParamSetDAL.GetSysParam("INVOICEAUTOLOCK").isnullortrue();
T_ALL_DA T_ALL_DA = new EntityDA.T_ALL_DA();
var blUpSQL = "update ch_fee_invoice set INVOICECODE='" + InvCode + "',INVOICENO='" + InvNum + "',INVOICEINFOURL='" + PictureUrl + "',INVOICEPDFURL='" + PdfUrl + "',INVOICEMAKETIME='" + InvoiceDate + "',EINVOICESTATE='2' where GID='" + invId + "' ";
if (needautolock)
{
blUpSQL = "update ch_fee_invoice set BILLSTATUS=1,INVOICECODE='" + InvCode + "',INVOICENO='" + InvNum + "',INVOICEINFOURL='" + PictureUrl + "',INVOICEPDFURL='" + PdfUrl + "',INVOICEMAKETIME='" + InvoiceDate + "',EINVOICESTATE='2' where GID='" + invId + "' ";
}
bool bl = T_ALL_DA.GetExecuteSqlCommand(blUpSQL);
//读取成功后,发送邮件
//if (inv.PushMode == "0" && !string.IsNullOrEmpty(inv.Email))
//{
// MailHelper.SendMailInvoiceRecord(inv.GID);
//}
msg = rtnObj.message;
return true;
}
else
{
msg = rtnObj.message;
return false;
}
}
#endregion
#region 冲红
/// <summary>
/// 冲红
/// </summary>
/// <param name="strParams"></param>
/// <returns></returns>
public string RedInvoice(string strParams)
{
//logger.Debug($"瑞宏冲红:{strParams}");
var rtn = DoPostData(strParams, "chinaeinv.api.invoice.v3.ch_async");
//logger.Debug($"瑞宏冲红返回:{rtn}");
return rtn;
}
/// <summary>
/// 冲红
/// </summary>
/// <param name="redModel"></param>
/// <returns></returns>
public string RedInvoice(RuihongRedInvoiceModel redModel)
{
return RedInvoice(JsonConvert.SerializeObject(redModel));
}
/// <summary>
/// 冲红
/// </summary>
/// <param name="invId"></param>
/// <returns></returns>
public bool RedInvoiceRecord(string invId, out string msg)
{
var inv = ChinvoiceDAL.GetData("cm.GID='" + invId + "'");
//var invItems = ChinvoiceDAL.GetDetailList("PID='" + invId + "'");
RuihongRedInvoiceModel redModel = new RuihongRedInvoiceModel();
redModel.serialNo = inv.GID;
redModel.postTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
redModel.originalCode = inv.REDCODE + inv.REDNUM;
redModel.reason = string.IsNullOrEmpty(inv.REMARK) ? "冲红" : inv.REMARK;
string rtn = RedInvoice(redModel);
var rtnObj = JsonConvert.DeserializeObject<RuihongRespCommon>(rtn);
if (rtnObj.code == "0")
{
//inv.SerialNo = rtnObj.serialNo;
//inv.Status = InvoiceRecord.StatusPost;
//invDB.SaveChanges();
T_ALL_DA T_ALL_DA = new EntityDA.T_ALL_DA();
var blUpSQL = "update ch_fee_invoice set INVOICESERIALNUM='" + rtnObj.serialNo + "',EINVOICESTATE='2' where GID='" + invId + "' ";
bool bl = T_ALL_DA.GetExecuteSqlCommand(blUpSQL);
msg = rtnObj.message;
return true;
}
else
{
msg = rtnObj.message;
return false;
}
}
#endregion
public string DoPostData(string kpParams, string cmd)
{
//appCode
string appcode = UrlEncode(AppCode, Encoding.UTF8);
//cmdName
string cmdName = UrlEncode(cmd, Encoding.UTF8);
//sign
string sign = UrlEncode(GetSign(kpParams), Encoding.UTF8);
//URL
StringBuilder Url = new StringBuilder();
Url.Append(ApiUrl);
Url.Append("?sign=" + sign);
Url.Append("&cmdName=" + cmdName);
Url.Append("&appCode=" + appcode);
//Post 请求URL
HttpWebRequest request = null;
HttpWebResponse response = null;
try
{
//设置最大连接数
ServicePointManager.DefaultConnectionLimit = 200;
//设置https验证方式
if (ApiUrl.StartsWith("https", StringComparison.OrdinalIgnoreCase))
{
ServicePointManager.ServerCertificateValidationCallback =
new RemoteCertificateValidationCallback(CheckValidationResult);
}
request = WebRequest.Create(Url.ToString()) as HttpWebRequest;
byte[] requestBytes = Encoding.GetEncoding("UTF-8").GetBytes(kpParams);
request.Method = "POST";
request.Timeout = 180 * 1000;
request.ContentType = "application/json;charset=UTF-8";
request.ContentLength = requestBytes.Length;
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(requestBytes, 0, requestBytes.Length);
requestStream.Close();
}
//获取响应报文
response = request.GetResponse() as HttpWebResponse;
using (StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream(), Encoding.GetEncoding("UTF-8")))
{
return reader.ReadToEnd().Trim();
}
}
catch (Exception ex)
{
return ex.Message;
}
finally
{
//关闭连接和流
if (response != null)
{
response.Close();
}
if (request != null)
{
request.Abort();
}
}
}
#endregion
#region 私有方法
private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
{
return true;
}
/// <summary>
/// UrlEncode
/// </summary>
/// <param name="temp">要转码的文本</param>
/// <param name="encoding">编码</param>
/// <returns></returns>
private string UrlEncode(string temp, Encoding encoding)
{
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < temp.Length; i++)
{
string t = temp[i].ToString();
string k = HttpUtility.UrlEncode(t, encoding);
if (t == k)
{
stringBuilder.Append(t);
}
else
{
stringBuilder.Append(k.ToUpper());
}
}
return stringBuilder.ToString();
}
/// <summary>
/// 数字签名
/// </summary>
/// <returns></returns>
private string GetSign(string kpParams)
{
try
{
var keyStorePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, KeyStore);
//logger.Debug($"keyStorePath:{keyStorePath}");
//logger.Debug($"KeyStorePsw:{KeyStorePsw}");
X509Certificate2 x = new X509Certificate2(keyStorePath, KeyStorePsw, X509KeyStorageFlags.Exportable);
RSACryptoServiceProvider rsa = x.PrivateKey as RSACryptoServiceProvider;
byte[] data = Encoding.UTF8.GetBytes(kpParams);
RSACryptoServiceProvider privateKey1 = new RSACryptoServiceProvider();
privateKey1.ImportParameters(rsa.ExportParameters(true));
byte[] sign = privateKey1.SignData(data, "MD5");
string strSign = Convert.ToBase64String(sign);
string s1 = strSign.Substring(0, 76);
string s2 = strSign.Substring(76 * 1, 76);
string s3 = strSign.Substring(76 * 2);
string resultSign = UrlEncode(s1, Encoding.UTF8) + "%0D%0A"
+ UrlEncode(s2, Encoding.UTF8) + "%0D%0A"
+ UrlEncode(s3, Encoding.UTF8);
return resultSign;
}
catch (Exception ex)
{
var excep = ex;
while (excep != null)
{
//logger.Error(excep.Message);
//logger.Error(excep.StackTrace);
excep = excep.InnerException;
}
return string.Empty;
}
}
#endregion
}
#region 交互对象
#region 开票请求
public class RYTPostModel
{
public string version { get; set; }
public RYTPostHeadModel Head { get; set; }
public string Body { get; set; }
}
public class RYTPostHeadModel
{
public string SerialNo { get; set; }
public string PostTime { get; set; }
public string Code { get; set; }
public string Message { get; set; }
}
public class RYTInvoiceModel
{
/// <summary>
/// 是 50 操作流水号。传入重复的操作流水号则认为是重复操作。
/// </summary>
public string SerialNo { get; set; }
/// <summary>
/// 是 100 购货方名称,即发票抬头。
/// </summary>
public string CustomerName { get; set; }
/// <summary>
/// 否 20 购货方纳税人识别号或者个人身份证号
/// </summary>
public string CustomerCode { get; set; }
/// <summary>
/// 否 79 购货方地址。
/// </summary>
public string CustomerAddress { get; set; }
/// <summary>
/// 否 20 购货方电话。
/// </summary>
public string CustomerTel { get; set; }
/// <summary>
/// 否 69 购货方开户银行。
/// </summary>
public string CustomerBankName { get; set; }
/// <summary>
/// 否 30 购货方银行账号。
/// </summary>
public string CustomerBankAccount { get; set; }
/// <summary>
/// 否 69 销货方开户银行。
/// </summary>
public string PartnerBankName { get; set; }
/// <summary>
/// 否 30 销货方银行账号。
/// </summary>
public string PartnerBankAccount { get; set; }
/// <summary>
/// 是 8 开票人。
/// </summary>
public string Drawer { get; set; }
/// <summary>
/// 否 8 收款人。
/// </summary>
public string Payee { get; set; }
/// <summary>
/// 否 8 复核人。
/// </summary>
public string Reviewer { get; set; }
/// <summary>
/// 否 20 币别。
/// </summary>
public string Currency { get; set; }
public decimal Price { get; set; }
/// <summary>
/// 否 2 开 0- 平台模板 1- 自定义,美金发票备注必填 2- 平台模板+自定义,发票备注
/// </summary>
public int RemarkType { get; set; }
/// <summary>
/// 否 130 发票备注。
/// </summary>
public string Remark { get; set; }
/// <summary>
/// 否 50 邮箱。
/// </summary>
public string Email { get; set; }
/// <summary>
/// 否 2 开票类型。p:电子增值税普通发票(默认) ps:电子收购发票 py成品油
/// </summary>
public string InvoiceDrawType { get; set; }
/// <summary>
/// 是 100 发票项目明细列表。每张发票最多一百条。
/// </summary>
public List<RYTInvoiceItemModel> Details { get; set; }
}
public class RYTInvoiceItemModel
{
/// <summary>
/// 是 50 费用名称。
/// </summary>
public string GoodsName { get; set; }
/// <summary>
/// 否 项次。
/// </summary>
public int Item { get; set; }
/// <summary>
/// 是 1 发票行性质 0 正常行、1 折扣行、2 被 折扣行。
/// </summary>
public int Type { get; set; }
/// <summary>
/// 是 90 商品编码。可在每一行商品下加入折扣行,折扣行商品名称与被折扣商品名称一致,金额和税额栏以负数填写,税率与被折扣行商品税率相同,其它栏不填写。
/// </summary>
public string Code { get; set; }
/// <summary>
/// 否 40 规格型号。
/// </summary>
public string Spec { get; set; }
/// <summary>
/// 否 20 单位。
/// </summary>
public string Unit { get; set; }
/// <summary>
/// 两者要么都为空,要么都不为空。 18(整)6(小) 商品单价。必须等于amount/quantity的四舍五入值。
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// 两者要么都为空,要么都不为空。 18(整)6(小) 数量。必须大于等于0.000001。
/// </summary>
public decimal Quantity { get; set; }
/// <summary>
/// 是 18(整)2(小) 税价合计金额。
/// </summary>
public decimal Amount { get; set; }
public string CatalogCode { get; set; }
public string ZeroTaxrateFlag { get; set; }
public decimal TaxRate { get; set; }
}
#endregion
#region 查票请求
public class RYTQueryModel
{
public string name { get; set; }
public string value1 { get; set; }
public string value2 { get; set; }
}
#endregion
#region 冲红请求
public class RYTRedInvoiceModel
{
/// <summary>
/// 是 50 操作流水号。传入重复的操作流水号则认为是重复操作。
/// </summary>
public string SerialNo { get; set; }
/// <summary>
/// 是 19 原发票代码
/// </summary>
public string OriginalInvoiceCode { get; set; }
/// <summary>
/// 是 20 +原发票号码。
/// </summary>
public string OriginalInvoiceNo { get; set; }
public string Email { get; set; }
}
#endregion
#region 返回
public class RYTRespCommon
{
public string version { get; set; }
public RYTRespQuery Head { get; set; }
public string Body { get; set; }
}
public class RYTRespQuery : RuihongRespCommon
{
public string SerialNo { get; set; }
public string PostTime { get; set; }
public string Code { get; set; }
public string Message { get; set; }
}
public class RYTRespQueryInner
{
public string SerialNo { get; set; }
public string InvoiceNo { get; set; }
public string InvoiceCode { get; set; }
public string CheckCode { get; set; }
public string FiscalCode { get; set; }
public string GenerateTime { get; set; }
public string Currency { get; set; }
public string PdfUrl { get; set; }
public string ViewUrl { get; set; }
}
#endregion
#endregion
}