提交修改

This commit is contained in:
quyixiao 2025-11-08 14:31:13 +08:00
parent 09f0796a30
commit 423b7d1934
3 changed files with 133 additions and 2 deletions

View File

@ -12,6 +12,7 @@ import com.heyu.api.data.entity.vv.VvReverseOrderEntity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lz.mybatis.plugin.annotations.Column;
import com.lz.mybatis.plugin.annotations.IF;
import com.lz.mybatis.plugin.annotations.LIMIT;
import com.lz.mybatis.plugin.annotations.OrderBy;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@ -51,4 +52,10 @@ public interface VvReverseOrderDao extends BaseMapper<VvReverseOrderEntity> {
@IF @Column(VvReverseOrderEntity.create_timestamp) Long maxCreateTimestamp,
@IF @OrderBy(VvReverseOrderEntity.create_timestamp) String createTimestampSort
);
@OrderBy(VvReverseOrderEntity.id_)
@LIMIT
VvReverseOrderEntity selectVvReverseOrderByTradeOrderId(Long tradeOrderId);
}

View File

@ -246,8 +246,7 @@ public class JsapiPrepay {
request.amount.currency = "CNY"; // 必填 退款币种 符合ISO 4217标准的三位字母代码固定传CNY代表人民币
String HOST = refundNotifyUrl;
String METHOD = "POST";
String PATH = "/v3/refund/domestic/refunds";
String uri = PATH;
String uri = "/v3/refund/domestic/refunds";
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(HOST + uri);

View File

@ -0,0 +1,125 @@
package com.heyu.api.controller.vv;
import com.alibaba.fastjson.JSONObject;
import com.heyu.api.alibaba.request.mm.enums.ReverseStatusEnums;
import com.heyu.api.data.dao.vv.VvReverseOrderDao;
import com.heyu.api.data.dao.vv.VvTradeOrderDao;
import com.heyu.api.data.dao.vv.VvTradeOrderLineDao;
import com.heyu.api.data.entity.vv.VvReverseOrderEntity;
import com.heyu.api.data.entity.vv.VvTradeOrderLineEntity;
import com.heyu.api.data.utils.NumberUtil;
import com.heyu.api.data.utils.StringUtils;
import com.heyu.api.jsapi.JsapiPrepay;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
@Slf4j
@RestController
@RequestMapping("/app/weixin")
public class AppWeiXinRefundNotifyController {
@Autowired
private VvTradeOrderLineDao vvTradeOrderLineDao;
// 微信支付APIv3密钥
@Value("${eb.config.weixin.pay.apiv3key}")
private String apiV3key;
@Autowired
private VvTradeOrderDao tradeOrderDao;
@Value("${eb.config.weixin.pay.mchid}")
private String mchid;
@Autowired
private JsapiPrepay jsapiPrepay;
@Autowired
private VvReverseOrderDao reverseOrderDao;
//退款回调
@PostMapping("/refundNotifyUrl")
@Transactional
public Object refundNotifyUrl(@RequestBody String jsonData) throws Exception {
//转为map格式
Map<String, String> jsonMap = JSONObject.parseObject(jsonData, Map.class);
//退款成功后返回一个加密字段resource,以下为解密
/**
* 解密需要从resource参数中获取到ciphertextnonceassociated_data这三个参数进行解密
*/
String resource = JSONObject.toJSONString(jsonMap.get("resource"));
JSONObject object = JSONObject.parseObject(resource);
String ciphertext = String.valueOf(object.get("ciphertext"));
String nonce = String.valueOf(object.get("nonce"));
String associated_data = String.valueOf(object.get("associated_data"));
String resultStr = decryptToString(associated_data.getBytes("UTF-8"), nonce.getBytes("UTF-8"), ciphertext);
log.info("AppWeiXinRefundNotifyController refundNotifyUrl resultStr = " + resultStr);
Map<String, String> reqInfo = JSONObject.parseObject(resultStr, Map.class);
String refund_status = reqInfo.get("refund_status");//退款状态
String out_trade_no = reqInfo.get("out_trade_no"); //订单号
Map<String, Object> parm = new HashMap<>();
if (!StringUtils.isEmpty(refund_status) && "SUCCESS".equals(refund_status)) {
VvReverseOrderEntity vvReverseOrderEntity = reverseOrderDao.selectVvReverseOrderByTradeOrderId(NumberUtil.objToLong(out_trade_no));
vvReverseOrderEntity.setGmtRefunded(new Date());
vvReverseOrderEntity.setStatus(ReverseStatusEnums.refunded.getStatus());
reverseOrderDao.updateVvReverseOrderById(vvReverseOrderEntity);
List<VvTradeOrderLineEntity> vvTradeOrderLineEntityList = vvTradeOrderLineDao.selectVvTradeOrderLineByTradeOrderId(NumberUtil.objToLong(out_trade_no));
for (VvTradeOrderLineEntity vvTradeOrderLineEntity : vvTradeOrderLineEntityList) {
vvTradeOrderLineEntity.setReverseStatus(ReverseStatusEnums.refunded.getStatus());
vvTradeOrderLineDao.updateVvTradeOrderLineById(vvTradeOrderLineEntity);
}
//你自己的业务
parm.put("code", "SUCCESS");
parm.put("message", "成功");
} else {
parm.put("code", "FAIL");
parm.put("message", "失败");
throw new RuntimeException("退款失败");
}
return parm; //返回给前端的参数
}
//退款回调 解密数据
public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec key = new SecretKeySpec(apiV3key.getBytes(), "AES");//todo 这里的apiV3key是你的商户APIV3密钥
GCMParameterSpec spec = new GCMParameterSpec(128, nonce);//规定为128
cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData);
return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
}