diff --git a/suimangService/src/main/java/com/iformall/domain/po/ProductOrderRefund.java b/suimangService/src/main/java/com/iformall/domain/po/ProductOrderRefund.java new file mode 100644 index 0000000..c98be75 --- /dev/null +++ b/suimangService/src/main/java/com/iformall/domain/po/ProductOrderRefund.java @@ -0,0 +1,84 @@ +package com.iformall.domain.po; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.iformall.domain.po.base.TenantEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.math.BigDecimal; +import java.util.Date; + +@TableName(value = "product_order_refund") +@Data +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) +public class ProductOrderRefund extends TenantEntity { + + protected Long id; + + @io.swagger.annotations.ApiModelProperty(value="系统订单号",name="orderId") + private Long orderId; + @io.swagger.annotations.ApiModelProperty(value="系统订单号",name="orderNumber") + private String orderNumber; + + @io.swagger.annotations.ApiModelProperty(value="EnumProject",name="projectType") + private Integer projectType; + @io.swagger.annotations.ApiModelProperty(value = "EnumProductOrderPayVendor", name = "payVendor") + private Integer payVendor; + + @io.swagger.annotations.ApiModelProperty(value="用户id",name="userId") + private Long userId; + + @io.swagger.annotations.ApiModelProperty(value="支付id",name="payId") + private Long payId; + + @io.swagger.annotations.ApiModelProperty(value="第三方订单号",name="transactionId") + private String transactionId; + + @io.swagger.annotations.ApiModelProperty(value="订单金额(分)",name="payAmount") + private Integer payAmount; + + @io.swagger.annotations.ApiModelProperty(value="退款金额(分)",name="refundAmount") + private Integer refundAmount; + + @io.swagger.annotations.ApiModelProperty(value="EnumRefundOrderStatus",name="refundOrderStatus") + private Integer refundOrderStatus; + + @io.swagger.annotations.ApiModelProperty(value="失败原因",name="failReason") + private String failReason; + + @io.swagger.annotations.ApiModelProperty(value="",name="refundId") + private String refundId; + + @io.swagger.annotations.ApiModelProperty(value="退款原因",name="refundReason") + private String refundReason; + + @io.swagger.annotations.ApiModelProperty(value="退款补充原因",name="refundDescription") + private String refundDescription; + + @io.swagger.annotations.ApiModelProperty(value="创建时间",name="createDate") + private Date createDate; + @io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateDate") + private Date updateDate; + + @TableField(exist = false) + private String payAmountStr; + public String getPayAmountStr() { + return payAmount != null ? new BigDecimal(payAmount).divide(new BigDecimal(100)).toPlainString() : payAmountStr; + } + + @TableField(exist = false) + private String refundAmountStr; + public String getRefundAmountStr() { + return refundAmount != null ? new BigDecimal(refundAmount).divide(new BigDecimal(100)).toPlainString() : refundAmountStr; + } + + @TableField(exist = false) + private Date startDate; + + @TableField(exist = false) + private Date endDate; + +} diff --git a/suimangService/src/main/java/com/iformall/enums/EnumRefundOrderStatus.java b/suimangService/src/main/java/com/iformall/enums/EnumRefundOrderStatus.java new file mode 100644 index 0000000..97c09f3 --- /dev/null +++ b/suimangService/src/main/java/com/iformall/enums/EnumRefundOrderStatus.java @@ -0,0 +1,39 @@ +package com.iformall.enums; + +/** + * + */ +public enum EnumRefundOrderStatus { + REFUND_WAIT(0, "退款中"), + REFUND_REQ_SUCCESS(1, "退款申请成功"), + REFUND_REQ_FAIL(2, "退款申请失败"), + REFUND_REQ_AGREE(3, "同意退款"), + REFUND_SUCCESS(4, "退款成功"), + REFUND_FAIL(5, "退款失败"), + ; + + public static EnumRefundOrderStatus getEnum(Integer code) { + for (EnumRefundOrderStatus value : values()) { + if (value.getCode().equals(code)) { + return value; + } + } + return null; + } + + private Integer code; + private String message; + + EnumRefundOrderStatus(Integer code, String message) { + this.code = code; + this.message = message; + } + + public Integer getCode() { + return code; + } + + public String getMessage() { + return message; + } +} diff --git a/suimangService/src/main/java/com/iformall/mapper/ProductOrderRefundMapper.java b/suimangService/src/main/java/com/iformall/mapper/ProductOrderRefundMapper.java new file mode 100644 index 0000000..828bf15 --- /dev/null +++ b/suimangService/src/main/java/com/iformall/mapper/ProductOrderRefundMapper.java @@ -0,0 +1,15 @@ +package com.iformall.mapper; + +import com.iformall.common.CommonMapper; +import com.iformall.domain.po.ProductOrderPay; +import com.iformall.domain.po.ProductOrderRefund; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +public interface ProductOrderRefundMapper extends CommonMapper { + + List findList(ProductOrderRefund record); + + int orderRefundUpdStatus(ProductOrderRefund record); +} diff --git a/suimangService/src/main/java/com/iformall/service/ProductOrderRefundService.java b/suimangService/src/main/java/com/iformall/service/ProductOrderRefundService.java new file mode 100644 index 0000000..9ad9fac --- /dev/null +++ b/suimangService/src/main/java/com/iformall/service/ProductOrderRefundService.java @@ -0,0 +1,31 @@ +package com.iformall.service; + +import com.github.pagehelper.PageInfo; +import com.iformall.common.ResultData; +import com.iformall.domain.po.ProductOrderPay; +import com.iformall.domain.po.ProductOrderRefund; +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxPayAccount; +import com.iformall.enums.EnumProductOrderPayVendor; +import com.iformall.service.pay.service.pay.PayAdapterService; +import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; + +public interface ProductOrderRefundService { + + /** + * 根据实体查询分页列表 + * + * @param record + * @param pageIndex + * @param pageSize + * @return + */ + PageInfo listAsPage(ProductOrderRefund record, Integer pageIndex, Integer pageSize); + + void saveOrUpdate(ProductOrderRefund record); + + ProductOrderRefund getById(Long id); + + void handleRefund(ProductOrderPay orderPay); + +} diff --git a/suimangService/src/main/java/com/iformall/service/impl/ProductOrderPayServiceImpl.java b/suimangService/src/main/java/com/iformall/service/impl/ProductOrderPayServiceImpl.java index c0d8057..b62e9a6 100644 --- a/suimangService/src/main/java/com/iformall/service/impl/ProductOrderPayServiceImpl.java +++ b/suimangService/src/main/java/com/iformall/service/impl/ProductOrderPayServiceImpl.java @@ -17,6 +17,7 @@ import com.iformall.service.pay.PayServiceFactory; import com.iformall.service.pay.service.pay.PayAdapterService; import com.iformall.service.pay.service.pay.entity.PayAdapterResult; import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; +import com.iformall.service.pay.service.refund.RefundPayAdapterService; import com.iformall.utils.DateUtils; import com.iformall.utils.RedisLock; import lombok.extern.slf4j.Slf4j; @@ -58,6 +59,9 @@ public class ProductOrderPayServiceImpl implements ProductOrderPayService { @Autowired WxPayAccountService wxPayAccountService; + @Autowired + ProductOrderRefundService productOrderRefundService; + @Autowired PayServiceFactory payServiceFactory; @@ -246,8 +250,7 @@ public class ProductOrderPayServiceImpl implements ProductOrderPayService { if(EnumPayOrderStatus.ORDER_STATUS_REFUND_WAIT.getCode().equals(productOrderPay.getPayOrderStatus())){ logger.info("当前订单异常支付,退款处理"); - //todo 退款 - + productOrderRefundService.handleRefund(productOrderPay); return; } diff --git a/suimangService/src/main/java/com/iformall/service/impl/ProductOrderRefundServiceImpl.java b/suimangService/src/main/java/com/iformall/service/impl/ProductOrderRefundServiceImpl.java new file mode 100644 index 0000000..03ae4ea --- /dev/null +++ b/suimangService/src/main/java/com/iformall/service/impl/ProductOrderRefundServiceImpl.java @@ -0,0 +1,122 @@ +package com.iformall.service.impl; + +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import com.iformall.common.ErrorCode; +import com.iformall.common.IdWorker; +import com.iformall.common.ResultData; +import com.iformall.domain.po.*; +import com.iformall.enums.*; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.*; +import com.iformall.service.*; +import com.iformall.service.pay.PayServiceFactory; +import com.iformall.service.pay.service.pay.PayAdapterService; +import com.iformall.service.pay.service.pay.entity.PayAdapterResult; +import com.iformall.service.pay.service.pay.entity.PayQueryAdapterResult; +import com.iformall.service.pay.service.refund.RefundPayAdapterService; +import com.iformall.service.pay.service.refund.entity.RefundAdapterResult; +import com.iformall.utils.RedisLock; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.aop.framework.AopContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; + +@Service +@Slf4j +public class ProductOrderRefundServiceImpl implements ProductOrderRefundService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + ProductOrderRefundMapper productOrderRefundMapper; + + @Autowired + ProductOrderPayMapper productOrderPayMapper; + + @Autowired + PayServiceFactory payServiceFactory; + + @Autowired + WxAppinfoService wxAppinfoService; + + @Autowired + WxPayAccountService wxPayAccountService; + + @Override + public PageInfo listAsPage(ProductOrderRefund record, Integer pageIndex, Integer pageSize) { + return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> productOrderRefundMapper.findList(record)); + } + + @Override + public void saveOrUpdate(ProductOrderRefund record) { + Date now = new Date(); + if (record.getId() == null) { + final IdWorker idWorker = IdWorker.get(); + record.setId(idWorker.nextId()); + record.setCreateDate(now); + record.setUpdateDate(now); + productOrderRefundMapper.insert(record); + } else { + record.setUpdateDate(now); + productOrderRefundMapper.updateById(record); + } + } + + @Override + public ProductOrderRefund getById(Long id) { + return productOrderRefundMapper.selectById(id); + } + + @Override + public void handleRefund(ProductOrderPay orderPay) { + String refundReason = "重复支付退款"; + + Date now = new Date(); + ProductOrderRefund record = new ProductOrderRefund(); + final IdWorker idWorker = IdWorker.get(); + record.setId(idWorker.nextId()); + record.setOrderId(orderPay.getOrderId()); + record.setOrderNumber(orderPay.getOrderNumber()); + record.setProjectType(orderPay.getProjectType()); + record.setPayVendor(orderPay.getPayVendor()); + record.setUserId(orderPay.getUserId()); + record.setPayId(orderPay.getId()); + record.setTransactionId(orderPay.getTransactionId()); + record.setPayAmount(orderPay.getPayAmount()); + record.setRefundAmount(orderPay.getPayAmount()); + record.setRefundOrderStatus(EnumRefundOrderStatus.REFUND_WAIT.getCode()); + record.setRefundReason(refundReason); + record.setCreateDate(now); + record.setUpdateDate(now); + productOrderRefundMapper.insert(record); + + RefundPayAdapterService refundPayAdapterService = payServiceFactory.getRefundPayAdapterService(record.getPayVendor()); + + EnumProductOrderPayVendor payVendorEnum = EnumProductOrderPayVendor.getEnum(record.getPayVendor()); + WxAppinfo appinfo = wxAppinfoService.getProjectCAppInfoFromRedis(record.getProjectType(), payVendorEnum.getPlat()); + WxPayAccount payAccount = wxPayAccountService.getByIdFromRedis(appinfo.getPayId()); + + RefundAdapterResult refund = refundPayAdapterService.refund(appinfo, payAccount, record); + if(refund.isSuccess()){ + ProductOrderRefund orderRefundUpd = new ProductOrderRefund(); + orderRefundUpd.setId(record.getId()); + orderRefundUpd.setRefundId(refund.getRefundId()); + orderRefundUpd.setRefundOrderStatus(EnumRefundOrderStatus.REFUND_REQ_SUCCESS.getCode()); + productOrderRefundMapper.updateById(orderRefundUpd); + + ProductOrderPay orderPayUpd = new ProductOrderPay(); + orderPayUpd.setId(orderPay.getId()); + orderPayUpd.setPayOrderStatus(EnumPayOrderStatus.ORDER_STATUS_PENDING_REFUND.getCode()); + productOrderPayMapper.orderPayUpdStatus(orderPayUpd); + } + + } + +} diff --git a/suimangService/src/main/java/com/iformall/service/pay/PayServiceFactory.java b/suimangService/src/main/java/com/iformall/service/pay/PayServiceFactory.java index 01ec892..60fdb01 100644 --- a/suimangService/src/main/java/com/iformall/service/pay/PayServiceFactory.java +++ b/suimangService/src/main/java/com/iformall/service/pay/PayServiceFactory.java @@ -6,6 +6,7 @@ import com.iformall.enums.EnumAppPlat; import com.iformall.enums.EnumPayVersion; import com.iformall.enums.EnumProductOrderPayVendor; import com.iformall.service.pay.service.pay.wx.v3.nativePay.WxNativePayV3AdapterService; +import com.iformall.service.pay.service.refund.ali.AliRefundAdapterService; import com.iformall.service.pay.service.refund.douyin.TtRefundAdapterService; import com.iformall.service.pay.service.refund.wx.v2.WxRefundAdapterService; import com.iformall.service.pay.service.refund.wx.v3.WxRefundV3AdapterService; @@ -50,6 +51,7 @@ public class PayServiceFactory { private Map payVendorServiceMap = null; private Map payVendorShareMap = null; + private Map payVendorRefundMap = null; private Map platQrcodeMap = null; private Map platMsgMap = null; @@ -92,6 +94,8 @@ public class PayServiceFactory { @Autowired TtRefundAdapterService ttRefundService; + @Autowired + AliRefundAdapterService aliRefundService; @Autowired WxCashOutQYFKAdapterService wxCashOutService; @@ -235,6 +239,18 @@ public class PayServiceFactory { } return refundMap; } + + private Map getPayVendorRefundMap(){ + if (null == payVendorRefundMap ) { + payVendorRefundMap = new ConcurrentHashMap(); + payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_WECHAT.getCode()+"_", wxRefundV3AdapterService); + payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_WECHAT_NATIVE.getCode()+"_", wxRefundV3AdapterService); + payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_ALIPAY.getCode()+"_", aliRefundService); +// payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_ALIPAY_WAP.getCode()+"_",); + payVendorRefundMap.put(EnumProductOrderPayVendor.PAY_WAY_TT.getCode()+"_",ttRefundService); + } + return payVendorRefundMap; + } private Map getCashOutMap() { if (null == cashoutMap ) { @@ -334,6 +350,14 @@ public class PayServiceFactory { } return refundService; } + + public RefundPayAdapterService getRefundPayAdapterService(Integer payVendor) throws MallinkException{ + RefundPayAdapterService refundService = getPayVendorRefundMap().get(payVendor+"_"); + if (null == refundService) { + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payWay["+payVendor+"] 退款service未找到"); + } + return refundService; + } public CashOutAdapterService getCashOutAdapterService(Integer type,Integer payVersion)throws MallinkException { CashOutAdapterService cashOutService = getCashOutMap().get(type+"_"+payVersion); diff --git a/suimangService/src/main/java/com/iformall/service/pay/service/refund/RefundPayAdapterService.java b/suimangService/src/main/java/com/iformall/service/pay/service/refund/RefundPayAdapterService.java index 7bb406a..28a0012 100644 --- a/suimangService/src/main/java/com/iformall/service/pay/service/refund/RefundPayAdapterService.java +++ b/suimangService/src/main/java/com/iformall/service/pay/service/refund/RefundPayAdapterService.java @@ -2,10 +2,7 @@ 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.domain.po.*; import com.iformall.enums.EnumPayType; import com.iformall.enums.EnumPayWay; import com.iformall.service.pay.service.refund.entity.RefundAdapterResult; @@ -23,6 +20,8 @@ public interface RefundPayAdapterService { * @return */ public RefundAdapterResult refund(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,Long orderId,EnumPayType payType); + + public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund); /** * API查询退款 @@ -32,6 +31,8 @@ public interface RefundPayAdapterService { * @return */ public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record); + + public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, ProductOrderRefund orderRefund); /** * 平台方 异步通知 diff --git a/suimangService/src/main/java/com/iformall/service/pay/service/refund/ali/AliRefundAdapterService.java b/suimangService/src/main/java/com/iformall/service/pay/service/refund/ali/AliRefundAdapterService.java new file mode 100644 index 0000000..22aef90 --- /dev/null +++ b/suimangService/src/main/java/com/iformall/service/pay/service/refund/ali/AliRefundAdapterService.java @@ -0,0 +1,199 @@ +package com.iformall.service.pay.service.refund.ali; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alipay.api.AlipayApiException; +import com.alipay.api.AlipayClient; +import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest; +import com.alipay.api.request.AlipayTradeRefundRequest; +import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse; +import com.alipay.api.response.AlipayTradeRefundResponse; +import com.iformall.common.ErrorCode; +import com.iformall.domain.po.*; +import com.iformall.douyin.pay.TtPayService; +import com.iformall.douyin.pay.exception.TtPayException; +import com.iformall.douyin.payv2.request.TtPayRefundQueryV2Request; +import com.iformall.douyin.payv2.request.TtPayRefundV2Request; +import com.iformall.douyin.payv2.result.TtPayRefundQueryV2Result; +import com.iformall.douyin.payv2.result.TtPayRefundV2Result; +import com.iformall.enums.EnumPayType; +import com.iformall.enums.EnumPayWay; +import com.iformall.enums.EnumRefundOrderStatus; +import com.iformall.enums.EnumRefundStatus; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxPayOrderMapper; +import com.iformall.mapper.WxRefundOrderMapper; +import com.iformall.service.WxAppinfoService; +import com.iformall.service.WxOrderService; +import com.iformall.service.WxPayAccountService; +import com.iformall.service.pay.service.refund.RefundPayAdapterService; +import com.iformall.service.pay.service.refund.entity.RefundAdapterResult; +import com.iformall.service.pay.service.refund.entity.RefundNotifyAdapterResult; +import com.iformall.utils.Constant; +import com.iformall.utils.MaUtil; +import com.iformall.utils.XmlUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +@Slf4j +@Service +public class AliRefundAdapterService implements RefundPayAdapterService{ + + @Autowired + MaUtil maUtil; + + /** + * 做为分账的扩展数据 + * @param + * @return + */ + protected String getCpExtra(WxRefundOrder record) { + Map map = new HashMap<>(); + map.put("tenantId",record.getTenantId()); + return JSON.toJSONString(map); + } + + @Override + public RefundAdapterResult refund(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,Long orderId,EnumPayType payType) { + return null; + } + + @Override + public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { + AlipayClient aliPayClient = maUtil.getAliPayClient(appInfo, payAccount); + AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); + JSONObject bizContent = new JSONObject(); + bizContent.put("out_trade_no", orderRefund.getOrderNumber()); + bizContent.put("refund_amount", orderRefund.getRefundAmountStr()); + bizContent.put("refund_reason", orderRefund.getRefundDescription()); + bizContent.put("out_request_no", orderRefund.getId().toString()); + + //// 返回参数选项,按需传入 + //JSONArray queryOptions = new JSONArray(); + //queryOptions.add("refund_detail_item_list"); + //bizContent.put("query_options", queryOptions); + + request.setBizContent(bizContent.toString()); + + try { + AlipayTradeRefundResponse response = aliPayClient.execute(request); + if(response.isSuccess()){ + if("10000".equals(response.getCode())){ + RefundAdapterResult refundAdapterResult = new RefundAdapterResult(); + refundAdapterResult.setSuccess(true); + refundAdapterResult.setCode(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); + refundAdapterResult.setData(response); + return refundAdapterResult; + } + } + return new RefundAdapterResult(false,EnumRefundStatus.REFUND_REQ_FAIL.getCode(),response.getMsg(),response); + } catch (AlipayApiException e) { + log.error("支付宝退款失败{}"+e.getMessage()); + e.printStackTrace(); + return new RefundAdapterResult(false,EnumRefundStatus.REFUND_REQ_FAIL.getCode(),EnumRefundStatus.REFUND_REQ_FAIL.getMessage(),null); + } + } + + @Override + public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { + return null; + } + + @Override + public RefundAdapterResult queryRefund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { + AlipayClient aliPayClient = maUtil.getAliPayClient(appInfo, payAccount); + AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest(); + JSONObject bizContent = new JSONObject(); + bizContent.put("out_trade_no", orderRefund.getOrderNumber()); + bizContent.put("out_request_no", orderRefund.getId()); + + //// 返回参数选项,按需传入 + //JSONArray queryOptions = new JSONArray(); + //queryOptions.add("refund_detail_item_list"); + //bizContent.put("query_options", queryOptions); + + request.setBizContent(bizContent.toString()); + try { + AlipayTradeFastpayRefundQueryResponse response = aliPayClient.execute(request); + if(response.isSuccess()){ + if("REFUND_SUCCESS".equals(response.getRefundStatus())){ + return new RefundAdapterResult(true, EnumRefundOrderStatus.REFUND_SUCCESS.getCode(),"退款成功",response); + } + return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_FAIL.getCode(),"退款失败",response); + } + } catch (AlipayApiException e) { + e.printStackTrace(); + log.error("查询支付宝退款结果失败"+e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),e.getMessage()); + } + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); + } + + + @Autowired + WxAppinfoService wxAppinfoService; + @Autowired + WxPayAccountService wxPayAccountService; + @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) { + log.info("TtRefundAdapterService notify{}"+paramMap); + String tenantId = paramMap.get("tenantId"); + /** + * + */ + String refundno = paramMap.get("cp_refundno"); + Long refundOrderId = Long.valueOf(refundno); + WxRefundOrder refundOrder = wxRefundOrderMapper.selectById(refundOrderId); + + String appId = paramMap.get("appid"); + WxAppinfo appinfo = wxAppinfoService.getByAppIdFromRedis(appId,tenantId); + if (appinfo == null) { + log.error("未找到appid信息:" + appId); + throw new MallinkException(ErrorCode.APP_ID_NOT_FOUND); + } + WxPayAccount payAccount = wxPayAccountService.getByIdFromRedis(appinfo.getPayId()); + if (payAccount == null) { + log.error("未找到mch_id信息:" + appId); + throw new MallinkException(ErrorCode.MCH_INFO_NOT_FOUND); + } + if (!"SUCCESS".equals(paramMap.get("status"))) { + log.error("notify refund, wxpay status not success, paramMap: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifyErrorResult("订单状态码非SUCCESS"); + } + + // 验证退款金额 + if (!paramMap.get("refund_amount").equals(refundOrder.getRefundFee().toString())) { + log.error("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: " + paramMap.toString() + ", payWay:" + payWay.toString()); + return notifySuccessResult(refundOrder.getPayOrderNo(), paramMap.get("cp_refundno"), refundOrder); + } + +} diff --git a/suimangService/src/main/java/com/iformall/service/pay/service/refund/douyin/TtRefundAdapterService.java b/suimangService/src/main/java/com/iformall/service/pay/service/refund/douyin/TtRefundAdapterService.java index 58d4d06..d5a18c1 100644 --- a/suimangService/src/main/java/com/iformall/service/pay/service/refund/douyin/TtRefundAdapterService.java +++ b/suimangService/src/main/java/com/iformall/service/pay/service/refund/douyin/TtRefundAdapterService.java @@ -16,6 +16,7 @@ import com.iformall.douyin.payv2.result.TtPayRefundQueryV2Result; import com.iformall.douyin.payv2.result.TtPayRefundV2Result; import com.iformall.enums.EnumPayType; import com.iformall.enums.EnumPayWay; +import com.iformall.enums.EnumRefundOrderStatus; import com.iformall.enums.EnumRefundStatus; import com.iformall.exception.MallinkException; import com.iformall.mapper.WxPayAccountMapper; @@ -121,7 +122,33 @@ public class TtRefundAdapterService implements RefundPayAdapterService{ // } } - @Override + @Override + public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { + + CreateRefund createRefund = new CreateRefund(); + createRefund.setAppId(appInfo.getAppId()); + createRefund.setSalt(payAccount.getApiKey()); + createRefund.setOutOrderNo(orderRefund.getOrderNumber()); + createRefund.setOutRefundNo(orderRefund.getId().toString()); + createRefund.setReason(orderRefund.getRefundReason()); + createRefund.setRefundAmount(orderRefund.getRefundAmount()); + + + CreateRefundResult refund = DouYinPayHelper.createRefund(createRefund); + if(refund.isSuccess()){ + RefundAdapterResult refundAdapterResult = new RefundAdapterResult(); + refundAdapterResult.setSuccess(true); + refundAdapterResult.setCode(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); + refundAdapterResult.setRefundId(refund.getRefundNo()); + refundAdapterResult.setData(refund); + + return refundAdapterResult; + }else{ + return new RefundAdapterResult(false,EnumRefundStatus.REFUND_REQ_FAIL.getCode(),refund.getMsg(),refund); + } + } + + @Override public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { try { TtPayService ttPayService = maUtil.getTtPayService(appInfo, payAccount); @@ -146,20 +173,23 @@ public class TtRefundAdapterService implements RefundPayAdapterService{ throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常"); } - -// QueryRefundResult queryRefundResult = DouYinPayHelper.refundQuery(appInfo.getAppId(), payAccount.getApiKey(), String.valueOf(record.getId()), null); -// if(queryRefundResult != null){ -// if("SUCCESS".equals(queryRefundResult.getRefundStatus())){ -// return new RefundAdapterResult(true,0,"退款",queryRefundResult); -// }else{ -// return new RefundAdapterResult(false,ErrorCode.REFUND_ORDER_ERROR.getCode(),"退款失败",queryRefundResult); -// } -// }else{ -// throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); -// } } - @Autowired + @Override + public RefundAdapterResult queryRefund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { + QueryRefundResult queryRefundResult = DouYinPayHelper.refundQuery(appInfo.getAppId(), payAccount.getApiKey(), String.valueOf(orderRefund.getId()), null); + if(queryRefundResult != null){ + if("SUCCESS".equals(queryRefundResult.getRefundStatus())){ + return new RefundAdapterResult(true, EnumRefundOrderStatus.REFUND_SUCCESS.getCode(),"退款成功",queryRefundResult); + }else{ + return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_FAIL.getCode(),"退款失败",queryRefundResult); + } + }else{ + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR); + } + } + + @Autowired WxAppinfoService wxAppinfoService; @Autowired WxPayAccountService wxPayAccountService; diff --git a/suimangService/src/main/java/com/iformall/service/pay/service/refund/entity/RefundAdapterResult.java b/suimangService/src/main/java/com/iformall/service/pay/service/refund/entity/RefundAdapterResult.java index e4e8dd4..756abb4 100644 --- a/suimangService/src/main/java/com/iformall/service/pay/service/refund/entity/RefundAdapterResult.java +++ b/suimangService/src/main/java/com/iformall/service/pay/service/refund/entity/RefundAdapterResult.java @@ -8,6 +8,7 @@ public class RefundAdapterResult implements Serializable{ private Integer code; private String msg; private Object data; + private String refundId; public RefundAdapterResult() { @@ -48,4 +49,11 @@ public class RefundAdapterResult implements Serializable{ this.code = code; } + public String getRefundId() { + return refundId; + } + public void setRefundId(String refundId) { + this.refundId = refundId; + } + } diff --git a/suimangService/src/main/java/com/iformall/service/pay/service/refund/wx/v2/WxRefundAdapterService.java b/suimangService/src/main/java/com/iformall/service/pay/service/refund/wx/v2/WxRefundAdapterService.java index b047c3a..a710c79 100644 --- a/suimangService/src/main/java/com/iformall/service/pay/service/refund/wx/v2/WxRefundAdapterService.java +++ b/suimangService/src/main/java/com/iformall/service/pay/service/refund/wx/v2/WxRefundAdapterService.java @@ -5,6 +5,7 @@ import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; +import com.iformall.domain.po.*; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -14,10 +15,6 @@ 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; @@ -408,7 +405,12 @@ public class WxRefundAdapterService implements RefundPayAdapterService{ } } - @Override + @Override + public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { + return null; + } + + @Override public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { if (payAccount.getType() == EnumPayMode.MCH.getCode()) { Map paramMap = WxPayment.buildWeappRefundQueryMap( @@ -503,7 +505,12 @@ public class WxRefundAdapterService implements RefundPayAdapterService{ } } - @Autowired + @Override + public RefundAdapterResult queryRefund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { + return null; + } + + @Autowired WxAppinfoMapper wxAppinfoMapper; @Autowired WxPayAccountMapper wxPayAccountMapper; diff --git a/suimangService/src/main/java/com/iformall/service/pay/service/refund/wx/v3/WxRefundV3AdapterService.java b/suimangService/src/main/java/com/iformall/service/pay/service/refund/wx/v3/WxRefundV3AdapterService.java index 5981452..8b1c137 100644 --- a/suimangService/src/main/java/com/iformall/service/pay/service/refund/wx/v3/WxRefundV3AdapterService.java +++ b/suimangService/src/main/java/com/iformall/service/pay/service/refund/wx/v3/WxRefundV3AdapterService.java @@ -7,6 +7,8 @@ import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; +import com.iformall.domain.po.*; +import com.iformall.enums.*; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; @@ -19,16 +21,6 @@ import com.github.binarywang.wxpay.service.WxPayService; 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.WxOrder; -import com.iformall.domain.po.WxPayAccount; -import com.iformall.domain.po.WxPayOrder; -import com.iformall.domain.po.WxRefundOrder; -import com.iformall.enums.EnumPayMchType; -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; @@ -59,10 +51,6 @@ import lombok.extern.slf4j.Slf4j; @Slf4j @Service public class WxRefundV3AdapterService implements RefundPayAdapterService{ - - - @Autowired - MaUtil maUtil; @Lazy @Autowired @@ -71,6 +59,10 @@ public class WxRefundV3AdapterService implements RefundPayAdapterService{ @Lazy @Autowired WxPayAccountService wxPayAccountService; + + + @Autowired + MaUtil maUtil; private V3PayRefundReq getReq(WxPayAccount payAccount,WxAppinfo appInfo,WxRefundOrder record,WxPayOrder payOrder,Long orderId,EnumPayType payType) { V3PayRefundReq req = new V3PayRefundReq(); @@ -160,6 +152,42 @@ public class WxRefundV3AdapterService implements RefundPayAdapterService{ return getResultFromSp(response, record, payOrder); } + @Override + public RefundAdapterResult refund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { + + WxPayService payService = maUtil.getWxPayServiceBySelfModel(appInfo, payAccount); + + V3PayRefundReq req = new V3PayRefundReq(); + req.setOut_trade_no(orderRefund.getOrderNumber()); + req.setOut_refund_no(orderRefund.getId().toString()); + req.setReason(orderRefund.getFailReason()); + + V3PayRefundAmountReq amount = new V3PayRefundAmountReq(); + amount.setRefund(orderRefund.getRefundAmount()); + amount.setTotal(orderRefund.getPayAmount()); + req.setAmount(amount); + + String response = null; + try { + try { + response = WxPayV3.payCommonRefund(payService, req); + }catch(WxPayException e) { + log.error("weixin pay v3 refund error. " ,e); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getCustomErrorMsg()); + } + } catch (Exception e) { + log.error("退款异常: " + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); + } + JSONObject resp = JSON.parseObject(response); + RefundAdapterResult result = new RefundAdapterResult(); + result.setSuccess(true); + result.setCode(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode()); + result.setRefundId(resp.getString("refund_id")); + result.setData(resp); + return result; + } + @Override public RefundAdapterResult queryRefund(WxAppinfo appInfo,WxPayAccount payAccount, WxRefundOrder record) { // 服务商模式 @@ -192,6 +220,37 @@ public class WxRefundV3AdapterService implements RefundPayAdapterService{ } } + @Override + public RefundAdapterResult queryRefund(WxAppinfo appInfo, WxPayAccount payAccount, ProductOrderRefund orderRefund) { + WxPayService payService = maUtil.getWxPayServiceBySelfModel(appInfo, payAccount); + String response = null; + try { + try { + response = WxPayV3.payCommonRefundQuery(payService, String.valueOf(orderRefund.getId())); + }catch(WxPayException e) { + log.error("weixin pay v3 query refund error " ,e); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), e.getCustomErrorMsg()); + } + JSONObject result = JSON.parseObject(response); + String refund_status_0 = result.getString("status"); + if("SUCCESS".equals(refund_status_0)){ + return new RefundAdapterResult(true, EnumRefundOrderStatus.REFUND_SUCCESS.getCode(),"退款成功",result); + }else if("CLOSED".equals(refund_status_0)){ + return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_FAIL.getCode(),"退款关闭,指商户发起退款失败的情况",result); + }else if("PROCESSING".equals(refund_status_0)){ + return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_REQ_SUCCESS.getCode(),"退款中",result); + }else if("ABNORMAL".equals(refund_status_0)){ + return new RefundAdapterResult(false,EnumRefundOrderStatus.REFUND_FAIL.getCode(), + "退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败。",result); + }else{ + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(),"查询状态异常 非法状态"); + } + } catch (Exception e) { + log.error("退款异常: " + e.getMessage()); + throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR.getCode(), "退款异常"); + } + } + @Autowired WxAppinfoMapper wxAppinfoMapper; @Autowired diff --git a/suimangService/src/main/resources/mapper/ProductOrderPayMapper.xml b/suimangService/src/main/resources/mapper/ProductOrderPayMapper.xml index 58dde04..c6007ae 100644 --- a/suimangService/src/main/resources/mapper/ProductOrderPayMapper.xml +++ b/suimangService/src/main/resources/mapper/ProductOrderPayMapper.xml @@ -89,7 +89,7 @@ - and `order_status` in + and `pay_order_status` in #{sItem} diff --git a/suimangService/src/main/resources/mapper/ProductOrderRefundMapper.xml b/suimangService/src/main/resources/mapper/ProductOrderRefundMapper.xml new file mode 100644 index 0000000..5653ee0 --- /dev/null +++ b/suimangService/src/main/resources/mapper/ProductOrderRefundMapper.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `id`,`tenant_id`,`parent_tenant_id`,`order_id`,`order_number`,`project_type`,`pay_vendor`, + `user_id`,`pay_id`,`transaction_id`,`pay_amount`, + `refund_amount`,`refund_order_status`,`fail_reason`,`refund_id`,`refund_reason`,`refund_description` + `create_date`,`update_date` + + + + where 1 = 1 + + + and `id` = #{id} + + + + and `tenant_id` = #{tenantId} + + + and `parent_tenant_id` = #{parentTenantId} + + + + and `order_id` = #{orderId} + + + and `order_number` = #{orderNumber} + + and `project_type` = #{projectType} + and `pay_vendor` = #{payVendor} + + + and `user_id` = #{userId} + + + and `pay_id` = #{payId} + + + + and `transaction_id` = #{transactionId} + + + + and `refund_order_status` = #{refundOrderStatus} + + + and `create_date` >= #{startDate} + + + and `create_date` <= #{endDate} + + + + and `refund_order_status` in + + #{sItem} + + + + + and id in + + #{idItem} + + + order by ${sortColumns} + + + + + + + update product_order_pay + set `pay_order_status` = #{payOrderStatus} + ,`update_date` = #{updateDate} + + ,`open_id` = #{openId} + + + ,`transaction_id` = #{transactionId} + + + ,`pay_time` = #{payTime} + + + ,`pay_way` = #{payWay} + + where id = #{id} + and `pay_order_status` != #{payOrderStatus} + + and `pay_order_status` = #{isOrderStatus} + + + + + + + + + update product_order_pay + set `pay_order_status` = #{payOrderStatus} + ,`update_date` = now() + where `order_id` = #{orderId} + + +