@@ -0,0 +1,6 @@ | |||
.DS_Store | |||
java/.idea/ | |||
java/out/ | |||
java/*.iml | |||
cs/.vs/ |
@@ -0,0 +1,22 @@ | |||
| |||
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 |
@@ -0,0 +1,196 @@ | |||
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); | |||
} | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
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")] |
@@ -0,0 +1,34 @@ | |||
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); | |||
} | |||
} |
@@ -0,0 +1,133 @@ | |||
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(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,183 @@ | |||
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; } | |||
} | |||
} |
@@ -0,0 +1,82 @@ | |||
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; } | |||
} | |||
} |
@@ -0,0 +1,14 @@ | |||
using System.Collections.Generic; | |||
namespace com.chinaeinv.einv.order.dto | |||
{ | |||
/** | |||
* “根据订单编号查询发票”方法响应和回调数据 | |||
*/ | |||
public class InvoiceResult : Result { | |||
/** | |||
* 发票列表 | |||
*/ | |||
public List<Invoice> invoices { get; set; } | |||
} | |||
} |
@@ -0,0 +1,156 @@ | |||
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; } | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
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; | |||
} | |||
} | |||
} |
@@ -0,0 +1,69 @@ | |||
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; } | |||
} | |||
} |
@@ -0,0 +1,17 @@ | |||
namespace com.chinaeinv.einv.order.dto | |||
{ | |||
/** | |||
* 异步方法响应和“取消订单”方法响应 | |||
*/ | |||
public class Result { | |||
/** | |||
* 处理结果代码 | |||
*/ | |||
public string code { get; set; } | |||
/** | |||
* 处理结果消息 | |||
*/ | |||
public string message { get; set; } | |||
} | |||
} |
@@ -0,0 +1,85 @@ | |||
<?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> |
@@ -0,0 +1,6 @@ | |||
<?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> |
@@ -0,0 +1,191 @@ | |||
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); | |||
} | |||
} |
@@ -0,0 +1,36 @@ | |||
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; | |||
} |
@@ -0,0 +1,92 @@ | |||
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); | |||
} | |||
} |
@@ -0,0 +1,454 @@ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,203 @@ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,387 @@ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,72 @@ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,174 @@ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,32 @@ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,888 @@ | |||
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(); | |||
} | |||
} |
@@ -0,0 +1,223 @@ | |||
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; | |||
} | |||
} |