# 发票打印
# 发票打印
# URL
POST
Content-Type:application/json; charset=UTF-8
http://{HOST}:{PORT}/output-tax/api/invoice-his/print?appid=XXXXX
TIP
打印接口只支持纸质发票打印
# 请求体
{
"fpDm":"发票代码",
"fpHm":"发票号码",
"qdbz":"清单标志",
"orgCode":"组织编码"
}
# 请求体参数
| 参数 | 是否必填| 类型| 描述 | 说明 | | :----------- | :----------------------------------------------------------- | :----------------------------------------------------------- | | fpDm| 是|String|发票代码|| | fpHm|是|String| 发票号码 | | qdbz|否|String| 清单标志;0-只打印发票;1-打印清单;默认0 | | orgCode| 是|String|组织编码||
# 返回值
{
"code": "0000",
"msg": "success"
}
# 返回结果说明
参数 | 类型 | 描述 | 说明 |
---|---|---|---|
code | String | 状态码 | 详见状态码说明 |
msg | String | 信息说明 |
# 附录
# 样例代码
# Java(适用于JDK1.6及其更高版本)
# Maven配置文件依赖
依赖配置如下
<!-- httpclient,发送HTTP请求 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
<!-- gson,json转换工具 -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.7</version>
</dependency>
<!-- jjwt,Java Web Token签名工具包 -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.6.0</version>
</dependency>
# API调用代码
import com.google.gson.GsonBuilder;
import com.yonyou.einvoice.einvoiceApply.JwtParamBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.compression.CompressionCodecs;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.util.io.pem.PemReader;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @date 2018/5/25
* <p>
* 扫码开票接口测试代码,适用于JDK1.6及更高版本,jdk1.6版本需要对签名方法稍做修改,修改方法在签名方法内已经写明
* 请求参数的注意事项也在参数构建的过程中写明,请详细阅读样例代码。
*/
public class InsertForQRInvoice {
//测试环境有测试appid和证书,正式环境有正式appid和证书,请务必对应使用
//测试环境appid就用这个,正式环境需要替换成正式的
private static String APPID = "commontesterCA";
//这个是测试环境的域名,正式环境为https://fapiao.yonyoucloud.com
private static String DOMAIN = "https://yesfp.yonyoucloud.com";
private static String URL = DOMAIN + "/input-tax/api/pit/report/import?appid=" + APPID;
//pro22.pfx为测试环境通讯证书,正式环境需要替换成正式的
private static String KEYPATH = "src/main/resources/certificate/pro22.pfx";
//证书密码
private static String PASSWORD = "password";
public static void main(String[] args) {
try {
new InsertForQRInvoice().callQRInvoiceApply();
} catch (Exception e) {
e.printStackTrace();
}
}
private static CloseableHttpClient createSSLClientDefault() {
try {
SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
@Override
public boolean isTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
}).build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier() {
@Override
public boolean verify(String s, SSLSession sslSession) {
return true;
}
});
return HttpClients.custom().setSSLSocketFactory(sslsf).build();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
}
return HttpClients.createDefault();
}
public void callQRInvoiceApply() throws Exception {
// 提供两种构建HttpClient实例的方法,如果使用被注释掉的方法构建实例报证书不被信任的错误,那么请使用未被注释的构建方法
// HttpClient httpClient = HttpClients.custom().build();
HttpClient httpClient = createSSLClientDefault(); //信任所有https证书
HttpPost httpPost = new HttpPost(URL);
// 构造POST请求体
String body = this.buildRequestDatas();
// 签名
String sign = this.sign(body);
httpPost.addHeader("sign", sign);
httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");
StringEntity se = new StringEntity(body.toString(), "UTF-8");
se.setContentType("text/json");
se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
httpPost.setEntity(se);
// 发送http post请求,并得到响应结果
HttpResponse response = httpClient.execute(httpPost);
String result = "";
if (response != null) {
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
result = EntityUtils.toString(resEntity, "UTF-8");
System.out.println(result);
}
}
}
/**
* 签名
*
* @param paramsMap 表单参数
* @return 签名值
* @throws Exception
*/
private String sign(String paramsMap) throws Exception {
// 读取CA证书与PEM格式证书需要根据实际证书使用情况而定,目前这两种都支持
PrivateKey privateKey = loadPrivateKeyOfCA();
// PrivateKey privateKey = loadPrivateKeyOfPem();
Map<String, Object> claims =
JwtParamBuilder.build().setSubject("tester").setIssuer("einvoice").setAudience("einvoice")
.addJwtId().addIssuedAt().setExpirySeconds(300).setNotBeforeSeconds(300).getClaims();
// 此签名数据必须存在,否则在验证签名时会不通过。
claims.put("requestdatas", getMD5(paramsMap));
// 使用jdk1.6版本时,删除下面代码的中.compressWith(CompressionCodecs.DEFLATE)
String compactJws = Jwts.builder().signWith(SignatureAlgorithm.RS512, privateKey)
.setClaims(claims).compressWith(CompressionCodecs.DEFLATE).compact();
return compactJws;
}
/**
* 计算MD5
*
* @param str
* @return
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
private String getMD5(String str) throws UnsupportedEncodingException, NoSuchAlgorithmException {
byte[] buf = null;
buf = str.getBytes("utf-8");
MessageDigest md5 = null;
md5 = MessageDigest.getInstance("MD5");
md5.update(buf);
byte[] tmp = md5.digest();
StringBuilder sb = new StringBuilder();
for (byte b : tmp) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
/**
* 读取证书私钥
*
* @return
* @throws UnrecoverableKeyException
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws CertificateException
* @throws IOException
*/
protected PrivateKey loadPrivateKeyOfCA() throws UnrecoverableKeyException, KeyStoreException,
NoSuchAlgorithmException, CertificateException, IOException {
FileInputStream in = new FileInputStream(KEYPATH);
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(in, PASSWORD.toCharArray());
String alias = ks.aliases().nextElement();
PrivateKey caprk = (PrivateKey) ks.getKey(alias, PASSWORD.toCharArray());
return caprk;
}
/**
* 构造请求的json数据
*
* @return
*/
private String buildRequestDatas() {
return "这应该是一个json格式字符串";
}
#####API相关工具类
package com.yonyou.einvoice.test;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* @author wangweir
*
*/
public class JwtParamBuilder {
/** JWT {@code Issuer} claims parameter name: <code>"iss"</code> */
public static final String ISSUER = "iss";
/** JWT {@code Subject} claims parameter name: <code>"sub"</code> */
public static final String SUBJECT = "sub";
/** JWT {@code Audience} claims parameter name: <code>"aud"</code> */
public static final String AUDIENCE = "aud";
/** JWT {@code Expiration} claims parameter name: <code>"exp"</code> */
public static final String EXPIRATION = "exp";
/** JWT {@code Not Before} claims parameter name: <code>"nbf"</code> */
public static final String NOT_BEFORE = "nbf";
/** JWT {@code Issued At} claims parameter name: <code>"iat"</code> */
public static final String ISSUED_AT = "iat";
/** JWT {@code JWT ID} claims parameter name: <code>"jti"</code> */
public static final String ID = "jti";
private Map<String, Object> claims;
private final long now;
private JwtParamBuilder() {
claims = new HashMap<>();
now = System.currentTimeMillis() / 1000l;
}
public static JwtParamBuilder build() {
return new JwtParamBuilder();
}
public JwtParamBuilder addIssuedAt() {
claims.put(ISSUED_AT, now);
return this;
}
public JwtParamBuilder setExpirySeconds(final Integer expirySeconds) {
claims.put(EXPIRATION, now + expirySeconds);
return this;
}
public JwtParamBuilder setNotBeforeSeconds(final Integer beforeSeconds) {
claims.put(NOT_BEFORE, now - beforeSeconds);
return this;
}
public JwtParamBuilder setSubject(String sub) {
addOneClaim(SUBJECT, sub);
return this;
}
public JwtParamBuilder setIssuer(String iss) {
addOneClaim(ISSUER, iss);
return this;
}
public JwtParamBuilder setAudience(String aud) {
addOneClaim(AUDIENCE, aud);
return this;
}
public JwtParamBuilder addJwtId() {
return setJwtId(UUID.randomUUID().toString());
}
public JwtParamBuilder setJwtId(String jwtid) {
addOneClaim(ID, UUID.randomUUID().toString());
return this;
}
public JwtParamBuilder claim(String name, Object value) {
if (value == null) {
this.claims.remove(name);
} else {
this.claims.put(name, value);
}
return this;
}
private void addOneClaim(String key, String value) {
if (value != null && value.length() > 0) {
claims.put(key, value);
}
}
/**
* @return the claims
*/
public Map<String, Object> getClaims() {
return claims;
}
}