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/RuihongHelper.cs

945 lines
32 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;
using DSWeb.Areas.CommMng.DAL;
namespace DSWeb.Common.Helper
{
public class RuihongHelper
{
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 RuihongHelper()
{
}
/// <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)
{
BasicDataRefDAL.SaveLog($"{strParams}","", "瑞宏开票", "发出");
var rtn = DoPostData(strParams, "chinaeinv.api.invoice.v3.kp_async");
BasicDataRefDAL.SaveLog($"{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 + "'");
RuihongPostModel postModel = new RuihongPostModel();
postModel.serialNo = inv.GID;
postModel.postTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
postModel.order = new RuihongPostOrderModel() { orderNo = inv.GID };
if (inv.RECVCURR=="USD")
{
postModel.dynamicParams = new { dollarAmount = inv.OTCURRAMOUNT.ToString() };
}
RuihongPostInvoiceModel postInv = new RuihongPostInvoiceModel();
if (IsTestMode)
{
postInv.taxpayerCode = "91370200264807TEST4A";
}
else
{
//var company = MsCompanysDAL.GetNoPicData("GID='" + inv.COMPANYID + "'");
postInv.taxpayerCode = inv.TAXCODE;
postInv.taxpayerName = inv.BILLRISES;
postInv.taxpayerAddress = inv.ADDRESS;
postInv.taxpayerTel = inv.OFFICEPHONE;
}
if (!string.IsNullOrEmpty(inv.PUSHEMAIL)) {
postModel.notices = new List<RuihongPostNoticeModel>();
postModel.notices.Add(new RuihongPostNoticeModel()
{
type = "email",
value= inv.PUSHEMAIL
});
}
//分拆银行和账号
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;
}
postInv.taxpayerBankName = inv.ACCOUNT.Substring(0, idx + 1);
postInv.taxpayerBankAccount = inv.ACCOUNT.Substring(idx + 1);
break;
}
postInv.customerCode = inv.CUSTRATENO;
postInv.customerName = inv.INVOICECUSTNAME;
postInv.customerAddress = inv.CUSTADDR;
postInv.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;
}
postInv.customerBankName = inv.CUSTBANK.Substring(0, idx + 1);
postInv.customerBankAccount = inv.CUSTBANK.Substring(idx + 1);
break;
}
postInv.drawer = inv.OPERATORNAME;
postInv.reviewer = inv.CHECKER;
postInv.payee = inv.PAYEE;
postInv.totalAmount = inv.INVAMOUNT;
postInv.remark = inv.REMARK;
postModel.invoice = postInv;
postInv.items = new List<RuihongPostInvoiceItemModel>();
foreach (var item in invItems)
{
var goodsCode = item.GOODCODE == null ? string.Empty : item.GOODCODE;
goodsCode = goodsCode.PadRight(19, '0');
//零税率标识。1:免税,2:不征税,3:普通零税率。税率为零的情况下如果不传则默认为1:免税。
var = "1";
if (item.TAXRATE > 0)
{
= null;
}
else
{
if (item.ZTAXTYPE == "免税") = "1";
if (item.ZTAXTYPE == "不征税") = "2";
if (item.ZTAXTYPE == "普通零税率") = "3";
}
var taxrate = Math.Round(item.TAXRATE / 100, 2, MidpointRounding.AwayFromZero).ToString();
if (taxrate == "0.00" || taxrate == "0.0") taxrate = "0";
postInv.items.Add(new RuihongPostInvoiceItemModel()
{
type = "0",
name = item.GOODSNAMEREF,
spec = item.SPEC,
uom = item.UNIT,
quantity = item.PKGS,
taxRate = taxrate,
amount = Math.Round(item.AMOUNT + item.TAX, 2, MidpointRounding.AwayFromZero) ,
price = item.PRICE,
catalogCode = goodsCode,
preferentialPolicyFlg = item.ISUSEPREF,
addedValueTaxFlg = item.DEFREMARK,
zeroTaxRateFlg =
});
}
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
{
T_ALL_DA T_ALL_DA = new EntityDA.T_ALL_DA();
var blUpSQL = "update ch_fee_invoice set EINVOICESTATE='1' where GID='" + invId + "' ";
bool bl = T_ALL_DA.GetExecuteSqlCommand(blUpSQL);
msg = rtnObj.message;
return false;
}
}
#endregion
#region 查票
/// <summary>
/// 查票
/// </summary>
/// <param name="strParams"></param>
/// <returns></returns>
public string QueryInvoice(string strParams)
{
BasicDataRefDAL.SaveLog($"{strParams}", "", "瑞宏查票", "发出");
//logger.Debug($"瑞宏查票:{strParams}");
var rtn = DoPostData(strParams, "chinaeinv.api.invoice.v3.cx");
BasicDataRefDAL.SaveLog($"{rtn}", "", "瑞宏查票返回", "返回");
//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)
{
BasicDataRefDAL.SaveLog($"{strParams}", "", "瑞宏冲红", "发出");
var rtn = DoPostData(strParams, "chinaeinv.api.invoice.v3.ch_async");
BasicDataRefDAL.SaveLog($"{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 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 RuihongPostModel
{
/// <summary>
/// 是 50 操作流水号。传入重复的操作流水号则认为是重复操作。
/// </summary>
public string serialNo { get; set; }
/// <summary>
/// 是 19 请求发送时间。格式为yyyy-MM-dd HH:mm:ss。
/// </summary>
public string postTime { get; set; }
/// <summary>
/// 是 订单信息。
/// </summary>
public RuihongPostOrderModel order { get; set; }
/// <summary>
/// 是 发票信息。
/// </summary>
public RuihongPostInvoiceModel invoice { get; set; }
/// <summary>
/// 否 3 通知方式列表最多3条。
/// </summary>
public List<RuihongPostNoticeModel> notices { get; set; }
/// <summary>
/// 否 20 扩展参数。一组Key-Value形式的数据会在响应报文中回传给调用方由调用者和瑞宏网双方根据实际情况协商使用。
/// </summary>
public object extendedParams { get; set; }
/// <summary>
/// 否 自定义参数。一组Key-Value形式的数据key值callbackUrlValue为回调地址“http://wwww.***.com/test/invoice”
/// </summary>
public object dynamicParams { get; set; }
}
public class RuihongPostOrderModel
{
/// <summary>
/// 是 50 订单编号。
/// </summary>
public string orderNo { get; set; }
/// <summary>
/// 否 100 消费者的用户名。
/// </summary>
public string account { get; set; }
/// <summary>
/// 否 250 货物配送地址。
/// </summary>
public string address { get; set; }
/// <summary>
/// 否 消费者电话号码。手机号码或区号-固定电话号码。
/// </summary>
public string tel { get; set; }
/// <summary>
/// 否 消费者电子邮件地址。电子邮件格式。
/// </summary>
public string email { get; set; }
}
public class RuihongPostInvoiceItemModel
{
/// <summary>
/// 是 1 发票行性质 0 正常行、1 折扣行、2 被 折扣行。
/// </summary>
public string type { get; set; }
/// <summary>
/// 否 50 商品编码。
/// </summary>
public string code { get; set; }
/// <summary>
/// 是 90 商品名称。可在每一行商品下加入折扣行,折扣行商品名称与被折扣商品名称一致,金额和税额栏以负数填写,税率与被折扣行商品税率相同,其它栏不填写。
/// </summary>
public string name { get; set; }
/// <summary>
/// 否 40 规格型号。
/// </summary>
public string spec { 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>
/// 否 20 单位。
/// </summary>
public string uom { get; set; }
/// <summary>
/// 是 6(小) 税率。只能为0、 0.03、0.04、0.06、0.10、0.11、0.16、0.17。
/// </summary>
public string taxRate { get; set; }
/// <summary>
/// 是 18(整)2(小) 税价合计金额。
/// </summary>
public decimal amount { get; set; }
/// <summary>
/// 是 50 商品分类编码。目前的分类编码为19位不足19位的在后面补0。
/// </summary>
public string catalogCode { get; set; }
/// <summary>
/// 否 1 优惠政策标识。0:不使用,1:使用。
/// </summary>
public string preferentialPolicyFlg { get; set; }
/// <summary>
/// 否 50 增值税特殊管理当优惠政策标识为1时必填
/// </summary>
public string addedValueTaxFlg { get; set; }
/// <summary>
/// 否 1 零税率标识。1:免税,2:不征税,3:普通零税率。税率为零的情况下如果不传则默认为3:普通零税率。
/// </summary>
public string zeroTaxRateFlg { get; set; }
}
public class RuihongPostInvoiceModel
{
/// <summary>
/// 是 20 销货方纳税人识别号。
/// </summary>
public string taxpayerCode { get; set; }
/// <summary>
/// 否 100 销货方纳税人名称
/// </summary>
public string taxpayerName { get; set; }
/// <summary>
/// 否 79 销货方地址。如果填写则使用填写的信息,否则使用纳税人注册时预留的信息。
/// </summary>
public string taxpayerAddress { get; set; }
/// <summary>
/// 否 20 销货方电话。
/// </summary>
public string taxpayerTel { get; set; }
/// <summary>
/// 否 69 销货方开户银行。
/// </summary>
public string taxpayerBankName { get; set; }
/// <summary>
/// 否 30 销货方银行账号。
/// </summary>
public string taxpayerBankAccount { 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>
/// 否 2 开票类型。p:电子增值税普通发票(默认) ps:电子收购发票 py成品油
/// </summary>
public string invoiceType { get; set; }
/// <summary>
/// 否 50 店铺编号
/// </summary>
public string shopCode { get; set; }
/// <summary>
/// 否 50 店铺名称
/// </summary>
public string shopName { get; set; }
/// <summary>
/// 否 50 支付方式
/// </summary>
public string payType { get; set; }
/// <summary>
/// 否 50 支付流水号
/// </summary>
public string payBillNo { 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>
/// 是 18(整)2(小) 税价合计金额。必须大于等于0.01元;必须等于发票明细合计金额;必须小于等于在税务局进行票种核定时确定的单张发票开票限额。
/// </summary>
public decimal totalAmount { get; set; }
/// <summary>
/// 否 130 发票备注。
/// </summary>
public string remark { get; set; }
/// <summary>
/// 是 100 发票项目明细列表。每张发票最多一百条。
/// </summary>
public List<RuihongPostInvoiceItemModel> items { get; set; }
}
public class RuihongPostNoticeModel
{
/// <summary>
/// 是 通知类型。短信sms电子邮件email。
/// </summary>
public string type { get; set; }
/// <summary>
/// 是 通知类型为短信时,必须为手机号码;通知类型为电子邮件时,必须为邮件地址。
/// </summary>
public string value { get; set; }
}
#endregion
#region 查票请求
public class RuihongQueryModel
{
public string serialNo { get; set; }
public string postTime { get; set; }
public List<RuihongQueryInner> criteria { get; set; }
}
public class RuihongQueryInner
{
public string name { get; set; }
public string value { get; set; }
}
#endregion
#region 冲红请求
public class RuihongRedInvoiceModel
{
/// <summary>
/// 是 50 操作流水号。传入重复的操作流水号则认为是重复操作。
/// </summary>
public string serialNo { get; set; }
/// <summary>
/// 是 19 请求发送时间。格式为yyyy-MM-dd HH:mm:ss。
/// </summary>
public string postTime { get; set; }
/// <summary>
/// 是 20 原发票代码+原发票号码。
/// </summary>
public string originalCode { get; set; }
/// <summary>
/// 是 250 冲红原因。
/// </summary>
public string reason { get; set; }
/// <summary>
/// 否 3 通知方式列表。
/// </summary>
public List<RuihongPostNoticeModel> notices { get; set; }
/// <summary>
/// 否 100 发票项目明细列表。每张发票最多一百条。如果为空则按照原发票金额和明细全额冲红。如果不为空则按照该明细和金额进行部分冲红。
/// </summary>
public List<RuihongPostInvoiceItemModel> items { get; set; }
}
#endregion
#region 返回
public class RuihongRespCommon
{
public string serialNo { get; set; }
public string postTime { get; set; }
public string code { get; set; }
public string message { get; set; }
}
public class RuihongRespQuery : RuihongRespCommon
{
public List<RuihongRespQueryInner> invoices { get; set; }
}
public class RuihongRespQueryInner
{
public string orderNo { get; set; }
public string code { get; set; }
public string checkCode { get; set; }
public string fiscalCode { get; set; }
public string status { get; set; }
public string generateTime { get; set; }
public string pdfUnsignedUrl { get; set; }
public string viewUrl { get; set; }
public string relatedCode { get; set; }
public string validReason { get; set; }
public string validTime { get; set; }
}
#endregion
#endregion
}