Selaa lähdekoodia

appv1.2需求

wangxy 1 viikko sitten
vanhempi
commit
226b698385
18 muutettua tiedostoa jossa 389 lisäystä ja 11 poistoa
  1. 6 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java
  2. 54 0
      fs-admin/src/main/java/com/fs/his/controller/FsExternalOrderController.java
  3. 69 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  4. 26 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseClearLog.java
  5. 2 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  6. 2 1
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  7. 14 0
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseClearLogMapper.java
  8. 2 2
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  9. 2 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCoursePeriodDaysService.java
  10. 109 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodDaysServiceImpl.java
  11. 2 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java
  12. 6 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java
  13. 2 0
      fs-service/src/main/java/com/fs/his/param/FsExternalOrderAddParam.java
  14. 47 5
      fs-service/src/main/java/com/fs/his/service/impl/FsExternalOrderServiceImpl.java
  15. 33 0
      fs-service/src/main/resources/mapper/course/FsUserCourseClearLogMapper.xml
  16. 4 0
      fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml
  17. 2 2
      fs-service/src/main/resources/mapper/his/FsExternalOrderMapper.xml
  18. 7 1
      fs-service/src/main/resources/mapper/his/FsUserMapper.xml

+ 6 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java

@@ -153,6 +153,12 @@ public class FsUserCoursePeriodController extends BaseController {
         return fsUserCoursePeriodDaysService.addCourse(entity);
     }
 
+    @PreAuthorize("@ss.hasPermi('course:period:addCourse')")
+    @PostMapping("/insertCourse")
+    public R insertCourse(@RequestBody FsUserCoursePeriodDays entity){
+        return fsUserCoursePeriodDaysService.insertCourse(entity);
+    }
+
     @PreAuthorize("@ss.hasPermi('course:period:dayRemove')")
     @Log(title = "会员营期课程删除", businessType = BusinessType.DELETE)
     @DeleteMapping("/day/{ids}")

+ 54 - 0
fs-admin/src/main/java/com/fs/his/controller/FsExternalOrderController.java

@@ -0,0 +1,54 @@
+package com.fs.his.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.his.domain.FsExternalOrder;
+import com.fs.his.domain.vo.FsExternalOrderListVO;
+import com.fs.his.service.IFsExternalOrderService;
+import com.fs.his.vo.FsExternalOrderDetailVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/his/externalOrder")
+public class FsExternalOrderController extends BaseController {
+
+    @Autowired
+    private IFsExternalOrderService fsExternalOrderService;
+
+    @GetMapping("/list")
+    @PreAuthorize("@ss.hasPermi('his:externalOrder:list')")
+    public TableDataInfo list(FsExternalOrder fsExternalOrder) {
+        startPage();
+        List<FsExternalOrderListVO> list = fsExternalOrderService.selectExternalOrderListVO(fsExternalOrder);
+        return getDataTable(list);
+    }
+
+    @GetMapping(value = "/{orderId}")
+    @PreAuthorize("@ss.hasPermi('his:externalOrder:query')")
+    public AjaxResult getInfo(@PathVariable("orderId") Long orderId) {
+        FsExternalOrderDetailVO detail = fsExternalOrderService.selectExternalOrderDetailVO(orderId);
+        return AjaxResult.success(detail);
+    }
+
+    @Log(title = "审核外部订单", businessType = BusinessType.UPDATE)
+    @PostMapping("/audit/{orderId}")
+    @PreAuthorize("@ss.hasPermi('his:externalOrder:audit')")
+    public R audit(@PathVariable("orderId") Long orderId) {
+        return fsExternalOrderService.auditExternalOrder(orderId);
+    }
+
+    @Log(title = "取消外部订单", businessType = BusinessType.UPDATE)
+    @PostMapping("/cancel/{orderId}")
+    @PreAuthorize("@ss.hasPermi('his:externalOrder:cancel')")
+    public R cancel(@PathVariable("orderId") Long orderId) {
+        return fsExternalOrderService.cancelExternalOrder(orderId);
+    }
+}

+ 69 - 0
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -18,8 +18,12 @@ import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.QwIpadTotalVo;
 import com.fs.company.vo.RedPacketMoneyVO;
+import com.fs.course.domain.FsUserCourseClearLog;
+import com.fs.course.domain.FsUserCompanyUser;
 import com.fs.course.dto.BatchSendCourseAllDTO;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
+import com.fs.course.mapper.FsUserCompanyUserMapper;
+import com.fs.course.mapper.FsUserCourseClearLogMapper;
 import com.fs.course.service.IFsCourseCheckinActivityService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsUserCourseOrderService;
@@ -165,6 +169,10 @@ public class Task {
     @Autowired
     FsCourseRedPacketLogMapper fsCourseRedPacketLogMapper;
     @Autowired
+    FsUserCompanyUserMapper fsUserCompanyUserMapper;
+    @Autowired
+    FsUserCourseClearLogMapper fsUserCourseClearLogMapper;
+    @Autowired
     QwApiService qwApiService;
     //每天执行一次
     @Autowired
@@ -1971,4 +1979,65 @@ public class Task {
         }
     }
 
+    /**
+     * 清除3个月未登录APP用户的看课关系
+     * APP用户判断条件:login_device、source、app_create_time都不为空
+     */
+    public void clearInactiveAppUserCourseRelation() {
+        log.info("开始清除3个月未登录APP用户的看课关系");
+        try {
+            String threeMonthsAgo = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", 
+                DateUtils.addMonths(new Date(), -3));
+            
+            List<Long> userIds = fsUserMapper.selectInactiveAppUsers(threeMonthsAgo);
+            if (userIds == null || userIds.isEmpty()) {
+                log.info("没有需要清除看课关系的用户");
+                return;
+            }
+            
+            log.info("找到{}个3个月未登录的APP用户", userIds.size());
+            
+            List<FsUserCompanyUser> relations = fsUserCompanyUserMapper.selectList(
+                new LambdaQueryWrapper<FsUserCompanyUser>()
+                    .in(FsUserCompanyUser::getUserId, userIds)
+            );
+            
+            if (relations.isEmpty()) {
+                log.info("没有需要清除的看课关系");
+                return;
+            }
+            
+            log.info("找到{}条看课关系需要清除", relations.size());
+            
+            List<FsUserCourseClearLog> clearLogs = relations.stream()
+                .map(relation -> {
+                    FsUserCourseClearLog log = new FsUserCourseClearLog();
+                    log.setUserId(relation.getUserId());
+                    log.setProjectId(relation.getProjectId());
+                    log.setCompanyId(relation.getCompanyId());
+                    log.setCompanyUserId(relation.getCompanyUserId());
+                    log.setCreateTime(LocalDateTime.now());
+                    return log;
+                })
+                .collect(Collectors.toList());
+            
+            int batchSize = 100;
+            for (int i = 0; i < clearLogs.size(); i += batchSize) {
+                int endIndex = Math.min(i + batchSize, clearLogs.size());
+                List<FsUserCourseClearLog> batch = clearLogs.subList(i, endIndex);
+                fsUserCourseClearLogMapper.batchInsertFsUserCourseClearLog(batch);
+            }
+            
+            List<Long> relationIds = relations.stream()
+                .map(FsUserCompanyUser::getId)
+                .collect(Collectors.toList());
+            
+            fsUserCompanyUserMapper.deleteBatchIds(relationIds);
+            
+            log.info("清除3个月未登录APP用户的看课关系完成,共清除{}条记录", relations.size());
+        } catch (Exception e) {
+            log.error("清除3个月未登录APP用户的看课关系失败: {}", e.getMessage(), e);
+        }
+    }
+
 }

+ 26 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseClearLog.java

@@ -0,0 +1,26 @@
+package com.fs.course.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Data
+@TableName("fs_user_course_clear_log")
+public class FsUserCourseClearLog {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    private Long userId;
+
+    private Long projectId;
+
+    private Long companyId;
+
+    private Long companyUserId;
+
+    private LocalDateTime createTime;
+}

+ 2 - 0
fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java

@@ -109,6 +109,8 @@ public class FsUserCourseVideo extends BaseEntity
 
     private Long productId;//拍商品id
 
+    private Integer isVip;//是否VIP课程 0:否 1:是
+
     private Long listingStartTime;//商品售卖时间
 
     private Long listingEndTime;//商品结束售卖时间

+ 2 - 1
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -621,7 +621,7 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
             "INNER JOIN ( " +
             "    SELECT user_id, video_id, MAX(log_id) AS log_id " +
             "    FROM fs_course_watch_log " +
-            "    WHERE user_id IS NOT NULL " +
+            "    WHERE user_id IS NOT NULL  AND  user_id=4051515674 " +
             "      AND watch_type = 1 " +
             "      AND send_type = 1 " +
             "      AND create_time >= CURDATE() " +
@@ -631,6 +631,7 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
             "WHERE l.log_type <> 2 " +
             "  AND l.watch_type = 1 " +
             "  AND l.send_type = 1 " +
+            "and l.user_id=4051515674" +
             "  AND NOT EXISTS ( " +
             "      SELECT 1 FROM fs_course_watch_log f " +
             "      WHERE f.user_id = l.user_id " +

+ 14 - 0
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseClearLogMapper.java

@@ -0,0 +1,14 @@
+package com.fs.course.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsUserCourseClearLog;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+public interface FsUserCourseClearLogMapper extends BaseMapper<FsUserCourseClearLog> {
+
+    int insertFsUserCourseClearLog(FsUserCourseClearLog log);
+
+    int batchInsertFsUserCourseClearLog(@Param("list") List<FsUserCourseClearLog> list);
+}

+ 2 - 2
fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java

@@ -100,7 +100,7 @@ public interface FsUserCourseVideoMapper
 
     @Select({"<script> " +
             "select v.video_id, v.title, v.video_url,v.package_json, v.thumbnail,v.duration as seconds, SEC_TO_TIME(v.duration) as duration,v.create_time, v.talent_id, v.course_id, " +
-            " v.status, v.course_sort,v.line_one,v.line_two,v.line_three,v.upload_type,1 as is_vip,CASE \n" +
+            " v.status, v.course_sort,v.line_one,v.line_two,v.line_three,v.upload_type, v.is_vip as is_vip,CASE \n" +
             "        WHEN l.log_id IS NOT NULL THEN 1\n" +
             "        ELSE 0\n" +
             "    END AS is_buy  from fs_user_course_video v  " +
@@ -115,7 +115,7 @@ public interface FsUserCourseVideoMapper
 
     @Select({"<script> " +
             "select v.video_id, v.title,v.package_json, v.video_url, v.thumbnail,v.duration as seconds, SEC_TO_TIME(v.duration) as duration,v.create_time, v.talent_id, v.course_id, " +
-            " v.status, v.course_sort,v.line_one,v.line_two,v.line_three,v.upload_type,1 as is_vip,0 as is_buy  from fs_user_course_video v  " +
+            " v.status, v.course_sort,v.line_one,v.line_two,v.line_three,v.upload_type,v.is_vip as is_vip,0 as is_buy  from fs_user_course_video v  " +
             " where v.is_del = 0 and  v.course_id = #{maps.courseId}   " +
             "<if test = ' maps.keyword!=null and maps.keyword != \"\" '> " +
             "and v.title like CONCAT('%',#{maps.keyword},'%') " +

+ 2 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCoursePeriodDaysService.java

@@ -77,6 +77,8 @@ public interface IFsUserCoursePeriodDaysService extends IService<FsUserCoursePer
 
     R addCourse(FsUserCoursePeriodDays entity);
 
+    R insertCourse(FsUserCoursePeriodDays entity);
+
     R updateListCourseData(List<FsUserCoursePeriodDays> entity);
 
     /**

+ 109 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCoursePeriodDaysServiceImpl.java

@@ -229,6 +229,115 @@ public class FsUserCoursePeriodDaysServiceImpl extends ServiceImpl<FsUserCourseP
         return R.ok();
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public R insertCourse(FsUserCoursePeriodDays entity) {
+        if (entity == null || entity.getPeriodId() == null || entity.getCourseId() == null) {
+            return R.error("参数不能为空");
+        }
+        Long videoId = entity.getVideoId();
+        if (videoId == null && CollectionUtils.isNotEmpty(entity.getVideoIds())) {
+            videoId = entity.getVideoIds().get(0);
+        }
+        if (videoId == null) {
+            return R.error("课程章节不能为空");
+        }
+
+        FsUserCoursePeriod period = fsUserCoursePeriodMapper.selectFsUserCoursePeriodById(entity.getPeriodId());
+        if (period == null) {
+            return R.error("营期不存在");
+        }
+
+        LocalDate insertDate = entity.getDayDate();
+        if (insertDate == null && entity.getStartDateTime() != null) {
+            insertDate = entity.getStartDateTime().toLocalDate();
+        }
+        if (insertDate == null) {
+            return R.error("插入课程日期不能为空");
+        }
+        if (!insertDate.isAfter(LocalDate.now())) {
+            return R.error("只能插入未开始的课程");
+        }
+        if (insertDate.isBefore(period.getPeriodStartingTime()) || insertDate.isAfter(period.getPeriodEndTime())) {
+            return R.error("插入课程日期不在营期范围内");
+        }
+
+        LocalDateTime startDateTime = entity.getStartDateTime();
+        if (startDateTime == null && entity.getStartTime() != null) {
+            startDateTime = LocalDateTime.of(insertDate, entity.getStartTime());
+        }
+        LocalDateTime endDateTime = entity.getEndDateTime();
+        if (endDateTime == null && entity.getEndTime1() != null) {
+            endDateTime = LocalDateTime.of(insertDate, entity.getEndTime1());
+        }
+        FsUserCourseVideo video = fsUserCourseVideoService.selectFsUserCourseVideoByVideoId(videoId);
+        if (startDateTime == null && video != null && video.getViewStartTime() != null) {
+            startDateTime = LocalDateTime.of(insertDate, video.getViewStartTime());
+        }
+        if (endDateTime == null && video != null && video.getViewEndTime() != null) {
+            endDateTime = LocalDateTime.of(insertDate, video.getViewEndTime());
+        }
+        if (endDateTime == null) {
+            return R.error("课程结束时间不能为空");
+        }
+        if (endDateTime.toLocalDate().isAfter(period.getPeriodEndTime())) {
+            return R.error("课程结束时间不能大于营期结束时间");
+        }
+        final LocalDate insertDateFinal = insertDate;
+        final Long videoIdFinal = videoId;
+
+        List<FsUserCoursePeriodDays> dayList = list(new QueryWrapper<FsUserCoursePeriodDays>()
+                .eq("period_id", period.getPeriodId())
+                .eq("del_flag", "0")
+                .orderByAsc("day_date"));
+        List<FsUserCoursePeriodDays> shiftList = dayList.stream()
+                .filter(e -> e.getDayDate() != null && !e.getDayDate().isBefore(insertDateFinal))
+                .filter(e -> e.getStartDateTime() != null && e.getEndDateTime() != null)
+                .filter(e -> e.getStartDateTime().toLocalDate().equals(e.getEndDateTime().toLocalDate()))
+                .collect(Collectors.toList());
+        boolean overPeriod = shiftList.stream()
+                .map(FsUserCoursePeriodDays::getEndDateTime)
+                .filter(Objects::nonNull)
+                .anyMatch(e -> e.plusDays(1).toLocalDate().isAfter(period.getPeriodEndTime()));
+        if (overPeriod) {
+            return R.error("顺延后的课程结束时间不能大于营期结束时间");
+        }
+
+        shiftList.forEach(e -> {
+            e.setDayDate(e.getDayDate().plusDays(1));
+            e.setStartDateTime(e.getStartDateTime().plusDays(1));
+            e.setEndDateTime(e.getEndDateTime().plusDays(1));
+            if (e.getLastJoinTime() != null) {
+                e.setLastJoinTime(e.getLastJoinTime().plusDays(1));
+            }
+        });
+        if (CollectionUtils.isNotEmpty(shiftList)) {
+            fsUserCoursePeriodDaysMapper.batchUpdateCoursePeriodDays(shiftList);
+        }
+
+        FsUserCoursePeriodDays insertDay = new FsUserCoursePeriodDays();
+        insertDay.setPeriodId(entity.getPeriodId());
+        insertDay.setCourseId(entity.getCourseId());
+        insertDay.setVideoId(videoIdFinal);
+        insertDay.setDayDate(insertDate);
+        insertDay.setStartDateTime(startDateTime);
+        insertDay.setEndDateTime(endDateTime);
+        if (entity.getLastJoinTime() != null) {
+            insertDay.setLastJoinTime(entity.getLastJoinTime());
+        } else if (entity.getJoinTime() != null) {
+            insertDay.setLastJoinTime(LocalDateTime.of(insertDate, entity.getJoinTime()));
+        } else if (video != null && video.getLastJoinTime() != null) {
+            insertDay.setLastJoinTime(LocalDateTime.of(insertDate, video.getLastJoinTime()));
+        }
+        insertDay.setMoney(entity.getMoney());
+        insertDay.setRegistrationSwitch(entity.getRegistrationSwitch() == null ? 1 : entity.getRegistrationSwitch());
+        insertDay.setLesson((int) dayList.stream().filter(e -> e.getDayDate() != null && e.getDayDate().isBefore(insertDateFinal)).count());
+        insertDay.setStatus(0);
+        insertDay.setCreateTime(new Date());
+        save(insertDay);
+        return R.ok();
+    }
+
     @Override
     public R updateListCourseData(List<FsUserCoursePeriodDays> entity) {
         List<FsUserCoursePeriodDays> collect = entity.stream().map(e -> {

+ 2 - 0
fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java

@@ -87,6 +87,8 @@ public class FsUserCourseVideoQVO extends BaseEntity {
 
     private Long productId;//拍商品id
 
+    private Integer isVip;//是否VIP课程 0:否 1:是
+
     private Long listingStartTime;//商品售卖时间
 
     private Long listingEndTime;//商品结束售卖时间

+ 6 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserMapper.java

@@ -616,6 +616,12 @@ public interface FsUserMapper
      */
     List<FsUserVO> selectExternalUserList(FsUserParam fsUser);
 
+    /**
+     * 查询3个月未登录的APP用户
+     * APP用户判断条件:login_device、source、app_create_time都不为空
+     */
+    List<Long> selectInactiveAppUsers(@Param("threeMonthsAgo") String threeMonthsAgo);
+
     /**
      * 邀请看课数据漏斗统计
      */

+ 2 - 0
fs-service/src/main/java/com/fs/his/param/FsExternalOrderAddParam.java

@@ -37,4 +37,6 @@ public class FsExternalOrderAddParam {
 
     private Long addressId;
 
+    private  BigDecimal totalPrice;
+
 }

+ 47 - 5
fs-service/src/main/java/com/fs/his/service/impl/FsExternalOrderServiceImpl.java

@@ -261,9 +261,8 @@ public class FsExternalOrderServiceImpl implements IFsExternalOrderService {
             order.setStoreId(storeId);
         }
         order.setTotalNum(totalNum);
-        order.setTotalPrice(totalPrice);
+        order.setTotalPrice(param.getTotalPrice()!=null?param.getTotalPrice():totalPrice);
         order.setPayPrice(param.getPayMoney() != null ? param.getPayMoney() : totalPrice);
-
         if (fsExternalOrderMapper.insertFsExternalOrder(order) > 0) {
             for (FsExternalOrderItem item : items) {
                 item.setOrderId(order.getOrderId());
@@ -308,6 +307,7 @@ public class FsExternalOrderServiceImpl implements IFsExternalOrderService {
         }
 
         List<ShopOrderDTO> shopOrderList = new ArrayList<>();
+        List<ShopOrderDTO> codOrderList = new ArrayList<>();
         Map<String, Long> orderCodeToIdMap = new HashMap<>();
 
         for (Long orderId : orderIds) {
@@ -333,6 +333,12 @@ public class FsExternalOrderServiceImpl implements IFsExternalOrderService {
             ShopOrderDTO shopOrderDTO = buildShopOrderDTO(order);
             if (shopOrderDTO != null) {
                 shopOrderList.add(shopOrderDTO);
+                if (isCodOrder(order)) {
+                    ShopOrderDTO codOrderDTO = buildCodShopOrderDTO(order, shopOrderDTO);
+                    if (codOrderDTO != null) {
+                        codOrderList.add(codOrderDTO);
+                    }
+                }
                 orderCodeToIdMap.put(order.getOrderCode(), orderId);
             }
         }
@@ -381,6 +387,43 @@ public class FsExternalOrderServiceImpl implements IFsExternalOrderService {
 
             Thread.sleep(600);
         }
+
+        for (int i = 0; i < codOrderList.size(); i += batchSize) {
+            int endIndex = Math.min(i + batchSize, codOrderList.size());
+            List<ShopOrderDTO> batch = new ArrayList<>(codOrderList.subList(i, endIndex));
+            ErpOrderResponseDTO response = jstErpHttpService.batchUpload(batch);
+            log.info("外部订单货到付款推送聚水潭,批次: {}-{}, 结果: {}", i, endIndex, response);
+            Thread.sleep(600);
+        }
+    }
+
+    private boolean isCodOrder(FsExternalOrder order) {
+        return order != null && (Integer.valueOf(2).equals(order.getPayType()) || Integer.valueOf(3).equals(order.getPayType()));
+    }
+
+    private ShopOrderDTO buildCodShopOrderDTO(FsExternalOrder order, ShopOrderDTO shopOrderDTO) {
+        if (order == null || shopOrderDTO == null) {
+            return null;
+        }
+        ShopOrderDTO codOrderDTO = JSON.parseObject(JSON.toJSONString(shopOrderDTO), ShopOrderDTO.class);
+        BigDecimal totalPrice = order.getTotalPrice() == null ? BigDecimal.ZERO : order.getTotalPrice();
+        BigDecimal payPrice = order.getPayPrice() == null ? BigDecimal.ZERO : order.getPayPrice();
+        BigDecimal codAmount = totalPrice.subtract(payPrice);
+        if (codAmount.compareTo(BigDecimal.ZERO) < 0) {
+            codAmount = BigDecimal.ZERO;
+        }
+        codOrderDTO.setIsCod(true);
+        codOrderDTO.setPayAmount(totalPrice.doubleValue());
+
+        PaymentDTO paymentDTO = new PaymentDTO();
+        paymentDTO.setAmount(codAmount.doubleValue());
+        paymentDTO.setOuterPayId(String.format("%s%d", order.getOrderCode(), 1));
+        paymentDTO.setPayDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
+        paymentDTO.setPayment("货到付款");
+        paymentDTO.setBuyerAccount(order.getUserName());
+        paymentDTO.setSellerAccount("平台销售");
+        codOrderDTO.setPay(paymentDTO);
+        return codOrderDTO;
     }
 
     private ShopOrderDTO buildShopOrderDTO(FsExternalOrder order) {
@@ -398,12 +441,11 @@ public class FsExternalOrderServiceImpl implements IFsExternalOrderService {
         ShopOrderDTO shopOrderDTO = new ShopOrderDTO();
         shopOrderDTO.setShopId(Long.valueOf(fsStore.getShopCode()));
         shopOrderDTO.setSoId(order.getOrderCode());
-
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         shopOrderDTO.setOrderDate(sdf.format(new Date()));
         shopOrderDTO.setShopStatus("WAIT_SELLER_SEND_GOODS");
         shopOrderDTO.setShopBuyerId(order.getUserName());
-        shopOrderDTO.setPayAmount(order.getPayPrice().doubleValue());
+        shopOrderDTO.setPayAmount(order.getTotalPrice().doubleValue());
         shopOrderDTO.setFreight(order.getFreightPrice() != null ? order.getFreightPrice().doubleValue() : 0.0);
 
         StringBuilder remarkBuilder = new StringBuilder();
@@ -487,7 +529,7 @@ public class FsExternalOrderServiceImpl implements IFsExternalOrderService {
             itemDTO.setName(orderItem.getProductName());
             itemDTO.setShopIId(orderItem.getProductCode() != null ? orderItem.getProductCode().trim() : "");
             itemDTO.setPropertiesValue(orderItem.getProductSpec());
-            itemDTO.setAmount(orderItem.getTotalPrice());
+            itemDTO.setAmount(orderItem.getTotalPrice().multiply(new BigDecimal(orderItem.getNum())));
             itemDTO.setPrice(orderItem.getPrice());
             itemDTO.setQty(orderItem.getNum().intValue());
             itemDTO.setOuterOiId(String.format("%s%d", order.getOrderCode(), orderItem.getItemId()));

+ 33 - 0
fs-service/src/main/resources/mapper/course/FsUserCourseClearLogMapper.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.course.mapper.FsUserCourseClearLogMapper">
+
+    <resultMap type="com.fs.course.domain.FsUserCourseClearLog" id="FsUserCourseClearLogResult">
+        <id property="id" column="id"/>
+        <result property="userId" column="user_id"/>
+        <result property="projectId" column="project_id"/>
+        <result property="companyId" column="company_id"/>
+        <result property="companyUserId" column="company_user_id"/>
+        <result property="createTime" column="create_time"/>
+    </resultMap>
+
+    <sql id="selectFsUserCourseClearLogVo">
+        select id, user_id, project_id, company_id, company_user_id, create_time from fs_user_course_clear_log
+    </sql>
+
+    <insert id="insertFsUserCourseClearLog" parameterType="com.fs.course.domain.FsUserCourseClearLog">
+        insert into fs_user_course_clear_log (user_id, project_id, company_id, company_user_id, create_time)
+        values (#{userId}, #{projectId}, #{companyId}, #{companyUserId}, #{createTime})
+    </insert>
+
+    <insert id="batchInsertFsUserCourseClearLog" parameterType="java.util.List">
+        insert into fs_user_course_clear_log (user_id, project_id, company_id, company_user_id, create_time)
+        values
+        <foreach collection="list" item="item" separator=",">
+            (#{item.userId}, #{item.projectId}, #{item.companyId}, #{item.companyUserId}, #{item.createTime})
+        </foreach>
+    </insert>
+
+</mapper>

+ 4 - 0
fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml

@@ -37,6 +37,7 @@
         <result property="lastJoinTime"    column="last_join_time"    />
         <result property="projectId"    column="project_id"    />
         <result property="isFirst"    column="is_first"    />
+        <result property="isVip"    column="is_vip"    />
         <result property="remark"    column="remark"    />
     </resultMap>
 
@@ -105,6 +106,7 @@
             <if test="projectId != null">project_id,</if>
             <if test="isProduct != null">is_product,</if>
             <if test="productId != null">product_id,</if>
+            <if test="isVip != null">is_vip,</if>
             <if test="listingStartTime != null">listing_start_time,</if>
             <if test="listingEndTime != null">listing_end_time,</if>
             <if test="userId != null">user_id,</if>
@@ -145,6 +147,7 @@
             <if test="lastJoinTime != null">#{lastJoinTime},</if>
             <if test="isProduct != null">#{isProduct},</if>
             <if test="productId != null">#{productId},</if>
+            <if test="isVip != null">#{isVip},</if>
             <if test="listingStartTime != null">#{listingStartTime},</if>
             <if test="listingEndTime != null">#{listingEndTime},</if>
             <if test="projectId != null">#{projectId},</if>
@@ -236,6 +239,7 @@
             <if test="lastJoinTime != null">last_join_time = #{lastJoinTime},</if>
             <if test="isProduct != null">is_product = #{isProduct},</if>
             <if test="productId != null">product_id = #{productId},</if>
+            <if test="isVip != null">is_vip = #{isVip},</if>
             <if test="listingStartTime != null">listing_start_time = #{listingStartTime},</if>
             <if test="listingEndTime != null">listing_end_time = #{listingEndTime},</if>
             <if test="projectId != null">project_id = #{projectId},</if>

+ 2 - 2
fs-service/src/main/resources/mapper/his/FsExternalOrderMapper.xml

@@ -186,7 +186,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             o.user_name AS userName,
             o.user_phone AS userPhone,
             GROUP_CONCAT(oi.product_name SEPARATOR ',') AS productNames,
-            SUM(oi.price) AS receivablePrice,
+            IFNULL(o.total_price, SUM(oi.price)) AS receivablePrice,
             o.pay_price AS payPrice,
             o.pay_type AS payType,
             o.external_create_time AS externalCreateTime,
@@ -231,7 +231,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             o.user_phone AS userPhone,
             o.user_address AS userAddress,
             o.total_num AS totalNum,
-            o.total_price AS totalPrice,
+            o.total_price AS receivablePrice,
             o.pay_price AS payPrice,
             o.freight_price AS freightPrice,
             o.is_pay AS isPay,

+ 7 - 1
fs-service/src/main/resources/mapper/his/FsUserMapper.xml

@@ -990,7 +990,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                     </when>
                 </choose>
             </if>
-            and fcwl.user_id = #{fsUserId} and fucu.company_user_id = #{userId}
+            and fcwl.user_id = #{fsUserId} and fucu.company_user_id = #{userId} and fcwl.watch_type=1 and fcwl.send_type=1
             <if test="userCompanyId!=null">
                 and fucu.id = #{userCompanyId}
             </if>
@@ -2732,6 +2732,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         ORDER BY fu.user_id DESC
     </select>
 
+    <select id="selectInactiveAppUsers" resultType="java.lang.Long">
+        SELECT user_id FROM fs_user
+        WHERE update_time &lt; #{threeMonthsAgo}
+          and ((source is not null and source != '') and login_device is not null or app_create_time is not null)
+    </select>
+
     <!-- 邀请看课数据漏斗统计 -->
     <select id="countCourseInviteFunnel" resultType="Map">
         SELECT