zhijiezhao 1 år sedan
förälder
incheckning
d4c1873f84

+ 70 - 5
src/main/java/com/caimei365/order/components/OnlinePostFormUtil.java

@@ -3,12 +3,11 @@ package com.caimei365.order.components;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import lombok.extern.slf4j.Slf4j;
-import okhttp3.FormBody;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
+import okhttp3.*;
 
 import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
 
@@ -61,7 +60,7 @@ public class OnlinePostFormUtil {
         JSONObject res = JSON.parseObject(content);
         //网银查询回调
         if (!"SUCCESS".equals(res.getString("rt10_orderStatus"))) {
-            log.info("网银查询成功结果------->"+res.toString());
+            log.info("网银查询成功结果------->" + res.toString());
         }
         /** rt4_success 为 true,需验签  **/
         return res.toJavaObject(clazz);
@@ -108,4 +107,70 @@ public class OnlinePostFormUtil {
         /** rt4_success 为 true,需验签  **/
         return res.toJavaObject(clazz);
     }
+
+    public static <T> T splitPostForm(Map<String, String> params, String url, String sign, Class<T> clazz) {
+        FormBody.Builder builder = new FormBody.Builder();
+        for (Map.Entry<String, String> entry : params.entrySet()) {
+            builder.add(entry.getKey(), entry.getValue());
+        }
+        builder.add("sign", sign);
+
+        Request request = new Request.Builder() // okHttp post
+                .url(url)
+                .post(builder.build())
+                .build();
+
+        Response response = null;
+        try {
+            response = client.newCall(request).execute();
+        } catch (IOException e) {
+            throw new IllegalStateException("请求出错", e);
+        }
+        if (!response.isSuccessful()) {
+            try {
+                log.info(response.body().string());
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+            throw new RuntimeException("请求失败了: http response code: " + response.code());
+        }
+
+        ResponseBody body = response.body();
+        String content = null;
+        try {
+            content = body.string();
+        } catch (IOException e) {
+            throw new IllegalStateException("IO异常", e);
+        }
+        JSONObject res = JSON.parseObject(content);
+        if (!res.getBooleanValue("rt4_success")) {
+            log.error("error: " + res.getString("rt6_retMsg"));
+        }
+        /** rt4_success 为 true,需验签  **/
+        return res.toJavaObject(clazz);
+    }
+
+
+    public static Map<String, String> splitConvertBean(Object bean) {
+        Class clazz = bean.getClass();
+        Field[] fields = clazz.getDeclaredFields();
+        for (Field f : fields) {
+            f.setAccessible(true);
+        }
+        try {
+            Map<String, String> retMap = new LinkedHashMap<>();
+            for (Field f : fields) {
+                String key = f.toString().substring(f.toString().lastIndexOf(".") + 1);
+                Object value = f.get(bean);
+                if (value == null) {
+                    value = "";
+                }
+                retMap.put(key, (String) value);
+            }
+            return retMap;
+        } catch (Exception e) {
+            log.info("分账", e);
+            throw new IllegalStateException("分账异常", e);
+        }
+    }
 }

+ 4 - 1
src/main/java/com/caimei365/order/constant/Constant.java

@@ -26,7 +26,10 @@ public class Constant {
     public static final String AT_MAIL = "caimei365@yeah.net";
 
     public static final String SPLIT = "&";
-
+    /**
+     * 分账回调地址
+     */
+    public static final String prodWYREFUND = "https://core.caimei365.com/order/pay/refund/split/callback";
     /**
      * 快捷支付地址
      */

+ 12 - 0
src/main/java/com/caimei365/order/controller/HeliPayApi.java

@@ -434,6 +434,18 @@ public class HeliPayApi {
         return heliPayService.delayedSplittingCallback(data);
     }
 
+    /**
+     * 网银退款手续费转回回调
+     */
+    @ApiOperation("网银退款手续费转回回调")
+    @PostMapping("/refund/split/callback")
+    public String refundSplittingCallback(AccountResVo data) {
+        if (null == data) {
+            return "回调参数失败";
+        }
+        return heliPayService.refundSplittingCallback(data);
+    }
+
     @ApiOperation("银行通道码获取")
     @GetMapping("/bankcode")
     public ResponseJson<Map<String, Object>> bankcode() {

+ 5 - 0
src/main/java/com/caimei365/order/mapper/OrderRefundMapper.java

@@ -8,6 +8,7 @@ import com.caimei365.order.model.vo.OrderVo;
 import com.caimei365.order.model.vo.UserVo;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 /**
@@ -53,4 +54,8 @@ public interface OrderRefundMapper {
     Integer findShopOrderRefundCount(Integer orderId);
 
     void updateOrderRefund(Integer orderId, Integer refundType);
+
+    void insertTransfer(BigDecimal money, String orderRequestNo, Integer shopOrderId);
+
+    OrderReceiptRelationPo findOrderRelationByNo(String orderRequestNo);
 }

+ 4 - 0
src/main/java/com/caimei365/order/model/po/OrderReceiptRelationPo.java

@@ -83,4 +83,8 @@ public class OrderReceiptRelationPo implements Serializable {
      * 子订单id
      */
     private Integer shopOrderId;
+    /**
+     * 商户号
+     */
+    private String splitCode;
 }

+ 3 - 1
src/main/java/com/caimei365/order/service/HeliPayService.java

@@ -37,7 +37,7 @@ public interface HeliPayService {
     /**
      * 延时分账
      */
-    void delayedSplitting(String callUrl);
+//    void delayedSplitting(String callUrl);
     /**
      * 延时分账异步回调
      */
@@ -70,4 +70,6 @@ public interface HeliPayService {
     ResponseJson<String> bindCardNoCode(HeliDto heliDto);
 
     ResponseJson<List<QuickBankVo>> unCodeInfos();
+
+    String refundSplittingCallback(AccountResVo data);
 }

+ 213 - 147
src/main/java/com/caimei365/order/service/impl/HeliPayServiceImpl.java

@@ -8,6 +8,7 @@ import com.caimei365.order.components.WeChatService;
 import com.caimei365.order.constant.Constant;
 import com.caimei365.order.mapper.BaseMapper;
 import com.caimei365.order.mapper.OrderCommonMapper;
+import com.caimei365.order.mapper.OrderRefundMapper;
 import com.caimei365.order.mapper.PayOrderMapper;
 import com.caimei365.order.model.ResponseJson;
 import com.caimei365.order.model.bo.PayParamBo;
@@ -78,6 +79,8 @@ public class HeliPayServiceImpl implements HeliPayService {
     private RemoteCallService remoteCallService;
     @Resource
     private WeChatService weChatService;
+    @Resource
+    private OrderRefundMapper refundMapper;
     @Value("${caimei.wwwDomain}")
     private String domain;
 
@@ -634,153 +637,153 @@ public class HeliPayServiceImpl implements HeliPayService {
         return openId;
     }
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void delayedSplitting(String callUrl) {
-        log.info("【延时分账】>>>>>>>>>>延时分账,每一小时执行一次");
-        Calendar calendar = Calendar.getInstance();
-        calendar.setTime(new Date());
-        //todo 测试 不减时间,现在有就分账
-        //测试查5分钟前的单
-        calendar.add(Calendar.SECOND, -5);
-//        calendar.add(Calendar.DAY_OF_MONTH, -1);
-        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
-        String currentTime = format.format(calendar.getTime());
-        // 查询未分账已支付收款      排除线上订金/充值订单
-        List<OrderReceiptRelationPo> orderRelations = payOrderMapper.getUndividedPaidReceipt(currentTime);
-        if (null != orderRelations && orderRelations.size() > 0) {
-            for (OrderReceiptRelationPo orderRelation : orderRelations) {
-                log.info("【延时分账】>>>>>>>>>>订单id:" + orderRelation.getOrderId() + "进入延时分账");
-                // 收款对应的订单信息
-                OrderVo order = orderCommonMapper.getOrderByOrderId(orderRelation.getOrderId());
-                PayParamBo payParam = new PayParamBo();
-                //支付金额
-                payParam.setPayAmount(MathUtil.mul(orderRelation.getAssociateAmount(), 100).intValue());
-                if (12 == orderRelation.getPayType()) {
-                    // 网银支付
-                    payParam.setPayWay("UNIONPAY");
-                }
-                if (17 == orderRelation.getPayType()) {
-                    //b2c网银
-                    payParam.setPayWay("B2C");
-                }
-                //微信0.65%手续费
-                if (8 == orderRelation.getPayType() || 13 == orderRelation.getPayType() || 15 == orderRelation.getPayType()) {
-                    payParam.setPayWay("WX");
-                }
-                List<SplitAccountPo> splitBillDetail = setSplitAccountDetail(order, payParam);
-                List<Map<String, String>> maps = new ArrayList<>();
-                List<ShopOrderVo> shopOrderList = orderCommonMapper.getShopOrderListByOrderId(order.getOrderId());
-                for (ShopOrderVo shopOrder : shopOrderList) {
-                    double shopTotalAmount = 0.00;
-                    String subUserNo = "";
-                    for (SplitAccountPo account : splitBillDetail) {
-                        //供应商有支付平台账户type=4
-                        if (null != account.getType() && 4 == account.getType() && shopOrder.getShopId().equals(account.getShopId())) {
-                            shopTotalAmount = MathUtil.add(shopTotalAmount, account.getSplitAccount()).doubleValue();
-                            subUserNo = account.getSubUserNo();
-                        }
-                    }
-//                    addMaps(maps, shopTotalAmount, subUserNo);
-                }
-                if (null == splitBillDetail || splitBillDetail.size() == 0) {
-                    log.info("无满足条件分账单号");
-                    return;
-                }
-                //公账-专票总金额,私账-无票总金额,公账-普票总金额
-                //Type2,3奥泰,1,5信息
-                //todo 正式改
-                String sp1 = "";
-                BigDecimal totalAmount1 = BigDecimal.ZERO;
-                String sp2 = "";
-                BigDecimal totalAmount2 = BigDecimal.ZERO;
-                for (SplitAccountPo account : splitBillDetail) {
-                    if (1 == account.getType() || 5 == account.getType()) {
-                        totalAmount1 = MathUtil.add(totalAmount1, account.getSplitAccount());
-                        sp1 = account.getSubUserNo();
-                    }
-                    if (2 == account.getType() || 3 == account.getType()) {
-                        totalAmount2 = MathUtil.add(totalAmount2, account.getSplitAccount());
-                        sp2 = account.getSubUserNo();
-                    }
-                }
-                ArrayList<AccountPayOrder.AccountPayOrderExt.SplitBillRule> splitBillRules = new ArrayList<>();
-                if (MathUtil.compare(totalAmount1, 0.01) > 0) {
-                    AccountPayOrder.AccountPayOrderExt.SplitBillRule splitBillRule = new AccountPayOrder.AccountPayOrderExt.SplitBillRule();
-                    splitBillRule.setSplitBillAmount(totalAmount1);
-                    splitBillRule.setSplitBillMerchantNo(sp1);
-                    splitBillRules.add(splitBillRule);
-                }
-                if (MathUtil.compare(totalAmount2, 0.01) > 0) {
-                    AccountPayOrder.AccountPayOrderExt.SplitBillRule splitBillRule = new AccountPayOrder.AccountPayOrderExt.SplitBillRule();
-                    splitBillRule.setSplitBillAmount(totalAmount2);
-                    splitBillRule.setSplitBillMerchantNo(sp2);
-                    splitBillRules.add(splitBillRule);
-                }
-                //第三方分账接口
-                try {
-                    AccountPayOrder accountPayOrder = new AccountPayOrder();
-                    accountPayOrder.setP1_bizType("AccountPaySub");
-                    accountPayOrder.setP2_signType("MD5");
-                    String format1 = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss.SSS").format(new Date());
-                    accountPayOrder.setP3_timestamp(format1);
-                    String substring = format1.substring(20);
-                    // fz+当前微秒时间+原唯一订单号
-                    accountPayOrder.setP4_orderId("FZ" + substring + orderRelation.getOrderRequestNo());
-                    //todo 付款账户商编暂用网络
-                    accountPayOrder.setP5_customerNumber(Constant.CUSTOMERNUM2);
-                    AccountPayOrder.AccountPayOrderExt accountPayOrderExt = new AccountPayOrder.AccountPayOrderExt();
-                    //收款账户商编  填写splitBillRules时候不填写MerchantNo,Amount并且即使填写这两个参数不生效!!
-//                    accountPayOrderExt.setInMerchantNo(splitMoneyVo.getName());
-                    accountPayOrderExt.setOrderType(AccountPayOrderType.TRANSFER);
-//                    accountPayOrderExt.setAmount(splitMoneyVo.getSplitMoney());
-                    accountPayOrderExt.setServerCallbackUrl(callUrl);
-                    accountPayOrderExt.setGoodsName("分账");
-
-                    if (null != splitBillRules && splitBillRules.size() > 0) {
-                        accountPayOrderExt.setSplitBillRules(splitBillRules);
-                    }
-                    String ext = JSON.toJSONString(accountPayOrderExt);
-                    log.info("分账规则串json串:" + ext);
-                    accountPayOrder.setP6_ext(ext);
-                    // 生成签名
-                    StringBuilder builder = new StringBuilder();
-                    builder.append(SPLIT)
-                            .append(accountPayOrder.getP1_bizType()).append(SPLIT)
-                            .append(accountPayOrder.getP2_signType()).append(SPLIT)
-                            .append(accountPayOrder.getP3_timestamp()).append(SPLIT)
-                            .append(accountPayOrder.getP4_orderId()).append(SPLIT)
-                            .append(accountPayOrder.getP5_customerNumber()).append(SPLIT)
-                            .append(accountPayOrder.getP6_ext()).append(SPLIT)
-                            .append(XUNI);
-                    String sign = Disguiser.disguiseMD5(builder.toString().trim());
-                    Map<String, String> bean = convertBean(accountPayOrder);
-                    log.info("--------------------> 发送分账参数:  " + bean);
-                    Map<String, String> map = postForm(bean, Constant.FZ, sign, Map.class);
-                    log.info("----------------分账返回数据: " + map.toString());
-                    if (map != null) {
-                        String code = map.get("rt5_retCode");
-                        if (!"0000".equals(code)) {
-                            String msg = map.get("rt6_retMsg");
-                            log.info("【延时分账】>>>>>>>>>>第三方延迟分账失败>>>>>>>msg:" + msg);
-                        } else {
-                            for (SplitAccountPo splitAccount : splitBillDetail) {
-                                splitAccount.setMbOrderId(orderRelation.getMbOrderId());
-                                splitAccount.setOrderRequestNo(substring + orderRelation.getOrderRequestNo());
-                                splitAccount.setPayStatus(1);
-                                // 保存分账详情
-                                payOrderMapper.insertSplitAccount(splitAccount);
-                            }
-                            log.info("【延时分账】>>>>>>>>>>此订单分账结束");
-                        }
-                    }
-                } catch (Exception e) {
-                    log.error("【延时分账】>>>>>>>>>>错误信息", e);
-                }
-
-            }
-        }
-    }
+//    @Override
+//    @Transactional(rollbackFor = Exception.class)
+//    public void delayedSplitting(String callUrl) {
+//        log.info("【延时分账】>>>>>>>>>>延时分账,每一小时执行一次");
+//        Calendar calendar = Calendar.getInstance();
+//        calendar.setTime(new Date());
+//        //todo 测试 不减时间,现在有就分账
+//        //测试查5分钟前的单
+//        calendar.add(Calendar.SECOND, -5);
+////        calendar.add(Calendar.DAY_OF_MONTH, -1);
+//        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//        String currentTime = format.format(calendar.getTime());
+//        // 查询未分账已支付收款      排除线上订金/充值订单
+//        List<OrderReceiptRelationPo> orderRelations = payOrderMapper.getUndividedPaidReceipt(currentTime);
+//        if (null != orderRelations && orderRelations.size() > 0) {
+//            for (OrderReceiptRelationPo orderRelation : orderRelations) {
+//                log.info("【延时分账】>>>>>>>>>>订单id:" + orderRelation.getOrderId() + "进入延时分账");
+//                // 收款对应的订单信息
+//                OrderVo order = orderCommonMapper.getOrderByOrderId(orderRelation.getOrderId());
+//                PayParamBo payParam = new PayParamBo();
+//                //支付金额
+//                payParam.setPayAmount(MathUtil.mul(orderRelation.getAssociateAmount(), 100).intValue());
+//                if (12 == orderRelation.getPayType()) {
+//                    // 网银支付
+//                    payParam.setPayWay("UNIONPAY");
+//                }
+//                if (17 == orderRelation.getPayType()) {
+//                    //b2c网银
+//                    payParam.setPayWay("B2C");
+//                }
+//                //微信0.65%手续费
+//                if (8 == orderRelation.getPayType() || 13 == orderRelation.getPayType() || 15 == orderRelation.getPayType()) {
+//                    payParam.setPayWay("WX");
+//                }
+//                List<SplitAccountPo> splitBillDetail = setSplitAccountDetail(order, payParam);
+//                List<Map<String, String>> maps = new ArrayList<>();
+//                List<ShopOrderVo> shopOrderList = orderCommonMapper.getShopOrderListByOrderId(order.getOrderId());
+//                for (ShopOrderVo shopOrder : shopOrderList) {
+//                    double shopTotalAmount = 0.00;
+//                    String subUserNo = "";
+//                    for (SplitAccountPo account : splitBillDetail) {
+//                        //供应商有支付平台账户type=4
+//                        if (null != account.getType() && 4 == account.getType() && shopOrder.getShopId().equals(account.getShopId())) {
+//                            shopTotalAmount = MathUtil.add(shopTotalAmount, account.getSplitAccount()).doubleValue();
+//                            subUserNo = account.getSubUserNo();
+//                        }
+//                    }
+////                    addMaps(maps, shopTotalAmount, subUserNo);
+//                }
+//                if (null == splitBillDetail || splitBillDetail.size() == 0) {
+//                    log.info("无满足条件分账单号");
+//                    return;
+//                }
+//                //公账-专票总金额,私账-无票总金额,公账-普票总金额
+//                //Type2,3奥泰,1,5信息
+//                //todo 正式改
+//                String sp1 = "";
+//                BigDecimal totalAmount1 = BigDecimal.ZERO;
+//                String sp2 = "";
+//                BigDecimal totalAmount2 = BigDecimal.ZERO;
+//                for (SplitAccountPo account : splitBillDetail) {
+//                    if (1 == account.getType() || 5 == account.getType()) {
+//                        totalAmount1 = MathUtil.add(totalAmount1, account.getSplitAccount());
+//                        sp1 = account.getSubUserNo();
+//                    }
+//                    if (2 == account.getType() || 3 == account.getType()) {
+//                        totalAmount2 = MathUtil.add(totalAmount2, account.getSplitAccount());
+//                        sp2 = account.getSubUserNo();
+//                    }
+//                }
+//                ArrayList<AccountPayOrder.AccountPayOrderExt.SplitBillRule> splitBillRules = new ArrayList<>();
+//                if (MathUtil.compare(totalAmount1, 0.01) > 0) {
+//                    AccountPayOrder.AccountPayOrderExt.SplitBillRule splitBillRule = new AccountPayOrder.AccountPayOrderExt.SplitBillRule();
+//                    splitBillRule.setSplitBillAmount(totalAmount1);
+//                    splitBillRule.setSplitBillMerchantNo(sp1);
+//                    splitBillRules.add(splitBillRule);
+//                }
+//                if (MathUtil.compare(totalAmount2, 0.01) > 0) {
+//                    AccountPayOrder.AccountPayOrderExt.SplitBillRule splitBillRule = new AccountPayOrder.AccountPayOrderExt.SplitBillRule();
+//                    splitBillRule.setSplitBillAmount(totalAmount2);
+//                    splitBillRule.setSplitBillMerchantNo(sp2);
+//                    splitBillRules.add(splitBillRule);
+//                }
+//                //第三方分账接口
+//                try {
+//                    AccountPayOrder accountPayOrder = new AccountPayOrder();
+//                    accountPayOrder.setP1_bizType("AccountPaySub");
+//                    accountPayOrder.setP2_signType("MD5");
+//                    String format1 = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss.SSS").format(new Date());
+//                    accountPayOrder.setP3_timestamp(format1);
+//                    String substring = format1.substring(20);
+//                    // fz+当前微秒时间+原唯一订单号
+//                    accountPayOrder.setP4_orderId("FZ" + substring + orderRelation.getOrderRequestNo());
+//                    //todo 付款账户商编暂用网络
+//                    accountPayOrder.setP5_customerNumber(Constant.CUSTOMERNUM2);
+//                    AccountPayOrder.AccountPayOrderExt accountPayOrderExt = new AccountPayOrder.AccountPayOrderExt();
+//                    //收款账户商编  填写splitBillRules时候不填写MerchantNo,Amount并且即使填写这两个参数不生效!!
+////                    accountPayOrderExt.setInMerchantNo(splitMoneyVo.getName());
+//                    accountPayOrderExt.setOrderType(AccountPayOrderType.TRANSFER);
+////                    accountPayOrderExt.setAmount(splitMoneyVo.getSplitMoney());
+//                    accountPayOrderExt.setServerCallbackUrl(callUrl);
+//                    accountPayOrderExt.setGoodsName("分账");
+//
+//                    if (null != splitBillRules && splitBillRules.size() > 0) {
+//                        accountPayOrderExt.setSplitBillRules(splitBillRules);
+//                    }
+//                    String ext = JSON.toJSONString(accountPayOrderExt);
+//                    log.info("分账规则串json串:" + ext);
+//                    accountPayOrder.setP6_ext(ext);
+//                    // 生成签名
+//                    StringBuilder builder = new StringBuilder();
+//                    builder.append(SPLIT)
+//                            .append(accountPayOrder.getP1_bizType()).append(SPLIT)
+//                            .append(accountPayOrder.getP2_signType()).append(SPLIT)
+//                            .append(accountPayOrder.getP3_timestamp()).append(SPLIT)
+//                            .append(accountPayOrder.getP4_orderId()).append(SPLIT)
+//                            .append(accountPayOrder.getP5_customerNumber()).append(SPLIT)
+//                            .append(accountPayOrder.getP6_ext()).append(SPLIT)
+//                            .append(XUNI);
+//                    String sign = Disguiser.disguiseMD5(builder.toString().trim());
+//                    Map<String, String> bean = convertBean(accountPayOrder);
+//                    log.info("--------------------> 发送分账参数:  " + bean);
+//                    Map<String, String> map = postForm(bean, Constant.FZ, sign, Map.class);
+//                    log.info("----------------分账返回数据: " + map.toString());
+//                    if (map != null) {
+//                        String code = map.get("rt5_retCode");
+//                        if (!"0000".equals(code)) {
+//                            String msg = map.get("rt6_retMsg");
+//                            log.info("【延时分账】>>>>>>>>>>第三方延迟分账失败>>>>>>>msg:" + msg);
+//                        } else {
+//                            for (SplitAccountPo splitAccount : splitBillDetail) {
+//                                splitAccount.setMbOrderId(orderRelation.getMbOrderId());
+//                                splitAccount.setOrderRequestNo(substring + orderRelation.getOrderRequestNo());
+//                                splitAccount.setPayStatus(1);
+//                                // 保存分账详情
+//                                payOrderMapper.insertSplitAccount(splitAccount);
+//                            }
+//                            log.info("【延时分账】>>>>>>>>>>此订单分账结束");
+//                        }
+//                    }
+//                } catch (Exception e) {
+//                    log.error("【延时分账】>>>>>>>>>>错误信息", e);
+//                }
+//
+//            }
+//        }
+//    }
 
     @Override
     public String delayedSplittingCallback(AccountResVo data) {
@@ -1747,6 +1750,69 @@ public class HeliPayServiceImpl implements HeliPayService {
         return ResponseJson.success(banks);
     }
 
+    @Override
+    public String refundSplittingCallback(AccountResVo data) {
+        log.info("网银退款分账异步回调参数-------------------》 " + data.toString());
+        try {
+            String oriMessage = MyBeanUtils.getSigned(data, null);
+            oriMessage = oriMessage + SPLIT + XUNI;
+            String checkSign = Disguiser.disguiseMD5(oriMessage.trim());
+            log.info("网银退款回调签名 :" + data.getSign());
+            log.info("checkSign : " + checkSign);
+            if (!checkSign.equals(data.getSign())) {
+                log.info("网银退款分账异步回调验签失败------------------");
+                return "验签失败";
+            }
+            // wytk+sss + orderRequestNo
+            String orderRequestNo = data.getRt7_orderId().substring(7);
+            String status = data.getRt10_orderStatus();
+            log.info("【网银退款分账回调】>>>>>>>>>>分账状态:" + status);
+            if (!"SUCCESS".equals(status)) {
+                return "分账失败";
+            }
+            OrderReceiptRelationPo po = refundMapper.findOrderRelationByNo(orderRequestNo);
+            // 网银退款
+            Map<String, String> sPara = new HashMap<String, String>();
+            sPara.put("P1_bizType", "OnlineRefund");
+            sPara.put("P2_orderId", orderRequestNo);
+            sPara.put("P3_customerNumber", po.getSplitCode());
+            sPara.put("P4_refundAmount", po.getAssociateAmount().toString());
+            sPara.put("P5_refundOrderId", "TK" + orderRequestNo);
+            sPara.put("P6_desc", "无");
+            sPara.put("P7_serverCallbackUrl", "");
+            StringBuffer sb = new StringBuffer();
+            sb.append("&").append("OnlineRefund").append("&").append(orderRequestNo).append("&").append(po.getSplitCode()).append("&").
+                    append(po.getAssociateAmount().toString()).append("&").append("TK" + orderRequestNo).append("&").append("无").append("&").append("&").append(Constant.WANGYIN);
+            String sign = Disguiser.disguiseMD5(sb.toString());
+            sPara.put("sign", sign);
+            OnlineRefundData on = OnlinePostFormUtil.refundPostForm(sPara, Constant.YL, sign, OnlineRefundData.class);
+            if (!"0000".equals(on.getRt2_retCode())) {
+                log.info("网银退款失败:" + on.toString());
+                return "分账失败";
+            } else {
+                String assemblyRespOriSign = MyBeanUtils.getSignedByPresetParameter(on, OnlineRefundData.NEED_SIGN_PARAMS);
+                log.info("组装返回结果签名串:" + assemblyRespOriSign);
+                assemblyRespOriSign += Constant.SPLIT + Constant.WANGYIN;
+                String backSign = Disguiser.disguiseMD5(assemblyRespOriSign.trim());
+                if (!backSign.equals(on.getSign())) {
+                    log.error("网银退款验签失败========================" + on.getRt3_retMsg());
+                    return "分账失败";
+                } else {
+                    CmRefundRecord cmRefundRecord = new CmRefundRecord();
+                    cmRefundRecord.setRefundAmount(Double.parseDouble(po.getAssociateAmount().toString()));
+                    cmRefundRecord.setOrderRequestNo(orderRequestNo);
+                    cmRefundRecord.setShopOrderId(po.getShopOrderId());
+                    refundMapper.insertCmRefundRecord(cmRefundRecord);
+                    log.info("网银退款成功");
+                }
+            }
+        } catch (Exception e) {
+            log.error("【网银退款手续费转账失败】>>>>>>>>>>网银退款分账异常", e);
+            return "分账失败";
+        }
+        return "SUCCESS";
+    }
+
     public static <T> T postForm(Map<String, String> params, String url, String sign, Class<T> clazz) {
         FormBody.Builder builder = new FormBody.Builder();
         for (Map.Entry<String, String> entry : params.entrySet()) {

+ 62 - 36
src/main/java/com/caimei365/order/service/impl/OrderRefundServiceImpl.java

@@ -1,5 +1,6 @@
 package com.caimei365.order.service.impl;
 
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.caimei365.order.components.OnlinePostFormUtil;
 import com.caimei365.order.constant.Constant;
@@ -7,9 +8,11 @@ import com.caimei365.order.mapper.BaseMapper;
 import com.caimei365.order.mapper.OrderRefundMapper;
 import com.caimei365.order.mapper.PayOrderMapper;
 import com.caimei365.order.model.ResponseJson;
+import com.caimei365.order.model.enums.AccountPayOrderType;
 import com.caimei365.order.model.po.*;
 import com.caimei365.order.model.vo.*;
 import com.caimei365.order.service.OrderRefundService;
+import com.caimei365.order.utils.MathUtil;
 import com.caimei365.order.utils.helipay.Disguiser;
 import com.caimei365.order.utils.helipay.HttpClientService;
 import com.caimei365.order.utils.helipay.MessageHandle;
@@ -21,6 +24,7 @@ import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.math.BigDecimal;
 import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.concurrent.atomic.AtomicReference;
@@ -202,7 +206,12 @@ public class OrderRefundServiceImpl implements OrderRefundService {
          *   其他
          */
         if (12 == relationPo.getPayType() || 17 == relationPo.getPayType()) {
-            unionRefund(relationPo.getOrderRequestNo(), relationPo.getAssociateAmount().toString(), relationPo.getShopOrderId(), splitCode);
+            /** todo
+             *  网银退款此处只是发起手续费退回分账请求,如果本次退款中包含网银退款,应该直接return方法,在发起分账请求回调中
+             *  继续退款方法中的其他操作,当前版本暂不考虑失败,默认转账成功
+             */
+            BigDecimal charge = 12 == relationPo.getPayType() ? BigDecimal.valueOf(10) : MathUtil.mul(relationPo.getAssociateAmount(), 0.002, 2);
+            unionRefund(relationPo.getOrderRequestNo(), charge, relationPo.getShopOrderId(), splitCode);
         } else if (29 == relationPo.getPayType() || 30 == relationPo.getPayType()) {
             quickRefund(relationPo, splitCode);
         } else {
@@ -236,44 +245,61 @@ public class OrderRefundServiceImpl implements OrderRefundService {
 
     /**
      * attention:网银退款不退手续费!
-     * 1.本方法内转账手续费等待到账再发起退款请求  todo 暂未转
-     * 2.异步
-     * 3.回调
+     * 本方法内转账手续费等待到账再发起退款请求
+     * 本方法内仅发起向申请退款账户的分账请求,手续费分账给申请账户后,在回调接口中,再进行网银退款
      */
     @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
-    public void unionRefund(String orderRequestNo, String money, Integer shopOrderId, String splitCode) throws Exception {
-        Map<String, String> sPara = new HashMap<String, String>();
-        sPara.put("P1_bizType", "OnlineRefund");
-        sPara.put("P2_orderId", orderRequestNo);
-        sPara.put("P3_customerNumber", splitCode);
-        sPara.put("P4_refundAmount", money);
-        sPara.put("P5_refundOrderId", "TK" + orderRequestNo);
-        sPara.put("P6_desc", "无");
-        sPara.put("P7_serverCallbackUrl", "");
-        StringBuffer sb = new StringBuffer();
-        sb.append("&").append("OnlineRefund").append("&").append(orderRequestNo).append("&").append(splitCode).append("&").
-                append(money).append("&").append("TK" + orderRequestNo).append("&").append("无").append("&").append("&").append(Constant.WANGYIN);
-        String sign = Disguiser.disguiseMD5(sb.toString());
-        sPara.put("sign", sign);
-        OnlineRefundData on = OnlinePostFormUtil.refundPostForm(sPara, Constant.YL, sign, OnlineRefundData.class);
-        if (!"0000".equals(on.getRt2_retCode())) {
-            log.info("网银退款失败:" + on.toString());
-            throw new Exception("网银退款失败");
-        } else {
-            String assemblyRespOriSign = MyBeanUtils.getSignedByPresetParameter(on, OnlineRefundData.NEED_SIGN_PARAMS);
-            log.info("组装返回结果签名串:" + assemblyRespOriSign);
-            assemblyRespOriSign += Constant.SPLIT + Constant.WANGYIN;
-            String checkSign = Disguiser.disguiseMD5(assemblyRespOriSign.trim());
-            if (!checkSign.equals(on.getSign())) {
-                log.error("网银退款验签失败========================" + on.getRt3_retMsg());
-                throw new Exception("网银退款验签失败!");
+    public void unionRefund(String orderRequestNo, BigDecimal money, Integer shopOrderId, String splitCode) {
+
+        ArrayList<AccountPayOrder.AccountPayOrderExt.SplitBillRule> splitBillRules = new ArrayList<>();
+        AccountPayOrder.AccountPayOrderExt.SplitBillRule splitBillRule = new AccountPayOrder.AccountPayOrderExt.SplitBillRule();
+        splitBillRule.setSplitBillAmount(money);
+        splitBillRule.setSplitBillMerchantNo(splitCode);
+        splitBillRules.add(splitBillRule);
+
+        AccountPayOrder accountPayOrder = new AccountPayOrder();
+        accountPayOrder.setP1_bizType("AccountPaySub");
+        accountPayOrder.setP2_signType("MD5");
+        String format1 = new SimpleDateFormat("yyyy-MM-dd_HH:mm:ss.SSS").format(new Date());
+        accountPayOrder.setP3_timestamp(format1);
+        String substring = format1.substring(20);
+        // fz+当前微秒时间+原唯一订单号
+        accountPayOrder.setP4_orderId("WYTK" + substring + orderRequestNo);
+        // 付款账户子订单绑定商户号
+        accountPayOrder.setP5_customerNumber(Constant.CUSTOMERNUM2);
+        AccountPayOrder.AccountPayOrderExt accountPayOrderExt = new AccountPayOrder.AccountPayOrderExt();
+        accountPayOrderExt.setOrderType(AccountPayOrderType.TRANSFER);
+        // 分账回调地址,此处重写一个接口,做网银退款专用,收到回调后,再接口中再进行网银的退款
+        accountPayOrderExt.setServerCallbackUrl(Constant.prodWYREFUND);
+        accountPayOrderExt.setGoodsName("网银手续费");
+        accountPayOrderExt.setSplitBillRules(splitBillRules);
+
+        String ext = JSON.toJSONString(accountPayOrderExt);
+        log.info("网银退款手续费分账规则串json串:" + ext);
+        accountPayOrder.setP6_ext(ext);
+        // 生成签名
+        StringBuilder builder = new StringBuilder();
+        builder.append(Constant.SPLIT)
+                .append(accountPayOrder.getP1_bizType()).append(Constant.SPLIT)
+                .append(accountPayOrder.getP2_signType()).append(Constant.SPLIT)
+                .append(accountPayOrder.getP3_timestamp()).append(Constant.SPLIT)
+                .append(accountPayOrder.getP4_orderId()).append(Constant.SPLIT)
+                .append(accountPayOrder.getP5_customerNumber()).append(Constant.SPLIT)
+                .append(accountPayOrder.getP6_ext()).append(Constant.SPLIT)
+                .append(Constant.XUNI);
+        String sign = Disguiser.disguiseMD5(builder.toString().trim());
+        Map<String, String> bean = OnlinePostFormUtil.splitConvertBean(accountPayOrder);
+        log.info("--------------------> 网银退款-手续费转账 参数:  " + bean);
+        Map<String, String> map = OnlinePostFormUtil.splitPostForm(bean, Constant.FZ, sign, Map.class);
+        log.info("----------------网银退款-手续费转账 返回数据: " + map.toString());
+        if (map != null) {
+            String code = map.get("rt5_retCode");
+            if (!"0000".equals(code)) {
+                String msg = map.get("rt6_retMsg");
+                log.info("【网银退款-手续费转账】>>>>>>>>>>网银退款手续费转账失败>>>>>>>msg:" + msg);
             } else {
-                CmRefundRecord cmRefundRecord = new CmRefundRecord();
-                cmRefundRecord.setRefundAmount(Double.parseDouble(money));
-                cmRefundRecord.setOrderRequestNo(orderRequestNo);
-                cmRefundRecord.setShopOrderId(shopOrderId);
-                refundMapper.insertCmRefundRecord(cmRefundRecord);
-                log.info("网银退款成功");
+                refundMapper.insertTransfer(money, orderRequestNo, shopOrderId);
+                log.info("【网银退款-手续费转账】>>>>>>>>>>网银退款手续费转账发起成功>>>>>>>");
             }
         }
     }

+ 13 - 1
src/main/resources/mapper/OrderRefundMapper.xml

@@ -84,6 +84,11 @@
              WHERE shopOrderId = #{shopOrderId})
     </insert>
 
+    <insert id="insertTransfer">
+        insert into cm_refund_transfer(transferType, transferTime, transferAmount, orderRequestNo, shopOrderId)
+        values (1, now(), #{money}, #{orderRequestNo}, #{shopOrderId})
+    </insert>
+
     <update id="updateSecondProduct">
         UPDATE cm_second_hand_detail
         SET sold = 0
@@ -236,7 +241,14 @@
         select count(*)
         from cm_shop_order
         where refundStatus = 1
-        and orderID = #{orderId}
+          and orderID = #{orderId}
+    </select>
+
+    <select id="findOrderRelationByNo" resultType="com.caimei365.order.model.po.OrderReceiptRelationPo">
+        select cso.splitCode,cror.associateAmount,cror.orderRequestNo,cror.shopOrderId
+        from cm_receipt_order_relation cror
+        left join cm_shop_order cso on cror.shopOrderId = cso.shopOrderId
+        where cror.orderRequestNo = #{orderRequestNo}
     </select>
 
 </mapper>