|
@@ -0,0 +1,327 @@
|
|
|
+package com.caimei365.order.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.caimei365.order.components.OnlinePostFormUtil;
|
|
|
+import com.caimei365.order.constant.Constant;
|
|
|
+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.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;
|
|
|
+import com.caimei365.order.utils.helipay.MyBeanUtils;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.commons.httpclient.HttpStatus;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+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;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author zzj
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+public class OrderRefundServiceImpl implements OrderRefundService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private OrderRefundMapper refundMapper;
|
|
|
+ @Resource
|
|
|
+ private PayOrderMapper payOrderMapper;
|
|
|
+ @Resource
|
|
|
+ private BaseMapper baseMapper;
|
|
|
+
|
|
|
+
|
|
|
+ @Override
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public ResponseJson refundShopOrder(Integer shopOrderId) throws Exception {
|
|
|
+ /** todo
|
|
|
+ * 当前版本退款为原路退回,无自定义退款和部分退,仅可全退。 线上/线下/余额 三种支付方式,
|
|
|
+ * 如果线上退回,退款并改变主订单/子订单状态
|
|
|
+ * 如果线下退回,仅改变状态,不做其他处理
|
|
|
+ * 如果余额支付,退回余额,改变状态
|
|
|
+ * 所有支付方式,有采美豆使用的,一律退回采美豆,当前版本无采美豆抵扣运费,优惠券退回当前版本暂不考虑
|
|
|
+ */
|
|
|
+ OrderVo order = refundMapper.findOrder(shopOrderId);
|
|
|
+ UserVo user = refundMapper.findUser(order.getUserId());
|
|
|
+
|
|
|
+ List<OrderReceiptRelationPo> relationPos = refundMapper.findPayWays(shopOrderId);
|
|
|
+ CmReturnedPurchase cmReturnedPurchase = new CmReturnedPurchase();
|
|
|
+ String returnNo = "T" + System.currentTimeMillis() + new Random().nextInt(1000);
|
|
|
+ cmReturnedPurchase.setReturnedNo(returnNo);
|
|
|
+
|
|
|
+ AtomicReference<Double> refundBalanceFee = new AtomicReference<>(0d);
|
|
|
+ AtomicReference<Double> refundOnlineFee = new AtomicReference<>(0d);
|
|
|
+ AtomicReference<Double> refundOfflineFee = new AtomicReference<>(0d);
|
|
|
+
|
|
|
+ for (OrderReceiptRelationPo relationPo : relationPos) {
|
|
|
+ switch (relationPo.getPayWay()) {
|
|
|
+ case 1:
|
|
|
+ returnOnline(relationPo);
|
|
|
+ refundOnlineFee.updateAndGet(v -> v + relationPo.getAssociateAmount());
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ returnOffline(relationPo, cmReturnedPurchase);
|
|
|
+ refundOfflineFee.updateAndGet(v -> v + relationPo.getAssociateAmount());
|
|
|
+ break;
|
|
|
+ case 3:
|
|
|
+ returnBalance(relationPo, cmReturnedPurchase, order);
|
|
|
+ refundBalanceFee.updateAndGet(v -> v + relationPo.getAssociateAmount());
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ throw new IllegalStateException("payWay Unexpected ------>" + relationPo.getPayWay());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 修改子订单信息
|
|
|
+ // 修改订单信息 refundType
|
|
|
+
|
|
|
+
|
|
|
+ // 二手订单交易全退,标记未售
|
|
|
+ if (1 == order.getSecondHandOrderFlag() && 7 == order.getStatus()) {
|
|
|
+ refundMapper.updateSecondProduct(shopOrderId);
|
|
|
+ }
|
|
|
+
|
|
|
+ //采美豆退款相关
|
|
|
+ if (7 == order.getStatus()) {
|
|
|
+ int userBeans = null == user.getUserBeans() ? 0 : user.getUserBeans();
|
|
|
+ /** todo
|
|
|
+ * 抵扣运费需退回,当前版本暂取消抵扣运费
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 1.下单赠送采美豆回收
|
|
|
+ * 2.下单扣除采美豆返回
|
|
|
+ */
|
|
|
+ Integer num = refundMapper.findByBeansType(order.getOrderId());
|
|
|
+ if (num != null && num > 0) {
|
|
|
+ UserBeansHistoryPo beansHistory = new UserBeansHistoryPo();
|
|
|
+ beansHistory.setBeansType(11);
|
|
|
+ beansHistory.setType(2);
|
|
|
+ beansHistory.setNum(num);
|
|
|
+ beansHistory.setPushStatus(0);
|
|
|
+ baseMapper.insertBeansHistory(beansHistory);
|
|
|
+ userBeans = userBeans - num;
|
|
|
+ user.setUserBeans(userBeans);
|
|
|
+ }
|
|
|
+ //订单低于1000扣500豆子退回
|
|
|
+ if (order.getPayTotalFee() != null && order.getPayTotalFee() < 1000) {
|
|
|
+ // 查本单是否扣豆子,所有子订单全退的情况下,有就返回
|
|
|
+ UserBeansHistoryPo bean = refundMapper.findLowOrder(order.getOrderId());
|
|
|
+ if (bean != null) {
|
|
|
+ //有扣豆子记录
|
|
|
+ UserBeansHistoryPo beanHistory = new UserBeansHistoryPo();
|
|
|
+ beanHistory.setUserId(order.getUserId());
|
|
|
+ beanHistory.setOrderId(order.getOrderId());
|
|
|
+ beanHistory.setBeansType(16);
|
|
|
+ beanHistory.setType(1);
|
|
|
+ beanHistory.setNum(500);
|
|
|
+ beanHistory.setPushStatus(0);
|
|
|
+ beanHistory.setAddTime(new Date());
|
|
|
+ baseMapper.insertBeansHistory(beanHistory);
|
|
|
+ user.setUserBeans(user.getUserBeans() + 500);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 修改user信息
|
|
|
+
|
|
|
+ return ResponseJson.success();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public void returnOnline(OrderReceiptRelationPo relationPo) throws Exception {
|
|
|
+ String splitCode = payOrderMapper.getSplitCodeByShopOrderId(relationPo.getShopOrderId());
|
|
|
+ /** 网银
|
|
|
+ * 快捷
|
|
|
+ * 其他
|
|
|
+ */
|
|
|
+ if (12 == relationPo.getPayType() || 17 == relationPo.getPayType()) {
|
|
|
+ unionRefund(relationPo.getOrderRequestNo(), relationPo.getAssociateAmount().toString(), relationPo.getShopOrderId(), splitCode);
|
|
|
+ } else if (29 == relationPo.getPayType() || 30 == relationPo.getPayType()) {
|
|
|
+ quickRefund(relationPo, splitCode);
|
|
|
+ } else {
|
|
|
+ onlinePay(relationPo, splitCode);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void returnOffline(OrderReceiptRelationPo relationPo, CmReturnedPurchase cmReturnedPurchase) {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ public void returnBalance(OrderReceiptRelationPo relationPo, CmReturnedPurchase cmReturnedPurchase, OrderVo order) {
|
|
|
+ //添加余额收支记录
|
|
|
+ BalanceRecordPo cmUserBalanceRecord = new BalanceRecordPo();
|
|
|
+ cmUserBalanceRecord.setUserId(order.getUserId());
|
|
|
+ cmUserBalanceRecord.setType(1);
|
|
|
+ cmUserBalanceRecord.setBalanceType(3);
|
|
|
+ cmUserBalanceRecord.setAddDate(new Date());
|
|
|
+ cmUserBalanceRecord.setAmount(relationPo.getAssociateAmount());
|
|
|
+ cmUserBalanceRecord.setOrderId(order.getOrderId());
|
|
|
+ cmUserBalanceRecord.setShopOrderId(order.getShopOrderId());
|
|
|
+ cmUserBalanceRecord.setReturnedId(cmReturnedPurchase.getId());
|
|
|
+ cmUserBalanceRecord.setDelFlag(0);
|
|
|
+ baseMapper.insertBalanceRecord(cmUserBalanceRecord);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * attention:网银退款不退手续费!
|
|
|
+ * 1.本方法内转账手续费等待到账再发起退款请求 todo 暂未转
|
|
|
+ * 2.异步
|
|
|
+ * 3.回调
|
|
|
+ */
|
|
|
+ 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("网银退款验签失败!");
|
|
|
+ } else {
|
|
|
+ CmRefundRecord cmRefundRecord = new CmRefundRecord();
|
|
|
+ cmRefundRecord.setRefundAmount(Double.parseDouble(money));
|
|
|
+ cmRefundRecord.setOrderRequestNo(orderRequestNo);
|
|
|
+ cmRefundRecord.setShopOrderId(shopOrderId);
|
|
|
+ refundMapper.insertCmRefundRecord(cmRefundRecord);
|
|
|
+ log.info("网银退款成功");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void onlinePay(OrderReceiptRelationPo relationPo, String splitCode) throws Exception {
|
|
|
+ AppPayRefundOrderVo orderVo = new AppPayRefundOrderVo();
|
|
|
+ orderVo.setP1_bizType("AppPayRefund");
|
|
|
+ orderVo.setP3_customerNumber(splitCode);
|
|
|
+ //退款原单号
|
|
|
+ orderVo.setP2_orderId(relationPo.getOrderRequestNo());
|
|
|
+ //自定义退款单号
|
|
|
+ String tk = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
|
|
|
+ orderVo.setP4_refundOrderId("TK" + tk + relationPo.getOrderRequestNo());
|
|
|
+ //退款金额
|
|
|
+ orderVo.setP5_amount(relationPo.getAssociateAmount().toString());
|
|
|
+ Map<String, String> map = MyBeanUtils.convertBean(orderVo, new LinkedHashMap());
|
|
|
+ String oriMessage = MyBeanUtils.getSignedByPresetParameter(map, AppPayRefundOrderVo.NEED_SIGN_PARAMS);
|
|
|
+ oriMessage += Constant.SAOMA;
|
|
|
+ String sign = Disguiser.disguiseMD5(oriMessage.trim());
|
|
|
+ log.info("签名串:" + sign);
|
|
|
+ map.put("sign", sign);
|
|
|
+ log.info("发送参数:" + map);
|
|
|
+ Map<String, Object> resultMap = HttpClientService.getHttpResp(map, Constant.REQUEST_URL);
|
|
|
+ log.info("响应结果:" + resultMap);
|
|
|
+ if ((Integer) resultMap.get("statusCode") == HttpStatus.SC_OK) {
|
|
|
+ String resultMsg = (String) resultMap.get("response");
|
|
|
+ AppPayRefundOrderResponseVo orderResponseVo = JSONObject.parseObject(resultMsg, AppPayRefundOrderResponseVo.class);
|
|
|
+ String assemblyRespOriSign = MyBeanUtils.getSignedByPresetParameter(orderResponseVo, AppPayRefundOrderResponseVo.NEED_SIGN_PARAMS);
|
|
|
+ assemblyRespOriSign += Constant.SAOMA;
|
|
|
+ log.info("组装返回结果签名串:" + assemblyRespOriSign);
|
|
|
+ String responseSign = orderResponseVo.getSign();
|
|
|
+ log.info("响应签名:" + responseSign);
|
|
|
+ String checkSign = Disguiser.disguiseMD5(assemblyRespOriSign.trim());
|
|
|
+ if (checkSign.equals(responseSign)) {
|
|
|
+ if ("0001".equals(orderResponseVo.getRt2_retCode())) {
|
|
|
+ CmRefundRecord cmRefundRecord = new CmRefundRecord();
|
|
|
+ cmRefundRecord.setRefundAmount(relationPo.getAssociateAmount());
|
|
|
+ cmRefundRecord.setOrderRequestNo(relationPo.getOrderRequestNo());
|
|
|
+ cmRefundRecord.setShopOrderId(relationPo.getShopOrderId());
|
|
|
+ refundMapper.insertCmRefundRecord(cmRefundRecord);
|
|
|
+ log.info("第三方退款成功>>>>>>>shopOrderId>>>" + relationPo.getShopOrderId());
|
|
|
+ } else {
|
|
|
+ log.error("退款失败========================" + orderResponseVo.getRt5_orderId() + "-" + orderResponseVo.getRt3_retMsg());
|
|
|
+ throw new RuntimeException("第三方退款失败!");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.error("退款验签失败");
|
|
|
+ throw new RuntimeException("第三方退款验签失败!");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.error("退款请求失败");
|
|
|
+ throw new RuntimeException("第三方退款请求失败!");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void quickRefund(OrderReceiptRelationPo relationPo, String splitCode) throws Exception {
|
|
|
+ //快捷支付
|
|
|
+ QuickPaySpRefundVo quickPaySpRefundVo = new QuickPaySpRefundVo();
|
|
|
+ quickPaySpRefundVo.setP1_bizType("QuickPaySpRefund");
|
|
|
+ quickPaySpRefundVo.setP2_orderId(relationPo.getOrderRequestNo());
|
|
|
+ quickPaySpRefundVo.setP3_customerNumber(splitCode);
|
|
|
+ quickPaySpRefundVo.setP4_refundOrderId("ref" + relationPo.getOrderRequestNo());
|
|
|
+ /**
|
|
|
+ * [{ 'splitBillMerchantEmail': 'xun.zhang@caimei365.com','refundAmount': 0.12}]
|
|
|
+ */
|
|
|
+ String email = refundMapper.findSplitCodeEmail(splitCode);
|
|
|
+ String refundJson = "[{ 'splitBillMerchantEmail': '" + email + "','refundAmount': " + relationPo.getAssociateAmount() + "}]";
|
|
|
+ quickPaySpRefundVo.setP5_ruleJson(refundJson);
|
|
|
+ quickPaySpRefundVo.setP6_callbackUrl("localhost:8080/manager");
|
|
|
+ quickPaySpRefundVo.setSignatureType("SM3WITHSM2");
|
|
|
+ Map reqestMap = MessageHandle.getReqestMap(quickPaySpRefundVo);
|
|
|
+ Map<String, Object> resultMap = HttpClientService.getHttpResp(reqestMap, Constant.REQUEST_URL_QUICKPAY);
|
|
|
+ if ((Integer) resultMap.get("statusCode") != HttpStatus.SC_OK) {
|
|
|
+ log.info("-------------------快捷支付退款请求失败---------------");
|
|
|
+ throw new RuntimeException("快捷支付退款请求失败!");
|
|
|
+ } else {
|
|
|
+ String resultMsg = (String) resultMap.get("response");
|
|
|
+ QuickPaySpRefundResponseVo responseVo = JSONObject.parseObject(resultMsg, QuickPaySpRefundResponseVo.class);
|
|
|
+ log.info("--------------------->快捷支付退款json: " + JSONObject.toJSON(responseVo));
|
|
|
+ if (!MessageHandle.checkSign(responseVo)) {
|
|
|
+ log.info("---------------快捷支付退款验签失败------------------");
|
|
|
+ throw new RuntimeException("快捷支付退款验签失败!");
|
|
|
+ } else {
|
|
|
+ if ("0000".equals(responseVo.getRt2_retCode())) {
|
|
|
+ CmRefundRecord cmRefundRecord = new CmRefundRecord();
|
|
|
+ cmRefundRecord.setRefundAmount(relationPo.getAssociateAmount());
|
|
|
+ cmRefundRecord.setOrderRequestNo(relationPo.getOrderRequestNo());
|
|
|
+ cmRefundRecord.setShopOrderId(relationPo.getShopOrderId());
|
|
|
+ refundMapper.insertCmRefundRecord(cmRefundRecord);
|
|
|
+ log.info("---------------快捷支付退款成功------------------");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|