.DS_Store | |||||
java/.idea/ | |||||
java/out/ | |||||
java/*.iml | |||||
cs/.vs/ |
| |||||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||||
# Visual Studio 14 | |||||
VisualStudioVersion = 14.0.24720.0 | |||||
MinimumVisualStudioVersion = 10.0.40219.1 | |||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "einv-demo-order-cs", "einv-demo-order-cs\einv-demo-order-cs.csproj", "{EB51574C-DA86-4CBE-BC6B-1FCA249B0D6A}" | |||||
EndProject | |||||
Global | |||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
Debug|Any CPU = Debug|Any CPU | |||||
Release|Any CPU = Release|Any CPU | |||||
EndGlobalSection | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{EB51574C-DA86-4CBE-BC6B-1FCA249B0D6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{EB51574C-DA86-4CBE-BC6B-1FCA249B0D6A}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{EB51574C-DA86-4CBE-BC6B-1FCA249B0D6A}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{EB51574C-DA86-4CBE-BC6B-1FCA249B0D6A}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
EndGlobal |
using System; | |||||
using System.Collections.Generic; | |||||
using com.chinaeinv.einv.order; | |||||
using com.chinaeinv.einv.order.dto; | |||||
using System.Collections; | |||||
namespace einv_demo_order_cs | |||||
{ | |||||
class Program | |||||
{ | |||||
// 由电子发票平台分配的appCode | |||||
private static string appCode = "请向瑞宏网工作人员索取"; | |||||
// 证书文件路径 | |||||
private static string keyStorePath = "请向瑞宏网工作人员索取"; | |||||
// 证书密码 | |||||
private static string password = "请向瑞宏网工作人员索取"; | |||||
// 接口URL | |||||
private static string apiUrl = "https://www.chinaeinv.com:943/igs/api/orderApi.jspa"; | |||||
// 销售方纳税人识别号 | |||||
private static string testTaxpayerCode = "请向瑞宏网工作人员索取"; | |||||
private static OrderFacade orderFacade = new OrderFacadeAgent(appCode, keyStorePath, password, apiUrl); | |||||
static void Main(string[] args) | |||||
{ | |||||
// (异步)开具蓝字发票 | |||||
TestKpAsync(); | |||||
// (异步)开具红字发票 | |||||
//TestChAsync(); | |||||
// (异步)对开票失败的订单重新开票 | |||||
//TestRetryKpAsync(); | |||||
// (同步)取消订单 | |||||
//TestCancel(); | |||||
// (同步)根据订单编号查询发票 | |||||
//TestCxByOrderNo(); | |||||
Console.WriteLine("按回车键退出。"); | |||||
Console.ReadLine(); //等待用户按一个回车 | |||||
return; //可选,按下回车后关闭 | |||||
} | |||||
/** | |||||
* (异步)开具蓝字发票 | |||||
*/ | |||||
private static void TestKpAsync() | |||||
{ | |||||
Order order = new Order(); | |||||
// 订单编号 | |||||
order.orderNo = "OrderNo-007"; | |||||
// 销货方纳税人识别号 | |||||
order.taxpayerCode = testTaxpayerCode; | |||||
// 用户扫码key | |||||
order.scanCodeKey = Guid.NewGuid().ToString(); | |||||
// 店铺 | |||||
order.shopName = "第198店"; | |||||
// 店铺编号 | |||||
order.shopCode = "198"; | |||||
// 订单时间(yyyy-MM-dd HH:mm:ss) | |||||
order.orderTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); | |||||
// 联系人 | |||||
order.contact = "小明"; | |||||
// 联系电话 | |||||
order.contactTel = "18000000000"; | |||||
// 邮箱 | |||||
order.contactMail = "test@chinaeinv.cn"; | |||||
// 配送地址 | |||||
order.shippingAddress = "火星北路1024号"; | |||||
// 购货方名称,即发票抬头 | |||||
order.customerName = "小明"; | |||||
// 是否自动开票 | |||||
order.autoBilling = true; | |||||
// 开票人 | |||||
order.drawer = "张三"; | |||||
// 收款人 | |||||
order.payee = "李四"; | |||||
// 复核人 | |||||
order.reviewer = "王五"; | |||||
// 开票金额 | |||||
order.totalAmount = "24000"; | |||||
// 发票备注 | |||||
order.remark = "软件系统维护期限为2018年1月1日至2019年12月31日。"; | |||||
// 发票明细1 | |||||
OrderItem orderItem1 = new OrderItem(); | |||||
//商品编码 | |||||
orderItem1.code = "001"; | |||||
//商品名称 | |||||
orderItem1.name = "软件开发"; | |||||
//规格型号 | |||||
orderItem1.spec = "无"; | |||||
//税率 | |||||
orderItem1.taxRate = "0.06"; | |||||
//税价合计金额 | |||||
orderItem1.amount = "10000"; | |||||
//商品分类编码 | |||||
orderItem1.catalogCode = "3040203000000000000"; | |||||
// 发票明细2 | |||||
OrderItem orderItem2 = new OrderItem(); | |||||
//商品编码 | |||||
orderItem2.code = "002"; | |||||
//商品名称 | |||||
orderItem2.name = "软件系统维护"; | |||||
//规格型号 | |||||
orderItem2.spec = "无"; | |||||
//商品单价 | |||||
orderItem2.price = "8000"; | |||||
//数量 | |||||
orderItem2.quantity = "2"; | |||||
//单位 | |||||
orderItem2.uom = "年"; | |||||
//税率 | |||||
orderItem2.taxRate = "0.06"; | |||||
//税价合计金额 | |||||
orderItem2.amount = "16000"; | |||||
//折扣金额 | |||||
orderItem2.discountAmount = "2000"; | |||||
//商品分类编码 | |||||
orderItem2.catalogCode = "3040203000000000000"; | |||||
// 发票明细 | |||||
order.orderItems = new List<OrderItem>(); | |||||
order.orderItems.Add(orderItem1); | |||||
order.orderItems.Add(orderItem2); | |||||
// 扩展参数 | |||||
order.extendedParams = new Hashtable(); | |||||
order.extendedParams.Add("testExtendedNo1", "12345678"); | |||||
order.extendedParams.Add("testExtendedNo2", "87654321"); | |||||
// 调用接口方法 | |||||
orderFacade.KpAsync(order); | |||||
} | |||||
/** | |||||
* (异步)开具红字发票 | |||||
*/ | |||||
private static void TestChAsync() | |||||
{ | |||||
Order order = new Order(); | |||||
// 订单编号 | |||||
order.orderNo = "OrderNo-006"; | |||||
// 销货方纳税人识别号 | |||||
order.taxpayerCode = testTaxpayerCode; | |||||
// 冲红原因 | |||||
order.reason = "开票信息有误。"; | |||||
// 调用接口方法 | |||||
orderFacade.ChAsync(order); | |||||
} | |||||
/** | |||||
* (异步)对开票失败的订单重新开票 | |||||
*/ | |||||
private static void TestRetryKpAsync() | |||||
{ | |||||
OrderBase order = new OrderBase(); | |||||
// 订单编号 | |||||
order.orderNo = "OrderNo-004"; | |||||
// 销货方纳税人识别号 | |||||
order.taxpayerCode = testTaxpayerCode; | |||||
// 调用接口方法 | |||||
orderFacade.RetryKpAsync(order); | |||||
} | |||||
/** | |||||
* (同步)取消订单 | |||||
*/ | |||||
private static void TestCancel() | |||||
{ | |||||
OrderBase order = new OrderBase(); | |||||
// 订单编号 | |||||
order.orderNo = "OrderNo-004"; | |||||
// 销货方纳税人识别号 | |||||
order.taxpayerCode = testTaxpayerCode; | |||||
// 调用接口方法 | |||||
orderFacade.Cancel(order); | |||||
} | |||||
/** | |||||
* (同步)根据订单编号查询发票 | |||||
*/ | |||||
private static void TestCxByOrderNo() | |||||
{ | |||||
OrderBase orderBase = new OrderBase("OrderNo-006", testTaxpayerCode); | |||||
// 调用接口方法 | |||||
orderFacade.CxByOrderNo(orderBase); | |||||
} | |||||
} | |||||
} |
using System.Reflection; | |||||
using System.Runtime.CompilerServices; | |||||
using System.Runtime.InteropServices; | |||||
// 有关程序集的一般信息由以下 | |||||
// 控制。更改这些特性值可修改 | |||||
// 与程序集关联的信息。 | |||||
[assembly: AssemblyTitle("einv-demo-order-cs")] | |||||
[assembly: AssemblyDescription("")] | |||||
[assembly: AssemblyConfiguration("")] | |||||
[assembly: AssemblyCompany("")] | |||||
[assembly: AssemblyProduct("einv-demo-order-cs")] | |||||
[assembly: AssemblyCopyright("Copyright © 2018")] | |||||
[assembly: AssemblyTrademark("")] | |||||
[assembly: AssemblyCulture("")] | |||||
//将 ComVisible 设置为 false 将使此程序集中的类型 | |||||
//对 COM 组件不可见。 如果需要从 COM 访问此程序集中的类型, | |||||
//请将此类型的 ComVisible 特性设置为 true。 | |||||
[assembly: ComVisible(false)] | |||||
// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID | |||||
[assembly: Guid("eb51574c-da86-4cbe-bc6b-1fca249b0d6a")] | |||||
// 程序集的版本信息由下列四个值组成: | |||||
// | |||||
// 主版本 | |||||
// 次版本 | |||||
// 生成号 | |||||
// 修订号 | |||||
// | |||||
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, | |||||
// 方法是按如下所示使用“*”: : | |||||
// [assembly: AssemblyVersion("1.0.*")] | |||||
[assembly: AssemblyVersion("1.0.0.0")] | |||||
[assembly: AssemblyFileVersion("1.0.0.0")] |
using com.chinaeinv.einv.order.dto; | |||||
namespace com.chinaeinv.einv.order | |||||
{ | |||||
/** | |||||
* 订单接口 | |||||
*/ | |||||
public interface OrderFacade { | |||||
/** | |||||
* (异步)开具蓝字发票异步方法 | |||||
*/ | |||||
Result KpAsync(Order order); | |||||
/** | |||||
* (异步)开具红字发票异步方法 | |||||
*/ | |||||
Result ChAsync(Order order); | |||||
/** | |||||
* (异步)对开票失败的订单重新开票异步方法 | |||||
*/ | |||||
Result RetryKpAsync(OrderBase orderBase); | |||||
/** | |||||
* (同步)取消订单 | |||||
*/ | |||||
Result Cancel(OrderBase orderBase); | |||||
/** | |||||
* (同步)根据订单编号查询发票 | |||||
*/ | |||||
InvoiceResult CxByOrderNo(OrderBase orderBase); | |||||
} | |||||
} |
using System; | |||||
using System.Net; | |||||
using System.Text; | |||||
using System.Web; | |||||
using System.Security.Cryptography; | |||||
using System.Security.Cryptography.X509Certificates; | |||||
using com.chinaeinv.einv.order.dto; | |||||
using Newtonsoft.Json; | |||||
namespace com.chinaeinv.einv.order | |||||
{ | |||||
/** | |||||
* 订单接口代理实现 | |||||
*/ | |||||
public class OrderFacadeAgent : OrderFacade { | |||||
private string appCode, keyStorePath, password, apiUrl; | |||||
/** | |||||
* 构造方法 | |||||
* @param appCode 由电子发票平台分配的appCode | |||||
* @param keyStorePath 密钥库文件路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @param apiUrl 接口URL | |||||
*/ | |||||
public OrderFacadeAgent(string appCode, string keyStorePath, string password, string apiUrl) { | |||||
this.appCode = appCode; | |||||
this.keyStorePath = keyStorePath; | |||||
this.password = password; | |||||
this.apiUrl = apiUrl; | |||||
} | |||||
/** | |||||
* (异步)开具蓝字发票 | |||||
*/ | |||||
public Result KpAsync(Order order) { | |||||
return Exec<Result, Order>(order, "chinaeinv.api.order.v11.kp_async"); | |||||
} | |||||
/** | |||||
* (异步)开具红字发票 | |||||
*/ | |||||
public Result ChAsync(Order order) { | |||||
return Exec<Result, Order>(order, "chinaeinv.api.order.v11.ch_async"); | |||||
} | |||||
/** | |||||
* (异步)对开票失败的订单重新开票 | |||||
*/ | |||||
public Result RetryKpAsync(OrderBase orderBase) { | |||||
return Exec<Result, OrderBase>(orderBase, "chinaeinv.api.order.v11.retryKp_async"); | |||||
} | |||||
/** | |||||
* (同步)取消订单 | |||||
*/ | |||||
public Result Cancel(OrderBase orderBase) { | |||||
return Exec<Result, OrderBase>(orderBase, "chinaeinv.api.order.v11.cancel"); | |||||
} | |||||
/** | |||||
* (同步)根据订单编号查询发票 | |||||
*/ | |||||
public InvoiceResult CxByOrderNo(OrderBase orderBase) { | |||||
return Exec<InvoiceResult, OrderBase>(orderBase, "chinaeinv.api.order.v11.cx.orderNo"); | |||||
} | |||||
/** | |||||
* 调用接口 | |||||
* @param order 请求数据 | |||||
* @return 响应数据 | |||||
* @throws Exception | |||||
*/ | |||||
private T Exec<T,O>(O order, string cmdName) { | |||||
// 将Order对象转为json | |||||
string requestJson = JsonConvert.SerializeObject(order, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); | |||||
Console.WriteLine("方法名称: " + cmdName + ", 请求报文: " + requestJson); | |||||
// 生成签名 | |||||
string sign = GetSign(requestJson); | |||||
Console.WriteLine("方法名称: " + cmdName + ", 签名: " + sign); | |||||
// 调用接口 | |||||
string responseJson; | |||||
using (var client = new WebClient()) | |||||
{ | |||||
client.Encoding = Encoding.UTF8; | |||||
client.QueryString.Add("appCode", appCode); | |||||
client.QueryString.Add("cmdName", cmdName); | |||||
client.QueryString.Add("sign", UrlEncode(UrlEncode(sign, Encoding.UTF8), Encoding.UTF8)); // C#中需要进行两次UrlEncode,不然发送请求时加号会变空格,导致验签失败。 | |||||
responseJson = client.UploadString(apiUrl, requestJson); | |||||
} | |||||
Console.WriteLine("方法名称: " + cmdName + ", 响应报文: " + responseJson); | |||||
// 将响应json转为对象 | |||||
return JsonConvert.DeserializeObject<T>(responseJson); | |||||
} | |||||
/** | |||||
* 数字签名 | |||||
*/ | |||||
private string GetSign(string kpParams) | |||||
{ | |||||
X509Certificate2 x = new X509Certificate2(keyStorePath, password, 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"); | |||||
return Convert.ToBase64String(sign); | |||||
} | |||||
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(); | |||||
} | |||||
} | |||||
} |
using System.Collections.Generic; | |||||
namespace com.chinaeinv.einv.order.dto | |||||
{ | |||||
/** | |||||
* 开票请求中的发票信息 | |||||
*/ | |||||
public class Invoice | |||||
{ | |||||
/** | |||||
* 订单编号 | |||||
*/ | |||||
public string orderNo { get; set; } | |||||
/** | |||||
* 子订单编号 | |||||
*/ | |||||
public string subOrderNo { get; set; } | |||||
/** | |||||
* 店铺名称 | |||||
*/ | |||||
public string shopName { get; set; } | |||||
/** | |||||
* 店铺编号 | |||||
*/ | |||||
public string shopCode { get; set; } | |||||
/** | |||||
* 销货方纳税人识别号 | |||||
*/ | |||||
public string taxpayerCode { get; set; } | |||||
/** | |||||
* 销货方名称 | |||||
*/ | |||||
public string taxpayerName { get; set; } | |||||
/** | |||||
* 销货方地址 | |||||
*/ | |||||
public string taxpayerAddress { get; set; } | |||||
/** | |||||
* 销货方电话 | |||||
*/ | |||||
public string taxpayerTel { get; set; } | |||||
/** | |||||
* 销货方开户银行 | |||||
*/ | |||||
public string taxpayerBankName { get; set; } | |||||
/** | |||||
* 销货方银行账号 | |||||
*/ | |||||
public string taxpayerBankAccount { get; set; } | |||||
/** | |||||
* 购货方纳税人识别号 | |||||
*/ | |||||
public string customerCode { get; set; } | |||||
/** | |||||
* 购货方名称,即发票抬头 | |||||
*/ | |||||
public string customerName { get; set; } | |||||
/** | |||||
* 购货方地址 | |||||
*/ | |||||
public string customerAddress { get; set; } | |||||
/** | |||||
* 购货方电话 | |||||
*/ | |||||
public string customerTel { get; set; } | |||||
/** | |||||
* 购货方开户银行 | |||||
*/ | |||||
public string customerBankName { get; set; } | |||||
/** | |||||
* 购货方银行账号 | |||||
*/ | |||||
public string customerBankAccount { get; set; } | |||||
/** | |||||
* 发票代码+发票号码 | |||||
*/ | |||||
public string code { get; set; } | |||||
/** | |||||
* 校验码 | |||||
*/ | |||||
public string checkCode { get; set; } | |||||
/** | |||||
* 税控码 | |||||
*/ | |||||
public string fiscalCode { get; set; } | |||||
/** | |||||
* 发票状态 | |||||
* 正常:1 | |||||
* 红冲:3 | |||||
* 被红冲:4 | |||||
*/ | |||||
public string status { get; set; } | |||||
/** | |||||
* 生成时间 | |||||
*/ | |||||
public string generateTime { get; set; } | |||||
/** | |||||
* 税价合计金额 | |||||
*/ | |||||
public string totalAmount { get; set; } | |||||
/** | |||||
* 不含税金额 | |||||
*/ | |||||
public string noTaxAmount { get; set; } | |||||
/** | |||||
* 税额 | |||||
*/ | |||||
public string taxAmount { get; set; } | |||||
/** | |||||
* 开票人 | |||||
*/ | |||||
public string drawer { get; set; } | |||||
/** | |||||
* 收款人 | |||||
*/ | |||||
public string payee { get; set; } | |||||
/** | |||||
* 复核人 | |||||
*/ | |||||
public string reviewer { get; set; } | |||||
/** | |||||
* 发票备注 | |||||
*/ | |||||
public string remark { get; set; } | |||||
/** | |||||
* 未签名PDF下载URL | |||||
*/ | |||||
public string pdfUnsignedUrl { get; set; } | |||||
/** | |||||
* 查看URL | |||||
*/ | |||||
public string viewUrl { get; set; } | |||||
/** | |||||
* 关联发票编号 | |||||
*/ | |||||
public string relatedCode { get; set; } | |||||
/** | |||||
* 作废/红冲原因 | |||||
*/ | |||||
public string validReason { get; set; } | |||||
/** | |||||
* 作废/红冲时间 | |||||
*/ | |||||
public string validTime { get; set; } | |||||
/** | |||||
* 项目明细 | |||||
*/ | |||||
public List<InvoiceItem> items { get; set; } | |||||
} | |||||
} |
namespace com.chinaeinv.einv.order.dto | |||||
{ | |||||
/** | |||||
* 发票项目明细 | |||||
*/ | |||||
public class InvoiceItem { | |||||
/** | |||||
* 发票行性质 0 正常行、1 折扣行、2 被折扣行 | |||||
*/ | |||||
public string type { get; set; } | |||||
/** | |||||
* 商品编码 | |||||
*/ | |||||
public string code { get; set; } | |||||
/** | |||||
* 商品名称 | |||||
*/ | |||||
public string name { get; set; } | |||||
/** | |||||
* 规格型号 | |||||
*/ | |||||
public string spec { get; set; } | |||||
/** | |||||
* 含税商品单价 | |||||
*/ | |||||
public string price { get; set; } | |||||
/** | |||||
* 数量 | |||||
*/ | |||||
public string quantity { get; set; } | |||||
/** | |||||
* 单位 | |||||
*/ | |||||
public string uom { get; set; } | |||||
/** | |||||
* 税率 | |||||
*/ | |||||
public string taxRate { get; set; } | |||||
/** | |||||
* 税价合计金额 | |||||
*/ | |||||
public string amount { get; set; } | |||||
/** | |||||
* 不含税金额 | |||||
*/ | |||||
public string noTaxAmount { get; set; } | |||||
/** | |||||
* 税额 | |||||
*/ | |||||
public string taxAmount { get; set; } | |||||
/** | |||||
* 商品分类编码 | |||||
*/ | |||||
public string catalogCode { get; set; } | |||||
/** | |||||
* 优惠政策标识 | |||||
*/ | |||||
public string preferentialPolicyFlg { get; set; } | |||||
/** | |||||
* 增值税特殊管理 | |||||
*/ | |||||
public string addedValueTaxFlg { get; set; } | |||||
/** | |||||
* 零税率标识 | |||||
*/ | |||||
public string zeroTaxRateFlg { get; set; } | |||||
} | |||||
} |
using System.Collections.Generic; | |||||
namespace com.chinaeinv.einv.order.dto | |||||
{ | |||||
/** | |||||
* “根据订单编号查询发票”方法响应和回调数据 | |||||
*/ | |||||
public class InvoiceResult : Result { | |||||
/** | |||||
* 发票列表 | |||||
*/ | |||||
public List<Invoice> invoices { get; set; } | |||||
} | |||||
} |
using System.Collections.Generic; | |||||
using System.Collections; | |||||
using System; | |||||
namespace com.chinaeinv.einv.order.dto | |||||
{ | |||||
/** | |||||
* 订单详细信息 | |||||
*/ | |||||
public class Order : OrderBase { | |||||
/** | |||||
* 用户扫码key | |||||
*/ | |||||
public string scanCodeKey { get; set; } | |||||
/** | |||||
* 店铺 | |||||
*/ | |||||
public string shopName { get; set; } | |||||
/** | |||||
* 店铺编号 | |||||
*/ | |||||
public string shopCode { get; set; } | |||||
/** | |||||
* 订单时间(yyyy-MM-dd HH:mm:ss) | |||||
*/ | |||||
public string orderTime { get; set; } | |||||
/** | |||||
* 联系人 | |||||
*/ | |||||
public string contact { get; set; } | |||||
/** | |||||
* 联系电话 | |||||
*/ | |||||
public string contactTel { get; set; } | |||||
/** | |||||
* 邮箱 | |||||
*/ | |||||
public string contactMail { get; set; } | |||||
/** | |||||
* 配送地址 | |||||
*/ | |||||
public string shippingAddress { get; set; } | |||||
/** | |||||
* 销货方名称 | |||||
*/ | |||||
public string taxpayerName { get; set; } | |||||
/** | |||||
* 销货方地址 | |||||
*/ | |||||
public string taxpayerAddress { get; set; } | |||||
/** | |||||
* 销货方电话 | |||||
*/ | |||||
public string taxpayerTel { get; set; } | |||||
/** | |||||
* 销货方开户银行 | |||||
*/ | |||||
public string taxpayerBankName { get; set; } | |||||
/** | |||||
* 销货方银行账号 | |||||
*/ | |||||
public string taxpayerBankAccount { get; set; } | |||||
/** | |||||
* 购货方名称,即发票抬头 | |||||
*/ | |||||
public string customerName { get; set; } | |||||
/** | |||||
* 购货方纳税人识别号 | |||||
*/ | |||||
public string customerCode { get; set; } | |||||
/** | |||||
* 购货方地址 | |||||
*/ | |||||
public string customerAddress { get; set; } | |||||
/** | |||||
* 购货方电话 | |||||
*/ | |||||
public string customerTel { get; set; } | |||||
/** | |||||
* 购货方开户银行 | |||||
*/ | |||||
public string customerBankName { get; set; } | |||||
/** | |||||
* 购货方银行账号 | |||||
*/ | |||||
public string customerBankAccount { get; set; } | |||||
/** | |||||
* 是否自动开票 | |||||
*/ | |||||
public Boolean autoBilling { get; set; } | |||||
/** | |||||
* 开票人 | |||||
*/ | |||||
public string drawer { get; set; } | |||||
/** | |||||
* 收款人 | |||||
*/ | |||||
public string payee { get; set; } | |||||
/** | |||||
* 复核人 | |||||
*/ | |||||
public string reviewer { get; set; } | |||||
/** | |||||
* 开票金额 | |||||
*/ | |||||
public string totalAmount { get; set; } | |||||
/** | |||||
* 发票备注 | |||||
*/ | |||||
public string remark { get; set; } | |||||
/** | |||||
* 冲红原因 | |||||
*/ | |||||
public string reason { get; set; } | |||||
/** | |||||
* 订单明细 | |||||
*/ | |||||
public List<OrderItem> orderItems { get; set; } | |||||
/** | |||||
* 扩展参数 | |||||
*/ | |||||
public Hashtable extendedParams { get; set; } | |||||
/** | |||||
* 动态参数 | |||||
*/ | |||||
public Hashtable dynamicParams { get; set; } | |||||
} | |||||
} |
namespace com.chinaeinv.einv.order.dto | |||||
{ | |||||
/** | |||||
* 订单基本信息 | |||||
*/ | |||||
public class OrderBase { | |||||
/** | |||||
* 订单编号 | |||||
*/ | |||||
public string orderNo { get; set; } | |||||
/** | |||||
* 子订单编号 | |||||
*/ | |||||
public string subOrderNo { get; set; } | |||||
/** | |||||
* 销货方纳税人识别号 | |||||
*/ | |||||
public string taxpayerCode { get; set; } | |||||
/** | |||||
* 发票类型 | |||||
*/ | |||||
public string invoiceType { get; set; } | |||||
public OrderBase() { | |||||
} | |||||
public OrderBase(string orderNo, string taxpayerCode) { | |||||
this.orderNo = orderNo; | |||||
this.taxpayerCode = taxpayerCode; | |||||
} | |||||
public OrderBase(string orderNo, string subOrderNo, string taxpayerCode) { | |||||
this.orderNo = orderNo; | |||||
this.subOrderNo = subOrderNo; | |||||
this.taxpayerCode = taxpayerCode; | |||||
} | |||||
} | |||||
} |
namespace com.chinaeinv.einv.order.dto | |||||
{ | |||||
public class OrderItem { | |||||
/** | |||||
* 商品编码 | |||||
*/ | |||||
public string code { get; set; } | |||||
/** | |||||
* 商品名称 | |||||
*/ | |||||
public string name { get; set; } | |||||
/** | |||||
* 规格型号 | |||||
*/ | |||||
public string spec { get; set; } | |||||
/** | |||||
* 商品单价 | |||||
*/ | |||||
public string price { get; set; } | |||||
/** | |||||
* 数量 | |||||
*/ | |||||
public string quantity { get; set; } | |||||
/** | |||||
* 单位 | |||||
*/ | |||||
public string uom { get; set; } | |||||
/** | |||||
* 税率 | |||||
*/ | |||||
public string taxRate { get; set; } | |||||
/** | |||||
* 税价合计金额 | |||||
*/ | |||||
public string amount { get; set; } | |||||
/** | |||||
* 折扣金额 | |||||
*/ | |||||
public string discountAmount { get; set; } | |||||
/** | |||||
* 商品分类编码 | |||||
*/ | |||||
public string catalogCode { get; set; } | |||||
/** | |||||
* 优惠政策标识 | |||||
*/ | |||||
public string preferentialPolicyFlg { get; set; } | |||||
/** | |||||
* 增值税特殊管理 | |||||
*/ | |||||
public string addedValueTaxFlg { get; set; } | |||||
/** | |||||
* 零税率标识 | |||||
*/ | |||||
public string zeroTaxRateFlg { get; set; } | |||||
} | |||||
} |
namespace com.chinaeinv.einv.order.dto | |||||
{ | |||||
/** | |||||
* 异步方法响应和“取消订单”方法响应 | |||||
*/ | |||||
public class Result { | |||||
/** | |||||
* 处理结果代码 | |||||
*/ | |||||
public string code { get; set; } | |||||
/** | |||||
* 处理结果消息 | |||||
*/ | |||||
public string message { get; set; } | |||||
} | |||||
} |
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | |||||
<PropertyGroup> | |||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | |||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | |||||
<ProjectGuid>{EB51574C-DA86-4CBE-BC6B-1FCA249B0D6A}</ProjectGuid> | |||||
<OutputType>Exe</OutputType> | |||||
<AppDesignerFolder>Properties</AppDesignerFolder> | |||||
<RootNamespace>einv_demo_order_cs</RootNamespace> | |||||
<AssemblyName>einv-demo-order-cs</AssemblyName> | |||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion> | |||||
<FileAlignment>512</FileAlignment> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | |||||
<PlatformTarget>AnyCPU</PlatformTarget> | |||||
<DebugSymbols>true</DebugSymbols> | |||||
<DebugType>full</DebugType> | |||||
<Optimize>false</Optimize> | |||||
<OutputPath>bin\Debug\</OutputPath> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | |||||
<PlatformTarget>AnyCPU</PlatformTarget> | |||||
<DebugType>pdbonly</DebugType> | |||||
<Optimize>true</Optimize> | |||||
<OutputPath>bin\Release\</OutputPath> | |||||
<DefineConstants>TRACE</DefineConstants> | |||||
<ErrorReport>prompt</ErrorReport> | |||||
<WarningLevel>4</WarningLevel> | |||||
</PropertyGroup> | |||||
<ItemGroup> | |||||
<Reference Include="Newtonsoft.Json, Version=4.0.3.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL"> | |||||
<SpecificVersion>False</SpecificVersion> | |||||
<HintPath>lib\Newtonsoft.Json.dll</HintPath> | |||||
</Reference> | |||||
<Reference Include="System" /> | |||||
<Reference Include="System.Core" /> | |||||
<Reference Include="System.Runtime.Serialization" /> | |||||
<Reference Include="System.Security" /> | |||||
<Reference Include="System.Web" /> | |||||
<Reference Include="System.Xml.Linq" /> | |||||
<Reference Include="System.Data.DataSetExtensions" /> | |||||
<Reference Include="Microsoft.CSharp" /> | |||||
<Reference Include="System.Data" /> | |||||
<Reference Include="System.Xml" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Compile Include="com\chinaeinv\einv\order\dto\Invoice.cs" /> | |||||
<Compile Include="com\chinaeinv\einv\order\dto\InvoiceItem.cs" /> | |||||
<Compile Include="com\chinaeinv\einv\order\dto\InvoiceResult.cs" /> | |||||
<Compile Include="com\chinaeinv\einv\order\dto\Order.cs" /> | |||||
<Compile Include="com\chinaeinv\einv\order\dto\OrderBase.cs" /> | |||||
<Compile Include="com\chinaeinv\einv\order\dto\OrderItem.cs" /> | |||||
<Compile Include="com\chinaeinv\einv\order\dto\Result.cs" /> | |||||
<Compile Include="com\chinaeinv\einv\order\OrderFacade.cs" /> | |||||
<Compile Include="com\chinaeinv\einv\order\OrderFacadeAgent.cs" /> | |||||
<Compile Include="Program.cs" /> | |||||
<Compile Include="Properties\AssemblyInfo.cs" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<Content Include="lib\Newtonsoft.Json.dll"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</Content> | |||||
<Content Include="lib\Newtonsoft.Json.pdb"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</Content> | |||||
<Content Include="lib\Newtonsoft.Json.xml"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</Content> | |||||
</ItemGroup> | |||||
<ItemGroup> | |||||
<None Include="PTTEST17.pfx" /> | |||||
</ItemGroup> | |||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | |||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | |||||
Other similar extension points exist, see Microsoft.Common.targets. | |||||
<Target Name="BeforeBuild"> | |||||
</Target> | |||||
<Target Name="AfterBuild"> | |||||
</Target> | |||||
--> | |||||
</Project> |
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<ProjectView>ProjectFiles</ProjectView> | |||||
</PropertyGroup> | |||||
</Project> |
import com.chinaeinv.einv.order.OrderFacade; | |||||
import com.chinaeinv.einv.order.OrderFacadeAgent; | |||||
import com.chinaeinv.einv.order.dto.*; | |||||
import java.math.BigDecimal; | |||||
import java.time.LocalDateTime; | |||||
import java.time.format.DateTimeFormatter; | |||||
import java.util.*; | |||||
public class Main { | |||||
// 由电子发票平台分配的appCode | |||||
private static final String appCode = "请向瑞宏网工作人员索取"; | |||||
// 密钥库文件路径 | |||||
private static final String keyStorePath = "请向瑞宏网工作人员索取"; | |||||
// 密钥库别名 | |||||
private static final String alias = "请向瑞宏网工作人员索取"; | |||||
// 密钥库密码 | |||||
private static final String password = "请向瑞宏网工作人员索取"; | |||||
// 接口URL | |||||
private static final String apiUrl = "https://www.chinaeinv.com:943/igs/api/orderApi.jspa"; | |||||
// 销售方纳税人识别号 | |||||
private static final String testTaxpayerCode = "请向瑞宏网工作人员索取"; | |||||
private static final DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); | |||||
private static OrderFacade orderFacade = new OrderFacadeAgent(appCode, keyStorePath, alias, password, apiUrl); | |||||
private static String orderNo = UUID.randomUUID().toString(); | |||||
public static void main(String[] args) throws Exception { | |||||
System.out.println("订单编号:" + orderNo); | |||||
// (异步)开具蓝字发票 | |||||
testKpAsync(); | |||||
// (异步)开具红字发票 | |||||
//testChAsync(); | |||||
// (异步)对开票失败的订单重新开票 | |||||
//testRetryKpAsync(); | |||||
// (同步)取消订单 | |||||
//testCancel(); | |||||
// (同步)根据订单编号查询发票 | |||||
testCxByOrderNo(); | |||||
} | |||||
/** | |||||
* (异步)开具蓝字发票 | |||||
*/ | |||||
private static void testKpAsync() throws Exception { | |||||
Order order = new Order(); | |||||
// 订单编号 | |||||
order.setOrderNo(orderNo); | |||||
// 销货方纳税人识别号 | |||||
order.setTaxpayerCode(testTaxpayerCode); | |||||
// 用户扫码key | |||||
order.setScanCodeKey(UUID.randomUUID().toString()); | |||||
// 店铺 | |||||
order.setShopName("第198店"); | |||||
// 店铺编号 | |||||
order.setShopCode("198"); | |||||
// 订单时间(yyyy-MM-dd HH:mm:ss) | |||||
order.setOrderTime(LocalDateTime.now().format(df)); | |||||
// 联系人 | |||||
order.setContact("小小明222"); | |||||
// 联系电话 | |||||
order.setContactTel("18000000000"); | |||||
// 邮箱 | |||||
order.setContactMail("test@chinaeinv.cn"); | |||||
// 配送地址 | |||||
order.setShippingAddress("火星北路1024号"); | |||||
// 购货方名称,即发票抬头 | |||||
order.setCustomerName(UUID.randomUUID().toString().replace("-","")); | |||||
order.setCustomerCode(""); | |||||
// 是否自动开票 | |||||
order.setAutoBilling(true); | |||||
// 开票人 | |||||
order.setDrawer("张三"); | |||||
// 收款人 | |||||
order.setPayee("李四"); | |||||
// 复核人 | |||||
order.setReviewer("王五"); | |||||
// 开票金额 | |||||
order.setTotalAmount(new BigDecimal("24000")); | |||||
// 发票备注 | |||||
order.setRemark("软件系统维护期限为2018年1月1日至2019年12月31日。"); | |||||
// 发票明细1 | |||||
OrderItem orderItem1 = new OrderItem(); | |||||
//商品编码 | |||||
orderItem1.setCode("001"); | |||||
//商品名称 | |||||
orderItem1.setName("软件开发"); | |||||
//规格型号 | |||||
orderItem1.setSpec("无"); | |||||
//税率 | |||||
orderItem1.setTaxRate(new BigDecimal("0.06")); | |||||
//税价合计金额 | |||||
orderItem1.setAmount(new BigDecimal("10000")); | |||||
//商品分类编码 | |||||
orderItem1.setCatalogCode("3040203000000000000"); | |||||
// 发票明细2 | |||||
OrderItem orderItem2 = new OrderItem(); | |||||
//商品编码 | |||||
orderItem2.setCode("002"); | |||||
//商品名称 | |||||
orderItem2.setName("软件系统维护"); | |||||
//规格型号 | |||||
orderItem2.setSpec("无"); | |||||
//商品单价 | |||||
orderItem2.setPrice(new BigDecimal("8000")); | |||||
//数量 | |||||
orderItem2.setQuantity(new BigDecimal("2")); | |||||
//单位 | |||||
orderItem2.setUom("年"); | |||||
//税率 | |||||
orderItem2.setTaxRate(new BigDecimal("0.06")); | |||||
//税价合计金额 | |||||
orderItem2.setAmount(new BigDecimal("16000")); | |||||
//折扣金额 | |||||
orderItem2.setDiscountAmount(new BigDecimal("2000")); | |||||
//商品分类编码 | |||||
orderItem2.setCatalogCode("3040203000000000000"); | |||||
// 发票明细 | |||||
order.setOrderItems(Arrays.asList(orderItem1, orderItem2)); | |||||
// 扩展参数 | |||||
order.setExtendedParams(Collections.singletonMap("testExtendedNo", "12345678")); | |||||
// 调用接口方法 | |||||
orderFacade.kpAsync(order); | |||||
} | |||||
/** | |||||
* (异步)开具红字发票 | |||||
*/ | |||||
private static void testChAsync() throws Exception { | |||||
Order order = new Order(); | |||||
// 订单编号 | |||||
order.setOrderNo("OrderNo-105"); | |||||
// 销货方纳税人识别号 | |||||
order.setTaxpayerCode(testTaxpayerCode); | |||||
// 冲红原因 | |||||
order.setReason("开票信息有误。"); | |||||
// 调用接口方法 | |||||
orderFacade.chAsync(order); | |||||
} | |||||
/** | |||||
* (异步)对开票失败的订单重新开票 | |||||
*/ | |||||
private static void testRetryKpAsync() throws Exception { | |||||
Order order = new Order(); | |||||
// 订单编号 | |||||
order.setOrderNo("OrderNo-001"); | |||||
// 销货方纳税人识别号 | |||||
order.setTaxpayerCode(testTaxpayerCode); | |||||
// 调用接口方法 | |||||
orderFacade.retryKpAsync(order); | |||||
} | |||||
/** | |||||
* (同步)取消订单 | |||||
*/ | |||||
private static void testCancel() throws Exception { | |||||
Order order = new Order(); | |||||
// 订单编号 | |||||
order.setOrderNo("OrderNo-001"); | |||||
// 销货方纳税人识别号 | |||||
order.setTaxpayerCode(testTaxpayerCode); | |||||
// 调用接口方法 | |||||
orderFacade.cancel(order); | |||||
} | |||||
/** | |||||
* (同步)根据订单编号查询发票 | |||||
*/ | |||||
private static void testCxByOrderNo() throws Exception { | |||||
OrderBase orderBase = new OrderBase(orderNo, testTaxpayerCode); | |||||
// 调用接口方法 | |||||
orderFacade.cxByOrderNo(orderBase); | |||||
} | |||||
} |
package com.chinaeinv.einv.order; | |||||
import com.chinaeinv.einv.order.dto.InvoiceResult; | |||||
import com.chinaeinv.einv.order.dto.Order; | |||||
import com.chinaeinv.einv.order.dto.OrderBase; | |||||
import com.chinaeinv.einv.order.dto.Result; | |||||
/** | |||||
* 订单接口 | |||||
*/ | |||||
public interface OrderFacade { | |||||
/** | |||||
* (异步)开具蓝字发票异步方法 | |||||
*/ | |||||
Result kpAsync(Order order) throws Exception; | |||||
/** | |||||
* (异步)开具红字发票异步方法 | |||||
*/ | |||||
Result chAsync(Order order) throws Exception; | |||||
/** | |||||
* (异步)对开票失败的订单重新开票异步方法 | |||||
*/ | |||||
Result retryKpAsync(OrderBase orderBase) throws Exception; | |||||
/** | |||||
* (同步)取消订单 | |||||
*/ | |||||
Result cancel(OrderBase orderBase) throws Exception; | |||||
/** | |||||
* (同步)根据订单编号查询发票 | |||||
*/ | |||||
InvoiceResult cxByOrderNo(OrderBase orderBase) throws Exception; | |||||
} |
package com.chinaeinv.einv.order; | |||||
import com.alibaba.fastjson.JSON; | |||||
import com.chinaeinv.einv.order.dto.*; | |||||
import com.chinaeinv.einv.util.CertificateUtils; | |||||
import com.chinaeinv.einv.util.HttpUtil; | |||||
import java.net.URLEncoder; | |||||
import java.util.HashMap; | |||||
import java.util.Map; | |||||
/** | |||||
* 订单接口代理实现 | |||||
*/ | |||||
public class OrderFacadeAgent implements OrderFacade { | |||||
private String appCode, keyStorePath, alias, password, apiUrl; | |||||
/** | |||||
* 构造方法 | |||||
* @param appCode 由电子发票平台分配的appCode | |||||
* @param keyStorePath 密钥库文件路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @param apiUrl 接口URL | |||||
*/ | |||||
public OrderFacadeAgent(String appCode, String keyStorePath, String alias, String password, String apiUrl) { | |||||
this.appCode = appCode; | |||||
this.keyStorePath = keyStorePath; | |||||
this.alias = alias; | |||||
this.password = password; | |||||
this.apiUrl = apiUrl; | |||||
} | |||||
/** | |||||
* (异步)开具蓝字发票 | |||||
*/ | |||||
public Result kpAsync(Order order) throws Exception { | |||||
return exec(order, "chinaeinv.api.order.v11.kp_async", Result.class); | |||||
} | |||||
/** | |||||
* (异步)开具红字发票 | |||||
*/ | |||||
public Result chAsync(Order order) throws Exception { | |||||
return exec(order, "chinaeinv.api.order.v11.ch_async", Result.class); | |||||
} | |||||
/** | |||||
* (异步)对开票失败的订单重新开票 | |||||
*/ | |||||
public Result retryKpAsync(OrderBase orderBase) throws Exception { | |||||
return exec(orderBase, "chinaeinv.api.order.v11.retryKp_async", Result.class); | |||||
} | |||||
/** | |||||
* (同步)取消订单 | |||||
*/ | |||||
public Result cancel(OrderBase orderBase) throws Exception { | |||||
return exec(orderBase, "chinaeinv.api.order.v11.cancel", Result.class); | |||||
} | |||||
/** | |||||
* (同步)根据订单编号查询发票 | |||||
*/ | |||||
public InvoiceResult cxByOrderNo(OrderBase orderBase) throws Exception { | |||||
return exec(orderBase, "chinaeinv.api.order.v11.cx.orderNo", InvoiceResult.class); | |||||
} | |||||
/** | |||||
* 调用接口 | |||||
* @param order 请求数据 | |||||
* @return 响应数据 | |||||
* @throws Exception | |||||
*/ | |||||
private <T> T exec(OrderBase order, String cmdName, Class<T> resultType) throws Exception { | |||||
// 将Order对象转为json | |||||
String requestJson = JSON.toJSONString(order); | |||||
System.out.println("方法名称: " + cmdName + ", 请求报文: " + requestJson); | |||||
// 生成签名 | |||||
String sign = CertificateUtils.signToBase64(requestJson.getBytes("UTF-8"), keyStorePath, alias, password); | |||||
System.out.println("方法名称: " + cmdName + ", 签名: " + sign); | |||||
// 调用接口 | |||||
Map<String, String> params = new HashMap<>(); | |||||
params.put("appCode", appCode); | |||||
params.put("cmdName", cmdName); | |||||
params.put("sign", URLEncoder.encode(sign,"UTF-8")); | |||||
String responseJson = HttpUtil.doPost(apiUrl, params, requestJson); | |||||
System.out.println("方法名称: " + cmdName + ", 响应报文: " + responseJson); | |||||
return JSON.parseObject(responseJson, resultType); | |||||
} | |||||
} |
package com.chinaeinv.einv.order.dto; | |||||
import java.math.BigDecimal; | |||||
import java.util.List; | |||||
/** | |||||
* 开票请求中的发票信息 | |||||
*/ | |||||
public class Invoice { | |||||
/** | |||||
* 订单编号 | |||||
*/ | |||||
private String orderNo; | |||||
/** | |||||
* 子订单编号 | |||||
*/ | |||||
private String subOrderNo; | |||||
/** | |||||
* 店铺名称 | |||||
*/ | |||||
private String shopName; | |||||
/** | |||||
* 店铺编号 | |||||
*/ | |||||
private String shopCode; | |||||
/** | |||||
* 销货方纳税人识别号 | |||||
*/ | |||||
private String taxpayerCode; | |||||
/** | |||||
* 销货方名称 | |||||
*/ | |||||
private String taxpayerName; | |||||
/** | |||||
* 销货方地址 | |||||
*/ | |||||
private String taxpayerAddress; | |||||
/** | |||||
* 销货方电话 | |||||
*/ | |||||
private String taxpayerTel; | |||||
/** | |||||
* 销货方开户银行 | |||||
*/ | |||||
private String taxpayerBankName; | |||||
/** | |||||
* 销货方银行账号 | |||||
*/ | |||||
private String taxpayerBankAccount; | |||||
/** | |||||
* 购货方纳税人识别号 | |||||
*/ | |||||
private String customerCode; | |||||
/** | |||||
* 购货方名称,即发票抬头 | |||||
*/ | |||||
private String customerName; | |||||
/** | |||||
* 购货方地址 | |||||
*/ | |||||
private String customerAddress; | |||||
/** | |||||
* 购货方电话 | |||||
*/ | |||||
private String customerTel; | |||||
/** | |||||
* 购货方开户银行 | |||||
*/ | |||||
private String customerBankName; | |||||
/** | |||||
* 购货方银行账号 | |||||
*/ | |||||
private String customerBankAccount; | |||||
/** | |||||
* 发票代码+发票号码 | |||||
*/ | |||||
private String code; | |||||
/** | |||||
* 校验码 | |||||
*/ | |||||
private String checkCode; | |||||
/** | |||||
* 税控码 | |||||
*/ | |||||
private String fiscalCode; | |||||
/** | |||||
* 发票状态 | |||||
* 正常:1 | |||||
* 红冲:3 | |||||
* 被红冲:4 | |||||
*/ | |||||
private String status; | |||||
/** | |||||
* 生成时间 | |||||
*/ | |||||
private String generateTime; | |||||
/** | |||||
* 税价合计金额 | |||||
*/ | |||||
private BigDecimal totalAmount; | |||||
/** | |||||
* 不含税金额 | |||||
*/ | |||||
private BigDecimal noTaxAmount; | |||||
/** | |||||
* 税额 | |||||
*/ | |||||
private BigDecimal taxAmount; | |||||
/** | |||||
* 开票人 | |||||
*/ | |||||
private String drawer; | |||||
/** | |||||
* 收款人 | |||||
*/ | |||||
private String payee; | |||||
/** | |||||
* 复核人 | |||||
*/ | |||||
private String reviewer; | |||||
/** | |||||
* 发票备注 | |||||
*/ | |||||
private String remark; | |||||
/** | |||||
* 未签名PDF下载URL | |||||
*/ | |||||
private String pdfUnsignedUrl; | |||||
/** | |||||
* 查看URL | |||||
*/ | |||||
private String viewUrl; | |||||
/** | |||||
* 关联发票编号 | |||||
*/ | |||||
private String relatedCode; | |||||
/** | |||||
* 作废/红冲原因 | |||||
*/ | |||||
private String validReason; | |||||
/** | |||||
* 作废/红冲时间 | |||||
*/ | |||||
private String validTime; | |||||
/** | |||||
* 项目明细 | |||||
*/ | |||||
private List<InvoiceItem> items; | |||||
public String getOrderNo() { | |||||
return orderNo; | |||||
} | |||||
public void setOrderNo(String orderNo) { | |||||
this.orderNo = orderNo; | |||||
} | |||||
public String getSubOrderNo() { | |||||
return subOrderNo; | |||||
} | |||||
public void setSubOrderNo(String subOrderNo) { | |||||
this.subOrderNo = subOrderNo; | |||||
} | |||||
public String getShopName() { | |||||
return shopName; | |||||
} | |||||
public void setShopName(String shopName) { | |||||
this.shopName = shopName; | |||||
} | |||||
public String getShopCode() { | |||||
return shopCode; | |||||
} | |||||
public void setShopCode(String shopCode) { | |||||
this.shopCode = shopCode; | |||||
} | |||||
public String getTaxpayerCode() { | |||||
return taxpayerCode; | |||||
} | |||||
public void setTaxpayerCode(String taxpayerCode) { | |||||
this.taxpayerCode = taxpayerCode; | |||||
} | |||||
public String getTaxpayerName() { | |||||
return taxpayerName; | |||||
} | |||||
public void setTaxpayerName(String taxpayerName) { | |||||
this.taxpayerName = taxpayerName; | |||||
} | |||||
public String getTaxpayerAddress() { | |||||
return taxpayerAddress; | |||||
} | |||||
public void setTaxpayerAddress(String taxpayerAddress) { | |||||
this.taxpayerAddress = taxpayerAddress; | |||||
} | |||||
public String getTaxpayerTel() { | |||||
return taxpayerTel; | |||||
} | |||||
public void setTaxpayerTel(String taxpayerTel) { | |||||
this.taxpayerTel = taxpayerTel; | |||||
} | |||||
public String getTaxpayerBankName() { | |||||
return taxpayerBankName; | |||||
} | |||||
public void setTaxpayerBankName(String taxpayerBankName) { | |||||
this.taxpayerBankName = taxpayerBankName; | |||||
} | |||||
public String getTaxpayerBankAccount() { | |||||
return taxpayerBankAccount; | |||||
} | |||||
public void setTaxpayerBankAccount(String taxpayerBankAccount) { | |||||
this.taxpayerBankAccount = taxpayerBankAccount; | |||||
} | |||||
public String getCustomerCode() { | |||||
return customerCode; | |||||
} | |||||
public void setCustomerCode(String customerCode) { | |||||
this.customerCode = customerCode; | |||||
} | |||||
public String getCustomerName() { | |||||
return customerName; | |||||
} | |||||
public void setCustomerName(String customerName) { | |||||
this.customerName = customerName; | |||||
} | |||||
public String getCustomerAddress() { | |||||
return customerAddress; | |||||
} | |||||
public void setCustomerAddress(String customerAddress) { | |||||
this.customerAddress = customerAddress; | |||||
} | |||||
public String getCustomerTel() { | |||||
return customerTel; | |||||
} | |||||
public void setCustomerTel(String customerTel) { | |||||
this.customerTel = customerTel; | |||||
} | |||||
public String getCustomerBankName() { | |||||
return customerBankName; | |||||
} | |||||
public void setCustomerBankName(String customerBankName) { | |||||
this.customerBankName = customerBankName; | |||||
} | |||||
public String getCustomerBankAccount() { | |||||
return customerBankAccount; | |||||
} | |||||
public void setCustomerBankAccount(String customerBankAccount) { | |||||
this.customerBankAccount = customerBankAccount; | |||||
} | |||||
public String getCode() { | |||||
return code; | |||||
} | |||||
public void setCode(String code) { | |||||
this.code = code; | |||||
} | |||||
public String getCheckCode() { | |||||
return checkCode; | |||||
} | |||||
public void setCheckCode(String checkCode) { | |||||
this.checkCode = checkCode; | |||||
} | |||||
public String getFiscalCode() { | |||||
return fiscalCode; | |||||
} | |||||
public void setFiscalCode(String fiscalCode) { | |||||
this.fiscalCode = fiscalCode; | |||||
} | |||||
public String getStatus() { | |||||
return status; | |||||
} | |||||
public void setStatus(String status) { | |||||
this.status = status; | |||||
} | |||||
public String getGenerateTime() { | |||||
return generateTime; | |||||
} | |||||
public void setGenerateTime(String generateTime) { | |||||
this.generateTime = generateTime; | |||||
} | |||||
public BigDecimal getTotalAmount() { | |||||
return totalAmount; | |||||
} | |||||
public void setTotalAmount(BigDecimal totalAmount) { | |||||
this.totalAmount = totalAmount; | |||||
} | |||||
public BigDecimal getNoTaxAmount() { | |||||
return noTaxAmount; | |||||
} | |||||
public void setNoTaxAmount(BigDecimal noTaxAmount) { | |||||
this.noTaxAmount = noTaxAmount; | |||||
} | |||||
public BigDecimal getTaxAmount() { | |||||
return taxAmount; | |||||
} | |||||
public void setTaxAmount(BigDecimal taxAmount) { | |||||
this.taxAmount = taxAmount; | |||||
} | |||||
public String getDrawer() { | |||||
return drawer; | |||||
} | |||||
public void setDrawer(String drawer) { | |||||
this.drawer = drawer; | |||||
} | |||||
public String getPayee() { | |||||
return payee; | |||||
} | |||||
public void setPayee(String payee) { | |||||
this.payee = payee; | |||||
} | |||||
public String getReviewer() { | |||||
return reviewer; | |||||
} | |||||
public void setReviewer(String reviewer) { | |||||
this.reviewer = reviewer; | |||||
} | |||||
public String getRemark() { | |||||
return remark; | |||||
} | |||||
public void setRemark(String remark) { | |||||
this.remark = remark; | |||||
} | |||||
public String getPdfUnsignedUrl() { | |||||
return pdfUnsignedUrl; | |||||
} | |||||
public void setPdfUnsignedUrl(String pdfUnsignedUrl) { | |||||
this.pdfUnsignedUrl = pdfUnsignedUrl; | |||||
} | |||||
public String getViewUrl() { | |||||
return viewUrl; | |||||
} | |||||
public void setViewUrl(String viewUrl) { | |||||
this.viewUrl = viewUrl; | |||||
} | |||||
public String getRelatedCode() { | |||||
return relatedCode; | |||||
} | |||||
public void setRelatedCode(String relatedCode) { | |||||
this.relatedCode = relatedCode; | |||||
} | |||||
public String getValidReason() { | |||||
return validReason; | |||||
} | |||||
public void setValidReason(String validReason) { | |||||
this.validReason = validReason; | |||||
} | |||||
public String getValidTime() { | |||||
return validTime; | |||||
} | |||||
public void setValidTime(String validTime) { | |||||
this.validTime = validTime; | |||||
} | |||||
public List<InvoiceItem> getItems() { | |||||
return items; | |||||
} | |||||
public void setItems(List<InvoiceItem> items) { | |||||
this.items = items; | |||||
} | |||||
} |
package com.chinaeinv.einv.order.dto; | |||||
import java.math.BigDecimal; | |||||
/** | |||||
* 发票项目明细 | |||||
*/ | |||||
public class InvoiceItem { | |||||
/** | |||||
* 发票行性质 0 正常行、1 折扣行、2 被折扣行 | |||||
*/ | |||||
private String type; | |||||
/** | |||||
* 商品编码 | |||||
*/ | |||||
private String code; | |||||
/** | |||||
* 商品名称 | |||||
*/ | |||||
private String name; | |||||
/** | |||||
* 规格型号 | |||||
*/ | |||||
private String spec; | |||||
/** | |||||
* 含税商品单价 | |||||
*/ | |||||
private BigDecimal price; | |||||
/** | |||||
* 数量 | |||||
*/ | |||||
private BigDecimal quantity; | |||||
/** | |||||
* 单位 | |||||
*/ | |||||
private String uom; | |||||
/** | |||||
* 税率 | |||||
*/ | |||||
private BigDecimal taxRate; | |||||
/** | |||||
* 税价合计金额 | |||||
*/ | |||||
private BigDecimal amount; | |||||
/** | |||||
* 不含税金额 | |||||
*/ | |||||
private BigDecimal noTaxAmount; | |||||
/** | |||||
* 税额 | |||||
*/ | |||||
private BigDecimal taxAmount; | |||||
/** | |||||
* 商品分类编码 | |||||
*/ | |||||
private String catalogCode; | |||||
/** | |||||
* 优惠政策标识 | |||||
*/ | |||||
private String preferentialPolicyFlg; | |||||
/** | |||||
* 增值税特殊管理 | |||||
*/ | |||||
private String addedValueTaxFlg; | |||||
/** | |||||
* 零税率标识 | |||||
*/ | |||||
private String zeroTaxRateFlg; | |||||
public String getType() { | |||||
return type; | |||||
} | |||||
public void setType(String type) { | |||||
this.type = type; | |||||
} | |||||
public String getCode() { | |||||
return code; | |||||
} | |||||
public void setCode(String code) { | |||||
this.code = code; | |||||
} | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
public void setName(String name) { | |||||
this.name = name; | |||||
} | |||||
public String getSpec() { | |||||
return spec; | |||||
} | |||||
public void setSpec(String spec) { | |||||
this.spec = spec; | |||||
} | |||||
public BigDecimal getPrice() { | |||||
return price; | |||||
} | |||||
public void setPrice(BigDecimal price) { | |||||
this.price = price; | |||||
} | |||||
public BigDecimal getQuantity() { | |||||
return quantity; | |||||
} | |||||
public void setQuantity(BigDecimal quantity) { | |||||
this.quantity = quantity; | |||||
} | |||||
public String getUom() { | |||||
return uom; | |||||
} | |||||
public void setUom(String uom) { | |||||
this.uom = uom; | |||||
} | |||||
public BigDecimal getTaxRate() { | |||||
return taxRate; | |||||
} | |||||
public void setTaxRate(BigDecimal taxRate) { | |||||
this.taxRate = taxRate; | |||||
} | |||||
public BigDecimal getAmount() { | |||||
return amount; | |||||
} | |||||
public void setAmount(BigDecimal amount) { | |||||
this.amount = amount; | |||||
} | |||||
public BigDecimal getNoTaxAmount() { | |||||
return noTaxAmount; | |||||
} | |||||
public void setNoTaxAmount(BigDecimal noTaxAmount) { | |||||
this.noTaxAmount = noTaxAmount; | |||||
} | |||||
public BigDecimal getTaxAmount() { | |||||
return taxAmount; | |||||
} | |||||
public void setTaxAmount(BigDecimal taxAmount) { | |||||
this.taxAmount = taxAmount; | |||||
} | |||||
public String getCatalogCode() { | |||||
return catalogCode; | |||||
} | |||||
public void setCatalogCode(String catalogCode) { | |||||
this.catalogCode = catalogCode; | |||||
} | |||||
public String getPreferentialPolicyFlg() { | |||||
return preferentialPolicyFlg; | |||||
} | |||||
public void setPreferentialPolicyFlg(String preferentialPolicyFlg) { | |||||
this.preferentialPolicyFlg = preferentialPolicyFlg; | |||||
} | |||||
public String getAddedValueTaxFlg() { | |||||
return addedValueTaxFlg; | |||||
} | |||||
public void setAddedValueTaxFlg(String addedValueTaxFlg) { | |||||
this.addedValueTaxFlg = addedValueTaxFlg; | |||||
} | |||||
public String getZeroTaxRateFlg() { | |||||
return zeroTaxRateFlg; | |||||
} | |||||
public void setZeroTaxRateFlg(String zeroTaxRateFlg) { | |||||
this.zeroTaxRateFlg = zeroTaxRateFlg; | |||||
} | |||||
} |
package com.chinaeinv.einv.order.dto; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* “根据订单编号查询发票”方法响应和回调数据 | |||||
*/ | |||||
public class InvoiceResult extends Result { | |||||
/** | |||||
* 发票列表 | |||||
*/ | |||||
private List<Invoice> invoices; | |||||
public List<Invoice> getInvoices() { | |||||
return invoices; | |||||
} | |||||
public void setInvoices(List<Invoice> invoices) { | |||||
this.invoices = invoices; | |||||
} | |||||
} |
package com.chinaeinv.einv.order.dto; | |||||
import java.math.BigDecimal; | |||||
import java.util.List; | |||||
import java.util.Map; | |||||
/** | |||||
* 订单详细信息 | |||||
*/ | |||||
public class Order extends OrderBase { | |||||
/** | |||||
* 用户扫码key | |||||
*/ | |||||
private String scanCodeKey; | |||||
/** | |||||
* 店铺 | |||||
*/ | |||||
private String shopName; | |||||
/** | |||||
* 店铺编号 | |||||
*/ | |||||
private String shopCode; | |||||
/** | |||||
* 订单时间(yyyy-MM-dd HH:mm:ss) | |||||
*/ | |||||
private String orderTime; | |||||
/** | |||||
* 联系人 | |||||
*/ | |||||
private String contact; | |||||
/** | |||||
* 联系电话 | |||||
*/ | |||||
private String contactTel; | |||||
/** | |||||
* 邮箱 | |||||
*/ | |||||
private String contactMail; | |||||
/** | |||||
* 配送地址 | |||||
*/ | |||||
private String shippingAddress; | |||||
/** | |||||
* 销货方名称 | |||||
*/ | |||||
private String taxpayerName; | |||||
/** | |||||
* 销货方地址 | |||||
*/ | |||||
private String taxpayerAddress; | |||||
/** | |||||
* 销货方电话 | |||||
*/ | |||||
private String taxpayerTel; | |||||
/** | |||||
* 销货方开户银行 | |||||
*/ | |||||
private String taxpayerBankName; | |||||
/** | |||||
* 销货方银行账号 | |||||
*/ | |||||
private String taxpayerBankAccount; | |||||
/** | |||||
* 购货方名称,即发票抬头 | |||||
*/ | |||||
private String customerName; | |||||
/** | |||||
* 购货方纳税人识别号 | |||||
*/ | |||||
private String customerCode; | |||||
/** | |||||
* 购货方地址 | |||||
*/ | |||||
private String customerAddress; | |||||
/** | |||||
* 购货方电话 | |||||
*/ | |||||
private String customerTel; | |||||
/** | |||||
* 购货方开户银行 | |||||
*/ | |||||
private String customerBankName; | |||||
/** | |||||
* 购货方银行账号 | |||||
*/ | |||||
private String customerBankAccount; | |||||
/** | |||||
* 是否自动开票 | |||||
*/ | |||||
private boolean autoBilling; | |||||
/** | |||||
* 开票人 | |||||
*/ | |||||
private String drawer; | |||||
/** | |||||
* 收款人 | |||||
*/ | |||||
private String payee; | |||||
/** | |||||
* 复核人 | |||||
*/ | |||||
private String reviewer; | |||||
/** | |||||
* 开票金额 | |||||
*/ | |||||
private BigDecimal totalAmount; | |||||
/** | |||||
* 发票备注 | |||||
*/ | |||||
private String remark; | |||||
/** | |||||
* 冲红原因 | |||||
*/ | |||||
private String reason; | |||||
/** | |||||
* 订单明细 | |||||
*/ | |||||
private List<OrderItem> orderItems; | |||||
/** | |||||
* 扩展参数 | |||||
*/ | |||||
private Map<String, String> extendedParams; | |||||
/** | |||||
* 动态参数 | |||||
*/ | |||||
private Map<String, String> dynamicParams; | |||||
public String getScanCodeKey() { | |||||
return scanCodeKey; | |||||
} | |||||
public void setScanCodeKey(String scanCodeKey) { | |||||
this.scanCodeKey = scanCodeKey; | |||||
} | |||||
public String getShopName() { | |||||
return shopName; | |||||
} | |||||
public void setShopName(String shopName) { | |||||
this.shopName = shopName; | |||||
} | |||||
public String getShopCode() { | |||||
return shopCode; | |||||
} | |||||
public void setShopCode(String shopCode) { | |||||
this.shopCode = shopCode; | |||||
} | |||||
public String getOrderTime() { | |||||
return orderTime; | |||||
} | |||||
public void setOrderTime(String orderTime) { | |||||
this.orderTime = orderTime; | |||||
} | |||||
public String getContact() { | |||||
return contact; | |||||
} | |||||
public void setContact(String contact) { | |||||
this.contact = contact; | |||||
} | |||||
public String getContactTel() { | |||||
return contactTel; | |||||
} | |||||
public void setContactTel(String contactTel) { | |||||
this.contactTel = contactTel; | |||||
} | |||||
public String getContactMail() { | |||||
return contactMail; | |||||
} | |||||
public void setContactMail(String contactMail) { | |||||
this.contactMail = contactMail; | |||||
} | |||||
public String getShippingAddress() { | |||||
return shippingAddress; | |||||
} | |||||
public void setShippingAddress(String shippingAddress) { | |||||
this.shippingAddress = shippingAddress; | |||||
} | |||||
public String getTaxpayerName() { | |||||
return taxpayerName; | |||||
} | |||||
public void setTaxpayerName(String taxpayerName) { | |||||
this.taxpayerName = taxpayerName; | |||||
} | |||||
public String getTaxpayerAddress() { | |||||
return taxpayerAddress; | |||||
} | |||||
public void setTaxpayerAddress(String taxpayerAddress) { | |||||
this.taxpayerAddress = taxpayerAddress; | |||||
} | |||||
public String getTaxpayerTel() { | |||||
return taxpayerTel; | |||||
} | |||||
public void setTaxpayerTel(String taxpayerTel) { | |||||
this.taxpayerTel = taxpayerTel; | |||||
} | |||||
public String getTaxpayerBankName() { | |||||
return taxpayerBankName; | |||||
} | |||||
public void setTaxpayerBankName(String taxpayerBankName) { | |||||
this.taxpayerBankName = taxpayerBankName; | |||||
} | |||||
public String getTaxpayerBankAccount() { | |||||
return taxpayerBankAccount; | |||||
} | |||||
public void setTaxpayerBankAccount(String taxpayerBankAccount) { | |||||
this.taxpayerBankAccount = taxpayerBankAccount; | |||||
} | |||||
public String getCustomerName() { | |||||
return customerName; | |||||
} | |||||
public void setCustomerName(String customerName) { | |||||
this.customerName = customerName; | |||||
} | |||||
public String getCustomerCode() { | |||||
return customerCode; | |||||
} | |||||
public void setCustomerCode(String customerCode) { | |||||
this.customerCode = customerCode; | |||||
} | |||||
public String getCustomerAddress() { | |||||
return customerAddress; | |||||
} | |||||
public void setCustomerAddress(String customerAddress) { | |||||
this.customerAddress = customerAddress; | |||||
} | |||||
public String getCustomerTel() { | |||||
return customerTel; | |||||
} | |||||
public void setCustomerTel(String customerTel) { | |||||
this.customerTel = customerTel; | |||||
} | |||||
public String getCustomerBankName() { | |||||
return customerBankName; | |||||
} | |||||
public void setCustomerBankName(String customerBankName) { | |||||
this.customerBankName = customerBankName; | |||||
} | |||||
public String getCustomerBankAccount() { | |||||
return customerBankAccount; | |||||
} | |||||
public void setCustomerBankAccount(String customerBankAccount) { | |||||
this.customerBankAccount = customerBankAccount; | |||||
} | |||||
public boolean isAutoBilling() { | |||||
return autoBilling; | |||||
} | |||||
public void setAutoBilling(boolean autoBilling) { | |||||
this.autoBilling = autoBilling; | |||||
} | |||||
public String getDrawer() { | |||||
return drawer; | |||||
} | |||||
public void setDrawer(String drawer) { | |||||
this.drawer = drawer; | |||||
} | |||||
public String getPayee() { | |||||
return payee; | |||||
} | |||||
public void setPayee(String payee) { | |||||
this.payee = payee; | |||||
} | |||||
public String getReviewer() { | |||||
return reviewer; | |||||
} | |||||
public void setReviewer(String reviewer) { | |||||
this.reviewer = reviewer; | |||||
} | |||||
public BigDecimal getTotalAmount() { | |||||
return totalAmount; | |||||
} | |||||
public void setTotalAmount(BigDecimal totalAmount) { | |||||
this.totalAmount = totalAmount; | |||||
} | |||||
public String getRemark() { | |||||
return remark; | |||||
} | |||||
public void setRemark(String remark) { | |||||
this.remark = remark; | |||||
} | |||||
public String getReason() { | |||||
return reason; | |||||
} | |||||
public void setReason(String reason) { | |||||
this.reason = reason; | |||||
} | |||||
public List<OrderItem> getOrderItems() { | |||||
return orderItems; | |||||
} | |||||
public void setOrderItems(List<OrderItem> orderItems) { | |||||
this.orderItems = orderItems; | |||||
} | |||||
public Map<String, String> getExtendedParams() { | |||||
return extendedParams; | |||||
} | |||||
public void setExtendedParams(Map<String, String> extendedParams) { | |||||
this.extendedParams = extendedParams; | |||||
} | |||||
public Map<String, String> getDynamicParams() { | |||||
return dynamicParams; | |||||
} | |||||
public void setDynamicParams(Map<String, String> dynamicParams) { | |||||
this.dynamicParams = dynamicParams; | |||||
} | |||||
} |
package com.chinaeinv.einv.order.dto; | |||||
/** | |||||
* 订单基本信息 | |||||
*/ | |||||
public class OrderBase { | |||||
/** | |||||
* 订单编号 | |||||
*/ | |||||
private String orderNo; | |||||
/** | |||||
* 子订单编号 | |||||
*/ | |||||
private String subOrderNo; | |||||
/** | |||||
* 销货方纳税人识别号 | |||||
*/ | |||||
private String taxpayerCode; | |||||
/** | |||||
* 发票类型 | |||||
*/ | |||||
private String invoiceType; | |||||
public OrderBase() { | |||||
} | |||||
public OrderBase(String orderNo, String taxpayerCode) { | |||||
this.orderNo = orderNo; | |||||
this.taxpayerCode = taxpayerCode; | |||||
} | |||||
public OrderBase(String orderNo, String subOrderNo, String taxpayerCode) { | |||||
this.orderNo = orderNo; | |||||
this.subOrderNo = subOrderNo; | |||||
this.taxpayerCode = taxpayerCode; | |||||
} | |||||
public String getOrderNo() { | |||||
return orderNo; | |||||
} | |||||
public void setOrderNo(String orderNo) { | |||||
this.orderNo = orderNo; | |||||
} | |||||
public String getSubOrderNo() { | |||||
return subOrderNo; | |||||
} | |||||
public void setSubOrderNo(String subOrderNo) { | |||||
this.subOrderNo = subOrderNo; | |||||
} | |||||
public String getTaxpayerCode() { | |||||
return taxpayerCode; | |||||
} | |||||
public void setTaxpayerCode(String taxpayerCode) { | |||||
this.taxpayerCode = taxpayerCode; | |||||
} | |||||
public String getInvoiceType() { | |||||
return invoiceType; | |||||
} | |||||
public void setInvoiceType(String invoiceType) { | |||||
this.invoiceType = invoiceType; | |||||
} | |||||
} |
package com.chinaeinv.einv.order.dto; | |||||
import java.math.BigDecimal; | |||||
public class OrderItem { | |||||
/** | |||||
* 商品编码 | |||||
*/ | |||||
private String code; | |||||
/** | |||||
* 商品名称 | |||||
*/ | |||||
private String name; | |||||
/** | |||||
* 规格型号 | |||||
*/ | |||||
private String spec; | |||||
/** | |||||
* 商品单价 | |||||
*/ | |||||
private BigDecimal price; | |||||
/** | |||||
* 数量 | |||||
*/ | |||||
private BigDecimal quantity; | |||||
/** | |||||
* 单位 | |||||
*/ | |||||
private String uom; | |||||
/** | |||||
* 税率 | |||||
*/ | |||||
private BigDecimal taxRate; | |||||
/** | |||||
* 税价合计金额 | |||||
*/ | |||||
private BigDecimal amount; | |||||
/** | |||||
* 折扣金额 | |||||
*/ | |||||
private BigDecimal discountAmount; | |||||
/** | |||||
* 商品分类编码 | |||||
*/ | |||||
private String catalogCode; | |||||
/** | |||||
* 优惠政策标识 | |||||
*/ | |||||
private String preferentialPolicyFlg; | |||||
/** | |||||
* 增值税特殊管理 | |||||
*/ | |||||
private String addedValueTaxFlg; | |||||
/** | |||||
* 零税率标识 | |||||
*/ | |||||
private String zeroTaxRateFlg; | |||||
public String getCode() { | |||||
return code; | |||||
} | |||||
public void setCode(String code) { | |||||
this.code = code; | |||||
} | |||||
public String getName() { | |||||
return name; | |||||
} | |||||
public void setName(String name) { | |||||
this.name = name; | |||||
} | |||||
public String getSpec() { | |||||
return spec; | |||||
} | |||||
public void setSpec(String spec) { | |||||
this.spec = spec; | |||||
} | |||||
public BigDecimal getPrice() { | |||||
return price; | |||||
} | |||||
public void setPrice(BigDecimal price) { | |||||
this.price = price; | |||||
} | |||||
public BigDecimal getQuantity() { | |||||
return quantity; | |||||
} | |||||
public void setQuantity(BigDecimal quantity) { | |||||
this.quantity = quantity; | |||||
} | |||||
public String getUom() { | |||||
return uom; | |||||
} | |||||
public void setUom(String uom) { | |||||
this.uom = uom; | |||||
} | |||||
public BigDecimal getTaxRate() { | |||||
return taxRate; | |||||
} | |||||
public void setTaxRate(BigDecimal taxRate) { | |||||
this.taxRate = taxRate; | |||||
} | |||||
public BigDecimal getAmount() { | |||||
return amount; | |||||
} | |||||
public void setAmount(BigDecimal amount) { | |||||
this.amount = amount; | |||||
} | |||||
public BigDecimal getDiscountAmount() { | |||||
return discountAmount; | |||||
} | |||||
public void setDiscountAmount(BigDecimal discountAmount) { | |||||
this.discountAmount = discountAmount; | |||||
} | |||||
public String getCatalogCode() { | |||||
return catalogCode; | |||||
} | |||||
public void setCatalogCode(String catalogCode) { | |||||
this.catalogCode = catalogCode; | |||||
} | |||||
public String getPreferentialPolicyFlg() { | |||||
return preferentialPolicyFlg; | |||||
} | |||||
public void setPreferentialPolicyFlg(String preferentialPolicyFlg) { | |||||
this.preferentialPolicyFlg = preferentialPolicyFlg; | |||||
} | |||||
public String getAddedValueTaxFlg() { | |||||
return addedValueTaxFlg; | |||||
} | |||||
public void setAddedValueTaxFlg(String addedValueTaxFlg) { | |||||
this.addedValueTaxFlg = addedValueTaxFlg; | |||||
} | |||||
public String getZeroTaxRateFlg() { | |||||
return zeroTaxRateFlg; | |||||
} | |||||
public void setZeroTaxRateFlg(String zeroTaxRateFlg) { | |||||
this.zeroTaxRateFlg = zeroTaxRateFlg; | |||||
} | |||||
} |
package com.chinaeinv.einv.order.dto; | |||||
/** | |||||
* 异步方法响应和“取消订单”方法响应 | |||||
*/ | |||||
public class Result { | |||||
/** | |||||
* 处理结果代码 | |||||
*/ | |||||
private String code; | |||||
/** | |||||
* 处理结果消息 | |||||
*/ | |||||
private String message; | |||||
public String getCode() { | |||||
return code; | |||||
} | |||||
public void setCode(String code) { | |||||
this.code = code; | |||||
} | |||||
public String getMessage() { | |||||
return message; | |||||
} | |||||
public void setMessage(String message) { | |||||
this.message = message; | |||||
} | |||||
} |
package com.chinaeinv.einv.util; | |||||
import javax.crypto.Cipher; | |||||
import java.io.*; | |||||
import java.nio.MappedByteBuffer; | |||||
import java.nio.channels.FileChannel; | |||||
import java.security.KeyStore; | |||||
import java.security.PrivateKey; | |||||
import java.security.PublicKey; | |||||
import java.security.Signature; | |||||
import java.security.cert.Certificate; | |||||
import java.security.cert.CertificateException; | |||||
import java.security.cert.CertificateFactory; | |||||
import java.security.cert.X509Certificate; | |||||
import java.util.Base64; | |||||
import java.util.Date; | |||||
/** | |||||
* <p> | |||||
* 数字签名/加密解密工具包 | |||||
* </p> | |||||
*/ | |||||
public class CertificateUtils { | |||||
/** | |||||
* Java密钥库(Java 密钥库,JKS)KEY_STORE | |||||
*/ | |||||
public static final String KEY_STORE = "JKS"; | |||||
public static final String X509 = "X.509"; | |||||
/** | |||||
* 文件读取缓冲区大小 | |||||
*/ | |||||
private static final int CACHE_SIZE = 2048; | |||||
/** | |||||
* 最大文件加密块 | |||||
*/ | |||||
private static final int MAX_ENCRYPT_BLOCK = 117; | |||||
/** | |||||
* 最大文件解密块 | |||||
*/ | |||||
private static final int MAX_DECRYPT_BLOCK = 128; | |||||
/** | |||||
* <p> | |||||
* 根据密钥库获得私钥 | |||||
* </p> | |||||
* | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
static PrivateKey getPrivateKey(String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
KeyStore keyStore = getKeyStore(keyStorePath, password); | |||||
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); | |||||
return privateKey; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 获得密钥库 | |||||
* </p> | |||||
* | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
private static KeyStore getKeyStore(String keyStorePath, String password) | |||||
throws Exception { | |||||
FileInputStream in = new FileInputStream(keyStorePath); | |||||
KeyStore keyStore = KeyStore.getInstance(KEY_STORE); | |||||
keyStore.load(in, password.toCharArray()); | |||||
in.close(); | |||||
return keyStore; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 根据证书获得公钥 | |||||
* </p> | |||||
* | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
static PublicKey getPublicKey(String certificatePath) throws CertificateException, IOException { | |||||
Certificate certificate = getCertificate(certificatePath); | |||||
PublicKey publicKey = certificate.getPublicKey(); | |||||
return publicKey; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 根据证书获得公钥 | |||||
* </p> | |||||
* | |||||
* @param certificateInStream 证书输入流 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
static PublicKey getPublicKey(InputStream certificateInStream) throws CertificateException, IOException { | |||||
Certificate certificate = getCertificate(certificateInStream); | |||||
PublicKey publicKey = certificate.getPublicKey(); | |||||
return publicKey; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 获得证书 | |||||
* </p> | |||||
* | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
private static Certificate getCertificate(String certificatePath) throws CertificateException, IOException { | |||||
CertificateFactory certificateFactory = CertificateFactory.getInstance(X509); | |||||
FileInputStream in = new FileInputStream(certificatePath); | |||||
Certificate certificate = certificateFactory.generateCertificate(in); | |||||
in.close(); | |||||
return certificate; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 获得证书 | |||||
* </p> | |||||
* | |||||
* @param certificateInStream 证书输入流 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
private static Certificate getCertificate(InputStream certificateInStream) throws CertificateException, IOException { | |||||
CertificateFactory certificateFactory = CertificateFactory.getInstance(X509); | |||||
Certificate certificate = certificateFactory.generateCertificate(certificateInStream); | |||||
certificateInStream.close(); | |||||
return certificate; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 根据密钥库获得证书 | |||||
* </p> | |||||
* | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
private static Certificate getCertificate(String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
KeyStore keyStore = getKeyStore(keyStorePath, password); | |||||
Certificate certificate = keyStore.getCertificate(alias); | |||||
return certificate; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 私钥加密 | |||||
* </p> | |||||
* | |||||
* @param data 源数据 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static byte[] encryptByPrivateKey(byte[] data, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
// 取得私钥 | |||||
PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); | |||||
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); | |||||
System.out.print("\n=========="+privateKey.getAlgorithm()+"\n=========="); | |||||
cipher.init(Cipher.ENCRYPT_MODE, privateKey); | |||||
int inputLen = data.length; | |||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||||
int offSet = 0; | |||||
byte[] cache; | |||||
int i = 0; | |||||
// 对数据分段加密 | |||||
while (inputLen - offSet > 0) { | |||||
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { | |||||
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); | |||||
} else { | |||||
cache = cipher.doFinal(data, offSet, inputLen - offSet); | |||||
} | |||||
out.write(cache, 0, cache.length); | |||||
i++; | |||||
offSet = i * MAX_ENCRYPT_BLOCK; | |||||
} | |||||
byte[] encryptedData = out.toByteArray(); | |||||
out.close(); | |||||
return encryptedData; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 文件私钥加密 | |||||
* </p> | |||||
* <p> | |||||
* 过大的文件可能会导致内存溢出 | |||||
* </> | |||||
* | |||||
* @param filePath 文件路径 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static byte[] encryptFileByPrivateKey(String filePath, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
byte[] data = fileToByte(filePath); | |||||
return encryptByPrivateKey(data, keyStorePath, alias, password); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 文件加密 | |||||
* </p> | |||||
* | |||||
* @param srcFilePath 源文件 | |||||
* @param destFilePath 加密后文件 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @throws Exception | |||||
*/ | |||||
public static void encryptFileByPrivateKey(String srcFilePath, String destFilePath, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
// 取得私钥 | |||||
PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); | |||||
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); | |||||
cipher.init(Cipher.ENCRYPT_MODE, privateKey); | |||||
File srcFile = new File(srcFilePath); | |||||
FileInputStream in = new FileInputStream(srcFile); | |||||
File destFile = new File(destFilePath); | |||||
if (!destFile.getParentFile().exists()) { | |||||
destFile.getParentFile().mkdirs(); | |||||
} | |||||
destFile.createNewFile(); | |||||
OutputStream out = new FileOutputStream(destFile); | |||||
byte[] data = new byte[MAX_ENCRYPT_BLOCK]; | |||||
byte[] encryptedData; // 加密块 | |||||
while (in.read(data) != -1) { | |||||
encryptedData = cipher.doFinal(data); | |||||
out.write(encryptedData, 0, encryptedData.length); | |||||
out.flush(); | |||||
} | |||||
out.close(); | |||||
in.close(); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 文件加密成BASE64编码的字符串 | |||||
* </p> | |||||
* | |||||
* @param filePath 文件路径 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
// public static String encryptFileToBase64ByPrivateKey(String filePath, String keyStorePath, String alias, String password) | |||||
// throws Exception { | |||||
// byte[] encryptedData = encryptFileByPrivateKey(filePath, keyStorePath, alias, password); | |||||
// return Base64Utils.encode(encryptedData); | |||||
// } | |||||
/** | |||||
* <p> | |||||
* 私钥解密 | |||||
* </p> | |||||
* | |||||
* @param encryptedData 已加密数据 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static byte[] decryptByPrivateKey(byte[] encryptedData, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
// 取得私钥 | |||||
PrivateKey privateKey = getPrivateKey(keyStorePath, alias, password); | |||||
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm()); | |||||
cipher.init(Cipher.DECRYPT_MODE, privateKey); | |||||
// 解密byte数组最大长度限制: 128 | |||||
int inputLen = encryptedData.length; | |||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||||
int offSet = 0; | |||||
byte[] cache; | |||||
int i = 0; | |||||
// 对数据分段解密 | |||||
while (inputLen - offSet > 0) { | |||||
if (inputLen - offSet > MAX_DECRYPT_BLOCK) { | |||||
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); | |||||
} else { | |||||
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); | |||||
} | |||||
out.write(cache, 0, cache.length); | |||||
i++; | |||||
offSet = i * MAX_DECRYPT_BLOCK; | |||||
} | |||||
byte[] decryptedData = out.toByteArray(); | |||||
out.close(); | |||||
return decryptedData; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 公钥加密 | |||||
* </p> | |||||
* | |||||
* @param data 源数据 | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static byte[] encryptByPublicKey(byte[] data, String certificatePath) | |||||
throws Exception { | |||||
// 取得公钥 | |||||
PublicKey publicKey = getPublicKey(certificatePath); | |||||
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); | |||||
cipher.init(Cipher.ENCRYPT_MODE, publicKey); | |||||
int inputLen = data.length; | |||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||||
int offSet = 0; | |||||
byte[] cache; | |||||
int i = 0; | |||||
// 对数据分段加密 | |||||
while (inputLen - offSet > 0) { | |||||
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { | |||||
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); | |||||
} else { | |||||
cache = cipher.doFinal(data, offSet, inputLen - offSet); | |||||
} | |||||
out.write(cache, 0, cache.length); | |||||
i++; | |||||
offSet = i * MAX_ENCRYPT_BLOCK; | |||||
} | |||||
byte[] encryptedData = out.toByteArray(); | |||||
out.close(); | |||||
return encryptedData; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 公钥解密 | |||||
* </p> | |||||
* | |||||
* @param encryptedData 已加密数据 | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static byte[] decryptByPublicKey(byte[] encryptedData, String certificatePath) | |||||
throws Exception { | |||||
PublicKey publicKey = getPublicKey(certificatePath); | |||||
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); | |||||
cipher.init(Cipher.DECRYPT_MODE, publicKey); | |||||
int inputLen = encryptedData.length; | |||||
ByteArrayOutputStream out = new ByteArrayOutputStream(); | |||||
int offSet = 0; | |||||
byte[] cache; | |||||
int i = 0; | |||||
// 对数据分段解密 | |||||
while (inputLen - offSet > 0) { | |||||
if (inputLen - offSet > MAX_DECRYPT_BLOCK) { | |||||
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); | |||||
} else { | |||||
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet); | |||||
} | |||||
out.write(cache, 0, cache.length); | |||||
i++; | |||||
offSet = i * MAX_DECRYPT_BLOCK; | |||||
} | |||||
byte[] decryptedData = out.toByteArray(); | |||||
out.close(); | |||||
return decryptedData; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 文件解密 | |||||
* </p> | |||||
* | |||||
* @param srcFilePath 源文件 | |||||
* @param destFilePath 目标文件 | |||||
* @param certificatePath 证书存储路径 | |||||
* @throws Exception | |||||
*/ | |||||
public static void decryptFileByPublicKey(String srcFilePath, String destFilePath, String certificatePath) | |||||
throws Exception { | |||||
PublicKey publicKey = getPublicKey(certificatePath); | |||||
Cipher cipher = Cipher.getInstance(publicKey.getAlgorithm()); | |||||
cipher.init(Cipher.DECRYPT_MODE, publicKey); | |||||
File srcFile = new File(srcFilePath); | |||||
FileInputStream in = new FileInputStream(srcFile); | |||||
File destFile = new File(destFilePath); | |||||
if (!destFile.getParentFile().exists()) { | |||||
destFile.getParentFile().mkdirs(); | |||||
} | |||||
destFile.createNewFile(); | |||||
OutputStream out = new FileOutputStream(destFile); | |||||
byte[] data = new byte[MAX_DECRYPT_BLOCK]; | |||||
byte[] decryptedData; // 解密块 | |||||
while (in.read(data) != -1) { | |||||
decryptedData = cipher.doFinal(data); | |||||
out.write(decryptedData, 0, decryptedData.length); | |||||
out.flush(); | |||||
} | |||||
out.close(); | |||||
in.close(); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 生成数据签名 | |||||
* </p> | |||||
* | |||||
* @param data 源数据 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static byte[] sign(byte[] data, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
// 获得证书 | |||||
X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password); | |||||
// 获取私钥 | |||||
KeyStore keyStore = getKeyStore(keyStorePath, password); | |||||
// 取得私钥 | |||||
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); | |||||
// 构建签名 | |||||
Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); | |||||
signature.initSign(privateKey); | |||||
signature.update(data); | |||||
return signature.sign(); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 生成数据签名并以BASE64编码 | |||||
* </p> | |||||
* | |||||
* @param data 源数据 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static String signToBase64(byte[] data, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
return Base64.getEncoder().encodeToString(sign(data, keyStorePath, alias, password)); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 生成文件数据签名(BASE64) | |||||
* </p> | |||||
* <p> | |||||
* 需要先将文件私钥加密,再根据加密后的数据生成签名(BASE64),适用于小文件 | |||||
* </p> | |||||
* | |||||
* @param filePath 源文件 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static String signFileToBase64WithEncrypt(String filePath, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
byte[] encryptedData = encryptFileByPrivateKey(filePath, keyStorePath, alias, password); | |||||
return signToBase64(encryptedData, keyStorePath, alias, password); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 生成文件签名 | |||||
* </p> | |||||
* <p> | |||||
* 注意:<br> | |||||
* 方法中使用了FileChannel,其巨大Bug就是不会释放文件句柄,导致签名的文件无法操作(移动或删除等)<br> | |||||
* 该方法已被generateFileSign取代 | |||||
* </p> | |||||
* | |||||
* @param filePath 文件路径 | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
@Deprecated | |||||
public static byte[] signFile(String filePath, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
byte[] sign = new byte[0]; | |||||
// 获得证书 | |||||
X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password); | |||||
// 获取私钥 | |||||
KeyStore keyStore = getKeyStore(keyStorePath, password); | |||||
// 取得私钥 | |||||
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); | |||||
// 构建签名 | |||||
Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); | |||||
signature.initSign(privateKey); | |||||
File file = new File(filePath); | |||||
if (file.exists()) { | |||||
FileInputStream in = new FileInputStream(file); | |||||
FileChannel fileChannel = in.getChannel(); | |||||
MappedByteBuffer byteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, file.length()); | |||||
signature.update(byteBuffer); | |||||
fileChannel.close(); | |||||
in.close(); | |||||
sign = signature.sign(); | |||||
} | |||||
return sign; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 生成文件数字签名 | |||||
* </p> | |||||
* | |||||
* @param filePath | |||||
* @param keyStorePath | |||||
* @param alias | |||||
* @param password | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static byte[] generateFileSign(String filePath, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
byte[] sign = new byte[0]; | |||||
// 获得证书 | |||||
X509Certificate x509Certificate = (X509Certificate) getCertificate(keyStorePath, alias, password); | |||||
// 获取私钥 | |||||
KeyStore keyStore = getKeyStore(keyStorePath, password); | |||||
// 取得私钥 | |||||
PrivateKey privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray()); | |||||
// 构建签名 | |||||
Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); | |||||
signature.initSign(privateKey); | |||||
File file = new File(filePath); | |||||
if (file.exists()) { | |||||
FileInputStream in = new FileInputStream(file); | |||||
byte[] cache = new byte[CACHE_SIZE]; | |||||
int nRead = 0; | |||||
while ((nRead = in.read(cache)) != -1) { | |||||
signature.update(cache, 0, nRead); | |||||
} | |||||
in.close(); | |||||
sign = signature.sign(); | |||||
} | |||||
return sign; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 文件签名成BASE64编码字符串 | |||||
* </p> | |||||
* | |||||
* @param filePath | |||||
* @param keyStorePath | |||||
* @param alias | |||||
* @param password | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static String signFileToBase64(String filePath, String keyStorePath, String alias, String password) | |||||
throws Exception { | |||||
return Base64.getEncoder().encodeToString(generateFileSign(filePath, keyStorePath, alias, password)); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 验证签名 | |||||
* </p> | |||||
* | |||||
* @param data 已加密数据 | |||||
* @param sign 数据签名[BASE64] | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static boolean verifySign(byte[] data, String sign, String certificatePath) | |||||
throws Exception { | |||||
// 获得证书 | |||||
X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath); | |||||
// 获得公钥 | |||||
PublicKey publicKey = x509Certificate.getPublicKey(); | |||||
// 构建签名 | |||||
Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); | |||||
signature.initVerify(publicKey); | |||||
signature.update(data); | |||||
return signature.verify(Base64.getDecoder().decode(sign)); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 验证签名 | |||||
* </p> | |||||
* | |||||
* @param data 已加密数据 | |||||
* @param sign 数据签名[BASE64] | |||||
* @param certificate 证书 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static boolean verifySign(byte[] data, String sign, byte[] certificate) | |||||
throws Exception { | |||||
// 获得证书 | |||||
X509Certificate x509Certificate = (X509Certificate) getCertificate(new ByteArrayInputStream(certificate)); | |||||
// 获得公钥 | |||||
PublicKey publicKey = x509Certificate.getPublicKey(); | |||||
// 构建签名 | |||||
Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); | |||||
signature.initVerify(publicKey); | |||||
signature.update(data); | |||||
return signature.verify(Base64.getDecoder().decode(sign)); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 校验文件签名 | |||||
* </p> | |||||
* | |||||
* @param filePath | |||||
* @param sign | |||||
* @param certificatePath | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
// public static boolean validateFileSign(String filePath, String sign, String certificatePath) | |||||
// throws Exception { | |||||
// boolean result = false; | |||||
// // 获得证书 | |||||
// X509Certificate x509Certificate = (X509Certificate) getCertificate(certificatePath); | |||||
// // 获得公钥 | |||||
// PublicKey publicKey = x509Certificate.getPublicKey(); | |||||
//// System.out.print("测试私钥"); | |||||
//// System.out.print(publicKey); | |||||
//// System.out.print("测试私钥"); | |||||
//// System.out.print("\n"); | |||||
// | |||||
// // 构建签名 | |||||
// Signature signature = Signature.getInstance(x509Certificate.getSigAlgName()); | |||||
// signature.initVerify(publicKey); | |||||
// File file = new File(filePath); | |||||
// if (file.exists()) { | |||||
// byte[] decodedSign = Base64Utils.decode(sign); | |||||
// FileInputStream in = new FileInputStream(file); | |||||
// byte[] cache = new byte[CACHE_SIZE]; | |||||
// int nRead = 0; | |||||
// while ((nRead = in.read(cache)) != -1) { | |||||
// signature.update(cache, 0, nRead); | |||||
// } | |||||
// in.close(); | |||||
// result = signature.verify(decodedSign); | |||||
// } | |||||
// return result; | |||||
// } | |||||
/** | |||||
* <p> | |||||
* BASE64解码->签名校验 | |||||
* </p> | |||||
* | |||||
* @param base64String BASE64编码字符串 | |||||
* @param sign 数据签名[BASE64] | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
// public static boolean verifyBase64Sign(String base64String, String sign, String certificatePath) | |||||
// throws Exception { | |||||
// byte[] data = Base64Utils.decode(base64String); | |||||
// return verifySign(data, sign, certificatePath); | |||||
// } | |||||
/** | |||||
* <p> | |||||
* BASE64解码->公钥解密-签名校验 | |||||
* </p> | |||||
* | |||||
* | |||||
* @param base64String BASE64编码字符串 | |||||
* @param sign 数据签名[BASE64] | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
// public static boolean verifyBase64SignWithDecrypt(String base64String, String sign, String certificatePath) | |||||
// throws Exception { | |||||
// byte[] encryptedData = Base64Utils.decode(base64String); | |||||
// byte[] data = decryptByPublicKey(encryptedData, certificatePath); | |||||
// return verifySign(data, sign, certificatePath); | |||||
// } | |||||
/** | |||||
* <p> | |||||
* 文件公钥解密->签名校验 | |||||
* </p> | |||||
* | |||||
* @param encryptedFilePath 加密文件路径 | |||||
* @param sign 数字证书[BASE64] | |||||
* @param certificatePath | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
// public static boolean verifyFileSignWithDecrypt(String encryptedFilePath, String sign, String certificatePath) | |||||
// throws Exception { | |||||
// byte[] encryptedData = fileToByte(encryptedFilePath); | |||||
// byte[] data = decryptByPublicKey(encryptedData, certificatePath); | |||||
// return verifySign(data, sign, certificatePath); | |||||
// } | |||||
/** | |||||
* <p> | |||||
* 校验证书当前是否有效 | |||||
* </p> | |||||
* | |||||
* @param certificate 证书 | |||||
* @return | |||||
*/ | |||||
public static boolean verifyCertificate(Certificate certificate) { | |||||
return verifyCertificate(new Date(), certificate); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 验证证书是否过期或无效 | |||||
* </p> | |||||
* | |||||
* @param date 日期 | |||||
* @param certificate 证书 | |||||
* @return | |||||
*/ | |||||
public static boolean verifyCertificate(Date date, Certificate certificate) { | |||||
boolean isValid = true; | |||||
try { | |||||
X509Certificate x509Certificate = (X509Certificate) certificate; | |||||
x509Certificate.checkValidity(date); | |||||
} catch (Exception e) { | |||||
isValid = false; | |||||
} | |||||
return isValid; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 验证数字证书是在给定的日期是否有效 | |||||
* </p> | |||||
* | |||||
* @param date 日期 | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
*/ | |||||
public static boolean verifyCertificate(Date date, String certificatePath) { | |||||
Certificate certificate; | |||||
try { | |||||
certificate = getCertificate(certificatePath); | |||||
return verifyCertificate(certificate); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* <p> | |||||
* 验证数字证书是在给定的日期是否有效 | |||||
* </p> | |||||
* | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
*/ | |||||
public static boolean verifyCertificate(Date date, String keyStorePath, String alias, String password) { | |||||
Certificate certificate; | |||||
try { | |||||
certificate = getCertificate(keyStorePath, alias, password); | |||||
return verifyCertificate(certificate); | |||||
} catch (Exception e) { | |||||
e.printStackTrace(); | |||||
return false; | |||||
} | |||||
} | |||||
/** | |||||
* <p> | |||||
* 验证数字证书当前是否有效 | |||||
* </p> | |||||
* | |||||
* @param keyStorePath 密钥库存储路径 | |||||
* @param alias 密钥库别名 | |||||
* @param password 密钥库密码 | |||||
* @return | |||||
*/ | |||||
public static boolean verifyCertificate(String keyStorePath, String alias, String password) { | |||||
return verifyCertificate(new Date(), keyStorePath, alias, password); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 验证数字证书当前是否有效 | |||||
* </p> | |||||
* | |||||
* @param certificatePath 证书存储路径 | |||||
* @return | |||||
*/ | |||||
public static boolean verifyCertificate(String certificatePath) { | |||||
return verifyCertificate(new Date(), certificatePath); | |||||
} | |||||
/** | |||||
* <p> | |||||
* 文件转换为byte数组 | |||||
* </p> | |||||
* | |||||
* @param filePath 文件路径 | |||||
* @return | |||||
* @throws Exception | |||||
*/ | |||||
public static byte[] fileToByte(String filePath) throws Exception { | |||||
byte[] data = new byte[0]; | |||||
File file = new File(filePath); | |||||
if (file.exists()) { | |||||
FileInputStream in = new FileInputStream(file); | |||||
ByteArrayOutputStream out = new ByteArrayOutputStream(2048); | |||||
byte[] cache = new byte[CACHE_SIZE]; | |||||
int nRead = 0; | |||||
while ((nRead = in.read(cache)) != -1) { | |||||
out.write(cache, 0, nRead); | |||||
out.flush(); | |||||
} | |||||
out.close(); | |||||
in.close(); | |||||
data = out.toByteArray(); | |||||
} | |||||
return data; | |||||
} | |||||
/** | |||||
* <p> | |||||
* 二进制数据写文件 | |||||
* </p> | |||||
* | |||||
* @param bytes 二进制数据 | |||||
* @param filePath 文件生成目录 | |||||
*/ | |||||
public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { | |||||
InputStream in = new ByteArrayInputStream(bytes); | |||||
File destFile = new File(filePath); | |||||
if (!destFile.getParentFile().exists()) { | |||||
destFile.getParentFile().mkdirs(); | |||||
} | |||||
destFile.createNewFile(); | |||||
OutputStream out = new FileOutputStream(destFile); | |||||
byte[] cache = new byte[CACHE_SIZE]; | |||||
int nRead = 0; | |||||
while ((nRead = in.read(cache)) != -1) { | |||||
out.write(cache, 0, nRead); | |||||
out.flush(); | |||||
} | |||||
out.close(); | |||||
in.close(); | |||||
} | |||||
} |
package com.chinaeinv.einv.util; | |||||
import javax.net.ssl.*; | |||||
import java.io.*; | |||||
import java.net.HttpURLConnection; | |||||
import java.net.URL; | |||||
import java.net.URLEncoder; | |||||
import java.security.SecureRandom; | |||||
import java.security.cert.X509Certificate; | |||||
import java.util.Map; | |||||
import java.util.Map.Entry; | |||||
/** | |||||
* 进行http访问的基本类 | |||||
*/ | |||||
public class HttpUtil { | |||||
private static final String DEFAULT_CHARSET = "UTF-8"; | |||||
private static final String METHOD_POST = "POST"; | |||||
private static final String METHOD_GET = "GET"; | |||||
private static final int CONNECTTIMEOUT = 5000; | |||||
private static final int READTIMEOUT = 5000; | |||||
private static class DefaultTrustManager implements X509TrustManager { | |||||
public X509Certificate[] getAcceptedIssuers() { | |||||
return null; | |||||
} | |||||
public void checkClientTrusted(X509Certificate[] cert, String oauthType) | |||||
throws java.security.cert.CertificateException { | |||||
} | |||||
public void checkServerTrusted(X509Certificate[] cert, String oauthType) | |||||
throws java.security.cert.CertificateException { | |||||
} | |||||
} | |||||
private static HttpURLConnection getConnection(URL url, String method) | |||||
throws IOException { | |||||
HttpURLConnection conn; | |||||
if ("https".equals(url.getProtocol())) { | |||||
SSLContext ctx; | |||||
try { | |||||
ctx = SSLContext.getInstance("TLS"); | |||||
ctx.init(new KeyManager[0], new TrustManager[] { new DefaultTrustManager() }, | |||||
new SecureRandom()); | |||||
} catch (Exception e) { | |||||
throw new IOException(e); | |||||
} | |||||
HttpsURLConnection connHttps = (HttpsURLConnection) url.openConnection(); | |||||
connHttps.setSSLSocketFactory(ctx.getSocketFactory()); | |||||
connHttps.setHostnameVerifier(new HostnameVerifier() { | |||||
public boolean verify(String hostname, SSLSession session) { | |||||
return true;// 默认都认证通过 | |||||
} | |||||
}); | |||||
conn = connHttps; | |||||
} else { | |||||
conn = (HttpURLConnection) url.openConnection(); | |||||
} | |||||
conn.setRequestMethod(method); | |||||
conn.setDoInput(true); | |||||
conn.setDoOutput(true); | |||||
conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8"); | |||||
conn.setRequestProperty("Connection", "Keep-Alive"); | |||||
return conn; | |||||
} | |||||
/** | |||||
* 通过get方法访问 | |||||
* | |||||
* @param url 访问的url地址 | |||||
* @param urlParams 请求需要的参数 | |||||
* @return 返回请求响应的数据 | |||||
* @throws IOException | |||||
*/ | |||||
public static String doGet(String url, Map<String, String> urlParams) | |||||
throws IOException { | |||||
if (isEmpty(url)) { | |||||
throw new IllegalArgumentException("The parameter 'url' can not be null or blank."); | |||||
} | |||||
url += buildQuery(urlParams, DEFAULT_CHARSET); | |||||
HttpURLConnection conn = getConnection(new URL(url), METHOD_GET); | |||||
String s = getResponseAsString(conn); | |||||
return s; | |||||
} | |||||
/** | |||||
* | |||||
* @param url api请求的权路径url地址 | |||||
* @param urlParams 请求的参数 | |||||
* @param requestJson 请求报文 | |||||
* @return 请求响应 | |||||
* @throws IOException | |||||
*/ | |||||
public static String doPost(String url, Map<String, String> urlParams, String requestJson) throws IOException { | |||||
return doPost(url, urlParams, requestJson, CONNECTTIMEOUT, READTIMEOUT); | |||||
} | |||||
/** | |||||
* | |||||
* 通过post方法请求数据 | |||||
* | |||||
* @param url 请求的url地址 | |||||
* @param urlParams 请求的参数 | |||||
* @param requestJson 请求报文 | |||||
* @param connectTimeOut 请求连接过期时间 | |||||
* @param readTimeOut 请求读取过期时间 | |||||
* @return 请求响应 | |||||
* @throws IOException | |||||
*/ | |||||
public static String doPost(String url, Map<String, String> urlParams, String requestJson, | |||||
int connectTimeOut, int readTimeOut) throws IOException { | |||||
if (isEmpty(url)) { | |||||
throw new IllegalArgumentException("The parameter 'url' can not be null or blank."); | |||||
} | |||||
url += buildQuery(urlParams, DEFAULT_CHARSET); | |||||
HttpURLConnection conn = getConnection(new URL(url), METHOD_POST); | |||||
conn.setConnectTimeout(connectTimeOut); | |||||
conn.setReadTimeout(readTimeOut); | |||||
conn.getOutputStream().write(requestJson.getBytes(DEFAULT_CHARSET)); | |||||
String s = getResponseAsString(conn); | |||||
return s; | |||||
} | |||||
/** | |||||
* | |||||
* @param params 请求参数 | |||||
* @return 构建query | |||||
*/ | |||||
public static String buildQuery(Map<String, String> params, String charset) throws UnsupportedEncodingException { | |||||
if (params == null || params.isEmpty()) { | |||||
return ""; | |||||
} | |||||
StringBuilder sb = new StringBuilder(); | |||||
boolean first = true; | |||||
for (Entry<String, String> entry : params.entrySet()) { | |||||
if (first) { | |||||
sb.append("?"); | |||||
first = false; | |||||
} else { | |||||
sb.append("&"); | |||||
} | |||||
String key = entry.getKey(); | |||||
String value = entry.getValue(); | |||||
if (areNotEmpty(key, value)) { | |||||
sb.append(key).append("=").append(URLEncoder.encode(value, charset)); | |||||
} | |||||
} | |||||
return sb.toString(); | |||||
} | |||||
private static String getResponseAsString(HttpURLConnection conn) throws IOException { | |||||
InputStream es = conn.getErrorStream(); | |||||
if (es == null) { | |||||
return getStreamAsString(conn.getInputStream(), DEFAULT_CHARSET); | |||||
} else { | |||||
String msg = getStreamAsString(es, DEFAULT_CHARSET); | |||||
if (isEmpty(msg)) { | |||||
throw new IOException(conn.getResponseCode() + " : " + conn.getResponseMessage()); | |||||
} else { | |||||
throw new IOException(msg); | |||||
} | |||||
} | |||||
} | |||||
private static String getStreamAsString(InputStream input, String charset) throws IOException { | |||||
StringBuilder sb = new StringBuilder(); | |||||
BufferedReader bf = null; | |||||
try { | |||||
bf = new BufferedReader(new InputStreamReader(input, charset)); | |||||
String str; | |||||
while ((str = bf.readLine()) != null) { | |||||
sb.append(str); | |||||
} | |||||
return sb.toString(); | |||||
} finally { | |||||
if (bf != null) { | |||||
bf.close(); | |||||
} | |||||
} | |||||
} | |||||
/** | |||||
* 判断字符串为空 | |||||
* | |||||
* @param str 字符串信息 | |||||
* @return true or false | |||||
*/ | |||||
private static boolean isEmpty(String str) { | |||||
return str == null || str.trim().length() == 0; | |||||
} | |||||
/** | |||||
* 判断字符数组,不为空 | |||||
* | |||||
* @param values 字符数组 | |||||
* @return true or false | |||||
*/ | |||||
public static boolean areNotEmpty(String... values) { | |||||
if (values == null || values.length == 0) { | |||||
return false; | |||||
} | |||||
for (String value : values) { | |||||
if (isEmpty(value)) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
} |