|
@@ -0,0 +1,348 @@
|
|
|
+package org.jeecg.modules.pay.config;
|
|
|
+
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
+import com.alibaba.fastjson2.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.jeecg.modules.pay.entity.ProfitSharingRequest;
|
|
|
+import org.jeecg.modules.pay.entity.Receiver;
|
|
|
+import org.jeecg.modules.pay.entity.ReceiverAddForm;
|
|
|
+import org.jeecg.modules.system.app.entity.AppOrder;
|
|
|
+import org.jeecg.modules.system.app.entity.AppProfitSharingInfo;
|
|
|
+import org.jeecg.modules.system.app.entity.AppProfitSharingRecords;
|
|
|
+import org.jeecg.modules.system.app.mapper.AppOrderMapper;
|
|
|
+import org.jeecg.modules.system.app.mapper.AppProfitSharingInfoMapper;
|
|
|
+import org.jeecg.modules.system.app.mapper.AppProfitSharingRecordsMapper;
|
|
|
+import org.springframework.core.io.ClassPathResource;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import javax.crypto.BadPaddingException;
|
|
|
+import javax.crypto.Cipher;
|
|
|
+import javax.crypto.IllegalBlockSizeException;
|
|
|
+import javax.crypto.NoSuchPaddingException;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.nio.charset.StandardCharsets;
|
|
|
+import java.security.InvalidKeyException;
|
|
|
+import java.security.NoSuchAlgorithmException;
|
|
|
+import java.security.cert.*;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+import static java.lang.Thread.sleep;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class WeChatProfitSharingService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private WechatPayV3Utils wechatPayV3Utils;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private AppOrderMapper appOrderMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private AppProfitSharingRecordsMapper appProfitSharingRecordsMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private AppProfitSharingInfoMapper appProfitSharingInfoMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 添加分账接收方
|
|
|
+ *
|
|
|
+ * @param receiverAddForm
|
|
|
+ * @return JSONObject
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public JSONObject receiversAdd(ReceiverAddForm receiverAddForm) throws Exception {
|
|
|
+ ClassPathResource classPathResource = new ClassPathResource("cert/platform_cert.pem");
|
|
|
+ InputStream certStream = classPathResource.getInputStream();
|
|
|
+ X509Certificate x509Certificate = getCertificate(certStream);
|
|
|
+
|
|
|
+ String name = rsaEncryptOAEP(receiverAddForm.getName(), x509Certificate);
|
|
|
+ receiverAddForm.setName(name);
|
|
|
+ JSONObject params = JSONObject.from(receiverAddForm);
|
|
|
+ log.info("分账接收方:{}", receiverAddForm);
|
|
|
+ JSONObject body = wechatPayV3Utils.profitSharingSendPost(WechatUrlConstants.PAY_V3_RECEIVERS_ADD, params);
|
|
|
+ log.info("添加分账接收方结果:{}", body);
|
|
|
+ return body;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分账
|
|
|
+ *
|
|
|
+ * @param orderCode 订单编号
|
|
|
+ * @return JSONObject
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ public JSONObject profitSharing(String orderCode) throws Exception {
|
|
|
+ AppOrder appOrder = appOrderMapper.selectOne(Wrappers.lambdaQuery(AppOrder.class).eq(AppOrder::getOrderCode, orderCode).last(
|
|
|
+ "limit 1"));
|
|
|
+ //订单预分账详情列表
|
|
|
+ List<AppProfitSharingInfo> appProfitSharingInfos = appProfitSharingInfoMapper.selectList(Wrappers.lambdaQuery(AppProfitSharingInfo.class).eq(AppProfitSharingInfo::getOrderId,
|
|
|
+ appOrder.getId()));
|
|
|
+
|
|
|
+ Integer orderAmount = RatiosUtil.amount_fee(appOrder.getPrice());
|
|
|
+ int amount = 0;
|
|
|
+ for (AppProfitSharingInfo appProfitSharingInfo : appProfitSharingInfos) {
|
|
|
+ amount = amount + appProfitSharingInfo.getPreAmount();
|
|
|
+ }
|
|
|
+
|
|
|
+ //创建分账记录
|
|
|
+ AppProfitSharingRecords appProfitSharingRecords = new AppProfitSharingRecords();
|
|
|
+ appProfitSharingRecords.setProfitSharingNo("P" + orderCode);
|
|
|
+ appProfitSharingRecords.setOrderId(appOrder.getId());
|
|
|
+ appProfitSharingRecords.setOrderAmount(orderAmount);
|
|
|
+ appProfitSharingRecords.setAmount(amount);
|
|
|
+ appProfitSharingRecords.setProcedureFee(orderAmount - amount);
|
|
|
+ appProfitSharingRecords.setProfitSharingTime(new Date());
|
|
|
+
|
|
|
+ List<AppProfitSharingInfo> receiverRecords = appProfitSharingInfos.stream().filter(e -> e.getType() == 1).collect(Collectors.toList());
|
|
|
+ List<AppProfitSharingInfo> partyFunding = appProfitSharingInfos.stream().filter(e -> e.getType() == 0).collect(Collectors.toList());
|
|
|
+ List<Receiver> receivers = new ArrayList<>();
|
|
|
+ //查询当前订单的分账接收方列表
|
|
|
+ for (AppProfitSharingInfo receiverRecord : receiverRecords) {
|
|
|
+ Receiver receiver = new Receiver();
|
|
|
+ receiver.setType("MERCHANT_ID")
|
|
|
+ .setAccount(receiverRecord.getMchId())
|
|
|
+ .setAmount(receiverRecord.getPreAmount())
|
|
|
+ .setDescription("商户:" + receiverRecord.getMchName() + "于订单" + receiverRecord.getOrgCode() + "分账所获金额:" + receiverRecord.getPreAmount());
|
|
|
+ receivers.add(receiver);
|
|
|
+
|
|
|
+ //添加分账接收方
|
|
|
+ ReceiverAddForm receiverAddForm = new ReceiverAddForm();
|
|
|
+ receiverAddForm.setSub_mchid(partyFunding.get(0).getMchId());
|
|
|
+ receiverAddForm.setSub_appid(WechatConstants.WECHAT_SUB_APPID);
|
|
|
+ receiverAddForm.setAccount(receiver.getAccount());
|
|
|
+ receiverAddForm.setName(receiverRecord.getMchName());
|
|
|
+
|
|
|
+ receiversAdd(receiverAddForm);
|
|
|
+ sleep(1000);
|
|
|
+ }
|
|
|
+ ProfitSharingRequest profitSharingRequest = new ProfitSharingRequest();
|
|
|
+ profitSharingRequest
|
|
|
+ .setAppid(WechatConstants.WECHAT_SP_APPID)
|
|
|
+ .setSub_mchid(partyFunding.get(0).getMchId())
|
|
|
+ .setTransaction_id(appOrder.getTransactionId())
|
|
|
+ .setOut_order_no(appProfitSharingRecords.getProfitSharingNo())
|
|
|
+ .setReceivers(receivers)
|
|
|
+ .setUnfreeze_unsplit(Boolean.TRUE);
|
|
|
+ try {
|
|
|
+ JSONObject res = wechatPayV3Utils.profitSharingSendPost(WechatUrlConstants.PAY_V3_PROFIT_SHARING, JSONObject.from(profitSharingRequest));
|
|
|
+ log.info("微信服务商分账--------------------------------------------------wechatPay res:{}", res.toString());
|
|
|
+ if (ObjectUtil.isNotEmpty(res)) {
|
|
|
+ if ("PROCESSING".equals(res.getString("state"))) {
|
|
|
+ appProfitSharingRecords.setStatus(0);
|
|
|
+ appOrder.setProfitSharingStatus(1);
|
|
|
+ }
|
|
|
+ if ("FINISHED".equals(res.getString("state"))) {
|
|
|
+ appProfitSharingRecords.setStatus(1);
|
|
|
+ appOrder.setProfitSharingStatus(2);
|
|
|
+ }
|
|
|
+ String wechatOrderId = res.getString("order_id");
|
|
|
+ String transactionId = res.getString("transaction_id");
|
|
|
+ appProfitSharingRecords.setTransactionId(transactionId);
|
|
|
+ appProfitSharingRecords.setProfitSharingOrderId(wechatOrderId);
|
|
|
+ appProfitSharingRecordsMapper.insert(appProfitSharingRecords);
|
|
|
+
|
|
|
+ //订单
|
|
|
+ appOrder.setOutOrderNo(appProfitSharingRecords.getProfitSharingNo());
|
|
|
+ appOrder.setProfitSharingOrderId(wechatOrderId);
|
|
|
+ appOrderMapper.updateById(appOrder);
|
|
|
+
|
|
|
+ if (ObjectUtil.isNotEmpty(res.get("receivers"))) {
|
|
|
+ List<WechatReceiver> wechatReceivers = (List<WechatReceiver>) res.get("receivers");
|
|
|
+ for (WechatReceiver wechatReceiver : wechatReceivers) {
|
|
|
+ //关联订单分账详情
|
|
|
+ for (AppProfitSharingInfo appProfitSharingInfo : appProfitSharingInfos) {
|
|
|
+ if (Objects.equals(wechatReceiver.getAccount(), appProfitSharingInfo.getMchId())) {
|
|
|
+ appProfitSharingInfo.setProfitSharingRecordsId(appProfitSharingRecords.getId());
|
|
|
+ appProfitSharingInfo.setAmount(wechatReceiver.getAmount());
|
|
|
+ appProfitSharingInfo.setStatus(wechatReceiver.getResult());
|
|
|
+ appProfitSharingInfo.setDescription(wechatReceiver.getDescription());
|
|
|
+ appProfitSharingInfoMapper.updateById(appProfitSharingInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 查询分账结果并修改订单分账详情
|
|
|
+ *
|
|
|
+ * @param orderCode 订单编号
|
|
|
+ * @return JSONObject
|
|
|
+ */
|
|
|
+ public JSONObject getProfitSharingResult(String orderCode) {
|
|
|
+ AppOrder appOrder = appOrderMapper.selectOne(Wrappers.lambdaQuery(AppOrder.class).eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
|
|
|
+
|
|
|
+ AppProfitSharingRecords appProfitSharingRecords = appProfitSharingRecordsMapper.selectOne(Wrappers.lambdaQuery(AppProfitSharingRecords.class).eq(AppProfitSharingRecords::getOrderId,
|
|
|
+ appOrder.getId()).last("limit 1"));
|
|
|
+
|
|
|
+ List<AppProfitSharingInfo> appProfitSharingInfos = appProfitSharingInfoMapper.selectList(Wrappers.lambdaQuery(AppProfitSharingInfo.class).eq(AppProfitSharingInfo::getOrderId,
|
|
|
+ appOrder.getId()));
|
|
|
+
|
|
|
+ List<AppProfitSharingInfo> partyFunding = appProfitSharingInfos.stream().filter(e -> e.getType() == 0).collect(Collectors.toList());
|
|
|
+ HashMap<String, String> map = new HashMap<>();
|
|
|
+ map.put("sub_mchid", partyFunding.get(0).getMchId());
|
|
|
+ map.put("transaction_id", appOrder.getTransactionId());
|
|
|
+
|
|
|
+ String params = WechatPayV3Utils.formatUrlParam(map);
|
|
|
+ try {
|
|
|
+ String url = WechatUrlConstants.PAY_V3_GET_PROFIT_SHARING + "P" + orderCode + "?" + params;
|
|
|
+ JSONObject res = wechatPayV3Utils.sendGet(url);
|
|
|
+ log.info("微信服务商分账结果查询--------------------------------------------------wechatPay res:{}", res.toString());
|
|
|
+
|
|
|
+ if (ObjectUtil.isNotEmpty(res)) {
|
|
|
+ if ("PROCESSING".equals(res.getString("state"))) {
|
|
|
+ appProfitSharingRecords.setStatus(0);
|
|
|
+ appOrder.setProfitSharingStatus(1);
|
|
|
+ }
|
|
|
+ if ("FINISHED".equals(res.getString("state"))) {
|
|
|
+ appProfitSharingRecords.setStatus(1);
|
|
|
+ appOrder.setProfitSharingStatus(2);
|
|
|
+ }
|
|
|
+ String wechatOrderId = res.getString("order_id");
|
|
|
+ String transactionId = res.getString("transaction_id");
|
|
|
+ appProfitSharingRecords.setTransactionId(transactionId);
|
|
|
+ appProfitSharingRecords.setProfitSharingOrderId(wechatOrderId);
|
|
|
+ appProfitSharingRecordsMapper.insert(appProfitSharingRecords);
|
|
|
+
|
|
|
+ //订单
|
|
|
+ appOrder.setOutOrderNo(appProfitSharingRecords.getProfitSharingNo());
|
|
|
+ appOrder.setProfitSharingOrderId(wechatOrderId);
|
|
|
+ appOrderMapper.updateById(appOrder);
|
|
|
+
|
|
|
+ if (ObjectUtil.isNotEmpty(res.get("receivers"))) {
|
|
|
+ List<WechatReceiver> wechatReceivers = (List<WechatReceiver>) res.get("receivers");
|
|
|
+ for (WechatReceiver wechatReceiver : wechatReceivers) {
|
|
|
+ //关联订单分账详情
|
|
|
+ for (AppProfitSharingInfo appProfitSharingInfo : appProfitSharingInfos) {
|
|
|
+ if (Objects.equals(wechatReceiver.getAccount(), appProfitSharingInfo.getMchId())) {
|
|
|
+ appProfitSharingInfo.setProfitSharingRecordsId(appProfitSharingRecords.getId());
|
|
|
+ appProfitSharingInfo.setAmount(wechatReceiver.getAmount());
|
|
|
+ appProfitSharingInfo.setStatus(wechatReceiver.getResult());
|
|
|
+ appProfitSharingInfo.setDescription(wechatReceiver.getDescription());
|
|
|
+ appProfitSharingInfoMapper.updateById(appProfitSharingInfo);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return res;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分账回退
|
|
|
+ *
|
|
|
+ * @param orderCode 订单编号
|
|
|
+ * @return JSONObject
|
|
|
+ */
|
|
|
+ public JSONObject returnProfitSharing(String orderCode) {
|
|
|
+ AppOrder appOrder = appOrderMapper.selectOne(Wrappers.lambdaQuery(AppOrder.class).eq(AppOrder::getOrderCode, orderCode).last("limit 1"));
|
|
|
+
|
|
|
+ List<AppProfitSharingInfo> appProfitSharingInfos = appProfitSharingInfoMapper.selectList(Wrappers.lambdaQuery(AppProfitSharingInfo.class).eq(AppProfitSharingInfo::getOrderId,
|
|
|
+ appOrder.getId()));
|
|
|
+ List<AppProfitSharingInfo> receiverRecords = appProfitSharingInfos.stream().filter(e -> e.getType() == 1).collect(Collectors.toList());
|
|
|
+ List<AppProfitSharingInfo> partyFunding = appProfitSharingInfos.stream().filter(e -> e.getType() == 0).collect(Collectors.toList());
|
|
|
+
|
|
|
+ for (AppProfitSharingInfo receiverRecord : receiverRecords) {
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
+ map.put("sub_mchid", partyFunding.get(0).getMchId());
|
|
|
+ map.put("out_order_no ", "P" + orderCode);
|
|
|
+ map.put("order_id", appOrder.getProfitSharingOrderId());
|
|
|
+ map.put("out_return_no", "T" + orderCode);
|
|
|
+ map.put("return_mchid", receiverRecord.getMchId());
|
|
|
+ map.put("amount", receiverRecord.getAmount());
|
|
|
+ map.put("description", receiverRecord.getMchName() +"分账订单:"+ orderCode + "退还金额:" + receiverRecord.getAmount());
|
|
|
+
|
|
|
+ try {
|
|
|
+ JSONObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_RETURN_ORDER, JSONObject.from(map));
|
|
|
+ log.info("微信服务商分账回退--------------------------------------------------wechatPay res:{}", res.toString());
|
|
|
+ return res;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取分账回退结果
|
|
|
+ *
|
|
|
+ * @param orderCode 订单编号
|
|
|
+ * @return JSONObject
|
|
|
+ */
|
|
|
+ public JSONObject getReturnProfitSharing(String orderCode) {
|
|
|
+ HashMap<String, String> map = new HashMap<>();
|
|
|
+ map.put("sub_mchid", WechatConstants.WECHAT_SUB_MCH_ID);
|
|
|
+ map.put("out_order_no", "P" + orderCode);
|
|
|
+
|
|
|
+ String params = WechatPayV3Utils.formatUrlParam(map);
|
|
|
+ try {
|
|
|
+ String url = WechatUrlConstants.PAY_V3_GET_RETURN_ORDER + "T" + orderCode + "?" + params;
|
|
|
+ JSONObject res = wechatPayV3Utils.sendGet(url);
|
|
|
+ log.info("微信服务商分账结果查询--------------------------------------------------wechatPay res:{}", res.toString());
|
|
|
+ return res;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取证书
|
|
|
+ *
|
|
|
+ * @param inputStream 证书文件
|
|
|
+ * @return {@link X509Certificate} 获取证书
|
|
|
+ */
|
|
|
+ public static X509Certificate getCertificate(InputStream inputStream) {
|
|
|
+ try {
|
|
|
+ CertificateFactory cf = CertificateFactory.getInstance("X509");
|
|
|
+ X509Certificate cert = (X509Certificate) cf.generateCertificate(inputStream);
|
|
|
+ cert.checkValidity();
|
|
|
+ return cert;
|
|
|
+ } catch (CertificateExpiredException e) {
|
|
|
+ throw new RuntimeException("证书已过期", e);
|
|
|
+ } catch (CertificateNotYetValidException e) {
|
|
|
+ throw new RuntimeException("证书尚未生效", e);
|
|
|
+ } catch (CertificateException e) {
|
|
|
+ throw new RuntimeException("无效的证书", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 公钥加密 加密隐私信息数据
|
|
|
+ *
|
|
|
+ * @param certificate 平台公钥证书
|
|
|
+ * @return 加密后的数据
|
|
|
+ * @throws Exception 异常信息
|
|
|
+ */
|
|
|
+ public static String rsaEncryptOAEP(String message, X509Certificate certificate)
|
|
|
+ throws IllegalBlockSizeException, IOException {
|
|
|
+ try {
|
|
|
+ Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
|
|
|
+ cipher.init(Cipher.ENCRYPT_MODE, certificate.getPublicKey());
|
|
|
+ byte[] data = message.getBytes(StandardCharsets.UTF_8);
|
|
|
+ byte[] cipherdata = cipher.doFinal(data);
|
|
|
+ return Base64.getEncoder().encodeToString(cipherdata);
|
|
|
+ } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
|
|
|
+ throw new RuntimeException("当前Java环境不支持RSA v1.5/OAEP", e);
|
|
|
+ } catch (InvalidKeyException e) {
|
|
|
+ throw new IllegalArgumentException("无效的证书", e);
|
|
|
+ } catch (IllegalBlockSizeException | BadPaddingException e) {
|
|
|
+ throw new IllegalBlockSizeException("加密原串的长度不能超过214字节");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|