对比新文件 |
| | |
| | | package com.mzl.flower.service.payment; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.mzl.flower.config.SybPaymentProperties; |
| | | import com.mzl.flower.config.exception.ValidationException; |
| | | import com.mzl.flower.config.security.SecurityUtils; |
| | | import com.mzl.flower.constant.Constants; |
| | | import com.mzl.flower.dto.request.payment.UserPaymentDTO; |
| | | import com.mzl.flower.entity.flower.Flower; |
| | | import com.mzl.flower.entity.payment.*; |
| | | import com.mzl.flower.mapper.flower.FlowerMapper; |
| | | import com.mzl.flower.mapper.payment.*; |
| | | import com.mzl.flower.pay.SybConstants; |
| | | import com.mzl.flower.pay.SybPayService; |
| | | import com.mzl.flower.pay.SybUtil; |
| | | import com.mzl.flower.service.BaseService; |
| | | import com.mzl.flower.service.coupon.CouponRecordService; |
| | | import com.mzl.flower.service.flower.FlowerService; |
| | | import com.mzl.flower.service.point.PointGoodsService; |
| | | import com.mzl.flower.utils.UUIDGenerator; |
| | | import io.micrometer.core.instrument.util.StringUtils; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.TreeMap; |
| | | |
| | | @Service |
| | | @Transactional |
| | | @Slf4j |
| | | public class UserPaymentSybService extends BaseService { |
| | | |
| | | @Autowired |
| | | private UserPaymentMapper userPaymentMapper; |
| | | |
| | | @Autowired |
| | | private RedisLockService lockService; |
| | | |
| | | @Autowired |
| | | private OrderMapper orderMapper; |
| | | |
| | | @Autowired |
| | | private OrderItemMapper orderItemMapper; |
| | | |
| | | @Autowired |
| | | private FlowerMapper flowerMapper; |
| | | |
| | | @Autowired |
| | | private FlowerService flowerService; |
| | | |
| | | @Autowired |
| | | private DeliveryOrderService deliveryOrderService; |
| | | |
| | | @Autowired |
| | | private OrderRefundMapper orderRefundMapper; |
| | | |
| | | @Autowired |
| | | private OrderPointGoodsMapper orderPointGoodsMapper; |
| | | |
| | | @Autowired |
| | | private PointGoodsService pointGoodsService; |
| | | |
| | | @Autowired |
| | | private CouponRecordService couponRecordService; |
| | | |
| | | @Autowired |
| | | private OrderService orderService; |
| | | |
| | | @Autowired |
| | | private SybPaymentProperties sybPaymentProperties; |
| | | |
| | | /** |
| | | * 通联支付 |
| | | * |
| | | * @param order |
| | | * @return |
| | | */ |
| | | public Map prepay(Order order) throws Exception { |
| | | String userId = SecurityUtils.getUserId(); |
| | | UserPayment up = prepareUserPayment(userId, order); |
| | | log.info("UserPayment: " + toJSONString(up)); |
| | | |
| | | SybPayService service = new SybPayService(); |
| | | long trxamt = prepareAmount(up.getPaymentAmount()); |
| | | String reqsn = order.getId(); |
| | | String unireqsn = ""; |
| | | String body = "通联支付"; |
| | | String remark = "通联支付"; |
| | | String notifyUrl = sybPaymentProperties.getCallBackUrl() + "/flower/api/ua/notify/syb/paid"; |
| | | |
| | | // 调用接口 |
| | | Map map = service.createOrder(trxamt, reqsn, unireqsn, body, remark, notifyUrl); |
| | | |
| | | up.setPrepayResponse(toJSONString(map)); |
| | | |
| | | userPaymentMapper.insert(up); |
| | | |
| | | return map; |
| | | } |
| | | |
| | | private Integer prepareAmount(BigDecimal amount){ |
| | | return amount.multiply(new BigDecimal(100)).intValue(); |
| | | } |
| | | |
| | | private UserPayment prepareUserPayment(String userId, Order order){ |
| | | UserPayment up = new UserPayment(); |
| | | up.setId(UUIDGenerator.getUUID()); |
| | | up.setUserId(userId); |
| | | up.setOrderId(order.getId()); |
| | | up.setPaymentAmount(order.getTotalAmount()); |
| | | up.setPaymentTime(LocalDateTime.now()); |
| | | up.create(userId); |
| | | |
| | | return up; |
| | | } |
| | | |
| | | /** |
| | | * 动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容由于收银宝加字段而引起的签名异常 |
| | | * @param request |
| | | * @return |
| | | */ |
| | | private TreeMap<String, String> getParams(HttpServletRequest request){ |
| | | TreeMap<String, String> map = new TreeMap<>(); |
| | | Map reqMap = request.getParameterMap(); |
| | | for(Object key:reqMap.keySet()){ |
| | | String value = ((String[])reqMap.get(key))[0]; |
| | | System.out.println(key+";"+value); |
| | | map.put(key.toString(),value); |
| | | } |
| | | return map; |
| | | } |
| | | |
| | | public String handlePayCallback(HttpServletRequest request) { |
| | | try { |
| | | request.setCharacterEncoding("UTF-8");//通知传输的编码为GBK |
| | | TreeMap<String,String> params = getParams(request);//动态遍历获取所有收到的参数,此步非常关键,因为收银宝以后可能会加字段,动态获取可以兼容 |
| | | |
| | | String appkey = ""; |
| | | if("RSA".equals(params.get("signtype"))) |
| | | appkey = SybConstants.SYB_RSATLPUBKEY; |
| | | else if("SM2".equals(params.get("signtype"))) |
| | | appkey = SybConstants.SYB_SM2TLPUBKEY; |
| | | else |
| | | appkey = SybConstants.SYB_MD5_APPKEY; |
| | | boolean isSign = SybUtil.validSign(params, appkey, params.get("signtype"));// 接受到推送通知,首先验签 |
| | | log.info("验签结果:" + isSign); |
| | | |
| | | //验签完毕进行业务处理 |
| | | if(isSign){ |
| | | String originalXml = toJSONString(params); |
| | | log.info("transaction: " + originalXml); |
| | | String outTradeNo = params.get("cusorderid");//统一下单对应的reqsn订单号 |
| | | String transactionId = params.get("trxid");//通联收银宝交易流水号 |
| | | String orderId = outTradeNo; |
| | | Integer trxamt = Integer.parseInt(params.get("trxamt"));//交易金额 单位:分 |
| | | log.info("======trxamt: " + trxamt); |
| | | |
| | | String trxstatus = params.get("trxstatus");//支付状态 |
| | | String status = Constants.PAYMENT_STATUS.FAILED.name(); |
| | | //交易状态详见交易返回码说明 |
| | | /*0000:交易成功 |
| | | 错误码为空: 交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(例如30秒)查询交易 |
| | | 1001:交易不存在 |
| | | 2008或者2000 : 交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易 |
| | | 3开头的错误码代表交易失败 |
| | | 3888-流水号重复 |
| | | 3889-交易控制失败,具体原因看errmsg |
| | | 3099-渠道商户错误 |
| | | 3014-交易金额小于应收手续费 |
| | | 3031-校验实名信息失败 |
| | | 3088-交易未支付(在查询时间区间内未成功支付,如已影响资金24小时内会做差错退款处理) |
| | | 3089-撤销异常,如已影响资金24小时内会做差错退款处理 |
| | | 3045-其他错误,具体原因看errmsg |
| | | 3999-其他错误,具体原因看errmsg |
| | | 其他3开头的错误码代表交易失败,具体原因请读取errmsg |
| | | */ |
| | | if ("0000".equals(trxstatus)){ |
| | | status = Constants.PAYMENT_STATUS.SUCCESS.name(); |
| | | } |
| | | |
| | | UserPaymentDTO dto = new UserPaymentDTO(); |
| | | dto.setOrderId(orderId); |
| | | dto.setTransactionId(transactionId); |
| | | dto.setOutTradeNo(outTradeNo); |
| | | dto.setOriginalXml(originalXml); |
| | | dto.setPaymentAmountCallback(trxamt + ""); |
| | | dto.setStatus(status); |
| | | |
| | | saveCallbackInfo(dto, Constants.ORDER_STATUS_BACKEND.PAYMENT.name()); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("解析付款通知出错:{}", e.getMessage(), e); |
| | | } |
| | | |
| | | return "success"; |
| | | } |
| | | |
| | | public void saveCallbackInfo(UserPaymentDTO dto, String orderStatus){ |
| | | String orderId = dto.getOrderId(); |
| | | boolean lock = lockService.getObjectLock(RedisLockService.LOCK_KEY_PAYMENT_NOTIFY_, orderId); |
| | | if(!lock){ |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | UserPayment up = userPaymentMapper.selectOne( |
| | | new QueryWrapper<UserPayment>().eq("order_id", orderId)); |
| | | BeanUtils.copyProperties(dto, up); |
| | | |
| | | up.setPaymentTimeCallback(LocalDateTime.now()); |
| | | userPaymentMapper.updateById(up); |
| | | |
| | | Order order = orderMapper.selectById(orderId); |
| | | if(Constants.ORDER_STATUS_BACKEND.PAYMENT.name().equals(orderStatus)) { |
| | | order.setPaymentTrId(dto.getTransactionId()); |
| | | if (up.getPaymentAmountCallback() != null) { |
| | | order.setPaymentAmount(new BigDecimal(up.getPaymentAmountCallback()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));//转换成单位元 |
| | | } else { |
| | | order.setPaymentAmount(order.getTotalAmount()); |
| | | } |
| | | order.setPaymentTime(up.getPaymentTimeCallback()); |
| | | order.setStatus(Constants.ORDER_STATUS.SEND.name()); |
| | | } else if (Constants.ORDER_STATUS_BACKEND.CANCEL.name().equals(orderStatus)){ |
| | | order.setStatus(Constants.ORDER_STATUS.CANCEL.name()); |
| | | } |
| | | order.setStatusBackend(orderStatus); |
| | | orderMapper.updateById(order); |
| | | |
| | | if(Constants.ORDER_STATUS_BACKEND.PAYMENT.name().equals(orderStatus)) { |
| | | postPayment(order); |
| | | } else if (Constants.ORDER_STATUS_BACKEND.CANCEL.name().equals(orderStatus)){ |
| | | releasePrepayLock(order); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error(e.getMessage(), e); |
| | | } finally { |
| | | lockService.releaseObjectLock(RedisLockService.LOCK_KEY_PAYMENT_NOTIFY_, orderId); |
| | | } |
| | | } |
| | | |
| | | private void postPayment(Order order){ |
| | | log.info("回调后处理订单信息:" + toJSONString(order)); |
| | | //创建配送单 |
| | | deliveryOrderService.createDeliveryOrder(order); |
| | | flowerService.updateFlowerSales(order); |
| | | } |
| | | |
| | | public boolean checkOrderStatusPayAgain(String outTradeNo) throws Exception { |
| | | UserPayment up = userPaymentMapper.selectOne( |
| | | new QueryWrapper<UserPayment>().eq("order_id", outTradeNo)); |
| | | String s = up.getStatus(); |
| | | if(StringUtils.isNotEmpty(s)){ |
| | | return true; |
| | | } |
| | | |
| | | SybPayService service = new SybPayService(); |
| | | Map<String,String> params = service.query(outTradeNo, up.getTransactionId()); |
| | | |
| | | String originalXml = toJSONString(params);//回调请求内容 |
| | | log.info("message: " + originalXml); |
| | | String transactionId = params.get("trxid");//通联收银宝交易流水号 |
| | | String orderId = outTradeNo; |
| | | |
| | | String trxcode = params.get("trxcode"); |
| | | /* 交易类型 |
| | | VSP501:微信支付 |
| | | VSP502:微信支付撤销 |
| | | VSP503:微信支付退款 |
| | | */ |
| | | String trxstatus = params.get("trxstatus");//支付状态 |
| | | if("VSP501".equals(trxcode)){ |
| | | if("0000".equals(trxstatus)) { |
| | | String status = Constants.PAYMENT_STATUS.SUCCESS.name(); |
| | | UserPaymentDTO dto = new UserPaymentDTO(); |
| | | dto.setOrderId(orderId); |
| | | dto.setTransactionId(transactionId); |
| | | dto.setOutTradeNo(outTradeNo); |
| | | dto.setOriginalXml(originalXml); |
| | | String trxamtStr = params.get("trxamt");//交易金额 单位:分 |
| | | log.info("======trxamt: " + trxamtStr); |
| | | dto.setPaymentAmountCallback(trxamtStr); |
| | | |
| | | dto.setStatus(status); |
| | | |
| | | String orderStatus = Constants.ORDER_STATUS_BACKEND.PAYMENT.name(); |
| | | |
| | | saveCallbackInfo(dto, orderStatus); |
| | | |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return !("1001".equals(trxstatus) || StringUtils.isEmpty(trxstatus) |
| | | || "2008".equals(trxstatus) |
| | | || "2000".equals(trxstatus)); |
| | | } |
| | | |
| | | public boolean checkOrderStatusRefund(String outTradeNo) throws Exception { |
| | | UserPayment up = userPaymentMapper.selectOne( |
| | | new QueryWrapper<UserPayment>().eq("order_id", outTradeNo)); |
| | | String s = up.getStatus(); |
| | | if(StringUtils.isEmpty(s)){ |
| | | return true; |
| | | } |
| | | |
| | | SybPayService service = new SybPayService(); |
| | | Map<String,String> params = service.query(outTradeNo, up.getTransactionId()); |
| | | |
| | | String originalXml = toJSONString(params);//回调请求内容 |
| | | log.info("message: " + originalXml); |
| | | |
| | | String trxcode = params.get("trxcode"); |
| | | /* 交易类型 |
| | | VSP501:微信支付 |
| | | VSP502:微信支付撤销 |
| | | VSP503:微信支付退款 |
| | | */ |
| | | if ("VSP502".equals(trxcode) || "VSP503".equals(trxcode)){ |
| | | String trxid = params.get("trxid"); |
| | | updateOrderRefund(outTradeNo, trxid); |
| | | |
| | | return true; |
| | | } |
| | | |
| | | return false; |
| | | } |
| | | |
| | | public void cancelOrder(String orderId) throws Exception { |
| | | UserPayment up = userPaymentMapper.selectOne( |
| | | new QueryWrapper<UserPayment>().eq("order_id", orderId)); |
| | | if(StringUtils.isNotEmpty(up.getStatus())){ |
| | | throw new ValidationException("订单不可取消"); |
| | | } |
| | | |
| | | SybPayService service = new SybPayService(); |
| | | |
| | | Map<String,String> params = service.query(orderId, up.getTransactionId()); |
| | | String retcode = params.get("retcode"); |
| | | if(!"SUCCESS".equals(retcode)){ |
| | | throw new ValidationException("查询订单交易状态失败: " + params.get("retmsg")); |
| | | } |
| | | String trxstatus = params.get("trxstatus");//支付状态 |
| | | |
| | | if("1001".equals(trxstatus) || "3088".equals(trxstatus)){ |
| | | //3088-交易未支付(在查询时间区间内未成功支付,如已影响资金24小时内会做差错退款处理) |
| | | //1001:交易不存在 |
| | | //直接取消 |
| | | } else if (StringUtils.isEmpty(trxstatus) |
| | | || "2008".equals(trxstatus) |
| | | || "2000".equals(trxstatus)) { |
| | | String trxid = params.get("trxid"); |
| | | //2008或者2000 : 交易处理中,请查询交易,如果是实时交易(例如刷卡支付,交易撤销,退货),建议每隔一段时间(10秒)查询交易 |
| | | Map<String,String> map = service.close(trxid, orderId); |
| | | log.info("======关闭订单结果" + toJSONString(map)); |
| | | |
| | | retcode = map.get("retcode"); |
| | | if(!"SUCCESS".equals(retcode)){ |
| | | throw new ValidationException("调用通联关闭订单失败: " + map.get("retmsg")); |
| | | } |
| | | trxstatus = map.get("trxstatus"); |
| | | if(!"0000".equals(trxstatus)){ |
| | | throw new ValidationException("取消订单失败: " + map.get("errmsg")); |
| | | } |
| | | |
| | | } else { |
| | | throw new ValidationException("订单不可取消"); |
| | | } |
| | | |
| | | Order order = orderMapper.selectById(orderId); |
| | | order.setStatus(Constants.ORDER_STATUS.CANCEL.name()); |
| | | order.setStatusBackend(Constants.ORDER_STATUS_BACKEND.CANCEL.name()); |
| | | order.setCancelTime(LocalDateTime.now()); |
| | | order.update(SecurityUtils.getUserId()); |
| | | orderMapper.updateById(order); |
| | | |
| | | up.setStatus(Constants.PAYMENT_STATUS.CLOSED.name()); |
| | | up.update(SecurityUtils.getUserId()); |
| | | userPaymentMapper.updateById(up); |
| | | |
| | | releasePrepayLock(order); |
| | | } |
| | | |
| | | private void releasePrepayLock(Order order){ |
| | | log.info("恢复库存 积分商品兑换券 优惠券: " + order); |
| | | revertFlowerStock(order.getId()); |
| | | |
| | | //恢复积分商品兑换券 |
| | | revertPointGoodsRecord(order.getId()); |
| | | |
| | | //恢复优惠券 |
| | | String memberCouponId = order.getMemberCouponId(); |
| | | if(StringUtils.isNotEmpty(memberCouponId)) { |
| | | couponRecordService.cancelCouponUsage(order.getId()); |
| | | } |
| | | } |
| | | |
| | | private void revertPointGoodsRecord(String orderId){ |
| | | List<OrderPointGoods> ls = orderPointGoodsMapper.selectList(new QueryWrapper<OrderPointGoods>() |
| | | .eq("order_id", orderId)); |
| | | if(ls != null && ls.size() > 0){ |
| | | for(OrderPointGoods pg : ls){ |
| | | pointGoodsService.revertExchangeGoods(pg.getGoodsRecordId()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | public Map payAgain(String orderId){ |
| | | // 获取订单里面的商品是否有限购的,如果有则判断是否已经超过限购数量 |
| | | List<OrderItem> orderItemList = orderItemMapper.selectList(new QueryWrapper<OrderItem>() |
| | | .eq("order_id", orderId)); |
| | | |
| | | orderItemList.forEach(orderItem -> { |
| | | // 限购数量 鲜花数量校验 |
| | | Integer completeNumToday=orderService.getFlowerCompleteNumToday(orderItem.getCreateBy(),orderItem.getFlowerId()); |
| | | Integer tmp=completeNumToday+orderItem.getNum(); |
| | | Flower flower=flowerMapper.selectById(orderItem.getFlowerId()); |
| | | if(null!=flower.getLimited() && tmp.compareTo(flower.getLimited())>0){ |
| | | throw new ValidationException("商品:'"+flower.getName()+"' 昨天17:00到今天17:00 超过限售数量:"+flower.getLimited()+"!"); |
| | | } |
| | | }); |
| | | |
| | | UserPayment up = userPaymentMapper.selectOne( |
| | | new QueryWrapper<UserPayment>().eq("order_id", orderId)); |
| | | if(StringUtils.isNotEmpty(up.getStatus())){ |
| | | throw new ValidationException("订单不可再支付"); |
| | | } |
| | | |
| | | return parseObject(up.getPrepayResponse(), TreeMap.class); |
| | | } |
| | | |
| | | public synchronized void revertFlowerStock(String orderId){ |
| | | List<OrderItem> ls = orderItemMapper.selectList(new QueryWrapper<OrderItem>() |
| | | .eq("order_id", orderId)); |
| | | for(OrderItem c : ls){ |
| | | flowerMapper.addFlowerStock(c.getFlowerId(), c.getNum()); |
| | | } |
| | | } |
| | | |
| | | public void refundOrderCustomer(String orderId) throws Exception { |
| | | UserPayment up = userPaymentMapper.selectOne( |
| | | new QueryWrapper<UserPayment>().eq("order_id", orderId)); |
| | | if(up.getPaymentAmount() == null){ |
| | | throw new ValidationException("订单不可退款"); |
| | | } |
| | | |
| | | long trxamt = prepareAmount(up.getPaymentAmount()); |
| | | String reqsn = orderId; |
| | | String oldtrxid = up.getTransactionId(); |
| | | String oldreqsn = orderId; |
| | | |
| | | SybPayService service = new SybPayService(); |
| | | Map<String,String> map = service.cancel(trxamt, reqsn, oldtrxid, oldreqsn); |
| | | String retcode = map.get("retcode"); |
| | | if(!"SUCCESS".equals(retcode)){ |
| | | throw new ValidationException("调用通联撤销接口失败: " + map.get("retmsg")); |
| | | } |
| | | |
| | | //这个不是订单状态,是通用的,如果是支付查询,代表就是订单状态,如果是退款代表的是退款状态 |
| | | String trxstatus = map.get("trxstatus"); |
| | | if(!"0000".equals(trxstatus)){ |
| | | log.error("通联撤销交易失败:" + map.get("errmsg")); |
| | | throw new ValidationException("订单退款交易失败:" + map.get("errmsg")); |
| | | } |
| | | |
| | | updateOrderRefund(orderId, oldtrxid); |
| | | } |
| | | |
| | | /** |
| | | * 退款 |
| | | * |
| | | * @param orderId |
| | | */ |
| | | public void refundOrder(String orderId) throws Exception { |
| | | UserPayment up = userPaymentMapper.selectOne( |
| | | new QueryWrapper<UserPayment>().eq("order_id", orderId)); |
| | | if(up.getPaymentAmount() == null){ |
| | | throw new ValidationException("订单不可退款"); |
| | | } |
| | | |
| | | long trxamt = prepareAmount(up.getPaymentAmount()); |
| | | String reqsn = orderId; |
| | | String oldtrxid = up.getTransactionId(); |
| | | String oldreqsn = orderId; |
| | | |
| | | SybPayService service = new SybPayService(); |
| | | Map<String,String> map = service.refund(trxamt, reqsn, oldtrxid, oldreqsn); |
| | | String retcode = map.get("retcode"); |
| | | if(!"SUCCESS".equals(retcode)){ |
| | | throw new ValidationException("调用通联退款失败: " + map.get("retmsg")); |
| | | } |
| | | |
| | | //这个不是订单状态,是通用的,如果是支付查询,代表就是订单状态,如果是退款代表的是退款状态 |
| | | String trxstatus = map.get("trxstatus"); |
| | | if(!"0000".equals(trxstatus)){ |
| | | throw new ValidationException("订单退款交易失败:" + map.get("errmsg")); |
| | | } |
| | | |
| | | updateOrderRefund(orderId, oldtrxid); |
| | | } |
| | | |
| | | private void updateOrderRefund(String orderId, String refundNo){ |
| | | Order o = orderMapper.selectById(orderId); |
| | | |
| | | if(Constants.ORDER_STATUS.REFUND.name().equals(o.getStatus())){ |
| | | return; |
| | | } |
| | | |
| | | o.setRefundAmount(o.getPaymentAmount()); |
| | | o.setRefundNo(refundNo); |
| | | o.setRefundTime(LocalDateTime.now()); |
| | | |
| | | o.setStatus(Constants.ORDER_STATUS.REFUND.name()); |
| | | o.setStatusBackend(Constants.ORDER_STATUS_BACKEND.REFUND.name()); |
| | | o.update("sys"); |
| | | |
| | | orderMapper.updateById(o); |
| | | |
| | | deliveryOrderService.refundDelete(orderId); |
| | | |
| | | releasePrepayLock(o); |
| | | } |
| | | |
| | | public String refundOrderSub(Order o, BigDecimal refundAmount) throws Exception { |
| | | if(o.getPaymentTime() == null || o.getPaymentAmount() == null){ |
| | | throw new ValidationException("未支付订单不可退款"); |
| | | } |
| | | |
| | | if(o.getRefundTime() != null){ |
| | | throw new ValidationException("已全额退款订单不可退款"); |
| | | } |
| | | |
| | | if (refundAmount == null || refundAmount.doubleValue() == 0) { |
| | | throw new ValidationException("退款金额不能为空"); |
| | | } |
| | | |
| | | List<OrderRefund> reLs = orderRefundMapper.selectList(new QueryWrapper<OrderRefund>() |
| | | .eq("order_id", o.getId())); |
| | | BigDecimal rra = new BigDecimal(0); |
| | | if(reLs != null && reLs.size() > 0){ |
| | | for(OrderRefund r : reLs){ |
| | | rra = rra.add(r.getRefundAmount()); |
| | | } |
| | | } |
| | | |
| | | long total = (long)prepareAmount(o.getPaymentAmount()); |
| | | long refund = (long)prepareAmount(refundAmount); |
| | | |
| | | long rraa = (long)prepareAmount(rra); |
| | | if(rraa + refund > total){ |
| | | throw new ValidationException("退款金额不能大于订单金额"); |
| | | } |
| | | |
| | | OrderRefund re = new OrderRefund(); |
| | | re.setId(UUIDGenerator.getUUID()); |
| | | re.setOrderId(o.getId()); |
| | | re.setOrderAmount(o.getPaymentAmount()); |
| | | re.setRefundAmount(refundAmount); |
| | | |
| | | UserPayment up = userPaymentMapper.selectOne( |
| | | new QueryWrapper<UserPayment>().eq("order_id", o.getId())); |
| | | |
| | | long trxamt = refund; |
| | | String reqsn = o.getId(); |
| | | String oldtrxid = up.getTransactionId(); |
| | | String oldreqsn = null; |
| | | |
| | | SybPayService service = new SybPayService(); |
| | | Map<String,String> map = service.refund(trxamt, reqsn, oldtrxid, oldreqsn); |
| | | String retcode = map.get("retcode"); |
| | | if(!"SUCCESS".equals(retcode)){ |
| | | throw new ValidationException("调用通联退款失败: " + map.get("retmsg")); |
| | | } |
| | | |
| | | //这个不是订单状态,是通用的,如果是支付查询,代表就是订单状态,如果是退款代表的是退款状态 |
| | | String trxstatus = map.get("trxstatus"); |
| | | if(!"0000".equals(trxstatus)){ |
| | | throw new ValidationException("订单退款交易失败:" + map.get("errmsg")); |
| | | } |
| | | |
| | | re.setRequest(toJSONString(map)); |
| | | re.create(SecurityUtils.getUserId()); |
| | | |
| | | re.setStatus(retcode); |
| | | re.setNotification(retcode); |
| | | re.setNotifyTime(LocalDateTime.now()); |
| | | |
| | | orderRefundMapper.insert(re); |
| | | |
| | | return re.getId(); |
| | | } |
| | | |
| | | } |