xgb 2 недель назад
Родитель
Сommit
10ff09b8b1

+ 97 - 0
fs-admin/src/main/java/com/fs/company/controller/CompanyRedPacketBalanceLogsController.java

@@ -0,0 +1,97 @@
+package com.fs.company.controller;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyRedPacketBalanceLogs;
+import com.fs.company.service.ICompanyRedPacketBalanceLogsService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 企业红包余额记录Controller
+ *
+ * @author fs
+ * @date 2025-11-19
+ */
+@RestController
+@RequestMapping("/company/companyRedPacketBalanceLogs")
+public class CompanyRedPacketBalanceLogsController extends BaseController
+{
+    @Autowired
+    private ICompanyRedPacketBalanceLogsService companyRedPacketBalanceLogsService;
+
+    /**
+     * 查询企业红包余额记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRedPacketBalanceLogs:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs)
+    {
+        startPage();
+        List<CompanyRedPacketBalanceLogs> list = companyRedPacketBalanceLogsService.selectCompanyRedPacketBalanceLogsList(companyRedPacketBalanceLogs);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出企业红包余额记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRedPacketBalanceLogs:export')")
+    @Log(title = "企业红包余额记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs)
+    {
+        List<CompanyRedPacketBalanceLogs> list = companyRedPacketBalanceLogsService.selectCompanyRedPacketBalanceLogsList(companyRedPacketBalanceLogs);
+        ExcelUtil<CompanyRedPacketBalanceLogs> util = new ExcelUtil<CompanyRedPacketBalanceLogs>(CompanyRedPacketBalanceLogs.class);
+        return util.exportExcel(list, "企业红包余额记录数据");
+    }
+
+    /**
+     * 获取企业红包余额记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRedPacketBalanceLogs:query')")
+    @GetMapping(value = "/{logsId}")
+    public AjaxResult getInfo(@PathVariable("logsId") Long logsId)
+    {
+        return AjaxResult.success(companyRedPacketBalanceLogsService.selectCompanyRedPacketBalanceLogsByLogsId(logsId));
+    }
+
+    /**
+     * 新增企业红包余额记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRedPacketBalanceLogs:add')")
+    @Log(title = "企业红包余额记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs)
+    {
+        return toAjax(companyRedPacketBalanceLogsService.insertCompanyRedPacketBalanceLogs(companyRedPacketBalanceLogs));
+    }
+
+    /**
+     * 修改企业红包余额记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRedPacketBalanceLogs:edit')")
+    @Log(title = "企业红包余额记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs)
+    {
+        return toAjax(companyRedPacketBalanceLogsService.updateCompanyRedPacketBalanceLogs(companyRedPacketBalanceLogs));
+    }
+
+    /**
+     * 删除企业红包余额记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyRedPacketBalanceLogs:remove')")
+    @Log(title = "企业红包余额记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{logsIds}")
+    public AjaxResult remove(@PathVariable Long[] logsIds)
+    {
+        return toAjax(companyRedPacketBalanceLogsService.deleteCompanyRedPacketBalanceLogsByLogsIds(logsIds));
+    }
+}

+ 51 - 7
fs-admin/src/main/java/com/fs/his/task/CompanyBalanceTask.java

@@ -1,13 +1,15 @@
 package com.fs.his.task;
 package com.fs.his.task;
 
 
+import com.fs.common.core.domain.R;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.company.service.ICompanyService;
-import com.fs.company.vo.RedPacketMoneyVO;
 import com.fs.course.service.BalanceRollbackErrorService;
 import com.fs.course.service.BalanceRollbackErrorService;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 
 
-import java.util.List;
+import java.util.Date;
 
 
 /**
 /**
  * @description: 公司余额同步定时任务 (红包余额)
  * @description: 公司余额同步定时任务 (红包余额)
@@ -16,6 +18,7 @@ import java.util.List;
  * @version: 1.0
  * @version: 1.0
  */
  */
 @Component("companyBalanceTask")
 @Component("companyBalanceTask")
+@Slf4j
 public class CompanyBalanceTask {
 public class CompanyBalanceTask {
 
 
 
 
@@ -62,15 +65,27 @@ public class CompanyBalanceTask {
     }
     }
 
 
     /**
     /**
-     * @Description: 红包余额回滚(回滚的是客户没领取的红包),红包记录表中,两天没领取的记录不会再发送
+     * @Description: 优化成回滚前查询记录,一笔一笔回滚
      * @Param: 每天0点执行一次
      * @Param: 每天0点执行一次
      * @Return:
      * @Return:
      * @Author xgb
      * @Author xgb
      * @Date 2025/11/7 9:48
      * @Date 2025/11/7 9:48
      */
      */
-    public void rollbackRedPacketMoney() throws Exception {
-        // 这个地方真加的是company money字段 xgb 红包余额独立后这个方法弃用
-        companyService.rollbackRedPacketMoney();
+    public void rollbackRedPacketMoney(String time) throws Exception {
+        // 默认是前两天时间
+        String createSTime;
+        String createETime;
+        if (StringUtils.isNotBlank(time)) {
+            Date date = DateUtils.parseDate(time);
+            createSTime = time+" 00:00:00";
+            createETime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,DateUtils.addDays(date, 1))+" 00:00:00";
+        } else {
+            createSTime = DateUtils.parseDateToStr( DateUtils.YYYY_MM_DD,DateUtils.addDays(new Date(), -2))+" 00:00:00";
+            createETime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,DateUtils.addDays(new Date(), -1))+" 00:00:00";
+        }
+
+        // 这个地方真加的是company money字段 xgb
+        companyService.rollbackRedPacketMoney(createSTime, createETime);
     }
     }
 
 
     /**
     /**
@@ -86,6 +101,35 @@ public class CompanyBalanceTask {
 
 
 
 
 
 
+    /**
+     * @Description: 更具批次号查询转账结果
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/12/25 10:31
+     */
+    public void checkMchTransferStatus(String outBatchNo,String companyIdStr) {
+        Long companyId=Long.parseLong(companyIdStr);
+        String result=companyService.checkMchTransferStatus(outBatchNo,companyId);
+        log.info("查询商户转账结果:{}",result);
+    }
+
+
+
+    /**
+     * @Description: 更具批次号查询转账结果
+     * @Param:
+     * @Return:
+     * @Author xgb
+     * @Date 2025/12/25 10:31
+     */
+    public void checkMchTransferStatusByBatchID(String batchId,String companyIdStr) {
+        Long companyId=Long.parseLong(companyIdStr);
+        R result=companyService.checkMchTransferStatusByBatchID(batchId,companyId);
+        log.info("查询商户转账结果:{}",result);
+    }
+
+
 
 
 
 
 }
 }

+ 48 - 0
fs-service/src/main/java/com/fs/company/domain/CompanyRedPacketBalanceLogs.java

@@ -0,0 +1,48 @@
+package com.fs.company.domain;
+
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 企业红包余额记录对象 company_red_packet_balance_logs
+ *
+ * @author fs
+ * @date 2025-11-19
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CompanyRedPacketBalanceLogs extends BaseEntity{
+
+    /** ID */
+    private Long logsId;
+
+    /** 企业ID */
+    @Excel(name = "企业ID")
+    private Long companyId;
+
+    // 企业名称
+    private String companyName;
+
+    /** 金额 */
+    @Excel(name = "金额")
+    private BigDecimal money;
+
+    /** 余额 */
+    @Excel(name = "余额")
+    private BigDecimal balance;
+
+    /** 类型 字典字段 */
+    @Excel(name = "类型")
+    private Integer logsType;
+
+    /** 是否处理状态(0-初始化,1-已同步(收到红包回调)) */
+    private Long status;
+
+    // 红包日志id
+    private Long redPacketId;
+
+}

+ 3 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyRechargeMapper.java

@@ -84,6 +84,9 @@ public interface CompanyRechargeMapper
             "<if test = 'maps.payType != null  '> " +
             "<if test = 'maps.payType != null  '> " +
             "and r.pay_type = #{maps.payType}" +
             "and r.pay_type = #{maps.payType}" +
             "</if>" +
             "</if>" +
+            "<if test = 'maps.businessType != null  '> " +
+            "and r.business_type = #{maps.businessType}" +
+            "</if>" +
             "<if test= 'maps.params != null and maps.params !=\"\"'>"+
             "<if test= 'maps.params != null and maps.params !=\"\"'>"+
             "<if test = 'maps.params.beginTime != null and maps.params.beginTime != \"\" '> " +
             "<if test = 'maps.params.beginTime != null and maps.params.beginTime != \"\" '> " +
             "and date_format(r.pay_time,'%y%m%d') &gt;= date_format(#{maps.params.beginTime},'%y%m%d') " +
             "and date_format(r.pay_time,'%y%m%d') &gt;= date_format(#{maps.params.beginTime},'%y%m%d') " +

+ 70 - 0
fs-service/src/main/java/com/fs/company/mapper/CompanyRedPacketBalanceLogsMapper.java

@@ -0,0 +1,70 @@
+package com.fs.company.mapper;
+
+import java.util.Date;
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyRedPacketBalanceLogs;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 企业红包余额记录Mapper接口
+ *
+ * @author fs
+ * @date 2025-11-19
+ */
+public interface CompanyRedPacketBalanceLogsMapper extends BaseMapper<CompanyRedPacketBalanceLogs>{
+    /**
+     * 查询企业红包余额记录
+     *
+     * @param logsId 企业红包余额记录主键
+     * @return 企业红包余额记录
+     */
+    CompanyRedPacketBalanceLogs selectCompanyRedPacketBalanceLogsByLogsId(Long logsId);
+
+    /**
+     * 查询企业红包余额记录列表
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 企业红包余额记录集合
+     */
+    List<CompanyRedPacketBalanceLogs> selectCompanyRedPacketBalanceLogsList(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs);
+
+    /**
+     * 新增企业红包余额记录
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 结果
+     */
+    int insertCompanyRedPacketBalanceLogs(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs);
+
+    /**
+     * 修改企业红包余额记录
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 结果
+     */
+    int updateCompanyRedPacketBalanceLogs(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs);
+
+    /**
+     * 删除企业红包余额记录
+     *
+     * @param logsId 企业红包余额记录主键
+     * @return 结果
+     */
+    int deleteCompanyRedPacketBalanceLogsByLogsId(Long logsId);
+
+    /**
+     * 批量删除企业红包余额记录
+     *
+     * @param logsIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteCompanyRedPacketBalanceLogsByLogsIds(Long[] logsIds);
+
+    Company getCompanyRedPacketBalance(Long companyId);
+
+    void updateCompanyRedPacketBalanceLogsByRedPacketId(CompanyRedPacketBalanceLogs redLogs);
+
+    List<CompanyRedPacketBalanceLogs> selectCompanyRedPacketBalanceLogsListByStatus(@Param("createSTime") String createSTime,@Param("createETime") String createETime);
+}

+ 65 - 0
fs-service/src/main/java/com/fs/company/service/ICompanyRedPacketBalanceLogsService.java

@@ -0,0 +1,65 @@
+package com.fs.company.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyRedPacketBalanceLogs;
+
+import java.util.List;
+
+/**
+ * 企业红包余额记录Service接口
+ *
+ * @author fs
+ * @date 2025-11-19
+ */
+public interface ICompanyRedPacketBalanceLogsService extends IService<CompanyRedPacketBalanceLogs>{
+    /**
+     * 查询企业红包余额记录
+     *
+     * @param logsId 企业红包余额记录主键
+     * @return 企业红包余额记录
+     */
+    CompanyRedPacketBalanceLogs selectCompanyRedPacketBalanceLogsByLogsId(Long logsId);
+
+    /**
+     * 查询企业红包余额记录列表
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 企业红包余额记录集合
+     */
+    List<CompanyRedPacketBalanceLogs> selectCompanyRedPacketBalanceLogsList(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs);
+
+    /**
+     * 新增企业红包余额记录
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 结果
+     */
+    int insertCompanyRedPacketBalanceLogs(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs);
+
+    /**
+     * 修改企业红包余额记录
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 结果
+     */
+    int updateCompanyRedPacketBalanceLogs(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs);
+
+    /**
+     * 批量删除企业红包余额记录
+     *
+     * @param logsIds 需要删除的企业红包余额记录主键集合
+     * @return 结果
+     */
+    int deleteCompanyRedPacketBalanceLogsByLogsIds(Long[] logsIds);
+
+    /**
+     * 删除企业红包余额记录信息
+     *
+     * @param logsId 企业红包余额记录主键
+     * @return 结果
+     */
+    int deleteCompanyRedPacketBalanceLogsByLogsId(Long logsId);
+
+    Company getCompanyRedPacketBalance(Long companyId);
+}

+ 5 - 3
fs-service/src/main/java/com/fs/company/service/ICompanyService.java

@@ -172,7 +172,7 @@ public interface ICompanyService
 
 
     void redPacketTopUpCompany(Long companyId, BigDecimal money,String type);
     void redPacketTopUpCompany(Long companyId, BigDecimal money,String type);
 
 
-    void asyncRecordBalanceLog(Long companyId, BigDecimal money,Integer logType, BigDecimal balance, String remark);
+    void asyncRecordBalanceLog(Long companyId, BigDecimal money, Integer logType, BigDecimal balance, String remark, Long logId);
 
 
     void recordRedPacketBalance();
     void recordRedPacketBalance();
 
 
@@ -182,7 +182,9 @@ public interface ICompanyService
      */
      */
     void batchUpdateCompany(List<Company> list);
     void batchUpdateCompany(List<Company> list);
 
 
-    void rollbackRedPacketMoney();
+    void rollbackRedPacketMoney(String createSTime, String createETime);
 
 
-    Company selectCompanyByStoreId(Long storeId);
+    String checkMchTransferStatus(String outBatchNo,Long companyId);
+
+    R checkMchTransferStatusByBatchID(String batchId, Long companyId);
 }
 }

+ 99 - 0
fs-service/src/main/java/com/fs/company/service/impl/CompanyRedPacketBalanceLogsServiceImpl.java

@@ -0,0 +1,99 @@
+package com.fs.company.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.domain.CompanyRedPacketBalanceLogs;
+import com.fs.company.mapper.CompanyRedPacketBalanceLogsMapper;
+import com.fs.company.service.ICompanyRedPacketBalanceLogsService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 企业红包余额记录Service业务层处理
+ *
+ * @author fs
+ * @date 2025-11-19
+ */
+@Service
+public class CompanyRedPacketBalanceLogsServiceImpl extends ServiceImpl<CompanyRedPacketBalanceLogsMapper, CompanyRedPacketBalanceLogs> implements ICompanyRedPacketBalanceLogsService {
+
+    /**
+     * 查询企业红包余额记录
+     *
+     * @param logsId 企业红包余额记录主键
+     * @return 企业红包余额记录
+     */
+    @Override
+    public CompanyRedPacketBalanceLogs selectCompanyRedPacketBalanceLogsByLogsId(Long logsId)
+    {
+        return baseMapper.selectCompanyRedPacketBalanceLogsByLogsId(logsId);
+    }
+
+    /**
+     * 查询企业红包余额记录列表
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 企业红包余额记录
+     */
+    @Override
+    public List<CompanyRedPacketBalanceLogs> selectCompanyRedPacketBalanceLogsList(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs)
+    {
+        return baseMapper.selectCompanyRedPacketBalanceLogsList(companyRedPacketBalanceLogs);
+    }
+
+    /**
+     * 新增企业红包余额记录
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 结果
+     */
+    @Override
+    public int insertCompanyRedPacketBalanceLogs(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs)
+    {
+        companyRedPacketBalanceLogs.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertCompanyRedPacketBalanceLogs(companyRedPacketBalanceLogs);
+    }
+
+    /**
+     * 修改企业红包余额记录
+     *
+     * @param companyRedPacketBalanceLogs 企业红包余额记录
+     * @return 结果
+     */
+    @Override
+    public int updateCompanyRedPacketBalanceLogs(CompanyRedPacketBalanceLogs companyRedPacketBalanceLogs)
+    {
+        return baseMapper.updateCompanyRedPacketBalanceLogs(companyRedPacketBalanceLogs);
+    }
+
+    /**
+     * 批量删除企业红包余额记录
+     *
+     * @param logsIds 需要删除的企业红包余额记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyRedPacketBalanceLogsByLogsIds(Long[] logsIds)
+    {
+        return baseMapper.deleteCompanyRedPacketBalanceLogsByLogsIds(logsIds);
+    }
+
+    /**
+     * 删除企业红包余额记录信息
+     *
+     * @param logsId 企业红包余额记录主键
+     * @return 结果
+     */
+    @Override
+    public int deleteCompanyRedPacketBalanceLogsByLogsId(Long logsId)
+    {
+        return baseMapper.deleteCompanyRedPacketBalanceLogsByLogsId(logsId);
+    }
+
+    @Override
+    public Company getCompanyRedPacketBalance(Long companyId) {
+        return baseMapper.getCompanyRedPacketBalance(companyId);
+    }
+}

+ 238 - 33
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -12,16 +12,18 @@ import com.alibaba.fastjson.JSON;
 import com.fs.common.constant.FsConstants;
 import com.fs.common.constant.FsConstants;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.*;
 import com.fs.company.domain.*;
 import com.fs.company.mapper.*;
 import com.fs.company.mapper.*;
 import com.fs.company.param.CompanyParam;
 import com.fs.company.param.CompanyParam;
-import com.fs.company.service.ICompanyMiniappService;
-import com.fs.company.service.ICompanyProfitService;
-import com.fs.company.service.ICompanyRoleService;
+import com.fs.company.service.*;
 import com.fs.company.vo.*;
 import com.fs.company.vo.*;
+import com.fs.course.config.CourseConfig;
+import com.fs.course.config.RedPacketConfig;
+import com.fs.course.domain.FsCourseRedPacketLog;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.his.domain.FsInquiryOrder;
 import com.fs.his.domain.FsInquiryOrder;
@@ -37,6 +39,14 @@ import com.fs.store.config.CompanyMenuConfig;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.system.service.ISysConfigService;
 import com.fs.system.service.ISysConfigService;
+import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesRequest;
+import com.github.binarywang.wxpay.bean.transfer.QueryTransferBatchesResult;
+import com.github.binarywang.wxpay.bean.transfer.TransferBillsGetResult;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.TransferService;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageHelper;
 import com.google.gson.Gson;
 import com.google.gson.Gson;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.CollectionUtils;
@@ -45,10 +55,10 @@ import org.redisson.api.RLock;
 import org.redisson.api.RedissonClient;
 import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
-import com.fs.company.service.ICompanyService;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.support.TransactionTemplate;
 import org.springframework.transaction.support.TransactionTemplate;
 
 
@@ -114,6 +124,156 @@ public class CompanyServiceImpl implements ICompanyService
     @Autowired
     @Autowired
     private TransactionTemplate transactionTemplate;
     private TransactionTemplate transactionTemplate;
 
 
+    @Autowired
+    private CompanyRedPacketBalanceLogsMapper companyRedPacketBalanceLogsMapper;
+
+    @Autowired
+    private ICompanyConfigService companyConfigService;
+
+    @Override
+    public String checkMchTransferStatus(String outBatchNo,Long companyId) {
+
+        // 查看红包发送配置
+        String json = configService.selectConfigByKey("course.config");
+        CourseConfig courseConfig = JSONUtil.toBean(json, CourseConfig.class);
+        RedPacketConfig config;
+        switch (courseConfig.getRedPacketMode()){// 1-总配置 2- 分公司配置
+            case 1:
+                json = configService.selectConfigByKey("redPacket.config");
+                config = JSONUtil.toBean(json, RedPacketConfig.class);
+                break;
+            case 2:
+                json = companyConfigService.selectRedPacketConfigByKey(companyId);
+                //如果分公司配置为空就走总后台的配置
+                if (StringUtils.isEmpty(json)){
+                    json = configService.selectConfigByKey("redPacket.config");
+                }
+                config = JSONUtil.toBean(json, RedPacketConfig.class);
+                break;
+            default:
+                throw new UnsupportedOperationException("当前红包模式不支持!");
+        }
+
+        WxPayConfig payConfig = new WxPayConfig();
+        BeanUtils.copyProperties(config, payConfig);
+
+        WxPayService wxPayService = new WxPayServiceImpl();
+        wxPayService.setConfig(payConfig);
+
+        TransferService transferService = wxPayService.getTransferService();
+
+        if (Objects.isNull(config.getIsNew()) || !Arrays.asList(0,1).contains(config.getIsNew())) {
+            logger.error("红包配置错误 isNew is err");
+            throw new CustomException("红包配置错误 isNew is err ");
+        }
+
+        try {
+            if (config.getIsNew() == 0) {
+                QueryTransferBatchesRequest request = new QueryTransferBatchesRequest();
+                request.setOutBatchNo(outBatchNo);
+                request.setNeedQueryDetail(true);
+                request.setOffset(0);
+                request.setLimit(20);
+                request.setDetailStatus("ALL");
+                QueryTransferBatchesResult result = transferService.transferBatchesOutBatchNo(request);
+                List<QueryTransferBatchesResult.TransferDetail> detailList = result.getTransferDetailList();
+                boolean isSuccess = detailList.stream().anyMatch(d -> "SUCCESS".equals(d.getDetailStatus()));
+                if (isSuccess) {
+                    return result.getTransferBatch().getBatchId();
+                }
+
+                boolean isFail = detailList.stream().anyMatch(d -> "FAIL".equals(d.getDetailStatus()));
+                if (isFail) {
+                    return "";
+                }
+            } else {
+                TransferBillsGetResult result = transferService.getBillsByOutBillNo(outBatchNo);
+                if ("SUCCESS".equals(result.getState())) {
+                    return result.getTransferBillNo();
+                } else if ("FAIL".equals(result.getState())) {
+                    return "";
+                } else if ("CANCELLED".equals(result.getState())) {
+                    return "";
+                }
+            }
+        } catch (WxPayException e) {
+            logger.error("查询转账单失败 err: {}", e.getMessage(), e);
+            throw new CustomException("查询转账单失败:" + e.getMessage());
+        }
+
+        throw new CustomException("转账处理中");
+    }
+
+    @Override
+    public R checkMchTransferStatusByBatchID(String batchId, Long companyId) {
+        // 获取配置信息
+        CourseConfig courseConfig = JSONUtil.toBean(configService.selectConfigByKey("course.config"), CourseConfig.class);
+
+        String json;
+        RedPacketConfig config = new RedPacketConfig();
+        // 根据红包模式获取配置
+        switch (courseConfig.getRedPacketMode()){
+            case 1:
+                json = configService.selectConfigByKey("redPacket.config");
+                config = JSONUtil.toBean(json, RedPacketConfig.class);
+                break;
+            case 2:
+                json = companyConfigService.selectRedPacketConfigByKey(companyId);
+                //如果分公司配置为空就走总后台的配置
+                if (StringUtils.isEmpty(json)){
+                    json = configService.selectConfigByKey("redPacket.config");
+                }
+                config = JSONUtil.toBean(json, RedPacketConfig.class);
+                break;
+            default:
+                throw new UnsupportedOperationException("当前红包模式不支持!");
+        }
+
+        //创建微信订单
+        WxPayConfig payConfig = new WxPayConfig();
+        BeanUtils.copyProperties(config,payConfig);
+        WxPayService wxPayService = new WxPayServiceImpl();
+        wxPayService.setConfig(payConfig);
+        TransferService transferService=wxPayService.getTransferService();
+
+        Map<String,Object> map = new HashMap<>();
+        map.put("status","待确认"); //
+        if (config.getIsNew() != null && config.getIsNew() == 1) {
+            try {
+                TransferBillsGetResult queryRedPacketResult = transferService.getBillsByTransferBillNo(batchId);
+                logger.info("FsCourseRedPacketLog-batchId:{},【红包处理】查询批次结果:{}",batchId,queryRedPacketResult.toString());
+                if(("SUCCESS").equals(queryRedPacketResult.getState())){
+                    map.put("status","success");
+                }else if(("FAIL").equals(queryRedPacketResult.getState())){
+                    map.put("status","fail");
+                }
+                return R.ok(map);
+            } catch (WxPayException e) {
+                logger.error(e.getMessage());
+                return R.error(e.getMessage());
+            }
+        } else {
+            QueryTransferBatchesRequest request = new QueryTransferBatchesRequest();
+            request.setBatchId(batchId);
+            request.setNeedQueryDetail(false);
+
+            try {
+                QueryTransferBatchesResult queryTransferBatchesResult = transferService.transferBatchesBatchId(request);
+                logger.info("FsCourseRedPacketLog-batchId,【红包处理】查询批次结果:{}",batchId,queryTransferBatchesResult.toString());
+                if(("FINISHED").equals(queryTransferBatchesResult.getTransferBatch().getBatchStatus())){
+                    map.put("status","success");
+                }else if(("CLOSED").equals(queryTransferBatchesResult.getTransferBatch().getBatchStatus())){
+                    map.put("status","fail");
+                }
+                return R.ok(map);
+            } catch (WxPayException e) {
+                logger.error(e.getMessage());
+                return R.error(e.getMessage());
+            }
+        }
+
+    }
+
     @Override
     @Override
     public List<OptionsVO> selectAllCompanyList(Long deptId) {
     public List<OptionsVO> selectAllCompanyList(Long deptId) {
         return companyMapper.selectAllCompanyList(deptId);
         return companyMapper.selectAllCompanyList(deptId);
@@ -1380,7 +1540,7 @@ public class CompanyServiceImpl implements ICompanyService
                                     // 记录余额变更日志
                                     // 记录余额变更日志
                                     String remark = "同步公司余额,差额: " + amount+"(正数为增加,负数为扣减)";
                                     String remark = "同步公司余额,差额: " + amount+"(正数为增加,负数为扣减)";
                                     // 实际不发生交易只是从缓存同步金额到数据库中 交易金额登记为0,备注清楚同步的金额
                                     // 实际不发生交易只是从缓存同步金额到数据库中 交易金额登记为0,备注清楚同步的金额
-                                    asyncRecordBalanceLog(company.getCompanyId(),new BigDecimal(0),17,redisMoney,remark);
+                                    asyncRecordBalanceLog(company.getCompanyId(),new BigDecimal(0),17,redisMoney,remark, null);
                                 }
                                 }
                             }
                             }
                             return null;
                             return null;
@@ -1433,7 +1593,7 @@ public class CompanyServiceImpl implements ICompanyService
                 redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
                 redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
 
 
                 // 异步登记余额添加日志
                 // 异步登记余额添加日志
-                asyncRecordBalanceLog(companyId,money,16,newMoney,"红包充值(负数为扣款)");
+                asyncRecordBalanceLog(companyId,money,16,newMoney,"红包充值(负数为扣款)", null);
 
 
             } else {
             } else {
                 logger.error("获取redis锁失败,异常请求参数companyId:{},money:{},type:{}",companyId,money, type);
                 logger.error("获取redis锁失败,异常请求参数companyId:{},money:{},type:{}",companyId,money, type);
@@ -1459,28 +1619,29 @@ public class CompanyServiceImpl implements ICompanyService
 
 
     /**
     /**
      * 异步登记余额添加日志  xgb
      * 异步登记余额添加日志  xgb
+     *
      * @param companyId 公司ID
      * @param companyId 公司ID
-     * @param money 变更金额
-     * @param balance 当前余额
-     * @param remark 备注信息
-     * @param logType 16-红包余额充值 15-红包余额扣除 17-同步公司余额
+     * @param money     变更金额
+     * @param logType   16-红包余额充值 15-红包余额扣除 17-同步公司余额
+     * @param balance   当前余额
+     * @param remark    备注信息
+     * @param logId
      */
      */
     @Async
     @Async
     @Override
     @Override
-    public void asyncRecordBalanceLog(Long companyId, BigDecimal money,Integer logType, BigDecimal balance, String remark) {
+    public void asyncRecordBalanceLog(Long companyId, BigDecimal money, Integer logType, BigDecimal balance, String remark, Long logId) {
         try {
         try {
-            CompanyMoneyLogs log = new CompanyMoneyLogs();
+            CompanyRedPacketBalanceLogs log = new CompanyRedPacketBalanceLogs();
             log.setCompanyId(companyId);
             log.setCompanyId(companyId);
             log.setRemark(remark);
             log.setRemark(remark);
             log.setMoney(money);
             log.setMoney(money);
             log.setLogsType(logType); // 同步余额
             log.setLogsType(logType); // 同步余额
             log.setBalance(balance);
             log.setBalance(balance);
             log.setCreateTime(new Date());
             log.setCreateTime(new Date());
-            moneyLogsMapper.insertCompanyMoneyLogs(log);
-            logger.info("异步登记余额日志成功 - 公司ID: {}, 金额: {}, 余额: {}, 备注: {}",
-                    companyId, money, balance, remark);
+            log.setRedPacketId(logId);
+            companyRedPacketBalanceLogsMapper.insertCompanyRedPacketBalanceLogs(log);
         } catch (Exception e) {
         } catch (Exception e) {
-            logger.error("异步登记余额日志失败 - 公司ID: {}, 金额: {}, 余额: {}, 备注: {}",
+            logger.error("异步登记红包余额日志失败 - 公司ID: {}, 金额: {}, 余额: {}, 备注: {}",
                     companyId, money, balance, remark, e);
                     companyId, money, balance, remark, e);
         }
         }
     }
     }
@@ -1508,7 +1669,7 @@ public class CompanyServiceImpl implements ICompanyService
                     // 实际不发生交易只是从缓存获取当天余额报错25小时 交易金额登记为0,备注清楚同步的金额
                     // 实际不发生交易只是从缓存获取当天余额报错25小时 交易金额登记为0,备注清楚同步的金额
                     String remark = "时间:" + time +",当前公司余额,金额: " + moneyStr;
                     String remark = "时间:" + time +",当前公司余额,金额: " + moneyStr;
                     BigDecimal money = new BigDecimal(moneyStr);
                     BigDecimal money = new BigDecimal(moneyStr);
-                    asyncRecordBalanceLog(company.getCompanyId(),new BigDecimal(0),18,money,remark);
+                    asyncRecordBalanceLog(company.getCompanyId(),new BigDecimal(0),18,money,remark, null);
                 }
                 }
                 return null;
                 return null;
             });
             });
@@ -1530,20 +1691,67 @@ public class CompanyServiceImpl implements ICompanyService
      * @Param:
      * @Param:
      * @Return:
      * @Return:
      * @Author xgb
      * @Author xgb
-     * @Date 2025/11/7 9:53
+     * @Date 2025/12/25 9:32
      */
      */
     @Override
     @Override
-    public void rollbackRedPacketMoney() {
-        List<RedPacketMoneyVO> redPacketMoneyVOS = fsCourseRedPacketLogMapper.selectFsCourseAddRedPacketLogByCompany();
-        for(RedPacketMoneyVO company:redPacketMoneyVOS){
-            logger.info("红包余额回滚开始:{}",company);
-        }
-        Optional.ofNullable(redPacketMoneyVOS).ifPresent(list -> list.forEach(company -> {
+    public void rollbackRedPacketMoney(String createSTime, String createETime) {
+        // 回滚前查询一下红包记录
+        List<CompanyRedPacketBalanceLogs> companyRedPacketBalanceLogsList = companyRedPacketBalanceLogsMapper.selectCompanyRedPacketBalanceLogsListByStatus(createSTime, createETime);
+
+        Optional.ofNullable(companyRedPacketBalanceLogsList).ifPresent(list -> list.forEach(company -> {
+
+            if(company.getRedPacketId()==null){// 无数据跳过
+                logger.info("红包记录未登记,流水{}",company.getLogsId());
+                return;
+            }
+
+            // 查询红包记录
+            FsCourseRedPacketLog redLogs = fsCourseRedPacketLogMapper.selectFsCourseRedPacketLogByLogId(company.getRedPacketId());
+            if(redLogs==null){
+                logger.error("未查询到红包记录,流水{}",company.getLogsId());
+                return;
+            }
 
 
             if(company.getCompanyId()==null){
             if(company.getCompanyId()==null){
-                logger.error("红包记录表中存在公司id为null的异常数据");
+                logger.error("红包记录表中存在公司id为null的异常数据,流水{}",company.getLogsId());
+                return;
+            }
+
+            if(!StringUtils.isEmpty(redLogs.getBatchId())){
+                R result=checkMchTransferStatusByBatchID(redLogs.getBatchId(),redLogs.getCompanyId());
+                if("200".equals(result.get("code"))){
+                    FsCourseRedPacketLog update = new FsCourseRedPacketLog();
+                    update.setUpdateTime(new Date());
+                    update.setLogId(redLogs.getLogId());
+
+                    // 更新扣减状态
+                    CompanyRedPacketBalanceLogs redBalanceLogs = new CompanyRedPacketBalanceLogs();
+                    redBalanceLogs.setRedPacketId(company.getRedPacketId());
+
+                    if("success".equals(result.get("status"))){
+                        update.setStatus(1);
+                        fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(update);
+
+                        redBalanceLogs.setStatus(1L);
+                        companyRedPacketBalanceLogsMapper.updateCompanyRedPacketBalanceLogsByRedPacketId(redBalanceLogs);
+                        return;
+                    }else if("fail".equals(result.get("status"))){// 只对失败的部分进行回滚
+                        // 更新支付状态
+                        update.setStatus(2); // 已退回
+                        fsCourseRedPacketLogMapper.updateFsCourseRedPacketLog(update);
+
+                        redBalanceLogs.setStatus(2L);
+                        companyRedPacketBalanceLogsMapper.updateCompanyRedPacketBalanceLogsByRedPacketId(redBalanceLogs);
+                    }
+                }else {
+                    logger.info("商户转账状态查询失败,流水{}",company.getLogsId());
+                    return;
+                }
+            }else {
+                logger.error("红包记录表中存在商户批次号为null的异常数据,流水{}",company.getLogsId());
                 return;
                 return;
             }
             }
+
             String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + company.getCompanyId();
             String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + company.getCompanyId();
             // 加锁,与看课发放红包的加锁保持一致
             // 加锁,与看课发放红包的加锁保持一致
             RLock lock = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + company.getCompanyId());
             RLock lock = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + company.getCompanyId());
@@ -1557,14 +1765,14 @@ public class CompanyServiceImpl implements ICompanyService
                     if (StringUtils.isNotEmpty(moneyStr)) {
                     if (StringUtils.isNotEmpty(moneyStr)) {
                         redisMoney = new BigDecimal(moneyStr);
                         redisMoney = new BigDecimal(moneyStr);
                     }else {
                     }else {
-                        logger.error("缓存公司id:{}的余额不存在,回滚金额{}",company.getCompanyId(),company.getMoney());
+                        logger.error("缓存公司id:{}的余额不存在,回滚金额{}",company.getCompanyId(),redLogs.getAmount());
                         return;
                         return;
                     }
                     }
-                    BigDecimal newMoney = redisMoney.add(company.getMoney());
+                    BigDecimal newMoney = redisMoney.add(redLogs.getAmount());
                     redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
                     redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
 
 
-                    String remark = "执行时间:"+DateUtils.getTime()+",T2天客户未领取红包退回,金额: " + company.getMoney();
-                    asyncRecordBalanceLog(company.getCompanyId(),company.getMoney(),16,newMoney,remark);
+                    String remark = "执行时间:"+DateUtils.getTime()+",T2天客户未领取红包退回,金额: " + redLogs.getAmount();
+                    asyncRecordBalanceLog(company.getCompanyId(),redLogs.getAmount(),19,newMoney,remark, redLogs.getLogId());
                 }
                 }
             } catch (Exception e) {
             } catch (Exception e) {
                 logger.error("退回的红包同步增加到缓存和数据表,参数错误,请求异常,异常信息:{}", e.getMessage(), e);
                 logger.error("退回的红包同步增加到缓存和数据表,参数错误,请求异常,异常信息:{}", e.getMessage(), e);
@@ -1579,8 +1787,5 @@ public class CompanyServiceImpl implements ICompanyService
             }
             }
         }));
         }));
     }
     }
-    @Override
-    public Company selectCompanyByStoreId(Long storeId) {
-        return companyMapper.selectCompanyByStoreId(storeId);
-    }
+
 }
 }

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

@@ -73,4 +73,7 @@ public class FsCourseRedPacketLog extends BaseEntity
      */
      */
     private BigDecimal accBalanceAfter;
     private BigDecimal accBalanceAfter;
 
 
+    //商户号
+    private String mchId;
+
 }
 }

+ 162 - 33
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -1466,41 +1466,170 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     private R sendRedPacketRewardToUser(FsCourseSendRewardUParam param, FsCourseWatchLog log, CourseConfig config, WxSendRedPacketParam packetParam, BigDecimal amount) {
     private R sendRedPacketRewardToUser(FsCourseSendRewardUParam param, FsCourseWatchLog log, CourseConfig config, WxSendRedPacketParam packetParam, BigDecimal amount) {
 
 
 
 
-        // 发送红包
-        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());
+        // 自动看课红包余额字段实时监控  xgb 1111
+        if("1".equals(config.getIsRedPackageBalanceDeduction())) {
+            // 新增的有设计文档 可以找 xgb 要
+            // ===================== 20251022 xgb 修改 本次修改目的为了实时扣减公司余额=====================
+            // 1 使用redis缓存加锁 预扣减余额 红包发送失败 恢复redis缓存余额,如果回滚失败登记异常记录表 定时任务重新回滚余额
+            // 2 另起定时任务 同步缓存余额到redis中
+            // 3 注意!!!!! 启动系统时查询公司账户余额(这个时候要保证余额正确)启动会自动保存到redis缓存中
+            // 注意!!!!! 打开这个开关前记得检测redis缓存余额是否正确 若不正确 修改数据库字段red_package_money,删除redis缓存,重启系统,
+
+
+            // 预设值异常对象
+            BalanceRollbackError balanceRollbackError = new BalanceRollbackError();
+            balanceRollbackError.setCompanyId(packetParam.getCompanyId());
+            balanceRollbackError.setUserId(param.getUserId());
+            balanceRollbackError.setLogId(log.getLogId());
+            balanceRollbackError.setVideoId(log.getVideoId());
+            balanceRollbackError.setStatus(0);
+            balanceRollbackError.setMoney(amount);
+
+            if (packetParam.getCompanyId() == null) {
+                logger.error("发送红包参数错误,公司不能为空,异常请求参数{}", packetParam);
+                return R.error("发送红包失败,请联系管理员");
+            }
+            String companyMoneyKey = FsConstants.COMPANY_MONEY_KEY + packetParam.getCompanyId();
+
+            // 第一次加锁:预扣减余额
+            RLock lock1 = redissonClient.getLock(FsConstants.COMPANY_MONEY_LOCK + packetParam.getCompanyId());
+            boolean lockAcquired = false;
+            BigDecimal newMoney;
+            try {
+                if (lock1.tryLock(3, 10, TimeUnit.SECONDS)) {
+                    lockAcquired = true;
+                    BigDecimal originalMoney;
+                    // 获取当前余额
+                    String moneyStr = redisCache.getCacheObject(companyMoneyKey);
+                    if (StringUtils.isNotEmpty(moneyStr)) {
+                        originalMoney = new BigDecimal(moneyStr);
+                    } else {
+                        // 缓存没有值,重启系统恢复redis数据 保证数据正确性
+                        logger.error("发送红包获取redis余额缓存异常,异常请求参数{}", packetParam);
+                        return R.error("系统异常,请稍后重试");
+                    }
+
+                    if (originalMoney.compareTo(BigDecimal.ZERO) < 0) {
+                        logger.error("服务商余额不足,异常请求参数{}", packetParam);
+                        return R.error("服务商余额不足,请联系群主服务器充值!");
+                    }
+
+                    // 预扣减金额
+                    newMoney = originalMoney.subtract(amount);
+                    redisCache.setCacheObject(companyMoneyKey, newMoney.toString());
+                } else {
+                    logger.error("获取redis锁失败,异常请求参数{}", packetParam);
+                    return R.error("系统繁忙,请稍后重试");
+                }
+            } catch (Exception e) {
+                logger.error("预扣减余额失败: 异常请求参数{},异常信息{}", packetParam, e.getMessage(), e);
+                return R.error("系统异常,请稍后重试");
+            } finally {
+                // 只有在成功获取锁的情况下才释放锁
+                if (lockAcquired && lock1.isHeldByCurrentThread()) {
+                    try {
+                        lock1.unlock();
+                    } catch (IllegalMonitorStateException e) {
+                        logger.warn("尝试释放非当前线程持有的锁: companyId={}", packetParam.getCompanyId());
+                    }
+                }
             }
             }
-            // 添加红包记录
-            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());
 
 
-            redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
-            // 更新观看记录的奖励类型
-            log.setRewardType(config.getRewardType());
-            courseWatchLogMapper.updateFsCourseWatchLog(log);
+            // 调用第三方接口(锁外操作)
+            R sendRedPacket;
+            try {
+                sendRedPacket= paymentService.sendRedPacket(packetParam);
+            } catch (Exception e) {
+                logger.error("红包发送异常: 异常请求参数{}",packetParam, e);
+                // 异常时回滚余额
+
+                rollbackBalance(balanceRollbackError);
+                return R.error("奖励发送失败,请联系客服");
+            }
 
 
+            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());
+
+                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+                // 更新观看记录的奖励类型
+                log.setRewardType(config.getRewardType());
+                courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+                // 异步登记余额扣减日志
+                BigDecimal money=amount.multiply(BigDecimal.valueOf(-1));
+                companyService.asyncRecordBalanceLog(param.getCompanyId(), money, 15, newMoney, "发放红包",redPacketLog.getLogId());
 //            redisCache.setCacheObject("h5user:redPacket:"+param.getUserId(),LocalDateTime.now().toString());
 //            redisCache.setCacheObject("h5user:redPacket:"+param.getUserId(),LocalDateTime.now().toString());
 
 
-            return sendRedPacket;
-        } else {
-            return R.error("奖励发送失败,请联系客服");
+                return sendRedPacket;
+            } else {
+                // 登记回滚流水表
+                rollbackBalance(balanceRollbackError);
+                return R.error("奖励发送失败,请联系客服");
+            }
+
+
+
+        }else {
+            // 发送红包
+            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());
+                }
+                //存储商户ID
+                if (StringUtils.isNotEmpty(sendRedPacket.get("mchId").toString())){
+                    redPacketLog.setMchId(sendRedPacket.get("mchId").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());
+
+                redPacketLogMapper.insertFsCourseRedPacketLog(redPacketLog);
+                // 更新观看记录的奖励类型
+                log.setRewardType(config.getRewardType());
+                courseWatchLogMapper.updateFsCourseWatchLog(log);
+
+//            redisCache.setCacheObject("h5user:redPacket:"+param.getUserId(),LocalDateTime.now().toString());
+
+                return sendRedPacket;
+            } else {
+                return R.error("奖励发送失败,请联系客服");
+            }
         }
         }
     }
     }
 
 
@@ -1713,9 +1842,9 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                     courseWatchLogMapper.updateFsCourseWatchLog(log);
                     courseWatchLogMapper.updateFsCourseWatchLog(log);
 
 
                     // 异步登记余额扣减日志
                     // 异步登记余额扣减日志
-                    BigDecimal money=amount.multiply(BigDecimal.valueOf(-1));
-                    companyService.asyncRecordBalanceLog(param.getCompanyId(), money, 15, newMoney, "发放红包");
-                    // 发送成功,记录日志等操作
+                    BigDecimal money = amount.multiply(BigDecimal.valueOf(-1));
+                    companyService.asyncRecordBalanceLog(param.getCompanyId(), money, 15, newMoney, "发放红包", redPacketLog.getLogId());
+
                     return sendRedPacket;
                     return sendRedPacket;
 
 
 
 

+ 105 - 0
fs-service/src/main/resources/mapper/company/CompanyRedPacketBalanceLogsMapper.xml

@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.company.mapper.CompanyRedPacketBalanceLogsMapper">
+
+    <resultMap type="CompanyRedPacketBalanceLogs" id="CompanyRedPacketBalanceLogsResult">
+        <result property="logsId"    column="logs_id"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="money"    column="money"    />
+        <result property="remark"    column="remark"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="balance"    column="balance"    />
+        <result property="logsType"    column="logs_type"    />
+        <result property="status"    column="status"    />
+        <result property="redPacketId"    column="red_packet_id"    />
+    </resultMap>
+
+    <sql id="selectCompanyRedPacketBalanceLogsVo">
+        select logs_id, company_id, money, remark, create_time, balance, logs_type, status,red_packet_id from company_red_packet_balance_logs
+    </sql>
+
+    <select id="selectCompanyRedPacketBalanceLogsList" parameterType="CompanyRedPacketBalanceLogs" resultMap="CompanyRedPacketBalanceLogsResult">
+        select l.logs_id, l.company_id, l.money, l.remark, l.create_time, l.balance, l.logs_type, l.status,l.red_packet_id,c.company_name
+        from
+        company_red_packet_balance_logs l
+        left join company c on c.company_id = l.company_id
+        <where>
+            <if test="logsId != null "> and l.logs_id = #{logsId}</if>
+            <if test="companyId != null "> and l.company_id = #{companyId}</if>
+            <if test="params.beginCreateTime != null and params.beginCreateTime != '' and params.endCreateTime != null and params.endCreateTime != ''"> and l.create_time between #{params.beginCreateTime} and #{params.endCreateTime}</if>
+            <if test="logsType != null "> and l.logs_type = #{logsType}</if>
+        </where>
+    </select>
+
+    <select id="selectCompanyRedPacketBalanceLogsByLogsId" parameterType="Long" resultMap="CompanyRedPacketBalanceLogsResult">
+        <include refid="selectCompanyRedPacketBalanceLogsVo"/>
+        where logs_id = #{logsId}
+    </select>
+
+    <select id="getCompanyRedPacketBalance" resultType="com.fs.company.domain.Company">
+        SELECT * FROM company WHERE company_id = #{companyId}
+    </select>
+    <select id="selectCompanyRedPacketBalanceLogsListByStatus"
+            resultType="com.fs.company.domain.CompanyRedPacketBalanceLogs">
+        <include refid="selectCompanyRedPacketBalanceLogsVo"/>  where logs_type = 15 and status = 0  and create_time &gt;= #{createSTime}  AND create_time &lt; #{createETime}
+    </select>
+
+    <insert id="insertCompanyRedPacketBalanceLogs" parameterType="CompanyRedPacketBalanceLogs" useGeneratedKeys="true" keyProperty="logsId">
+        insert into company_red_packet_balance_logs
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">company_id,</if>
+            <if test="money != null">money,</if>
+            <if test="remark != null">remark,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="balance != null">balance,</if>
+            <if test="logsType != null">logs_type,</if>
+            <if test="status != null">status,</if>
+            <if test="redPacketId != null">red_packet_id,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="companyId != null">#{companyId},</if>
+            <if test="money != null">#{money},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="balance != null">#{balance},</if>
+            <if test="logsType != null">#{logsType},</if>
+            <if test="status != null">#{status},</if>
+            <if test="redPacketId != null">#{redPacketId},</if>
+        </trim>
+    </insert>
+
+    <update id="updateCompanyRedPacketBalanceLogs" parameterType="CompanyRedPacketBalanceLogs">
+        update company_red_packet_balance_logs
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="money != null">money = #{money},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="balance != null">balance = #{balance},</if>
+            <if test="logsType != null">logs_type = #{logsType},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="redPacketId != null">red_packet_id = #{redPacketId},</if>
+        </trim>
+        where logs_id = #{logsId}
+    </update>
+    <update id="updateCompanyRedPacketBalanceLogsByRedPacketId">
+        update company_red_packet_balance_logs
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="status != null">status = #{status},</if>
+        </trim>
+        where red_packet_id = #{redPacketId} and logs_type = 15
+    </update>
+
+    <delete id="deleteCompanyRedPacketBalanceLogsByLogsId" parameterType="Long">
+        delete from company_red_packet_balance_logs where logs_id = #{logsId}
+    </delete>
+
+    <delete id="deleteCompanyRedPacketBalanceLogsByLogsIds" parameterType="String">
+        delete from company_red_packet_balance_logs where logs_id in
+        <foreach item="logsId" collection="array" open="(" separator="," close=")">
+            #{logsId}
+        </foreach>
+    </delete>
+</mapper>