赞
踩
目录
这里的appid 和 secret 是公众号的 不要写小程序的哦
https请求方式: GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
参数说明
参数 | 是否必须 | 说明 |
---|---|---|
grant_type | 是 | 获取access_token填写client_credential |
appid | 是 | 第三方用户唯一凭证 |
secret | 是 | 第三方用户唯一凭证密钥,即appsecret |
这个获取代码我就不写了哈 应该都知道
这个地方代码我也不写 上面获取到的 Access token传入进来就行了 自己用postman调用一下 拿到invoice_url中的s_pappid存起来就行了
请求URL:https://api.weixin.qq.com/card/invoice/seturl?access_token={access_token}
请求方法:POST
请求参数
请求参数使用JSON格式,传入空值{}
返回结果
返回结果为JSON格式,字段如下:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
errcode | string | 是 | 错误码 |
errmsg | string | 是 | 错误信息 |
invoice_url | string | 否 | 该开票平台专用的授权链接。开票平台须将 invoice_url 内的 s_pappid 给到服务的商户,商户在请求授权链接时会向微信传入该参数,标识所使用的开票平台是哪家 |
这个获取到账号请截取下来 只需要获取一次 保存到配置文件即可
ticket 的有效期,一般为 7200 秒
这个我也不写了 还是把上面获取的ACCESS_TOKEN传入 就能拿到ticket 记得写成一个方法
请求方式
请求URL:https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=wx_card
请求方法:GET
返回结果
返回结果使用JSON格式,字段如下:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
errcode | Int | 是 | 错误码,含义见错误码 |
errmsg | String | 是 | 错误信息,含义见错误码 |
ticket | String | 是 | 临时票据,用于在获取授权链接时作为参数传入 |
expires_in | Int | 是 | ticket 的有效期,一般为 7200 秒 |
示例代码
- 返回:
- {
- "errcode": 0,
- "errmsg":"ok",
- "ticket":"m7RQzjA_ljjEkt-JCoklRM5zrzYr-6PI09QydZmNXXz-opTqMv53aFj1ykRt_AOtvqidqZZsLhCDgwGC6nBDiA",
- "expires_in": 7200
- }
请求方式 请求URL:https://api.weixin.qq.com/card/invoice/setbizattr?action=set_contact&access_token={access_token}
请求方法:POST
请求参数使用JSON格式,字段如下:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
contact | Object | 是 | 联系方式信息 |
contact是Object,里面包括以下字段:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
time_out | int | 是 | 开票超时时间 |
phone | string | 是 | 联系电话 |
- public static JSONObject setContactInfo(String accessToken, int timeout, String phone) {
- try {
- String url = "https://api.weixin.qq.com/card/invoice/setbizattr?action=set_contact&access_token=" + accessToken;
- URL obj = new URL(url);
- HttpURLConnection conn = (HttpURLConnection) obj.openConnection();
- // 设置请求方法为POST
- conn.setRequestMethod("POST");
- // 设置请求头
- conn.setRequestProperty("Content-Type", "application/json");
- // 构造请求参数
- String requestBodyJson = "{\"contact\": {\"time_out\": " + timeout + ", \"phone\": \"" + phone + "\"}}";
- // 发送POST请求
- conn.setDoOutput(true);
- DataOutputStream wr = new DataOutputStream(conn.getOutputStream());
- wr.writeBytes(requestBodyJson);
- wr.flush();
- wr.close();
- // 读取响应
- BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
- String inputLine;
- StringBuilder response = new StringBuilder();
- while ((inputLine = in.readLine()) != null) {
- response.append(inputLine);
- }
- in.close();
- // 解析JSON响应
- JSONObject result = new JSONObject(response.toString());
-
- conn.disconnect();
- return result;
- } catch (Exception e) {
- e.printStackTrace();
- JSONObject result = new JSONObject();
- return result.put("errcode", 1);
- }
- }
获取授权页 让用户填写 抬头
根据自己需求选 类型
请求方式
请求URL:https://api.weixin.qq.com/card/invoice/getauthurl?access_token={access_token}
请求方法:POST
请求参数
请求参数使用JSON格式,字段如下:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
s_pappid | String | 是 | 开票平台在微信的标识号,商户需要找开票平台提供 |
order_id | String | 是 | 订单id,在商户内单笔开票请求的唯一识别号, |
money | Int | 是 | 订单金额,以分为单位 |
timestamp | Int | 是 | 时间戳 |
source | String | 是 | 开票来源,app:app开票,web:微信h5开票,wxa:小程序开发票,wap:普通网页开票 |
redirect_url | String | 否 | 授权成功后跳转页面。本字段只有在source为H5的时候需要填写,引导用户在微信中进行下一步流程。app开票因为从外部app拉起微信授权页,授权完成后自动回到原来的app,故无需填写。 |
ticket | String | 是 | 从上一环节中获取 |
type | Int | 是 | 授权类型,0:开票授权,1:填写字段开票授权,2:领票授权 |
- /**
- * 获取授权url
- */
- public static JSONObject getAuthURLnew(String source,int money,String order_id,String ticket,String accessToken,String sPappid,int timestamp) throws Exception{
- if(money == 0 || order_id == null || ticket == null || sPappid==null){
- JSONObject errParams = new JSONObject();
- errParams.put("errcode",1);
- return errParams;
- }
- int code = sendPostRequest(accessToken);
- if(code == 1){
- JSONObject errParams = new JSONObject();
- errParams.put("errcode",1);
- return errParams;
- }
- String auth_url = "";
-
- // 准备请求参数
- JSONObject requestParams = new JSONObject();
- requestParams.put("s_pappid", sPappid);
- requestParams.put("order_id", order_id);
- requestParams.put("money", money); // 假设订单金额为1元,单位为分
- requestParams.put("timestamp", timestamp);
- requestParams.put("source", source); // 根据你的需求选择开票来源
- // requestParams.put("redirect_url", "YOUR_REDIRECT_URL"); // 如果需要的话
- requestParams.put("ticket", ticket);
- requestParams.put("type", 1); // 根据你的需求选择授权类型
-
-
-
- // 发送POST请求到微信API
- String apiUrl = "https://api.weixin.qq.com/card/invoice/getauthurl?access_token=" + accessToken;
- URL url = new URL(apiUrl);
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setRequestMethod("POST");
- connection.setRequestProperty("Content-Type", "application/json; utf-8");
- connection.setRequestProperty("Accept", "application/json");
- connection.setDoOutput(true);
-
- try (OutputStream os = connection.getOutputStream()) {
- byte[] input = requestParams.toString().getBytes("utf-8");
- os.write(input, 0, input.length);
- }
-
- try (BufferedReader br = new BufferedReader(
- new InputStreamReader(connection.getInputStream(), "utf-8"))) {
- StringBuilder response = new StringBuilder();
- String responseLine;
- while ((responseLine = br.readLine()) != null) {
- response.append(responseLine.trim());
- }
- // 将JSON字符串转换为JSONObject
- JSONObject data = new JSONObject(response.toString());
- // 从JSONObject中获取auth_url的值
- auth_url = data.getString("auth_url");
- connection.disconnect();
- return data;
-
- }
- }
小程序返回的数据是这样的
我们只需要 把返回的auth_url 和appid 换上去就行了代码下面
这是在微信开发者工具 你们逻辑哪个地方该打开这个授权页 就写在哪哦
- wx.navigateToMiniProgram({
- appId: '{appid}',
- path: '{auth_url}',
- success(res) {
- console.log('navigateToMiniProgram success:', res)
- },
- fail(error){
- console.log('navigateToMiniProgram fail:', error)
- },
- complete(res){
- console.log('navigateToMiniProgram complete:', res)
- }
- })
在用户授权同意发票存入自己微信账户后,商户可以收到授权完成的状态推送。收到推送后,可以将order_id连同开票信息一并发送给开票平台,以便开票平台在开票成功后将电子发票插入用户卡包。
该事件将发送至开发者填写的URL(登录公众平台进入【开发者中心设置】,如果是open账号,也得用公众号账号来接,参考下图)。
这个你要去那里设置回调地址 接收那边的回调带给你个 订单id 然后可以通过这个id去查用户收钱填写的信息
我是这样处理的 回调地址是你们上面设置的
if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType = eventMessage.getEvent();
// 收取授权完成事件推送
if (eventType.equals(MessageUtil.USER_AUTHORIZE_INVOICE)) {
//授权成功的ID
Invoice invoice = new Invoice();
String succOrderId = eventMessage.getSuccOrderId();
if(succOrderId!=null || succOrderId != ""){
invoice.getAuthdata(succOrderId);
}
}
上面进入的你回调之后
请求方式
请求URL:https://api.weixin.qq.com/card/invoice/getauthdata?access_token={access_token}
请求方法:POST
请求参数
请求参数使用JSON格式,字段如下:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
order_id | string | 是 | 发票order_id |
s_pappid | String | 是 | 开票平台在微信的标识,由开票平台告知商户 |
- // 查询授权完成状态
- @SuppressWarnings("unused")
- public static JSONObject callGetAuthDataAPI(String accessToken, String orderId, String sPappid) throws Exception {
- String API_URL = "https://api.weixin.qq.com/card/invoice/getauthdata?access_token=%s";
- String apiUrl = String.format(API_URL, accessToken);
- URL url = new URL(apiUrl);
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setRequestMethod("POST");
- connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
- connection.setRequestProperty("Accept", "application/json");
- connection.setDoOutput(true);
-
- JSONObject requestBody = new JSONObject();
- requestBody.put("order_id", orderId);
- requestBody.put("s_pappid", sPappid);
-
- try (DataOutputStream os = new DataOutputStream(connection.getOutputStream())) {
- byte[] input = requestBody.toString().getBytes("utf-8");
- os.write(input, 0, input.length);
- }
-
- try (BufferedReader br = new BufferedReader(
- new InputStreamReader(connection.getInputStream(), "utf-8"))) {
- StringBuilder response = new StringBuilder();
- String responseLine;
- while ((responseLine = br.readLine()) != null) {
- response.append(responseLine.trim());
- }
- JSONObject result = new JSONObject(response.toString());
- return result;
- }
- }
查询出来的的数据 自己记得插入数据库对应开票订单的信息
只需创建一次 把卡劵id card_id 存起来哈
- 返回:
- {
- "errcode": 0,
- "errmsg": "ok",
- "card_id": "pjZ8Yt9WoOePThU0NfUKz5-tBEWU"
- }
请求方式
请求URL:https://api.weixin.qq.com/card/invoice/platform/createcard?access_token={access_token}
请求方法:POST
请求参数
请求参数使用JSON格式,字段如下:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
invoice_info | Object | 是 | 发票模板对象 |
invoice_info为Object,里面包括以下字段:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
base_info | object | 是 | 发票卡券模板基础信息 |
payee | string | 是 | 收款方(开票方)全称,显示在发票详情内。故建议一个收款方对应一个发票卡券模板 |
type | string | 是 | 发票类型 |
base_info为Object,里面包括以下字段:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
logo_url | string | 是 | 发票商家 LOGO ,请参考 新增永久素材 |
title | string | 是 | 收款方(显示在列表),上限为 9 个汉字,建议填入商户简称 |
custom_url_name | string | 否 | 开票平台自定义入口名称,与 custom_url 字段共同使用,长度限制在 5 个汉字内 |
custom_url | string | 否 | 开票平台自定义入口跳转外链的地址链接 , 发票外跳的链接会带有发票参数,用于标识是从哪张发票跳出的链接 |
custom_url_sub_title | string | 否 | 显示在入口右侧的 tips ,长度限制在 6 个汉字内 |
promotion_url_name | string | 否 | 营销场景的自定义入口 |
promotion_url | string | 否 | 入口跳转外链的地址链接,发票外跳的链接会带有发票参数,用于标识是从那张发票跳出的链接 |
promotion_url_sub_title | string | 否 | 显示在入口右侧的 tips ,长度限制在 6 个汉字内 |
- //创建发票卡劵模板
- public static JSONObject createInvoiceCardTemplate(String accessToken, JSONObject invoiceInfo) throws Exception {
-
- String url = "https://api.weixin.qq.com/card/invoice/platform/createcard?access_token="+accessToken;
- URL obj = new URL(url);
- HttpURLConnection con = (HttpURLConnection) obj.openConnection();
-
- // 设置请求方法
- con.setRequestMethod("POST");
-
- // 设置请求头
- con.setRequestProperty("Content-Type", "application/json; utf-8");
- con.setRequestProperty("Accept", "application/json");
- con.setDoOutput(true);
-
- // 构建请求体
- String jsonInputString = invoiceInfo.toString();
-
- try (OutputStream os = con.getOutputStream()) {
- byte[] input = jsonInputString.getBytes("utf-8");
- os.write(input, 0, input.length);
- }
-
- try (BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "utf-8"))) {
- StringBuilder response = new StringBuilder();
- String responseLine;
- while ((responseLine = br.readLine()) != null) {
- response.append(responseLine.trim());
- }
- JSONObject result = new JSONObject(response.toString());
- int errcode = (int) result.get("errcode");
- if (errcode == 0) {
- return result;
- } else {
- JSONObject result1 = new JSONObject();
- return result1.put("errcode",1);
- }
- }
- }
这里把财务开好的PDF发票文件 我这里写了一个pdf文件识别 拿到了对应的抬头信息
记得把返回的s_media_id在数据库对应订单存起来
- 返回:
- {
- "errcode":0,
- "errmsg":"ok",
- "s_media_id":"3015806758683707"
- }
请求方式
请求URL:https://api.weixin.qq.com/card/invoice/platform/setpdf?access_token={access_token}
请求方法:POST
请求参数
数据格式使用multipart/form-data,参数清单如下:
参数 | 是否必填 | 描述 |
---|---|---|
是 | form-data中媒体文件标识,有filename、filelength、content-type等信息 |
- //上传发票
- public static JSONObject uploadPDF(File file,String access_token,String invoiceName){
- JSONObject objectData = extractInvoiceNumber(file);
- int code = (int)objectData.get("errcode");
- JSONObject errParams = new JSONObject();
- if(code==1){
- errParams.put("errcode",1);
- errParams.put("errmsg","PDF文件解析失败");
- return errParams;
- }
- if(!invoiceName.equals(objectData.get("companyName"))){
- errParams.put("errcode",1);
- errParams.put("errmsg","发票抬头与学生需开不一致");
- return errParams;
- }
- String urlString = "https://api.weixin.qq.com/card/invoice/platform/setpdf?access_token="+access_token;
-
- URL url;
- try {
- url = new URL(urlString);
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setRequestMethod("POST");
- conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW");
- conn.setDoOutput(true);
- conn.setDoInput(true);
- conn.setUseCaches(false);
-
- // 获取输出流
- OutputStream os = (OutputStream) conn.getOutputStream();
-
- // 写入multipart/form-data的边界
- String boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW";
- os.write(("--" + boundary + "\r\n").getBytes());
-
- // 写入文件表单字段
- String formFieldName = "pdf";
- String fileName = file.getName();
- String contentType = Files.probeContentType(file.toPath());
- String contentDisposition = "Content-Disposition: form-data; name=\"" + formFieldName + "\"; filename=\"" + fileName + "\"\r\n";
- os.write(contentDisposition.getBytes());
- os.write(("Content-Type: " + contentType + "\r\n\r\n").getBytes());
-
- // 写入文件内容
- Files.copy(file.toPath(), os);
-
- // 写入multipart/form-data的结束边界
- os.write(("\r\n--" + boundary + "--\r\n").getBytes());
-
- // 刷新输出流
- os.flush();
- os.close();
-
- // 获取响应
- int responseCode = conn.getResponseCode();
- if (responseCode == HttpURLConnection.HTTP_OK) {
- BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
- StringBuilder response = new StringBuilder();
- String line;
- while ((line = br.readLine()) != null) {
- response.append(line);
- }
- br.close();
- // 处理响应数据
- // 将JSON字符串转换为JSONObject
- JSONObject data = new JSONObject(response.toString());
- // 从JSONObject中获取auth_url的值
- int errcode = (int)data.get("errcode");
- if(errcode!=0){
- errParams.put("errcode",1);
- errParams.put("errmsg","PDF文件上传失败");
- return errParams;
- }
- String sMediaId = data.getString("s_media_id");
- if(sMediaId==null || sMediaId==""){
- errParams.put("errcode",1);
- errParams.put("errmsg","PDF文件上传失败");
- return errParams;
- }
- errParams.put("errcode",0);
- errParams.put("sMediaId",sMediaId);
- return errParams;
- } else {
- // 处理错误
- errParams.put("errcode",1);
- errParams.put("errmsg","PDF文件上传失败");
- return errParams;
- }
- } catch (Exception e) {
- // TODO Auto-generated catch block
- errParams.put("errcode",1);
- return errParams;
- }
-
- }
PDF发票文件识别信息工具方法 使用的正则表达式
- public static JSONObject extractInvoiceNumber(File file) {
- JSONObject ObjectData = new JSONObject();
- try {
- // File file = new File("D:\\fp1.pdf");
- PDDocument document = PDDocument.load(file);
- PDFTextStripper pdfStripper = new PDFTextStripper();
- pdfStripper.setSortByPosition(true);
- String text = pdfStripper.getText(document);
-
- System.out.println(text);
- document.close();
-
- int fee = 0; //发票的金额,以分为单位
- String billingNo = ""; //发票号码
- String billingCode = ""; //发票代码
- int feeWithoutTax = 0;//不含税金额,以分为单位
- int tax = 0; //税额,以分为单位
- int billingTime = 0; //发票的开票时间,为10位时间戳(utc+8)
- String checkCode = ""; //校验码,发票pdf右上角,开票日期下的校验码;数电发票发票校验码为空
- String companyName = ""; //发票抬头
-
- Pattern pattern = Pattern.compile("发票号码:\\s*(\\d+)");
- Matcher matcher = pattern.matcher(text);
-
- List<String> companyList = new ArrayList<>();
- companyList.add("发票号码:\\s*(\\d+)");
- companyList.add("发票号码:(\\d+)");
- // 查找匹配的发票号码
- for (String patternName : companyList) {
- // 使用正则表达式进行匹配
- pattern = Pattern.compile(patternName);
- matcher = pattern.matcher(text);
- if (matcher.find()){
- billingNo = matcher.group(1);
- System.out.println("发票号码:"+billingNo);
- break;
- }
- }
- if (billingNo.equals("")){
- System.out.println("未找到发票抬头");
- }
-
- companyList.clear();
- companyList.add("购 名称:(.*?) ");
- companyList.add("名 称: (.*?)\\s");
- companyList.add(" 名 称: (.*?)\\s");
- companyList.add("买 名称:(.*?) ");
- // 查找匹配的发票抬头
- for (String patternName : companyList) {
- // 使用正则表达式进行匹配
- pattern = Pattern.compile(patternName);
- matcher = pattern.matcher(text);
- if (matcher.find()){
- companyName = matcher.group(1);
- System.out.println("提取的发票抬头为:" + companyName);
- break;
- }
- }
- if (companyName.equals("")){
- System.out.println("未找到发票抬头");
- }
-
- companyList.clear();
- companyList.add("(小写)¥(\\d+\\.\\d{2})");
- companyList.add(" \\(小写\\) ¥\\s*(\\d+\\.\\d{2})");
- companyList.add("(小写)¥\\s*(\\d+(\\.\\d+)?)");
- // 查找匹配的发票金额
- for (String patternName : companyList) {
- // 使用正则表达式进行匹配
- pattern = Pattern.compile(patternName);
- matcher = pattern.matcher(text);
- if (matcher.find()){
- String invoiceNumber = matcher.group(1);
- Double number = Double.parseDouble(invoiceNumber);
- number = number * 100;
- fee = (int) number.doubleValue();
- System.out.println("提取的发票金额为:" + fee);
- break;
- }
- }
- if (fee==0){
- System.out.println("未找到发票金额");
- }
-
-
- companyList.clear();
- companyList.add("合 计 ¥(\\d+\\.\\d{2})\\s*¥(\\d+\\.\\d{2})");
- companyList.add("合 计 ¥(\\d+\\.\\d{2})\\s*¥(\\d+\\.\\d{2})");
- companyList.add("合 计 ¥(\\d+\\.\\d{2})\\s*¥(\\d+\\.\\d{2})");
- // 查找匹配的不含税金额
- for (String patternName : companyList) {
- // 使用正则表达式进行匹配
- pattern = Pattern.compile(patternName);
- matcher = pattern.matcher(text);
- if (matcher.find()){
- String invoiceNumber = matcher.group(1);
- Double number = Double.parseDouble(invoiceNumber);
- number = number * 100;
- feeWithoutTax = (int) number.doubleValue();
- System.out.println("提取的不含税金额为:" + feeWithoutTax);
- break;
- }
- }
- if (feeWithoutTax==0){
- System.out.println("未找到不含税金额");
- }
-
-
- companyList.clear();
- companyList.add("合\\s*计\\s*¥\\d+(\\.\\d+)?\\s*¥(\\d+(\\.\\d+)?)");
- // 查找匹配的税金额
- for (String patternName : companyList) {
- // 使用正则表达式进行匹配
- pattern = Pattern.compile(patternName);
- matcher = pattern.matcher(text);
- if (matcher.find()){
- String invoiceNumber = matcher.group(2);
- Double number = Double.parseDouble(invoiceNumber);
- number = number * 100;
- tax = (int) number.doubleValue();
- System.out.println("提取的税金额为:" + tax);
- break;
- }
- }
- if (tax==0){
- System.out.println("未找到税金额");
- }
-
- if (text.contains("发票代码")) {
- companyList.clear();
- companyList.add("发票代码:\\s*(\\d+)");
- companyList.add("发票代码:(\\d+)");
- // 查找匹配的发票代码
- for (String patternName : companyList) {
- // 使用正则表达式进行匹配
- pattern = Pattern.compile(patternName);
- matcher = pattern.matcher(text);
- if (matcher.find()) {
- billingCode = matcher.group(1);
- System.out.println("提取的发票代码为:" + billingCode);
- break;
- }
- }
- if (billingCode.equals("")) {
- System.out.println("未找到发票代码");
- }
- }else{
- System.out.println("未找到发票代码");
- }
-
-
- companyList.clear();
- companyList.add("校 验 码:\\s*(\\d+(\\s+\\d+)*)");
- companyList.add("校 验 码:\\s*(\\d+(?:\\s+\\d+)*)");
- // 查找匹配的校 验 码
- for (String patternName : companyList) {
- // 使用正则表达式进行匹配
- pattern = Pattern.compile(patternName);
- matcher = pattern.matcher(text);
- if (matcher.find()) {
- checkCode = matcher.group(1);
- System.out.println("提取的校 验 码为:" + checkCode);
- break;
- }
- }
- if (checkCode.equals("")) {
- System.out.println("未找到校 验 码");
- }
-
- if (text.contains("开票日期")) {
- companyList.clear();
- companyList.add("开票日期:\\s*(\\d{4})\\s*年\\s*(\\d{1,2})\\s*月\\s*(\\d{1,2})\\s*日");
- companyList.add("开票日期:(\\d{4})年(\\d{1,2})月(\\d{1,2})日");
- // 查找匹配的校 验 码
- for (String patternName : companyList) {
- // 使用正则表达式进行匹配
- pattern = Pattern.compile(patternName);
- matcher = pattern.matcher(text);
- if (matcher.find()) {
- // 提取年份、月份和日期
- String year = matcher.group(1);
- String month = matcher.group(2);
- String day = matcher.group(3);
- // 组合成完整的日期字符串(如果需要特定格式,可以在这里进行格式化)
- String invoiceDate = year + "年" + month + "月" + day+"日";
- billingTime = format(invoiceDate);
- System.out.println("提取的开票日期为:" + invoiceDate);
- break;
- }
- }
- if (billingTime==0) {
- System.out.println("未找到开票日期");
- }
- }else{
- System.out.println("未找到开票日期");
- }
- ObjectData.put("errcode",0);
- ObjectData.put("fee",fee);
- ObjectData.put("billingNo",billingNo);
- ObjectData.put("billingCode",billingCode);
- ObjectData.put("feeWithoutTax",feeWithoutTax);
- ObjectData.put("tax",tax);
- ObjectData.put("billingTime",billingTime);
- ObjectData.put("checkCode",checkCode);
- ObjectData.put("companyName",companyName);
- return ObjectData;
- } catch (Exception e) {
- ObjectData.put("errcode",1);
- return ObjectData;
- }
- }
-
- //时间单位转换
- public static int format(String dateString) {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
- sdf.setTimeZone(TimeZone.getTimeZone("GMT+8")); // 设置时区为GMT+8
- try {
- Date date = sdf.parse(dateString);
- return (int) (date.getTime() / 1000); // 转换为以秒为单位的时间戳
- } catch (Exception e) {
- return 1;
- }
- }
请求方式
请求URL:https://api.weixin.qq.com/card/invoice/insert?access_token={access_token}
请求方法:POST
请求参数
请求参数使用JSON格式,字段如下:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
order_id | string | 是 | 发票order_id,既商户给用户授权开票的订单号 |
card_id | String | 是 | 发票card_id |
appid | String | 是 | 该订单号授权时使用的appid,一般为商户appid |
card_ext | Object | 是 | 发票具体内容 |
card_ext为Object,包括以下内容:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
nonce_str | String | 是 | 随机字符串,防止重复 |
user_card | Object | 是 | 用户信息结构体 |
user_card中包含一个invoice_user_data对象,invoice_user_data包含以下内容:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
fee | Int | 是 | 发票的金额,以分为单位 |
title | String | 是 | 发票的抬头 |
billing_time | Int | 是 | 发票的开票时间,为10位时间戳(utc+8) |
billing_no | String | 是 | 发票的发票号码;数电发票传20位发票号码 |
billing_code | String | 是 | 发票的发票代码;数电发票发票代码为空 |
info | List | 否 | 商品详情结构,见下方 |
fee_without_tax | Int | 是 | 不含税金额,以分为单位 |
tax | Int | 是 | 税额,以分为单位 |
s_pdf_media_id | String | 是 | 发票pdf文件上传到微信发票平台后,会生成一个发票s_media_id,该s_media_id可以直接用于关联发票PDF和发票卡券。发票上传参考“ 3 上传PDF ”一节 |
s_trip_pdf_media_id | String | 否 | 其它消费附件的PDF,如行程单、水单等,PDF上传方式参考“ 3 上传PDF ”一节 |
check_code | String | 是 | 校验码,发票pdf右上角,开票日期下的校验码;数电发票发票校验码为空 |
buyer_number | String | 否 | 购买方纳税人识别号 |
buyer_address_and_phone | String | 否 | 购买方地址、电话 |
buyer_bank_account | String | 否 | 购买方开户行及账号 |
seller_number | String | 否 | 销售方纳税人识别号 |
seller_address_and_phone | String | 否 | 销售方地址、电话 |
seller_bank_account | String | 否 | 销售方开户行及账号 |
remarks | String | 否 | 备注,发票右下角初 |
cashier | String | 否 | 收款人,发票左下角处 |
maker | String | 否 | 开票人,发票下方处 |
info为Object列表,列表中每个Object包含以下信息:
参数 | 类型 | 是否必填 | 描述 |
---|---|---|---|
name | String | 是 | 项目的名称 |
num | Int | 否 | 项目的数量 |
unit | String | 否 | 项目的单位,如个 |
price | Int | 是 | 项目的单价 |
- //将电子发票卡券插入用户卡包
- public static JSONObject pushCoupons(String invoiceName,String sMediaId,String accessToken,String orderId,File file,String cardId) {
- JSONObject errParams = new JSONObject();
- try{
- JSONObject objectData = extractInvoiceNumber(file);
-
- // String sMediaId = element.getChildText("s_media_id");
- //
- // String invoiceName=element.getChildText("invoice_name");
- String apiUrl = "https://api.weixin.qq.com/card/invoice/insert?access_token="+accessToken;
- JSONObject jsonParams = new JSONObject();
- JSONObject cardExt = new JSONObject();
- JSONObject userCard = new JSONObject();
- JSONObject invoiceUserData = new JSONObject();
- // List<Object> infoList = new ArrayList<Object>();
- // JSONObject info = new JSONObject();
- UUID uuid=UUID.randomUUID();
-
- invoiceUserData.put("fee", objectData.getInt("fee"));
- invoiceUserData.put("title", invoiceName);
- invoiceUserData.put("billing_time", objectData.getInt("billingTime"));
- invoiceUserData.put("billing_no", objectData.get("billingNo"));
- invoiceUserData.put("billing_code", objectData.get("billingCode"));
- invoiceUserData.put("fee_without_tax", objectData.getInt("feeWithoutTax"));
- invoiceUserData.put("tax", objectData.getInt("tax"));
- invoiceUserData.put("s_pdf_media_id", sMediaId);
- invoiceUserData.put("check_code", objectData.get("checkCode"));
-
- userCard.put("invoice_user_data", invoiceUserData);
- cardExt.put("nonce_str",uuid);
- cardExt.put("user_card", userCard);
-
- jsonParams.put("order_id", orderId);
- jsonParams.put("card_ext", cardExt);
- jsonParams.put("card_id", cardId); //模板id
- jsonParams.put("appid", "wxb92aeb7a8c2089e5");
-
- // 创建连接
- URL url = new URL(apiUrl);
- HttpURLConnection connection = (HttpURLConnection) url.openConnection();
- connection.setRequestMethod("POST");
- connection.setRequestProperty("Content-Type", "application/json; utf-8");
- connection.setRequestProperty("Accept", "application/json");
- connection.setDoOutput(true);
- // 写入请求数据
- try (OutputStream os = connection.getOutputStream()) {
- byte[] input = jsonParams.toString().getBytes("utf-8");
- os.write(input, 0, input.length);
- }
- // 读取响应
- try (BufferedReader br = new BufferedReader(
- new InputStreamReader(connection.getInputStream(), "utf-8"))) {
- StringBuilder response = new StringBuilder();
- String responseLine;
- while ((responseLine = br.readLine()) != null) {
- response.append(responseLine.trim());
- }
- // 将JSON字符串转换为JSONObject
- JSONObject data = new JSONObject(response.toString());
- connection.disconnect();
- return data;
-
- }
-
- }catch(Exception e){
- errParams.put("errcode",1);
- return errParams;
- }
-
- }
这样一套流程下来 就把发票插入到 对应的授权人的 微信卡包里啦
然后对应人公众号会收到一个收到发票的信息
创作不易 有问题可以留言
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。