You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DS7/DSWeb/Areas/Account/DAL/Chfee_invoice_HangXin/RYTHelper.cs

771 lines
25 KiB
C#

2 years ago
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
}