Ver Fonte

Merge branch 'master' of http://1.14.104.71:10880/root/ylrz_his_scrm_java

# Conflicts:
#	fs-service/src/main/resources/mapper/his/FsUserMapper.xml
caoliqin há 1 dia atrás
pai
commit
e68753a051
55 ficheiros alterados com 1228 adições e 372 exclusões
  1. 1 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java
  2. 94 0
      fs-admin/src/main/java/com/fs/qw/FsCourseTask.java
  3. 2 0
      fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java
  4. 80 4
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserVoiceLogController.java
  5. 2 0
      fs-service/src/main/java/com/fs/company/service/ICompanyConfigService.java
  6. 38 0
      fs-service/src/main/java/com/fs/company/service/impl/CompanyConfigServiceImpl.java
  7. 15 24
      fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java
  8. 9 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseRedPacketLog.java
  9. 5 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java
  10. 1 0
      fs-service/src/main/java/com/fs/course/param/FsUserCourseOrderDoPayParam.java
  11. 1 0
      fs-service/src/main/java/com/fs/course/param/FsUserVipOrderPayUParam.java
  12. 85 15
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java
  13. 63 6
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java
  14. 5 5
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseTrainingCampServiceImpl.java
  15. 230 211
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  16. 63 6
      fs-service/src/main/java/com/fs/course/service/impl/FsUserVipOrderServiceImpl.java
  17. 4 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/api/WdtClient.java
  18. 1 1
      fs-service/src/main/java/com/fs/erp/http/JstErpHttpServiceImpl.java
  19. 23 7
      fs-service/src/main/java/com/fs/erp/service/impl/K9OrderScrmServiceImpl.java
  20. 2 2
      fs-service/src/main/java/com/fs/erp/service/impl/WdtErpGoodsServiceImpl.java
  21. 14 0
      fs-service/src/main/java/com/fs/his/domain/FsStorePayment.java
  22. 1 0
      fs-service/src/main/java/com/fs/his/mapper/FsStorePaymentMapper.java
  23. 2 0
      fs-service/src/main/java/com/fs/his/param/FsStorePaymentParam.java
  24. 105 11
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java
  25. 47 9
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  26. 40 6
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  27. 6 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserCouponServiceImpl.java
  28. 2 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java
  29. 2 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderItemScrmService.java
  30. 1 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreCartScrmServiceImpl.java
  31. 5 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderItemScrmServiceImpl.java
  32. 2 0
      fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemVO.java
  33. 1 1
      fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java
  34. 41 14
      fs-service/src/main/java/com/fs/qw/service/impl/QwUserVoiceLogServiceImpl.java
  35. 49 0
      fs-service/src/main/java/com/fs/qw/vo/QwUserVoiceLogTotalVo.java
  36. 5 0
      fs-service/src/main/java/com/fs/qw/vo/QwUserVoiceLogVo.java
  37. 22 8
      fs-service/src/main/java/com/fs/system/service/impl/SysConfigServiceImpl.java
  38. 2 0
      fs-service/src/main/resources/application-config-druid-qdtst.yml
  39. 2 0
      fs-service/src/main/resources/application-druid-kyt.yml
  40. 1 1
      fs-service/src/main/resources/application-druid-qdtst.yml
  41. 4 0
      fs-service/src/main/resources/mapper/course/FsCourseRedPacketLogMapper.xml
  42. 7 0
      fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml
  43. 4 3
      fs-service/src/main/resources/mapper/course/FsUserCourseTrainingCampMapper.xml
  44. 1 0
      fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml
  45. 9 1
      fs-service/src/main/resources/mapper/his/FsStorePaymentMapper.xml
  46. 4 8
      fs-service/src/main/resources/mapper/his/FsUserMapper.xml
  47. 12 6
      fs-service/src/main/resources/mapper/hisStore/FsStoreOrderItemScrmMapper.xml
  48. 17 3
      fs-service/src/main/resources/mapper/qw/QwUserVoiceLogMapper.xml
  49. 1 1
      fs-service/src/main/resources/mapper/store/FsUserCourseCountMapper.xml
  50. 68 11
      fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
  51. 1 1
      fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java
  52. 4 4
      fs-user-app/src/main/java/com/fs/app/controller/store/CourseH5ScrmController.java
  53. 2 2
      fs-user-app/src/main/java/com/fs/app/controller/store/CourseWxH5ScrmController.java
  54. 18 0
      fs-user-app/src/main/java/com/fs/framework/config/RedisConfig.java
  55. 2 1
      fs-user-app/src/main/resources/application.yml

+ 1 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserCourseVideoController.java

@@ -202,6 +202,7 @@ public class FsUserCourseVideoController extends BaseController
         return R.ok();
     }
     @PostMapping("/batchUpdateRed")
+    @Log(title = "按课程批量保存设置红包金额", businessType = BusinessType.UPDATE)
     public R batchUpdateRed(@RequestBody List<BatchRedUpdate> list){
         fsUserCourseVideoService.batchUpdateRed(list);
         return R.ok();

+ 94 - 0
fs-admin/src/main/java/com/fs/qw/FsCourseTask.java

@@ -1,11 +1,27 @@
 package com.fs.qw;
 
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.qw.service.IQwWorkTaskService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import io.jsonwebtoken.lang.Assert;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.http.util.Asserts;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
 /**
  * 后台统计相关 定时任务
  */
@@ -16,7 +32,85 @@ public class FsCourseTask {
     private IFsCourseWatchLogService fsCourseWatchLogService;
     @Autowired
     private IQwWorkTaskService qwWorkTaskService;
+    @Autowired
+    private RedisCache redisCache;
+    private static final String REDPACKET_COMPANY_MONEY_CHANGE = "redpacket_money_CHANGE";
+    @Autowired
+    private SysConfigMapper sysConfigMapper;
+    private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
+    private static final String REDPACKET_COMPANY_MONEY = "redpacket_money";
+
+    @Autowired
+    private RedissonClient redissonClient;
+
+    /**
+     * 润天公司账户充值
+     * @param chargeMoney 充值金额
+     */
+    public void rechargeRedpacketMoney(String chargeMoney){
+        Assert.notNull(chargeMoney,"充值金额不能为空!");
+
+        log.info("润天公司账户充值 充值金额: {}",chargeMoney);
+
+        RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
+        try{
+            boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
+
+            if (!locked) {
+                log.error("获取锁失败...");
+                return;
+            }
+
+            BigDecimal redPacketCompanyMoney = redisCache.getCacheObject(REDPACKET_COMPANY_MONEY);
+            if(ObjectUtils.isNull(redPacketCompanyMoney)){
+                redPacketCompanyMoney = BigDecimal.ZERO;
+            }
+            BigDecimal value = redPacketCompanyMoney.add(new BigDecimal(chargeMoney));
+
+            log.info("润天公司账户充值成功 目前余额: {}",value);
 
+            redisCache.setCacheObject(REDPACKET_COMPANY_MONEY,value);
+
+
+            // 保存到数据库
+            SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("company.money");
+
+            sysConfig.setConfigValue(value.setScale(4, RoundingMode.HALF_UP).toPlainString());
+            sysConfig.setConfigKey("company.money");
+            sysConfigMapper.updateConfig(sysConfig);
+
+        }catch (Exception e){
+            log.error("充值失败 原因:{}", ExceptionUtils.getFullStackTrace(e),e);
+            throw new RuntimeException(e);
+        }finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+            }
+        }
+    }
+    /**
+     * 公司红包金额变更
+     */
+    public void redpacketCompanyMoneyChange(){
+        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("company.money");
+        Asserts.notNull(sysConfig,"公司账户配置不能为空!");
+
+        String configValue = sysConfig.getConfigValue();
+        Asserts.notNull(configValue,"公司账户余额不能为空");
+
+        BigDecimal oldBigDecimal = new BigDecimal(configValue);
+
+        BigDecimal redPacketCompanyMoney = redisCache.getCacheObject(REDPACKET_COMPANY_MONEY);
+
+        log.info("公司账户红包余额变更 {} -> {}",oldBigDecimal,redPacketCompanyMoney);
+
+        // 如果两者不一致才同步到数据库
+        if(oldBigDecimal.compareTo(redPacketCompanyMoney) != 0){
+            sysConfig.setConfigValue(redPacketCompanyMoney.setScale(4, RoundingMode.HALF_UP).toPlainString());
+            sysConfig.setConfigKey("company.money");
+            sysConfigMapper.updateConfig(sysConfig);
+        }
+    }
     /**
      * 添加企微观看日志
      * @throws Exception

+ 2 - 0
fs-company/src/main/java/com/fs/company/controller/course/FsUserCoursePeriodController.java

@@ -191,6 +191,7 @@ public class FsUserCoursePeriodController extends BaseController {
 
     @ApiOperation("按课程批量保存设置红包金额")
     @PostMapping("/batchRedPacket")
+    @Log(title = "按课程批量保存设置红包金额", businessType = BusinessType.UPDATE)
     public R batchRedPacketMoney(@RequestBody List<FsUserCourseVideoRedPackage> videoRedPackageList) {
         try {
             fsUserCourseVideoRedPackageService.batchSaveCompanyRedPackage(videoRedPackageList);
@@ -203,6 +204,7 @@ public class FsUserCoursePeriodController extends BaseController {
 
     @ApiOperation("按营期批量保存设置红包金额")
     @PostMapping("/batchRedPacket/byPeriod")
+    @Log(title = "按营期批量保存设置红包金额", businessType = BusinessType.UPDATE)
     public R batchRedPacketByPeriod(@RequestBody List<FsBatchPeriodRedPackageParam> periodRedPackageList) {
         try {
             fsUserCourseVideoRedPackageService.batchRedPacketByPeriod(periodRedPackageList);

+ 80 - 4
fs-company/src/main/java/com/fs/company/controller/qw/QwUserVoiceLogController.java

@@ -1,12 +1,18 @@
 package com.fs.company.controller.qw;
 
 import com.fs.common.annotation.Log;
+import com.fs.common.constant.HttpStatus;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.PageDomain;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.core.page.TableSupport;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.ServletUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.service.ICompanyUserService;
 import com.fs.framework.security.LoginUser;
 import com.fs.framework.service.TokenService;
 import com.fs.qw.domain.QwUserVoiceLog;
@@ -22,8 +28,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * 企微用户通话记录Controller
@@ -44,6 +52,9 @@ public class QwUserVoiceLogController extends BaseController
     @Autowired
     private IQwTagService iQwTagService;
 
+    @Autowired
+    private ICompanyUserService userService;
+
     /**
      * 查询企微用户通话记录列表
      */
@@ -137,23 +148,88 @@ public class QwUserVoiceLogController extends BaseController
     @GetMapping("/totalList")
     public TableDataInfo totalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     {
-        startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwUserVoiceLog.setCompanyId(loginUser.getCompany().getCompanyId());
         qwUserVoiceLog.setQwUserId(1L);
         List<QwUserVoiceLogTotalVo> list = qwUserVoiceLogService.selectQwUserVoiceLogTotalList(qwUserVoiceLog);
-        return getDataTable(list);
+        list.forEach(item->{
+            if(item.getQwExternalContact() != null){
+                if (item.getQwExternalContact().getTagIds() != null && !Objects.equals(item.getQwExternalContact().getTagIds(), "[]")) {
+                    QwTagSearchParam param = new QwTagSearchParam();
+                    Gson gson = new Gson();
+                    List<String> tagIds = gson.fromJson(
+                            item.getQwExternalContact().getTagIds(),
+                            new TypeToken<List<String>>() {
+                            }.getType()
+                    );
+                    param.setTagIds(tagIds);
+                    item.setTagIdsName(iQwTagService.selectQwTagListByTagIds(param));
+                }
+            }
+        });
+
+        // 获取分页参数
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+
+        int total = list.size();
+        // 在内存中进行分页处理
+        if (pageNum != null && pageSize != null) {
+            int fromIndex = (pageNum - 1) * pageSize;
+            int toIndex = Math.min(fromIndex + pageSize, total);
+
+            // 确保索引不越界
+            if (fromIndex < total) {
+                list = list.subList(fromIndex, toIndex);
+            } else {
+                list = new ArrayList<>(); // 返回空列表
+            }
+        }
+
+        // 构造返回结果
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(total);
+        return rspData;
     }
 
 
     @GetMapping("/sellTotalList")
     public TableDataInfo sellTotalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     {
-        startPage();
         LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
         qwUserVoiceLog.setCompanyId(loginUser.getCompany().getCompanyId());
         List<QwUserVoiceLogTotalVo> list = qwUserVoiceLogService.selectQwUserVoiceLogTotalList(qwUserVoiceLog);
-        return getDataTable(list);
+
+        // 获取分页参数
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+
+        int total = list.size();
+        // 在内存中进行分页处理
+        if (pageNum != null && pageSize != null) {
+            int fromIndex = (pageNum - 1) * pageSize;
+            int toIndex = Math.min(fromIndex + pageSize, total);
+
+            // 确保索引不越界
+            if (fromIndex < total) {
+                list = list.subList(fromIndex, toIndex);
+            } else {
+                list = new ArrayList<>(); // 返回空列表
+            }
+        }
+
+        // 构造返回结果
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(total);
+        return rspData;
     }
 
     @PreAuthorize("@ss.hasPermi('qw:qwUserVoiceLog:sellTotalExport')")

+ 2 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyConfigService.java

@@ -67,4 +67,6 @@ public interface ICompanyConfigService
     String selectConfigByKey(String configKey);
 
     CompanyConfig selectCompanyConfigByServerKey(String key);
+
+    String selectRedPacketConfigByKey(Long companyId);
 }

+ 38 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyConfigServiceImpl.java

@@ -8,10 +8,15 @@ import com.fs.company.domain.CompanyConfig;
 import com.fs.company.mapper.CompanyConfigMapper;
 import com.fs.company.service.ICompanyConfigService;
 import com.fs.system.domain.SysConfig;
+import org.apache.http.util.Asserts;
+import org.redisson.api.RedissonClient;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 
 import static com.fs.common.utils.DictUtils.getCacheKey;
 
@@ -28,6 +33,10 @@ public class CompanyConfigServiceImpl implements ICompanyConfigService
     private RedisCache redisCache;
     @Autowired
     private CompanyConfigMapper companyConfigMapper;
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate; // 注入RedisTemplate
+    private static final String REDIS_KEY_PREFIX = "red_packet_config:";
+    private static final long CACHE_TIMEOUT = 24 * 60 * 60;
 
     /**
      * 查询参数配置
@@ -133,4 +142,33 @@ public class CompanyConfigServiceImpl implements ICompanyConfigService
     public CompanyConfig selectCompanyConfigByServerKey(String key) {
         return companyConfigMapper.selectCompanyConfigByServerKey(key);
     }
+
+    @Override
+    public String selectRedPacketConfigByKey(Long companyId) {
+        Asserts.notNull(companyId,"公司id不能为空!");
+        String redisKey = REDIS_KEY_PREFIX + companyId;
+        String cachedConfig = redisTemplate.opsForValue().get(redisKey);
+        if (cachedConfig != null) {
+            return cachedConfig;
+        }
+        synchronized (getSynchronizationObject(companyId)) {
+            cachedConfig = redisTemplate.opsForValue().get(redisKey);
+
+            if (cachedConfig != null) {
+                return cachedConfig;
+            }
+            String configFromDb = companyConfigMapper.selectRedPacketConfigByKey(companyId);
+            if (configFromDb != null) {
+                redisTemplate.opsForValue().set(redisKey, configFromDb, CACHE_TIMEOUT, TimeUnit.SECONDS);
+            } else {
+                redisTemplate.opsForValue().set(redisKey, "", 5 * 60, TimeUnit.SECONDS);
+            }
+            return configFromDb;
+        }
+    }
+
+    private static final ConcurrentHashMap<Long, Object> LOCKS = new ConcurrentHashMap<>();
+    private static Object getSynchronizationObject(Long companyId) {
+        return LOCKS.computeIfAbsent(companyId, k -> new Object());
+    }
 }

+ 15 - 24
fs-service/src/main/java/com/fs/core/config/WxMaConfiguration.java

@@ -33,8 +33,10 @@ import org.yaml.snakeyaml.events.Event;
 import javax.annotation.PostConstruct;
 import java.io.File;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Collectors;
 
 @Slf4j
@@ -97,20 +99,7 @@ public class WxMaConfiguration {
     }
 
     public static WxMaService getMaService(String appid) {
-        // 从缓存获取
-        WxMaService wxService = maServices.get(appid);
-        if (wxService != null) {
-            return wxService;
-        }
-
-        // 缓存未命中,查询数据库
-        synchronized (WxMaConfiguration.class) {
-            // 双重检查
-            wxService = maServices.get(appid);
-            if (wxService != null) {
-                return wxService;
-            }
-
+        return maServices.computeIfAbsent(appid,e->{
             // 查询数据库
             FsCoursePlaySourceConfigMapper configMapper = SpringUtils.getBean(FsCoursePlaySourceConfigMapper.class);
             Wrapper<FsCoursePlaySourceConfig> queryWrapper = Wrappers.<FsCoursePlaySourceConfig>lambdaQuery()
@@ -121,11 +110,8 @@ public class WxMaConfiguration {
                 throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
             }
 
-            WxMaService service = getWxMaService(config.getAppid(), config.getSecret(), config.getToken(), config.getAesKey(), config.getMsgDataFormat());
-            maServices.put(appid, service);
-            log.info("Initialized WxMaService for appid: {}", appid);
-            return service;
-        }
+            return getWxMaService(config.getAppid(), config.getSecret(), config.getToken(), config.getAesKey(), config.getMsgDataFormat());
+        });
     }
 
     /**
@@ -156,11 +142,16 @@ public class WxMaConfiguration {
         }
 
         maServices = configs.stream()
-            .map(a -> {
-                WxMaService service = getWxMaService(a.getAppid(), a.getSecret(), a.getToken(), a.getAesKey(), a.getMsgDataFormat());
-                routers.put(a.getAppid(), this.newRouter(service));
-                return service;
-            }).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a));
+                .map(a -> {
+                    WxMaService service = getWxMaService(a.getAppid(), a.getSecret(), a.getToken(), a.getAesKey(), a.getMsgDataFormat());
+                    routers.put(a.getAppid(), this.newRouter(service));
+                    return service;
+                }).collect(Collectors.toMap(
+                        s -> s.getWxMaConfig().getAppid(),
+                        a -> a,
+                        (existing, replacement) -> replacement,
+                        ConcurrentHashMap::new
+                ));
     }
 
     private WxMaMessageRouter newRouter(WxMaService service) {

+ 9 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseRedPacketLog.java

@@ -64,4 +64,13 @@ public class FsCourseRedPacketLog extends BaseEntity
 
     private String appId;//小程序appId
 
+    /**
+     * 账户余额扣减前
+     */
+    private BigDecimal accBalanceBefore;
+    /**
+     * 账户余额扣减后
+     */
+    private BigDecimal accBalanceAfter;
+
 }

+ 5 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseWatchLogMapper.java

@@ -519,4 +519,9 @@ public interface FsCourseWatchLogMapper extends BaseMapper<FsCourseWatchLog> {
     Long selectByWatchlxDay(@Param("userId") Long userId,@Param("projectId")  Long projectId);
 
     List<FsCourseWatchLogListVO> selectFsCourseWatchLogListVOexport(@Param("maps") FsCourseWatchLogListParam param);
+
+    /**
+     * 查询训练营看课人数
+     */
+    Integer getUserCountByCampId(@Param("trainingCampId") Long trainingCampId);
 }

+ 1 - 0
fs-service/src/main/java/com/fs/course/param/FsUserCourseOrderDoPayParam.java

@@ -10,4 +10,5 @@ public class FsUserCourseOrderDoPayParam implements Serializable {
     @NotNull(message = "订单号不能为空")
     Long orderId;
     Long userId;
+    String appId;
 }

+ 1 - 0
fs-service/src/main/java/com/fs/course/param/FsUserVipOrderPayUParam.java

@@ -11,4 +11,5 @@ public class FsUserVipOrderPayUParam implements Serializable {
    private Long userId;
    @NotNull(message = "orderId不能为空")
    private Long orderId;
+   private String appId;
 }

+ 85 - 15
fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java

@@ -7,6 +7,8 @@ import java.util.*;
 import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.core.domain.R;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
@@ -27,6 +29,7 @@ import com.fs.his.domain.*;
 import com.fs.his.dto.PayConfigDTO;
 import com.fs.his.enums.FsCourseProductOrderStatusEnum;
 import com.fs.his.mapper.FsStorePaymentMapper;
+import com.fs.his.mapper.FsUserWxMapper;
 import com.fs.his.param.ApplyCourseProductOrderRefundParam;
 import com.fs.his.param.FsCourseProductOrderComputeParam;
 import com.fs.his.param.FsCourseProductOrderDoPayParam;
@@ -125,8 +128,11 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 
     private static final int CODE_LENGTH = 12;
 
+//    @Autowired
+//    private IFsUserWxService userWxService;
+
     @Autowired
-    private IFsUserWxService userWxService;
+    private FsUserWxMapper fsUserWxMapper;
 
 
     /**
@@ -271,9 +277,40 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
             return R.error("订单状态不正确");
         }
         FsUser user = userService.selectFsUserByUserId(courseProductOrder.getUserId());
-        FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), user.getUserId(), 1);
-        logger.info("用户微信信息==============={}",fsUserWx);
-        if (user != null && fsUserWx != null && StringUtils.isNotEmpty(fsUserWx.getOpenId())) {
+
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, user.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+            logger.info("用户微信信息==============={}",fsUserWx);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, user.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                logger.info("用户微信信息==============={}",fsUserWx);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+
+//        FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), user.getUserId(), 1);
+//        logger.info("用户微信信息==============={}",fsUserWx);
+//        if (user != null && fsUserWx != null && StringUtils.isNotEmpty(fsUserWx.getOpenId())) {
+        if (user != null && StringUtils.isNotEmpty(openId)) {
             Map<String,Object> moneys= Maps.newHashMap();
             FsCourseProduct courseProduct = JSONUtil.toBean(courseProductOrder.getProductJson(), FsCourseProduct.class);
             moneys.put("payPrice",courseProduct.getProductPrice());
@@ -316,12 +353,43 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
         }
         FsUser user = userService.selectFsUserByUserId(param.getUserId());
         logger.info("用户信息==============={}",user);
-        FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), user.getUserId(), 1);
-        logger.info("用户微信信息==============={}",fsUserWx);
-        if (user != null && fsUserWx != null && StringUtils.isNotEmpty(fsUserWx.getOpenId())) {
+
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, user.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+            logger.info("用户微信信息==============={}",fsUserWx);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, user.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                logger.info("用户微信信息==============={}",fsUserWx);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+
+//        FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), user.getUserId(), 1);
+//        logger.info("用户微信信息==============={}",fsUserWx);
+//        if (user != null && fsUserWx != null && StringUtils.isNotEmpty(fsUserWx.getOpenId())) {
+        if (user != null && StringUtils.isNotEmpty(openId)) {
             if (courseProduct.getProductPrice().compareTo(new BigDecimal(0))==1) {
-                String json = configService.selectConfigByKey("his.pay");
-                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 String payCode =  OrderCodeUtils.getOrderSn();
                 if(StringUtils.isEmpty(payCode)){
                     return R.error("订单生成失败,请重试");
@@ -338,7 +406,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                 storePayment.setCompanyId(courseProductOrder.getCompanyId());
                 storePayment.setCompanyUserId(courseProductOrder.getCompanyUserId());
                 storePayment.setRemark("拍商品订单支付");
-                storePayment.setOpenId(fsUserWx.getOpenId());
+                storePayment.setOpenId(openId);
                 storePayment.setUserId(user.getUserId());
                 storePayment.setBusinessId(courseProductOrder.getCourseOrderId().toString());
                 if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
@@ -347,7 +415,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                         WxPayConfig payConfig = new WxPayConfig();
                         SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
                         FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                        payConfig.setAppId(fsPayConfig.getAppId());
+                        payConfig.setAppId(appId);
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
                         payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -356,7 +424,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                         payConfig.setNotifyUrl(wxPayProperties.getNotifyUrl());
                         wxPayService.setConfig(payConfig);
                         WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
-                        orderRequest.setOpenid(fsUserWx.getOpenId());//公众号支付提供用户openid
+                        orderRequest.setOpenid(openId);//公众号支付提供用户openid
                         orderRequest.setBody("拍商品订单支付");
                         orderRequest.setOutTradeNo("product-" + storePayment.getPayCode());
                         orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(storePayment.getPayMoney().toString()));//测试
@@ -378,7 +446,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                         p.setLowOrderId("product-" + storePayment.getPayCode());
                         p.setBody("拍商品订单支付");
                         p.setIsMinipg("1");
-                        p.setOpenId(fsUserWx.getOpenId());
+                        p.setOpenId(openId);
                         p.setAttach("");
                         p.setStoreid("0");
                         CreateWxOrderResult wxOrder = payService.createWxOrder(p);
@@ -408,7 +476,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                         }
                         o.setPayerName("微信用户"+phone);
                         o.setGoodsInfo("拍商品订单支付"); // 订单信息
-                        o.setOpenId(fsUserWx.getOpenId());
+                        o.setOpenId(openId);
                         o.setOrderType(3);
                         o.setOrderId(courseProductOrder.getCourseOrderId().toString());
                         TzBankResult<PayCreateOrderResult> result = tzBankService.createOrder(o);
@@ -421,7 +489,8 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                         logger.info("创建汇付订单");
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_MINIAPP");
-                        o.setOpenid(fsUserWx.getOpenId());
+                        o.setOpenid(openId);
+                        o.setAppId(appId);
                         o.setReqSeqId("product-"+storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
                         o.setGoodsDesc("拍商品订单支付");
@@ -430,6 +499,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                         FsStorePayment mt=new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }

+ 63 - 6
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java

@@ -377,15 +377,40 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
         String json = configService.selectConfigByKey("his.pay");
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
-        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
-        if (StringUtils.isBlank(openId)){
+//        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+//        if (StringUtils.isBlank(openId)){
+//            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+//                    .eq(FsUserWx::getFsUserId, param.getUserId())
+//                    .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+//            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+//            if (Objects.nonNull(fsUserWx)){
+//                openId = fsUserWx.getOpenId();
+//            }
+//        }
+
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
             Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                     .eq(FsUserWx::getFsUserId, param.getUserId())
-                    .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+                    .eq(FsUserWx::getAppId, appId);
             FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
-            if (Objects.nonNull(fsUserWx)){
+            if (fsUserWx != null) {
                 openId = fsUserWx.getOpenId();
             }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
         }
 
         if(user!=null&& StringUtils.isNotEmpty(openId)) {
@@ -484,6 +509,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_MINIAPP");
                         o.setOpenid(openId);
+                        o.setAppId(appId);
                         o.setReqSeqId("course-" + storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
                         o.setGoodsDesc("课程订单支付");
@@ -491,6 +517,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                         FsStorePayment mt = new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
 
@@ -521,14 +548,42 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
 //            }
 //        }
         FsUser user=fsUserMapper.selectFsUserByUserId(param.getUserId());
+
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+
         if(user!=null){
             if(order.getPayMoney().compareTo(new BigDecimal(0))==1){
                 String payCode =  OrderCodeUtils.getOrderSn();
                 if(StringUtils.isEmpty(payCode)){
                     return R.error("订单生成失败,请重试");
                 }
-                String json = configService.selectConfigByKey("his.pay");
-                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
                 storePayment.setPayMode(payConfigDTO.getType());
@@ -574,10 +629,12 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                         o.setReqSeqId("course-"+storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
                         o.setGoodsDesc("课程订单支付");
+                        o.setAppId(appId);
                         HuifuCreateOrderResult result = huiFuService.createOrder(o);
                         FsStorePayment mt=new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }

+ 5 - 5
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseTrainingCampServiceImpl.java

@@ -11,10 +11,7 @@ import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.domain.FsUserCoursePeriodDays;
 import com.fs.course.domain.FsUserCourseTrainingCamp;
 import com.fs.course.dto.FsUserCourseTrainingCampDTO;
-import com.fs.course.mapper.FsUserCoursePeriodDaysMapper;
-import com.fs.course.mapper.FsUserCoursePeriodMapper;
-import com.fs.course.mapper.FsUserCourseTrainingCampMapper;
-import com.fs.course.mapper.FsUserCourseVideoRedPackageMapper;
+import com.fs.course.mapper.*;
 import com.fs.course.service.IFsUserCoursePeriodDaysService;
 import com.fs.course.service.IFsUserCourseTrainingCampService;
 import com.fs.course.vo.FsUserCourseTrainingCampVO;
@@ -46,6 +43,7 @@ public class FsUserCourseTrainingCampServiceImpl extends ServiceImpl<FsUserCours
     private final FsUserCoursePeriodDaysMapper fsUserCoursePeriodDaysMapper;
 
     private final IFsUserCoursePeriodDaysService fsUserCoursePeriodDaysService;
+    private final FsCourseWatchLogMapper fsCourseWatchLogMapper;
 
     /**
      * 查询训练营列表
@@ -54,7 +52,9 @@ public class FsUserCourseTrainingCampServiceImpl extends ServiceImpl<FsUserCours
      */
     @Override
     public List<FsUserCourseTrainingCampVO> selectFsUserCourseTrainingCampVOListByMap(Map<String, Object> params) {
-        return baseMapper.selectFsUserCourseTrainingCampVOListByMap(params);
+        List<FsUserCourseTrainingCampVO> trainingCampVOS = baseMapper.selectFsUserCourseTrainingCampVOListByMap(params);
+        trainingCampVOS.forEach(camp -> camp.setVipCount(fsCourseWatchLogMapper.getUserCountByCampId(camp.getTrainingCampId())));
+        return trainingCampVOS;
     }
 
     /**

+ 230 - 211
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.domain.R;
@@ -60,19 +61,27 @@ import com.fs.qwApi.service.QwApiService;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.SopUserLogsInfoMapper;
 import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysDictDataMapper;
 import com.fs.system.service.ISysConfigService;
 import com.fs.voice.utils.StringUtil;
 import com.github.binarywang.wxpay.bean.transfer.TransferBillsResult;
+import com.google.common.collect.Sets;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.rocketmq.spring.core.RocketMQTemplate;
+import org.jetbrains.annotations.NotNull;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import org.redisson.client.RedisClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.BeansException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -82,6 +91,7 @@ import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
@@ -104,6 +114,26 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private Boolean isNewWxMerchant;
     private static final Logger logger = LoggerFactory.getLogger(FsUserCourseVideoServiceImpl.class);
 
+    /**
+     * 红包账户锁
+     */
+    private static final String REDPACKET_POOL_LOCK = "redpacket_pool_lock";
+
+    /**
+     * 公司红包金额
+     */
+    private static final String REDPACKET_COMPANY_MONEY = "redpacket_money";
+
+    /**
+     * 红包改变记录
+     */
+    private static final String REDPACKET_COMPANY_MONEY_CHANGE = "redpacket_money_change";
+
+    /**
+     * 是否开启红包账户扣减
+     */
+    @Value("${enableRedPackAccount:0}")
+    private String ENABLE_RED_PACK_ACCOUNT;
 
     private static final String miniappRealLink = "/pages_course/video.html?course=";
     private static final String REAL_LINK_PREFIX = "/courseH5/pages/course/learning?course=";
@@ -139,6 +169,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private AsyncIsAddKfXfkService xfkService;
 
 
+    @Autowired
+    private RedissonClient redissonClient;
     @Autowired
     private QwExternalContactMapper qwExternalContactMapper;
     @Autowired
@@ -216,6 +248,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     private CloudHostProper cloudHostProper;
 
+    @Autowired
+    private RedisTemplate<String,BigDecimal> redisTemplate;
+
 
     /**
      * 查询课堂视频
@@ -412,7 +447,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     @Override
     public R isAddKf(FsUserCourseVideoAddKfUParam param) {
-        logger.info("zyp \n【判断添加客服】:{}",param);
+        logger.info("【判断添加客服】:{}",param);
         //查询用户
         FsUser fsUser = fsUserMapper.selectFsUserByUserId(param.getUserId());
         //用户不存在唤起重新授权
@@ -583,7 +618,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         log.setQwUserId(Long.valueOf(param.getQwUserId()));
         log.setCreateTime(new Date());
         log.setLogType(3);
-        logger.info("zyp \n【群聊生成看课记录】:{}",param);
+        logger.info("【群聊生成看课记录】:{}",param);
         courseWatchLogMapper.insertFsCourseWatchLog(log);
     }
 
@@ -778,7 +813,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     public R getInternetTraffic(FsUserCourseVideoFinishUParam param) {
         try {
             if (param.getBufferRate()==null){
-                logger.error("zyp \n【缓冲值空】参数: {}",param);
+                logger.error("【缓冲值空】参数: {}",param);
                 return R.error("缓冲值空");
             }
             FsCourseTrafficLog trafficLog = new FsCourseTrafficLog();
@@ -805,13 +840,13 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             // 处理 UUID 为空的情况
             if (StringUtils.isNotEmpty(trafficLog.getUuId())) {
                 // 直接插入或更新
-//                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
+//                logger.error("【插入或更新流量】:{}",trafficLog);
                 fsCourseTrafficLogMapper.insertOrUpdateTrafficLog(trafficLog);
             }
         } catch (Exception e) {
             e.printStackTrace();
             // 打印参数param和异常信息
-            logger.error("zyp \n【插入或更新流量失败】参数: {}, 错误信息:{}", param, e.getMessage(), e);
+            logger.error("【插入或更新流量失败】参数: {}, 错误信息:{}", param, e.getMessage(), e);
             return R.error();
         }
         return R.ok();
@@ -1047,13 +1082,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 try {
                     handleFsUserWx(user,param.getAppId());
                 }catch (Exception e){
-                    logger.error("zyp \n 【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId());
+                    logger.error("【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId());
                 }
             }else {
                 packetParam.setOpenId(fsUserWx.getOpenId());
             }
             //查出公司绑定openid并赋值
-
         }
 
         //判断服务号配置是否存在
@@ -1067,104 +1101,125 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         packetParam.setAppId(param.getAppId());
         packetParam.setUser(user);
 
-        System.out.println("红包金额"+amount);
-        System.out.println("红包商户号"+packetParam);
+        logger.info("红包金额 {},红包商户号 {}",amount,packetParam);
         //2025.6.19 红包金额为0的时候
         if (amount.compareTo(BigDecimal.ZERO)>0){
 
-//            Company company = companyMapper.selectCompanyByIdForUpdate(param.getCompanyId());
-           // BigDecimal money = company.getMoney();
-         //   BigDecimal subtract = money.subtract(amount);
-//            if (subtract.compareTo(BigDecimal.ZERO)<0){
-//                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-//                redPacketLog.setCourseId(param.getCourseId());
-//                redPacketLog.setCompanyId(param.getCompanyId());
-//                redPacketLog.setUserId(param.getUserId());
-//                redPacketLog.setVideoId(param.getVideoId());
-//                redPacketLog.setStatus(2);
-//                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-//                redPacketLog.setCompanyUserId(param.getCompanyUserId());
-//                redPacketLog.setCreateTime(new Date());
-//                redPacketLog.setAmount(amount);
-//                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-//                redPacketLog.setPeriodId(param.getPeriodId());
-//                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-//                return R.error("余额不足请稍等");
-//            }
-            // 发送红包
-            R sendRedPacket = paymentService.sendRedPacket(packetParam);
-            if (sendRedPacket.get("code").equals(200)) {
-                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                TransferBillsResult transferBillsResult;
-                if (sendRedPacket.get("isNew").equals(1)){
-                    transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
-                    redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
-                    redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                }else {
-                    redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+            //---------------发红包前先判断润天账户余额是否足够---------
+            RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
+            try{
+                boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
+
+                if (!locked) {
+                    logger.error("获取锁失败");
+                    return R.error("[红包领取] 系统繁忙,请重试!");
+                }
+
+                // 发送红包
+                return sendRedPacketRewardToUser(param, log, config, packetParam, amount);
+
+            }catch (Exception e){
+                logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
+                throw new RuntimeException(e);
+            }finally {
+                if (lock.isHeldByCurrentThread()) {
+                    lock.unlock();
                 }
-                // 添加红包记录
-                redPacketLog.setCourseId(param.getCourseId());
-//            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                redPacketLog.setCompanyId(param.getCompanyId());
-                redPacketLog.setUserId(param.getUserId());
-                redPacketLog.setVideoId(param.getVideoId());
-                redPacketLog.setStatus(0);
-                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-                redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                redPacketLog.setCreateTime(new Date());
-                redPacketLog.setAmount(amount);
-                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-                redPacketLog.setPeriodId(param.getPeriodId());
-                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-
-                // 更新观看记录的奖励类型
-                log.setRewardType(config.getRewardType());
-                courseWatchLogMapper.updateFsCourseWatchLog(log);
-//
-//                company.setMoney(subtract);
-//                companyMapper.updateCompany(company);
-//
-//                CompanyMoneyLogs logs=new CompanyMoneyLogs();
-//                logs.setCompanyId(company.getCompanyId());
-//                logs.setRemark("扣除红包金额");
-//                logs.setMoney(amount.multiply(new BigDecimal(-1)));
-//                logs.setLogsType(15);
-//                logs.setBalance(company.getMoney());
-//                logs.setCreateTime(new Date());
-//                moneyLogsMapper.insertCompanyMoneyLogs(logs);
-
-                return sendRedPacket;
-            } else {
-                return R.error("奖励发送失败,请联系客服");
             }
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
             redPacketLog.setCourseId(param.getCourseId());
-//            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+
             redPacketLog.setCompanyId(param.getCompanyId());
             redPacketLog.setUserId(param.getUserId());
             redPacketLog.setVideoId(param.getVideoId());
             redPacketLog.setStatus(0);
-            redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+            redPacketLog.setQwUserId(param.getQwUserId());
             redPacketLog.setCompanyUserId(param.getCompanyUserId());
             redPacketLog.setCreateTime(new Date());
             redPacketLog.setAmount(BigDecimal.ZERO);
-            redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+            redPacketLog.setWatchLogId(log.getLogId());
             redPacketLog.setPeriodId(param.getPeriodId());
             redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
 
             // 更新观看记录的奖励类型
-//            if (param.getLinkType() == null || param.getLinkType() == 0) {
             log.setRewardType(config.getRewardType());
             courseWatchLogMapper.updateFsCourseWatchLog(log);
-//            }
             return R.ok("红包发送成功");
         }
 
     }
 
+    private R sendRedPacketRewardToUser(FsCourseSendRewardUParam param, FsCourseWatchLog log, CourseConfig config, WxSendRedPacketParam packetParam, BigDecimal amount) {
+
+        BigDecimal companyMoney = null;
+        if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+            companyMoney = redisTemplate.opsForValue().get(REDPACKET_COMPANY_MONEY);
+
+            if(ObjectUtils.isNull(companyMoney)){
+                SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
+                if(ObjectUtils.isNull(sysConfig)){
+                    throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
+                }
+                String configValue = sysConfig.getConfigValue();
+                companyMoney = new BigDecimal(configValue);
+                logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
+            }
+
+            if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
+                logger.info("润天账户余额: {} 不足!", companyMoney);
+                return R.error("[红包领取] 账户余额不足,请联系管理员!");
+            }
+        }
+
+        // 发送红包
+        R sendRedPacket = paymentService.sendRedPacket(packetParam);
+        if (sendRedPacket.get("code").equals(200)) {
+            FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+            TransferBillsResult transferBillsResult;
+            if (sendRedPacket.get("isNew").equals(1)){
+                transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
+                redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+            }else {
+                redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+            }
+            // 添加红包记录
+            redPacketLog.setCourseId(param.getCourseId());
+            redPacketLog.setCompanyId(param.getCompanyId());
+            redPacketLog.setUserId(param.getUserId());
+            redPacketLog.setVideoId(param.getVideoId());
+            redPacketLog.setStatus(0);
+            redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+            redPacketLog.setCompanyUserId(param.getCompanyUserId());
+            redPacketLog.setCreateTime(new Date());
+            redPacketLog.setAmount(amount);
+            redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+            redPacketLog.setPeriodId(param.getPeriodId());
+            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                redPacketLog.setAccBalanceBefore(companyMoney);
+                redPacketLog.setAccBalanceAfter(companyMoney.subtract(amount));
+            }
+
+            redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+            // 更新观看记录的奖励类型
+            log.setRewardType(config.getRewardType());
+            courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+            if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                // 更新账户余额
+                logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
+
+                companyMoney = companyMoney.subtract(amount);
+                redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
+            }
+            return sendRedPacket;
+        } else {
+            return R.error("奖励发送失败,请联系客服");
+        }
+    }
+
 
     private void handleFsUserWx(FsUser user, String appId) {
         FsUserWx fsUserWx = new FsUserWx();
@@ -1177,7 +1232,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         fsUserWx.setUpdateTime(new Date());
         fsUserWxService.saveOrUpdateByUniqueKey(fsUserWx);
 
-        logger.info("zyp \n 【更新或插入用户与小程序{}的绑定关系】:{}", appId, user.getUserId());
+        logger.info("【更新或插入用户与小程序{}的绑定关系】:{}", appId, user.getUserId());
     }
 
     /**
@@ -1232,14 +1287,14 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
                 if (fsUserWx ==null){
                     if (user.getCourseMaOpenId()==null){
-                        logger.error("zyp \n 【转账openId参数错误】:{}", user.getUserId());
+                        logger.error(" 【转账openId参数错误】:{}", user.getUserId());
                         return R.error("openId参数错误,请清理缓存后重新授权!");
                     }
                     packetParam.setOpenId(user.getCourseMaOpenId());
                     try {
                         handleFsUserWx(user,param.getAppId());
                     }catch (Exception e){
-                        logger.error("zyp \n 【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId(),e);
+                        logger.error(" 【更新或插入用户与小程序的绑定关系失败】:{}", user.getUserId(),e);
                     }
 
                 }else {
@@ -1259,11 +1314,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         packetParam.setAppId(param.getAppId());
         packetParam.setUser(user);
 
-        System.out.println("红包金额"+amount);
-        System.out.println("红包商户号"+packetParam);
-//        if (ObjectUtils.isNotEmpty(config.getIsNegative())&&config.getIsNegative() == 1) {
-//            return processRedPacket(config, packetParam, param, amount, log);
-//        }
+        logger.info("红包金额 {},红包商户号 {}",amount,packetParam);
+
         //2025.6.19 红包金额为0的时候
         if (amount.compareTo(BigDecimal.ZERO)>0){
 
@@ -1272,42 +1324,93 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             if (money.compareTo(BigDecimal.ZERO)<0) {
                 return R.error("服务商余额不足,请联系群主服务器充值!");
             }
-            // 发送红包
-            R sendRedPacket = paymentService.sendRedPacket(packetParam);
-            if (sendRedPacket.get("code").equals(200)) {
-                FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-                TransferBillsResult transferBillsResult;
-                if (sendRedPacket.get("isNew").equals(1)){
-                    transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
-                    redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
-                    redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-                }else {
-                    redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-                    redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
+
+            //---------------发红包前先判断润天账户余额是否足够---------
+            RLock lock = redissonClient.getLock(REDPACKET_POOL_LOCK);
+            try{
+                boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
+
+                if (!locked) {
+                    logger.error("获取锁失败");
+                    return R.error("[红包领取] 系统繁忙,请重试!");
+                }
+
+                BigDecimal companyMoney = null;
+                if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                    companyMoney = redisTemplate.opsForValue().get(REDPACKET_COMPANY_MONEY);
+                    if(ObjectUtils.isNull(companyMoney)){
+                        SysConfig sysConfig = sysConfigService.selectConfigByConfigKey("company.money");
+                        if(ObjectUtils.isNull(sysConfig)){
+                            throw new IllegalArgumentException("润天公司账户余额不能为空!请检查配置!");
+                        }
+                        String configValue = sysConfig.getConfigValue();
+                        companyMoney = new BigDecimal(configValue);
+                        logger.info("缓存公司余额为空,从数据库读取 companyMoney: {}",companyMoney);
+                    }
+
+                    if (companyMoney.compareTo(BigDecimal.ZERO) <= 0) {
+                        logger.info("润天账户余额: {} 不足!", companyMoney);
+                        return R.error("[红包领取] 账户余额不足,请联系管理员!");
+                    }
+                }
+                // 发送红包
+                R sendRedPacket = paymentService.sendRedPacket(packetParam);
+                if (sendRedPacket.get("code").equals(200)) {
+                    FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
+                    TransferBillsResult transferBillsResult;
+                    if (sendRedPacket.get("isNew").equals(1)){
+                        transferBillsResult = (TransferBillsResult)sendRedPacket.get("data");
+                        redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
+                        redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
+                    }else {
+                        redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
+                        redPacketLog.setBatchId(sendRedPacket.get("batchId").toString());
+                    }
+                    // 添加红包记录
+                    redPacketLog.setCourseId(param.getCourseId());
+                    redPacketLog.setCompanyId(param.getCompanyId());
+                    redPacketLog.setUserId(param.getUserId());
+                    redPacketLog.setVideoId(param.getVideoId());
+                    redPacketLog.setStatus(0);
+                    redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
+                    redPacketLog.setCompanyUserId(param.getCompanyUserId());
+                    redPacketLog.setCreateTime(new Date());
+                    redPacketLog.setAmount(amount);
+                    redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
+                    redPacketLog.setPeriodId(param.getPeriodId());
+                    redPacketLog.setAppId(param.getAppId());
+                    if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                        redPacketLog.setAccBalanceBefore(companyMoney);
+                        redPacketLog.setAccBalanceAfter(companyMoney.subtract(amount));
+                    }
+                    redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+
+                    // 更新观看记录的奖励类型
+                    log.setRewardType(config.getRewardType());
+                    courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+
+                    if(StringUtils.equals(ENABLE_RED_PACK_ACCOUNT,"1")) {
+                        // 更新账户余额
+                        logger.info("[更新账户余额] 当前余额{} 更新后余额{}",companyMoney.toPlainString(),companyMoney.subtract(amount).toPlainString());
+
+                        companyMoney = companyMoney.subtract(amount);
+                        redisTemplate.opsForValue().set(REDPACKET_COMPANY_MONEY,companyMoney);
+                    }
+
+                    return sendRedPacket;
+                } else {
+                    return R.error("奖励发送失败,请联系客服");
+                }
+            }catch (Exception e){
+                logger.error("领取红包失败原因:{}", ExceptionUtils.getFullStackTrace(e),e);
+                throw new RuntimeException(e);
+            }finally {
+                if (lock.isHeldByCurrentThread()) {
+                    lock.unlock();
                 }
-                // 添加红包记录
-                redPacketLog.setCourseId(param.getCourseId());
-                redPacketLog.setCompanyId(param.getCompanyId());
-                redPacketLog.setUserId(param.getUserId());
-                redPacketLog.setVideoId(param.getVideoId());
-                redPacketLog.setStatus(0);
-                redPacketLog.setQwUserId(param.getQwUserId() != null ? param.getQwUserId() : null);
-                redPacketLog.setCompanyUserId(param.getCompanyUserId());
-                redPacketLog.setCreateTime(new Date());
-                redPacketLog.setAmount(amount);
-                redPacketLog.setWatchLogId(log.getLogId() != null ? log.getLogId() : null);
-                redPacketLog.setPeriodId(param.getPeriodId());
-                redPacketLog.setAppId(param.getAppId());
-                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-
-                // 更新观看记录的奖励类型
-                log.setRewardType(config.getRewardType());
-                courseWatchLogMapper.updateFsCourseWatchLog(log);
-
-                return sendRedPacket;
-            } else {
-                return R.error("奖励发送失败,请联系客服");
             }
+
         } else {
             FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
             // 添加红包记录
@@ -1334,93 +1437,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
     }
 
-    /**
-     * 直接发送奖励
-     *
-     * @param config
-     * @param packetParam
-     * @param param
-     * @param amount
-     * @param log
-     * @return
-     */
-    private R processRedPacket(CourseConfig config, WxSendRedPacketParam packetParam, FsCourseSendRewardUParam param, BigDecimal amount, FsCourseWatchLog log) {
-        R sendRedPacket = paymentService.sendRedPacket(packetParam);
-
-        if (!sendRedPacket.get("code").equals(200)) {
-            return R.error("奖励发送失败,请联系客服");
-        }
-
-        createRedPacketLog(sendRedPacket, param, amount, log);
-        updateWatchLogRewardType(log, config);
-
-        return sendRedPacket;
-    }
-
-    private void createRedPacketLog(R sendRedPacket, FsCourseSendRewardUParam param, BigDecimal amount, FsCourseWatchLog log) {
-        FsCourseRedPacketLog redPacketLog = new FsCourseRedPacketLog();
-
-        // Set common fields
-        redPacketLog.setCourseId(param.getCourseId());
-        redPacketLog.setCompanyId(param.getCompanyId());
-        redPacketLog.setUserId(param.getUserId());
-        redPacketLog.setVideoId(param.getVideoId());
-        redPacketLog.setStatus(0);
-        redPacketLog.setQwUserId(param.getQwUserId());
-        redPacketLog.setCompanyUserId(param.getCompanyUserId());
-        redPacketLog.setCreateTime(new Date());
-        redPacketLog.setAmount(amount);
-        redPacketLog.setWatchLogId(log != null ? log.getLogId() : null);
-        redPacketLog.setPeriodId(param.getPeriodId());
-        redPacketLog.setAppId(param.getAppId());
-
-        // Set batch number based on isNew flag
-        if (sendRedPacket.get("isNew").equals(1)) {
-            TransferBillsResult transferBillsResult = (TransferBillsResult) sendRedPacket.get("data");
-            redPacketLog.setResult(JSON.toJSONString(sendRedPacket));
-            redPacketLog.setOutBatchNo(transferBillsResult.getOutBillNo());
-        } else {
-            redPacketLog.setOutBatchNo(sendRedPacket.get("orderCode").toString());
-        }
-
-        redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-    }
-
-    private void updateWatchLogRewardType(FsCourseWatchLog log, CourseConfig config) {
-        if (log != null) {
-            log.setRewardType(config.getRewardType());
-            courseWatchLogMapper.updateFsCourseWatchLog(log);
-        }
-    }
-    /**
-     * 获取用户openId
-     *
-     * @param userId    用户ID
-     * @param companyId 公司ID
-     * @param source    来源 1公众号 2小程序
-     * @return openId
-     */
-    private String getOpenId(Long userId, Long companyId, Integer source) {
-        Company company = companyMapper.selectCompanyById(companyId);
-        String appId = source == 1 ? company.getCourseMaAppId() : company.getCourseMiniAppId();
-
-        // 公司配置为空时获取默认配置
-        if (StringUtils.isBlank(appId)) {
-            String json = configService.selectConfigByKey("course.config");
-            CourseConfig config = JSON.parseObject(json, CourseConfig.class);
-            appId = source == 1 ? config.getMpAppId() : config.getMiniprogramAppid();
-        }
-
-        // 查询openId
-        Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery().eq(FsUserWx::getFsUserId, userId).eq(FsUserWx::getAppId, appId);
-        FsUserWx fsUserWx = fsUserWxService.getOne(queryWrapper);
-        if (Objects.isNull(fsUserWx)) {
-            throw new CustomException("获取openId失败");
-        }
-
-        return fsUserWx.getOpenId();
-    }
-
     /**
      * 发放积分奖励
      *
@@ -2163,6 +2179,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }
         link.setProjectCode(cloudHostProper.getProjectCode());
 
+        link.setProjectCode(cloudHostProper.getProjectCode());
+
         String randomString = generateRandomStringWithLock();
         if (StringUtil.strIsNullOrEmpty(randomString)){
             link.setLink(UUID.randomUUID().toString().replace("-", ""));
@@ -2171,6 +2189,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         }
 
         link.setCreateTime(sendTime);
+        link.setProjectCode(cloudHostProper.getProjectCode());
 
         FsCourseRealLink courseMap = new FsCourseRealLink();
         BeanUtils.copyProperties(link,courseMap);
@@ -2608,7 +2627,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     public R getInternetTrafficIsOpen(FsUserCourseVideoFinishUParam param) {
         try {
             if (param.getBufferRate()==null){
-                logger.error("zyp \n【缓冲值空】参数: {}",param);
+                logger.error("【缓冲值空】参数: {}",param);
                 return R.error("缓冲值空");
             }
             FsCourseTrafficLog trafficLog = new FsCourseTrafficLog();
@@ -2629,13 +2648,13 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             // 处理 UUID 为空的情况
             if (StringUtils.isNotEmpty(trafficLog.getUuId())) {
                 // 直接插入或更新
-//                logger.error("zyp \n【插入或更新流量】:{}",trafficLog);
+//                logger.error("【插入或更新流量】:{}",trafficLog);
                 fsCourseTrafficLogMapper.insertOrUpdateTrafficLog(trafficLog);
             }
         } catch (Exception e) {
             e.printStackTrace();
             // 打印参数param和异常信息
-            logger.error("zyp \n【插入或更新流量失败】参数: {}, 错误信息:{}", param, e.getMessage(), e);
+            logger.error("【插入或更新流量失败】参数: {}, 错误信息:{}", param, e.getMessage(), e);
             return R.error();
         }
         return R.ok();
@@ -2651,7 +2670,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             log.setDuration(0L);
             log.setCreateTime(new Date());
             log.setLogType(3);
-            logger.info("zyp \n【群聊生成看课记录】:{}",param);
+            logger.info("【群聊生成看课记录】:{}",param);
             courseWatchLogMapper.insertFsCourseWatchLog(log);
         } catch (BeansException e) {
             return R.error("群聊生成看课记录失败!");

+ 63 - 6
fs-service/src/main/java/com/fs/course/service/impl/FsUserVipOrderServiceImpl.java

@@ -236,15 +236,39 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
         String json = configService.selectConfigByKey("his.pay");
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
-        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
-        if (StringUtils.isBlank(openId)){
+//        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+//        if (StringUtils.isBlank(openId)){
+//            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+//                    .eq(FsUserWx::getFsUserId, param.getUserId())
+//                    .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+//            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+//            if (Objects.nonNull(fsUserWx)){
+//                openId = fsUserWx.getOpenId();
+//            }
+//        }
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
             Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                     .eq(FsUserWx::getFsUserId, param.getUserId())
-                    .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+                    .eq(FsUserWx::getAppId, appId);
             FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
-            if (Objects.nonNull(fsUserWx)){
+            if (fsUserWx != null) {
                 openId = fsUserWx.getOpenId();
             }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
         }
 
         if(user!=null&& StringUtils.isNotEmpty(openId)) {
@@ -343,6 +367,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_MINIAPP");
                         o.setOpenid(openId);
+                        o.setAppId(appId);
                         o.setReqSeqId("appvip-" + storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
                         o.setGoodsDesc("会员开通订单支付");
@@ -350,6 +375,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                         FsStorePayment mt = new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }
@@ -371,14 +397,43 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
             return R.error("非法操作");
         }
         FsUser user = userMapper.selectFsUserByUserId(param.getUserId());
+
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+
         if(user!=null){
             if(order.getPayMoney().compareTo(new BigDecimal(0))==1){
                 String payCode =  OrderCodeUtils.getOrderSn();
                 if(StringUtils.isEmpty(payCode)){
                     return R.error("订单生成失败,请重试");
                 }
-                String json = configService.selectConfigByKey("his.pay");
-                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
                 storePayment.setPayMode(payConfigDTO.getType());
@@ -421,6 +476,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("A_NATIVE");
 //                        o.setOpenid(user.getMaOpenId());
+                        o.setAppId(appId);
                         o.setReqSeqId("appvip-"+storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
                         o.setGoodsDesc("会员开通订单支付");
@@ -428,6 +484,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                         FsStorePayment mt=new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }

+ 4 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/wangdian/api/WdtClient.java

@@ -26,6 +26,9 @@ public class WdtClient {
 	ConfigUtil configUtil;
 
 
+	private String getWarehouseNo() {
+		return configUtil.getErpConfig().getErpWarehouseCode();
+	}
 
 	private String getAppKey() {
 		return configUtil.getSysConfig().getErpWdAppKey();
@@ -135,6 +138,7 @@ public class WdtClient {
 		log.info("开始执行请求,相对路径:{},请求参数:{}", relativeUrl, params);
 
 
+		params.put("warehouse_no", getWarehouseNo());
 		params.put("appkey", appkey);
 		params.put("sid", sid);
 		params.put("timestamp", Long.toString(System.currentTimeMillis()/1000));

+ 1 - 1
fs-service/src/main/java/com/fs/erp/http/JstErpHttpServiceImpl.java

@@ -30,7 +30,7 @@ import java.util.Map;
 public class JstErpHttpServiceImpl implements JstErpHttpService {
 
     //正式
-    private static final String BASE_URL = "https://openapi.jushuitan.com/";
+    private static final String BASE_URL = "https://openapi.jushuitan.com";
     /**
      * 获取access_token、refresh_token url
      */

+ 23 - 7
fs-service/src/main/java/com/fs/erp/service/impl/K9OrderScrmServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.http.HttpUtil;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.fs.common.exception.ServiceException;
+import com.fs.common.utils.CloudHostUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
@@ -20,6 +21,7 @@ import com.fs.hisStore.dto.FsStoreCartDTO;
 import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
 import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
 import com.fs.hisStore.service.IFsStoreOrderItemScrmService;
+import com.fs.hisStore.vo.FsStoreOrderItemVO;
 import lombok.extern.slf4j.Slf4j;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -336,13 +338,27 @@ public class K9OrderScrmServiceImpl implements IErpOrderService {
 
     private List<KingbosOrderD1Data> buildOrderDetailData(FsStoreOrderScrm order, String orderId) {
         logger.debug("【金博网络订单】开始构建订单明细,订单号: {}", order.getOrderCode());
-        FsStoreOrderItemScrm query = new FsStoreOrderItemScrm();
-        query.setOrderId(order.getId());
-        List<FsStoreOrderItemScrm> orderItems = storeOrderItemService.selectFsStoreOrderItemList(query);
+//        FsStoreOrderItemScrm query = new FsStoreOrderItemScrm();
+//        query.setOrderId(order.getId());
+//        List<FsStoreOrderItemScrm> orderItems = storeOrderItemService.selectFsStoreOrderItemList(query);
+
+//        List<KingbosOrderD1Data> d1Datas = orderItems.stream()
+//                .map(item -> buildOrderDetailItem(item, orderId))
+//                .collect(Collectors.toList());
+
+
+        List<FsStoreOrderItemVO> orderItems = storeOrderItemService.selectFsStoreOrderItemListAndProductByOrderId(order.getId());
+        //2025.09.19 中康需求只推非药品
+        List<KingbosOrderD1Data> d1Datas = orderItems.stream().filter(item->{
+                    if (CloudHostUtils.hasCloudHostName("中康")){
+                        return item.getIsDrug() == null || item.getIsDrug() == 1;
+                    } else {
+                        return true;
+                    }
+                })
+                .map(item -> buildOrderDetailItem(item, orderId))
+                .collect(Collectors.toList());
 
-        List<KingbosOrderD1Data> d1Datas = orderItems.stream()
-            .map(item -> buildOrderDetailItem(item, orderId))
-            .collect(Collectors.toList());
 
         logger.debug("【金博网络订单】订单明细构建完成,订单号: {}, 明细数量: {}", order.getOrderCode(), d1Datas.size());
         return d1Datas;
@@ -355,7 +371,7 @@ public class K9OrderScrmServiceImpl implements IErpOrderService {
         return item;
     }
 
-    private KingbosOrderD1Data buildOrderDetailItem(FsStoreOrderItemScrm orderItem, String orderId) {
+    private KingbosOrderD1Data buildOrderDetailItem(FsStoreOrderItemVO orderItem, String orderId) {
         FsStoreCartDTO cartDTO = JSONUtil.toBean(orderItem.getJsonInfo(), FsStoreCartDTO.class);
         BigDecimal quantity = new BigDecimal(orderItem.getNum());
 

+ 2 - 2
fs-service/src/main/java/com/fs/erp/service/impl/WdtErpGoodsServiceImpl.java

@@ -99,8 +99,8 @@ public class WdtErpGoodsServiceImpl implements IErpGoodsService {
                 for (ErpWdtStockDTO stock : stocks) {
                     ErpGoodsStock erpGoodsStock = new ErpGoodsStock();
                     erpGoodsStock.setBarcode(barcode);
-                    erpGoodsStock.setQty(stock.getStock_num());
-                    erpGoodsStock.setSalable_qty(stock.getAvaliable_num());
+                    erpGoodsStock.setQty(stock.getStock_num().split("\\.")[0]); //999979.0000
+                    erpGoodsStock.setSalable_qty(stock.getAvaliable_num().split("\\.")[0]); //999976.0000
                     list.add(erpGoodsStock);
                 }
             } else {

+ 14 - 0
fs-service/src/main/java/com/fs/his/domain/FsStorePayment.java

@@ -97,6 +97,10 @@ public class FsStorePayment extends BaseEntity
     private Integer isShare;
 
 
+    //小程序appId
+    private String appId;
+
+
     public Integer getIsShare() {
         return isShare;
     }
@@ -307,6 +311,15 @@ public class FsStorePayment extends BaseEntity
         return storeId;
     }
 
+
+    public String getAppId() {
+        return appId;
+    }
+
+    public void setAppId(String appId) {
+        this.appId = appId;
+    }
+
     @Override
     public String toString() {
         return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
@@ -328,6 +341,7 @@ public class FsStorePayment extends BaseEntity
             .append("refundMoney", getRefundMoney())
             .append("refundTime", getRefundTime())
             .append("storeId", getStoreId())
+            .append("appId", getAppId())
             .toString();
     }
 }

+ 1 - 0
fs-service/src/main/java/com/fs/his/mapper/FsStorePaymentMapper.java

@@ -97,6 +97,7 @@ public interface FsStorePaymentMapper
             "            <if test=\"maps.refundEndTime != null \">  and DATE(sp.refund_time) &lt;= DATE(#{maps.refundEndTime})</if>\n" +
             "            <if test=\"maps.payBeginTime != null \">  and DATE(sp.pay_time) &gt;= DATE(#{maps.payBeginTime})</if>\n" +
             "            <if test=\"maps.payEndTime != null \">  and DATE(sp.pay_time) &lt;= DATE(#{maps.payEndTime})</if>\n" +
+            "            <if test=\"maps.appId != null and maps.appId != ''\">  and sp.app_id like #{maps.appId}</if>\n" +
             " ORDER BY payment_id desc  "+
             "</script>"})
     List<FsStorePaymentVO> selectFsStorePaymentListVO(@Param("maps")FsStorePaymentParam fsStorePayment);

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

@@ -116,4 +116,6 @@ public class FsStorePaymentParam extends BaseEntity {
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
 
+    private String appId;
+
 }

+ 105 - 11
fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java

@@ -1024,6 +1024,8 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         FsStorePayment mt=new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        //多小程序支付 更新小程序appid
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }
@@ -1107,6 +1109,31 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 }
                 String json = configService.selectConfigByKey("his.pay");
                 PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+                String openId = null;
+                String appId = param.getAppId();
+                if (StringUtils.isNotBlank(appId)) {
+                    //查询fs_user_wx的openId
+                    Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                            .eq(FsUserWx::getFsUserId, param.getUserId())
+                            .eq(FsUserWx::getAppId, appId);
+                    FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                    if (fsUserWx != null) {
+                        openId = fsUserWx.getOpenId();
+                    }
+                } else {
+                    appId = payConfigDTO.getAppId();
+                    openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+                    if (StringUtils.isBlank(openId)){
+                        Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                                .eq(FsUserWx::getFsUserId, param.getUserId())
+                                .eq(FsUserWx::getAppId, appId);
+                        FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                        if (Objects.nonNull(fsUserWx)){
+                            openId = fsUserWx.getOpenId();
+                        }
+                    }
+                }
+
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
                 storePayment.setPayMode(payConfigDTO.getType());
@@ -1155,11 +1182,14 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         o.setReqSeqId("package-"+storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
                         o.setGoodsDesc("套餐包订单支付");
+                        o.setAppId(appId);
+                        o.setOpenid(openId);
                         HuifuCreateOrderResult result = huiFuService.createOrder(o);
                         logger.info("创建汇付支付:"+result);
                         FsStorePayment mt=new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }
@@ -1185,10 +1215,39 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         }
         //如果存在优惠券  判断优惠券是否已使用
         FsUser user=userService.selectFsUserByUserId(param.getUserId());
-        if(user!=null&& StringUtils.isNotEmpty(user.getMpOpenId())){
+
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+//        if(user!=null&& StringUtils.isNotEmpty(user.getMpOpenId())){
+        if(user!=null&& StringUtils.isNotEmpty(openId)){
             if(fsPackageOrder.getPayMoney().compareTo(new BigDecimal(0))==1){
-                String json = configService.selectConfigByKey("his.pay");
-                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 String payCode =  OrderCodeUtils.getOrderSn();
                 if(StringUtils.isEmpty(payCode)){
                     return R.error("订单生成失败,请重试");
@@ -1205,7 +1264,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 storePayment.setCompanyId(fsPackageOrder.getCompanyId());
                 storePayment.setCompanyUserId(fsPackageOrder.getCompanyUserId());
                 storePayment.setRemark("套餐包订单支付");
-                storePayment.setOpenId(user.getMpOpenId());
+                storePayment.setOpenId(openId);
                 storePayment.setUserId(user.getUserId());
                 storePayment.setStoreId(fsPackageOrder.getStoreId());
                 storePayment.setBusinessId(fsPackageOrder.getOrderId().toString());
@@ -1223,7 +1282,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         }
                         o.setPayerName("微信用户"+phone);
                         o.setGoodsInfo("套餐包订单支付"); // 订单信息
-                        o.setOpenId(user.getMpOpenId());
+                        o.setOpenId(openId);
                         o.setOrderType(3);
                         o.setOrderId(fsPackageOrder.getOrderId().toString());
                         o.setPayType(Arrays.asList(PayType.WECHAT_PUBLIC_ACCOUNT.getCode()));
@@ -1237,7 +1296,8 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         logger.info("创建汇付订单");
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_JSAPI");
-                        o.setOpenid(user.getMpOpenId());
+                        o.setOpenid(openId);
+                        o.setAppId(appId);
                         o.setReqSeqId("package-"+storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
                         o.setGoodsDesc("套餐包订单支付");
@@ -1246,6 +1306,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         FsStorePayment mt=new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }
@@ -1272,14 +1333,44 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         }
         //如果存在优惠券  判断优惠券是否已使用
         FsUser user=userService.selectFsUserByUserId(param.getUserId());
+
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+
+        //金牛多小程序支付
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+
         if(user!=null){
             if(fsPackageOrder.getPayMoney().compareTo(new BigDecimal(0))==1){
                 String payCode =  OrderCodeUtils.getOrderSn();
                 if(StringUtils.isEmpty(payCode)){
                     return R.error("订单生成失败,请重试");
                 }
-                String json = configService.selectConfigByKey("his.pay");
-                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
                 storePayment.setPayMode(payConfigDTO.getType());
@@ -1292,7 +1383,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 storePayment.setCompanyId(fsPackageOrder.getCompanyId());
                 storePayment.setCompanyUserId(fsPackageOrder.getCompanyUserId());
                 storePayment.setRemark("套餐包订单支付");
-                storePayment.setOpenId(user.getMpOpenId());
+                storePayment.setOpenId(openId);
                 storePayment.setUserId(user.getUserId());
                 storePayment.setStoreId(fsPackageOrder.getStoreId());
                 storePayment.setBusinessId(fsPackageOrder.getOrderId().toString());
@@ -1311,7 +1402,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         }
                         o.setPayerName("微信用户"+phone);
                         o.setGoodsInfo("套餐包订单支付"); // 订单信息
-                        o.setOpenId(user.getMpOpenId());
+                        o.setOpenId(openId);
                         o.setOrderType(3);
                         o.setOrderId(fsPackageOrder.getOrderId().toString());
                         o.setPayType(Arrays.asList(PayType.ALIPAY_BARCODE_PAYMENT.getCode()));
@@ -1327,12 +1418,15 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         o.setTradeType("A_NATIVE");
                         o.setReqSeqId("package-"+storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
+                        o.setOpenid(openId);
+                        o.setAppId(appId);
                         o.setGoodsDesc("套餐包订单支付");
                         HuifuCreateOrderResult result = huiFuService.createOrder(o);
                         logger.info("创建汇付支付:"+result);
                         FsStorePayment mt=new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }
@@ -1402,7 +1496,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
             CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                 FsStorePayment fsStorePayment = fsStorePaymentMapper.selectLastByBusinessCode(vo.getOrderSn());
                 if (fsStorePayment != null) {
-                    vo.setBusinessCode("package-" + fsStorePayment.getBusinessCode());
+                    vo.setBusinessCode("package-" + fsStorePayment.getPayCode());
                 }
             });
             futures.add(future);

+ 47 - 9
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -2673,18 +2673,24 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         //在线支付
         String json = configService.selectConfigByKey("his.pay");
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
-        String openId = "";
-        if (StringUtils.isNotEmpty(param.getAppId())) {
-            FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), param.getUserId(), 1);
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
             if (fsUserWx != null) {
                 openId = fsUserWx.getOpenId();
             }
         } else {
+            appId = payConfigDTO.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                         .eq(FsUserWx::getFsUserId, param.getUserId())
-                        .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+                        .eq(FsUserWx::getAppId, appId);
                 FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
                 if (Objects.nonNull(fsUserWx)){
                     openId = fsUserWx.getOpenId();
@@ -2805,6 +2811,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                         FsStorePayment mt = new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }
@@ -2829,7 +2836,36 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         }
 
         FsUser user = userService.selectFsUserByUserId(param.getUserId());
-        if (user != null && StringUtils.isNotEmpty(user.getMaOpenId())) {
+
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+
+        if (user != null && StringUtils.isNotEmpty(openId)) {
 
             if (order.getPayMoney().compareTo(new BigDecimal(0)) == 0) {
                 IFsStoreOrderService fsStoreOrderService1 = (IFsStoreOrderService) AopContext.currentProxy();
@@ -2841,8 +2877,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 if (StringUtils.isEmpty(payCode)) {
                     return R.error("订单生成失败,请重试");
                 }
-                String json = configService.selectConfigByKey("his.pay");
-                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 FsStorePayment storePayment = new FsStorePayment();
                 storePayment.setStatus(0);
                 storePayment.setPayCode(payCode);
@@ -2853,7 +2889,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 storePayment.setPayTypeCode("alipay");
                 storePayment.setBusinessType(2);
                 storePayment.setRemark("药品订单支付");
-                storePayment.setOpenId(user.getMaOpenId());
+                storePayment.setOpenId(openId);
                 storePayment.setUserId(user.getUserId());
                 storePayment.setCompanyId(order.getCompanyId());
                 storePayment.setCompanyUserId(order.getCompanyUserId());
@@ -2885,7 +2921,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                     } else if (payConfigDTO.getType().equals("hf")) {
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("A_NATIVE");
-                        o.setOpenid(user.getMaOpenId());
+                        o.setOpenid(openId);
+                        o.setAppId(appId);
                         o.setReqSeqId("store-" + storePayment.getPayCode());
                         o.setTransAmt(storePayment.getPayMoney().toString());
                         o.setGoodsDesc("药品订单支付");
@@ -2893,6 +2930,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                         FsStorePayment mt = new FsStorePayment();
                         mt.setPaymentId(storePayment.getPaymentId());
                         mt.setTradeNo(result.getHf_seq_id());
+                        mt.setAppId(appId);
                         storePaymentService.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
                     }

+ 40 - 6
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -26,6 +26,7 @@ import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyConfigMapper;
 import com.fs.company.param.FsStoreStatisticsParam;
+import com.fs.company.service.ICompanyConfigService;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyUserService;
 import com.fs.company.vo.FsStorePaymentStatisticsVO;
@@ -115,6 +116,7 @@ import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.servlet.http.HttpServletRequest;
@@ -475,9 +477,11 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         return fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
     }
 
+    @Autowired
+    private ICompanyConfigService companyConfigService;
 
     @Override
-    @Transactional
+    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
     public R sendRedPacket(WxSendRedPacketParam param) {
 
         String json;
@@ -489,7 +493,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
                 config = JSONUtil.toBean(json, RedPacketConfig.class);
                 break;
             case 2:
-                json = companyConfigMapper.selectRedPacketConfigByKey(param.getCompanyId());
+                json = companyConfigService.selectRedPacketConfigByKey(param.getCompanyId());
                 config = JSONUtil.toBean(json, RedPacketConfig.class);
                 break;
         }
@@ -499,7 +503,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             String appId = StringUtils.isBlank(param.getAppId()) ? config.getMiniappId() : param.getAppId();
             config.setAppId(appId);
         }
-        System.out.println("最终传参"+config);
+        logger.info("最终传参 {}",config);
         //组合返回参数
         R result = new R();
         // 根据 isNew 判断使用哪种发红包方式
@@ -510,7 +514,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         }
         result.put("mchId",config.getMchId()+"");
         result.put("isNew",config.getIsNew());
-        System.out.println("红包返回:"+result);
+        logger.info("红包返回:{}",result);
         return result;
     }
 
@@ -1222,6 +1226,34 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         if (user==null){
             return R.error("用户不存在!");
         }
+
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = userWxMapper.selectOne(queryWrapper);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = userWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+
         Company company = companyService.selectCompanyById(param.getCompanyId());
         if (company==null || company.getStatus()==0){
             return R.error("服务商不存在,或已被停用!");
@@ -1252,22 +1284,24 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         storePayment.setPayTypeCode("weixin");
         storePayment.setBusinessType(1);
         storePayment.setRemark("商城收款订单支付");
-        storePayment.setOpenId(user.getMaOpenId());
+        storePayment.setOpenId(openId);
         storePayment.setUserId(user.getUserId());
         fsStorePaymentMapper.insertFsStorePayment(storePayment);
 
         //汇付支付
         HuiFuCreateOrder o = new HuiFuCreateOrder();
         o.setTradeType("T_MINIAPP");
-        o.setOpenid(user.getMaOpenId());
+        o.setOpenid(openId);
         o.setReqSeqId("payment-"+storePayment.getPayCode());
         o.setTransAmt(storePayment.getPayMoney().toString());
         o.setGoodsDesc("商城订单支付");
+        o.setAppId(appId);
         HuifuCreateOrderResult result = huiFuService.createOrder(o);
         if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
             FsStorePayment mt=new FsStorePayment();
             mt.setPaymentId(storePayment.getPaymentId());
             mt.setTradeNo(result.getHf_seq_id());
+            mt.setAppId(appId);
             fsStorePaymentMapper.updateFsStorePayment(mt);
             Map<String, Object> resultMap = com.alibaba.fastjson.JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {});
             String s = (String) resultMap.get("package");

+ 6 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserCouponServiceImpl.java

@@ -5,11 +5,13 @@ import java.util.List;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.SecurityUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.his.domain.FsCoupon;
 import com.fs.his.mapper.FsCouponMapper;
 import com.fs.his.param.FsUserCouponParam;
 import com.fs.his.param.FsUserCouponSendParam;
 import com.fs.his.param.FsUserCouponUParam;
+import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsUserCouponCountUVO;
 import com.fs.his.vo.FsUserCouponListUVO;
 import com.fs.his.vo.FsUserCouponListVO;
@@ -111,6 +113,10 @@ public class FsUserCouponServiceImpl implements IFsUserCouponService
 
     @Override
     public List<FsUserCouponListVO> selectFsUserCouponListVO(FsUserCouponParam fsUserCoupon) {
+        String phone = fsUserCoupon.getPhone();
+        if (StringUtils.isNotBlank(phone)){
+            fsUserCoupon.setPhone(PhoneUtil.encryptPhone(phone));
+        }
         return fsUserCouponMapper.selectFsUserCouponListVO(fsUserCoupon);
     }
 

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreOrderItemScrmMapper.java

@@ -72,6 +72,8 @@ public interface FsStoreOrderItemScrmMapper
     @Select("select * from fs_store_order_item_scrm where order_id=#{orderId}")
     List<FsStoreOrderItemVO> selectMyFsStoreOrderItemListByOrderId(Long id);
 
+    List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long id);
+
     @Select({"<script> " +
             "select i.*,o.user_id,o.status, o.real_name,o.user_phone,o.user_address,o.create_time,o.pay_time,o.delivery_sn,o.delivery_name,o.delivery_id, c.company_name ,cu.nick_name as company_user_nick_name ,cu.phonenumber as company_usere_phonenumber,o.upload_time ,CASE WHEN o.certificates IS NULL OR o.certificates = '' THEN 0 ELSE 1 END AS is_upload   " +
             " ,p.title as package_name,cts.name as scheduleName from fs_store_order_item_scrm i left join fs_store_order_scrm o on o.id=i.order_id left join fs_user u on o.user_id=u.user_id  " +

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreOrderItemScrmService.java

@@ -66,6 +66,8 @@ public interface IFsStoreOrderItemScrmService
 
     List<FsStoreOrderItemVO> selectFsStoreOrderItemListByOrderId(Long ordreId);
 
+    List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long orderId);
+
     List<FsStoreOrderItemExportVO> selectFsStoreOrderItemListExportVO(FsStoreOrderParam fsStoreOrder);
 
     Long countFsStoreOrderItemListExportVO(FsStoreOrderParam fsStoreOrder);

+ 1 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreCartScrmServiceImpl.java

@@ -232,6 +232,7 @@ public class FsStoreCartScrmServiceImpl implements IFsStoreCartScrmService
                 ErpGoodsStockQueryResponse goodsStock = goodsService.getGoodsStock(queryRequert);
                 if(goodsStock != null && goodsStock.getStocks() != null && !goodsStock.getStocks().isEmpty()){
 
+//                    int stocks = Double.valueOf(goodsStock.getStocks().get(0).getSalable_qty()).intValue();
                     int stocks = Integer.valueOf(goodsStock.getStocks().get(0).getSalable_qty());
 
                     if(stocks<=0){

+ 5 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderItemScrmServiceImpl.java

@@ -102,6 +102,11 @@ public class FsStoreOrderItemScrmServiceImpl implements IFsStoreOrderItemScrmSer
         return fsStoreOrderItemMapper.selectFsStoreOrderItemListByOrderId(ordreId);
     }
 
+    @Override
+    public List<FsStoreOrderItemVO> selectFsStoreOrderItemListAndProductByOrderId(Long orderId) {
+        return fsStoreOrderItemMapper.selectFsStoreOrderItemListAndProductByOrderId(orderId);
+    }
+
     @Override
     public List<FsStoreOrderItemExportVO> selectFsStoreOrderItemListExportVO(FsStoreOrderParam fsStoreOrder) {
         return fsStoreOrderItemMapper.selectFsStoreOrderItemListExportVO(fsStoreOrder);

+ 2 - 0
fs-service/src/main/java/com/fs/hisStore/vo/FsStoreOrderItemVO.java

@@ -46,4 +46,6 @@ public class FsStoreOrderItemVO  implements Serializable
     @Excel(name = "是否为处方")
     private Integer isPrescribe;
 
+    private Integer isDrug; //是否为药品
+
 }

+ 1 - 1
fs-service/src/main/java/com/fs/qw/mapper/QwUserMapper.java

@@ -154,7 +154,7 @@ public interface QwUserMapper extends BaseMapper<QwUser>
             "            <if test=\"qwUserId != null  and qwUserId != ''\"> and qu.qw_user_id = #{qwUserId}</if>\n" +
             "            <if test=\"appKey != null  and appKey != ''\"> and qu.app_key = #{appKey}</if>\n" +
             "            <if test=\"nickName != null  and nickName != ''\"> and cu.nick_name like concat( #{nickName}, '%') </if>\n" +
-            "            <if test=\"qwUserName != null  and qwUserName != ''\"> and qu.qw_user_name like concat( #{qwUserName}, '%') </if> " +
+            "            <if test=\"qwUserName != null  and qwUserName != ''\"> and qu.qw_user_name like concat('%', #{qwUserName}, '%') </if> " +
             "            <if test=\"corpId != null \"> and qu.corp_id = #{corpId}</if>\n" +
             "            <if test=\"companyId != null \"> and qu.company_id = #{companyId}</if>\n " +
             "            <if test=\"cuDeptIdList != null and !cuDeptIdList.isEmpty() and  userType != '00' \">" +

+ 41 - 14
fs-service/src/main/java/com/fs/qw/service/impl/QwUserVoiceLogServiceImpl.java

@@ -22,10 +22,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -133,23 +130,53 @@ public class QwUserVoiceLogServiceImpl extends ServiceImpl<QwUserVoiceLogMapper,
         if(list != null && !list.isEmpty()){
             List<CompanyUser> companyUserList = companyUserMapper.selectCompanyUserByIds(list);
 
-            qwUserVoiceLogTotalVos.forEach(m-> {
-                companyUserList.forEach(n-> {
-                    if(m.getCompanyUserId() != null && n.getUserId() != null && m.getCompanyUserId().equals(n.getUserId())){
-                        m.setCompanyUserName(n.getNickName());
+            // 优化:使用Map提高查找效率,避免双重循环
+            Map<Long, CompanyUser> companyUserMap = companyUserList.stream()
+                    .collect(Collectors.toMap(CompanyUser::getUserId, user -> user, (existing, replacement) -> existing));
+
+            // 如果有部门过滤条件,则预先过滤用户列表
+            if (qwUserVoiceLog.getDeptId() != null) {
+                companyUserMap.entrySet().removeIf(entry ->
+                        entry.getValue().getDeptId() == null ||
+                                !entry.getValue().getDeptId().equals(qwUserVoiceLog.getDeptId()));
+            }
+
+            // 设置用户姓名和部门ID
+            qwUserVoiceLogTotalVos.forEach(logVo -> {
+                CompanyUser user = companyUserMap.get(logVo.getCompanyUserId());
+                if (user != null) {
+                    logVo.setCompanyUserName(user.getNickName());
+                    if (user.getDeptId() != null) {
+                        logVo.setDeptId(user.getDeptId());
                     }
-                });
+                }
             });
+
+            // 如果有部门过滤条件,过滤掉没有部门ID的记录
+            if (qwUserVoiceLog.getDeptId() != null) {
+                qwUserVoiceLogTotalVos = qwUserVoiceLogTotalVos.stream()
+                        .filter(m -> m.getDeptId() != null)
+                        .collect(Collectors.toList());
+            }
         }
+
         List<QwCompany> companyList = qwCompanyService.selectQwCompanyList(new QwCompany());
-        qwUserVoiceLogTotalVos.forEach(m -> companyList.forEach(n ->{
-            if(m.getCorpId().equals(n.getCorpId())){
-                m.setCorpName(n.getCorpName());
+        // 优化:使用Map提高查找效率
+        Map<String, String> corpIdToNameMap = companyList.stream()
+                .collect(Collectors.toMap(QwCompany::getCorpId, QwCompany::getCorpName, (existing, replacement) -> existing));
+
+        qwUserVoiceLogTotalVos.forEach(m -> {
+            String corpName = corpIdToNameMap.get(m.getCorpId());
+            if (corpName != null) {
+                m.setCorpName(corpName);
             }
-        }));
+        });
+
         String companyUserName = qwUserVoiceLog.getCompanyUserName();
         if(companyUserName != null && !companyUserName.isEmpty()){
-            qwUserVoiceLogTotalVos = qwUserVoiceLogTotalVos.stream().filter(n -> n.getCompanyUserName().contains(companyUserName)).collect(Collectors.toList());
+            qwUserVoiceLogTotalVos = qwUserVoiceLogTotalVos.stream()
+                    .filter(n -> n.getCompanyUserName() != null && n.getCompanyUserName().contains(companyUserName))
+                    .collect(Collectors.toList());
         }
         return qwUserVoiceLogTotalVos;
     }

+ 49 - 0
fs-service/src/main/java/com/fs/qw/vo/QwUserVoiceLogTotalVo.java

@@ -8,12 +8,17 @@ import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import lombok.EqualsAndHashCode;
 
+import java.util.List;
+
 @EqualsAndHashCode(callSuper = true)
 public class QwUserVoiceLogTotalVo extends BaseEntity {
 
     /** id */
     private Long id;
 
+
+
+
     @Excel(name = "客服名称")
     private String companyUserName;
 
@@ -63,6 +68,9 @@ public class QwUserVoiceLogTotalVo extends BaseEntity {
     //@Excel(name = "客服用户id")
     private Long companyUserId;
 
+
+    private Long[] companyUserIds;
+
     //接通数量
     @Excel(name = "接通数量")
     private Long connectCount;
@@ -78,6 +86,30 @@ public class QwUserVoiceLogTotalVo extends BaseEntity {
 
     private QwUser qwUser;
 
+
+    private Long deptId;
+
+
+    private List<String> tagIds;
+
+    private List<String> tagIdsName;
+
+    public List<String> getTagIds() {
+        return tagIds;
+    }
+
+    public void setTagIds(List<String> tagIds) {
+        this.tagIds = tagIds;
+    }
+
+    public List<String> getTagIdsName() {
+        return tagIdsName;
+    }
+
+    public void setTagIdsName(List<String> tagIdsName) {
+        this.tagIdsName = tagIdsName;
+    }
+
     public String getCorpName() {
         return corpName;
     }
@@ -198,6 +230,15 @@ public class QwUserVoiceLogTotalVo extends BaseEntity {
         this.companyUserId = companyUserId;
     }
 
+
+    public Long[] getCompanyUserIds() {
+        return companyUserIds;
+    }
+
+    public void setCompanyUserIds(Long[] companyUserIds) {
+        this.companyUserIds = companyUserIds;
+    }
+
     public String getCompanyUserName() {
         return companyUserName;
     }
@@ -237,4 +278,12 @@ public class QwUserVoiceLogTotalVo extends BaseEntity {
     public void setQwUser(QwUser qwUser) {
         this.qwUser = qwUser;
     }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
 }

+ 5 - 0
fs-service/src/main/java/com/fs/qw/vo/QwUserVoiceLogVo.java

@@ -44,6 +44,9 @@ public class QwUserVoiceLogVo extends BaseEntity {
     @Excel(name = "接听状态,1接听 2未接")
     private Integer status;
 
+    /** 部门id */
+    private Long deptId;
+
     /** 企微id */
     @Excel(name = "企微id")
     private String corpId;
@@ -59,6 +62,8 @@ public class QwUserVoiceLogVo extends BaseEntity {
     //@Excel(name = "销售用户id")
     private Long companyUserId;
 
+    private Long[] companyUserIds;
+
     @Excel(name = "销售用户名称")
     private String companyUserName;
 

+ 22 - 8
fs-service/src/main/java/com/fs/system/service/impl/SysConfigServiceImpl.java

@@ -14,8 +14,10 @@ import com.fs.system.service.ISysConfigService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import javax.annotation.PostConstruct;
+import javax.annotation.concurrent.ThreadSafe;
 import java.util.Collection;
 import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * 参数配置 服务层实现
@@ -23,6 +25,7 @@ import java.util.List;
 
  */
 @Service
+@ThreadSafe
 public class SysConfigServiceImpl implements ISysConfigService
 {
     @Autowired
@@ -31,6 +34,7 @@ public class SysConfigServiceImpl implements ISysConfigService
     @Autowired
     private RedisCache redisCache;
 
+    private static final ConcurrentHashMap<String, Object> KEY_LOCKS = new ConcurrentHashMap<>();
     /**
      * 项目启动时,初始化参数到缓存
      */
@@ -69,15 +73,25 @@ public class SysConfigServiceImpl implements ISysConfigService
         {
             return configValue;
         }
-        SysConfig config = new SysConfig();
-        config.setConfigKey(configKey);
-        SysConfig retConfig = configMapper.selectConfig(config);
-        if (StringUtils.isNotNull(retConfig))
-        {
-            redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
-            return retConfig.getConfigValue();
+        Object keyLock = KEY_LOCKS.computeIfAbsent(configKey, k -> new Object());
+
+        synchronized (keyLock){
+            configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey)));
+            if (StringUtils.isNotEmpty(configValue))
+            {
+                return configValue;
+            }
+
+            SysConfig config = new SysConfig();
+            config.setConfigKey(configKey);
+            SysConfig retConfig = configMapper.selectConfig(config);
+            if (StringUtils.isNotNull(retConfig))
+            {
+                redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
+                return retConfig.getConfigValue();
+            }
+            return StringUtils.EMPTY;
         }
-        return StringUtils.EMPTY;
     }
 
     /**

+ 2 - 0
fs-service/src/main/resources/application-config-druid-qdtst.yml

@@ -93,3 +93,5 @@ ipad:
 wx_miniapp_temp:
   pay_order_temp_id:
   inquiry_temp_id:
+
+enableRedPackAccount: 1

+ 2 - 0
fs-service/src/main/resources/application-druid-kyt.yml

@@ -147,3 +147,5 @@ openIM:
   userID: im
 #是否为新商户,新商户不走mpOpenId
 isNewWxMerchant: true
+
+enableRedPackAccount: 1

+ 1 - 1
fs-service/src/main/resources/application-druid-qdtst.yml

@@ -167,4 +167,4 @@ openIM:
     secret:
     userID:
 #是否为新商户,新商户不走mpOpenId
-isNewWxMerchant: true
+isNewWxMerchant: false

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

@@ -110,6 +110,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="result != null">result,</if>
             <if test="batchId != null">batch_id,</if>
             <if test="appId != null">app_id,</if>
+            <if test="accBalanceBefore != null">acc_balance_before,</if>
+            <if test="accBalanceAfter != null">acc_balance_after,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="courseId != null">#{courseId},</if>
@@ -129,6 +131,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="result != null">#{result},</if>
             <if test="batchId != null">#{batchId},</if>
             <if test="appId != null">#{appId},</if>
+            <if test="accBalanceBefore != null">#{accBalanceBefore},</if>
+            <if test="accBalanceAfter != null">#{accBalanceAfter},</if>
         </trim>
     </insert>
 

+ 7 - 0
fs-service/src/main/resources/mapper/course/FsCourseWatchLogMapper.xml

@@ -829,4 +829,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         order by l.finish_time desc,l.update_time desc,l.create_time desc
     </select>
 
+    <select id="getUserCountByCampId" resultType="java.lang.Integer">
+        select count(distinct cwl.user_id)
+        from fs_user_course_period ucp
+        inner join fs_course_watch_log cwl on ucp.period_id = cwl.period_id
+        where ucp.training_camp_id = #{trainingCampId}
+    </select>
+
 </mapper>

+ 4 - 3
fs-service/src/main/resources/mapper/course/FsUserCourseTrainingCampMapper.xml

@@ -11,11 +11,12 @@
         ctc.training_camp_name,
         ctc.order_number,
         min(if(ctp.period_starting_time >= CURDATE(), ctp.period_starting_time, null)) as recent_date,
-        count(distinct ctp.period_id) as period_count,
-        count(distinct cu.user_id)  as vip_count
+        count(distinct ctp.period_id) as period_count
         from fs_user_course_training_camp ctc
         left join fs_user_course_period ctp on ctc.training_camp_id = ctp.training_camp_id
-        left join fs_course_watch_log cu on cu.period_id = ctp.period_id
+        <if test="params.userId != null and params.userId != ''">
+            left join fs_course_watch_log cu on cu.period_id = ctp.period_id
+        </if>
         <where>
             ctc.del_flag ='0'
             <if test="params.trainingCampName != null and params.trainingCampName != ''">

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

@@ -367,6 +367,7 @@
         where course.is_del = 0 and video.video_id = #{videoId}
          and fcp.period_id = #{periodId}
         and fcpd.del_flag = 0 and video.is_del = 0 and fcp.del_flag = '0' and c.del_flag = '0'
+        limit 1
     </select>
 
     <select id="selectFsUserCourseVideoByVideoIdAndUserId" resultMap="FsUserCourseVideoResult">

+ 9 - 1
fs-service/src/main/resources/mapper/his/FsStorePaymentMapper.xml

@@ -31,10 +31,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="shareCode"    column="share_code"    />
         <result property="shareMoney"    column="share_money"    />
         <result property="isShare"    column="is_share"    />
+        <result property="appId"    column="app_id"    />
     </resultMap>
 
     <sql id="selectFsStorePaymentVo">
-        select payment_id, pay_code,is_share,share_status,share_code,share_money,business_code,pay_mode, pay_type_code,company_id,company_user_id, pay_money, pay_time, create_time, trade_no, user_id, open_id, business_type, business_id, status, remark, bank_transaction_id, bank_serial_no, refund_money, refund_time, store_id from fs_store_payment
+        select payment_id, pay_code,is_share,share_status,share_code,share_money,business_code,pay_mode, pay_type_code,company_id,company_user_id, pay_money, pay_time, create_time, trade_no, user_id, open_id, business_type, business_id, status, remark, bank_transaction_id, bank_serial_no, refund_money, refund_time, store_id,app_id from fs_store_payment
     </sql>
 
     <select id="selectFsStorePaymentList" parameterType="FsStorePayment" resultMap="FsStorePaymentResult">
@@ -56,6 +57,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="refundTime != null "> and refund_time = #{refundTime}</if>
             <if test="storeId != null "> and store_id = #{storeId}</if>
             <if test="businessCode != null "> and business_code = #{businessCode}</if>
+            <if test="appId != null and appId !=''"> and app_id = #{appId}</if>
         </where>
     </select>
 
@@ -92,6 +94,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="shareCode != null">share_code,</if>
             <if test="shareMoney != null">share_money,</if>
             <if test="isShare != null">is_share,</if>
+            <if test="appId != null">app_id,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="payCode != null">#{payCode},</if>
@@ -119,6 +122,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="shareCode != null">#{shareCode},</if>
             <if test="shareMoney != null">#{shareMoney},</if>
             <if test="isShare != null">#{isShare},</if>
+            <if test="appId != null">#{appId},</if>
          </trim>
     </insert>
 
@@ -150,6 +154,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="shareCode != null">share_code = #{shareCode},</if>
             <if test="shareMoney != null">share_money = #{shareMoney},</if>
             <if test="isShare != null">is_share = #{isShare},</if>
+            <if test="appId != null">app_id = #{appId},</if>
         </trim>
         where payment_id = #{paymentId}
     </update>
@@ -260,6 +265,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test="maps.payEndTime != null ">
             and DATE(sp.pay_time) &lt;= DATE(#{maps.payEndTime})
         </if>
+        <if test="maps.appId != null and maps.appId != '' ">
+            and sp.app_id like #{maps.appId}
+        </if>
     </select>
     <select id="selectLastByBusinessCode" resultType="com.fs.his.domain.FsStorePayment">
         select * from fs_store_payment where business_code like #{orderSn} order by create_time desc limit 1

+ 4 - 8
fs-service/src/main/resources/mapper/his/FsUserMapper.xml

@@ -1854,11 +1854,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             and u.is_del = 0
             AND (u.nickname IS NOT NULL or u.nick_name IS NOT NULL)
             <if test = "maps.nickname != null and  maps.nickname !='' " >
-                AND (
-                     u.nickname LIKE CONCAT("%",#{maps.nickname},"%")
-                    or
-                    u.nick_name LIKE CONCAT("%",#{maps.nickname},"%")
-                )
+                AND u.nick_name LIKE CONCAT("%",#{maps.nickname},"%")
             </if >
             <if test = "maps.userId != null and  maps.userId !='' " >
                 AND u.user_id = #{maps.userId}
@@ -1867,15 +1863,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                 AND u.phone LIKE CONCAT("%",#{maps.phone},"%")
             </if >
             <if test = "maps.startCreateTime != null and maps.endCreateTime != null" >
-                AND (DATE_FORMAT( u.create_time, "%Y-%m-%d" ) &gt;= DATE_FORMAT(#{maps.startCreateTime}, "%Y-%m-%d")
-                and DATE_FORMAT( u.create_time, "%Y-%m-%d" ) &lt;= DATE_FORMAT(#{maps.endCreateTime}, "%Y-%m-%d")
+                AND (DATE_FORMAT( ucu.create_time, "%Y-%m-%d" ) &gt;= DATE_FORMAT(#{maps.startCreateTime}, "%Y-%m-%d")
+                and DATE_FORMAT( ucu.create_time, "%Y-%m-%d" ) &lt;= DATE_FORMAT(#{maps.endCreateTime}, "%Y-%m-%d")
                 )
             </if >
             <if test = "maps.registerCode != null  and  maps.registerCode !=''  " >
                 AND u.register_code = #{maps.registerCode}
             </if >
             <if test = "maps.status != null" >
-                AND u.STATUS = #{maps.status}
+                AND ucu.status = #{maps.status}
             </if >
             <if test = "maps.companyId != null and maps.companyId != '' " >
                 AND company.company_id = #{maps.companyId}

+ 12 - 6
fs-service/src/main/resources/mapper/hisStore/FsStoreOrderItemScrmMapper.xml

@@ -3,7 +3,7 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.hisStore.mapper.FsStoreOrderItemScrmMapper">
-    
+
     <resultMap type="FsStoreOrderItemScrm" id="FsStoreOrderItemResult">
         <result property="itemId"    column="item_id"    />
         <result property="orderId"    column="order_id"    />
@@ -22,7 +22,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 
     <select id="selectFsStoreOrderItemList" parameterType="FsStoreOrderItemScrm" resultMap="FsStoreOrderItemResult">
         <include refid="selectFsStoreOrderItemVo"/>
-        <where>  
+        <where>
             <if test="orderId != null "> and order_id = #{orderId}</if>
             <if test="orderCode != null  and orderCode != ''"> and order_code = #{orderCode}</if>
             <if test="cartId != null "> and cart_id = #{cartId}</if>
@@ -33,12 +33,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="isPrescribe != null "> and is_prescribe = #{isPrescribe}</if>
         </where>
     </select>
-    
+
     <select id="selectFsStoreOrderItemById" parameterType="Long" resultMap="FsStoreOrderItemResult">
         <include refid="selectFsStoreOrderItemVo"/>
         where item_id = #{itemId}
     </select>
-        
+    <select id="selectFsStoreOrderItemListAndProductByOrderId"
+            resultType="com.fs.hisStore.vo.FsStoreOrderItemVO">
+        select i.*,p.is_drug from fs_store_order_item_scrm i
+                 left join fs_store_product_scrm p on i.product_id = p.product_id
+                 where i.order_id=#{orderId}
+    </select>
+
     <insert id="insertFsStoreOrderItem" parameterType="FsStoreOrderItemScrm" useGeneratedKeys="true" keyProperty="itemId">
         insert into fs_store_order_item_scrm
         <trim prefix="(" suffix=")" suffixOverrides=",">
@@ -88,5 +94,5 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             #{itemId}
         </foreach>
     </delete>
-    
-</mapper>
+
+</mapper>

+ 17 - 3
fs-service/src/main/resources/mapper/qw/QwUserVoiceLogMapper.xml

@@ -79,6 +79,11 @@
             <if test="companyId != null "> and c.company_id = #{companyId}</if>
             <if test="companyName != null "> and c.company_name like concat(#{companyName}, '%')</if>
             <if test="companyUserId != null "> and cu.user_id = #{companyUserId}</if>
+            <if test="companyUserId == null and companyUserIds != null and companyUserIds.length > 0"> and cu.user_id in
+                <foreach collection="companyUserIds" item="userId" open="(" separator="," close=")">
+                    #{userId}
+                </foreach>
+            </if>
             <if test="companyUserName != null  and companyUserName != ''"> and cu.user_name like concat(#{companyUserName}, '%')</if>
             <if test="beginTime != null and endTime != null">
                 AND date_format(uvl.create_time,'%Y-%m-%d') &gt;= #{beginTime}
@@ -92,16 +97,25 @@
         where id = #{id}
     </select>
     <select id="selectQwUserVoiceLogTotalList" resultMap="QwUserVoiceLogVoTotalResult">
-
-        SELECT
-        SUM(duration) duration,qu.qw_user_name,uvl.corp_id,qu.qw_user_id,uvl.company_user_id,
+        SELECT uvl.id, ext_id, uvl.qw_user_id, duration, title, uvl.status, uvl.corp_id,
+               uvl.company_id, uvl.company_user_id, uvl.create_time,qec.`name`,qec.tag_ids,qu.qw_user_name,
+        SUM(duration) duration,
         COUNT(CASE WHEN uvl.status=1 THEN 1 END) AS connectCount,
         COUNT(CASE WHEN uvl.status=2 THEN 1 END) AS noConnectCount
         FROM qw_user_voice_log uvl
         LEFT JOIN qw_user qu ON uvl.qw_user_id = qu.id
+        left join qw_external_contact qec on uvl.ext_id = qec.id
+
         <where>
             <if test="companyId != null ">and uvl.company_id = #{companyId}</if>
             <if test="companyUserId != null ">and uvl.company_user_id = #{companyUserId}</if>
+            <if test="tagIds != null">
+                and
+                <foreach collection="tagIds" item="tagId" separator="and">
+                    <!-- 使用JSON_CONTAINS检查JSON数组中是否包含指定元素 -->
+                    JSON_CONTAINS(qec.tag_ids, CONCAT('"', #{tagId}, '"'))
+                </foreach>
+            </if>
             <if test="qwUserName != null ">and qu.qw_user_name like concat(#{qwUserName}, '%')</if>
             <if test="beginTime != null and endTime != null">
                 AND date_format(uvl.create_time,'%Y-%m-%d') &gt;= #{beginTime}

+ 1 - 1
fs-service/src/main/resources/mapper/store/FsUserCourseCountMapper.xml

@@ -194,7 +194,7 @@
         FROM fs_course_watch_log
         left join fs_user_company_user ucu on ucu.user_id = fs_course_watch_log.user_id
         WHERE fs_course_watch_log.send_type = 1
-          AND fs_course_watch_log.create_time >= DATE_SUB( CURDATE(), INTERVAL 7 DAY ) and fs_course_watch_log.project = ucu.project_id
+          AND fs_course_watch_log.create_time >= DATE_SUB( CURDATE(), INTERVAL 15 DAY ) and fs_course_watch_log.project = ucu.project_id
         GROUP BY
             fs_course_watch_log.user_id, date(fs_course_watch_log.create_time),ucu.project_id
     </select>

+ 68 - 11
fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

@@ -245,23 +245,48 @@ public class InquiryOrderController extends  AppBaseController {
     public R payment(HttpServletRequest request, @Validated @RequestBody FsInquiryOrderDoPayParam param)
     {
         Long userId = Long.parseLong(getUserId());
-
+        param.setUserId(userId);
         FsUser user = userService.selectFsUserByUserId(userId);
         //在线支付
         String json = configService.selectConfigByKey("his.pay");
         PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
-        String openId = "";
-        if (StringUtils.isNotEmpty(param.getAppId())) {
-            FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), param.getUserId(), 1);
+//        String openId = "";
+//        if (StringUtils.isNotEmpty(param.getAppId())) {
+//            FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), param.getUserId(), 1);
+//            if (fsUserWx != null) {
+//                openId = fsUserWx.getOpenId();
+//            }
+//        } else {
+//            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+//            if (StringUtils.isBlank(openId)){
+//                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+//                        .eq(FsUserWx::getFsUserId, param.getUserId())
+//                        .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+//                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+//                if (Objects.nonNull(fsUserWx)){
+//                    openId = fsUserWx.getOpenId();
+//                }
+//            }
+//        }
+
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
             if (fsUserWx != null) {
                 openId = fsUserWx.getOpenId();
             }
         } else {
+            appId = payConfigDTO.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                         .eq(FsUserWx::getFsUserId, param.getUserId())
-                        .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+                        .eq(FsUserWx::getAppId, appId);
                 FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
                 if (Objects.nonNull(fsUserWx)){
                     openId = fsUserWx.getOpenId();
@@ -270,7 +295,7 @@ public class InquiryOrderController extends  AppBaseController {
         }
         //String json=configService.selectConfigByKey("his.pay");
         //PayConfigDTO payConfigDTO= JSONUtil.toBean(json, PayConfigDTO.class);
-        param.setUserId(Long.parseLong(getUserId()));
+
         FsInquiryOrder order=inquiryOrderService.selectFsInquiryOrderByOrderId(param.getOrderId());
 
         //FsUser user=userService.selectFsUserByUserId(Long.parseLong(getUserId()));
@@ -320,7 +345,7 @@ public class InquiryOrderController extends  AppBaseController {
                     WxPayConfig payConfig = new WxPayConfig();
                     SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
                     FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                    payConfig.setAppId(fsPayConfig.getAppId());
+                    payConfig.setAppId(appId);
                     payConfig.setMchId(fsPayConfig.getWxMchId());
                     payConfig.setMchKey(fsPayConfig.getWxMchKey());
                     payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -396,6 +421,7 @@ public class InquiryOrderController extends  AppBaseController {
                     HuiFuCreateOrder o = new HuiFuCreateOrder();
                     o.setTradeType("T_MINIAPP");
                     o.setOpenid(openId);
+                    o.setAppId(appId);
                     o.setReqSeqId("inquiry-"+storePayment.getPayCode());
                     o.setTransAmt(storePayment.getPayMoney().toString());
                     o.setGoodsDesc("问诊订单支付");
@@ -403,6 +429,7 @@ public class InquiryOrderController extends  AppBaseController {
                     FsStorePayment mt=new FsStorePayment();
                     mt.setPaymentId(storePayment.getPaymentId());
                     mt.setTradeNo(result.getHf_seq_id());
+                    mt.setAppId(appId);
                     storePaymentService.updateFsStorePayment(mt);
                     return R.ok().put("isPay",0).put("data",result).put("type","hf");
                 }
@@ -424,6 +451,34 @@ public class InquiryOrderController extends  AppBaseController {
         FsInquiryOrder order=inquiryOrderService.selectFsInquiryOrderByOrderId(param.getOrderId());
         FsUser user=userService.selectFsUserByUserId(Long.parseLong(getUserId()));
 
+        String json = configService.selectConfigByKey("his.pay");
+        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+
+        String openId = null;
+        String appId = param.getAppId();
+        if (StringUtils.isNotBlank(appId)) {
+            //查询fs_user_wx的openId
+            Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                    .eq(FsUserWx::getFsUserId, param.getUserId())
+                    .eq(FsUserWx::getAppId, appId);
+            FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+            if (fsUserWx != null) {
+                openId = fsUserWx.getOpenId();
+            }
+        } else {
+            appId = payConfigDTO.getAppId();
+            openId = Objects.isNull(user) ? "" : user.getMaOpenId();
+            if (StringUtils.isBlank(openId)){
+                Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                        .eq(FsUserWx::getFsUserId, param.getUserId())
+                        .eq(FsUserWx::getAppId, appId);
+                FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+                if (Objects.nonNull(fsUserWx)){
+                    openId = fsUserWx.getOpenId();
+                }
+            }
+        }
+
         if(order.getPayMoney().compareTo(new BigDecimal(0))==0){
             inquiryOrderService.payConfirm(order.getOrderSn(),"","","",2,null,null);
             return R.ok().put("isPay",1);
@@ -433,8 +488,8 @@ public class InquiryOrderController extends  AppBaseController {
             if(StringUtils.isEmpty(payCode)){
                 return R.error("订单生成失败,请重试");
             }
-            String json = configService.selectConfigByKey("his.pay");
-            PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+//            String json = configService.selectConfigByKey("his.pay");
+//            PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
             FsStorePayment storePayment=new FsStorePayment();
             storePayment.setStatus(0);
             storePayment.setPayMode(payConfigDTO.getType());
@@ -447,7 +502,7 @@ public class InquiryOrderController extends  AppBaseController {
             storePayment.setPayTypeCode("支付宝");
             storePayment.setBusinessType(1);
             storePayment.setRemark("问诊订单支付");
-            storePayment.setOpenId(user.getMaOpenId());
+            storePayment.setOpenId(openId);
             storePayment.setUserId(user.getUserId());
             storePayment.setBusinessId(order.getOrderId().toString());
             if(storePaymentService.insertFsStorePayment(storePayment)>0){
@@ -476,14 +531,16 @@ public class InquiryOrderController extends  AppBaseController {
                 }else if (payConfigDTO.getType().equals("hf")) {
                     HuiFuCreateOrder o = new HuiFuCreateOrder();
                     o.setTradeType("A_NATIVE");
-                    o.setOpenid(user.getMaOpenId());
+                    o.setOpenid(openId);
                     o.setReqSeqId("inquiry-"+storePayment.getPayCode());
                     o.setTransAmt(storePayment.getPayMoney().toString());
                     o.setGoodsDesc("问诊订单支付");
+                    o.setAppId(appId);
                     HuifuCreateOrderResult result = huiFuService.createOrder(o);
                     FsStorePayment mt=new FsStorePayment();
                     mt.setPaymentId(storePayment.getPaymentId());
                     mt.setTradeNo(result.getHf_seq_id());
+                    mt.setAppId(appId);
                     storePaymentService.updateFsStorePayment(mt);
                     return R.ok().put("isPay",0).put("data",result).put("type","hf");
                 }

+ 1 - 1
fs-user-app/src/main/java/com/fs/app/controller/course/CourseQwController.java

@@ -222,7 +222,7 @@ public class CourseQwController extends AppBaseController {
     public R sendReward(@RequestBody FsCourseSendRewardUParam param)
     {
         param.setUserId(Long.parseLong(getUserId()));
-        logger.info("zyp \n【发放奖励】:{}",param);
+        logger.info("【发放奖励】:{}",param);
         return courseVideoService.sendReward(param);
     }
 

+ 4 - 4
fs-user-app/src/main/java/com/fs/app/controller/store/CourseH5ScrmController.java

@@ -146,9 +146,9 @@ public class CourseH5ScrmController extends AppBaseController {
     public R courseAnswer(@RequestBody FsCourseQuestionAnswerUParam param)
     {
         param.setUserId(Long.parseLong(getUserId()));
-        logger.info("zyp \n【答题】:{}",param.getQuestions());
+        logger.info("【答题】:{}",param.getQuestions());
         if (param.getDuration()==null){
-            logger.info("zyp \n【未识别到时长】:{}",param.getUserId());
+            logger.info("【未识别到时长】:{}",param.getUserId());
         }
         return questionBankService.courseAnswer(param, false);
     }
@@ -159,13 +159,13 @@ public class CourseH5ScrmController extends AppBaseController {
     public R sendReward(@RequestBody FsCourseSendRewardUParam param)
     {
         param.setUserId(Long.parseLong(getUserId()));
-        logger.info("zyp \n【发放奖励】:{}",param);
+        logger.info("【发放奖励】:{}",param);
         return courseVideoService.sendReward(param);
     }
 
     @PostMapping("/getErrMsg")
     public void getErrMsg(@RequestParam("msg") String msg) {
-        logger.error("zyp \n【h5看课中途报错】:{}",msg);
+        logger.error("【h5看课中途报错】:{}",msg);
     }
 
 }

+ 2 - 2
fs-user-app/src/main/java/com/fs/app/controller/store/CourseWxH5ScrmController.java

@@ -121,14 +121,14 @@ public class CourseWxH5ScrmController extends AppBaseController {
     public R sendReward(@RequestBody FsCourseSendRewardUParam param)
     {
         param.setUserId(Long.parseLong(getUserId()));
-        logger.info("zyp \n【发放奖励】:{}",param);
+        logger.info("【发放奖励】:{}",param);
         return courseVideoService.sendRewardByFsUser(param);
     }
 
 
     @PostMapping("/getErrMsg")
     public void getErrMsg(@RequestParam("msg") String msg) {
-        logger.error("zyp \n【h5看课中途报错】:{}",msg);
+        logger.error("【h5看课中途报错】:{}",msg);
     }
 
 

+ 18 - 0
fs-user-app/src/main/java/com/fs/framework/config/RedisConfig.java

@@ -19,6 +19,7 @@ import org.springframework.data.redis.serializer.GenericToStringSerializer;
 import org.springframework.data.redis.serializer.RedisSerializationContext;
 import org.springframework.data.redis.serializer.StringRedisSerializer;
 
+import java.math.BigDecimal;
 import java.time.Duration;
 
 /**
@@ -86,7 +87,24 @@ public class RedisConfig extends CachingConfigurerSupport
         template.afterPropertiesSet();
         return template;
     }
+    @Bean
+    public RedisTemplate<String, BigDecimal> redisTemplateForBigDecimal(RedisConnectionFactory connectionFactory) {
+        RedisTemplate<String, BigDecimal> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+
+        // 使用GenericToStringSerializer保证BigDecimal精度不丢失
+        template.setValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
 
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(new GenericToStringSerializer<>(BigDecimal.class));
+
+        template.afterPropertiesSet();
+        return template;
+    }
     @Bean
     @SuppressWarnings(value = { "unchecked", "rawtypes" })
     public RedisTemplate<String, Object> redisTemplateForObject(RedisConnectionFactory connectionFactory) {

+ 2 - 1
fs-user-app/src/main/resources/application.yml

@@ -11,5 +11,6 @@ spring:
 #    active: druid-yzt
 #    active: druid-hdt
 #    active: druid-sxjz
+    active: druid-qdtst
 #    active: druid-yzt
-    active: druid-jnmy-test
+#    active: druid-jnmy-test