| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785 |
- package com.zsElectric.boot.business.service.impl;
- import cn.hutool.core.collection.CollUtil;
- import cn.hutool.core.util.ObjectUtil;
- import com.aliyun.oss.ServiceException;
- import com.baomidou.mybatisplus.core.toolkit.Wrappers;
- import com.google.gson.Gson;
- import com.google.gson.JsonObject;
- import com.zsElectric.boot.business.model.entity.UserRefundsOrderInfo;
- import com.zsElectric.boot.business.mapper.*;
- import com.zsElectric.boot.business.model.entity.*;
- import com.zsElectric.boot.business.model.form.applet.AppLevelOrderForm;
- import com.zsElectric.boot.business.model.form.applet.AppUserPayForm;
- import com.zsElectric.boot.business.model.query.applet.AppUserOrderInfoQuery;
- import com.zsElectric.boot.business.model.vo.applet.AppUserInfoVO;
- import com.zsElectric.boot.business.model.vo.applet.WechatPayParamsVO;
- import com.zsElectric.boot.business.service.*;
- import com.zsElectric.boot.common.constant.SystemConstants;
- import com.zsElectric.boot.core.exception.BusinessException;
- import com.zsElectric.boot.core.pay.*;
- import com.zsElectric.boot.security.util.SecurityUtils;
- import jakarta.servlet.http.HttpServletRequest;
- import jakarta.servlet.http.HttpServletResponse;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.RandomStringUtils;
- import org.apache.commons.lang3.StringUtils;
- import org.springframework.stereotype.Service;
- import com.baomidou.mybatisplus.core.metadata.IPage;
- import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.zsElectric.boot.business.model.form.UserOrderInfoForm;
- import com.zsElectric.boot.business.model.query.UserOrderInfoQuery;
- import com.zsElectric.boot.business.model.vo.UserOrderInfoVO;
- import com.zsElectric.boot.business.converter.UserOrderInfoConverter;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.text.DecimalFormat;
- import java.text.SimpleDateFormat;
- import java.time.LocalDateTime;
- import java.util.*;
- import java.util.concurrent.locks.ReentrantLock;
- import cn.hutool.core.lang.Assert;
- import cn.hutool.core.util.StrUtil;
- import org.springframework.transaction.annotation.Transactional;
- /**
- * 用户支付订单信息服务实现类
- *
- * @author zsElectric
- * @since 2025-12-16 16:25
- */
- @Slf4j
- @Service
- @RequiredArgsConstructor
- public class UserOrderInfoServiceImpl extends ServiceImpl<UserOrderInfoMapper, UserOrderInfo> implements UserOrderInfoService {
- private final UserOrderInfoConverter userOrderInfoConverter;
- private final UserInfoMapper userInfoMapper;
- private final RechargeLevelMapper rechargeLevelMapper;
- private final UserAccountMapper userAccountMapper;
- private final UserAccountService userAccountService;
- private final WechatPayV3Utils wechatPayV3Utils;
- private final ChargeOrderInfoMapper chargeOrderInfoMapper;
- private final UserRefundsOrderInfoMapper userRefundsOrderInfoMapper;
- // 声明一个可重入锁
- private final ReentrantLock lock = new ReentrantLock();
- /**
- * 获取用户支付订单信息分页列表
- *
- * @param queryParams 查询参数
- * @return {@link IPage<UserOrderInfoVO>} 用户支付订单信息分页列表
- */
- @Override
- public IPage<UserOrderInfoVO> getUserOrderInfoPage(UserOrderInfoQuery queryParams) {
- Page<UserOrderInfoVO> pageVO = this.baseMapper.getUserOrderInfoPage(
- new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
- queryParams
- );
- return pageVO;
- }
- /**
- * 获取用户支付订单信息表单数据
- *
- * @param id 用户支付订单信息ID
- * @return 用户支付订单信息表单数据
- */
- @Override
- public UserOrderInfoForm getUserOrderInfoFormData(Long id) {
- UserOrderInfo entity = this.getById(id);
- return userOrderInfoConverter.toForm(entity);
- }
- /**
- * 新增用户支付订单信息
- *
- * @param formData 用户支付订单信息表单对象
- * @return 是否新增成功
- */
- @Override
- public boolean saveUserOrderInfo(UserOrderInfoForm formData) {
- UserOrderInfo entity = userOrderInfoConverter.toEntity(formData);
- return this.save(entity);
- }
- /**
- * 更新用户支付订单信息
- *
- * @param id 用户支付订单信息ID
- * @param formData 用户支付订单信息表单对象
- * @return 是否修改成功
- */
- @Override
- public boolean updateUserOrderInfo(Long id, UserOrderInfoForm formData) {
- UserOrderInfo entity = userOrderInfoConverter.toEntity(formData);
- return this.updateById(entity);
- }
- /**
- * 删除用户支付订单信息
- *
- * @param ids 用户支付订单信息ID,多个以英文逗号(,)分割
- * @return 是否删除成功
- */
- @Override
- public boolean deleteUserOrderInfos(String ids) {
- Assert.isTrue(StrUtil.isNotBlank(ids), "删除的用户支付订单信息数据为空");
- // 逻辑删除
- List<Long> idList = Arrays.stream(ids.split(","))
- .map(Long::parseLong)
- .toList();
- return this.removeByIds(idList);
- }
- @Override
- public IPage<UserOrderInfoVO> getTicketRecords(AppUserOrderInfoQuery queryParams) {
- UserOrderInfoQuery userOrderInfoQuery = new UserOrderInfoQuery();
- userOrderInfoQuery.setUserId(SecurityUtils.getUserId());
- Page<UserOrderInfoVO> pageVO = this.baseMapper.getUserOrderInfoPage(
- new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
- userOrderInfoQuery
- );
- return pageVO;
- }
- @Override
- public AppUserInfoVO getAppletUserInfo(Long userId){
- return userInfoMapper.getAppletUserInfo(userId);
- }
- /**
- * 创建订单
- *
- * @param appLevelOrderForm
- * @return
- */
- @Override
- public AppUserPayForm createOrder(AppLevelOrderForm appLevelOrderForm) {
- Long userId = SecurityUtils.getUserId();
- String userOpenId = this.getAppletUserInfo(userId).getOpenid();
- String orderNo = createOrderNo("SP", userId);
- //创建订单
- UserOrderInfo orderInfo = new UserOrderInfo();
- orderInfo.setUserId(userId);
- orderInfo.setOrderNo(orderNo);
- orderInfo.setLevelId(appLevelOrderForm.getLevelId());
- orderInfo.setOpenid(userOpenId);
- this.save(orderInfo);
- //构建支付表单返回给前端支撑JsApi支付调用
- AppUserPayForm payForm = new AppUserPayForm();
- payForm.setOrderId(orderInfo.getId()).setOrderNo(orderNo);
- //查询档位
- RechargeLevel level = rechargeLevelMapper.selectById(appLevelOrderForm.getLevelId());
- Map<String, Object> result = payment(userOpenId, orderNo, level.getMoney());
- payForm.setParams(result);
- return payForm;
- }
- /**
- * 支付订单
- *
- * @param orderId
- * @return
- */
- @Override
- public AppUserPayForm payOrder(String orderId) {
- UserOrderInfo orderInfo = this.getById(orderId);
- //构建支付表单
- AppUserPayForm payForm = new AppUserPayForm();
- payForm.setOrderId(orderInfo.getId()).setOrderNo(orderInfo.getOrderNo());
- //查询档位
- RechargeLevel level = rechargeLevelMapper.selectById(orderInfo.getLevelId());
- Map<String,Object> result = payment(orderInfo.getOpenid(), orderInfo.getOrderNo(), level.getMoney());
- payForm.setParams(result);
- return payForm;
- }
- /**
- * 订单查询
- *
- * @param orderNo
- * @return
- */
- @Override
- public String orderQuery(String orderNo) throws Exception {
- //查询订单
- UserOrderInfo orderInfo = this.getById(Wrappers.<UserOrderInfo>lambdaQuery().eq(UserOrderInfo::getOrderNo, orderNo).last("limit 1"));
- if (ObjectUtil.isEmpty(orderInfo)) {
- throw new RuntimeException("当前订单不存在");
- }
- //null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
- JsonObject res = orderQueryByOutTradeNo(orderNo, WechatConstants.WECHAT_MCH_ID);
- String s = res == null ? null : res.get("trade_state").getAsString();
- // String s = "SUCCESS";
- if ("SUCCESS".equals(s)) {
- if (ObjectUtil.isNotEmpty(orderInfo) && Objects.equals(orderInfo.getOrderStatus(), SystemConstants.STATUS_ONE)) {
- String transactionId = res.get("transaction_id").getAsString();
- LocalDateTime payTime = LocalDateTime.now();
- // 微信返回的金额单位是分,需要转换为元
- BigDecimal payMoney = new BigDecimal(res.get("amount").getAsJsonObject().get("total").getAsString())
- .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
- //执行业务操作
- this.successPayOrder(orderInfo, transactionId, payTime, payMoney);
- }
- return "100001";//支付成功
- }
- if (s == null) {
- //查询订单
- return "100002";//查询失败
- }
- if ("USERPAYING".equals(s) || "ACCEPT".equals(s)) {
- //查询订单
- return "100003";//查询中
- }
- return "100004";//支付失败
- }
- /**
- * 微信支付回调
- *
- * @param request
- * @param response
- * @return
- */
- @Override
- public Map<String, String> wechatPayNotify(HttpServletRequest request, HttpServletResponse response) {
- Map<String, String> result = new HashMap<>(2);
- //验签及解析返回数据
- JsonObject res = wechatPayV3Utils.getCallbackData(request);
- if (res == null) {
- result.put("code", "FAIL");
- result.put("message", "失败");
- return result;
- }
- log.info("最终拿到的微信支付通知数据:" + res);
- String orderNo = res.get("out_trade_no").getAsString();
- if (lock.tryLock()) {
- // 处理支付成功后的业务 例如 将订单状态修改为已支付 具体参数键值可参考文档 注意!!! 微信可能会多次发送重复的通知 因此要判断业务是否已经处理过了 避免重复处理
- try {
- //查询订单,判断是否已修改为已支付状态
- UserOrderInfo orderInfo = this.getOne(Wrappers.<UserOrderInfo>lambdaQuery().eq(UserOrderInfo::getOrderNo, orderNo).last("limit 1"));
- if (ObjectUtil.isNotEmpty(orderInfo)) {
- if (Objects.equals(orderInfo.getOrderStatus(), SystemConstants.STATUS_TWO)) {
- result.put("code", "SUCCESS");
- result.put("message", "OK");
- return result;
- }
- if (Objects.equals(orderInfo.getOrderStatus(), SystemConstants.STATUS_ONE)) {
- String transactionId = res.get("transaction_id").getAsString();
- LocalDateTime payTime = LocalDateTime.now();
- // 微信返回的金额单位是分,需要转换为元
- BigDecimal payMoney = new BigDecimal(res.get("amount").getAsJsonObject().get("total").getAsString())
- .divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP);
- //执行业务操作
- this.successPayOrder(orderInfo, transactionId, payTime, payMoney);
- }
- }
- result.put("code", "SUCCESS");
- result.put("message", "OK");
- return result;
- } catch (Exception e) {
- log.error("微信支付回调异常:" + e.getMessage());
- result.put("code", "FAIL");
- result.put("message", "失败");
- return result;
- } finally {
- lock.unlock();
- }
- } else {
- result.put("code", "FAIL");
- result.put("message", "失败");
- return result;
- }
- }
- /**
- * 支付成功业务处理
- *
- * @param orderInfo
- * @param transactionId
- * @param payTime
- * @param orderMoney
- * @throws Exception
- */
- @Transactional(rollbackFor = Exception.class)
- protected void successPayOrder(UserOrderInfo orderInfo, String transactionId, LocalDateTime payTime, BigDecimal orderMoney) throws Exception {
- //修改订单状态为已支付
- orderInfo.setOrderStatus(SystemConstants.STATUS_TWO);
- orderInfo.setPayTime(payTime);
- orderInfo.setTransactionId(transactionId);
- orderInfo.setPayMoney(orderMoney);
- this.updateById(orderInfo);
- //账户变动及日志记录
- Long userId = orderInfo.getUserId();
- UserAccount userAccount = userAccountService.updateAccountBalanceAndLog(
- userId,
- orderMoney,
- SystemConstants.CHANGE_TYPE_ADD,
- SystemConstants.ACCOUNT_LOG_PAY_NOTE,
- orderInfo.getId()
- );
- //平订单超充金额(使用更新后的账户信息)
- orderBackTax(userId, userAccount);
- }
- private void orderBackTax(Long userId, UserAccount userAccount) {
- //查询超充订单
- List<ChargeOrderInfo> chargeOrderInfoList = chargeOrderInfoMapper.selectList(Wrappers.<ChargeOrderInfo>lambdaQuery()
- .eq(ChargeOrderInfo::getUserId, userId)
- .eq(ChargeOrderInfo::getMaspStatus, SystemConstants.STATUS_ONE)
- .orderByAsc(ChargeOrderInfo::getCreateTime)
- );
- if (CollUtil.isNotEmpty(chargeOrderInfoList)) {
- //余额减去超充金额(使用更新后的余额)
- BigDecimal balance = userAccount.getBalance();
- for (ChargeOrderInfo chargeOrderInfo : chargeOrderInfoList) {
- if (balance.compareTo(BigDecimal.ZERO) > 0) {
- BigDecimal deductAmount; // 本次扣除金额
- if (balance.compareTo(chargeOrderInfo.getTotalMaspMoney()) < 0) {
- //余额不足,部分补缴
- deductAmount = balance;
- chargeOrderInfo.setAlreadyMaspMoney(deductAmount);
- chargeOrderInfo.setMaspDesc("部分补缴");
- chargeOrderInfo.setMaspStatus(SystemConstants.STATUS_TWO);
- chargeOrderInfoMapper.updateById(chargeOrderInfo);
- //账户变动及日志记录
- userAccountService.updateAccountBalanceAndLog(
- userId,
- deductAmount.negate(),
- SystemConstants.CHANGE_TYPE_REDUCE,
- SystemConstants.ACCOUNT_LOG_BACK_TAX_NOTE,
- chargeOrderInfo.getId()
- );
- balance = BigDecimal.ZERO;
- continue;
- }
- //余额足够,完成补缴
- deductAmount = chargeOrderInfo.getTotalMaspMoney();
- balance = balance.subtract(deductAmount);
- chargeOrderInfo.setAlreadyMaspMoney(deductAmount);
- chargeOrderInfo.setMaspDesc("完成补缴");
- chargeOrderInfo.setMaspStatus(SystemConstants.STATUS_TWO);
- chargeOrderInfoMapper.updateById(chargeOrderInfo);
- //账户变动及日志记录
- userAccountService.updateAccountBalanceAndLog(
- userId,
- deductAmount.negate(),
- SystemConstants.CHANGE_TYPE_REDUCE,
- SystemConstants.ACCOUNT_LOG_BACK_TAX_NOTE,
- chargeOrderInfo.getId()
- );
- }
- }
- }
- }
- /**
- * 取消订单
- *
- * @param orderId
- * @return
- */
- @Override
- public String cancelOrder(String orderId) {
- UserOrderInfo orderInfo = this.getById(orderId);
- if (ObjectUtil.isNotEmpty(orderInfo)) {
- if (orderInfo.getOrderStatus() == 1) {
- log.info("修改订单:{},支付状态为已取消", orderId);
- orderInfo.setOrderStatus(SystemConstants.STATUS_THREE);
- this.updateById(orderInfo);
- }
- return "取消成功!";
- }
- return "取消失败,请刷新后重试!";
- }
- /**
- * 账户退款
- *
- * @return
- */
- @Override
- @Transactional(rollbackFor = Exception.class)
- public String refundOrder() throws Exception {
- //查询账户余额
- UserAccount userAccount = userAccountMapper.selectOne(Wrappers.<UserAccount>lambdaQuery().eq(UserAccount::getUserId, SecurityUtils.getUserId()).last("limit 1"));
- if (userAccount.getBalance().compareTo(BigDecimal.ZERO) == 0) {
- return "账户余额为 0";
- }
- BigDecimal refundMoney = userAccount.getBalance();
- //查询一年内已支付的所有券订单
- List<UserOrderInfo> userOrderInfoList = baseMapper.selectList(Wrappers.<UserOrderInfo>lambdaQuery()
- .eq(UserOrderInfo::getUserId, userAccount.getId())
- .eq(UserOrderInfo::getOrderStatus, SystemConstants.STATUS_TWO)
- .between(UserOrderInfo::getCreateTime, LocalDateTime.now().minusYears(1), LocalDateTime.now())
- );
- if (CollUtil.isEmpty(userOrderInfoList)) {
- log.info("当前用户一年内未支付任何券订单,无法进行退款操作!");
- throw new BusinessException("无法进行退款操作,请联系客服处理!");
- }
- for (UserOrderInfo userOrderInfo : userOrderInfoList) {
- if(refundMoney.compareTo(BigDecimal.ZERO) == 0){
- break;
- }
- if ((userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney())).compareTo(refundMoney) < 0) {
- //退款金额大于订单金额,则直接退退款金额
- refundOrder(userOrderInfo,refundMoney, "账户退款", SystemConstants.STATUS_ONE);
- //账户变动及日志记录
- userAccountService.updateAccountBalanceAndLog(
- SecurityUtils.getUserId(),
- refundMoney,
- SystemConstants.CHANGE_TYPE_REDUCE,
- SystemConstants.ACCOUNT_LOG_REFUND_NOTE,
- userOrderInfo.getId()
- );
- //修改订单状态
- userOrderInfo.setOrderStatus(SystemConstants.STATUS_FOUR);
- this.updateById(userOrderInfo);
- refundMoney = BigDecimal.ZERO;
- break;
- }
- if ((userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney())).compareTo(refundMoney) > 0) {
- //退款金额小于订单金额,则先退订单金额
- refundOrder(userOrderInfo,userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()), "账户退款", SystemConstants.STATUS_ONE);
- //账户变动及日志记录
- userAccountService.updateAccountBalanceAndLog(
- SecurityUtils.getUserId(),
- userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()),
- SystemConstants.CHANGE_TYPE_REDUCE,
- SystemConstants.ACCOUNT_LOG_REFUND_NOTE,
- userOrderInfo.getId()
- );
- //修改订单状态
- userOrderInfo.setOrderStatus(SystemConstants.STATUS_FOUR);
- this.updateById(userOrderInfo);
- refundMoney = refundMoney.subtract(userOrderInfo.getOrderMoney());
- }
- }
- return "账户退款,预计3个工作日内分一笔或多笔退还!如未收到,请联系客服!";
- }
- public void refundOrder(UserOrderInfo userOrderInfo, BigDecimal refundAmount, String reason, Integer type) {
- log.info("进入退款接口------>");
- log.info("执行操作的 原支付交易对应的商户订单号:{}", userOrderInfo.getOrderNo());
- //退款单号
- String out_refund_no = createOrderNo("TK",userOrderInfo.getId());
- // 创建退款订单
- UserRefundsOrderInfo userRefundsOrderInfo = new UserRefundsOrderInfo();
- userRefundsOrderInfo.setOrderId(userOrderInfo.getId());
- userRefundsOrderInfo.setOrderNo(userOrderInfo.getOrderNo());
- userRefundsOrderInfo.setOutRefundNo(out_refund_no);
- userRefundsOrderInfo.setReason(reason);
- userRefundsOrderInfo.setAmount(refundAmount);
- userRefundsOrderInfo.setType(type);
- userRefundsOrderInfo.setCreateTime(LocalDateTime.now());
- Map<String,Object> params = new HashMap<String,Object>();
- params.put("transaction_id", userOrderInfo.getTransactionId());
- params.put("out_trade_no", userOrderInfo.getOrderNo());//商户订单号
- params.put("out_refund_no", out_refund_no);//商户退款单号
- params.put("reason", reason);//退款原因
- params.put("notify_url", WechatUrlConstants.PAY_V3_REFUND_NOTIFY);//退款通知
- Map<String,Object> amount = new HashMap<String,Object>();
- amount.put("refund", amount_fee(refundAmount));//退款金额
- amount.put("currency", "CNY");
- amount.put("total", amount_fee(userOrderInfo.getOrderMoney()));//原订单金额
- params.put("amount", amount);
- // 执行请求POST 请求发送到微信退款接口
- Gson gson = new Gson();
- JsonObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_REFUND, gson.toJsonTree(params).getAsJsonObject());
- log.info("最终拿到的微信支付通知数据:" + res);
- final String status = res.get("status").getAsString();
- switch (status) {
- case "SUCCESS":
- log.info("订单:{},退款成功!原因:{}", userOrderInfo.getOrderNo(), reason);
- //修改订单状态
- userOrderInfo.setOrderStatus(SystemConstants.STATUS_FIVE);
- userOrderInfo.setRefundMoney(userOrderInfo.getRefundMoney().add(refundAmount));
- userOrderInfo.setRefundTime(LocalDateTime.now());
- this.updateById(userOrderInfo);
- break;
- case "CLOSED":
- log.info("退款关闭");
- break;
- case "PROCESSING":
- log.info("退款处理中");
- //修改订单状态
- userOrderInfo.setRefundMoney(userOrderInfo.getRefundMoney().add(refundAmount));
- this.updateById(userOrderInfo);
- break;
- case "ABNORMAL":
- log.info("订单:{},退款异常", userOrderInfo.getOrderNo());
- break;
- }
- userRefundsOrderInfo.setRefundId(res.get("refund_id").getAsString());
- userRefundsOrderInfo.setNotifyRequest(res.toString());
- userRefundsOrderInfo.setTransactionId(res.get("transaction_id").getAsString());
- userRefundsOrderInfo.setAcceptedTime(LocalDateTime.now());
- userRefundsOrderInfoMapper.insert(userRefundsOrderInfo);
- }
- @Override
- public Map<String, Object> refundCallback(HttpServletRequest request, HttpServletResponse response) {
- WechatRefundCallback refundCallback = new WechatRefundCallback() {
- @Override
- public void success(WechatCallbackRefundData refundData) {
- log.info("微信支付退款成功!");
- UserOrderInfo userOrderInfo = baseMapper.selectOne(Wrappers.lambdaQuery(UserOrderInfo.class).eq(UserOrderInfo::getOrderNo, refundData.getOrderNo()));
- userOrderInfo.setOrderStatus(SystemConstants.STATUS_FIVE);
- userOrderInfo.setRefundTime(refundData.getSuccessTime());
- baseMapper.updateById(userOrderInfo);
- UserRefundsOrderInfo userRefundsOrderInfo = userRefundsOrderInfoMapper.selectOne(Wrappers.<UserRefundsOrderInfo>lambdaQuery()
- .eq(UserRefundsOrderInfo::getOrderId, userOrderInfo.getId())
- .eq(UserRefundsOrderInfo::getRefundId, refundData.getTransactionRefundId())
- .last("limit 1")
- );
- userRefundsOrderInfo.setStatus(refundData.getStatus());
- userRefundsOrderInfo.setSuccessTime(refundData.getSuccessTime());
- userRefundsOrderInfoMapper.updateById(userRefundsOrderInfo);
- }
- @Override
- public void fail(WechatCallbackRefundData refundData) {
- log.info("微信支付退款失败!");
- UserOrderInfo userOrderInfo = baseMapper.selectOne(Wrappers.lambdaQuery(UserOrderInfo.class).eq(UserOrderInfo::getOrderNo, refundData.getOrderNo()));
- UserRefundsOrderInfo userRefundsOrderInfo = userRefundsOrderInfoMapper.selectOne(Wrappers.<UserRefundsOrderInfo>lambdaQuery()
- .eq(UserRefundsOrderInfo::getOrderId, userOrderInfo.getId())
- .eq(UserRefundsOrderInfo::getRefundId, refundData.getTransactionRefundId())
- .last("limit 1")
- );
- userRefundsOrderInfo.setStatus(refundData.getStatus());
- userRefundsOrderInfo.setSuccessTime(refundData.getSuccessTime());
- userRefundsOrderInfoMapper.updateById(userRefundsOrderInfo);
- }
- };
- Map<String, Object> result = new HashMap<>();
- if (lock.tryLock()) {
- // 2.签名验证
- //验签及解析返回数据
- JsonObject res = wechatPayV3Utils.getCallbackData(request);
- if (res == null) {
- result.put("code", "FAIL");
- result.put("message", "失败");
- return result;
- }
- log.info("最终拿到的微信支付通知数据:" + res);
- // 4.封装微信返回的数据
- WechatCallbackRefundData refundData = getRefundCallbackData(res);
- if ("SUCCESS".equals(refundData.getStatus())) {
- refundCallback.success(refundData);
- } else {
- // 特殊情况退款失败业务处理,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往商户平台-交易中心,手动处理此笔退款
- refundCallback.fail(refundData);
- }
- // 5.成功应答
- response.setStatus(200);
- result.put("code", "SUCCESS");
- result.put("message", "成功");
- } else {
- result.put("code", "FAIL");
- result.put("message", "失败");
- }
- return result;
- }
- private static WechatCallbackRefundData getRefundCallbackData(JsonObject res) {
- WechatCallbackRefundData refundData = new WechatCallbackRefundData();
- String successTime = res.get("success_time").getAsString();
- if (StringUtils.isNoneBlank(successTime)) {
- refundData.setSuccessTime(successTime);
- }
- refundData.setOrderNo(res.get("out_trade_no").getAsString());
- refundData.setRefundId(res.get("out_refund_no").getAsString());
- refundData.setTransactionId(res.get("transaction_id").getAsString());
- refundData.setTransactionRefundId(res.get("refund_id").getAsString());
- refundData.setChannel(res.get("channel").getAsString());
- final String status = res.get("refund_status").getAsString();
- refundData.setStatus(status);
- String refundMoney = res.getAsJsonObject("amount").get("refund").getAsString();
- refundData.setRefundMoney(new BigDecimal(refundMoney).movePointLeft(2));
- log.info("refundData:{}", refundData);
- return refundData;
- }
- /**
- * 通过商户订单号查询订单在微信侧支付状态
- *
- * @param out_trade_no 发起支付时创建的商户订单号
- * @return null代表查询失败 SUCCESS-成功 USERPAYING和ACCEPT为中间态 其他为支付失败
- */
- public JsonObject orderQueryByOutTradeNo(String out_trade_no, String subMchId) {
- String url = WechatUrlConstants.PAY_V3_QUERY_OUT;
- url = url.replace("{out_trade_no}", WXPayUtility.urlEncode(out_trade_no));
- Map<String, Object> args = new HashMap<>();
- args.put("sub_mchid", subMchId);
- url = url + "?" + WXPayUtility.urlEncode(args);
- return wechatPayV3Utils.sendGet(url);
- }
- /**
- * 构建支付表单返回给前端支撑JsApi支付调用
- *
- * @param openId
- * @param orderNo
- * @param amount
- * @return
- */
- private Map<String, Object> payment(String openId, String orderNo, BigDecimal amount) {
- //15分钟超时限制
- Calendar calendar = Calendar.getInstance();
- calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) + 15);
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
- //构建微信支付参数
- Map<String, Object> params = new HashMap<>();
- params.put("appid", WechatConstants.WECHAT_APPID); //小程序appid
- params.put("mchid", WechatConstants.WECHAT_MCH_ID); //商户号
- params.put("description", "订单业务"); //商品描述
- params.put("out_trade_no", orderNo); //商户订单号
- params.put("time_expire", sdf.format(calendar.getTime())); //交易结束时间 选填 时间到了之后将不能再支付 遵循rfc3339标准格式
- params.put("attach", orderNo); //附加数据 选填
- // 在查询API和支付通知中原样返回 可作为自定义参数使用
- params.put("notify_url", WechatUrlConstants.PAY_V3_NOTIFY); //支付结果异步通知接口
- //订单金额信息
- Map<String, Object> amount_json = new HashMap<>();
- //支付金额 单位:分
- // amount_json.put("total", Integer.parseInt(amount_fee(Double.valueOf("0.1"))));测试用例
- amount_json.put("total", Integer.parseInt(amount_fee(amount)));
- params.put("amount", amount_json);
- //支付者信息
- Map<String, Object> payer = new HashMap<>();
- //用户在小程序侧的openid
- payer.put("openid", openId);
- params.put("payer", payer);
- //小程序支付拉起参数
- Gson gson = new Gson();
- return wechatPay(gson.toJsonTree(params).getAsJsonObject());
- }
- /**
- * 小程序支付拉起
- *
- * @param params
- * @return
- * @throws ServiceException
- */
- public Map<String, Object> wechatPay(JsonObject params) throws ServiceException {
- //发起请求
- JsonObject res = wechatPayV3Utils.sendPost(WechatUrlConstants.PAY_V3_JSAPI, params);
- log.info("wechatPay res:{}", res.toString());
- if (StrUtil.isEmpty(res.get("prepay_id").getAsString())) {
- throw new ServiceException("支付发起失败");
- }
- StringBuilder sb = new StringBuilder();
- //返回给小程序拉起微信支付的参数
- Map<String, Object> result = new HashMap();
- // result.setAppId(WechatConstants.WECHAT_APPID); //小程序appid
- // sb.append(result.getAppId()).append("\n");
- // result.setTimeStamp((new Date().getTime() / 1000) + ""); //时间戳
- // sb.append(result.getTimeStamp()).append("\n");
- // result.setNonceStr(RandomStringUtils.randomAlphanumeric(32)); //32位随机字符串
- // sb.append(result.getNonceStr()).append("\n");
- // result.setPackageValue("prepay_id=" + res.get("prepay_id").getAsString()); //预支付id 格式为 prepay_id=xxx
- // sb.append(result.getPackageValue()).append("\n");
- // //签名
- // result.setPaySign(wechatPayV3Utils.signRSA(sb.toString()));
- // result.setSignType("RSA"); //加密方式 固定RSA
- // result.setOutTradeNo(params.get("out_trade_no").getAsString()); //商户订单号 此参数不是小程序拉起支付所需的参数 因此不参与签名
- return result;
- }
- /**
- * 创建商户订单号
- * 要求 32个字符内,只能是数字、大小写字母_-|*且在同一个商户号下唯一
- * 组成 两位前缀 + 17位时间戳 + 9位id补零 + 4位随机数 合计32位
- *
- * @param head 例如 商品-SP 退款-TK 等等
- * @param id 用户id
- * @return
- */
- public String createOrderNo(String head, Long id) {
- StringBuilder uid = new StringBuilder(id.toString());
- Date date = new Date();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
- int length = uid.length();
- for (int i = 0; i < 9 - length; i++) {
- uid.insert(0, "0");
- }
- return head + sdf.format(date) + uid + (int) ((Math.random() * 9 + 1) * 1000);
- }
- /**
- * 金额元转分字符串
- *
- * @param cny 元
- * @return
- */
- public String amount_fee(BigDecimal cny) {
- BigDecimal b2 = new BigDecimal("100");
- return cny.multiply(b2).setScale(0, RoundingMode.DOWN).toString();
- }
- public static String amount_fee(double price) {
- DecimalFormat df = new DecimalFormat("#.00");
- price = Double.valueOf(df.format(price));
- int money = (int) (price * 100);
- return money + "";
- }
- }
|