Kaynağa Gözat

Merge remote-tracking branch 'origin/master'

SheepHy 4 gün önce
ebeveyn
işleme
b30ce5643b
25 değiştirilmiş dosya ile 397 ekleme ve 645 silme
  1. 4 0
      national-motion-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
  2. 4 0
      national-motion-module-system/national-motion-system-biz/pom.xml
  3. 15 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/OrderController.java
  4. 32 11
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/commercial/CommercialController.java
  5. 2 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/AppOrderInfoDTO.java
  6. 24 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/form/TemporaryCourseForm.java
  7. 3 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/form/UserPayForm.java
  8. 6 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IOrderService.java
  9. 51 3
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/OrderServiceImpl.java
  10. 0 103
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/controller/PayController.java
  11. 0 74
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/service/PayService.java
  12. 0 398
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/service/impl/PayServiceImpl.java
  13. 7 3
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/vo/NotifyRequest.java
  14. 24 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/vo/NotifyResponse.java
  15. 2 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/quartz/job/OrTeachingJobService.java
  16. 97 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/redission/RedissonDelayQueue.java
  17. 6 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppCoursesVerificationRecord.java
  18. 8 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppOrder.java
  19. 27 0
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/form/VerifyForm.java
  20. 2 2
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppIsinMapper.xml
  21. 2 1
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/IAppCoureseService.java
  22. 2 4
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/IAppCoursesVerificationRecordService.java
  23. 44 33
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/impl/AppCoureseServiceImpl.java
  24. 28 10
      national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/impl/AppCoursesVerificationRecordServiceImpl.java
  25. 7 0
      pom.xml

+ 4 - 0
national-motion-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java

@@ -656,6 +656,10 @@ public interface CommonConstant {
     Integer ORDER_PRO_INFO_TYPE_6 = 6;
     Integer ORDER_PRO_INFO_TYPE_7 = 7;
 
+    /**
+     * 订单超时未支付延迟任务前缀
+     */
+     String ORDER_TIME_OUT_TASK_PREFIX= "OrderTimeOutTask_";
 
     /**
      *  券状态 0-待使用 1-已使用 2-已失效

+ 4 - 0
national-motion-module-system/national-motion-system-biz/pom.xml

@@ -44,6 +44,10 @@
 			<groupId>org.jeecgframework.jimureport</groupId>
 			<artifactId>jimubi-spring-boot-starter</artifactId>
 		</dependency>
+		<dependency>
+			<groupId>org.redisson</groupId>
+			<artifactId>redisson</artifactId>
+		</dependency>
 	</dependencies>
 	
 </project>

+ 15 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/OrderController.java

@@ -12,11 +12,14 @@ import org.jeecg.modules.app.form.UserPayForm;
 import org.jeecg.modules.app.service.IOrderService;
 import org.jeecg.modules.app.vo.OrderVO;
 import org.jeecg.modules.app.vo.QueryOrderVerifyRecordsVO;
+import org.jeecg.modules.pay.vo.NotifyRequest;
+import org.jeecg.modules.pay.vo.NotifyResponse;
 import org.simpleframework.xml.core.Validate;
 import org.springframework.format.annotation.DateTimeFormat;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import java.io.IOException;
 import java.util.Date;
 import java.util.List;
 
@@ -117,10 +120,21 @@ public class OrderController {
      */
     @Operation(summary = "订单-创建")
     @PostMapping("/createOrder")
-    public Result<UserPayForm> createOrder(@Validate @RequestBody CreateOrderForm createOrderForm) {
+    public Result<UserPayForm> createOrder(@Validate @RequestBody CreateOrderForm createOrderForm) throws IOException {
         return Result.ok(appOrderService.createOrder(createOrderForm));
     }
 
+    /**
+     * 支付回调
+     * @param
+     * @return
+     */
+    @Operation(summary = "支付回调")
+    @PostMapping("/orderNotify")
+    public NotifyResponse orderNotify(@RequestBody NotifyRequest notifyRequestForm) throws IOException {
+        return appOrderService.orderNotify(notifyRequestForm);
+    }
+
     /**
      * 订单-小程序支付后回显信息
      *

+ 32 - 11
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/controller/commercial/CommercialController.java

@@ -14,18 +14,24 @@ import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.modules.app.form.ClassPostponeForm;
 import org.jeecg.modules.app.form.CourseQueryUsersForm;
+import org.jeecg.modules.app.form.TemporaryCourseForm;
 import org.jeecg.modules.app.service.IAppIsinService;
 import org.jeecg.modules.app.vo.*;
+import org.jeecg.modules.redission.RedissonDelayQueue;
 import org.jeecg.modules.system.app.entity.AppCoursesPriceRules;
 import org.jeecg.modules.system.app.entity.AppCoursesVerificationRecord;
 import org.jeecg.modules.system.app.entity.FamilyMembers;
-import org.jeecg.modules.system.app.form.CoursesVerificationRecordForm;
+import org.jeecg.modules.system.app.form.VerifyForm;
 import org.jeecg.modules.system.app.service.*;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Comparator;
 import java.util.List;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Tag(name = "App商家端课程相关接口")
@@ -86,13 +92,13 @@ public class CommercialController {
     /**
      * 拍照验课上传图片
      *
-     * @param formList
+     * @param verifyForm
      * @return
      */
     @Operation(summary = "拍照验课上传图片")
     @PostMapping("/courseUploadImage")
-    public Result<Boolean> courseUploadImage(@RequestBody List<CoursesVerificationRecordForm> formList) {
-        return Result.OK(appCoursesVerificationRecordService.courseUploadImage(formList));
+    public Result<Boolean> courseUploadImage(@RequestBody VerifyForm verifyForm) {
+        return Result.OK(appCoursesVerificationRecordService.courseUploadImage(verifyForm));
     }
 
     /**
@@ -110,7 +116,12 @@ public class CommercialController {
                         .eq(ObjectUtil.isNotNull(form.getOrPostpone()), AppCoursesVerificationRecord::getOrPostpone, form.getOrPostpone())
                         .eq(ObjectUtil.isNotNull(form.getVerifyStatus()), AppCoursesVerificationRecord::getVerifyStatus, form.getVerifyStatus())
                 );
-        return Result.OK(verificationRecords);
+        ArrayList<AppCoursesVerificationRecord> list = verificationRecords.stream()
+                .collect(Collectors.collectingAndThen(
+                        Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AppCoursesVerificationRecord::getUseUserId))),
+                        ArrayList::new
+                ));
+        return Result.OK(list);
     }
 
     /**
@@ -129,15 +140,13 @@ public class CommercialController {
     /**
      * 临时约课
      *
-     * @param coursePriceRulesId
-     * @param userId
+     * @param temporaryCourseForm
      * @return
      */
     @Operation(summary = "临时约课")
-    @PutMapping("/temporaryCourse")
-    public Result<Boolean> temporaryCourse(@Schema(description = "课时ID") @RequestParam(name = "coursePriceRulesId") String coursePriceRulesId,
-                                           @Schema(description = "学生ID") @RequestParam(name = "userId") String userId) {
-        return Result.OK(appCoureseService.temporaryCourse(coursePriceRulesId, userId));
+    @PostMapping("/temporaryCourse")
+    public Result<Boolean> temporaryCourse(@RequestBody TemporaryCourseForm temporaryCourseForm) {
+        return Result.OK(appCoureseService.temporaryCourse(temporaryCourseForm));
     }
 
     /**
@@ -242,4 +251,16 @@ public class CommercialController {
     public String wechatPayNotify(HttpServletRequest request) {
         return "支付回调成功";
     }
+
+    private final RedissonDelayQueue redissonDelayQueue;
+    /**
+     * 测试超时未支付延时任务
+     */
+    @GetMapping("/orderTimeOutTask")
+    public void orderTimeOutTask() {
+        log.info("测试超时未支付延时任务-开始");
+        String task = "OrderTimeOutTask_1953753939752968194";
+        redissonDelayQueue.offerTask(task, 30);
+        log.info("测试超时未支付延时任务-结束");
+    }
 }

+ 2 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/dto/AppOrderInfoDTO.java

@@ -144,4 +144,6 @@ public class AppOrderInfoDTO implements Serializable {
     //提前预约时间:0免预约 单位:时
     @Schema(description = "提前预约时间:0免预约 单位:时")
     private Integer advanceTime;
+    @Schema(description = "参赛资质")
+    private String gameCertification;
 }

+ 24 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/form/TemporaryCourseForm.java

@@ -0,0 +1,24 @@
+package org.jeecg.modules.app.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Schema(description = "零食约课表单对象")
+public class TemporaryCourseForm implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "")
+    private String coursePriceRulesId;
+
+    @Schema(description = "用户IDs")
+    private List<String> userIds;
+}

+ 3 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/form/UserPayForm.java

@@ -20,4 +20,7 @@ public class UserPayForm implements Serializable {
 
     @Schema(description = "订单号")
     private String orderCode;
+
+    @Schema(description = "JsApi参数")
+    private String params;
 }

+ 6 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/IOrderService.java

@@ -5,7 +5,10 @@ import org.jeecg.modules.app.form.CreateOrderForm;
 import org.jeecg.modules.app.form.UserPayForm;
 import org.jeecg.modules.app.vo.OrderVO;
 import org.jeecg.modules.app.vo.QueryOrderVerifyRecordsVO;
+import org.jeecg.modules.pay.vo.NotifyRequest;
+import org.jeecg.modules.pay.vo.NotifyResponse;
 
+import java.io.IOException;
 import java.util.Date;
 import java.util.List;
 
@@ -65,7 +68,7 @@ public interface IOrderService {
      **/
     List<OrderVO.PreviewOrderPlaceSchoolTime> previewOrderPlaceSchoolTime(String placeId);
 
-    UserPayForm createOrder(CreateOrderForm createOrderForm);
+    UserPayForm createOrder(CreateOrderForm createOrderForm) throws IOException;
 
     /**
      * @Author SheepHy
@@ -79,4 +82,6 @@ public interface IOrderService {
     AppOrderInfoDTO queryOrderInfo(String orderCode);
 
     List<QueryOrderVerifyRecordsVO> queryOrderVerifyRecords(String orderId, String ticketNo);
+
+    NotifyResponse orderNotify(NotifyRequest notifyRequestForm);
 }

+ 51 - 3
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/app/service/impl/OrderServiceImpl.java

@@ -26,6 +26,10 @@ import org.jeecg.modules.app.service.IOrderService;
 import org.jeecg.modules.app.vo.AppGameScheduleVO;
 import org.jeecg.modules.app.vo.OrderVO;
 import org.jeecg.modules.app.vo.QueryOrderVerifyRecordsVO;
+import org.jeecg.modules.pay.V3LabsApi;
+import org.jeecg.modules.pay.vo.NotifyRequest;
+import org.jeecg.modules.pay.vo.NotifyResponse;
+import org.jeecg.modules.redission.RedissonDelayQueue;
 import org.jeecg.modules.system.app.entity.*;
 import org.jeecg.modules.system.app.mapper.*;
 import org.jeecg.modules.system.mapper.SysDepartMapper;
@@ -33,6 +37,7 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
+import java.io.IOException;
 import java.math.BigDecimal;
 import java.time.LocalDate;
 import java.time.LocalTime;
@@ -85,6 +90,8 @@ public class OrderServiceImpl implements IOrderService {
     private AppCoursesVerificationRecordMapper appCoursesVerificationRecordMapper;
     @Resource
     private AppContractSignMapper appContractSignMapper;
+    @Resource
+    private RedissonDelayQueue redissonDelayQueue;
 
     @Override
     @Transactional(rollbackFor = Exception.class)
@@ -353,7 +360,7 @@ public class OrderServiceImpl implements IOrderService {
      */
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public UserPayForm createOrder(CreateOrderForm createOrderForm) {
+    public UserPayForm createOrder(CreateOrderForm createOrderForm) throws IOException {
         //获取登录用户
         LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
 
@@ -662,7 +669,7 @@ public class OrderServiceImpl implements IOrderService {
                             appCoursesVerificationRecord.setUseUserName(familyMembers.getFullName());
                             appCoursesVerificationRecord.setVerifyStatus(0);
                             appCoursesVerificationRecord.setOrPostpone(0);
-                            appCoursesVerificationRecord.setCoursesType(0);
+                            appCoursesVerificationRecord.setCoursesType(appCoursesPriceRules.getCoursesType());
                             appCoursesVerificationRecordList.add(appCoursesVerificationRecord);
                         }
                     }
@@ -790,12 +797,32 @@ public class OrderServiceImpl implements IOrderService {
             appCoursesVerificationRecordMapper.insert(appCoursesVerificationRecord);
         }
 
-        //构建支付表单返回给前端支撑支付调用
+        //构建支付表单返回给前端支撑JsApi支付调用
         UserPayForm payForm = new UserPayForm();
         payForm
                 .setOrderId(appOrder.getId())
                 .setOrderCode(orderCode)
         ;
+
+        String out_trade_no = appOrder.getOrderCode();
+        Integer total_amount = appOrder.getPrice().multiply(new BigDecimal(100)).intValue();
+        String request_ip = "127.0.0.1";
+        String subject = "订单标题";
+        String notify_url = "https://www.baidu.com";
+        String sub_appid = "wx62ba790ae7983d34";
+        String user_id = "oWL7G6MsNrimSKUgr2ezEXgEp4Po";
+        String goods_id = appOrder.getProductIds();
+        String goods_name = "商品名称";
+        Integer quantity = appOrder.getAmount();
+
+        //拉卡拉预支付订单,返回构建小程序支付拉起参数
+        String res = V3LabsApi.transPreorder_wxpay_applet(out_trade_no, total_amount, request_ip, subject, notify_url, sub_appid, user_id, goods_id, goods_name, quantity);
+        payForm.setParams(res);
+
+        //发布任务到redission延迟队列
+        String task = CommonConstant.ORDER_TIME_OUT_TASK_PREFIX + appOrder.getId();
+        redissonDelayQueue.offerTask(task, 60 * 15);
+
         return payForm;
     }
 
@@ -838,6 +865,7 @@ public class OrderServiceImpl implements IOrderService {
         appOrderInfoDTO.setPhoneNumber(appOrder.getUserPhone());
         appOrderInfoDTO.setTotalPrice(appOrder.getOriginalPrice());
         appOrderInfoDTO.setPrice(appOrder.getPrice());
+        appOrderInfoDTO.setGameCertification(appOrder.getGameCertification());
         if (appOrder.getType().equals(CommonConstant.ORDER_TYPE_2)) {
             appOrderInfoDTO.setSDiscounts(appOrder.getSDiscounts());
             appOrderInfoDTO.setTDiscounts(appOrder.getTDiscounts());
@@ -1109,6 +1137,26 @@ public class OrderServiceImpl implements IOrderService {
         return appOrder;
     }
 
+    @Override
+    public NotifyResponse orderNotify(NotifyRequest notifyRequestForm) {
+
+        //查询订单
+        AppOrder appOrder = appOrderMapper.selectOne(Wrappers.<AppOrder>lambdaQuery().eq(AppOrder::getOrderCode, notifyRequestForm.getOut_trade_no()).last("limit 1"));
+        if (ObjectUtil.isNotEmpty(appOrder)) {
+            appOrder
+                    .setPayId(notifyRequestForm.getAcc_trade_no())
+                    .setOrderStatus(2)
+                    .setPayStatus(2)
+                    .setPayTime(DateUtil.parse(notifyRequestForm.getTrade_time(),"yyyyMMddHHmmss"))
+                    .setCallbackStatus(1);
+        }
+
+        NotifyResponse notifyResponse = new NotifyResponse();
+        notifyResponse.setCode("SUCCESS").setMessage("执行成功");
+
+        return notifyResponse;
+    }
+
     /**
      * @return String 订单号
      * @Author SheepHy

+ 0 - 103
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/controller/PayController.java

@@ -1,103 +0,0 @@
-package org.jeecg.modules.pay.controller;
-
-
-import io.swagger.v3.oas.annotations.Operation;
-import lombok.extern.slf4j.Slf4j;
-import org.jeecg.common.api.vo.Result;
-import org.jeecg.modules.pay.service.PayService;
-import org.jeecg.modules.pay.vo.NotifyVO;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-
-/**
- * <p>
- *     支付控制器
- * </p>
- *
- * @author HY
- * @date 2024-08-19 20:05
- */
-@RestController
-@RequestMapping("/edu/pay")
-@Slf4j
-public class PayController {
-    @Resource
-    private PayService payService;
-    /**
-     * 支付回调
-     *
-     * @param notifyVO {@link NotifyVO}
-     * @return
-     */
-    @Operation(summary="支付回调")
-    @RequestMapping(value = "/notify")
-    public Result<String> notify(@RequestBody NotifyVO notifyVO) {
-        payService.notify(notifyVO);
-        return Result.OK("执行成功");
-
-
-    }
-
-    /**
-     * <p>
-     *    主扫-支付宝
-     * </p>
-     * @author HY
-     * @Date 2024-08-18
-     */
-//    @Operation(summary="主扫-支付宝")
-//    @GetMapping(value = "/transPreorderALi")
-//    public Result<String> transPreorderALi(@RequestParam("orderId") String orderId){
-//        return Result.OK(payService.transPreorderALi(orderId));
-//    }
-
-    /**
-     * <p>
-     *     被扫-聚合
-     * </p>
-     * @author HY
-     * @Date
-     */
-//    @Operation(summary="被扫-聚合")
-//    @PostMapping(value = "/transMicropay")
-//    public Result<Boolean> transMicropay(TransMicropayDTO transMicropayDTO){
-//        if(Optional.ofNullable(payService.transMicropay(transMicropayDTO)).isPresent()){
-//            return Result.OK(payService.transMicropay(transMicropayDTO));
-//        }else {
-//            return Result.OK();
-//        }
-//    }
-
-//    /**
-//     * <p>
-//     *      退款
-//     * </p>
-//     * @author HY
-//     * @param
-//     * @return
-//     * @Date
-//     */
-//    @ApiOperation(value="退款", notes="退款")
-//    @GetMapping(value = "/relationRefund")
-//    public Result<RefundVO> relationRefund(@RequestParam("orderId") String orderId){
-//        return Result.OK(payService.relationRefund(orderId));
-//    }
-
-    /**
-     * <p>
-     *    交易查询
-     * </p>
-     * @author HY
-     * @param
-     * @return
-     * @Date
-     */
-//    @Operation(summary="交易查询")
-//    @GetMapping(value = "/queryTradeQuery")
-//    public Result<QueryOrderVO> queryTradeQuery(@RequestParam("orderId") String orderId){
-//        return Result.OK(payService.queryTradeQuery(orderId, null));
-//    }
-}

+ 0 - 74
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/service/PayService.java

@@ -1,74 +0,0 @@
-package org.jeecg.modules.pay.service;
-
-import org.jeecg.modules.pay.vo.NotifyVO;
-
-/**
- * <p>
- *
- * </p>
- *
- * @author HY
- * @date 2024-08-19 20:07
- */
-public interface PayService {
-/**
- * <p>
- *    支付回调
- * </p>
- * @author HY
- * @param notifyVO {@link NotifyVO}
- * @Date 2024-08-18
- */
-void notify(NotifyVO notifyVO);
-
-/**
- * <p>
- *    主扫-支付宝
- * </p>
- * @author HY
- * @Date 2024-08-18
- */
-//String transPreorderALi(String orderId);
-
-/**
- * <p>
- *    主扫-微信
- * </p>
- * @author HY
- * @Date 2024-08-18
- */
-//Map<String, Object> transPreorderWx(String orderId, String openid);
-
-/**
- * <p>
- *     被扫-聚合
- * </p>
- * @author HY
- * @Date
- */
-//boolean transMicropay(TransMicropayDTO transMicropayDTO);
-
-/**
- * <p>
- *      退款
- * </p>
- * @author HY
- * @param
- * @return
- * @Date
- */
-//boolean relationRefund(String orderId);
-
-/**
- * <p>
- *    交易查询
- * </p>
- * @author HY
- * @param
- * @return
- * @Date
- */
-//String queryTradeQuery(String orderId, String orderNumber);
-
-//boolean prePaymentInquiry(String orederId);
-}

+ 0 - 398
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/service/impl/PayServiceImpl.java

@@ -1,398 +0,0 @@
-package org.jeecg.modules.pay.service.impl;
-
-import org.jeecg.modules.pay.service.PayService;
-import org.jeecg.modules.pay.vo.NotifyVO;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-
-/**
- * <p>
- *
- * </p>
- *
- * @author HY
- * @date 2024-08-19 20:09
- */
-@Service
-public class PayServiceImpl implements PayService {
-
-
-
-    /**
-     * <p>
-     * 支付回调
-     * </p>
-     *
-     * @param notifyVO {@link NotifyVO}
-     * @return boolean
-     * @author HY
-     * @Date 2024-08-18
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void notify(NotifyVO notifyVO) {
-        System.out.println("支付回调:  " + notifyVO);
-
-//        if(null == eduOrder.getCallbackFlag()){
-//            queryTradeQuery(eduOrder.getId(),null);
-//        }
-//        if (Optional.ofNullable(eduOrder).isPresent()) {
-//            try {
-//                String trade_no = "H9995935";
-//                if(eduOrder.getPaymentType() == 1){
-//                    trade_no = "J9442025";
-//                }
-//                String string = V3LabsApi.queryTradeQuery(new TradeQueryRequest().setTerm_no(trade_no).setTrade_no(notifyVO.getTrade_no()).setOut_trade_no(notifyVO.getOut_trade_no()).setMerchant_no(notifyVO.getMerchant_no()));
-//                PayDataVO queryOrderVO = new Gson().fromJson(string, PayDataVO.class);
-//                Map<String, Object> respData = (Map<String, Object>) queryOrderVO.getResp_data();
-//                if (respData.get("trade_state").equals("SUCCESS") && respData.get("total_amount").equals(getMoney(eduOrder.getPayment()))) {
-//                    switch (respData.get("account_type").toString()){
-//                        case "WECHAT":
-//                            eduOrder.setPaymentType(1);
-//                            break;
-//                        case "ALIPAY":
-//                            eduOrder.setPaymentType(2);
-//                            break;
-//                        case "UQRCODEPAY":
-//                            eduOrder.setPaymentType(3);
-//                            break;
-//                        case "BESTPAY":
-//                            eduOrder.setPaymentType(4);
-//                            break;
-//                        case "DCPAY":
-//                            eduOrder.setPaymentType(5);
-//                            break;
-//                    }
-//                    eduOrder.setPayStatus(1);
-//                    eduOrderMapper.updateById(eduOrder);
-//                }
-//            } catch (Exception e) {
-//                log.print("订单:" + notifyVO.getAcc_trade_no() + "查询失败");
-//            }
-//        }
-
-    }
-
-//    @Override
-//    @Transactional(rollbackFor = Exception.class)
-//    public String transPreorderALi(String orderId) {
-//        EduOrder eduOrder = eduOrderMapper.selectOne(Wrappers.<EduOrder>lambdaQuery().eq(EduOrder::getId, orderId).ne(EduOrder::getPayStatus, 5));
-//        eduOrder.setPayStatus(2);
-//        eduOrderMapper.updateById(eduOrder);
-//        String orderNumber = generateAnOrderNumber();
-//        eduOrderNumberMapper.insert(new EduOrderNumber().setOrderNumber(orderNumber).setOrderId(orderId).setPayType(1));
-//        String transPreorderALi = null;
-//        if(Optional.ofNullable(eduOrder).isPresent() && eduOrder.getPayStatus() != 1){
-//            try {
-//                // 初始化主扫交易接口请求报文
-//                PreorderRequest request = new PreorderRequest(orderNumber, "ALIPAY",
-//                        "41", getMoney(eduOrder.getPayment()), new ReqLocationInfo(InetAddress.getLocalHost().getHostAddress()));
-//                // 订单标题,用于简单描述订单或商品主题,会传递给账户端 (账户端控制,实际最多42个字符),微信支付必送。
-//                request.setSubject(eduOrder.getTitle() + "-" + eduStudentMapper.selectById(eduOrder.getUserId()).getName());
-//                // 商户通知地址
-//                request.setNotify_url(LakalaPayConfig.NOTIFY_URL);
-//                String res = V3LabsApi.transPreorder(request);
-//                PayDataVO payDataVO = new Gson().fromJson(res, PayDataVO.class);
-//                if(payDataVO.getCode().equals("BBS00000") && payDataVO.getMsg().equals("成功")){
-//                    Map<String, Object> respData = (Map<String, Object>) payDataVO.getResp_data();
-//                    Map<String, Object> acc_resp_fields = (Map<String, Object>) respData.get("acc_resp_fields");
-//                    if(Optional.ofNullable(acc_resp_fields.get("code")).isPresent()){
-//                        transPreorderALi = (String) acc_resp_fields.get("code");
-//                        eduOrder.setPayStatus(2);
-//                    }
-//                }
-//            }catch (Exception e){
-//                throw new JeecgBootException("支付失败");
-//            }
-//            updateChildOrder(eduOrder.getId());
-//            eduOrder.setPaymentTime(new Date())
-//                    .setOrderId(orderNumber).setPaymentType(2);
-//            if(eduOrderMapper.updateById(eduOrder) == 0) throw new JeecgBootException("支付失败");
-//        }else if(eduOrder.getPayStatus() == 1){
-//            throw new JeecgBootException("已支付");
-//        }
-//        return transPreorderALi;
-//    }
-//
-//@Override
-//public Map<String, Object> transPreorderWx(String orderId,String openid) {
-//    if(!Optional.ofNullable(openid).isPresent()) throw new JeecgBootException("支付失败! 请重新尝试!");
-//    EduOrder eduOrder = eduOrderMapper.selectOne(Wrappers.<EduOrder>lambdaQuery().eq(EduOrder::getId, orderId).ne(EduOrder::getPayStatus, 5));
-//    eduOrder.setPayStatus(2);
-//    eduOrderMapper.updateById(eduOrder);
-//    String orderNumber = generateAnOrderNumber();
-//    eduOrderNumberMapper.insert(new EduOrderNumber().setOrderNumber(orderNumber).setOrderId(orderId).setPayType(1));
-//    Map<String, Object> acc_resp_fields = null;
-//    if(Optional.ofNullable(eduOrder).isPresent() && eduOrder.getPayStatus() != 1){
-//        try {
-//            // 初始化主扫交易接口请求报文
-//            PreorderRequest request = new PreorderRequest(orderNumber, "WECHAT",
-//                    "51", getMoney(eduOrder.getPayment()), new ReqLocationInfo(InetAddress.getLocalHost().getHostAddress()));
-//            // 订单标题,用于简单描述订单或商品主题,会传递给账户端 (账户端控制,实际最多42个字符),微信支付必送。
-//            request.setSubject(eduOrder.getTitle() + "-" + eduStudentMapper.selectById(eduOrder.getUserId()).getName());
-//            // 商户通知地址
-//            request.setNotify_url(LakalaPayConfig.NOTIFY_URL);
-//            // 账户端业务信息域
-//            WxPayAccBusiFieldsRequest accBusiFieldsRequest = new WxPayAccBusiFieldsRequest();
-//            // 子商户公众账号ID
-//            accBusiFieldsRequest.setSub_appid("wxe3e575a4a2142f5b");
-////            accBusiFieldsRequest.setSub_appid("678959622");
-//            // 用户标识
-//            accBusiFieldsRequest.setUser_id(openid);
-//            // 商品价格 单位元
-//            Integer price = new BigDecimal(getMoney(eduOrder.getPayment())).divide(new BigDecimal(100)).intValue();
-////            accBusiFieldsRequest.setDetail(new WxPayDetailRequest(new WxPayGoodsDatailRequest(orderNumber, eduOrder.getTitle(), 1, price)));
-//            request.setAcc_busi_fields(accBusiFieldsRequest);
-//            String res = V3LabsApi.transPreorder(request);
-//            System.out.println(res);
-//            PayDataVO payDataVO = new Gson().fromJson(res, PayDataVO.class);
-//            if(payDataVO.getCode().equals("BBS00000") && payDataVO.getMsg().equals("成功")){
-//                Map<String, Object> respData = (Map<String, Object>) payDataVO.getResp_data();
-//                acc_resp_fields = (Map<String, Object>) respData.get("acc_resp_fields");
-//                if(Optional.ofNullable(acc_resp_fields).isPresent() && Optional.ofNullable(acc_resp_fields.get("prepay_id")).isPresent()){
-//                    eduOrder.setPayStatus(2);
-//                }
-//            }
-//        }catch (Exception e){
-//            throw new JeecgBootException("支付失败");
-//        }
-//        updateChildOrder(eduOrder.getId());
-//        eduOrder.setPaymentTime(new Date()).setOrderId(orderNumber).setPaymentType(1);
-//        if(eduOrderMapper.updateById(eduOrder) == 0) throw new JeecgBootException("支付失败");
-//    }else if(eduOrder.getPayStatus() == 1){
-//        throw new JeecgBootException("已支付");
-//    }else {
-//        throw new JeecgBootException("支付失败");
-//    }
-//    return acc_resp_fields;
-//}
-//
-//@Override
-//    @Transactional(rollbackFor = Exception.class)
-//    public boolean transMicropay(TransMicropayDTO transMicropayDTO) {
-//        PayDataVO payDataVO = null;
-//        EduOrder eduOrder = eduOrderMapper.selectOne(Wrappers.<EduOrder>lambdaQuery().eq(EduOrder::getId, transMicropayDTO.getOrederId()).ne(EduOrder::getPayStatus, 5));
-//        eduOrder.setPayStatus(2);
-//        eduOrderMapper.updateById(eduOrder);
-//        String orderNumber = generateAnOrderNumber();
-//      eduOrderNumberMapper.insert(new EduOrderNumber().setOrderNumber(orderNumber).setOrderId(eduOrder.getId()).setPayType(1));
-//        if(Optional.ofNullable(eduOrder).isPresent() && eduOrder.getPayStatus() != 1){
-//            eduOrder.setPaymentType(getPayType(transMicropayDTO.getAuthCode()));
-//            try {
-//                // 初始化被扫交易接口请求报文
-//                MicropayRequest request = new MicropayRequest(orderNumber, transMicropayDTO.getAuthCode(),
-//                        getMoney(eduOrder.getPayment()),new ReqLocationInfo(InetAddress.getLocalHost().getHostAddress()));
-//                // 订单标题,用于简单描述订单或商品主题,会传递给账户端 (账户端控制,实际最多42个字符),微信支付必送。
-//                request.setSubject(eduOrder.getTitle() + "-" + eduStudentMapper.selectById(eduOrder.getUserId()).getName());
-//                // 商户通知地址
-//                request.setNotify_url(LakalaPayConfig.NOTIFY_URL);
-//                // 账户端业务信息域
-//                AliPayAccBusiFieldsRequest accBusiFieldsRequest = new AliPayAccBusiFieldsRequest();
-//                accBusiFieldsRequest.setGoods_detail(new AliPayGoodsDetailRequest(orderNumber, eduOrder.getTitle(),
-//                        1, eduOrder.getPayment().doubleValue()));
-//                request.setAcc_busi_fields(accBusiFieldsRequest);
-//                String res = V3LabsApi.transMicropay(request);
-//                payDataVO = new Gson().fromJson(res, PayDataVO.class);
-//                if(payDataVO.getCode().equals("BBS10000")){
-//                    Map<String, Object> respData = (Map<String, Object>) payDataVO.getResp_data();
-////                微信:WECHAT 支付宝:ALIPAY 银联:UQRCODEPAY 翼支付: BESTPAY 数字货币:DCPAY
-//                    switch (respData.get("account_type").toString()){
-//                        case "WECHAT":
-//                            eduOrder.setPaymentType(1);
-//                            break;
-//                        case "ALIPAY":
-//                            eduOrder.setPaymentType(2);
-//                            break;
-//                        case "UQRCODEPAY":
-//                            eduOrder.setPaymentType(3);
-//                            break;
-//                        case "BESTPAY":
-//                            eduOrder.setPaymentType(4);
-//                            break;
-//                        case "DCPAY":
-//                            eduOrder.setPaymentType(5);
-//                            break;
-//                    }
-//                    if(Objects.equals(respData.get("need_query").toString(), "1")){
-//                        eduOrder.setPayStatus(2);
-//                    }else {
-//                        eduOrder.setPayStatus(1);
-//                    }
-//                }
-//            }catch (Exception e){
-//                throw new JeecgBootException(payDataVO.getMsg());
-//            }
-//            updateChildOrder(eduOrder.getId());
-//            eduOrder.setPaymentTime(new Date()).setOrderId(orderNumber);
-//            if(eduOrderMapper.updateById(eduOrder) == 0) throw new JeecgBootException("支付失败");
-//        }else if(eduOrder.getPayStatus() == 1){
-//            throw new JeecgBootException("已支付");
-//        }
-//        return true;
-//    }
-//
-//    @Override
-//    @Transactional(rollbackFor = Exception.class)
-//    public boolean relationRefund(String orderId) {
-//        try {
-//            EduOrder eduOrder = eduOrderMapper.selectOne(Wrappers.<EduOrder>lambdaQuery().eq(EduOrder::getId, orderId).eq(EduOrder::getPayStatus, 1));
-//            if(!Optional.ofNullable(eduOrder).isPresent()) throw new JeecgBootException("账单未支付!");
-//            String orderNumber = generateAnOrderNumber();
-//            eduOrderNumberMapper.insert(new EduOrderNumber().setOrderNumber(orderNumber).setOrderId(eduOrder.getId()).setPayType(1).setPayType(2));
-//            updateChildOrder(eduOrder.getId());
-//            ReqLocationInfo location_info = new ReqLocationInfo(InetAddress.getLocalHost().getHostAddress());
-//            RefundRequest request = new RefundRequest(orderNumber, getMoney(eduOrder.getPayment()), location_info);
-//            request.setOrigin_out_trade_no(eduOrder.getOrderId());
-//            request.setOut_trade_no(orderNumber);
-//            String res = V3LabsApi.relationRefund(request);
-//            PayDataVO payDataVO = new Gson().fromJson(res, PayDataVO.class);
-//            if(payDataVO.getMsg().equals("成功")){
-//                eduOrder.setPayStatus(5).setOrderId(orderNumber);
-//                eduOrderMapper.updateById(eduOrder);
-//                return true;
-//            }else {
-//                throw new JeecgBootException("退款失败");
-//            }
-//        }catch (Exception e){
-//            throw new JeecgBootException("退款失败");
-//        }
-//    }
-//
-//    @Override
-//    public String queryTradeQuery(String orderId, String orderNumber) {
-//        String res = null;
-//        EduOrder eduOrder = null;
-//            // 初始化查询交易接口请求报文
-//            TradeQueryRequest request = new TradeQueryRequest();
-//            eduOrder = eduOrderMapper.selectById(orderId);
-//        if(null != orderNumber){
-//            request.setOut_trade_no(orderNumber);
-//        }else {
-//            request.setOut_trade_no(eduOrder.getOrderId());
-//        }
-//        res = V3LabsApi.queryTradeQuery(request);
-//        PayDataVO payDataVO = new Gson().fromJson(res, PayDataVO.class);
-//        Map<String, Object> respData = (Map<String, Object>) payDataVO.getResp_data();
-//        if(!Optional.ofNullable(respData).isPresent()) return "订单: " + orderId + " 未成功支付";
-//        if (respData.get("trade_state").equals("SUCCESS") && respData.get("total_amount").equals(getMoney(eduOrder.getPayment()))){
-//            switch (respData.get("account_type").toString()){
-//                case "WECHAT":
-//                    eduOrder.setPaymentType(1);
-//                    break;
-//                case "ALIPAY":
-//                    eduOrder.setPaymentType(2);
-//                    break;
-//                case "UQRCODEPAY":
-//                    eduOrder.setPaymentType(3);
-//                    break;
-//                case "BESTPAY":
-//                    eduOrder.setPaymentType(4);
-//                    break;
-//                case "DCPAY":
-//                    eduOrder.setPaymentType(5);
-//                    break;
-//            }
-//            eduOrder.setPayStatus(1).setCallbackFlag(1);
-//            if(null != orderNumber) eduOrder.setOrderId(orderNumber);
-//            eduOrderMapper.updateById(eduOrder);
-//            System.out.println(respData.get("trade_state_desc") + "  订单:  " + eduOrder.getId());
-//            return "SUCCESS";
-//        }else {
-//            return (String) respData.get("trade_state_desc");
-//        }
-//
-//    }
-//
-//    String generateAnOrderNumber(){
-//        int randomFourDigit = (int) (Math.random() * 9000) + 1000;
-//        return "8" + randomFourDigit + System.currentTimeMillis();
-//    }
-//
-//    int getPayType(String authCode){
-//        int payType = 0;
-//        if (Optional.ofNullable(authCode).isPresent() && authCode.length() > 2) {
-//            String substring = authCode.substring(0, 2);
-//            switch (substring) {
-//                case "10":
-//                case "11":
-//                case "12":
-//                case "13":
-//                case "14":
-//                case "15":
-//                    payType = 1;
-//                    break;
-//                case "25":
-//                case "26":
-//                case "27":
-//                case "28":
-//                case "29":
-//                case "30":
-//                    payType = 2;
-//                    break;
-//                case "62":
-//                    payType = 3;
-//                    break;
-//                case "01":
-//                    payType = 4;
-//                    break;
-//                case "51":
-//                    payType = 5;
-//                    break;
-//            }
-//        } else {
-//            payType = -1;
-//        }
-//        return payType;
-//    }
-//
-//    void updateChildOrder(String orderId){
-//        List<EduOrderChild> eduOrderChildren = eduOrderChildMapper.selectList(Wrappers.<EduOrderChild>lambdaQuery().eq(EduOrderChild::getOrderId, orderId));
-//        eduOrderChildren.forEach(a->{
-//            a.setSerialNumber(orderId);
-//        });
-//    }
-//
-//    String getMoney(BigDecimal payment){
-//        return String.valueOf(payment.multiply(new BigDecimal("100")).intValue());
-//    }
-//
-//    public WeiXinUserInfoVO getAccessToken(String code) {
-//        String url = StrFormatter.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={}&secret={}&code={}&grant_type=authorization_code", "wxe3e575a4a2142f5b", "0db278065bc326c8c808048126994c5e", code);
-//        //请求返回的内容,一个json对象
-//        String body = HttpUtil.get(url);
-//        System.out.println(body);
-//        if(!Optional.ofNullable(body).isPresent()) throw new JeecgBootException("请求异常请联系管理员!");
-//        //将接收的json对象转换为对象
-//        AccessTokenInfoVO accessTokenInfo = JSONUtil.toBean(body, AccessTokenInfoVO.class);
-//        System.out.println(accessTokenInfo.toString());
-//        //获取用户信息
-//        url = StrFormatter.format("https://api.weixin.qq.com/sns/userinfo?access_token={}&openid={}&lang=zh_CN",accessTokenInfo.getAccess_token(),accessTokenInfo.getOpenid());
-//        //请求返回的内容,一个json对象
-//        body = HttpUtil.get(url);
-//        WeiXinUserInfoVO weiXinUserInfo = JSONUtil.toBean(body, WeiXinUserInfoVO.class);
-//        System.out.println(weiXinUserInfo.toString());
-//        return weiXinUserInfo;
-//    }
-//
-//    public boolean prePaymentInquiry(String orderId){
-//        String res = null;
-//        try {
-//            // 初始化查询交易接口请求报文
-//            TradeQueryRequest request = new TradeQueryRequest();
-//            EduOrder eduOrder = eduOrderMapper.selectOne(Wrappers.<EduOrder>lambdaQuery().eq(EduOrder::getId, orderId));
-//            // 商户交易流水号
-//            request.setOut_trade_no(eduOrder.getOrderId());
-//            res = V3LabsApi.queryTradeQuery(request);
-//        } catch (Exception e) {
-//            return false;
-//        }
-//        PayDataVO payDataVO = new Gson().fromJson(res, PayDataVO.class);
-//        Map<String, Object> respData = (Map<String, Object>) payDataVO.getResp_data();
-//        if(!Optional.ofNullable(respData).isPresent()) return false;
-//        if (respData.get("trade_state").equals("SUCCESS")){
-//            return true;
-//        }
-//        return false;
-//    }
-}

+ 7 - 3
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/vo/NotifyVO.java → national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/vo/NotifyRequest.java

@@ -4,6 +4,8 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.experimental.Accessors;
 
+import java.io.Serializable;
+
 /**
  * <p>
  * 回调函数
@@ -14,8 +16,11 @@ import lombok.experimental.Accessors;
  */
 @Data
 @Accessors(chain = true)
-@Schema(description = "")
-public class NotifyVO {
+@Schema(description = "支付回调接收对象")
+public class NotifyRequest implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
     //	商户号
     public String merchant_no;
     //商户交易流水号
@@ -60,5 +65,4 @@ public class NotifyVO {
     public String card_type;
     //	备注
     public String remark;
-
 }

+ 24 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/pay/vo/NotifyResponse.java

@@ -0,0 +1,24 @@
+package org.jeecg.modules.pay.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+@Data
+@Accessors(chain = true)
+@Schema(description = "支付回调响应对象")
+public class NotifyResponse implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * {
+     *     "code": "SUCCESS",
+     *     "message": "执行成功"
+     * }
+     */
+    private String code;
+
+    private String message;
+}

+ 2 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/quartz/job/OrTeachingJobService.java

@@ -20,6 +20,7 @@ import org.jeecg.modules.system.app.service.IAppSitePlaceService;
 import org.jeecg.modules.system.app.service.IAppSitePriceRulesService;
 import org.jeecg.modules.system.app.service.IAppSiteService;
 import org.jeecg.modules.system.app.service.IAppTeachingTimeService;
+import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -48,7 +49,7 @@ public class OrTeachingJobService {
 
     private final IAppSiteService appSiteService;
 
-    //@Scheduled(cron = "0 00 15 ? * *")
+    @Scheduled(cron = "0 0 0 1 12 *")
     @Transactional(rollbackFor = Exception.class)
     public void execute() throws ParseException {
         log.info("开始执行定时任务");

+ 97 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/redission/RedissonDelayQueue.java

@@ -0,0 +1,97 @@
+package org.jeecg.modules.redission;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.modules.system.app.entity.AppOrder;
+import org.jeecg.modules.system.app.service.IAppOrderService;
+import org.redisson.Redisson;
+import org.redisson.api.RBlockingQueue;
+import org.redisson.api.RDelayedQueue;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.Config;
+import org.redisson.config.SingleServerConfig;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * @author wangzhiqiang
+ * @Date 2025/8/15
+ * @Desc 延迟队列实现订单超时取消
+ */
+@Component
+@Slf4j
+public class RedissonDelayQueue {
+
+    private RedissonClient redissonClient;
+
+    @Resource
+    private IAppOrderService appOrderService;
+
+    private RDelayedQueue<String> delayQueue;
+    private RBlockingQueue<String> blockingQueue;
+
+    @Value("${spring.redis.host}")
+    private String host;
+
+    @Value("${spring.redis.password}")
+    private String password;
+
+    @PostConstruct
+    public void init() {
+        initDelayQueue();
+        startDelayQueueConsumer();
+    }
+
+    private void initDelayQueue() {
+        Config config = new Config();
+
+        SingleServerConfig serverConfig = config.useSingleServer();
+        serverConfig.setAddress("redis://" + host +":6379");
+        if (StrUtil.isNotEmpty(password)){
+            serverConfig.setPassword(password);
+        }
+        //设置连接redis的心跳间隔(10s/次)
+        serverConfig.setPingConnectionInterval(10000);
+        redissonClient = Redisson.create(config);
+
+        blockingQueue = redissonClient.getBlockingQueue("OrderTimeOutTask");
+        delayQueue = redissonClient.getDelayedQueue(blockingQueue);
+    }
+
+    private void startDelayQueueConsumer() {
+        new Thread(() -> {
+            while (true) {
+                try {
+                    String task = blockingQueue.take();
+                    log.info("接收到延迟任务:{}", task);
+
+                    //执行业务代码
+                    String orderId = Arrays.stream(task.split("_")).collect(Collectors.toList()).get(1);
+                    AppOrder appOrder = appOrderService.getById(orderId);
+                    if(ObjectUtil.isNotEmpty(appOrder)){
+                        if (appOrder.getOrderStatus() == 0){
+                            log.info("修改订单:{},支付状态为已取消", orderId);
+                            appOrder.setOrderStatus(4);
+                            appOrderService.updateById(appOrder);
+                        }
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }, "OrderTimeOutTask-Consumer").start();
+    }
+
+    public void offerTask(String task, long seconds) {
+        log.info("添加延迟任务:{} 延迟时间:{}s", task, seconds);
+        delayQueue.offer(task, seconds, TimeUnit.SECONDS);
+    }
+
+}

+ 6 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppCoursesVerificationRecord.java

@@ -98,6 +98,12 @@ public class AppCoursesVerificationRecord implements Serializable {
     @Excel(name = "使用人名称", width = 15)
     @Schema(description = "使用人名称")
     private String useUserName;
+    /**
+     * 使用人手机号
+     */
+    @Excel(name = "使用人手机号", width = 15)
+    @Schema(description = "使用人手机号")
+    private String useUserPhone;
     /**
      * 使用人人脸照片
      */

+ 8 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/entity/AppOrder.java

@@ -101,8 +101,16 @@ public class AppOrder implements Serializable {
 	@Excel(name = "订单状态", width = 15)
     @Schema(description = "订单状态 0-待付款 1-待使用 2-已使用 3-已到期 4-已取消")
     private Integer orderStatus;
+
     @Schema(description = "售后状态 0-暂无售后 1-退款中 2-已退款")
     private Integer afterSaleStatus;
+
+    @Schema(description = "支付状态 0-待支付 1-支付成功 2-退款中 3-已退款")
+    private Integer payStatus;
+
+    @Schema(description = "回调状态 0-未回调 1-已回调")
+    private Integer callbackStatus;
+
 	/**参赛资质*/
 	@Excel(name = "参赛资质", width = 15)
     @Schema(description = "参赛资质")

+ 27 - 0
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/form/VerifyForm.java

@@ -0,0 +1,27 @@
+package org.jeecg.modules.system.app.form;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@AllArgsConstructor
+@NoArgsConstructor
+@Schema(description = "拍照验课上传图片表单对象")
+public class VerifyForm implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @Schema(description = "课时ID")
+    private String coursePriceRulesId;
+
+    @Schema(description = "用户列表")
+    private List<CoursesVerificationRecordForm>  formList;
+}

+ 2 - 2
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/mapper/xml/AppIsinMapper.xml

@@ -6,7 +6,7 @@
         SELECT
             i.id,
             i.use_time,
-            i.ticket_no
+            i.ticket_no,
             i.remark,
             opi.product_image,
             opi.product_name,
@@ -20,7 +20,7 @@
         <where>
             i.isin_status = 1
             <if test="orgCode != null and orgCode != ''">
-                i.org_code = #{orgCode}
+               and i.org_code = #{orgCode}
             </if>
         </where>
         ORDER BY

+ 2 - 1
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/IAppCoureseService.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.jeecg.modules.app.form.ClassPostponeForm;
+import org.jeecg.modules.app.form.TemporaryCourseForm;
 import org.jeecg.modules.app.vo.AppCoursesPageVO;
 import org.jeecg.modules.app.vo.CoursesPriceRulesVO;
 import org.jeecg.modules.app.vo.FamilyUserVO;
@@ -53,7 +54,7 @@ public interface IAppCoureseService extends IService<AppCourses> {
 
     List<CoursesPriceRulesVO> getCourseInfo(String courseId);
 
-    Boolean temporaryCourse(String coursePriceRulesId, String userId);
+    Boolean temporaryCourse(TemporaryCourseForm temporaryCourseForm);
 
     List<FamilyUserVO> getClassPostponeUsers(String coursePriceRulesId);
 

+ 2 - 4
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/IAppCoursesVerificationRecordService.java

@@ -3,9 +3,7 @@ package org.jeecg.modules.system.app.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.jeecg.modules.system.app.entity.AppCoursesVerificationRecord;
-import org.jeecg.modules.system.app.form.CoursesVerificationRecordForm;
-
-import java.util.List;
+import org.jeecg.modules.system.app.form.VerifyForm;
 
 /**
  * @Description: nm_courses_verification_record
@@ -15,5 +13,5 @@ import java.util.List;
  */
 public interface IAppCoursesVerificationRecordService extends IService<AppCoursesVerificationRecord> {
 
-    Boolean courseUploadImage(List<CoursesVerificationRecordForm> formList);
+    Boolean courseUploadImage(VerifyForm verifyForm);
 }

+ 44 - 33
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/impl/AppCoureseServiceImpl.java

@@ -11,7 +11,10 @@ import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.modules.app.form.ClassPostponeForm;
-import org.jeecg.modules.app.vo.*;
+import org.jeecg.modules.app.form.TemporaryCourseForm;
+import org.jeecg.modules.app.vo.AppCoursesPageVO;
+import org.jeecg.modules.app.vo.CoursesPriceRulesVO;
+import org.jeecg.modules.app.vo.FamilyUserVO;
 import org.jeecg.modules.system.app.dto.*;
 import org.jeecg.modules.system.app.entity.*;
 import org.jeecg.modules.system.app.mapper.*;
@@ -280,16 +283,21 @@ public class AppCoureseServiceImpl extends ServiceImpl<AppCoursesMapper, AppCour
 
             List<AppCoursesVerificationRecord> verificationRecordList = appCoursesVerificationRecordMapper
                     .selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery().eq(AppCoursesVerificationRecord::getCoursesPriceRuleId, priceRules.getId()));
+            ArrayList<AppCoursesVerificationRecord> verificationRecords = verificationRecordList.stream()
+                    .collect(Collectors.collectingAndThen(
+                            Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(AppCoursesVerificationRecord::getUseUserId))),
+                            ArrayList::new
+                    ));
             //共计
-            coursesPriceRulesVO.setTotalNum(verificationRecordList.size());
+            coursesPriceRulesVO.setTotalNum(verificationRecords.size());
             //延期
-            long postponeNum = verificationRecordList.stream().filter(e -> e.getOrPostpone() == 1).count();
+            long postponeNum = verificationRecords.stream().filter(e -> e.getOrPostpone() == 1).count();
             coursesPriceRulesVO.setPostponeNum((int) postponeNum);
             //已核验
-            long writtenOffNum = verificationRecordList.stream().filter(e -> e.getVerifyStatus() == 1).count();
+            long writtenOffNum = verificationRecords.stream().filter(e -> e.getVerifyStatus() == 1).count();
             coursesPriceRulesVO.setWrittenOffNum((int) writtenOffNum);
             //未核验
-            long unwrittenOffNum = verificationRecordList.stream().filter(e -> e.getVerifyStatus() == 0 && e.getOrPostpone() == 0).count();
+            long unwrittenOffNum = verificationRecords.stream().filter(e -> e.getVerifyStatus() == 0 && e.getOrPostpone() == 0).count();
             coursesPriceRulesVO.setUnwrittenOffNum((int) unwrittenOffNum);
 
             //判断是否为当日数据
@@ -321,40 +329,43 @@ public class AppCoureseServiceImpl extends ServiceImpl<AppCoursesMapper, AppCour
      * @return
      */
     @Override
-    public Boolean temporaryCourse(String coursePriceRulesId, String familyMemberId) {
+    public Boolean temporaryCourse(TemporaryCourseForm temporaryCourseForm) {
 
-        AppCoursesPriceRules appCoursesPriceRules = priceRulesMapper.selectById(coursePriceRulesId);
+        AppCoursesPriceRules appCoursesPriceRules = priceRulesMapper.selectById(temporaryCourseForm.getCoursePriceRulesId());
 
-        FamilyMembers familyMembers = familyMembersMapper.selectById(familyMemberId);
+        for (String userId : temporaryCourseForm.getUserIds()) {
+            FamilyMembers familyMembers = familyMembersMapper.selectById(userId);
 
-        if (ObjUtil.isEmpty(familyMembers)) {
-            throw new JeecgBootException("当前用户不存在,请确认后重新提交");
-        }
+            if (ObjUtil.isEmpty(familyMembers)) {
+                throw new JeecgBootException("当前用户不存在,请确认后重新提交");
+            }
+
+            //判断是否已存在
+            List<AppCoursesVerificationRecord> verificationRecords =
+                    appCoursesVerificationRecordMapper.selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery()
+                            .eq(AppCoursesVerificationRecord::getCoursesPriceRuleId, appCoursesPriceRules.getId())
+                            .eq(AppCoursesVerificationRecord::getUseUserId,userId)
+                    );
+            if (ObjUtil.isNotEmpty(verificationRecords)) {
+                throw new JeecgBootException(familyMembers.getFullName()+"已经在课程中,请确认后重新提交");
+            }
 
-        //判断是否已存在
-        List<AppCoursesVerificationRecord> verificationRecords =
-                appCoursesVerificationRecordMapper.selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery()
-                        .eq(AppCoursesVerificationRecord::getCoursesPriceRuleId, coursePriceRulesId)
-                        .eq(AppCoursesVerificationRecord::getUseUserId,familyMemberId)
-                );
-        if (ObjUtil.isNotEmpty(verificationRecords)) {
-            throw new JeecgBootException(familyMembers.getFullName()+"已经在课程中,请确认后重新提交");
+            AppCoursesVerificationRecord appCoursesVerificationRecord = new AppCoursesVerificationRecord();
+            appCoursesVerificationRecord.setCoursesId(appCoursesPriceRules.getCoursesId());
+            appCoursesVerificationRecord.setCoursesPriceRuleId(appCoursesPriceRules.getId());
+            appCoursesVerificationRecord.setCoursesName(appCoursesPriceRules.getName());
+            appCoursesVerificationRecord.setCoursesStartTime(appCoursesPriceRules.getStartTime());
+            appCoursesVerificationRecord.setCoursesEndTime(appCoursesPriceRules.getEndTime());
+            appCoursesVerificationRecord.setUseUserId(userId);
+            appCoursesVerificationRecord.setUseUserName(familyMembers.getFullName());
+            appCoursesVerificationRecord.setVerifyStatus(0);
+            appCoursesVerificationRecord.setOrPostpone(0);
+            appCoursesVerificationRecord.setCoursesType(0);
+
+            int insert = appCoursesVerificationRecordMapper.insert(appCoursesVerificationRecord);
+            if (insert < 1) throw new JeecgBootException("临时约课创建失败", SC_INTERNAL_SERVER_ERROR_500);
         }
 
-        AppCoursesVerificationRecord appCoursesVerificationRecord = new AppCoursesVerificationRecord();
-        appCoursesVerificationRecord.setCoursesId(appCoursesPriceRules.getCoursesId());
-        appCoursesVerificationRecord.setCoursesPriceRuleId(appCoursesPriceRules.getId());
-        appCoursesVerificationRecord.setCoursesName(appCoursesPriceRules.getName());
-        appCoursesVerificationRecord.setCoursesStartTime(appCoursesPriceRules.getStartTime());
-        appCoursesVerificationRecord.setCoursesEndTime(appCoursesPriceRules.getEndTime());
-        appCoursesVerificationRecord.setUseUserId(familyMemberId);
-        appCoursesVerificationRecord.setUseUserName(familyMembers.getFullName());
-        appCoursesVerificationRecord.setVerifyStatus(0);
-        appCoursesVerificationRecord.setOrPostpone(0);
-        appCoursesVerificationRecord.setCoursesType(0);
-
-        int insert = appCoursesVerificationRecordMapper.insert(appCoursesVerificationRecord);
-        if (insert < 1) throw new JeecgBootException("临时约课创建失败", SC_INTERNAL_SERVER_ERROR_500);
         return Boolean.TRUE;
     }
 

+ 28 - 10
national-motion-module-system/national-motion-system-biz/src/main/java/org/jeecg/modules/system/app/service/impl/AppCoursesVerificationRecordServiceImpl.java

@@ -1,17 +1,23 @@
 package org.jeecg.modules.system.app.service.impl;
 
 
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import org.apache.commons.lang3.ObjectUtils;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.constant.CommonConstant;
+import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.modules.system.app.entity.AppCoursesVerificationRecord;
+import org.jeecg.modules.system.app.entity.FamilyMembers;
 import org.jeecg.modules.system.app.form.CoursesVerificationRecordForm;
+import org.jeecg.modules.system.app.form.VerifyForm;
 import org.jeecg.modules.system.app.mapper.AppCoursesVerificationRecordMapper;
+import org.jeecg.modules.system.app.mapper.FamilyMembersMapper;
 import org.jeecg.modules.system.app.service.IAppCoursesVerificationRecordService;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
 import java.util.List;
 
 /**
@@ -23,21 +29,33 @@ import java.util.List;
 @Service
 public class AppCoursesVerificationRecordServiceImpl extends ServiceImpl<AppCoursesVerificationRecordMapper, AppCoursesVerificationRecord> implements IAppCoursesVerificationRecordService {
 
+    @Resource
+    FamilyMembersMapper  familyMembersMapper;
+
     @Override
-    public Boolean courseUploadImage(List<CoursesVerificationRecordForm> formList) {
+    public Boolean courseUploadImage(VerifyForm verifyForm) {
 
         //获取登录用户信息
         LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
 
-        for (CoursesVerificationRecordForm coursesVerificationRecordForm : formList) {
-            AppCoursesVerificationRecord appCoursesVerificationRecord = baseMapper.selectById(coursesVerificationRecordForm.getId());
-            if (ObjectUtils.isEmpty(appCoursesVerificationRecord)) {
-                appCoursesVerificationRecord.setVerifyStatus(CommonConstant.STATUS_1_INT);
-                appCoursesVerificationRecord.setVerifyUserId(sysUser.getId());
-                appCoursesVerificationRecord.setVerifyUserName(sysUser.getRealname());
-                appCoursesVerificationRecord.setVerifyImage(coursesVerificationRecordForm.getVerifyImage());
-                baseMapper.updateById(appCoursesVerificationRecord);
+        for (CoursesVerificationRecordForm coursesVerificationRecordForm : verifyForm.getFormList()) {
+            List<AppCoursesVerificationRecord> verificationRecordList = baseMapper.selectList(Wrappers.<AppCoursesVerificationRecord>lambdaQuery()
+                    .eq(AppCoursesVerificationRecord::getCoursesPriceRuleId, verifyForm.getCoursePriceRulesId())
+                    .eq(AppCoursesVerificationRecord::getUseUserId, coursesVerificationRecordForm.getId())
+                    .eq(AppCoursesVerificationRecord::getVerifyStatus, CommonConstant.STATUS_NORMAL)
+            );
+
+            if(CollUtil.isEmpty(verificationRecordList)){
+                FamilyMembers familyMembers = familyMembersMapper.selectById(coursesVerificationRecordForm.getId());
+                throw new JeecgBootException("当前用户"+familyMembers.getFullName()+"没有应验课程");
             }
+            verificationRecordList.forEach(verificationRecord -> {
+                verificationRecord.setVerifyStatus(CommonConstant.STATUS_1_INT);
+                verificationRecord.setVerifyUserId(sysUser.getId());
+                verificationRecord.setVerifyUserName(sysUser.getRealname());
+                verificationRecord.setVerifyImage(coursesVerificationRecordForm.getVerifyImage());
+                baseMapper.updateById(verificationRecord);
+            });
         }
         return Boolean.TRUE;
     }

+ 7 - 0
pom.xml

@@ -75,6 +75,7 @@
 
 		<httpclient.version>4.5.13</httpclient.version>
 		<gson.version>2.10</gson.version>
+		<redission.version>3.15.6</redission.version>
 	</properties>
 	<modules>
         <module>national-motion-base-core</module>
@@ -222,6 +223,12 @@
 				<version>3.8.0.2</version>
 			</dependency>
 
+			<dependency>
+				<groupId>org.redisson</groupId>
+				<artifactId>redisson</artifactId>
+				<version>3.13.1</version>
+			</dependency>
+
 			<!--mongon db-->
 			<dependency>
 				<groupId>org.jeecgframework.boot</groupId>