diff --git a/mallinkService/src/main/java/com/iformall/domain/po/WxRefundOrder.java b/mallinkService/src/main/java/com/iformall/domain/po/WxRefundOrder.java index 029cd6e22..ca37c4ebc 100644 --- a/mallinkService/src/main/java/com/iformall/domain/po/WxRefundOrder.java +++ b/mallinkService/src/main/java/com/iformall/domain/po/WxRefundOrder.java @@ -4,12 +4,14 @@ import com.baomidou.mybatisplus.annotation.TableName; import com.iformall.domain.po.base.TenantEntity; import lombok.Data; import lombok.EqualsAndHashCode; +import lombok.ToString; import java.util.*; @TableName(value = "wx_refund_order") @Data @EqualsAndHashCode(callSuper = true) +@ToString public class WxRefundOrder extends TenantEntity { protected Long id; diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java index a5f4e79de..13575e4f8 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxRefundOrderServiceImpl.java @@ -20,6 +20,9 @@ import com.iformall.pay.WxRefundOrderSP; import com.iformall.service.WxOrderService; import com.iformall.service.WxRefundOrderService; import com.iformall.service.helper.WxPayOrderServiceHelper; +import com.iformall.service.pay.PayServiceFactory; +import com.iformall.service.pay.entity.RefundAdapterResult; +import com.iformall.service.pay.entity.RefundNotifyAdapterResult; import com.iformall.utils.BeanUtils; import com.iformall.utils.CipherUtil; import com.iformall.utils.Utility; @@ -79,163 +82,14 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { @Autowired WxCardInfoMapper cardInfoMapper; + + @Autowired + PayServiceFactory payServiceFactory; + + - JSONObject errorRefundReqMap = JSON.parseObject("{\n" + - " \"SYSTEMERROR\": {\n" + - " \"detail\": \"接口返回错误\",\n" + - " \"reason\": \"系统超时等\",\n" + - " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + - " },\n" + - " \"BIZERR_NEED_RETRY\": {\n" + - " \"detail\": \"退款业务流程错误,需要商户触发重试来解决\",\n" + - " \"reason\": \"并发情况下,业务被拒绝,商户重试即可解决\",\n" + - " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + - " },\n" + - " \"TRADE_OVERDUE\": {\n" + - " \"detail\": \"订单已经超过退款期限\",\n" + - " \"reason\": \"订单已经超过可退款的最大期限(支付后一年内可退款)\\t\",\n" + - " \"resolution\": \"请选择其他方式自行退款\"\n" + - " },\n" + - " \"ERROR\": {\n" + - " \"detail\": \"业务错误\",\n" + - " \"reason\": \"申请退款业务发生错误\",\n" + - " \"resolution\": \"该错误都会返回具体的错误原因,请根据实际返回做相应处理。\"\n" + - " },\n" + - " \"USER_ACCOUNT_ABNORMAL\": {\n" + - " \"detail\": \"退款请求失败\",\n" + - " \"reason\": \"用户帐号注销\",\n" + - " \"resolution\": \"此状态代表退款申请失败,商户可自行处理退款。\"\n" + - " },\n" + - " \"INVALID_REQ_TOO_MUCH\": {\n" + - " \"detail\": \"无效请求过多\",\n" + - " \"reason\": \"连续错误请求数过多被系统短暂屏蔽\\t\",\n" + - " \"resolution\": \"请检查业务是否正常,确认业务正常后请在1分钟后再来重试\"\n" + - " },\n" + - " \"NOTENOUGH\": {\n" + - " \"detail\": \"余额不足\",\n" + - " \"reason\": \"商户可用退款余额不足\",\n" + - " \"resolution\": \"此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。\"\n" + - " },\n" + - " \"INVALID_TRANSACTIONID\": {\n" + - " \"detail\": \"无效transaction_id\",\n" + - " \"reason\": \"请求参数未按指引进行填写\",\n" + - " \"resolution\": \"请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败\"\n" + - " },\n" + - " \"PARAM_ERROR\": {\n" + - " \"detail\": \"参数错误\",\n" + - " \"reason\": \"请求参数未按指引进行填写\",\n" + - " \"resolution\": \"请求参数错误,请重新检查再调用退款申请\"\n" + - " },\n" + - " \"APPID_NOT_EXIST\": {\n" + - " \"detail\": \"APPID不存在\",\n" + - " \"reason\": \"参数中缺少APPID\",\n" + - " \"resolution\": \"请检查APPID是否正确\"\n" + - " },\n" + - " \"MCHID_NOT_EXIST\": {\n" + - " \"detail\": \"MCHID不存在\",\n" + - " \"reason\": \"参数中缺少MCHID\",\n" + - " \"resolution\": \"请检查MCHID是否正确\"\n" + - " },\n" + - " \"REQUIRE_POST_METHOD\": {\n" + - " \"detail\": \"请使用post方法\",\n" + - " \"reason\": \"未使用post传递参数\",\n" + - " \"resolution\": \"请检查请求参数是否通过post方法提交\"\n" + - " },\n" + - " \"SIGNERROR\": {\n" + - " \"detail\": \"签名错误\",\n" + - " \"reason\": \"参数签名结果不正确\",\n" + - " \"resolution\": \"请检查签名参数和方法是否都符合签名算法要求\"\n" + - " },\n" + - " \"XML_FORMAT_ERROR\": {\n" + - " \"detail\": \"XML格式错误\",\n" + - " \"reason\": \"XML格式错误\",\n" + - " \"resolution\": \"请检查XML参数格式是否正确\"\n" + - " },\n" + - " \"FREQUENCY_LIMITED\": {\n" + - " \"detail\": \"频率限制\",\n" + - " \"reason\": \"2个月之前的订单申请退款有频率限制\",\n" + - " \"resolution\": \"该笔退款未受理,请降低频率后重试\"\n" + - " }\n" + - "}"); - - JSONObject errorRefundQueryMap = JSON.parseObject("{\n" + - " \"SYSTEMERROR\": {\n" + - " \"detail\": \"接口返回错误\",\n" + - " \"reason\": \"系统超时等\",\n" + - " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + - " },\n" + - " \"BIZERR_NEED_RETRY\": {\n" + - " \"detail\": \"退款业务流程错误,需要商户触发重试来解决\",\n" + - " \"reason\": \"并发情况下,业务被拒绝,商户重试即可解决\",\n" + - " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + - " },\n" + - " \"TRADE_OVERDUE\": {\n" + - " \"detail\": \"订单已经超过退款期限\",\n" + - " \"reason\": \"订单已经超过可退款的最大期限(支付后一年内可退款)\\t\",\n" + - " \"resolution\": \"请选择其他方式自行退款\"\n" + - " },\n" + - " \"ERROR\": {\n" + - " \"detail\": \"业务错误\",\n" + - " \"reason\": \"申请退款业务发生错误\",\n" + - " \"resolution\": \"该错误都会返回具体的错误原因,请根据实际返回做相应处理。\"\n" + - " },\n" + - " \"USER_ACCOUNT_ABNORMAL\": {\n" + - " \"detail\": \"退款请求失败\",\n" + - " \"reason\": \"用户帐号注销\",\n" + - " \"resolution\": \"此状态代表退款申请失败,商户可自行处理退款。\"\n" + - " },\n" + - " \"INVALID_REQ_TOO_MUCH\": {\n" + - " \"detail\": \"无效请求过多\",\n" + - " \"reason\": \"连续错误请求数过多被系统短暂屏蔽\\t\",\n" + - " \"resolution\": \"请检查业务是否正常,确认业务正常后请在1分钟后再来重试\"\n" + - " },\n" + - " \"NOTENOUGH\": {\n" + - " \"detail\": \"余额不足\",\n" + - " \"reason\": \"商户可用退款余额不足\",\n" + - " \"resolution\": \"此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。\"\n" + - " },\n" + - " \"INVALID_TRANSACTIONID\": {\n" + - " \"detail\": \"无效transaction_id\",\n" + - " \"reason\": \"请求参数未按指引进行填写\",\n" + - " \"resolution\": \"请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败\"\n" + - " },\n" + - " \"PARAM_ERROR\": {\n" + - " \"detail\": \"参数错误\",\n" + - " \"reason\": \"请求参数未按指引进行填写\",\n" + - " \"resolution\": \"请求参数错误,请重新检查再调用退款申请\"\n" + - " },\n" + - " \"APPID_NOT_EXIST\": {\n" + - " \"detail\": \"APPID不存在\",\n" + - " \"reason\": \"参数中缺少APPID\",\n" + - " \"resolution\": \"请检查APPID是否正确\"\n" + - " },\n" + - " \"MCHID_NOT_EXIST\": {\n" + - " \"detail\": \"MCHID不存在\",\n" + - " \"reason\": \"参数中缺少MCHID\",\n" + - " \"resolution\": \"请检查MCHID是否正确\"\n" + - " },\n" + - " \"REQUIRE_POST_METHOD\": {\n" + - " \"detail\": \"请使用post方法\",\n" + - " \"reason\": \"未使用post传递参数\",\n" + - " \"resolution\": \"请检查请求参数是否通过post方法提交\"\n" + - " },\n" + - " \"SIGNERROR\": {\n" + - " \"detail\": \"签名错误\",\n" + - " \"reason\": \"参数签名结果不正确\",\n" + - " \"resolution\": \"请检查签名参数和方法是否都符合签名算法要求\"\n" + - " },\n" + - " \"XML_FORMAT_ERROR\": {\n" + - " \"detail\": \"XML格式错误\",\n" + - " \"reason\": \"XML格式错误\",\n" + - " \"resolution\": \"请检查XML参数格式是否正确\"\n" + - " },\n" + - " \"FREQUENCY_LIMITED\": {\n" + - " \"detail\": \"频率限制\",\n" + - " \"reason\": \"2个月之前的订单申请退款有频率限制\",\n" + - " \"resolution\": \"该笔退款未受理,请降低频率后重试\"\n" + - " }\n" + - "}"); + private boolean isMerchantOrder(WxOrder wxOrder, Long merchantId) { @@ -415,7 +269,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { record.setOrderId(rOrder.getId()); // 创建退款订单 Long refundId = idWorker.nextId(); - String out_refund_id = String.valueOf(refundId); + //String out_refund_id = String.valueOf(refundId); record.setId(refundId); record.updateTenantInfo(wxCouponOrder); @@ -428,7 +282,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { record.setRefundFee(payOrder.getPayAmount()); record.setRefundTimeStart(currentDate); record.setRefundOrderStatus(EnumRefundStatus.REFUND_WAIT.getCode()); - + record.setRefundVendor(payOrder.getPayVendor()); // 退款订单 try { int sqlRow = wxRefundOrderMapper.insert(record); @@ -441,203 +295,22 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { throw new MallinkException(ErrorCode.DB_FAIL); } - if (StringUtils.isBlank(payAccount.getApiKey())) { - logger.error("支付密钥为空"); - throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员"); - } - if (StringUtils.isBlank(payAccount.getCertPath())) { - logger.error("证书路径为空"); - throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书路径为空,请联系商城管理员"); - } - if (!Utility.isFileExist(payAccount.getCertPath())) { - logger.error("证书文件不存在"); - throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书文件不存在,请联系商城管理员"); - } // check 是否有退款订单 List refundList = wxRefundOrderMapper.findList(record); if (refundList.size() > 0) { logger.error("退款订单已存在, 无法再提交退款申请"); throw new MallinkException(ErrorCode.REFUND_ORDER_EXIST.getCode(), "退款订单已存在, 无法再提交退款申请"); } - // 实际支付 - // 向微信提交退款申请 - if (payAccount.getType() == EnumPayMode.MCH.getCode()) { - // 普通商户模式 - String noncestr = Utility.generate32UUID(); - WxRefundOrderP wxRefundOrderP = new WxRefundOrderP(); - wxRefundOrderP.setAppid(appInfo.getAppId()); - wxRefundOrderP.setMch_id(payAccount.getMchId()); - wxRefundOrderP.setNonce_str(noncestr); - // 微信内部订单号 - if (record.getTransactionId() != null) - wxRefundOrderP.setTransaction_id(record.getTransactionId()); - // 支付订单号 - wxRefundOrderP.setOut_trade_no(payOrder.getPayOrderNo()); - // 退款支付订单号 - wxRefundOrderP.setOut_refund_no(out_refund_id); - wxRefundOrderP.setTotal_fee(record.getTotalFee()); - wxRefundOrderP.setRefund_fee(record.getRefundFee()); - if (payType == EnumPayType.PAY_B_REFUND) { - wxRefundOrderP.setRefund_desc("B端商户退款"); - } else if (payType == EnumPayType.PAY_ADMIN_REFUND) { - wxRefundOrderP.setRefund_desc("管理端商户退款"); - } else if (payType == EnumPayType.PAY_AUTO_REFUND) { - wxRefundOrderP.setRefund_desc("超期自动退款"); - } else { - wxRefundOrderP.setRefund_desc("用户自己退款"); - } - wxRefundOrderP.setNotify_url(payAccount.getRefundNotifyUrl()); - - Map signMap = null; - try { - signMap = BeanUtils.toStringMap(wxRefundOrderP); - } catch (Exception e) { - logger.error("退款命令生辰: " + e.getMessage()); - throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); - } - - String signAgent = WxPayment.createSign(signMap, payAccount.getApiKey()); - signMap.put("sign", signAgent); - String response = null; - try { - response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); - } catch (Exception e) { - logger.error("退款异常: " + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); - } - logger.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString()); - Map returnMap = WxPayment.xmlToMap(response); - String result_no = returnMap.get("result_code"); - String refund_id = returnMap.get("refund_id"); - // 设置 微信退款订单号 - record.setRefundId(refund_id); - record.setRefundVendor(payOrder.getPayVendor()); - if ("SUCCESS".equals(result_no)) { - logger.info("微信退款订单申请成功: " + returnMap.toString()); - try { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } catch (Exception e) { - logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); - } - } else { - String errDesc = returnMap.get("err_code_des"); - if (errDesc.equalsIgnoreCase("订单已全额退款")) { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } - logger.error("微信退款订单申请失败: " + response); - String errMsg = ""; - JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); - if (errObj != null) { - errMsg = errObj.toJSONString(); - record.setFailReason(errMsg); - } else { - errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); - } - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode()); - wxRefundOrderMapper.updateById(record); - if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { - // 更新券状态 - throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); - } - return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap); - } - } else { - // 服务商模式 - String noncestr = Utility.generate32UUID(); - WxRefundOrderSP wxRefundOrderSP = new WxRefundOrderSP(); - wxRefundOrderSP.setAppid(appInfo.getParentAppId()); - wxRefundOrderSP.setSub_appid(appInfo.getAppId()); - wxRefundOrderSP.setMch_id(payAccount.getMchId()); - wxRefundOrderSP.setSub_mch_id(payAccount.getSubMchId()); - wxRefundOrderSP.setNonce_str(noncestr); - // 微信内部订单号 - if (record.getTransactionId() != null) - wxRefundOrderSP.setTransaction_id(record.getTransactionId()); - // 支付订单号 - wxRefundOrderSP.setOut_trade_no(payOrder.getPayOrderNo()); - // 退款支付订单号 - wxRefundOrderSP.setOut_refund_no(out_refund_id); - wxRefundOrderSP.setTotal_fee(record.getTotalFee()); - wxRefundOrderSP.setRefund_fee(record.getRefundFee()); - if (payType == EnumPayType.PAY_B_REFUND) { - wxRefundOrderSP.setRefund_desc("B端商户退款"); - } else if (payType == EnumPayType.PAY_ADMIN_REFUND) { - wxRefundOrderSP.setRefund_desc("管理端商户退款"); - } else if (payType == EnumPayType.PAY_AUTO_REFUND) { - wxRefundOrderSP.setRefund_desc("超期自动退款"); - } else { - wxRefundOrderSP.setRefund_desc("用户自己退款"); - } - wxRefundOrderSP.setNotify_url(payAccount.getRefundNotifyUrl()); - wxRefundOrderSP.setSign_type("HMAC-SHA256"); - - Map signMap = null; - try { - signMap = BeanUtils.toStringMap(wxRefundOrderSP); - } catch (Exception e) { - logger.error("退款命令生成: " + e.getMessage()); - throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); - } - - String signAgent = WxPayment.createSignHMAC(signMap, payAccount.getApiKey()); - signMap.put("sign", signAgent); - String response = null; - try { - response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); - } catch (Exception e) { - logger.error("退款异常: " + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); - } - logger.info("微信退款订单:" + wxRefundOrderSP.toString() + ", response: " + response.toString()); - Map returnMap = WxPayment.xmlToMap(response); - String result_no = returnMap.get("result_code"); - String refund_id = returnMap.get("refund_id"); - // 设置 微信退款订单号 - record.setRefundId(refund_id); - record.setRefundVendor(payOrder.getPayVendor()); - if ("SUCCESS".equals(result_no)) { - logger.info("微信退款订单申请成功: " + returnMap.toString()); - try { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } catch (Exception e) { - logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "订单状态更新失败"); - } - } else { - // 特殊处理 - String errDesc = returnMap.get("err_code_des"); - if (errDesc.equalsIgnoreCase("订单已全额退款")) { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } - logger.error("微信退款订单申请失败: " + response); - String errMsg = ""; - JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); - if (errObj != null) { - errMsg = errObj.toJSONString(); - record.setFailReason(errMsg); - } else { - errMsg = returnMap.get("err_code_des"); - record.setFailReason(errMsg); - } - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode()); - wxRefundOrderMapper.updateById(record); - if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { - // 更新券状态 - throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); - } - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg); - } + + RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor()).refund(payAccount, appInfo, record, payOrder, payType); + if (refundResult.isSuccess()) { + record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); + wxRefundOrderMapper.updateById(record); + return new ResultData(Result.SUCCESS, "退款订单申请成功", refundResult.getData()); + }else { + throw new MallinkException(refundResult.getCode(), refundResult.getMsg()); } + } @Override @@ -725,7 +398,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { record.setOrderId(rOrder.getId()); // 创建退款订单 Long refundId = idWorker.nextId(); - String out_refund_id = String.valueOf(refundId); + //String out_refund_id = String.valueOf(refundId); record.setId(refundId); record.updateTenantInfo(wxOrder); @@ -738,6 +411,7 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { record.setRefundFee(payOrder.getPayAmount()); record.setRefundTimeStart(currentDate); record.setRefundOrderStatus(EnumRefundStatus.REFUND_WAIT.getCode()); + record.setRefundVendor(payOrder.getPayVendor()); // 退款订单 try { @@ -750,202 +424,24 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { logger.error("退款订单数据库插入出错: " + record.toString()); throw new MallinkException(ErrorCode.DB_FAIL); } - WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); - if (StringUtils.isBlank(payAccount.getApiKey())) { - logger.error("支付密钥为空"); - throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员"); - } - if (StringUtils.isBlank(payAccount.getCertPath())) { - logger.error("证书路径为空"); - throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书路径为空,请联系商城管理员"); - } - if (!Utility.isFileExist(payAccount.getCertPath())) { - logger.error("证书文件不存在"); - throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书文件不存在,请联系商城管理员"); - } + // check 是否有退款订单 List refundList = wxRefundOrderMapper.findList(record); if (refundList.size() > 0) { logger.error("退款订单已存在, 无法再提交退款申请"); throw new MallinkException(ErrorCode.REFUND_ORDER_EXIST.getCode(), "退款订单已存在, 无法再提交退款申请"); } - - // 向微信提交退款申请 - if (payAccount.getType() == EnumPayMode.MCH.getCode()) { - // 普通商户模式 - String noncestr = Utility.generate32UUID(); - WxRefundOrderP wxRefundOrderP = new WxRefundOrderP(); - wxRefundOrderP.setAppid(appInfo.getAppId()); - wxRefundOrderP.setMch_id(payAccount.getMchId()); - wxRefundOrderP.setNonce_str(noncestr); - // 微信内部订单号 - if (record.getTransactionId() != null) - wxRefundOrderP.setTransaction_id(record.getTransactionId()); - // 支付订单号 - wxRefundOrderP.setOut_trade_no(payOrder.getPayOrderNo()); - // 退款支付订单号 - wxRefundOrderP.setOut_refund_no(out_refund_id); - wxRefundOrderP.setTotal_fee(record.getTotalFee()); - wxRefundOrderP.setRefund_fee(record.getRefundFee()); - if (payType == EnumPayType.PAY_B_REFUND) { - wxRefundOrderP.setRefund_desc("B端商户退款"); - } else if (payType == EnumPayType.PAY_ADMIN_REFUND) { - wxRefundOrderP.setRefund_desc("管理端商户退款"); - } else if (payType == EnumPayType.PAY_AUTO_REFUND) { - wxRefundOrderP.setRefund_desc("超期自动退款"); - } else { - wxRefundOrderP.setRefund_desc("用户自己退款"); - } - wxRefundOrderP.setNotify_url(payAccount.getRefundNotifyUrl()); - - Map signMap = null; - try { - signMap = BeanUtils.toStringMap(wxRefundOrderP); - } catch (Exception e) { - logger.error("退款命令生辰: " + e.getMessage()); - throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); - } - - String signAgent = WxPayment.createSign(signMap, payAccount.getApiKey()); - signMap.put("sign", signAgent); - String response = null; - try { - response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); - } catch (Exception e) { - logger.error("退款异常: " + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); - } - logger.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString()); - Map returnMap = WxPayment.xmlToMap(response); - String result_no = returnMap.get("result_code"); - String refund_id = returnMap.get("refund_id"); - // 设置 微信退款订单号 - record.setRefundId(refund_id); - record.setRefundVendor(payOrder.getPayVendor()); - if ("SUCCESS".equals(result_no)) { - logger.info("微信退款订单申请成功: " + returnMap.toString()); - try { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } catch (Exception e) { - logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); - } - } else { - String errDesc = returnMap.get("err_code_des"); - if (errDesc.equalsIgnoreCase("订单已全额退款")) { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } - logger.error("微信退款订单申请失败: " + response); - String errMsg = ""; - JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); - if (errObj != null) { - errMsg = errObj.toJSONString(); - record.setFailReason(errMsg); - } else { - errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); - } - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode()); - wxRefundOrderMapper.updateById(record); - if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { - // 更新券状态 - throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); - } - return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap); - } - } else { - // 服务商模式 - String noncestr = Utility.generate32UUID(); - WxRefundOrderSP wxRefundOrderSP = new WxRefundOrderSP(); - wxRefundOrderSP.setAppid(appInfo.getParentAppId()); - wxRefundOrderSP.setSub_appid(appInfo.getAppId()); - wxRefundOrderSP.setMch_id(payAccount.getMchId()); - wxRefundOrderSP.setSub_mch_id(payAccount.getSubMchId()); - wxRefundOrderSP.setNonce_str(noncestr); - // 微信内部订单号 - if (record.getTransactionId() != null) - wxRefundOrderSP.setTransaction_id(record.getTransactionId()); - // 支付订单号 - wxRefundOrderSP.setOut_trade_no(payOrder.getPayOrderNo()); - // 退款支付订单号 - wxRefundOrderSP.setOut_refund_no(out_refund_id); - wxRefundOrderSP.setTotal_fee(record.getTotalFee()); - wxRefundOrderSP.setRefund_fee(record.getRefundFee()); - if (payType == EnumPayType.PAY_B_REFUND) { - wxRefundOrderSP.setRefund_desc("B端商户退款"); - } else if (payType == EnumPayType.PAY_ADMIN_REFUND) { - wxRefundOrderSP.setRefund_desc("管理端商户退款"); - } else if (payType == EnumPayType.PAY_AUTO_REFUND) { - wxRefundOrderSP.setRefund_desc("超期自动退款"); - } else { - wxRefundOrderSP.setRefund_desc("用户自己退款"); - } - wxRefundOrderSP.setNotify_url(payAccount.getRefundNotifyUrl()); - wxRefundOrderSP.setSign_type("HMAC-SHA256"); - - Map signMap = null; - try { - signMap = BeanUtils.toStringMap(wxRefundOrderSP); - } catch (Exception e) { - logger.error("退款命令生辰: " + e.getMessage()); - throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); - } - - String signAgent = WxPayment.createSignHMAC(signMap, payAccount.getApiKey()); - signMap.put("sign", signAgent); - String response = null; - try { - response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); - } catch (Exception e) { - logger.error("退款异常: " + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); - } - logger.info("微信退款订单:" + wxRefundOrderSP.toString() + ", response: " + response.toString()); - Map returnMap = WxPayment.xmlToMap(response); - String result_no = returnMap.get("result_code"); - String refund_id = returnMap.get("refund_id"); - // 设置 微信退款订单号 - record.setRefundId(refund_id); - record.setRefundVendor(payOrder.getPayVendor()); - if ("SUCCESS".equals(result_no)) { - logger.info("微信退款订单申请成功: " + returnMap.toString()); - try { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } catch (Exception e) { - logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "订单状态更新失败"); - } - } else { - String errDesc = returnMap.get("err_code_des"); - if (errDesc.equalsIgnoreCase("订单已全额退款")) { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } - logger.error("微信退款订单申请失败: " + response); - String errMsg = ""; - JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); - if (errObj != null) { - errMsg = errObj.toJSONString(); - record.setFailReason(errMsg); - } else { - errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); - } - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode()); - wxRefundOrderMapper.updateById(record); - if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { - // 更新券状态 - throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); - } - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg); - } + WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); + if (null == payAccount) { + throw new MallinkException(ErrorCode.PAY_ORDER_QUERY_ERROR.getCode(), "payAccount为空[payId:"+appInfo.getPayId()+"]"); + } + RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor()).refund(payAccount, appInfo, record, payOrder, payType); + if (refundResult.isSuccess()) { + record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); + wxRefundOrderMapper.updateById(record); + return new ResultData(Result.SUCCESS, "退款订单申请成功", refundResult.getData()); + }else { + throw new MallinkException(refundResult.getCode(), refundResult.getMsg()); } } @@ -958,53 +454,13 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { @Override public ResultData queryRefundOrder(WxAppinfo appInfo, WxRefundOrder record) { WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); - if (payAccount.getType() == EnumPayMode.MCH.getCode()) { - Map paramMap = WxPayment.buildWeappRefundQueryMap( - appInfo.getAppId(), payAccount.getMchId(), - record.getTransactionId(), record.getPayOrderNo(), String.valueOf(record.getId()), - record.getRefundId(), payAccount.getApiKey()); - String response = WxPay.orderRefundQuery(paramMap); - Map returnMap = WxPayment.xmlToMap(response); - String result_no = returnMap.get("result_code"); - if ("SUCCESS".equals(result_no)) { - String refund_id = returnMap.get("refund_id"); - return new ResultData(Result.SUCCESS, "退款", returnMap); - } else { - wxRefundOrderMapper.updateById(record); - String errMsg = ""; - JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); - if (errObj != null) { - errMsg = errObj.toJSONString(); - record.setFailReason(errMsg); - } else { - errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); - } - return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap); - } - } else { - Map paramMap = WxPayment.buildSWeappRefundQueryMap( - appInfo.getParentAppId(), appInfo.getAppId(), payAccount.getMchId(), payAccount.getSubMchId(), - record.getTransactionId(), record.getPayOrderNo(), String.valueOf(record.getId()), record.getRefundId(), payAccount.getApiKey()); - String response = WxPay.orderRefundQuery(paramMap); - Map returnMap = WxPayment.xmlToMap(response); - String result_no = returnMap.get("result_code"); - if ("SUCCESS".equals(result_no)) { - String refund_id = returnMap.get("refund_id"); - return new ResultData(Result.SUCCESS, "退款", returnMap); - } else { - String errMsg = ""; - JSONObject errObj = errorRefundQueryMap.getJSONObject(result_no); - if (errObj != null) { - errMsg = errObj.toJSONString(); - record.setFailReason(errMsg); - } else { - errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); - } - wxRefundOrderMapper.updateById(record); - return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap); - } + RefundAdapterResult result = payServiceFactory.getRefundPayAdapterService(record.getRefundVendor()).queryRefund(appInfo, payAccount, record); + if (result.isSuccess()) { + return new ResultData(Result.SUCCESS, "退款", result.getData()); + }else { + record.setFailReason(result.getMsg()); + wxRefundOrderMapper.updateById(record); + return new ResultData(Result.ERROR, result.getMsg(), result.getData()); } } @@ -1017,206 +473,15 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { */ @Override public String notify(Map paramMap, EnumPayWay payWay) { - // how to get wechatAppId, wechatMchId, partnerKey - String appId = paramMap.get("appid"); - String subAppId = paramMap.get("sub_appid"); - String mchId = paramMap.get("mch_id"); - String subMchId = paramMap.get("sub_mch_id"); - if (StringUtils.isBlank(subAppId) && StringUtils.isBlank(subMchId)) { - // 普通商户号 - WxAppinfo appinfo = wxAppinfoMapper.findByAppId(appId); - if (appinfo == null) { - logger.error("未找到appid信息:" + appId); - throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); - } - WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId()); - if (payAccount == null) { - logger.error("未找到mch_id信息:" + mchId); - throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); - } - if (!mchId.equalsIgnoreCase(payAccount.getMchId())) { - logger.error("mch_id不对应:" + mchId + ",account:" + payAccount.getMchId()); - throw new MallinkException(ErrorCode.MCH_INFO_NOT_EQUAL); - } - String partnerKey = payAccount.getApiKey(); - try { - if (payWay.getType() == EnumPayWay.EnumPayWayType.WX_MINIPAY) { - if (!"SUCCESS".equals(paramMap.get("return_code"))) { - logger.warn("notify refund, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "订单状态码非SUCCESS"); - return XmlUtil.getRequestXml(resultMap); - } - - // 解密req_info - String req_info = CipherUtil.decryptReqInfo(paramMap.get("req_info"), partnerKey); - Map reqMap = WxPayment.xmlToMap(req_info); - - String payOrderNo = reqMap.get("out_trade_no"); - Long payOrderId = Long.valueOf(payOrderNo); - WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId); - if (payOrder == null) { - logger.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "支付订单不存在"); - return XmlUtil.getRequestXml(resultMap); - } - // 验证支付金额 - if (!reqMap.get("total_fee").equals(payOrder.getPayAmount().toString())) { - logger.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "支付订单总金额不一致"); - return XmlUtil.getRequestXml(resultMap); - } - String refundIdStr = reqMap.get("out_refund_no"); - Long refundOrderId = Long.valueOf(refundIdStr); - WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId); - if (refundOrder == null) { - logger.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "退款订单不存在"); - return XmlUtil.getRequestXml(resultMap); - } - // 验证支付金额 - if (!reqMap.get("total_fee").equals(refundOrder.getTotalFee().toString())) { - logger.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "订单总金额不一致"); - return XmlUtil.getRequestXml(resultMap); - } - // 验证退款金额 - if (!reqMap.get("refund_fee").equals(refundOrder.getRefundFee().toString())) { - logger.warn("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "退款总金额不一致"); - return XmlUtil.getRequestXml(resultMap); - } - - // 处理支付成功 - handleRefundSuccess(refundOrder, reqMap.get("transaction_id"), reqMap.get("refund_id")); - logger.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "SUCCESS"); - resultMap.put("return_msg", "OK"); - return XmlUtil.getRequestXml(resultMap); - } - } catch (RuntimeException e) { - logger.warn("notify refund paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); - } catch (Exception e) { - logger.warn("notify refund, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); - } - } else { - // 服务号回调 - WxAppinfo appinfo = wxAppinfoMapper.findByAppId(subAppId); - if (appinfo == null) { - logger.error("未找到appid信息:" + appId); - throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); - } - WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId()); - if (payAccount == null) { - logger.error("未找到mch_id信息:" + mchId); - throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); - } - if (!mchId.equalsIgnoreCase(payAccount.getMchId())) { - logger.error("mch_id不对应:" + mchId + ",account:" + payAccount.getMchId()); - throw new MallinkException(ErrorCode.MCH_INFO_NOT_EQUAL); - } - String partnerKey = payAccount.getApiKey(); - try { - if (payWay.getType() == EnumPayWay.EnumPayWayType.WX_MINIPAY) { - if (!"SUCCESS".equals(paramMap.get("return_code"))) { - logger.warn("notify order, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "订单状态码非SUCCESS"); - return XmlUtil.getRequestXml(resultMap); - } - - // 解密req_info - String req_info = CipherUtil.decryptReqInfo(paramMap.get("req_info"), partnerKey); - logger.info(req_info); - Map reqMap = WxPayment.xmlToMap(req_info); - - String payOrderNo = reqMap.get("out_trade_no"); - if (payOrderNo == null) { - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "SUCCESS"); - resultMap.put("return_msg", "OK"); - return XmlUtil.getRequestXml(resultMap); - } - Long payOrderId = Long.valueOf(payOrderNo); - WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId); - if (payOrder == null) { - logger.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "支付订单不存在"); - return XmlUtil.getRequestXml(resultMap); - } - // 验证支付金额 - if (!reqMap.get("total_fee").equals(payOrder.getPayAmount().toString())) { - logger.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "支付订单总金额不一致"); - return XmlUtil.getRequestXml(resultMap); - } - String refundIdStr = reqMap.get("out_refund_no"); - Long refundOrderId = Long.valueOf(refundIdStr); - WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId); - if (refundOrder == null) { - logger.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "退款订单不存在"); - return XmlUtil.getRequestXml(resultMap); - } - // 验证支付金额 - if (!reqMap.get("total_fee").equals(refundOrder.getTotalFee().toString())) { - logger.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "订单总金额不一致"); - return XmlUtil.getRequestXml(resultMap); - } - // 验证退款金额 - if (!reqMap.get("refund_fee").equals(refundOrder.getRefundFee().toString())) { - logger.warn("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "退款总金额不一致"); - return XmlUtil.getRequestXml(resultMap); - } - - // 处理支付成功 - handleRefundSuccess(refundOrder, reqMap.get("transaction_id"), reqMap.get("refund_id")); - logger.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + reqMap.toString() + ", payWay:" + payWay.toString()); - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "SUCCESS"); - resultMap.put("return_msg", "OK"); - return XmlUtil.getRequestXml(resultMap); - } - } catch (RuntimeException e) { - logger.warn("notify refund, wepay checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); - } catch (Exception e) { - logger.warn("notify refund, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); - } - } - - SortedMap resultMap = new TreeMap(); - resultMap.put("return_code", "FAIL"); - resultMap.put("return_msg", "FAILED"); - return XmlUtil.getRequestXml(resultMap); + RefundNotifyAdapterResult notifyResult = payServiceFactory.getRefundPayAdapterService(payWay.getCode()).notify(paramMap, payWay); + if (!notifyResult.isSuccess()) { + return notifyResult.getReturnJson(); + }else { + if (null != notifyResult.getRefundOrder()) { + handleRefundSuccess(notifyResult.getRefundOrder(), notifyResult.getTranscationId(), notifyResult.getRefundId()); + } + return notifyResult.getReturnJson(); + } } @Override @@ -1368,7 +633,8 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { record.setRefundFee(payOrder.getPayAmount()); record.setRefundTimeStart(currentDate); record.setRefundOrderStatus(EnumRefundStatus.REFUND_WAIT.getCode()); - + record.setRefundVendor(payOrder.getPayVendor()); + // 退款订单 try { int sqlRow = wxRefundOrderMapper.insert(record); @@ -1381,17 +647,9 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { throw new MallinkException(ErrorCode.DB_FAIL); } WxPayAccount payAccount = wxPayAccountMapper.selectById(appInfo.getPayId()); - if (StringUtils.isBlank(payAccount.getApiKey())) { - logger.error("支付密钥为空"); - throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员"); - } - if (StringUtils.isBlank(payAccount.getCertPath())) { - logger.error("证书路径为空"); - throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书路径为空,请联系商城管理员"); - } - if (!Utility.isFileExist(payAccount.getCertPath())) { - logger.error("证书文件不存在"); - throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书文件不存在,请联系商城管理员"); + if (null == payAccount) { + logger.error("order:("+orderId+")"+appInfo.getPayId()+"查询不到WxPayAccount"); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(), appInfo.getPayId()+"查询不到WxPayAccount"); } // check 是否有退款订单 List refundList = wxRefundOrderMapper.findList(record); @@ -1399,170 +657,13 @@ public class WxRefundOrderServiceImpl implements WxRefundOrderService { logger.error("退款订单已存在, 无法再提交退款申请"); throw new MallinkException(ErrorCode.REFUND_ORDER_EXIST.getCode(), "退款订单已存在, 无法再提交退款申请"); } - - // 实际支付 - // 向微信提交退款申请 - if (payAccount.getType().equals(EnumPayMode.MCH.getCode())) { - // 普通商户模式 - String noncestr = Utility.generate32UUID(); - WxRefundOrderP wxRefundOrderP = new WxRefundOrderP(); - wxRefundOrderP.setAppid(appInfo.getAppId()); - wxRefundOrderP.setMch_id(payAccount.getMchId()); - wxRefundOrderP.setNonce_str(noncestr); - // 微信内部订单号 - if (record.getTransactionId() != null) { - wxRefundOrderP.setTransaction_id(record.getTransactionId()); - } - // 支付订单号 - wxRefundOrderP.setOut_trade_no(payOrder.getPayOrderNo()); - // 退款支付订单号 - wxRefundOrderP.setOut_refund_no(out_refund_id); - wxRefundOrderP.setTotal_fee(record.getTotalFee()); - wxRefundOrderP.setRefund_fee(record.getRefundFee()); - wxRefundOrderP.setRefund_desc("拼团失败退款"); - wxRefundOrderP.setNotify_url(payAccount.getRefundNotifyUrl()); - - Map signMap = null; - try { - signMap = BeanUtils.toStringMap(wxRefundOrderP); - } catch (Exception e) { - logger.error("退款命令生辰: " + e.getMessage()); - throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); - } - - String signAgent = WxPayment.createSign(signMap, payAccount.getApiKey()); - signMap.put("sign", signAgent); - String response = null; - try { - response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); - } catch (Exception e) { - logger.error("退款异常: " + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); - } - logger.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString()); - Map returnMap = WxPayment.xmlToMap(response); - String result_no = returnMap.get("result_code"); - String refund_id = returnMap.get("refund_id"); - // 设置 微信退款订单号 - record.setRefundId(refund_id); - record.setRefundVendor(payOrder.getPayVendor()); - if ("SUCCESS".equals(result_no)) { - logger.info("微信退款订单申请成功: " + returnMap.toString()); - try { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } catch (Exception e) { - logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); - } - } else { - String errDesc = returnMap.get("err_code_des"); - if (errDesc.equalsIgnoreCase("订单已全额退款")) { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } - logger.error("微信退款订单申请失败: " + response); - String errMsg = ""; - JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); - if (errObj != null) { - errMsg = errObj.toJSONString(); - record.setFailReason(errMsg); - } else { - errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); - } - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode()); - wxRefundOrderMapper.updateById(record); - if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { - // 更新券状态 - throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); - } - return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg, returnMap); - } - } else { - // 服务商模式 - String noncestr = Utility.generate32UUID(); - WxRefundOrderSP wxRefundOrderSP = new WxRefundOrderSP(); - wxRefundOrderSP.setAppid(appInfo.getParentAppId()); - wxRefundOrderSP.setSub_appid(appInfo.getAppId()); - wxRefundOrderSP.setMch_id(payAccount.getMchId()); - wxRefundOrderSP.setSub_mch_id(payAccount.getSubMchId()); - wxRefundOrderSP.setNonce_str(noncestr); - // 微信内部订单号 - if (record.getTransactionId() != null) { - wxRefundOrderSP.setTransaction_id(record.getTransactionId()); - } - // 支付订单号 - wxRefundOrderSP.setOut_trade_no(payOrder.getPayOrderNo()); - // 退款支付订单号 - wxRefundOrderSP.setOut_refund_no(out_refund_id); - wxRefundOrderSP.setTotal_fee(record.getTotalFee()); - wxRefundOrderSP.setRefund_fee(record.getRefundFee()); - wxRefundOrderSP.setRefund_desc("拼团失败退款"); - wxRefundOrderSP.setNotify_url(payAccount.getRefundNotifyUrl()); - wxRefundOrderSP.setSign_type("HMAC-SHA256"); - - Map signMap = null; - try { - signMap = BeanUtils.toStringMap(wxRefundOrderSP); - } catch (Exception e) { - logger.error("退款命令生辰: " + e.getMessage()); - throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); - } - - String signAgent = WxPayment.createSignHMAC(signMap, payAccount.getApiKey()); - signMap.put("sign", signAgent); - String response = null; - try { - response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); - } catch (Exception e) { - logger.error("退款异常: " + e.getMessage()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); - } - logger.info("微信退款订单:" + wxRefundOrderSP.toString() + ", response: " + response.toString()); - Map returnMap = WxPayment.xmlToMap(response); - String result_no = returnMap.get("result_code"); - String refund_id = returnMap.get("refund_id"); - // 设置 微信退款订单号 - record.setRefundId(refund_id); - record.setRefundVendor(payOrder.getPayVendor()); - if ("SUCCESS".equals(result_no)) { - logger.info("微信退款订单申请成功: " + returnMap.toString()); - try { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } catch (Exception e) { - logger.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "订单状态更新失败"); - } - } else { - String errDesc = returnMap.get("err_code_des"); - if (errDesc.equalsIgnoreCase("订单已全额退款")) { - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); - wxRefundOrderMapper.updateById(record); - return new ResultData(Result.SUCCESS, "退款订单申请成功", returnMap); - } - logger.error("微信退款订单申请失败: " + response); - String errMsg = ""; - JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); - if (errObj != null) { - errMsg = errObj.toJSONString(); - record.setFailReason(errMsg); - } else { - errMsg = returnMap.get("return_msg"); - record.setFailReason(errMsg); - } - record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode()); - wxRefundOrderMapper.updateById(record); - if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { - // 更新券状态 - throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); - } - throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), errMsg); - } + RefundAdapterResult refundResult = payServiceFactory.getRefundPayAdapterService(payOrder.getPayVendor()).refund(payAccount, appInfo, record, payOrder, null); + if (refundResult.isSuccess()) { + record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); + wxRefundOrderMapper.updateById(record); + return new ResultData(Result.SUCCESS, "退款订单申请成功", refundResult.getData()); + }else { + throw new MallinkException(refundResult.getCode(), refundResult.getMsg()); } } diff --git a/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java b/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java index d68379b7d..fa7947961 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/PayServiceFactory.java @@ -14,8 +14,11 @@ import com.iformall.service.WxPayOrderService; import com.iformall.service.pay.service.pay.CDrivingPayService; import com.iformall.service.pay.service.pay.CPassivePayService; import com.iformall.service.pay.service.pay.PayAdapterService; -import com.iformall.service.pay.service.pay.miniApp.wx.appPay.WxMiniAppPayAdapterService; -import com.iformall.service.pay.service.pay.miniApp.wx.maPay.WxMiniMaPayAdapterService; +import com.iformall.service.pay.service.pay.wx.h5.WxH5PayService; +import com.iformall.service.pay.service.pay.wx.miniApp.appPay.WxMiniAppPayAdapterService; +import com.iformall.service.pay.service.pay.wx.miniApp.maPay.WxMiniMaPayAdapterService; +import com.iformall.service.pay.service.refund.RefundPayAdapterService; +import com.iformall.service.pay.service.refund.wx.WxRefundAdapterService; import com.iformall.service.pay.service.share.PayShareAdapterService; import com.iformall.service.pay.service.share.neupos.NeuPosPayShareService; import com.iformall.service.pay.service.share.wx.WxPayShareService; @@ -29,22 +32,60 @@ public class PayServiceFactory { private Map serviceMap = null; private Map shareMap = null; + private Map refundMap = null; @Autowired WxMiniAppPayAdapterService wxMiniAppPayService; @Autowired WxMiniMaPayAdapterService wxMiniAppMaPayService; @Autowired - WxPayOrderService wxPayOrderService; + WxH5PayService wxH5PayService; + + @Autowired WxPayShareService wxShareService; @Autowired NeuPosPayShareService neuPosPayShareService; + + @Autowired + WxRefundAdapterService wxRefundService; + + + + private Map getServiceMap() { + if (null == serviceMap) { + serviceMap = new ConcurrentHashMap(); + serviceMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxMiniAppPayService); + serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxMiniAppMaPayService); + serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_WAP.getCode(), wxH5PayService); + } + return serviceMap; + } + + private Map getShareMap(){ + if (null == shareMap ) { + shareMap = new ConcurrentHashMap(); + shareMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxShareService); + shareMap.put(EnumPayWay.PAY_WAY_POS_NEU.getCode(), neuPosPayShareService); + } + return shareMap; + } + + private Map getRefundMap(){ + if (null == refundMap ) { + refundMap = new ConcurrentHashMap(); + refundMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxRefundService); + refundMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxRefundService); + } + return refundMap; + } + public PayAdapterService getPayAdapterService(Integer type) throws MallinkException{ PayAdapterService service = getServiceMap().get(type); if (null == service) { - throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payType["+type+"] 支付service未找到"); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service未找到"); } return service; } @@ -52,51 +93,40 @@ public class PayServiceFactory { public CDrivingPayService getCDrivingPayService(Integer type) throws MallinkException{ PayAdapterService service = getServiceMap().get(type); if (null == service) { - throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payType["+type+"] 支付service未找到"); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service未找到"); } if (service instanceof CDrivingPayService) { return (CDrivingPayService) service; }else { - throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payType["+type+"] 支付service不是CDrivingPayService"); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service不是CDrivingPayService"); } } public CPassivePayService getCPassivePayService(Integer type) throws MallinkException{ PayAdapterService service = getServiceMap().get(type); if (null == service) { - throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payType["+type+"] 支付service未找到"); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service未找到"); } if (service instanceof CPassivePayService) { return (CPassivePayService) service; }else { - throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payType["+type+"] 支付service不是CPassivePayService"); - } - } - - private Map getServiceMap() { - if (null != serviceMap) { - serviceMap = new ConcurrentHashMap(); - serviceMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxMiniAppPayService); - serviceMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxMiniAppMaPayService); - } - return serviceMap; - } - - private Map getShareMap(){ - if (null != shareMap ) { - shareMap = new ConcurrentHashMap(); - shareMap.put(EnumPayWay.PAY_WAY_WECHAT.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_WECHAT_MA.getCode(), wxShareService); - shareMap.put(EnumPayWay.PAY_WAY_POS_NEU.getCode(), neuPosPayShareService); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 支付service不是CPassivePayService"); } - return shareMap; } public PayShareAdapterService getPayShareAdapterService(Integer type) throws MallinkException{ PayShareAdapterService shareService = getShareMap().get(type); if (null == shareService) { - throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payType["+type+"] 分账service未找到"); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 分账service未找到"); } return shareService; } + + public RefundPayAdapterService getRefundPayAdapterService(Integer type) throws MallinkException{ + RefundPayAdapterService refundService = getRefundMap().get(type); + if (null == refundService) { + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+type+"] 退款service未找到"); + } + return refundService; + } } diff --git a/mallinkService/src/main/java/com/iformall/service/pay/entity/RefundAdapterResult.java b/mallinkService/src/main/java/com/iformall/service/pay/entity/RefundAdapterResult.java new file mode 100644 index 000000000..826832bc4 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/entity/RefundAdapterResult.java @@ -0,0 +1,50 @@ +package com.iformall.service.pay.entity; + +import java.io.Serializable; + +public class RefundAdapterResult implements Serializable{ + private static final long serialVersionUID = -6647306162758854293L; + private boolean isSuccess; + private Integer code; + private String msg; + private Object data; + + + public RefundAdapterResult() { + + } + + public RefundAdapterResult(boolean isSuccess,Integer code,String msg,Object data) { + this.isSuccess = isSuccess; + this.msg = msg; + this.data = data; + } + + public boolean isSuccess() { + return isSuccess; + } + public void setSuccess(boolean isSuccess) { + this.isSuccess = isSuccess; + } + public String getMsg() { + return msg; + } + public void setMsg(String msg) { + this.msg = msg; + } + public Object getData() { + return data; + } + public void setData(Object data) { + this.data = data; + } + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/entity/RefundNotifyAdapterResult.java b/mallinkService/src/main/java/com/iformall/service/pay/entity/RefundNotifyAdapterResult.java new file mode 100644 index 000000000..131fe95aa --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/entity/RefundNotifyAdapterResult.java @@ -0,0 +1,87 @@ +package com.iformall.service.pay.entity; + +import java.io.Serializable; + +import com.iformall.domain.po.WxRefundOrder; + +public class RefundNotifyAdapterResult implements Serializable{ + private static final long serialVersionUID = -6647306162758854293L; + private boolean isSuccess; + private Integer code; + private String msg; + private String returnJson; + private String transcationId; + private String refundId; + private WxRefundOrder refundOrder; + + + public RefundNotifyAdapterResult() { + + } + + public RefundNotifyAdapterResult(boolean isSuccess,Integer code,String msg,String returnJson) { + this.isSuccess = isSuccess; + this.msg = msg; + this.returnJson = returnJson; + } + + public RefundNotifyAdapterResult(String transcationId,String refundId,WxRefundOrder refundOrder,String returnJson) { + this.isSuccess = true; + this.transcationId = transcationId; + this.refundId = refundId; + this.refundOrder = refundOrder; + this.returnJson = returnJson; + } + + public boolean isSuccess() { + return isSuccess; + } + public void setSuccess(boolean isSuccess) { + this.isSuccess = isSuccess; + } + public String getMsg() { + return msg; + } + public void setMsg(String msg) { + this.msg = msg; + } + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getTranscationId() { + return transcationId; + } + + public void setTranscationId(String transcationId) { + this.transcationId = transcationId; + } + + public String getRefundId() { + return refundId; + } + + public void setRefundId(String refundId) { + this.refundId = refundId; + } + + public String getReturnJson() { + return returnJson; + } + + public void setReturnJson(String returnJson) { + this.returnJson = returnJson; + } + + public WxRefundOrder getRefundOrder() { + return refundOrder; + } + + public void setRefundOrder(WxRefundOrder refundOrder) { + this.refundOrder = refundOrder; + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/BaseWxPayAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/BaseWxPayAdapterService.java similarity index 96% rename from mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/BaseWxPayAdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/BaseWxPayAdapterService.java index 26e88e954..508efe8e0 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/BaseWxPayAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/BaseWxPayAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.pay.miniApp.wx; +package com.iformall.service.pay.service.pay.wx; import java.util.Map; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/h5/WxH5PayService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/h5/WxH5PayService.java new file mode 100644 index 000000000..5c7ad931c --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/h5/WxH5PayService.java @@ -0,0 +1,45 @@ +package com.iformall.service.pay.service.pay.wx.h5; + +import java.util.Date; + +import org.springframework.stereotype.Service; + +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxOrder; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.po.WxPayOrder; +import com.iformall.enums.EnumPayShare; +import com.iformall.service.pay.entity.PayAdapterResult; +import com.iformall.service.pay.entity.PayExtraParam; +import com.iformall.service.pay.entity.PayQueryAdapterResult; +import com.iformall.service.pay.service.pay.CDrivingPayService; +import com.iformall.service.pay.service.pay.wx.BaseWxPayAdapterService; + +@Service +public class WxH5PayService extends BaseWxPayAdapterService implements CDrivingPayService{ + + @Override + public PayAdapterResult pay(WxPayAccount payAccount, WxOrder order, WxPayOrder record, EnumPayShare isShare, + WxAppinfo appInfo, Date currentDate, PayExtraParam params) throws Exception { + // TODO Auto-generated method stub + return null; + } + + @Override + public PayQueryAdapterResult queryPayStatus(WxPayOrder oldRecord, WxOrder order, WxAppinfo appInfo, + WxPayAccount payAccount) throws Exception { + return super.queryPayStatus(oldRecord, order, appInfo, payAccount); + } + + @Override + public int queryPayStatus(PayQueryAdapterResult statusObject, String orderOutNo) throws Exception { + return super.queryPayStatus(statusObject, orderOutNo); + } + + @Override + public int queryPayStatusCode(WxPayOrder oldRecord, WxOrder order, WxAppinfo appInfo, WxPayAccount payAccount) + throws Exception { + return super.queryPayStatusCode(oldRecord, order, appInfo, payAccount); + } + +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/appPay/WxMiniAppPayAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/appPay/WxMiniAppPayAdapterService.java similarity index 98% rename from mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/appPay/WxMiniAppPayAdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/appPay/WxMiniAppPayAdapterService.java index 53b979470..2b53ae516 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/appPay/WxMiniAppPayAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/appPay/WxMiniAppPayAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.pay.miniApp.wx.appPay; +package com.iformall.service.pay.service.pay.wx.miniApp.appPay; import java.util.Date; import java.util.Map; @@ -26,7 +26,7 @@ import com.iformall.service.pay.entity.PayAdapterResult; import com.iformall.service.pay.entity.PayExtraParam; import com.iformall.service.pay.entity.PayQueryAdapterResult; import com.iformall.service.pay.service.pay.CDrivingPayService; -import com.iformall.service.pay.service.pay.miniApp.wx.BaseWxPayAdapterService; +import com.iformall.service.pay.service.pay.wx.BaseWxPayAdapterService; import com.iformall.utils.BeanUtils; import com.iformall.utils.MapUtil; import com.iformall.utils.Utility; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/maPay/WxMiniMaPayAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/maPay/WxMiniMaPayAdapterService.java similarity index 98% rename from mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/maPay/WxMiniMaPayAdapterService.java rename to mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/maPay/WxMiniMaPayAdapterService.java index 745c1686c..71524ae60 100644 --- a/mallinkService/src/main/java/com/iformall/service/pay/service/pay/miniApp/wx/maPay/WxMiniMaPayAdapterService.java +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/pay/wx/miniApp/maPay/WxMiniMaPayAdapterService.java @@ -1,4 +1,4 @@ -package com.iformall.service.pay.service.pay.miniApp.wx.maPay; +package com.iformall.service.pay.service.pay.wx.miniApp.maPay; import java.util.Date; import java.util.Map; @@ -27,7 +27,7 @@ import com.iformall.service.pay.entity.PayAdapterResult; import com.iformall.service.pay.entity.PayExtraParam; import com.iformall.service.pay.entity.PayQueryAdapterResult; import com.iformall.service.pay.service.pay.CPassivePayService; -import com.iformall.service.pay.service.pay.miniApp.wx.BaseWxPayAdapterService; +import com.iformall.service.pay.service.pay.wx.BaseWxPayAdapterService; import com.iformall.utils.BeanUtils; import com.iformall.utils.Utility; import lombok.extern.slf4j.Slf4j; diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/refund/RefundPayAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/refund/RefundPayAdapterService.java new file mode 100644 index 000000000..8fa71dfc7 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/refund/RefundPayAdapterService.java @@ -0,0 +1,42 @@ +package com.iformall.service.pay.service.refund; + +import java.util.Map; + +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.po.WxPayOrder; +import com.iformall.domain.po.WxRefundOrder; +import com.iformall.enums.EnumPayType; +import com.iformall.enums.EnumPayWay; +import com.iformall.service.pay.entity.RefundAdapterResult; +import com.iformall.service.pay.entity.RefundNotifyAdapterResult; + +public interface RefundPayAdapterService { + + /** + * API退款 + * @param payAccount + * @param appInfo + * @param record + * @param payOrder + * @param payType + * @return + */ + public RefundAdapterResult refund(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,EnumPayType payType); + + /** + * API查询退款 + * @param appInfo + * @param payAccount + * @param record + * @return + */ + public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record); + + /** + * 平台方 异步通知 + * @param paramMap + * @param payWay + */ + public RefundNotifyAdapterResult notify(Map paramMap, EnumPayWay payWay); +} diff --git a/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/WxRefundAdapterService.java b/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/WxRefundAdapterService.java new file mode 100644 index 000000000..e497be7d8 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/pay/service/refund/wx/WxRefundAdapterService.java @@ -0,0 +1,636 @@ +package com.iformall.service.pay.service.refund.wx; + +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.po.WxPayOrder; +import com.iformall.domain.po.WxRefundOrder; +import com.iformall.enums.EnumPayMode; +import com.iformall.enums.EnumPayType; +import com.iformall.enums.EnumPayWay; +import com.iformall.enums.EnumRefundStatus; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxAppinfoMapper; +import com.iformall.mapper.WxPayAccountMapper; +import com.iformall.mapper.WxPayOrderMapper; +import com.iformall.mapper.WxRefundOrderMapper; +import com.iformall.pay.WxPay; +import com.iformall.pay.WxPayment; +import com.iformall.pay.WxRefundOrderP; +import com.iformall.pay.WxRefundOrderSP; +import com.iformall.service.pay.entity.RefundAdapterResult; +import com.iformall.service.pay.entity.RefundNotifyAdapterResult; +import com.iformall.service.pay.service.refund.RefundPayAdapterService; +import com.iformall.utils.BeanUtils; +import com.iformall.utils.CipherUtil; +import com.iformall.utils.Utility; +import com.iformall.utils.XmlUtil; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class WxRefundAdapterService implements RefundPayAdapterService{ + + JSONObject errorRefundReqMap = JSON.parseObject("{\n" + + " \"SYSTEMERROR\": {\n" + + " \"detail\": \"接口返回错误\",\n" + + " \"reason\": \"系统超时等\",\n" + + " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + + " },\n" + + " \"BIZERR_NEED_RETRY\": {\n" + + " \"detail\": \"退款业务流程错误,需要商户触发重试来解决\",\n" + + " \"reason\": \"并发情况下,业务被拒绝,商户重试即可解决\",\n" + + " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + + " },\n" + + " \"TRADE_OVERDUE\": {\n" + + " \"detail\": \"订单已经超过退款期限\",\n" + + " \"reason\": \"订单已经超过可退款的最大期限(支付后一年内可退款)\\t\",\n" + + " \"resolution\": \"请选择其他方式自行退款\"\n" + + " },\n" + + " \"ERROR\": {\n" + + " \"detail\": \"业务错误\",\n" + + " \"reason\": \"申请退款业务发生错误\",\n" + + " \"resolution\": \"该错误都会返回具体的错误原因,请根据实际返回做相应处理。\"\n" + + " },\n" + + " \"USER_ACCOUNT_ABNORMAL\": {\n" + + " \"detail\": \"退款请求失败\",\n" + + " \"reason\": \"用户帐号注销\",\n" + + " \"resolution\": \"此状态代表退款申请失败,商户可自行处理退款。\"\n" + + " },\n" + + " \"INVALID_REQ_TOO_MUCH\": {\n" + + " \"detail\": \"无效请求过多\",\n" + + " \"reason\": \"连续错误请求数过多被系统短暂屏蔽\\t\",\n" + + " \"resolution\": \"请检查业务是否正常,确认业务正常后请在1分钟后再来重试\"\n" + + " },\n" + + " \"NOTENOUGH\": {\n" + + " \"detail\": \"余额不足\",\n" + + " \"reason\": \"商户可用退款余额不足\",\n" + + " \"resolution\": \"此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。\"\n" + + " },\n" + + " \"INVALID_TRANSACTIONID\": {\n" + + " \"detail\": \"无效transaction_id\",\n" + + " \"reason\": \"请求参数未按指引进行填写\",\n" + + " \"resolution\": \"请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败\"\n" + + " },\n" + + " \"PARAM_ERROR\": {\n" + + " \"detail\": \"参数错误\",\n" + + " \"reason\": \"请求参数未按指引进行填写\",\n" + + " \"resolution\": \"请求参数错误,请重新检查再调用退款申请\"\n" + + " },\n" + + " \"APPID_NOT_EXIST\": {\n" + + " \"detail\": \"APPID不存在\",\n" + + " \"reason\": \"参数中缺少APPID\",\n" + + " \"resolution\": \"请检查APPID是否正确\"\n" + + " },\n" + + " \"MCHID_NOT_EXIST\": {\n" + + " \"detail\": \"MCHID不存在\",\n" + + " \"reason\": \"参数中缺少MCHID\",\n" + + " \"resolution\": \"请检查MCHID是否正确\"\n" + + " },\n" + + " \"REQUIRE_POST_METHOD\": {\n" + + " \"detail\": \"请使用post方法\",\n" + + " \"reason\": \"未使用post传递参数\",\n" + + " \"resolution\": \"请检查请求参数是否通过post方法提交\"\n" + + " },\n" + + " \"SIGNERROR\": {\n" + + " \"detail\": \"签名错误\",\n" + + " \"reason\": \"参数签名结果不正确\",\n" + + " \"resolution\": \"请检查签名参数和方法是否都符合签名算法要求\"\n" + + " },\n" + + " \"XML_FORMAT_ERROR\": {\n" + + " \"detail\": \"XML格式错误\",\n" + + " \"reason\": \"XML格式错误\",\n" + + " \"resolution\": \"请检查XML参数格式是否正确\"\n" + + " },\n" + + " \"FREQUENCY_LIMITED\": {\n" + + " \"detail\": \"频率限制\",\n" + + " \"reason\": \"2个月之前的订单申请退款有频率限制\",\n" + + " \"resolution\": \"该笔退款未受理,请降低频率后重试\"\n" + + " }\n" + + "}"); + + JSONObject errorRefundQueryMap = JSON.parseObject("{\n" + + " \"SYSTEMERROR\": {\n" + + " \"detail\": \"接口返回错误\",\n" + + " \"reason\": \"系统超时等\",\n" + + " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + + " },\n" + + " \"BIZERR_NEED_RETRY\": {\n" + + " \"detail\": \"退款业务流程错误,需要商户触发重试来解决\",\n" + + " \"reason\": \"并发情况下,业务被拒绝,商户重试即可解决\",\n" + + " \"resolution\": \"请不要更换商户退款单号,请使用相同参数再次调用API。\"\n" + + " },\n" + + " \"TRADE_OVERDUE\": {\n" + + " \"detail\": \"订单已经超过退款期限\",\n" + + " \"reason\": \"订单已经超过可退款的最大期限(支付后一年内可退款)\\t\",\n" + + " \"resolution\": \"请选择其他方式自行退款\"\n" + + " },\n" + + " \"ERROR\": {\n" + + " \"detail\": \"业务错误\",\n" + + " \"reason\": \"申请退款业务发生错误\",\n" + + " \"resolution\": \"该错误都会返回具体的错误原因,请根据实际返回做相应处理。\"\n" + + " },\n" + + " \"USER_ACCOUNT_ABNORMAL\": {\n" + + " \"detail\": \"退款请求失败\",\n" + + " \"reason\": \"用户帐号注销\",\n" + + " \"resolution\": \"此状态代表退款申请失败,商户可自行处理退款。\"\n" + + " },\n" + + " \"INVALID_REQ_TOO_MUCH\": {\n" + + " \"detail\": \"无效请求过多\",\n" + + " \"reason\": \"连续错误请求数过多被系统短暂屏蔽\\t\",\n" + + " \"resolution\": \"请检查业务是否正常,确认业务正常后请在1分钟后再来重试\"\n" + + " },\n" + + " \"NOTENOUGH\": {\n" + + " \"detail\": \"余额不足\",\n" + + " \"reason\": \"商户可用退款余额不足\",\n" + + " \"resolution\": \"此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。\"\n" + + " },\n" + + " \"INVALID_TRANSACTIONID\": {\n" + + " \"detail\": \"无效transaction_id\",\n" + + " \"reason\": \"请求参数未按指引进行填写\",\n" + + " \"resolution\": \"请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败\"\n" + + " },\n" + + " \"PARAM_ERROR\": {\n" + + " \"detail\": \"参数错误\",\n" + + " \"reason\": \"请求参数未按指引进行填写\",\n" + + " \"resolution\": \"请求参数错误,请重新检查再调用退款申请\"\n" + + " },\n" + + " \"APPID_NOT_EXIST\": {\n" + + " \"detail\": \"APPID不存在\",\n" + + " \"reason\": \"参数中缺少APPID\",\n" + + " \"resolution\": \"请检查APPID是否正确\"\n" + + " },\n" + + " \"MCHID_NOT_EXIST\": {\n" + + " \"detail\": \"MCHID不存在\",\n" + + " \"reason\": \"参数中缺少MCHID\",\n" + + " \"resolution\": \"请检查MCHID是否正确\"\n" + + " },\n" + + " \"REQUIRE_POST_METHOD\": {\n" + + " \"detail\": \"请使用post方法\",\n" + + " \"reason\": \"未使用post传递参数\",\n" + + " \"resolution\": \"请检查请求参数是否通过post方法提交\"\n" + + " },\n" + + " \"SIGNERROR\": {\n" + + " \"detail\": \"签名错误\",\n" + + " \"reason\": \"参数签名结果不正确\",\n" + + " \"resolution\": \"请检查签名参数和方法是否都符合签名算法要求\"\n" + + " },\n" + + " \"XML_FORMAT_ERROR\": {\n" + + " \"detail\": \"XML格式错误\",\n" + + " \"reason\": \"XML格式错误\",\n" + + " \"resolution\": \"请检查XML参数格式是否正确\"\n" + + " },\n" + + " \"FREQUENCY_LIMITED\": {\n" + + " \"detail\": \"频率限制\",\n" + + " \"reason\": \"2个月之前的订单申请退款有频率限制\",\n" + + " \"resolution\": \"该笔退款未受理,请降低频率后重试\"\n" + + " }\n" + + "}"); + + private WxRefundOrderP generateWxRefundOrderP(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,EnumPayType payType) { + String noncestr = Utility.generate32UUID(); + WxRefundOrderP wxRefundOrderP = new WxRefundOrderP(); + wxRefundOrderP.setAppid(appInfo.getAppId()); + wxRefundOrderP.setMch_id(payAccount.getMchId()); + wxRefundOrderP.setNonce_str(noncestr); + // 微信内部订单号 + if (record.getTransactionId() != null) + wxRefundOrderP.setTransaction_id(record.getTransactionId()); + // 支付订单号 + wxRefundOrderP.setOut_trade_no(payOrder.getPayOrderNo()); + // 退款支付订单号 + wxRefundOrderP.setOut_refund_no(String.valueOf(record.getId())); + wxRefundOrderP.setTotal_fee(record.getTotalFee()); + wxRefundOrderP.setRefund_fee(record.getRefundFee()); + if(null != payType) { + if (payType == EnumPayType.PAY_B_REFUND) { + wxRefundOrderP.setRefund_desc("B端商户退款"); + } else if (payType == EnumPayType.PAY_ADMIN_REFUND) { + wxRefundOrderP.setRefund_desc("管理端商户退款"); + } else if (payType == EnumPayType.PAY_AUTO_REFUND) { + wxRefundOrderP.setRefund_desc("超期自动退款"); + } else { + wxRefundOrderP.setRefund_desc("用户自己退款"); + } + } + wxRefundOrderP.setNotify_url(payAccount.getRefundNotifyUrl()); + return wxRefundOrderP; + } + + private RefundAdapterResult getReusltFromp(String response,WxRefundOrder record,WxPayOrder payOrder) throws MallinkException{ + Map returnMap = WxPayment.xmlToMap(response); + String result_no = returnMap.get("result_code"); + String refund_id = returnMap.get("refund_id"); + // 设置 微信退款订单号 + record.setRefundId(refund_id); + record.setRefundVendor(payOrder.getPayVendor()); + if ("SUCCESS".equals(result_no)) { + log.info("微信退款订单申请成功: " + returnMap.toString()); + try { + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(),"退款订单申请成功",returnMap); + } catch (Exception e) { + log.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); + } + } else { + String errDesc = returnMap.get("err_code_des"); + if (errDesc.equalsIgnoreCase("订单已全额退款")) { + return new RefundAdapterResult(true,EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(),"退款订单申请成功",returnMap); + } + log.error("微信退款订单申请失败: " + response); + String errMsg = ""; + JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); + if (errObj != null) { + errMsg = errObj.toJSONString(); + record.setFailReason(errMsg); + } else { + errMsg = returnMap.get("return_msg"); + record.setFailReason(errMsg); + } + if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { + // 更新券状态 + throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); + } + return new RefundAdapterResult(false, EnumRefundStatus.REFUND_REQ_FAIL.getCode(), errMsg, returnMap); + } + } + + + private WxRefundOrderSP generateWxRefundOrderSP(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,EnumPayType payType) { + String noncestr = Utility.generate32UUID(); + WxRefundOrderSP wxRefundOrderSP = new WxRefundOrderSP(); + wxRefundOrderSP.setAppid(appInfo.getParentAppId()); + wxRefundOrderSP.setSub_appid(appInfo.getAppId()); + wxRefundOrderSP.setMch_id(payAccount.getMchId()); + wxRefundOrderSP.setSub_mch_id(payAccount.getSubMchId()); + wxRefundOrderSP.setNonce_str(noncestr); + // 微信内部订单号 + if (record.getTransactionId() != null) + wxRefundOrderSP.setTransaction_id(record.getTransactionId()); + // 支付订单号 + wxRefundOrderSP.setOut_trade_no(payOrder.getPayOrderNo()); + // 退款支付订单号 + wxRefundOrderSP.setOut_refund_no(String.valueOf(record.getId())); + wxRefundOrderSP.setTotal_fee(record.getTotalFee()); + wxRefundOrderSP.setRefund_fee(record.getRefundFee()); + if(null != payType) { + if (payType == EnumPayType.PAY_B_REFUND) { + wxRefundOrderSP.setRefund_desc("B端商户退款"); + } else if (payType == EnumPayType.PAY_ADMIN_REFUND) { + wxRefundOrderSP.setRefund_desc("管理端商户退款"); + } else if (payType == EnumPayType.PAY_AUTO_REFUND) { + wxRefundOrderSP.setRefund_desc("超期自动退款"); + } else { + wxRefundOrderSP.setRefund_desc("用户自己退款"); + } + } + wxRefundOrderSP.setNotify_url(payAccount.getRefundNotifyUrl()); + wxRefundOrderSP.setSign_type("HMAC-SHA256"); + return wxRefundOrderSP; + } + + private RefundAdapterResult getResultFromSp(String response,WxRefundOrder record,WxPayOrder payOrder) { + Map returnMap = WxPayment.xmlToMap(response); + String result_no = returnMap.get("result_code"); + String refund_id = returnMap.get("refund_id"); + // 设置 微信退款订单号 + record.setRefundId(refund_id); + record.setRefundVendor(payOrder.getPayVendor()); + if ("SUCCESS".equals(result_no)) { + log.info("微信退款订单申请成功: " + returnMap.toString()); + try { + return new RefundAdapterResult(true, EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(), "退款订单申请成功", returnMap); + } catch (Exception e) { + log.error("微信退款订单更新入库出错: " + e.getMessage() + ", record: " + record.toString()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "订单状态更新失败"); + } + } else { + // 特殊处理 + String errDesc = returnMap.get("err_code_des"); + if (errDesc.equalsIgnoreCase("订单已全额退款")) { + return new RefundAdapterResult(true, EnumRefundStatus.REFUND_REQ_SUCCESS.getCode(), "退款订单申请成功", returnMap); + } + log.error("微信退款订单申请失败: " + response); + String errMsg = ""; + JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); + if (errObj != null) { + errMsg = errObj.toJSONString(); + record.setFailReason(errMsg); + } else { + errMsg = returnMap.get("err_code_des"); + record.setFailReason(errMsg); + } + if (errDesc.equalsIgnoreCase("超期订单不允许退款")) { + // 更新券状态 + throw new MallinkException(ErrorCode.REFUND_NOT_ALLOW); + } + return new RefundAdapterResult(false,EnumRefundStatus.REFUND_REQ_FAIL.getCode(),errMsg,returnMap); + } + } + + @Override + public RefundAdapterResult refund(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,EnumPayType payType) { + if (StringUtils.isBlank(payAccount.getApiKey())) { + log.error("支付密钥为空"); + throw new MallinkException(ErrorCode.API_KEY_NOT_FOUND.getCode(), "支付密钥为空,请联系商城管理员"); + } + if (StringUtils.isBlank(payAccount.getCertPath())) { + log.error("证书路径为空"); + throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书路径为空,请联系商城管理员"); + } + if (!Utility.isFileExist(payAccount.getCertPath())) { + log.error("证书文件不存在"); + throw new MallinkException(ErrorCode.CERT_PATH_NOT_FOUND.getCode(), "证书文件不存在,请联系商城管理员"); + } + + // 实际支付 + // 向微信提交退款申请 + if (payAccount.getType() == EnumPayMode.MCH.getCode()) { + // 普通商户模式 + WxRefundOrderP wxRefundOrderP = generateWxRefundOrderP(payAccount, appInfo, record, payOrder, payType); + + Map signMap = null; + try { + signMap = BeanUtils.toStringMap(wxRefundOrderP); + } catch (Exception e) { + log.error("退款命令生辰: " + e.getMessage()); + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); + } + + String signAgent = WxPayment.createSign(signMap, payAccount.getApiKey()); + signMap.put("sign", signAgent); + String response = null; + try { + response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); + } catch (Exception e) { + log.error("退款异常: " + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); + } + log.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString()); + return getReusltFromp(response, record, payOrder); + } else { + // 服务商模式 + WxRefundOrderSP wxRefundOrderSP = generateWxRefundOrderSP(payAccount, appInfo, record, payOrder, payType); + + Map signMap = null; + try { + signMap = BeanUtils.toStringMap(wxRefundOrderSP); + } catch (Exception e) { + log.error("退款命令生成: " + e.getMessage()); + throw new MallinkException(ErrorCode.SYS_PARAMETER_CAST_ERROR.getCode(), "退款签名异常"); + } + + String signAgent = WxPayment.createSignHMAC(signMap, payAccount.getApiKey()); + signMap.put("sign", signAgent); + String response = null; + try { + response = WxPay.orderRefund(signMap, payAccount.getCertPath(), payAccount.getMchId()); + } catch (Exception e) { + log.error("退款异常: " + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); + } + log.info("微信退款订单:" + wxRefundOrderSP.toString() + ", response: " + response.toString()); + return getResultFromSp(response, record, payOrder); + } + } + + @Override + public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { + if (payAccount.getType() == EnumPayMode.MCH.getCode()) { + Map paramMap = WxPayment.buildWeappRefundQueryMap( + appInfo.getAppId(), payAccount.getMchId(), + record.getTransactionId(), record.getPayOrderNo(), String.valueOf(record.getId()), + record.getRefundId(), payAccount.getApiKey()); + String response = WxPay.orderRefundQuery(paramMap); + Map returnMap = WxPayment.xmlToMap(response); + String result_no = returnMap.get("result_code"); + if ("SUCCESS".equals(result_no)) { + String refund_id = returnMap.get("refund_id"); + return new RefundAdapterResult(true,0,"退款",returnMap); + } else { + String errMsg = ""; + JSONObject errObj = errorRefundReqMap.getJSONObject(result_no); + if (errObj != null) { + errMsg = errObj.toJSONString(); + } else { + errMsg = returnMap.get("return_msg"); + } + return new RefundAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),errMsg,returnMap); + } + } else { + Map paramMap = WxPayment.buildSWeappRefundQueryMap( + appInfo.getParentAppId(), appInfo.getAppId(), payAccount.getMchId(), payAccount.getSubMchId(), + record.getTransactionId(), record.getPayOrderNo(), String.valueOf(record.getId()), record.getRefundId(), payAccount.getApiKey()); + String response = WxPay.orderRefundQuery(paramMap); + Map returnMap = WxPayment.xmlToMap(response); + String result_no = returnMap.get("result_code"); + if ("SUCCESS".equals(result_no)) { + String refund_id = returnMap.get("refund_id"); + return new RefundAdapterResult(true,0,"退款",returnMap); + } else { + String errMsg = ""; + JSONObject errObj = errorRefundQueryMap.getJSONObject(result_no); + if (errObj != null) { + errMsg = errObj.toJSONString(); + } else { + errMsg = returnMap.get("return_msg"); + } + return new RefundAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),errMsg,returnMap); + } + } + } + + @Autowired + WxAppinfoMapper wxAppinfoMapper; + @Autowired + WxPayAccountMapper wxPayAccountMapper; + @Autowired + WxPayOrderMapper wxPayOrderMapper; + @Autowired + WxRefundOrderMapper wxRefundOrderMapper; + + + private RefundNotifyAdapterResult notifyErrorResult(String msg) { + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "FAIL"); + resultMap.put("return_msg", msg); + return new RefundNotifyAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),msg,XmlUtil.getRequestXml(resultMap)); + } + + private RefundNotifyAdapterResult notifySuccessResult(String transactionId,String refundId,WxRefundOrder refundOrder) { + SortedMap resultMap = new TreeMap(); + resultMap.put("return_code", "SUCCESS"); + resultMap.put("return_msg", "OK"); + return new RefundNotifyAdapterResult(transactionId, refundId,refundOrder,XmlUtil.getRequestXml(resultMap)); + } + + + @Override + public RefundNotifyAdapterResult notify(Map paramMap, EnumPayWay payWay) { + // how to get wechatAppId, wechatMchId, partnerKey + String appId = paramMap.get("appid"); + String subAppId = paramMap.get("sub_appid"); + String mchId = paramMap.get("mch_id"); + String subMchId = paramMap.get("sub_mch_id"); + if (StringUtils.isBlank(subAppId) && StringUtils.isBlank(subMchId)) { + // 普通商户号 + WxAppinfo appinfo = wxAppinfoMapper.findByAppId(appId); + if (appinfo == null) { + log.error("未找到appid信息:" + appId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId()); + if (payAccount == null) { + log.error("未找到mch_id信息:" + mchId); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); + } + if (!mchId.equalsIgnoreCase(payAccount.getMchId())) { + log.error("mch_id不对应:" + mchId + ",account:" + payAccount.getMchId()); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_EQUAL); + } + String partnerKey = payAccount.getApiKey(); + try { + if (payWay.getType() == EnumPayWay.EnumPayWayType.WX_MINIPAY) { + if (!"SUCCESS".equals(paramMap.get("return_code"))) { + log.warn("notify refund, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单状态码非SUCCESS"); + } + + // 解密req_info + String req_info = CipherUtil.decryptReqInfo(paramMap.get("req_info"), partnerKey); + Map reqMap = WxPayment.xmlToMap(req_info); + + String payOrderNo = reqMap.get("out_trade_no"); + Long payOrderId = Long.valueOf(payOrderNo); + WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId); + if (payOrder == null) { + log.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("支付订单不存在"); + } + // 验证支付金额 + if (!reqMap.get("total_fee").equals(payOrder.getPayAmount().toString())) { + log.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("支付订单总金额不一致"); + } + String refundIdStr = reqMap.get("out_refund_no"); + Long refundOrderId = Long.valueOf(refundIdStr); + WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId); + if (refundOrder == null) { + log.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("退款订单不存在"); + } + // 验证支付金额 + if (!reqMap.get("total_fee").equals(refundOrder.getTotalFee().toString())) { + log.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单总金额不一致"); + } + // 验证退款金额 + if (!reqMap.get("refund_fee").equals(refundOrder.getRefundFee().toString())) { + log.warn("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("退款总金额不一致"); + } + + // 处理支付成功 + //handleRefundSuccess(refundOrder, reqMap.get("transaction_id"), reqMap.get("refund_id")); + log.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifySuccessResult(reqMap.get("transaction_id"), reqMap.get("refund_id"), refundOrder); + } + } catch (RuntimeException e) { + log.warn("notify refund paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); + } catch (Exception e) { + log.warn("notify refund, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); + } + } else { + // 服务号回调 + WxAppinfo appinfo = wxAppinfoMapper.findByAppId(subAppId); + if (appinfo == null) { + log.error("未找到appid信息:" + appId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + WxPayAccount payAccount = wxPayAccountMapper.selectById(appinfo.getPayId()); + if (payAccount == null) { + log.error("未找到mch_id信息:" + mchId); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); + } + if (!mchId.equalsIgnoreCase(payAccount.getMchId())) { + log.error("mch_id不对应:" + mchId + ",account:" + payAccount.getMchId()); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_EQUAL); + } + String partnerKey = payAccount.getApiKey(); + try { + if (payWay.getType() == EnumPayWay.EnumPayWayType.WX_MINIPAY) { + if (!"SUCCESS".equals(paramMap.get("return_code"))) { + log.warn("notify order, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单状态码非SUCCESS"); + } + + // 解密req_info + String req_info = CipherUtil.decryptReqInfo(paramMap.get("req_info"), partnerKey); + log.info(req_info); + Map reqMap = WxPayment.xmlToMap(req_info); + + String payOrderNo = reqMap.get("out_trade_no"); + if (payOrderNo == null) { + return notifySuccessResult(reqMap.get("transaction_id"), reqMap.get("refund_id"), null); + } + Long payOrderId = Long.valueOf(payOrderNo); + WxPayOrder payOrder = wxPayOrderMapper.selectById(payOrderId); + if (payOrder == null) { + log.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("支付订单不存在"); + } + // 验证支付金额 + if (!reqMap.get("total_fee").equals(payOrder.getPayAmount().toString())) { + log.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("支付订单总金额不一致"); + } + String refundIdStr = reqMap.get("out_refund_no"); + Long refundOrderId = Long.valueOf(refundIdStr); + WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId); + if (refundOrder == null) { + log.warn("notify refund, wxpay check pay order not exists, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("退款订单不存在"); + } + // 验证支付金额 + if (!reqMap.get("total_fee").equals(refundOrder.getTotalFee().toString())) { + log.warn("notify refund, wxpay check total_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单总金额不一致"); + } + // 验证退款金额 + if (!reqMap.get("refund_fee").equals(refundOrder.getRefundFee().toString())) { + log.warn("notify refund, wxpay check refund_fee is invalid, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("退款总金额不一致"); + } + + log.info("notify refund, wxpay checksign success, paramMap:{}, paramMap: " + reqMap.toString() + ", payWay:" + payWay.toString()); + return notifySuccessResult(reqMap.get("transaction_id"), reqMap.get("refund_id"), refundOrder); + } + } catch (RuntimeException e) { + log.warn("notify refund, wepay checksign error, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); + } catch (Exception e) { + log.warn("notify refund, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString() + ", e:" + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getMessage()); + } + } + + return notifyErrorResult("FAILED"); + } + +}