From 99d8adfd0bfc284a523dece5fbc011beaa46f95c Mon Sep 17 00:00:00 2001 From: ieaii <1069385070@qq.com> Date: Sun, 19 Jan 2025 10:22:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=98=BF=E9=87=8C=E4=BA=91?= =?UTF-8?q?=E7=89=A9=E6=B5=81=E5=92=8C=E5=BE=AE=E4=BF=A1=E5=88=86=E8=B4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/system/HotelBalanceLogList2.vue | 258 +++++++++++++++++++++ apiclient_cert.p12 | Bin 0 -> 2774 bytes han-hai-module-pay/han-hai-module-pay.iml | 18 +- .../java/org/jeecg/modules/pay/MpWxPayService.java | 2 + .../jeecg-boot-base-api/jeecg-boot-base-api.iml | 34 ++- .../jeecg-system-cloud-api.iml | 39 +++- .../jeecg-system-local-api.iml | 38 ++- .../jeecg-boot-base-core/jeecg-boot-base-core.iml | 38 ++- jeecg-boot-base/jeecg-boot-base-core/pom.xml | 75 ++++++ .../org/jeecg/common/util/HttpRequestUtil.java | 192 +++++++++++++++ .../main/java/org/jeecg/common/util/MoneyUtil.java | 28 +++ .../org/jeecg/common/util/VechatPayV3Util.java | 122 ++++++++++ .../jeecg/common/util/pay/WeChatPayConfig2.java | 164 +++++++++++++ .../controller/HotelBalanceLogController.java | 187 ++++++++++++++- .../hotelbalancelog/entity/HotelBalanceLog.java | 4 + .../modules/hotelbalancelog/req/AuditReq.java | 21 ++ .../req/TransferBatchesDetailsRequest.java | 25 ++ .../req/TransferBatchesRequest.java | 43 ++++ .../hotelbalancelog/resp/TransferBatchesResp.java | 27 +++ .../jeecg-boot-module-system.iml | 50 ++-- .../modules/xcx/order/req/QueryLogisticsReq.java | 6 +- .../xcx/order/service/impl/OrderServiceImpl.java | 122 ++++++---- .../xcx/shop/service/impl/ShopServiceImpl.java | 3 + .../src/main/resources/application-dev.yml | 41 +++- .../src/main/resources/application-prod.yml | 45 +++- .../src/main/resources/application-test.yml | 52 ++++- pom.xml | 87 ++++++- 27 files changed, 1623 insertions(+), 98 deletions(-) create mode 100644 admin-hanhai-vue/src/views/system/HotelBalanceLogList2.vue create mode 100644 apiclient_cert.p12 create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/HttpRequestUtil.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MoneyUtil.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/VechatPayV3Util.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/pay/WeChatPayConfig2.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/AuditReq.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/TransferBatchesDetailsRequest.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/TransferBatchesRequest.java create mode 100644 jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/resp/TransferBatchesResp.java diff --git a/admin-hanhai-vue/src/views/system/HotelBalanceLogList2.vue b/admin-hanhai-vue/src/views/system/HotelBalanceLogList2.vue new file mode 100644 index 0000000..5e26a2c --- /dev/null +++ b/admin-hanhai-vue/src/views/system/HotelBalanceLogList2.vue @@ -0,0 +1,258 @@ + + + + \ No newline at end of file diff --git a/apiclient_cert.p12 b/apiclient_cert.p12 new file mode 100644 index 0000000000000000000000000000000000000000..81e5a63ec397d12f83d976f0f096774a5eed5932 GIT binary patch literal 2774 zcmY+^c{~%28wc>2ZP;Xqku`E8mShsS&5@%r+Y)k2HMe||kW!At=Bhc$Rr(SmS4567 z<;Z>I&X;nOBi9hN<@)))UccY(`}_Uzyq?$dd7jtv=Nm(T_5pc#F%;-?h`KZQ9yNRrVAG16WMl-7gjtz)7lZb2i@1K4Ur?rHbvR+A6k^1;8}RPlCRpG zamz`P3uyM#o|{+^A*wo;$k7MXc0ObeVnZq7wc-&eJIsyUd9QO8K&F96$@15q=t2}< z9k8g%s^CW2ZvH`J*_e?2<6gFOaAP=E;Hgd0p=U2GJjI{%;LOv&(p8Gpkb?UidgzpJ zWj{g*;tjPhwuX-{hY+%Pk9p5#FJ*#S<&fm7CgL*PVvqT3B)a(kNk7QZ1LS^)jqeM0 zO@sG(w6F#Kc$M+83`}lwq*TxJ4c73*#a-#y2BYKRI_UJL~cea1@yzqyo zSXy%NhA%Xa9A|N4@)vAkxi(&Vno!W3#^ixp;;cCQX#N^q|FB$b#p2uA#(ZVogTIfi z+yVRQ1YXuWqflJUCFg#YgE1>*XBskE<7;x)VMbuuFu3St8ca^Anp*pPal%%uCyj|?=``hg-vh1ka;?#qh!Eqw@1z|2~;BjYd~BjElq_i zp4E=L^fNb2_}!@VnhC~Ec}t6`p6DTdJ63rU<*KXO>GM8*CGJN*m+|%_osyS>)JX2_ zf?mGhp;FjSyUDhQJ-O$BR#xIix4U$sHj-E|E z$*u^*mpj)BvK$*FT@AjK;cehW?0ymiTsYdkr{*gMBV&Eb8~N>FwOI|pr$20IEoAvS z8FcGpce@I%whi?%w`z6mM5_RN5iyyvM%`ZlgkT%o(7o-BLaDCh=K$N~V4E0I3$upl z7c^P8fkD9VrSPdftW@n?c`Cm6?DItw8f=R!C1ee@0<5&^@Kx)9e&<^2U2|uA%PgV< zgjLFiS?Gdi^t{|l$I3#j9&G5=FfU$Fmav~qsrDqCv#D2UBF1js99bftL3iC{qE-DI z{LBv8 z2j9$dR#H0dF0GpREg~28Uc=qkZPYqIg=#-?l8En7iO%+-giW^g9ii9+YW(!vnr;y@ zjw#Afm-jshB%!qqWO}s;<}#jS3k!{|aie_a?AUL0Xii;u{8slv-OZf$XnF}E1Nh*CpW%Dt(YE<$2M^mW zHtKEMkqU*7-9RX9tLvyyKXg!KkFzc8`Z{CaOU;iFV^Q(4@C z$mFYYgs7!NiPccYEJND`NQQir|Drz55u<*GdI{MMV-Ah=M+b)pzSUPn#{D`_Z>-e{vtJr&J<8Y2wN_!{Dz^i{c2cMt_k-jAL4%K-xW4}VY| z;J%Z~`#{eBpNhPHtLQCaL*r>!&iY$L5Czm~Jk>a6uB3f%RTtx<@v5+D8+2tkrdMQJ?xW&WI#>7SHvsU7XCTI ztzvH!yvV%v;r28BlQj1DKIx5&Ed&wqvL4hY2 zk)CZX0FH!pSE5V^gAa23ksw4+GeFf#GG$Qo?p#+>=+|adJ@I3>p=4>8bOJ$PR-G7A z2Q-Tz{Z$MIbvm5q(tj7mf5CRp07oUXD;zNt-?lWj{-)DxE&K#IwJB9!;no-Ghiwp` zqH59)R8MzQa!GGFwi(atbK@Qowd4G%Ej)J31Sf9>cC3C#`aZ=~B@9kccE=~ZL+|@p z4~{;U>9D_iOE_q3PzIWPedJ_UI!p31r{d!F#rMdL4&SRb^Ki_kPxc}uFbNCX$gtd@JWmA_usvBZxn0|h@xH}s#<)lH4|w}b4O+u zxQ*vkbm|@U$W{^9*g8AzjwJ|M=8Cu3`o!mq(S{h*n*3QBhd>mF+j{eKyPrdw>f4|N z2Hzh~$EJjAWCobD+){1F+Q}{s5QB2IUORkHhhCbGPeyIj?831GHs@i`D;@ax1lQ>) zA=mfRYAK5Q5J(@x!hWXC-z`~x6*94UE(`%BQ&;nhq6S8g_0K>j3^&skmFC^$t5()! zWPiKx-=-t%As)}9rqR~fWCc|0HDEY@bN7JZH+ z4i*OKZR~p6i&D55)?;?`4awBI#c$J9$BTNw(=JzV-iZi~)n&I|!bVMnbOZV|NoJ+O zQqUuSyeV(5eJS=6US~k_0XW%4g_bty6gmg)EdjI36iOyJ0~y)3?*&-EK4zy@52@N? zIp076v^B&wNJS*$Ib29+Ruh^To;=mkujfL` Qt^@J=OwQT(i0Q`t3-8e*S^xk5 literal 0 HcmV?d00001 diff --git a/han-hai-module-pay/han-hai-module-pay.iml b/han-hai-module-pay/han-hai-module-pay.iml index 0e31347..7cbedd8 100644 --- a/han-hai-module-pay/han-hai-module-pay.iml +++ b/han-hai-module-pay/han-hai-module-pay.iml @@ -51,12 +51,12 @@ - + - + - + @@ -65,12 +65,12 @@ - - - + + + - + @@ -90,8 +90,8 @@ - - + + diff --git a/han-hai-module-pay/src/main/java/org/jeecg/modules/pay/MpWxPayService.java b/han-hai-module-pay/src/main/java/org/jeecg/modules/pay/MpWxPayService.java index 17cbf0a..cc87b3e 100644 --- a/han-hai-module-pay/src/main/java/org/jeecg/modules/pay/MpWxPayService.java +++ b/han-hai-module-pay/src/main/java/org/jeecg/modules/pay/MpWxPayService.java @@ -140,6 +140,8 @@ public class MpWxPayService { public Object createUserOrder(String productName, String clientIp, String productId, Integer price, String orderNo, String openId, String body){ + + WxPayUnifiedOrderRequest request = new WxPayUnifiedOrderRequest(); request.setDeviceInfo("WEB"); //设备号 request.setTradeType("JSAPI"); //交易类型 diff --git a/jeecg-boot-base/jeecg-boot-base-api/jeecg-boot-base-api.iml b/jeecg-boot-base/jeecg-boot-base-api/jeecg-boot-base-api.iml index 4e855fc..e79e1e2 100644 --- a/jeecg-boot-base/jeecg-boot-base-api/jeecg-boot-base-api.iml +++ b/jeecg-boot-base/jeecg-boot-base-api/jeecg-boot-base-api.iml @@ -28,8 +28,6 @@ - - @@ -137,7 +135,6 @@ - @@ -190,8 +187,6 @@ - - @@ -214,6 +209,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/jeecg-system-cloud-api.iml b/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/jeecg-system-cloud-api.iml index e6fcbcf..c0f9559 100644 --- a/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/jeecg-system-cloud-api.iml +++ b/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/jeecg-system-cloud-api.iml @@ -10,7 +10,9 @@ - + + + @@ -32,7 +34,6 @@ - @@ -65,8 +66,6 @@ - - @@ -170,7 +169,6 @@ - @@ -223,8 +221,6 @@ - - @@ -247,6 +243,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/jeecg-system-local-api.iml b/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/jeecg-system-local-api.iml index 1b52415..9f5a3c9 100644 --- a/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/jeecg-system-local-api.iml +++ b/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/jeecg-system-local-api.iml @@ -10,7 +10,9 @@ - + + + @@ -47,8 +49,6 @@ - - @@ -156,7 +156,6 @@ - @@ -209,8 +208,6 @@ - - @@ -233,6 +230,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jeecg-boot-base/jeecg-boot-base-core/jeecg-boot-base-core.iml b/jeecg-boot-base/jeecg-boot-base-core/jeecg-boot-base-core.iml index f1c7418..40a49b9 100644 --- a/jeecg-boot-base/jeecg-boot-base-core/jeecg-boot-base-core.iml +++ b/jeecg-boot-base/jeecg-boot-base-core/jeecg-boot-base-core.iml @@ -10,7 +10,9 @@ - + + + @@ -47,8 +49,6 @@ - - @@ -166,7 +166,6 @@ - @@ -219,8 +218,6 @@ - - @@ -243,6 +240,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jeecg-boot-base/jeecg-boot-base-core/pom.xml b/jeecg-boot-base/jeecg-boot-base-core/pom.xml index be7b740..f047b59 100644 --- a/jeecg-boot-base/jeecg-boot-base-core/pom.xml +++ b/jeecg-boot-base/jeecg-boot-base-core/pom.xml @@ -261,6 +261,81 @@ compile + + + com.squareup.retrofit2 + converter-simplexml + ${converter-simplexml.version} + + + + javax.ws.rs + javax.ws.rs-api + ${javax.ws.rs-api.version} + + + + org.glassfish.jersey.core + jersey-client + ${jersey-client.version} + + + + org.glassfish.jersey.connectors + jersey-apache-connector + ${jersey-apache-connector.version} + + + + org.bouncycastle + bcprov-jdk15on + ${bcprov-jdk15on.version} + + + + net.sf.json-lib + json-lib + ${json-lib.version} + jdk15 + + + + com.squareup.okhttp3 + logging-interceptor + ${logging-interceptor.version} + + + + + com.github.wechatpay-apiv3 + wechatpay-apache-httpclient + ${wechatpay-apache-httpclientd.version} + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + + commons-httpclient + commons-httpclient + ${commons-httpclient.version} + + + + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + + org.apache.httpcomponents + httpmime + ${httpmime.version} + + diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/HttpRequestUtil.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/HttpRequestUtil.java new file mode 100644 index 0000000..096d5d5 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/HttpRequestUtil.java @@ -0,0 +1,192 @@ +package org.jeecg.common.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.ParseException; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.net.URLDecoder; + +/** + * Created by null on 2017/2/23. + */ +@Slf4j +public class HttpRequestUtil { + + private static Logger logger = LoggerFactory.getLogger(HttpRequestUtil.class); //日志记录 + + /** + * post请求 + * @param url url地址 + * @param jsonParam 参数 + * @return + */ + public static String post(String url,String jsonParam){ + //post请求返回结果 + DefaultHttpClient httpClient = new DefaultHttpClient(); + String jsonResult = null; + HttpPost method = new HttpPost(url); + try { + if (null != jsonParam) { + //解决中文乱码问题 + StringEntity entity = new StringEntity(jsonParam.toString(), "utf-8"); + entity.setContentEncoding("UTF-8"); + entity.setContentType("application/json"); + method.setEntity(entity); + } + HttpResponse result = httpClient.execute(method); + url = URLDecoder.decode(url, "UTF-8"); + /**请求发送成功,并得到响应**/ + if (result.getStatusLine().getStatusCode() == 200) { + String str = ""; + try { + /**读取服务器返回过来的json字符串数据**/ + str = EntityUtils.toString(result.getEntity()); + return str; + /**把json字符串转换成json对象**/ +// jsonResult = JSONObject.fromObject(str); + } catch (Exception e) { + logger.error("post请求提交失败:" + url, e); + } + } + } catch (IOException e) { + logger.error("post请求提交失败:" + url, e); + } + return jsonResult; + } + + /** + * 发送get请求 + * @param url 路径 + * @return + */ + public static String get(String url){ + String responseString = null; + try { + DefaultHttpClient client = new DefaultHttpClient(); + //发送get请求 + HttpGet request = new HttpGet(url); + HttpResponse response = client.execute(request); + + /**请求发送成功,并得到响应**/ + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + /**读取服务器返回过来的json字符串数据**/ + return EntityUtils.toString(response.getEntity()); + /**把json字符串转换成json对象**/ + } else { + logger.error("get请求提交失败:" + url); + } + } catch (IOException e) { + logger.error("get请求提交失败:" + url, e); + } + return responseString; + } + + + /** + * 发起批量转账API 批量转账到零钱 + * + * @param requestUrl + * @param requestJson 组合参数 + * @param wechatPayserialNo 商户证书序列号 + * @param mchID4M 商户号 + * @param privatekeypath 商户私钥证书路径 + * @return + */ + public static String postTransBatRequest( + String requestUrl, + String requestJson, + String wechatPayserialNo, + String wechatPayserialNo2, + String mchID4M, + String privatekeypath) { + CloseableHttpClient httpclient = HttpClients.createDefault(); + CloseableHttpResponse response = null; + HttpEntity entity = null; + try { + //商户私钥证书 + HttpPost httpPost = new HttpPost(requestUrl); + // NOTE: 建议指定charset=utf-8。低于4.4.6版本的HttpCore,不能正确的设置字符集,可能导致签名错误 + httpPost.addHeader("Content-Type", "application/json"); + httpPost.addHeader("Accept", "application/json"); + //"55E551E614BAA5A3EA38AE03849A76D8C7DA735A"); + httpPost.addHeader("Wechatpay-Serial", wechatPayserialNo); + //-------------------------核心认证 start----------------------------------------------------------------- + String strToken = VechatPayV3Util.getToken("POST", + "/v3/fund-app/mch-transfer/transfer-bills", + requestJson,mchID4M,wechatPayserialNo2, privatekeypath); + + log.error("微信转账token "+strToken); + // 添加认证信息 + httpPost.addHeader("Authorization", + "WECHATPAY2-SHA256-RSA2048" + " " + + strToken); + //---------------------------核心认证 end--------------------------------------------------------------- + httpPost.setEntity(new StringEntity(requestJson, "UTF-8")); + //发起转账请求 + response = httpclient.execute(httpPost); + entity = response.getEntity();//获取返回的数据 + log.info("-----getHeaders.Request-ID:"+response.getHeaders("Request-ID")); + return EntityUtils.toString(entity,"UTF-8"); + } catch (Exception e) { + e.printStackTrace(); + } finally { + // 关闭流 + } + return null; + } + + + /** + * 发送HTTP_GET请求 + * + * @see 该方法会自动关闭连接,释放资源 + * @param reqURL + * 请求地址(含参数) + * @param decodeCharset + * 解码字符集,解析响应数据时用之,其为null时默认采用UTF-8解码 + * @return 远程主机响应正文 + */ + public static String sendGetRequest(String reqURL,String auth,String decodeCharset) { + long responseLength = 0; // 响应长度 + String responseContent = null; // 响应内容 + CloseableHttpClient httpclient = HttpClients.createDefault(); + + HttpGet httpGet = new HttpGet(reqURL); // 创建org.apache.http.client.methods.HttpGet + httpGet.addHeader("Authorization", auth); + httpGet.addHeader("Accept", "application/json"); + httpGet.addHeader("User-Agent", "https://zh.wikipedia.org/wiki/User_agent"); + try { + HttpResponse response = httpclient.execute(httpGet); // 执行GET请求 + HttpEntity entity = response.getEntity(); // 获取响应实体 + if (null != entity) { + responseLength = entity.getContentLength(); + responseContent = EntityUtils.toString(entity, decodeCharset == null ? "UTF-8" : decodeCharset); + EntityUtils.consume(entity); // Consume response content + } + } catch (ClientProtocolException e) { + System.out.println("该异常通常是协议错误导致,比如构造HttpGet对象时传入的协议不对(将'http'写成'htp')或者服务器端返回的内容不符合HTTP协议要求等,堆栈信息如下"); + } catch (ParseException e) { + System.out.println(e.getMessage()); + } catch (IOException e) { + System.out.println("该异常通常是网络原因引起的,如HTTP服务器未启动等,堆栈信息如下"); + } finally { + httpclient.getConnectionManager().shutdown(); // 关闭连接,释放资源 + } + return responseContent; + } + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MoneyUtil.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MoneyUtil.java new file mode 100644 index 0000000..4bc487a --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MoneyUtil.java @@ -0,0 +1,28 @@ +package org.jeecg.common.util; + +import java.math.BigDecimal; + +/** + * Created by 廖师兄 + * 2017-07-02 13:53 + */ +public class MoneyUtil { + + /** + * 元转分 + * @param yuan + * @return + */ + public static Integer Yuan2Fen(Double yuan) { + return new BigDecimal(String.valueOf(yuan)).movePointRight(2).intValue(); + } + + /** + * 分转元 + * @param fen + * @return + */ + public static Double Fen2Yuan(Integer fen) { + return new BigDecimal(fen).movePointLeft(2).doubleValue(); + } +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/VechatPayV3Util.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/VechatPayV3Util.java new file mode 100644 index 0000000..ba25b55 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/VechatPayV3Util.java @@ -0,0 +1,122 @@ +package org.jeecg.common.util; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.springframework.util.StringUtils; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Random; + +/** + * @author java996.icu + * @title: VechatPayV3Util + * @projectName chemu + * @description: TODO + * @date 2022/12/8 15:00 + * @Version V1.0 + */ +@Slf4j +public class VechatPayV3Util { + + /** + * + * @param method 请求方法 post + * @param canonicalUrl 请求地址 + * @param body 请求参数 + * @param merchantId 这里用的商户号 + * @param certSerialNo 商户证书序列号 + * @param keyPath 商户证书地址 + * @return + * @throws Exception + */ + public static String getToken( + String method, + String canonicalUrl, + String body, + String merchantId, + String certSerialNo, + String keyPath) throws Exception { + String signStr = ""; + //获取32位随机字符串 + String nonceStr = getRandomString(32); + //当前系统运行时间 + long timestamp = System.currentTimeMillis() / 1000; + if (StringUtils.isEmpty(body)) { + body = ""; + } + //签名操作 + String message = buildMessage(method, canonicalUrl, timestamp, nonceStr, body); + //签名操作 + String signature = sign(message.getBytes("utf-8"), keyPath); + //组装参数 + signStr = "mchid=\"" + merchantId + "\",timestamp=\"" + timestamp+ "\",nonce_str=\"" + nonceStr + + "\",serial_no=\"" + certSerialNo + "\",signature=\"" + signature + "\""; + + return signStr; + } + + public static String buildMessage(String method, String canonicalUrl, long timestamp, String nonceStr, String body) { +// String canonicalUrl = url.encodedPath(); +// if (url.encodedQuery() != null) { +// canonicalUrl += "?" + url.encodedQuery(); +// } + return method + "\n" + canonicalUrl + "\n" + timestamp + "\n" + nonceStr + "\n" + body + "\n"; + } + + public static String sign(byte[] message, String keyPath) throws Exception { + Signature sign = Signature.getInstance("SHA256withRSA"); + sign.initSign(getPrivateKey(keyPath)); + sign.update(message); + return Base64.encodeBase64String(sign.sign()); + } + + /** + * 微信支付-前端唤起支付参数-获取商户私钥 + * + * @param filename 私钥文件路径 (required) + * @return 私钥对象 + */ + public static PrivateKey getPrivateKey(String filename) throws IOException { + + log.error("签名 证书地址是 "+filename); + String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8"); + try { + String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replaceAll("\\s+", ""); + //System.out.println("--------privateKey---------:"+privateKey); + KeyFactory kf = KeyFactory.getInstance("RSA"); + return kf.generatePrivate( + new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey))); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("当前Java环境不支持RSA", e); + } catch (InvalidKeySpecException e) { + throw new RuntimeException("无效的密钥格式"); + } + } + /** + * 获取随机位数的字符串 + * @param length + * @return + */ + public static String getRandomString(int length) { + String base = "abcdefghijklmnopqrstuvwxyz0123456789"; + Random random = new Random(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < length; i++) { + int number = random.nextInt(base.length()); + sb.append(base.charAt(number)); + } + return sb.toString(); + } + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/pay/WeChatPayConfig2.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/pay/WeChatPayConfig2.java new file mode 100644 index 0000000..e21d73d --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/pay/WeChatPayConfig2.java @@ -0,0 +1,164 @@ +package org.jeecg.common.util.pay; + +import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder; +import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; +import com.wechat.pay.contrib.apache.httpclient.auth.Verifier; +import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; +import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator; +import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager; +import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException; +import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException; +import com.wechat.pay.contrib.apache.httpclient.util.PemUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.impl.client.CloseableHttpClient; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.PrivateKey; + +/** + * @author java996.icu + * @title: WeChatPayConfig2 + * @projectName chemu + * @description: TODO + * @date 2022/12/7 16:36 + * @Version V1.0 + */ +@Component +@Data +@Slf4j +@ConfigurationProperties(prefix = "wxpay") +public class WeChatPayConfig2 { + + /** + * 应用编号 + */ + private String appId; + /** + * 商户号 + */ + private String mchId; + /** + * 服务商商户号 + */ + private String slMchId; + /** + * APIv2密钥 + */ + private String apiKey; + /** + * APIv3密钥 + */ + private String apiV3Key; + /** + * 支付通知回调地址 + */ + private String notifyUrl; + /** + * 退款回调地址 + */ + private String refundNotifyUrl; + + /** + * API 证书中的 key.pem + */ + private String keyPemPath; + + /** + * 商户序列号 + */ + private String serialNo; + + /** + * 微信支付V3-url前缀 + */ + private String baseUrl; + + + /** + * 获取商户的私钥文件 + * @param keyPemPath + * @return + */ + public PrivateKey getPrivateKey(String keyPemPath){ + + InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(keyPemPath); + if(inputStream==null){ + throw new RuntimeException("私钥文件不存在"); + } + return PemUtil.loadPrivateKey(inputStream); + } + + /** + * 获取证书管理器实例 + * @return + */ + @Bean + public Verifier getVerifier() throws GeneralSecurityException, IOException, HttpCodeException, NotFoundException { + + log.info("获取证书管理器实例"); + + //获取商户私钥 + PrivateKey privateKey = getPrivateKey(keyPemPath); + + //私钥签名对象 + PrivateKeySigner privateKeySigner = new PrivateKeySigner(serialNo, privateKey); + + //身份认证对象 + WechatPay2Credentials wechatPay2Credentials = new WechatPay2Credentials(mchId, privateKeySigner); + + // 使用定时更新的签名验证器,不需要传入证书 + CertificatesManager certificatesManager = CertificatesManager.getInstance(); + certificatesManager.putMerchant(mchId,wechatPay2Credentials,apiV3Key.getBytes(StandardCharsets.UTF_8)); + + return certificatesManager.getVerifier(mchId); + } + + + /** + * 获取支付http请求对象 + * @param verifier + * @return + */ + @Bean(name = "wxPayClient") + public CloseableHttpClient getWxPayClient(Verifier verifier) { + + //获取商户私钥 + PrivateKey privateKey = getPrivateKey(keyPemPath); + + WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() + .withMerchant(mchId, serialNo, privateKey) + .withValidator(new WechatPay2Validator(verifier)); + + // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新 + return builder.build(); + } + + /** + * 获取HttpClient,无需进行应答签名验证,跳过验签的流程 + */ + @Bean(name = "wxPayNoSignClient") + public CloseableHttpClient getWxPayNoSignClient(){ + + //获取商户私钥 + PrivateKey privateKey = getPrivateKey(keyPemPath); + + //用于构造HttpClient + WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create() + //设置商户信息 + .withMerchant(mchId, serialNo, privateKey) + //无需进行签名验证、通过withValidator((response) -> true)实现 + .withValidator((response) -> true); + + // 通过WechatPayHttpClientBuilder构造的HttpClient,会自动的处理签名和验签,并进行证书自动更新 + return builder.build(); + } + + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/controller/HotelBalanceLogController.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/controller/HotelBalanceLogController.java index 7dde92e..6453feb 100644 --- a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/controller/HotelBalanceLogController.java +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/controller/HotelBalanceLogController.java @@ -1,5 +1,8 @@ package org.jeecg.modules.hotelbalancelog.controller; +import java.math.BigDecimal; +import java.security.cert.X509Certificate; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -7,12 +10,29 @@ import java.util.stream.Collectors; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import com.wechat.pay.contrib.apache.httpclient.util.RsaCryptoUtil; +import org.apache.commons.lang.StringUtils; import org.jeecg.common.api.vo.Result; +import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.system.query.QueryGenerator; +import org.jeecg.common.util.HttpRequestUtil; +import org.jeecg.common.util.MoneyUtil; +import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.oConvertUtils; +import org.jeecg.common.util.pay.WeChatPayConfig2; +import org.jeecg.modules.hanHaiMember.entity.HanHaiMember; +import org.jeecg.modules.hanHaiMember.service.IHanHaiMemberService; import org.jeecg.modules.hotelbalancelog.entity.HotelBalanceLog; +import org.jeecg.modules.hotelbalancelog.req.AuditReq; +import org.jeecg.modules.hotelbalancelog.req.TransferBatchesDetailsRequest; +import org.jeecg.modules.hotelbalancelog.req.TransferBatchesRequest; +import org.jeecg.modules.hotelbalancelog.resp.TransferBatchesResp; import org.jeecg.modules.hotelbalancelog.service.IHotelBalanceLogService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -20,6 +40,8 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; +import org.jeecg.modules.hotelmemberaccount.entity.HotelMemberAccount; +import org.jeecg.modules.hotelmemberaccount.service.IHotelMemberAccountService; import org.jeecgframework.poi.excel.ExcelImportUtil; import org.jeecgframework.poi.excel.def.NormalExcelConstants; import org.jeecgframework.poi.excel.entity.ExportParams; @@ -27,6 +49,8 @@ import org.jeecgframework.poi.excel.entity.ImportParams; import org.jeecgframework.poi.excel.view.JeecgEntityExcelView; import org.jeecg.common.system.base.controller.JeecgController; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; @@ -49,7 +73,25 @@ import org.jeecg.common.aspect.annotation.AutoLog; public class HotelBalanceLogController extends JeecgController { @Autowired private IHotelBalanceLogService hotelBalanceLogService; - + @Resource + private RedisUtil redisUtil; + @Resource + private IHanHaiMemberService hanHaiMemberService; + @Resource + private IHotelMemberAccountService hotelMemberAccountService; + @Value("${weixin.mpAppId}") + private String appId; + @Value("${wechat.transferBatchUrl}") + private String transferBatchUrl; + @Value("${wechat.keyPemPath}") + private String pemPath; + @Value("${weixin.mchId}") + private String mchId; + @Value("${weixin.serialNo}") + private String wxsSerialNo; + @Resource + private WeChatPayConfig2 weChatPayConfig2; + /** * 分页列表查询 * @@ -71,7 +113,31 @@ public class HotelBalanceLogController extends JeecgController pageList = hotelBalanceLogService.page(page, queryWrapper); return Result.OK(pageList); } - + + + /** + * 分页列表查询 + * + * @param hotelBalanceLog + * @param pageNo + * @param pageSize + * @param req + * @return + */ + //@AutoLog(value = "hotel_balance_log-分页列表查询") + @ApiOperation(value="hotel_balance_log-分页列表查询", notes="hotel_balance_log-分页列表查询") + @GetMapping(value = "/list2") + public Result> queryPageList2(HotelBalanceLog hotelBalanceLog, + @RequestParam(name="pageNo", defaultValue="1") Integer pageNo, + @RequestParam(name="pageSize", defaultValue="10") Integer pageSize, + HttpServletRequest req) { + QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(hotelBalanceLog, req.getParameterMap()); + queryWrapper.eq("type",1); + Page page = new Page(pageNo, pageSize); + IPage pageList = hotelBalanceLogService.page(page, queryWrapper); + return Result.OK(pageList); + } + /** * 添加 * @@ -85,7 +151,7 @@ public class HotelBalanceLogController extends JeecgController audit(@RequestBody AuditReq auditReq){ + HotelBalanceLog hotelBalanceLog = hotelBalanceLogService.getById(auditReq.getId()); + + HotelBalanceLog hotelBalanceLog1 = new HotelBalanceLog(); + hotelBalanceLog1.setId(hotelBalanceLog.getId()); + hotelBalanceLog1.setStatus(1); + if(auditReq.getAudit() == 1){ + HotelMemberAccount hotelMemberAccount = hotelMemberAccountService.lambdaQuery() + .eq(HotelMemberAccount::getUserId, hotelBalanceLog.getUserId()) + .one(); + + BigDecimal bigDecimal = hotelMemberAccount.getShopBalance().add(hotelBalanceLog.getBalance()); + + HotelMemberAccount hotelMemberAccount1 = new HotelMemberAccount(); + hotelMemberAccount1.setId(hotelMemberAccount.getId()); + hotelMemberAccount1.setShopBalance(bigDecimal); + hotelMemberAccountService.updateById(hotelMemberAccount1); + hotelBalanceLog1.setStatus(3); + + + } + + + + hotelBalanceLogService.updateById(hotelBalanceLog1); + + return Result.OK(); + } + + /** + * 提现 + * @param + * @return + */ + @PostMapping("/withdrawal") + public Result withdrawal(@RequestBody AuditReq auditReq) { + + + Integer n = (Integer) redisUtil.get("WITHDRAWAL:" + auditReq.getId()); + if (n != null) { + throw new JeecgBootException("请勿重复点击,后果自负!"); + } + redisUtil.set("WITHDRAWAL:" + auditReq.getId(), 1, 5); + + HotelBalanceLog hotelBalanceLog = hotelBalanceLogService.getById(auditReq.getId()); + + HanHaiMember hanHaiMember = hanHaiMemberService.lambdaQuery() + .eq(HanHaiMember::getId, hotelBalanceLog.getUserId()) + .one(); + + HotelMemberAccount hotelMemberAccount = hotelMemberAccountService.lambdaQuery() + .eq(HotelMemberAccount::getUserId, hanHaiMember.getId()) + .one(); + + //微信-商家转账到零钱 + + String idStr = "H" + IdWorker.getIdStr(); + TransferBatchesRequest transferBatchesRequest = new TransferBatchesRequest(); + + transferBatchesRequest.setAppid(appId); + transferBatchesRequest.setOutBillNo(idStr); + transferBatchesRequest.setTransferRemark("商家提现"); + transferBatchesRequest.setOpenid(hanHaiMember.getAppletOpenid()); + transferBatchesRequest.setTransferSceneId("1000"); + String serialNo = null; + try { + X509Certificate certificate = weChatPayConfig2.getVerifier().getValidCertificate(); + serialNo = certificate.getSerialNumber().toString(16).toUpperCase(); + String encryptOAEP = RsaCryptoUtil.encryptOAEP(hotelBalanceLog.getName(), certificate); + transferBatchesRequest.setUserName(encryptOAEP); + } catch (Exception e) { + log.info("真实姓名加密失败"); + e.printStackTrace(); + throw new JeecgBootException("真实姓名加密失败"); + } + transferBatchesRequest.setTransferAmount(MoneyUtil.Yuan2Fen(hotelBalanceLog.getBalance().doubleValue())); + List transferBatchesDetailsRequests = new ArrayList<>(); + TransferBatchesDetailsRequest transferBatchesDetailsRequest = new TransferBatchesDetailsRequest(); + transferBatchesDetailsRequest.setInfoType("1000-现金营销"); + transferBatchesDetailsRequest.setInfoContent("商品返利"); + + + + transferBatchesDetailsRequests.add(transferBatchesDetailsRequest); + transferBatchesRequest.setTransferDetailList(transferBatchesDetailsRequests); + String jsonString = JSONObject.toJSONString(transferBatchesRequest); + + + String postTransBatRequest = HttpRequestUtil.postTransBatRequest(transferBatchUrl, jsonString, serialNo, wxsSerialNo, mchId, pemPath); + log.error("返回结果1:" + postTransBatRequest); + TransferBatchesResp transferBatchesResp = JSON.parseObject(postTransBatRequest, TransferBatchesResp.class); + log.error("返回结果2:" + transferBatchesResp); + if (transferBatchesResp == null || org.apache.commons.lang3.StringUtils.isBlank(transferBatchesResp.getBatchId())) { + throw new JeecgBootException("打款失败"); + } + + HotelBalanceLog hotelBalanceLog1 = new HotelBalanceLog(); + hotelBalanceLog1.setId(hotelBalanceLog.getId()); + hotelBalanceLog1.setStatus(2); + hotelBalanceLog1.setOutBatchNo(transferBatchesResp.getOutBatchNo()); + hotelBalanceLog1.setBatchId(transferBatchesResp.getBatchId()); + hotelBalanceLogService.updateById(hotelBalanceLog1); + + return Result.OK(); + } + } diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/entity/HotelBalanceLog.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/entity/HotelBalanceLog.java index 010bc52..3a639c3 100644 --- a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/entity/HotelBalanceLog.java +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/entity/HotelBalanceLog.java @@ -90,4 +90,8 @@ public class HotelBalanceLog implements Serializable { private BigDecimal platformServicePrice; /**订单Id*/ private String orderId; + /**商家批次单号*/ + private String outBatchNo; + /**微信批次单号*/ + private String batchId; } diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/AuditReq.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/AuditReq.java new file mode 100644 index 0000000..1fc3d96 --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/AuditReq.java @@ -0,0 +1,21 @@ +package org.jeecg.modules.hotelbalancelog.req; + +import lombok.Data; + +/** + * @author java996.icu + * @title: AuditReq + * @projectName hanhai-object-jdbc-20240829 + * @description: TODO + * @date 2025/1/16 22:49 + * @Version V1.0 + */ +@Data +public class AuditReq { + + /**id*/ + private String id; + /**0审核通过 1审核不通过*/ + private Integer audit; + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/TransferBatchesDetailsRequest.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/TransferBatchesDetailsRequest.java new file mode 100644 index 0000000..7cadccb --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/TransferBatchesDetailsRequest.java @@ -0,0 +1,25 @@ +package org.jeecg.modules.hotelbalancelog.req; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +/** + * @author java996.icu + * @title: TransferBatchesDetailsRequest + * @projectName merchant + * @description: TODO + * @date 2022/10/10 15:45 + * @Version V1.0 + */ +@Data +public class TransferBatchesDetailsRequest { + + /**转账场景为1000-现金营销,需填入活动名称、奖励说明*/ + @JSONField(name = "info_type") + private String infoType; + /**信息类型为活动名称,请在信息内容描述用户参与活动的名称,如新会员有礼 + 信息类型为奖励说明,请在信息内容描述用户因为什么奖励获取这笔资金,如注册会员抽奖一等奖*/ + @JSONField(name = "info_content") + private String infoContent; + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/TransferBatchesRequest.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/TransferBatchesRequest.java new file mode 100644 index 0000000..eb293be --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/req/TransferBatchesRequest.java @@ -0,0 +1,43 @@ +package org.jeecg.modules.hotelbalancelog.req; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +import javax.crypto.Mac; +import java.util.List; + +/** + * @author java996.icu + * @title: TransferBatchesRequest + * @projectName merchant + * @description: TODO + * @date 2022/10/10 15:32 + * @Version V1.0 + */ +@Data +public class TransferBatchesRequest { + + /**直连商户的appid*/ + private String appid; + /**商家批次单号*/ + @JSONField(name = "out_bill_no") + private String outBillNo; + /**批次备注*/ + @JSONField(name = "transfer_remark") + private String transferRemark; + /**转账总金额*/ + @JSONField(name = "transfer_amount") + private Integer transferAmount; + /**转账场景*/ + @JSONField(name = "transfer_scene_id") + private String transferSceneId; + @JSONField(name = "openid") + private String openid; + /**真实姓名*/ + @JSONField(name = "user_name") + private String userName; + /**发起批量转账的明细列表,最多三千笔*/ + @JSONField(name = "transfer_scene_report_infos") + private List transferDetailList; + +} diff --git a/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/resp/TransferBatchesResp.java b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/resp/TransferBatchesResp.java new file mode 100644 index 0000000..6a240fa --- /dev/null +++ b/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/modules/hotelbalancelog/resp/TransferBatchesResp.java @@ -0,0 +1,27 @@ +package org.jeecg.modules.hotelbalancelog.resp; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +/** + * @author java996.icu + * @title: TransferBatchesResp + * @projectName merchant + * @description: TODO + * @date 2022/12/13 14:29 + * @Version V1.0 + */ +@Data +public class TransferBatchesResp { + + /**微信批次单号*/ + @JSONField(name = "batch_id") + private String batchId; + /**商家批次单号*/ + @JSONField(name = "out_batch_no") + private String outBatchNo; + /**批次创建时间*/ + @JSONField(name = "create_time") + private String createTime; + +} diff --git a/jeecg-boot-module-system/jeecg-boot-module-system.iml b/jeecg-boot-module-system/jeecg-boot-module-system.iml index 025d9df..80cfd4c 100644 --- a/jeecg-boot-module-system/jeecg-boot-module-system.iml +++ b/jeecg-boot-module-system/jeecg-boot-module-system.iml @@ -14,7 +14,9 @@ - + + + @@ -171,13 +173,32 @@ + + + + + + + + + + + + + + + + + + + + - - - + + @@ -224,7 +245,6 @@ - @@ -244,9 +264,10 @@ - + + - + @@ -280,9 +301,9 @@ - - - + + + @@ -294,9 +315,12 @@ - - - + + + + + + diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/order/req/QueryLogisticsReq.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/order/req/QueryLogisticsReq.java index 1c271a0..f4bef65 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/order/req/QueryLogisticsReq.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/order/req/QueryLogisticsReq.java @@ -1,5 +1,6 @@ package org.jeecg.modules.xcx.order.req; +import io.swagger.annotations.ApiModelProperty; import lombok.Data; @Data @@ -7,7 +8,10 @@ public class QueryLogisticsReq { private String token; - private String id; + /**物流单号*/ + @ApiModelProperty(value = "物流单号") + private String no; + } diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/order/service/impl/OrderServiceImpl.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/order/service/impl/OrderServiceImpl.java index 881e7f9..117dda8 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/order/service/impl/OrderServiceImpl.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/order/service/impl/OrderServiceImpl.java @@ -8,18 +8,8 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.cainiao.link.consumer.LinkClient; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.constant.WxPayErrorCode; -import com.taobao.pac.sdk.cp.dataobject.request.GUOGUO_QUERY_LOGISTICS_DETAIL.GuoguoQueryLogisticsDetailRequest; -import com.taobao.pac.sdk.cp.dataobject.request.GUOGUO_QUERY_LOGISTICS_DETAIL.LogisticsDetailOption; -import com.taobao.pac.sdk.cp.dataobject.request.GUOGUO_QUERY_LOGISTICS_DETAIL.LogisticsDetailRequest; -import com.taobao.pac.sdk.cp.dataobject.request.GUOGUO_QUERY_SEND_ORDER_FULL_DETAIL.AccessOption; -import com.taobao.pac.sdk.cp.dataobject.request.GUOGUO_QUERY_SEND_ORDER_FULL_DETAIL.GuoguoCancelSendOrderRequest; -import com.taobao.pac.sdk.cp.dataobject.request.GUOGUO_QUERY_SEND_ORDER_FULL_DETAIL.QueryOrderConditionDTO; -import com.taobao.pac.sdk.cp.dataobject.response.GUOGUO_QUERY_LOGISTICS_DETAIL.GuoguoQueryLogisticsDetailResponse; -import com.taobao.pac.sdk.cp.dataobject.response.GUOGUO_QUERY_SEND_ORDER_FULL_DETAIL.GuoguoCreateSendOrderResponse; -import com.taobao.pac.sdk.cp.dataobject.response.GUOGUO_QUERY_SEND_ORDER_FULL_DETAIL.LogisticsDetailDTO; import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier; import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner; import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials; @@ -89,13 +79,14 @@ import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; -import java.io.ByteArrayInputStream; +import java.io.*; import java.math.BigDecimal; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.UnknownHostException; import java.security.PrivateKey; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; @Slf4j @@ -138,14 +129,12 @@ public class OrderServiceImpl implements IOrderService { private String serialNo; @Value("${weixin.apiV3Key}") private String apiV3Key; - @Value("${cainiao.appKey}") + @Value("${aliyun.kuaidi.appKey}") private String appKey; - @Value("${cainiao.appSecret}") + @Value("${aliyun.kuaidi.appSecret}") private String appSecret; - @Value("${cainiao.accountId}") - private String accountId; - @Value("${cainiao.accessCode}") - private String accessCode; + @Value("${aliyun.kuaidi.appCode}") + private String appCode; @Resource private IHotelOrderLogService hotelOrderLogService; @Resource @@ -3184,10 +3173,10 @@ public class OrderServiceImpl implements IOrderService { BigDecimal price = hotelMemberAccount.getShopBalance().add(shopPrice); -// HotelMemberAccount hotelMemberAccount1 = new HotelMemberAccount(); -// hotelMemberAccount1.setId(hotelMemberAccount.getId()); -// hotelMemberAccount1.setShopBalance(price); -// hotelMemberAccountService.updateById(hotelMemberAccount1); + HotelMemberAccount hotelMemberAccount1 = new HotelMemberAccount(); + hotelMemberAccount1.setId(hotelMemberAccount.getId()); + hotelMemberAccount1.setShopBalance(price); + hotelMemberAccountService.updateById(hotelMemberAccount1); @@ -3208,6 +3197,7 @@ public class OrderServiceImpl implements IOrderService { hotelOrderService.updateById(hotelOrder1); + /* //微信分账代码 // 初始化商户配置 Config config = @@ -3237,6 +3227,7 @@ public class OrderServiceImpl implements IOrderService { createOrderRequest.setReceivers(createOrderReceivers); profitsharingService.createOrder(createOrderRequest); + */ for (HotelOrderDetail hotelOrderDetail:hotelOrderDetails){ //子 @@ -3791,23 +3782,76 @@ public class OrderServiceImpl implements IOrderService { @Override public Result queryLogistics(QueryLogisticsReq queryLogisticsReq) { - //通过 LinkClient Builder 构造一个 LinkClient - com.cainiao.link.consumer.LinkClient linkClient = LinkClient.builder(appKey, appSecret).build(); - - GuoguoQueryLogisticsDetailRequest request = new GuoguoQueryLogisticsDetailRequest(); + HanHaiMember hanHaiMember = shiroRealm.checkUserTokenIsEffectHanHaiAccount(queryLogisticsReq.getToken()); + + if(StringUtils.isBlank(queryLogisticsReq.getNo())){ + throw new JeecgBootException("物流单号错误"); + } + + String host = "https://wuliu.market.alicloudapi.com";// 【1】请求地址 支持http 和 https 及 WEBSOCKET + String path = "/kdi"; // 【2】后缀 + String appcode = appCode; // 【3】开通服务后 买家中心-查看AppCode + String no = queryLogisticsReq.getNo();// 【4】快递单号 +// String type = "zto"; // 【4】请求参数,不知道可不填 95%能自动识别 +// String urlSend = host + path + "?no=" + no +"&type="+type; // 【5】拼接请求链接 + String urlSend = host + path + "?no=" + no; + try { + URL url = new URL(urlSend); + HttpURLConnection httpURLCon = (HttpURLConnection) url.openConnection(); + httpURLCon .setRequestProperty("Authorization", "APPCODE " + appcode);// 格式Authorization:APPCODE (中间是英文空格) + int httpCode = httpURLCon.getResponseCode(); + if (httpCode == 200) { + String json = read(httpURLCon.getInputStream()); + log.info("正常请求计费(其他均不计费)"); + log.info("获取返回的json:"); + log.info(json); + return Result.OK(json); + } else { + Map> map = httpURLCon.getHeaderFields(); + String error = map.get("X-Ca-Error-Message").get(0); + if (httpCode == 400 && error.equals("Invalid AppCode `not exists`")) { + log.error("AppCode错误 "); + } else if (httpCode == 400 && error.equals("Invalid Url")) { + log.error("请求的 Method、Path 或者环境错误"); + } else if (httpCode == 400 && error.equals("Invalid Param Location")) { + log.error("参数错误"); + } else if (httpCode == 403 && error.equals("Unauthorized")) { + log.error("服务未被授权(或URL和Path不正确)"); + } else if (httpCode == 403 && error.equals("Quota Exhausted")) { + log.error("套餐包次数用完 "); + } else if (httpCode == 403 && error.equals("Api Market Subscription quota exhausted")) { + log.error("套餐包次数用完,请续购套餐"); + } else { + log.error("参数名错误 或 其他错误"); + log.error(error); + } + } - LogisticsDetailRequest logisticsDetailRequest = new LogisticsDetailRequest(); - logisticsDetailRequest.setTdOrderId(15592780860652417L); - LogisticsDetailOption logisticsDetailOption = new LogisticsDetailOption(); - logisticsDetailOption.setAccessCode(accessCode); - logisticsDetailOption.setAccessMethod("LINK"); + } catch (MalformedURLException e) { + log.error("URL格式错误"); + } catch (UnknownHostException e) { + log.error("URL地址错误"); + } catch (Exception e) { + // 打开注释查看详细报错异常信息 + // e.printStackTrace(); + } + return Result.error("请求错误"); + } - request.setRequest(logisticsDetailRequest); - request.setOption(logisticsDetailOption); - GuoguoQueryLogisticsDetailResponse response = linkClient.execute(request, accountId, accessCode); - log.info("包裹返回信息:"+response.toString()); - return null; + /* + * 读取返回结果 + */ + private static String read(InputStream is) throws IOException { + StringBuffer sb = new StringBuffer(); + BufferedReader br = new BufferedReader(new InputStreamReader(is)); + String line = null; + while ((line = br.readLine()) != null) { + line = new String(line.getBytes(), "utf-8"); + sb.append(line); + } + br.close(); + return sb.toString(); } public Object testPay(String id){ diff --git a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/shop/service/impl/ShopServiceImpl.java b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/shop/service/impl/ShopServiceImpl.java index 5d28c27..7e7816f 100644 --- a/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/shop/service/impl/ShopServiceImpl.java +++ b/jeecg-boot-module-system/src/main/java/org/jeecg/modules/xcx/shop/service/impl/ShopServiceImpl.java @@ -156,6 +156,9 @@ public class ShopServiceImpl implements IShopService { if(StringUtils.isBlank(applyWithdrawalReq.getBankAddress())){ throw new JeecgBootException("请填写银行卡支行地址"); } + if(StringUtils.isBlank(hanHaiMember.getAppletOpenid())){ + throw new JeecgBootException("请先绑定微信"); + } BigDecimal money = hotelMemberAccount.getShopBalance().subtract(applyWithdrawalReq.getMoney()); HotelMemberAccount hotelMemberAccount1 = new HotelMemberAccount(); diff --git a/jeecg-boot-module-system/src/main/resources/application-dev.yml b/jeecg-boot-module-system/src/main/resources/application-dev.yml index d3f6ccb..f3b3b67 100644 --- a/jeecg-boot-module-system/src/main/resources/application-dev.yml +++ b/jeecg-boot-module-system/src/main/resources/application-dev.yml @@ -330,6 +330,19 @@ third-app: client-secret: ?? agent-id: ?? + +##配置微信 +wechat: + mpAppId: wxad5b3d20a75974c0 + mpAppSecret: 3b60a80c8e673986dd42f3cd6f2cf6b1 + mchId: 1684424511 + mchKey: 0fdb77429ffdf206c151af76a663041c + keyPath: D:\project\hanhai-object-jdbc-20240829\apiclient_cert.p12 + transferBatchUrl: https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills + #获取access_token接口 + getAccessTokenUrl: https://api.weixin.qq.com/cgi-bin/token + keyPemPath: D:\project\hanhai-object-jdbc-20240829\apiclient_key.pem + weixin: mpAppId: wxad5b3d20a75974c0 mpAppSecret: 3b60a80c8e673986dd42f3cd6f2cf6b1 @@ -341,9 +354,35 @@ weixin: apiV3Key: 0fdb77429ffdf206c151af76a663041c keyPemPath: apiclient_key.pem +wxpay: + #应用编号 + appId: wxad5b3d20a75974c0 + #商户号 + mchId: 1684424511 + # APIv2密钥 + apiKey: 0fdb77429ffdf206c151af76a663041c + # APIv3密钥 + apiV3Key: 0fdb77429ffdf206c151af76a663041c + # 微信支付V3-url前缀 + baseUrl: https://api.mch.weixin.qq.com/v3 + # 支付通知回调, pjm6m9.natappfree.cc 为内网穿透地址 + notifyUrl: http://pjm6m9.natappfree.cc/pay/payNotify + # 退款通知回调, pjm6m9.natappfree.cc 为内网穿透地址 + refundNotifyUrl: http://pjm6m9.natappfree.cc/pay/refundNotify + # 密钥路径,resources根目录下 + keyPemPath: apiclient_key.pem + #商户证书序列号 + serialNo: 617767B5F6790AA85EEDED28F82599AAF4830FB9 + cainiao: appKey: 251828 appSecret: 62Fyi41Yx047wbg7M2sL0SltPM25fsq8 accountId: 2218798171581 - accessCode: d53a04398f95bf6ed4984bc444caf696 \ No newline at end of file + accessCode: d53a04398f95bf6ed4984bc444caf696 + +aliyun: + kuaidi: + appKey: 204797985 + appSecret: pqQLX0uXZ725vq3px1Dp6FgLyil9Ac3Q + appCode: 0ba63f98943043e182cb25319459e966 diff --git a/jeecg-boot-module-system/src/main/resources/application-prod.yml b/jeecg-boot-module-system/src/main/resources/application-prod.yml index 4d49652..924aa8a 100644 --- a/jeecg-boot-module-system/src/main/resources/application-prod.yml +++ b/jeecg-boot-module-system/src/main/resources/application-prod.yml @@ -330,14 +330,57 @@ third-app: client-secret: ?? agent-id: ?? +##配置微信 +wechat: + mpAppId: wxad5b3d20a75974c0 + mpAppSecret: 3b60a80c8e673986dd42f3cd6f2cf6b1 + mchId: 1684424511 + mchKey: 0fdb77429ffdf206c151af76a663041c + keyPath: /usr/local/cert/apiclient_cert.p12 + transferBatchUrl: https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills + #获取access_token接口 + getAccessTokenUrl: https://api.weixin.qq.com/cgi-bin/token + keyPemPath: /usr/local/cert/apiclient_key.pem + weixin: mpAppId: wxad5b3d20a75974c0 mpAppSecret: 3b60a80c8e673986dd42f3cd6f2cf6b1 orderNotifyUrl: https://admin.buzhoudao.com/hotel/order/notify replaceOrderNotifyUrl: https://admin.buzhoudao.com/hotel/order/replace/notify + mchId: 1684424511 + mchKey: 0fdb77429ffdf206c151af76a663041c + serialNo: 617767B5F6790AA85EEDED28F82599AAF4830FB9 + apiV3Key: 0fdb77429ffdf206c151af76a663041c + keyPemPath: apiclient_key.pem + +wxpay: + #应用编号 + appId: wxad5b3d20a75974c0 + #商户号 + mchId: 1684424511 + # APIv2密钥 + apiKey: 0fdb77429ffdf206c151af76a663041c + # APIv3密钥 + apiV3Key: 0fdb77429ffdf206c151af76a663041c + # 微信支付V3-url前缀 + baseUrl: https://api.mch.weixin.qq.com/v3 + # 支付通知回调, pjm6m9.natappfree.cc 为内网穿透地址 + notifyUrl: http://pjm6m9.natappfree.cc/pay/payNotify + # 退款通知回调, pjm6m9.natappfree.cc 为内网穿透地址 + refundNotifyUrl: http://pjm6m9.natappfree.cc/pay/refundNotify + # 密钥路径,resources根目录下 + keyPemPath: apiclient_key.pem + #商户证书序列号 + serialNo: 617767B5F6790AA85EEDED28F82599AAF4830FB9 cainiao: appKey: 251828 appSecret: 62Fyi41Yx047wbg7M2sL0SltPM25fsq8 accountId: 2218798171581 - accessCode: \ No newline at end of file + accessCode: d53a04398f95bf6ed4984bc444caf696 + +aliyun: + kuaidi: + appKey: 204797985 + appSecret: pqQLX0uXZ725vq3px1Dp6FgLyil9Ac3Q + appCode: 0ba63f98943043e182cb25319459e966 diff --git a/jeecg-boot-module-system/src/main/resources/application-test.yml b/jeecg-boot-module-system/src/main/resources/application-test.yml index f29ecdc..24a0abf 100644 --- a/jeecg-boot-module-system/src/main/resources/application-test.yml +++ b/jeecg-boot-module-system/src/main/resources/application-test.yml @@ -330,8 +330,58 @@ third-app: client-secret: ?? agent-id: ?? + +##配置微信 +wechat: + mpAppId: wxad5b3d20a75974c0 + mpAppSecret: 3b60a80c8e673986dd42f3cd6f2cf6b1 + mchId: 1684424511 + mchKey: 0fdb77429ffdf206c151af76a663041c + keyPath: /usr/local/cert/apiclient_cert.p12 + transferBatchUrl: https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills + #获取access_token接口 + getAccessTokenUrl: https://api.weixin.qq.com/cgi-bin/token + keyPemPath: /usr/local/cert/apiclient_key.pem + weixin: mpAppId: wxad5b3d20a75974c0 mpAppSecret: 3b60a80c8e673986dd42f3cd6f2cf6b1 orderNotifyUrl: https://hotel.java996.icu/hotel/order/notify - replaceOrderNotifyUrl: https://hotel.java996.icu/hotel/order/replace/notify \ No newline at end of file + replaceOrderNotifyUrl: https://hotel.java996.icu/hotel/order/replace/notify + mchId: 1684424511 + mchKey: 0fdb77429ffdf206c151af76a663041c + serialNo: 617767B5F6790AA85EEDED28F82599AAF4830FB9 + apiV3Key: 0fdb77429ffdf206c151af76a663041c + keyPemPath: apiclient_key.pem + +wxpay: + #应用编号 + appId: wxad5b3d20a75974c0 + #商户号 + mchId: 1684424511 + # APIv2密钥 + apiKey: 0fdb77429ffdf206c151af76a663041c + # APIv3密钥 + apiV3Key: 0fdb77429ffdf206c151af76a663041c + # 微信支付V3-url前缀 + baseUrl: https://api.mch.weixin.qq.com/v3 + # 支付通知回调, pjm6m9.natappfree.cc 为内网穿透地址 + notifyUrl: http://pjm6m9.natappfree.cc/pay/payNotify + # 退款通知回调, pjm6m9.natappfree.cc 为内网穿透地址 + refundNotifyUrl: http://pjm6m9.natappfree.cc/pay/refundNotify + # 密钥路径,resources根目录下 + keyPemPath: apiclient_key.pem + #商户证书序列号 + serialNo: 617767B5F6790AA85EEDED28F82599AAF4830FB9 + +cainiao: + appKey: 251828 + appSecret: 62Fyi41Yx047wbg7M2sL0SltPM25fsq8 + accountId: 2218798171581 + accessCode: d53a04398f95bf6ed4984bc444caf696 + +aliyun: + kuaidi: + appKey: 204797985 + appSecret: pqQLX0uXZ725vq3px1Dp6FgLyil9Ac3Q + appCode: 0ba63f98943043e182cb25319459e966 diff --git a/pom.xml b/pom.xml index 3ef943f..aff812a 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,21 @@ 2.17.0 1.2.9 0.2.15 + + + 2.3.0 + 2.1.1 + 2.23.2 + 2.23.2 + 1.59 + 2.2.3 + 3.8.0 0.5.0 + + 4.5.3 + 3.1 + 4.4.10 + 4.5.3 @@ -333,16 +347,83 @@ wechatpay-java ${wechatpay-java.version} + + + + com.squareup.retrofit2 + converter-simplexml + ${converter-simplexml.version} + + + + javax.ws.rs + javax.ws.rs-api + ${javax.ws.rs-api.version} + + + + org.glassfish.jersey.core + jersey-client + ${jersey-client.version} + + + + org.glassfish.jersey.connectors + jersey-apache-connector + ${jersey-apache-connector.version} + + + + org.bouncycastle + bcprov-jdk15on + ${bcprov-jdk15on.version} + + + + net.sf.json-lib + json-lib + ${json-lib.version} + jdk15 + + + + com.squareup.okhttp3 + logging-interceptor + ${logging-interceptor.version} + + + com.github.wechatpay-apiv3 wechatpay-apache-httpclient ${wechatpay-apache-httpclientd.version} + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + + commons-httpclient + commons-httpclient + ${commons-httpclient.version} + + - pac.sdk - pac-sdk-cp - 1.0.0 + org.apache.httpcomponents + httpcore + ${httpcore.version} + + + org.apache.httpcomponents + httpmime + ${httpmime.version} + +