Просмотр исходного кода

[退款][新增]:微信退款申请及微信退款查询

release_toaliyun_real
Stormeye.Wu 7 лет назад
Родитель
Сommit
a955bb1b19
12 измененных файлов: 855 добавлений и 5 удалений
  1. +71
    -0
      mallinkAdmin/src/main/java/com/simple/controller/WxRefundOrderController.java
  2. +8
    -2
      mallinkService/src/main/java/com/simple/common/ErrorCode.java
  3. +252
    -0
      mallinkService/src/main/java/com/simple/domain/po/WxRefundOrder.java
  4. +39
    -0
      mallinkService/src/main/java/com/simple/enums/EnumRefundStatus.java
  5. +17
    -0
      mallinkService/src/main/java/com/simple/mapper/WxRefundOrderMapper.java
  6. +29
    -0
      mallinkService/src/main/java/com/simple/pay/WxPayment.java
  7. +10
    -1
      mallinkService/src/main/java/com/simple/pay/WxRefundOrderP.java
  8. +68
    -0
      mallinkService/src/main/java/com/simple/service/WxRefundOrderService.java
  9. +6
    -2
      mallinkService/src/main/java/com/simple/service/impl/WxPayOrderServiceImpl.java
  10. +222
    -0
      mallinkService/src/main/java/com/simple/service/impl/WxRefundOrderServiceImpl.java
  11. +5
    -0
      mallinkService/src/main/java/com/simple/utils/RandomUtils.java
  12. +128
    -0
      mallinkService/src/main/resources/mapper/WxRefundOrderMapper.xml

+ 71
- 0
mallinkAdmin/src/main/java/com/simple/controller/WxRefundOrderController.java Просмотреть файл

@@ -0,0 +1,71 @@
package com.simple.controller;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import com.github.pagehelper.PageInfo;
import com.simple.common.Result;
import com.simple.common.ResultData;

import com.simple.domain.po.WxRefundOrder;
import com.simple.service.WxRefundOrderService;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;

@RestController
@RequestMapping("wxRefundOrder")
public class WxRefundOrderController extends BaseController
{
@Autowired
private WxRefundOrderService wxRefundOrderService;

private Logger logger = Logger.getLogger(WxRefundOrderController.class);
@ApiOperation("分页列表接口")
@GetMapping("list")
@ApiImplicitParams({
@ApiImplicitParam(name="pageNum",value="页数",dataType="int", paramType = "query",required=true),
@ApiImplicitParam(name="pageSize",value="每页条数",dataType="int", paramType = "query",required=true)})
public ResultData list(@ModelAttribute WxRefundOrder wxRefundOrder,Integer pageNum, Integer pageSize) {
if (null == wxRefundOrder) wxRefundOrder = new WxRefundOrder();
final PageInfo<WxRefundOrder> page = wxRefundOrderService.listAsPage(wxRefundOrder, pageNum, pageSize);
return new ResultData(page);
}

@ApiOperation("新增接口")
@PostMapping("add")
public ResultData add(@RequestBody WxRefundOrder wxRefundOrder) {
//Assert.notNull(wxRefundOrder.getName(), "角色名不能为空");
//Assert.isTrue(!checkUnique(sysRole.getName(), null), "重复的角色名");
wxRefundOrderService.saveOrUpdate(wxRefundOrder);
return new ResultData();
}

@ApiOperation("根据id更新接口")
@PostMapping("update")
public ResultData update(@RequestBody WxRefundOrder wxRefundOrder) {
wxRefundOrderService.saveOrUpdate(wxRefundOrder);
return new ResultData();
}

@ApiOperation("根据id删除接口")
@GetMapping("/del")
@ApiImplicitParam(name="id",value="id",dataType="Long", paramType = "query",required=true)
public ResultData delete(Long id) {
wxRefundOrderService.deleteById(id);
return new ResultData(Result.SUCCESS, "删除成功", null);
}
@ApiOperation("根据id查询接口")
@GetMapping("/findById")
@ApiImplicitParam(name="id",value="id",dataType="Long", paramType = "query",required=true)
public ResultData findById(Long id) {
return new ResultData(Result.SUCCESS,"查询成功",wxRefundOrderService.getById(id));
}
}

+ 8
- 2
mallinkService/src/main/java/com/simple/common/ErrorCode.java Просмотреть файл

@@ -96,8 +96,14 @@ public enum ErrorCode{
* 支付
*/
PAY_ORDER_EXIST(12001, "支付订单已存在"),
PAY_ORDER_ERROR(12004, "支付订单异常"),
PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR(12005 , "验签失败");
PAY_ORDER_ERROR(12002, "支付订单异常"),
PAY_ORDER_NOTIFY_CHECK_SIGN_ERROR(12003 , "支付验签失败"),

REFUND_ORDER_EXIST(12004, "退款订单已存在"),
REFUND_PAY_ORDER_IS_NOT_EXIST(12005, "退款支付订单不存在"),
REFUND_PAY_ORDER_IS_ZERO(12006, "退款支付订单金额为0"),
REFUND_ORDER_ERROR(12007, "退款订单异常"),
REFUND_ORDER_NOTIFY_CHECK_SIGN_ERROR(12008, "退款验签失败");





+ 252
- 0
mallinkService/src/main/java/com/simple/domain/po/WxRefundOrder.java Просмотреть файл

@@ -0,0 +1,252 @@
package com.simple.domain.po;

import javax.persistence.*;
import java.util.*;
import java.math.*;
import javax.persistence.Transient;
import java.util.List;
import javax.persistence.Id;
import java.io.Serializable;

@Table(name = "wx_refund_order")
public class WxRefundOrder implements Serializable {
private static final long serialVersionUID = 1L;
@Id
protected Long id;
@Transient
protected List<Long> ids;
@Transient
protected String sortColumns;
public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}
public String getSortColumns() {
return sortColumns;
}
public List<Long> getIds() {
return ids;
}

public void setIds(List<Long> ids) {
this.ids = ids;
}
/*租户ID**/
@io.swagger.annotations.ApiModelProperty(value="租户ID",name="tenantId")
private String tenantId;
/*创建时间**/
@io.swagger.annotations.ApiModelProperty(value="创建时间",name="createTime")
private Date createTime;
/*更新时间**/
@io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateTime")
private Date updateTime;
/*微信生成的订单号**/
@io.swagger.annotations.ApiModelProperty(value="微信生成的订单号",name="transactionId")
private String transactionId;
/*订单ID-out_trade_no**/
@io.swagger.annotations.ApiModelProperty(value="订单ID-out_trade_no",name="orderId")
private Long orderId;
/*支付订单号**/
@io.swagger.annotations.ApiModelProperty(value="支付订单号",name="payOrderNo")
private String payOrderNo;
/*用户ID**/
@io.swagger.annotations.ApiModelProperty(value="用户ID",name="cUserId")
private Long cUserId;
/*订单总金额(分)**/
@io.swagger.annotations.ApiModelProperty(value="订单总金额(分)",name="totalFee")
private Integer totalFee;
/*退款总金额**/
@io.swagger.annotations.ApiModelProperty(value="退款总金额",name="refundFee")
private Integer refundFee;
/*退款发起时间(秒)**/
@io.swagger.annotations.ApiModelProperty(value="退款发起时间(秒)",name="refundTimeStart")
private Integer refundTimeStart;
/*退款结束时间(秒)**/
@io.swagger.annotations.ApiModelProperty(value="退款结束时间(秒)",name="refundTimeEnd")
private Integer refundTimeEnd;
/*支付渠道: 0-微信 1-支付宝 2-银联 **/
@io.swagger.annotations.ApiModelProperty(value="支付渠道: 0-微信 1-支付宝 2-银联 ",name="refundVendor")
private Integer refundVendor;
/*支付状态: 0-退款中;1-退款成功;2-退款失败**/
@io.swagger.annotations.ApiModelProperty(value="支付状态: 0-退款中;1-退款成功;2-退款失败",name="refundOrderStatus")
private Integer refundOrderStatus;
/*微信退款单号**/
@io.swagger.annotations.ApiModelProperty(value="微信退款单号",name="refundId")
private String refundId;
/*支付失败原因**/
@io.swagger.annotations.ApiModelProperty(value="支付失败原因",name="failReason")
private String failReason;
public String getTenantId() {
return tenantId;
}
public void setTenantId(String _tenantId) {
tenantId = _tenantId;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date _createTime) {
createTime = _createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date _updateTime) {
updateTime = _updateTime;
}
public String getTransactionId() {
return transactionId;
}
public void setTransactionId(String _transactionId) {
transactionId = _transactionId;
}
public Long getOrderId() {
return orderId;
}
public void setOrderId(Long _orderId) {
orderId = _orderId;
}
public String getPayOrderNo() {
return payOrderNo;
}
public void setPayOrderNo(String _payOrderNo) {
payOrderNo = _payOrderNo;
}
public Long getCUserId() {
return cUserId;
}
public void setCUserId(Long _cUserId) {
cUserId = _cUserId;
}
public Integer getTotalFee() {
return totalFee;
}
public void setTotalFee(Integer _totalFee) {
totalFee = _totalFee;
}
public Integer getRefundFee() {
return refundFee;
}
public void setRefundFee(Integer _refundFee) {
refundFee = _refundFee;
}
public Integer getRefundTimeStart() {
return refundTimeStart;
}
public void setRefundTimeStart(Integer _refundTimeStart) {
refundTimeStart = _refundTimeStart;
}
public Integer getRefundTimeEnd() {
return refundTimeEnd;
}
public void setRefundTimeEnd(Integer _refundTimeEnd) {
refundTimeEnd = _refundTimeEnd;
}
public Integer getRefundVendor() {
return refundVendor;
}
public void setRefundVendor(Integer _refundVendor) {
refundVendor = _refundVendor;
}
public Integer getRefundOrderStatus() {
return refundOrderStatus;
}
public void setRefundOrderStatus(Integer _refundOrderStatus) {
refundOrderStatus = _refundOrderStatus;
}
public String getRefundId() {
return refundId;
}
public void setRefundId(String _refundId) {
refundId = _refundId;
}
public String getFailReason() {
return failReason;
}
public void setFailReason(String _failReason) {
failReason = _failReason;
}



public static enum Field
{
Id_ASC("`id` ASC"),Id_DESC("`id` DESC")
,TenantId_ASC("`tenantId` ASC"),TenantId_DESC("`tenantId` DESC")
,CreateTime_ASC("`createTime` ASC"),CreateTime_DESC("`createTime` DESC")
,UpdateTime_ASC("`updateTime` ASC"),UpdateTime_DESC("`updateTime` DESC")
,TransactionId_ASC("`transactionId` ASC"),TransactionId_DESC("`transactionId` DESC")
,OrderId_ASC("`orderId` ASC"),OrderId_DESC("`orderId` DESC")
,PayOrderNo_ASC("`payOrderNo` ASC"),PayOrderNo_DESC("`payOrderNo` DESC")
,CUserId_ASC("`cUserId` ASC"),CUserId_DESC("`cUserId` DESC")
,TotalFee_ASC("`totalFee` ASC"),TotalFee_DESC("`totalFee` DESC")
,RefundFee_ASC("`refundFee` ASC"),RefundFee_DESC("`refundFee` DESC")
,RefundTimeStart_ASC("`refundTimeStart` ASC"),RefundTimeStart_DESC("`refundTimeStart` DESC")
,RefundTimeEnd_ASC("`refundTimeEnd` ASC"),RefundTimeEnd_DESC("`refundTimeEnd` DESC")
,RefundVendor_ASC("`refundVendor` ASC"),RefundVendor_DESC("`refundVendor` DESC")
,RefundOrderStatus_ASC("`refundOrderStatus` ASC"),RefundOrderStatus_DESC("`refundOrderStatus` DESC")
,RefundId_ASC("`refundId` ASC"),RefundId_DESC("`refundId` DESC")
,FailReason_ASC("`failReason` ASC"),FailReason_DESC("`failReason` DESC")
;
private String value;
Field(String value){
this.value = value;
}
public String getValue() {
return value;
}
public void setCol(String value) {
this.value = value;
}
@Override
public String toString() {
return this.getValue();
}
}
public void setSortColumns(WxRefundOrder.Field... fields)
{
if (fields == null || fields.length == 0) {
return;
}
for (int k = 0; k < fields.length; k++) {
if (fields[k] == null) {
return;
}
}
StringBuilder sb = new StringBuilder(fields[0].toString());
for (int k = 1; k < fields.length; k++) {
sb.append(",");
sb.append(fields[k].toString());
}
}
public void setSortColumns(String sortColumns)
{
if (sortColumns == null || "".equals(sortColumns.trim())) {
return;
}
if (sortColumns.contains(",")) {
String[] cols = sortColumns.split(",");
java.util.List<Field> fList = new java.util.ArrayList();
for (int k = 0; k < cols.length; k++) {
fList.add(Field.valueOf(cols[k]));
}
this.setSortColumns(fList.toArray(new Field[fList.size()]));
} else {
this.setSortColumns(Field.valueOf(sortColumns));
}
}
}

+ 39
- 0
mallinkService/src/main/java/com/simple/enums/EnumRefundStatus.java Просмотреть файл

@@ -0,0 +1,39 @@
package com.simple.enums;

/**
* Created by Stormeye on 2018/08/09.
*/
public enum EnumRefundStatus {
REFUND_UNKNOWN(-1, "未知"),
REFUND_WAIT(0, "退款中"),
REFUND_REQ_SUCCESS(1, "退款申请成功"),
REFUND_REQ_FAIL(2, "退款申请失败"),
REFUND_SUCCESS(3, "退款成功"),
REFUND_FAIL(4, "退款失败"),
;

public static EnumRefundStatus getEnum(Integer code) {
for (EnumRefundStatus value : values()) {
if (value.getCode().equals(code)) {
return value;
}
}
return null;
}

private Integer code;
private String message;

EnumRefundStatus(Integer code, String message) {
this.code = code;
this.message = message;
}

public Integer getCode() {
return code;
}

public String getMessage() {
return message;
}
}

+ 17
- 0
mallinkService/src/main/java/com/simple/mapper/WxRefundOrderMapper.java Просмотреть файл

@@ -0,0 +1,17 @@
package com.simple.mapper;

import java.util.*;
import com.simple.common.CommonMapper;
import org.apache.ibatis.annotations.Param;
import com.simple.domain.po.WxRefundOrder;

public interface WxRefundOrderMapper extends CommonMapper<WxRefundOrder, Long> {

List<WxRefundOrder> findList(WxRefundOrder wxRefundOrder);

}

+ 29
- 0
mallinkService/src/main/java/com/simple/pay/WxPayment.java Просмотреть файл

@@ -243,6 +243,35 @@ public class WxPayment {
return buildSignAfterParasMap(params, paternerKey);
}

/**
* 查询退款
*
* @param appid
* @param mch_id
* @param out_trade_no
* @param paternerKey
* @return
*/
public static Map<String, String> buildWeappRefundQueryMap(String appid, String mch_id,
String transaction_id, String out_trade_no, String out_refund_no, String refund_id,
String paternerKey) {
Map<String, String> params = new HashMap<String, String>();

params.put("appid", appid);
params.put("mch_id", mch_id);
if(!StringUtils.isBlank(refund_id)) {
params.put("refund_id", refund_id);
} else if (!StringUtils.isBlank(out_refund_no)) {
params.put("out_refund_no", out_refund_no);
} else if (!StringUtils.isBlank(transaction_id)) {
params.put("transaction_id", transaction_id);
} else if (!StringUtils.isBlank(out_trade_no)) {
params.put("out_trade_no", out_trade_no);
}

return buildSignAfterParasMap(params, paternerKey);
}

/**
* 组装签名的字段
*


mallinkService/src/main/java/com/simple/pay/WxRefundOrder.java → mallinkService/src/main/java/com/simple/pay/WxRefundOrderP.java Просмотреть файл

@@ -3,11 +3,12 @@ package com.simple.pay;
/**
* Created by Stormeye on 2018/8/10.
*/
public class WxRefundOrder {
public class WxRefundOrderP {
private String appid; // 公众账号ID
private String mch_id; // 商户号
private String nonce_str; // 随机字符串
private String sign; // 签名
private String transaction_id; // 微信订单号
private String out_trade_no; // 商户订单号
private String out_refund_no; // 商户退款单号
private Integer total_fee; // 支付金额
@@ -45,6 +46,14 @@ public class WxRefundOrder {
this.sign = sign;
}

public String getTransaction_id() {
return transaction_id;
}

public void setTransaction_id(String transaction_id) {
this.transaction_id = transaction_id;
}

public String getOut_trade_no() {
return out_trade_no;
}

+ 68
- 0
mallinkService/src/main/java/com/simple/service/WxRefundOrderService.java Просмотреть файл

@@ -0,0 +1,68 @@
package com.simple.service;

import java.util.*;
import com.github.pagehelper.PageInfo;
import com.simple.common.ResultData;
import com.simple.domain.po.WxAppinfo;
import com.simple.domain.po.WxCUser;
import com.simple.domain.po.WxRefundOrder;
import com.simple.enums.EnumPayWay;

public interface WxRefundOrderService {

/**
* 创建退款订单
* @param appInfo
* @param record 退款订单请求
* @param payWay
* @return
*/
ResultData createRefundOrder(WxAppinfo appInfo, WxRefundOrder record, EnumPayWay payWay);

/**
* 退款订单查询
* @param appInfo
* @param record
* @return
*/
ResultData queryRefundOrder(WxAppinfo appInfo, WxRefundOrder record);
/**
* 根据实体查询分页列表
*
* @param record
* @param pageIndex
* @param pageSize
* @return
*/
PageInfo<WxRefundOrder> listAsPage(WxRefundOrder record, Integer pageIndex, Integer pageSize);
/**
* 根据Id获得实体
*
* @param id
* @return
*/
WxRefundOrder getById(Long id);
/**
* 保存或更新实体
*
* @param record
*/
void saveOrUpdate(WxRefundOrder record);

/**
* 根据Id删除实体
*
* @param id
*/
void deleteById(Long id);

}

+ 6
- 2
mallinkService/src/main/java/com/simple/service/impl/WxPayOrderServiceImpl.java Просмотреть файл

@@ -103,7 +103,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService {
record.setPayOrderStatus(EnumPayStatus.PAY_WAY_WAIT.getCode());

int sqlRow = wxPayOrderMapper.insertSelective(record);
if(sqlRow == 1) {
if(sqlRow != 1) {
throw new MallinkException(ErrorCode.DB_FAIL);
}
WxPayAccount payAccount = wxPayAccountMapper.selectByPrimaryKey(appInfo.getPayId());
@@ -122,7 +122,7 @@ public class WxPayOrderServiceImpl implements WxPayOrderService {
wxPayOrderP.setTrade_type(WxPay.TradeType.APP.name()); // 终端类型
wxPayOrderP.setProduct_id(String.valueOf(order.getId())); // 订单ID
wxPayOrderP.setTime_start(Utility.getDataFormatStringYYYYMMDDHHmmss(currentTime));
wxPayOrderP.setTime_start(Utility.getDataFormatStringYYYYMMDDHHmmss(currentTime + 15 * 60)); // 15分钟结束
wxPayOrderP.setTime_expire(Utility.getDataFormatStringYYYYMMDDHHmmss(currentTime + 15 * 60)); // 15分钟结束
wxPayOrderP.setSign(WxPayment.createSign(BeanUtils.toStringMap(wxPayOrderP), payAccount.getApiKey()));
String response = WxPay.pushOrder(BeanUtils.toStringMap(wxPayOrderP));
logger.info("pay order, wechat pushOrder, wxPayOrder:" + wxPayOrderP.toString() + ", response: " + response.toString());
@@ -154,6 +154,10 @@ public class WxPayOrderServiceImpl implements WxPayOrderService {
}
}

// TODO
// 微信订单查询
// 微信关闭订单

@Override
public String notify(Map<String, String> paramMap, EnumPayWay payWay) {
// how to get wechatAppId, wechatMchId, partnerKey


+ 222
- 0
mallinkService/src/main/java/com/simple/service/impl/WxRefundOrderServiceImpl.java Просмотреть файл

@@ -0,0 +1,222 @@
package com.simple.service.impl;

import java.util.*;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.simple.common.ErrorCode;
import com.simple.common.ResultData;
import com.simple.domain.po.*;
import com.simple.enums.EnumPayStatus;
import com.simple.enums.EnumPayWay;
import com.simple.enums.EnumRefundStatus;
import com.simple.exception.MallinkException;
import com.simple.mapper.WxPayAccountMapper;
import com.simple.mapper.WxPayOrderMapper;
import com.simple.mapper.WxRefundOrderMapper;
import com.simple.pay.WxPay;
import com.simple.pay.WxPayment;
import com.simple.pay.WxRefundOrderP;
import com.simple.service.WxRefundOrderService;
import com.simple.utils.BeanUtils;
import com.simple.utils.Utility;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.simple.common.IdWorker;

@Service
public class WxRefundOrderServiceImpl implements WxRefundOrderService {
private Logger logger = Logger.getLogger(getClass());
@Autowired
WxRefundOrderMapper wxRefundOrderMapper;

@Autowired
WxPayOrderMapper wxPayOrderMapper;

@Autowired
WxPayAccountMapper wxPayAccountMapper;

JSONObject errorRefundReqMap = JSON.parseObject("{\"SYSTEMERROR\":{\"detail\":\"接口返回错误\",\"reason\":\"系统超时等\",\"resolution\":\"请不要更换商户退款单号,请使用相同参数再次调用API。\"},\n" +
"{\"BIZERR_NEED_RETRY\":{\"detail\":\"退款业务流程错误,需要商户触发重试来解决\",\"reason\":\"并发情况下,业务被拒绝,商户重试即可解决\",\"resolution\":\"请不要更换商户退款单号,请使用相同参数再次调用API。\"},\n" +
"{\"TRADE_OVERDUE\":{\"detail\":\"订单已经超过退款期限\",\"reason\":\"订单已经超过可退款的最大期限(支付后一年内可退款)\t\",\"resolution\":\"请选择其他方式自行退款\"},\n" +
"{\"ERROR\":{\"detail\":\"业务错误\",\"reason\":\"申请退款业务发生错误\",\"resolution\":\"该错误都会返回具体的错误原因,请根据实际返回做相应处理。\"},\n" +
"{\"USER_ACCOUNT_ABNORMAL\":{\"detail\":\"退款请求失败\",\"reason\":\"用户帐号注销\",\"resolution\":\"此状态代表退款申请失败,商户可自行处理退款。\"},\n" +
"{\"INVALID_REQ_TOO_MUCH\":{\"detail\":\"无效请求过多\",\"reason\":\"连续错误请求数过多被系统短暂屏蔽\t\",\"resolution\":\"请检查业务是否正常,确认业务正常后请在1分钟后再来重试\"},\n" +
"{\"NOTENOUGH\":{\"detail\":\"余额不足\",\"reason\":\"商户可用退款余额不足\",\"resolution\":\"此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。\"},\n" +
"{\"INVALID_TRANSACTIONID\":{\"detail\":\"无效transaction_id\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败\"},\n" +
"{\"PARAM_ERROR\":{\"detail\":\"参数错误\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"请求参数错误,请重新检查再调用退款申请\"},\n" +
"{\"APPID_NOT_EXIST\":{\"detail\":\"APPID不存在\",\"reason\":\"参数中缺少APPID\",\"resolution\":\"请检查APPID是否正确\"},\n" +
"{\"MCHID_NOT_EXIST\":{\"detail\":\"MCHID不存在\",\"reason\":\"参数中缺少MCHID\",\"resolution\":\"请检查MCHID是否正确\"},\n" +
"{\"REQUIRE_POST_METHOD\":{\"detail\":\"请使用post方法\",\"reason\":\"未使用post传递参数\",\"resolution\":\"请检查请求参数是否通过post方法提交\"},\n" +
"{\"SIGNERROR\":{\"detail\":\"签名错误\",\"reason\":\"参数签名结果不正确\",\"resolution\":\"请检查签名参数和方法是否都符合签名算法要求\"},\n" +
"{\"XML_FORMAT_ERROR\":{\"detail\":\"XML格式错误\",\"reason\":\"XML格式错误\",\"resolution\":\"请检查XML参数格式是否正确\"},\n" +
"{\"FREQUENCY_LIMITED\":{\"detail\":\"频率限制\",\"reason\":\"2个月之前的订单申请退款有频率限制\",\"resolution\":\"该笔退款未受理,请降低频率后重试\"}");

JSONObject errorRefundQueryMap = JSON.parseObject("{\"SYSTEMERROR\":{\"detail\":\"接口返回错误\",\"reason\":\"系统超时等\",\"resolution\":\"请不要更换商户退款单号,请使用相同参数再次调用API。\"},\n" +
"{\"BIZERR_NEED_RETRY\":{\"detail\":\"退款业务流程错误,需要商户触发重试来解决\",\"reason\":\"并发情况下,业务被拒绝,商户重试即可解决\",\"resolution\":\"请不要更换商户退款单号,请使用相同参数再次调用API。\"},\n" +
"{\"TRADE_OVERDUE\":{\"detail\":\"订单已经超过退款期限\",\"reason\":\"订单已经超过可退款的最大期限(支付后一年内可退款)\t\",\"resolution\":\"请选择其他方式自行退款\"},\n" +
"{\"ERROR\":{\"detail\":\"业务错误\",\"reason\":\"申请退款业务发生错误\",\"resolution\":\"该错误都会返回具体的错误原因,请根据实际返回做相应处理。\"},\n" +
"{\"USER_ACCOUNT_ABNORMAL\":{\"detail\":\"退款请求失败\",\"reason\":\"用户帐号注销\",\"resolution\":\"此状态代表退款申请失败,商户可自行处理退款。\"},\n" +
"{\"INVALID_REQ_TOO_MUCH\":{\"detail\":\"无效请求过多\",\"reason\":\"连续错误请求数过多被系统短暂屏蔽\t\",\"resolution\":\"请检查业务是否正常,确认业务正常后请在1分钟后再来重试\"},\n" +
"{\"NOTENOUGH\":{\"detail\":\"余额不足\",\"reason\":\"商户可用退款余额不足\",\"resolution\":\"此状态代表退款申请失败,商户可根据具体的错误提示做相应的处理。\"},\n" +
"{\"INVALID_TRANSACTIONID\":{\"detail\":\"无效transaction_id\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"请求参数错误,检查原交易号是否存在或发起支付交易接口返回失败\"},\n" +
"{\"PARAM_ERROR\":{\"detail\":\"参数错误\",\"reason\":\"请求参数未按指引进行填写\",\"resolution\":\"请求参数错误,请重新检查再调用退款申请\"},\n" +
"{\"APPID_NOT_EXIST\":{\"detail\":\"APPID不存在\",\"reason\":\"参数中缺少APPID\",\"resolution\":\"请检查APPID是否正确\"},\n" +
"{\"MCHID_NOT_EXIST\":{\"detail\":\"MCHID不存在\",\"reason\":\"参数中缺少MCHID\",\"resolution\":\"请检查MCHID是否正确\"},\n" +
"{\"REQUIRE_POST_METHOD\":{\"detail\":\"请使用post方法\",\"reason\":\"未使用post传递参数\",\"resolution\":\"请检查请求参数是否通过post方法提交\"},\n" +
"{\"SIGNERROR\":{\"detail\":\"签名错误\",\"reason\":\"参数签名结果不正确\",\"resolution\":\"请检查签名参数和方法是否都符合签名算法要求\"},\n" +
"{\"XML_FORMAT_ERROR\":{\"detail\":\"XML格式错误\",\"reason\":\"XML格式错误\",\"resolution\":\"请检查XML参数格式是否正确\"},\n" +
"{\"FREQUENCY_LIMITED\":{\"detail\":\"频率限制\",\"reason\":\"2个月之前的订单申请退款有频率限制\",\"resolution\":\"该笔退款未受理,请降低频率后重试\"}");

@Override
public ResultData createRefundOrder(WxAppinfo appInfo, WxRefundOrder record, EnumPayWay payWay) {
// check 是否有退款订单
List<WxRefundOrder> list = wxRefundOrderMapper.findList(record);
if (list.size() > 0) {
throw new MallinkException(ErrorCode.REFUND_ORDER_EXIST);
}
// check 支付 订单
WxPayOrder payOrder = null;
try {
WxPayOrder payOrderQ = new WxPayOrder();
payOrderQ.setOrderId(record.getOrderId());
payOrderQ.setId(Long.valueOf(record.getPayOrderNo()));
payOrderQ.setPayOrderNo(record.getPayOrderNo());
payOrderQ.setPayOrderStatus(EnumPayStatus.PAY_WAY_SUCCESS.getCode());
payOrder = wxPayOrderMapper.selectOne(payOrderQ);
} catch (Exception e) {
throw new MallinkException(ErrorCode.DB_FAIL);
}

if (payOrder == null) {
throw new MallinkException(ErrorCode.REFUND_PAY_ORDER_IS_NOT_EXIST);
}
if (payOrder.getPayAmount() <= 0) {
throw new MallinkException(ErrorCode.REFUND_PAY_ORDER_IS_NOT_EXIST);
}

// TODO check 可退券????

// 创建退款订单
final IdWorker idWorker = IdWorker.get();
Long id = idWorker.nextId();
Date currentDate = new Date();

try {
record.setId(id);
record.setTenantId(appInfo.getTenantId());
record.setCreateTime(currentDate);
record.setUpdateTime(currentDate);
record.setTransactionId(payOrder.getTransactionId());
record.setCUserId(payOrder.getCUserId());
record.setTotalFee(payOrder.getPayAmount());
record.setRefundFee(payOrder.getPayAmount());
record.setRefundTimeStart((int)(currentDate.getTime()/1000));
record.setRefundOrderStatus(EnumRefundStatus.REFUND_WAIT.getCode());
int sqlRow = wxRefundOrderMapper.insertSelective(record);
if(sqlRow != 1) {
throw new MallinkException(ErrorCode.DB_FAIL);
}
} catch (Exception e) {
throw new MallinkException(ErrorCode.DB_FAIL);
}

WxPayAccount payAccount = wxPayAccountMapper.selectByPrimaryKey(appInfo.getPayId());

// 退款申请
try {
String noncestr = Utility.generate32UUID();
WxRefundOrderP wxRefundOrderP = new WxRefundOrderP();
wxRefundOrderP.setAppid(appInfo.getAppId());
wxRefundOrderP.setMch_id(payAccount.getMchId());
wxRefundOrderP.setNonce_str(noncestr);
wxRefundOrderP.setTransaction_id(record.getTransactionId());
wxRefundOrderP.setOut_trade_no(record.getPayOrderNo());
wxRefundOrderP.setTotal_fee(record.getTotalFee());
wxRefundOrderP.setRefund_fee(record.getRefundFee());
wxRefundOrderP.setSign(WxPayment.createSign(BeanUtils.toStringMap(wxRefundOrderP), payAccount.getApiKey()));
String response = WxPay.orderRefund(BeanUtils.toStringMap(wxRefundOrderP), payAccount.getCertPath(), payAccount.getApiKey());
logger.info("微信退款订单:" + wxRefundOrderP.toString() + ", response: " + response.toString());
Map<String, String> returnMap = WxPayment.xmlToMap(response);
String result_no = returnMap.get("result_code");
if ("SUCCESS".equals(result_no)) {
String refund_id = returnMap.get("refund_id");
record.setRefundId(refund_id);
record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_SUCCESS.getCode());
wxRefundOrderMapper.updateByPrimaryKey(record);
return new ResultData(200, "退款订单申请成功", returnMap);
} else {
String refund_id = returnMap.get("refund_id");
record.setRefundId(refund_id);
record.setRefundOrderStatus(EnumRefundStatus.REFUND_REQ_FAIL.getCode());
wxRefundOrderMapper.updateByPrimaryKey(record);
JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
return new ResultData(ErrorCode.PAY_ORDER_ERROR.getCode(), errObj.toJSONString(), returnMap);
}
} catch(Exception e) {
throw new MallinkException(ErrorCode.REFUND_ORDER_ERROR);
}
}

// TODO
// 微信退款查询
@Override
public ResultData queryRefundOrder(WxAppinfo appInfo, WxRefundOrder record) {
WxPayAccount payAccount = wxPayAccountMapper.selectByPrimaryKey(appInfo.getPayId());

Map<String, String> 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<String, String> 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(200, "退款", returnMap);
} else {
wxRefundOrderMapper.updateByPrimaryKey(record);
JSONObject errObj = errorRefundReqMap.getJSONObject(result_no);
return new ResultData(ErrorCode.REFUND_ORDER_ERROR.getCode(), errObj.toJSONString(), returnMap);
}
}
// 微信退款结果通知


@Override
public PageInfo<WxRefundOrder> listAsPage(WxRefundOrder record, Integer pageIndex, Integer pageSize) {
return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxRefundOrderMapper.findList(record));
}

@Override
public WxRefundOrder getById(Long id) {
return wxRefundOrderMapper.selectByPrimaryKey(id);
}

@Override
public void saveOrUpdate(WxRefundOrder record) {
if (record.getId() == null) {
//record.setId(UUID.randomUUID().toString().replaceAll("-", ""));
final IdWorker idWorker = IdWorker.get();
record.setId(idWorker.nextId());
wxRefundOrderMapper.insertSelective(record);
} else {
wxRefundOrderMapper.updateByPrimaryKeySelective(record);
}
}

@Override
public void deleteById(Long id) {
wxRefundOrderMapper.deleteByPrimaryKey(id);
}
}

+ 5
- 0
mallinkService/src/main/java/com/simple/utils/RandomUtils.java Просмотреть файл

@@ -30,4 +30,9 @@ public class RandomUtils {
return str.toString();
}


public static void main(String[] args) {
System.out.println(getStr(32));
}

}

+ 128
- 0
mallinkService/src/main/resources/mapper/WxRefundOrderMapper.xml Просмотреть файл

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.simple.mapper.WxRefundOrderMapper">
<resultMap id="BaseResultMap" type="com.simple.domain.po.WxRefundOrder">
<id column="id" jdbcType="BIGINT" property="id" />
<result column="tenant_id" jdbcType="VARCHAR" property="tenantId" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="transaction_id" jdbcType="VARCHAR" property="transactionId" />
<result column="order_id" jdbcType="BIGINT" property="orderId" />
<result column="pay_order_no" jdbcType="VARCHAR" property="payOrderNo" />
<result column="c_user_id" jdbcType="BIGINT" property="cUserId" />
<result column="total_fee" jdbcType="INTEGER" property="totalFee" />
<result column="refund_fee" jdbcType="INTEGER" property="refundFee" />
<result column="refund_time_start" jdbcType="INTEGER" property="refundTimeStart" />
<result column="refund_time_end" jdbcType="INTEGER" property="refundTimeEnd" />
<result column="refund_vendor" jdbcType="INTEGER" property="refundVendor" />
<result column="refund_order_status" jdbcType="INTEGER" property="refundOrderStatus" />
<result column="refund_id" jdbcType="VARCHAR" property="refundId" />
<result column="fail_reason" jdbcType="VARCHAR" property="failReason" />
</resultMap>
<sql id="allColumns">
`id`,`tenant_id`,`create_time`,`update_time`,`transaction_id`,`order_id`,`pay_order_no`,`c_user_id`,`total_fee`,`refund_fee`,`refund_time_start`,`refund_time_end`,`refund_vendor`,`refund_order_status`,`refund_id`,`fail_reason`
</sql>

<sql id="dynamicWhereConditions">
where 1 = 1
<if test=" null != id ">
and `id` = #{id}
</if>
<if test=" null != tenantId ">
and `tenant_id` like concat('%', #{tenantId},'%')
</if>
<if test=" null != createTime ">
and `create_time` = #{createTime}
</if>
<if test=" null != updateTime ">
and `update_time` = #{updateTime}
</if>
<if test=" null != transactionId ">
and `transaction_id` like concat('%', #{transactionId},'%')
</if>
<if test=" null != orderId ">
and `order_id` = #{orderId}
</if>
<if test=" null != payOrderNo ">
and `pay_order_no` like concat('%', #{payOrderNo},'%')
</if>
<if test=" null != cUserId ">
and `c_user_id` = #{cUserId}
</if>
<if test=" null != totalFee ">
and `total_fee` = #{totalFee}
</if>
<if test=" null != refundFee ">
and `refund_fee` = #{refundFee}
</if>
<if test=" null != refundTimeStart ">
and `refund_time_start` = #{refundTimeStart}
</if>
<if test=" null != refundTimeEnd ">
and `refund_time_end` = #{refundTimeEnd}
</if>
<if test=" null != refundVendor ">
and `refund_vendor` = #{refundVendor}
</if>
<if test=" null != refundOrderStatus ">
and `refund_order_status` = #{refundOrderStatus}
</if>
<if test=" null != refundId ">
and `refund_id` like concat('%', #{refundId},'%')
</if>
<if test=" null != failReason ">
and `fail_reason` like concat('%', #{failReason},'%')
</if>
<if test=" null != ids ">
and id in
<foreach collection="ids" index="index" item="idItem" open="(" separator="," close=")">
#{idItem}
</foreach>
</if>
<if test=" null != sortColumns"> order by ${sortColumns} </if>
</sql>
<select id="findList" parameterType="com.simple.domain.po.WxRefundOrder" resultMap="BaseResultMap">
select <include refid="allColumns" /> from wx_refund_order
<include refid="dynamicWhereConditions" />
</select>
</mapper>

Загрузка…
Отмена
Сохранить