| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- package com.cyksj.service.special.impl;
- import cn.hutool.core.date.DateUtil;
- import cn.hutool.core.util.StrUtil;
- import com.alipay.api.internal.util.AlipaySignature;
- import com.baomidou.mybatisplus.core.toolkit.Wrappers;
- import com.cyksj.common.EnvCommonService;
- import com.cyksj.common.exception.BusinessRuntimeException;
- import com.cyksj.common.snowflake.Sequence;
- import com.cyksj.common.util.Codec;
- import com.cyksj.common.util.Jsons;
- import com.cyksj.config.zfb.BaseZfbConfig;
- import com.cyksj.config.zfb.ZfbProductCode;
- import com.cyksj.mapper.channel.ShopConfigMapper;
- import com.cyksj.mapper.special.SpecialMemberEntitlementMapper;
- import com.cyksj.mapper.special.SpecialPayOrderMapper;
- import com.cyksj.mapper.special.SpecialPayProductMapper;
- import com.cyksj.model.dto.AliPayParams;
- import com.cyksj.model.entity.ShopConfig;
- import com.cyksj.model.entity.SpecialPayOrder;
- import com.cyksj.model.entity.SpecialPayProduct;
- import com.cyksj.model.entity.SpecialMemberEntitlement;
- import com.cyksj.model.request.SpecialPayCreateReq;
- import com.cyksj.model.request.OrderAttach;
- import com.cyksj.model.response.AliPayTradeStatus;
- import com.cyksj.model.response.SpecialPayCreateRep;
- import com.cyksj.service.pay.AliPayCommonService;
- import com.cyksj.service.special.SpecialPayService;
- import com.cyksj.service.sys.SysConfigService;
- import lombok.RequiredArgsConstructor;
- import lombok.extern.slf4j.Slf4j;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import java.math.BigDecimal;
- import java.math.RoundingMode;
- import java.util.Date;
- import java.util.List;
- import java.util.Map;
- import java.util.Optional;
- @Slf4j
- @Service
- @RequiredArgsConstructor
- public class SpecialPayServiceImpl implements SpecialPayService {
- private static final Sequence SEQUENCE = new Sequence(0);
- private static final int ORDER_EXPIRE_MINUTES = 5;
- private final SpecialPayProductMapper productMapper;
- private final SpecialPayOrderMapper orderMapper;
- private final SpecialMemberEntitlementMapper entitlementMapper;
- private final ShopConfigMapper shopConfigMapper;
- private final SysConfigService sysConfigService;
- private final AliPayCommonService aliPayCommonService;
- private final EnvCommonService envCommonService;
- @Override
- public List<SpecialPayProduct> getEnabledProducts() {
- return productMapper.selectList(Wrappers.lambdaQuery(SpecialPayProduct.class)
- .eq(SpecialPayProduct::getEnabled, true)
- .orderByAsc(SpecialPayProduct::getSortBy, SpecialPayProduct::getId));
- }
- @Override
- @Transactional(rollbackFor = Throwable.class)
- public SpecialPayCreateRep createAlipayOrder(Long userId, SpecialPayCreateReq request) throws Exception {
- SpecialPayProduct product = productMapper.selectOne(Wrappers.lambdaQuery(SpecialPayProduct.class)
- .eq(SpecialPayProduct::getProductCode, request.getProductCode())
- .eq(SpecialPayProduct::getEnabled, true)
- .last("limit 1"));
- if (product == null) {
- throw BusinessRuntimeException.getInstance("支付套餐不存在或已下架");
- }
- if (product.getAmount() == null || product.getAmount().compareTo(BigDecimal.ZERO) <= 0
- || product.getDurationDays() == null || product.getDurationDays() <= 0) {
- throw BusinessRuntimeException.getInstance("支付套餐配置异常");
- }
- String alipayProductCode = getAlipayProductCode(request.getPayType());
- Date now = new Date();
- SpecialPayOrder order = new SpecialPayOrder();
- order.setOrderNo("SP" + SEQUENCE.nextId());
- order.setUserId(userId);
- order.setProductCode(product.getProductCode());
- order.setSubject(product.getProductName());
- order.setAmount(product.getAmount());
- order.setDurationDays(product.getDurationDays());
- order.setStatus(SpecialPayOrder.Status.CREATED);
- order.setFulfillStatus(SpecialPayOrder.FulfillStatus.INIT);
- order.setShopId(sysConfigService.getDefaultShopConfigByType("zfb"));
- order.setExpireTime(DateUtil.offsetMinute(now, ORDER_EXPIRE_MINUTES));
- order.setCreatedTime(now);
- order.setUpdateTime(now);
- orderMapper.insert(order);
- String notifyUrl = envCommonService.getNotifyHost() + BaseZfbConfig.specialPayNotifyUrl;
- AliPayParams payParams = aliPayCommonService.builderPayParams(
- order.getId(), order.getOrderNo(), order.getShopId(), order.getAmount(),
- order.getCreatedTime(), order.getSubject(), alipayProductCode,
- request.getPayMode(), notifyUrl, request.getReturnUrl());
- if (payParams == null || StrUtil.isBlank(payParams.getBody())) {
- throw BusinessRuntimeException.getInstance("支付宝下单失败");
- }
- SpecialPayCreateRep response = new SpecialPayCreateRep();
- response.setOrderNo(order.getOrderNo());
- response.setStatus(order.getStatus());
- response.setExpireTime(order.getExpireTime());
- response.setPayBody(payParams.getBody());
- return response;
- }
- @Override
- public SpecialPayOrder getUserOrder(Long userId, String orderNo) {
- SpecialPayOrder order = orderMapper.selectOne(Wrappers.lambdaQuery(SpecialPayOrder.class)
- .eq(SpecialPayOrder::getOrderNo, orderNo)
- .eq(SpecialPayOrder::getUserId, userId)
- .last("limit 1"));
- if (order == null) {
- throw BusinessRuntimeException.getInstance("订单不存在");
- }
- return order;
- }
- @Override
- public SpecialMemberEntitlement getMemberEntitlement(Long userId) {
- return entitlementMapper.selectOne(Wrappers.lambdaQuery(SpecialMemberEntitlement.class)
- .eq(SpecialMemberEntitlement::getUserId, userId)
- .last("limit 1"));
- }
- @Override
- @Transactional(rollbackFor = Throwable.class)
- public void handleAlipayNotify(Map<String, String> params) throws Exception {
- String appId = params.get("app_id");
- ShopConfig shopConfig = StrUtil.isBlank(appId) ? null : shopConfigMapper.getByAppId(appId);
- if (shopConfig == null || !AlipaySignature.rsaCheckV1(params, shopConfig.getPublicKey(),
- BaseZfbConfig.charset, BaseZfbConfig.signType)) {
- throw BusinessRuntimeException.getInstance("支付宝回调验签失败");
- }
- String orderNo = params.get("out_trade_no");
- SpecialPayOrder order = orderMapper.selectByOrderNoForUpdate(orderNo);
- if (order == null) {
- throw BusinessRuntimeException.getInstance("特殊支付订单不存在");
- }
- if (!StrUtil.equals(order.getShopId(), appId)) {
- throw BusinessRuntimeException.getInstance("支付宝回调商户不匹配");
- }
- String tradeStatus = params.get("trade_status");
- if (!AliPayTradeStatus.TRADE_SUCCESS.getStatus().equals(tradeStatus)
- && !AliPayTradeStatus.TRADE_FINISHED.getStatus().equals(tradeStatus)) {
- throw BusinessRuntimeException.getInstance("支付宝交易状态未成功");
- }
- verifyOrderIdentity(params, order);
- verifyAmount(params.get("total_amount"), order.getAmount());
- String tradeNo = params.get("trade_no");
- if (StrUtil.isBlank(tradeNo)) {
- throw BusinessRuntimeException.getInstance("支付宝交易号为空");
- }
- if (order.getStatus() == SpecialPayOrder.Status.PAID) {
- if (!StrUtil.equals(order.getAlipayTradeNo(), tradeNo)) {
- throw BusinessRuntimeException.getInstance("支付宝交易号不匹配");
- }
- return;
- }
- if (order.getStatus() != SpecialPayOrder.Status.CREATED) {
- throw BusinessRuntimeException.getInstance("当前订单状态不可支付");
- }
- Date payTime = new Date();
- if (StrUtil.isNotBlank(params.get("gmt_payment"))) {
- payTime = DateUtil.parse(params.get("gmt_payment"), "yyyy-MM-dd HH:mm:ss");
- }
- String buyerId = Optional.ofNullable(params.get("buyer_id"))
- .orElse(params.get("buyer_open_id"));
- if (orderMapper.markPaid(order.getId(), tradeNo, buyerId, payTime) != 1) {
- throw BusinessRuntimeException.getInstance("订单支付状态更新失败");
- }
- if (order.getDurationDays() == null || order.getDurationDays() <= 0) {
- throw BusinessRuntimeException.getInstance("订单套餐配置异常");
- }
- entitlementMapper.extend(order.getUserId(), order.getDurationDays(), order.getId());
- if (orderMapper.markFulfilled(order.getId()) != 1) {
- throw BusinessRuntimeException.getInstance("会员权益发放失败");
- }
- log.info("特殊支付宝订单支付并履约成功, orderNo:{}, tradeNo:{}", orderNo, tradeNo);
- }
- private String getAlipayProductCode(Integer payType) {
- if (Integer.valueOf(1).equals(payType)) {
- return ZfbProductCode.MOBILE_WEB.getProductCode();
- }
- if (Integer.valueOf(2).equals(payType)) {
- return ZfbProductCode.PC_WEB.getProductCode();
- }
- throw BusinessRuntimeException.getInstance("不支持的支付宝支付方式");
- }
- private void verifyOrderIdentity(Map<String, String> params, SpecialPayOrder order) {
- try {
- String body = Codec.DoBase64.custom().setData(params.get("body")).decodeAsText();
- OrderAttach attach = Jsons.parseObject(body, OrderAttach.class);
- if (attach == null || !order.getId().equals(attach.getO())
- || !StrUtil.equals(order.getOrderNo(), params.get("out_trade_no"))) {
- throw BusinessRuntimeException.getInstance("支付宝回调订单不匹配");
- }
- } catch (BusinessRuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw BusinessRuntimeException.getInstance("支付宝回调订单参数异常");
- }
- }
- private void verifyAmount(String totalAmount, BigDecimal expectedCents) {
- try {
- BigDecimal callbackCents = new BigDecimal(totalAmount)
- .multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.UNNECESSARY);
- if (expectedCents == null || callbackCents.compareTo(expectedCents) != 0) {
- throw BusinessRuntimeException.getInstance("支付宝回调金额不匹配");
- }
- } catch (BusinessRuntimeException e) {
- throw e;
- } catch (Exception e) {
- throw BusinessRuntimeException.getInstance("支付宝回调金额异常");
- }
- }
- }
|