Selaa lähdekoodia

管理后台:支付平台应用创建接口

wangqi49 2 viikkoa sitten
vanhempi
commit
972166ac95

+ 93 - 0
webchat-admin/src/main/java/com/webchat/admin/controller/PaymentAppController.java

@@ -0,0 +1,93 @@
+package com.webchat.admin.controller;
+
+import com.webchat.admin.service.PaymentAppService;
+import com.webchat.common.bean.APIPageResponseBean;
+import com.webchat.common.bean.APIResponseBean;
+import com.webchat.common.bean.APIResponseBeanUtil;
+import com.webchat.common.config.annotation.ValidatePermission;
+import com.webchat.common.helper.SessionHelper;
+import com.webchat.domain.vo.request.payment.CreateAppRequestVO;
+import com.webchat.domain.vo.response.payment.AppBaseResponseVO;
+import com.webchat.domain.vo.response.payment.CreateAppResponseVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@Slf4j
+@RestController
+@RequestMapping("/admin-service/payment/app")
+public class PaymentAppController {
+
+
+    @Autowired
+    private PaymentAppService paymentAppService;
+
+    /**
+     * 支付平台创建应用(接入方)
+     *
+     * @param createAppRequest
+     * @return
+     */
+    @ValidatePermission
+    @PostMapping("/create")
+    public APIResponseBean<CreateAppResponseVO> createApp(@RequestBody CreateAppRequestVO createAppRequest) {
+        String userId = SessionHelper.getCurrentUserId();
+        createAppRequest.setUserId(userId);
+        CreateAppResponseVO app = paymentAppService.createApp(createAppRequest);
+        return APIResponseBeanUtil.success(app);
+    }
+
+    /**
+     * 发布app
+     *
+     * @return
+     */
+    @ValidatePermission
+    @PostMapping("/publish/{appId}")
+    public APIResponseBean<Boolean> publishApp(@PathVariable Long appId) {
+        boolean result = paymentAppService.publishApp(appId);
+        String userId = SessionHelper.getCurrentUserId();
+        log.info("{}发布应用{},操作结果:{}", userId, appId, result);
+        return APIResponseBeanUtil.success(result);
+    }
+
+    /**
+     * 删除app
+     *
+     * @param appId
+     * @return
+     */
+    @ValidatePermission
+    @PostMapping("/delete/{appId}")
+    public APIResponseBean<Boolean> deleteApp(@PathVariable Long appId) {
+        boolean result = paymentAppService.deleteApp(appId);
+        String userId = SessionHelper.getCurrentUserId();
+        log.info("{}删除应用{},操作结果:{}", userId, appId, result);
+        return APIResponseBeanUtil.success(result);
+    }
+
+
+    /**
+     * 应用列表
+     *
+     * @param keywords
+     * @param pageNo
+     * @param pageSize
+     * @return
+     */
+    @ValidatePermission
+    @GetMapping("/page")
+    public APIPageResponseBean<AppBaseResponseVO> page(@RequestParam(value = "keywords", required = false) String keywords,
+                                                @RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
+                                                @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
+
+        return paymentAppService.page(keywords, pageNo, pageSize);
+    }
+}

+ 76 - 0
webchat-admin/src/main/java/com/webchat/admin/service/PaymentAppService.java

@@ -0,0 +1,76 @@
+package com.webchat.admin.service;
+
+import com.webchat.common.bean.APIPageResponseBean;
+import com.webchat.common.bean.APIResponseBean;
+import com.webchat.common.bean.APIResponseBeanUtil;
+import com.webchat.common.exception.BusinessException;
+import com.webchat.domain.vo.request.payment.CreateAppRequestVO;
+import com.webchat.domain.vo.response.payment.AppBaseResponseVO;
+import com.webchat.domain.vo.response.payment.CreateAppResponseVO;
+import com.webchat.rmi.pay.PaymentAppServiceClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PaymentAppService {
+
+
+    @Autowired
+    private PaymentAppServiceClient paymentAppServiceClient;
+
+    /**
+     * 支付平台创建应用(接入方)
+     *
+     * @param createAppRequest
+     * @return
+     */
+    public CreateAppResponseVO createApp(CreateAppRequestVO createAppRequest) {
+        APIResponseBean<CreateAppResponseVO> responseBean = paymentAppServiceClient.createApp(createAppRequest);
+        if (APIResponseBeanUtil.isOk(responseBean)) {
+            return responseBean.getData();
+        }
+        throw new BusinessException(responseBean.getMsg());
+    }
+
+    /**
+     * 发布app
+     *
+     * @return
+     */
+    public boolean publishApp(Long appId) {
+        APIResponseBean<Boolean> responseBean = paymentAppServiceClient.publishApp(appId);
+        if (APIResponseBeanUtil.isOk(responseBean)) {
+            return responseBean.getData();
+        }
+        throw new BusinessException(responseBean.getMsg());
+    }
+
+    /**
+     * 删除app
+     *
+     * @param appId
+     * @return
+     */
+    public boolean deleteApp(Long appId) {
+        APIResponseBean<Boolean> responseBean = paymentAppServiceClient.deleteApp(appId);
+        if (APIResponseBeanUtil.isOk(responseBean)) {
+            return responseBean.getData();
+        }
+        throw new BusinessException(responseBean.getMsg());
+    }
+
+
+    /**
+     * 应用列表
+     *
+     * @param keywords
+     * @param pageNo
+     * @param pageSize
+     * @return
+     */
+    public APIPageResponseBean<AppBaseResponseVO> page(String keywords, Integer pageNo, Integer pageSize) {
+
+        return paymentAppServiceClient.page(keywords, pageNo, pageSize);
+    }
+
+}

+ 22 - 0
webchat-pay/src/main/java/com/webchat/pay/controller/PaymentAppServiceController.java

@@ -1,12 +1,16 @@
 package com.webchat.pay.controller;
 
+import com.webchat.common.bean.APIPageResponseBean;
 import com.webchat.common.bean.APIResponseBean;
 import com.webchat.common.bean.APIResponseBeanUtil;
 import com.webchat.domain.vo.request.payment.CreateAppRequestVO;
+import com.webchat.domain.vo.response.payment.AppBaseResponseVO;
 import com.webchat.domain.vo.response.payment.CreateAppResponseVO;
 import com.webchat.pay.service.PaymentAppService;
 import com.webchat.rmi.pay.PaymentAppServiceClient;
+import org.simpleframework.xml.Path;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -24,4 +28,22 @@ public class PaymentAppServiceController implements PaymentAppServiceClient {
         CreateAppResponseVO app = paymentAppService.saveApp(createAppRequest);
         return APIResponseBeanUtil.success(app);
     }
+
+    @Override
+    public APIResponseBean<Boolean> publishApp(@PathVariable Long appId) {
+        paymentAppService.publishApp(appId);
+        return APIResponseBeanUtil.success(true);
+    }
+
+    @Override
+    public APIResponseBean<Boolean> deleteApp(@PathVariable Long appId) {
+        paymentAppService.deleteApp(appId);
+        return APIResponseBeanUtil.success(true);
+    }
+
+    @Override
+    public APIPageResponseBean<AppBaseResponseVO> page(String keywords, Integer pageNo, Integer pageSize) {
+
+        return paymentAppService.page(keywords, pageNo, pageSize);
+    }
 }

+ 7 - 0
webchat-pay/src/main/java/com/webchat/pay/repository/dao/IAppDAO.java

@@ -1,14 +1,21 @@
 package com.webchat.pay.repository.dao;
 
 import com.webchat.pay.repository.entity.AppEntity;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
 import org.springframework.data.jpa.repository.JpaRepository;
 import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
+
 
 @Repository
 public interface IAppDAO extends JpaSpecificationExecutor<AppEntity>,
         JpaRepository<AppEntity, Long> {
 
 
+    Page<AppEntity> findAllByStatusIn(List<Integer> statusList, Pageable pageable);
+
+    Page<AppEntity> findAllByNameLikeAndStatusIn(String appName, List<Integer> statusList, Pageable pageable);
 }

+ 6 - 0
webchat-pay/src/main/java/com/webchat/pay/service/PaymentApiService.java

@@ -2,6 +2,7 @@ package com.webchat.pay.service;
 
 
 import com.webchat.common.bean.APIResponseBean;
+import com.webchat.common.enums.CommonStatusEnum;
 import com.webchat.common.enums.RedisKeyEnum;
 import com.webchat.common.service.RedisService;
 import com.webchat.common.service.SnowflakeIdGeneratorService;
@@ -66,6 +67,10 @@ public class PaymentApiService {
          * 3. 校验签名
          */
         // 1. 校验访问凭证
+        AppBaseResponseVO app = appService.appInfo(appId);
+        if (app == null || !CommonStatusEnum.PUBLISHED.getStatusCode().equals(app.getStatus())) {
+            throw new PaymentAccessAuthException("应用不存在/未发布");
+        }
         AppAkSkDTO akSkDTO = appService.getAppAkSk(appId);
         if (akSkDTO == null) {
             throw new PaymentAccessAuthException("应用不存在");
@@ -122,6 +127,7 @@ public class PaymentApiService {
         Assert.notNull(appId, "交易凭证失效");
         AppBaseResponseVO appBaseResponse = appService.appInfo(appId);
         Assert.notNull(appBaseResponse, "应用不存在,联系客服");
+        Assert.isTrue(CommonStatusEnum.PUBLISHED.getStatusCode().equals(appBaseResponse.getStatus()), "应用未发布");
 
         /**
          * 基于雪花算法生成分布式下唯一id,作为交易分布式事务id,用于后续异常交易快速回滚

+ 67 - 1
webchat-pay/src/main/java/com/webchat/pay/service/PaymentAppService.java

@@ -1,6 +1,7 @@
 package com.webchat.pay.service;
 
 
+import com.webchat.common.bean.APIPageResponseBean;
 import com.webchat.common.constants.WebConstant;
 import com.webchat.common.enums.CommonStatusEnum;
 import com.webchat.common.enums.RedisKeyEnum;
@@ -13,13 +14,22 @@ import com.webchat.domain.vo.response.payment.AppBaseResponseVO;
 import com.webchat.domain.vo.response.payment.CreateAppResponseVO;
 import com.webchat.pay.repository.dao.IAppDAO;
 import com.webchat.pay.repository.entity.AppEntity;
+import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Service;
 import org.springframework.util.Assert;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
 @Service
 public class PaymentAppService {
 
@@ -110,6 +120,61 @@ public class PaymentAppService {
         return createAppResponseVO;
     }
 
+    /**
+     * 发布应用
+     * @param appId
+     */
+    public void publishApp(Long appId) {
+
+        this.updateAppStatus(appId, CommonStatusEnum.PUBLISHED);
+    }
+
+    /**
+     * 删除应用
+     * @param appId
+     */
+    public void deleteApp(Long appId) {
+
+        this.updateAppStatus(appId, CommonStatusEnum.DELETED);
+    }
+
+    private void updateAppStatus(Long appId, CommonStatusEnum status) {
+        AppEntity appEntity = appDAO.findById(appId).orElse(null);
+        Assert.notNull(appEntity, "状态修改失败: 应用不存在");
+        appEntity.setStatus(status.getStatusCode());
+        appDAO.save(appEntity);
+        // 刷新应用详情信息缓存
+        this.refreshAppInfoCache(appEntity);
+    }
+
+    /**
+     * 查询应用列表
+     *
+     * @param keywords
+     * @param pageNo
+     * @param pageSize
+     * @return
+     */
+    public APIPageResponseBean<AppBaseResponseVO> page(String keywords, Integer pageNo, Integer pageSize) {
+
+        Pageable pageable = PageRequest.of(pageNo - 1, pageSize, Sort.by(Sort.Direction.DESC, "id"));
+        List<Integer> statusList = new ArrayList<>();
+        statusList.add(CommonStatusEnum.NEW.getStatusCode());
+        statusList.add(CommonStatusEnum.PUBLISHED.getStatusCode());
+
+        Page<AppEntity> appEntities;
+        if (StringUtils.isBlank(keywords)) {
+            appEntities = appDAO.findAllByStatusIn(statusList, pageable);
+        } else {
+            appEntities = appDAO.findAllByNameLikeAndStatusIn("%" + keywords + "%", statusList, pageable);
+        }
+        List<AppBaseResponseVO> vos = new ArrayList<>();
+        if (appEntities != null && CollectionUtils.isNotEmpty(appEntities.getContent())) {
+            vos = appEntities.getContent().stream().map(this::covertResponseVo).collect(Collectors.toList());
+        }
+        return APIPageResponseBean.success(pageNo, pageSize, appEntities.getTotalElements(), vos);
+    }
+
     private AppBaseResponseVO covertResponseVo(AppEntity appEntity) {
         AppBaseResponseVO response = new AppBaseResponseVO();
         BeanUtils.copyProperties(appEntity, response);
@@ -194,7 +259,8 @@ public class PaymentAppService {
             appEntity = new AppEntity();
             appEntity.setAdmin(createAppRequest.getUserId());
             appEntity.setCreateBy(createAppRequest.getUserId());
-            appEntity.setStatus(CommonStatusEnum.NEW.getStatusCode());
+            // 后面改成默认新建状态
+            appEntity.setStatus(CommonStatusEnum.PUBLISHED.getStatusCode());
         }
         appEntity.setLogo(createAppRequest.getLogo());
         appEntity.setName(createAppRequest.getName());

+ 1 - 0
webchat-pay/src/main/java/com/webchat/pay/service/PaymentOrderService.java

@@ -5,6 +5,7 @@ import com.google.common.collect.Lists;
 import com.webchat.common.enums.RedisKeyEnum;
 import com.webchat.common.enums.payment.PaymentOrderDetailStatusEnum;
 import com.webchat.common.enums.payment.PaymentOrderStatusEnum;
+import com.webchat.common.enums.payment.PaymentTransTypeEnum;
 import com.webchat.common.service.RedisService;
 import com.webchat.common.service.SnowflakeIdGeneratorService;
 import com.webchat.common.util.JsonUtil;

+ 36 - 0
webchat-remote/src/main/java/com/webchat/rmi/pay/PaymentAppServiceClient.java

@@ -1,11 +1,16 @@
 package com.webchat.rmi.pay;
 
+import com.webchat.common.bean.APIPageResponseBean;
 import com.webchat.common.bean.APIResponseBean;
 import com.webchat.domain.vo.request.payment.CreateAppRequestVO;
+import com.webchat.domain.vo.response.payment.AppBaseResponseVO;
 import com.webchat.domain.vo.response.payment.CreateAppResponseVO;
 import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestParam;
 
 @FeignClient(name = "webchat-pay-service", contextId = "paymentAppServiceClient")
 public interface PaymentAppServiceClient {
@@ -19,4 +24,35 @@ public interface PaymentAppServiceClient {
      */
     @PostMapping("/pay-service/app/create")
     APIResponseBean<CreateAppResponseVO> createApp(@RequestBody CreateAppRequestVO createAppRequest);
+
+    /**
+     * 发布app
+     *
+     * @return
+     */
+    @PostMapping("/pay-service/app/publish/{appId}")
+    APIResponseBean<Boolean> publishApp(@PathVariable Long appId);
+
+    /**
+     * 删除app
+     *
+     * @param appId
+     * @return
+     */
+    @PostMapping("/pay-service/app/delete/{appId}")
+    APIResponseBean<Boolean> deleteApp(@PathVariable Long appId);
+
+
+    /**
+     * 应用列表
+     *
+     * @param keywords
+     * @param pageNo
+     * @param pageSize
+     * @return
+     */
+    @GetMapping("/pay-service/app/page")
+    APIPageResponseBean<AppBaseResponseVO> page(@RequestParam(value = "keywords", required = false) String keywords,
+                                                @RequestParam(value = "pageNo", required = false, defaultValue = "1") Integer pageNo,
+                                                @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize);
 }

+ 47 - 6
webchat-ugc/src/main/java/com/webchat/ugc/service/redpacket/AbstractOpenRedPacketService.java

@@ -4,14 +4,28 @@ import com.webchat.common.constants.RedPacketConstants;
 import com.webchat.common.enums.AccountRelationTypeEnum;
 import com.webchat.common.enums.RedisKeyEnum;
 import com.webchat.common.enums.RoleCodeEnum;
+import com.webchat.common.enums.payment.PaymentTransEventEnum;
+import com.webchat.common.enums.payment.PaymentTransTypeEnum;
 import com.webchat.common.exception.BusinessException;
 import com.webchat.common.service.RedisService;
+import com.webchat.common.util.ThreadPoolExecutorUtil;
+import com.webchat.domain.dto.payment.PaymentTransRequestDTO;
+import com.webchat.domain.vo.request.SendRedPacketRequestVO;
 import com.webchat.domain.vo.response.RedPacketBaseVO;
+import com.webchat.domain.vo.response.RedPacketDetailVO;
 import com.webchat.domain.vo.response.UserBaseResponseInfoVO;
+import com.webchat.ugc.repository.dao.IRedPacketRecordDAO;
+import com.webchat.ugc.repository.entity.RedPacketRecordEntity;
 import com.webchat.ugc.service.AccountService;
+import com.webchat.ugc.service.PaymentService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.Assert;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+
 
 public abstract class AbstractOpenRedPacketService implements RedPacketOpenInter {
 
@@ -21,6 +35,10 @@ public abstract class AbstractOpenRedPacketService implements RedPacketOpenInter
     private RedPacketService redPacketService;
     @Autowired
     private AccountService accountService;
+    @Autowired
+    private PaymentService paymentService;
+    @Autowired
+    private IRedPacketRecordDAO redPacketRecordDAO;
 
     /**
      * 实际红包拆分(保证并发数据安全)
@@ -83,10 +101,11 @@ public abstract class AbstractOpenRedPacketService implements RedPacketOpenInter
         Assert.isTrue(!isOpen, "重复拆分");
     }
 
+    @Transactional
     @Override
     public int open(Long redPacketId, String userId) {
 
-        RedPacketBaseVO redPacket = redPacketService.getRedPacket(redPacketId);
+        RedPacketDetailVO redPacket = redPacketService.getRedPacket(redPacketId);
         /**
          * 1. 校验红包拆分权限
          * 包含:红包有效、拆包权限 ……
@@ -97,15 +116,26 @@ public abstract class AbstractOpenRedPacketService implements RedPacketOpenInter
          * 2. 获得拆包资格,拆红包
          */
         int amount = this.openRedPacket(redPacket, userId);
-
+        BigDecimal openYun = new BigDecimal(amount).movePointLeft(2).setScale(2, RoundingMode.HALF_UP);
         /**
-         * 3. 调用支付平台(webchat-pay 微服务,完成用户拆包金额入账)
+         * 3. 业务侧持久化拆分数据
          */
-
+        RedPacketRecordEntity redPacketRecord = new RedPacketRecordEntity();
+        redPacketRecord.setRedPacketId(redPacketId);
+        redPacketRecord.setUserId(userId);
+        redPacketRecord.setMoney(openYun);
+        redPacketRecord.setCreateDate(new Date());
+        redPacketRecordDAO.save(redPacketRecord);
         /**
-         * 4. 业务侧持久化拆分数据
+         * 4. 调用支付平台(webchat-pay 微服务,完成用户拆包金额入账)
          */
-
+        String orderId = redPacket.getOrderId();
+        PaymentTransRequestDTO paymentTransRequest = this.buildPaymentTransRequestDTO(orderId, userId, openYun);
+        boolean transResult = paymentService.doTrans(paymentTransRequest);
+        if (!transResult) {
+            // TODO 回滚本次红包拆分消耗数据(回滚Redis缓存数据)
+            throw new BusinessException("服务繁忙");
+        }
         return amount;
     }
 
@@ -146,4 +176,15 @@ public abstract class AbstractOpenRedPacketService implements RedPacketOpenInter
 
         redPacketService.updateRedPacketStatus(redPacketId, status);
     }
+
+    private PaymentTransRequestDTO buildPaymentTransRequestDTO(String orderId, String userId, BigDecimal openYun) {
+        PaymentTransRequestDTO dto = new PaymentTransRequestDTO();
+        dto.setOrderId(orderId);
+        dto.setAmount(openYun);
+        dto.setTransType(PaymentTransTypeEnum.INCOME.getTransType());
+        dto.setTransDetail("拆分红包");
+        dto.setTransEvent(PaymentTransEventEnum.RED_PACKET.getTransEvent());
+        dto.setSourceUserId(userId);
+        return dto;
+    }
 }

+ 2 - 0
webchat-ugc/src/main/java/com/webchat/ugc/service/redpacket/RedPacketOpenInter.java

@@ -1,6 +1,8 @@
 package com.webchat.ugc.service.redpacket;
 
 
+import org.springframework.transaction.annotation.Transactional;
+
 public interface RedPacketOpenInter {
 
     /**

+ 3 - 3
webchat-ugc/src/main/java/com/webchat/ugc/service/redpacket/RedPacketService.java

@@ -265,12 +265,12 @@ public class RedPacketService {
     }
 
 
-    public RedPacketBaseVO getRedPacket(Long redPacketId) {
+    public RedPacketDetailVO getRedPacket(Long redPacketId) {
 
         String cacheKey = this.redPacketCacheKey(redPacketId);
         String cache = redisService.get(cacheKey);
         if (StringUtils.isNotBlank(cache)) {
-            return JsonUtil.fromJson(cache, RedPacketBaseVO.class);
+            return JsonUtil.fromJson(cache, RedPacketDetailVO.class);
         }
         /**
          * 虽然红包缓存设置的2 * 24小时,且红包24小时内有效,但是不能完全依赖redis
@@ -282,7 +282,7 @@ public class RedPacketService {
             lock.lock();
             cache = redisService.get(cacheKey);
             if (StringUtils.isNotBlank(cache)) {
-                return JsonUtil.fromJson(cache, RedPacketBaseVO.class);
+                return JsonUtil.fromJson(cache, RedPacketDetailVO.class);
             }
             return this.refreshRedPacketDetailCache(redPacketId);
         } catch (Exception e) {