Преглед на файлове

好友生成链接,聚水分仓等

yjwang преди 4 дни
родител
ревизия
04ca95c46c
променени са 28 файла, в които са добавени 983 реда и са изтрити 60 реда
  1. 14 1
      fs-admin/src/main/java/com/fs/his/task/Task.java
  2. 53 0
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreErpInfoController.java
  3. 3 0
      fs-service/src/main/java/com/fs/company/domain/Company.java
  4. 3 0
      fs-service/src/main/java/com/fs/company/mapper/CompanyMapper.java
  5. 2 0
      fs-service/src/main/java/com/fs/company/param/CompanyParam.java
  6. 3 0
      fs-service/src/main/java/com/fs/company/vo/CompanyVO.java
  7. 33 0
      fs-service/src/main/java/com/fs/erp/dto/OrderModifyWmsRequestDTO.java
  8. 9 0
      fs-service/src/main/java/com/fs/erp/http/JstErpHttpService.java
  9. 10 0
      fs-service/src/main/java/com/fs/erp/http/JstErpHttpServiceImpl.java
  10. 51 2
      fs-service/src/main/java/com/fs/erp/service/impl/FsJstAftersalePushScrmServiceImpl.java
  11. 51 2
      fs-service/src/main/java/com/fs/erp/service/impl/FsJstAftersalePushServiceImpl.java
  12. 6 7
      fs-service/src/main/java/com/fs/erp/service/impl/JSTErpOrderServiceImpl.java
  13. 94 13
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  14. 52 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreErpInfo.java
  15. 5 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreScrm.java
  16. 26 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreErpInfoMapper.java
  17. 22 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreErpInfoService.java
  18. 60 14
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java
  19. 87 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreErpInfoServiceImpl.java
  20. 78 14
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  21. 4 4
      fs-service/src/main/resources/application-config-dev-yjb.yml
  22. 77 0
      fs-service/src/main/resources/db/20260518-店铺ERP信息表.sql
  23. 7 0
      fs-service/src/main/resources/mapper/company/CompanyMapper.xml
  24. 90 0
      fs-service/src/main/resources/mapper/hisStore/FsStoreErpInfoMapper.xml
  25. 7 2
      fs-service/src/main/resources/mapper/hisStore/FsStoreScrmMapper.xml
  26. 1 1
      fs-service/src/main/resources/mapper/statis/ConsumptionBalanceMapper.xml
  27. 50 0
      fs-user-app/src/main/java/com/fs/app/controller/store/StoreOrderScrmController.java
  28. 85 0
      sql/optimize_fs_course_watch_log.sql

+ 14 - 1
fs-admin/src/main/java/com/fs/his/task/Task.java

@@ -1622,6 +1622,7 @@ public class Task {
                 String json = configService.selectConfigByKey("course.config");
                 CourseConfig config = JSON.parseObject(json, CourseConfig.class);
                 Map<String,List<CompanyUser>> companyUserMap = companyUserList.stream().collect(Collectors.groupingBy(c->String.valueOf(c.getCompanyId())));
+                Map<String,Long> checkMap = new HashMap<>();
                 periodDaysList.forEach(p->{
                     String[] companyIdList= p.getCompanyId().split(",");
                     for (String companyId: companyIdList){
@@ -1642,10 +1643,22 @@ public class Task {
                                 //生成看课链接
                                 fsCourseLinkService.getGotoWxAppLink("/pages_course/videovip?course="+jsonObject.toJSONString(),config.getLoginMiniAppId());
                                 try {
-                                    Thread.sleep(300);
+                                    Thread.sleep(120);
                                 } catch (InterruptedException e) {
                                     throw new RuntimeException(e);
                                 }
+
+                                String key = u.getUserId() + "_" + p.getProjectId();
+                                if(!checkMap.containsKey(key)){
+                                    //生成好友邀请链接
+                                    fsCourseLinkService.getGotoWxAppLink("/pages_course/becomeVIP?becomeVip="+jsonObject.toJSONString(),config.getLoginMiniAppId());
+                                    checkMap.put(key, 0L);
+                                    try {
+                                        Thread.sleep(120);
+                                    } catch (InterruptedException e) {
+                                        throw new RuntimeException(e);
+                                    }
+                                }
                             });
                         }
                     }

+ 53 - 0
fs-admin/src/main/java/com/fs/hisStore/controller/FsStoreErpInfoController.java

@@ -0,0 +1,53 @@
+package com.fs.hisStore.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.enums.BusinessType;
+import com.fs.hisStore.domain.FsStoreErpInfo;
+import com.fs.hisStore.service.IFsStoreErpInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * ERP信息Controller
+ *
+ * @author fs
+ * @date 2026-05-18
+ */
+@RestController
+@RequestMapping("/store/his/storeErpInfo")
+public class FsStoreErpInfoController extends BaseController {
+
+    @Autowired
+    private IFsStoreErpInfoService fsStoreErpInfoService;
+
+    /**
+     * 根据关联ID和类型查询ERP信息
+     * type参数:1-店铺 2-销售
+     */
+    @PreAuthorize("@ss.hasPermi('his:store:edit')")
+    @GetMapping("/{refId}")
+    public AjaxResult getInfoByRefId(@PathVariable("refId") Long refId,
+                                     @RequestParam(value = "type", defaultValue = "1") Integer type) {
+        return AjaxResult.success(fsStoreErpInfoService.selectByRefId(refId, type));
+    }
+
+    /**
+     * 保存或更新ERP信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:store:edit')")
+    @Log(title = "ERP信息", businessType = BusinessType.UPDATE)
+    @PostMapping("/save")
+    public AjaxResult save(@RequestBody FsStoreErpInfo fsStoreErpInfo) {
+        if (fsStoreErpInfo == null || fsStoreErpInfo.getRefId() == null) {
+            return AjaxResult.error("关联ID不能为空");
+        }
+        if (fsStoreErpInfo.getType() == null) {
+            fsStoreErpInfo.setType(FsStoreErpInfo.TYPE_STORE);
+        }
+        fsStoreErpInfoService.saveOrUpdate(fsStoreErpInfo);
+        return AjaxResult.success();
+    }
+}

+ 3 - 0
fs-service/src/main/java/com/fs/company/domain/Company.java

@@ -156,4 +156,7 @@ public class Company extends BaseEntity
     @TableField(exist = false)
     private Integer ipadDeactivate;
 
+    /** 是否填写ERP信息:0-否 1-是 */
+    private Integer hasErpInfo;
+
 }

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

@@ -87,6 +87,9 @@ public interface CompanyMapper
             "<if test = 'maps.status != null   '> " +
             "and c.status = #{maps.status}" +
             "</if>" +
+            "<if test = 'maps.hasErpInfo != null'> " +
+            "and ifnull(c.has_erp_info, 0) = #{maps.hasErpInfo}" +
+            "</if>" +
             "order by c.company_id desc " +
             "</script>"})
     List<CompanyVO> selectCompanyVOList(@Param("maps")CompanyParam param);

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

@@ -16,4 +16,6 @@ public class CompanyParam
     private String phonenumber;
     private Long deptId;
     private Long[] companyIds;
+    /** ERP信息筛选:0-未填写 1-已填写 */
+    private Integer hasErpInfo;
 }

+ 3 - 0
fs-service/src/main/java/com/fs/company/vo/CompanyVO.java

@@ -107,4 +107,7 @@ public class CompanyVO implements Serializable
 
     //ipda禁用0否1是
     private Integer ipadDeactivate;
+
+    /** 是否填写ERP信息:0-否 1-是 */
+    private Integer hasErpInfo;
 }

+ 33 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderModifyWmsRequestDTO.java

@@ -0,0 +1,33 @@
+package com.fs.erp.dto;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 订单指定发货仓请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2026-05-18
+ */
+@Data
+@Accessors(chain = true)
+public class OrderModifyWmsRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ERP内部订单号
+     */
+    @JSONField(name = "o_id")
+    private Long oId;
+
+    /**
+     * 仓库编码
+     */
+    @JSONField(name = "wms_co_id")
+    private Long wmsCoId;
+}

+ 9 - 0
fs-service/src/main/java/com/fs/erp/http/JstErpHttpService.java

@@ -2,6 +2,8 @@ package com.fs.erp.http;
 
 import com.alibaba.fastjson.JSONObject;
 import com.fs.erp.dto.*;
+
+import java.util.List;
 import com.fs.ybPay.dto.RefundOrderDTO;
 
 /**
@@ -63,6 +65,13 @@ public interface JstErpHttpService {
      */
     CommonResponse cancel(OrderCancelRequestDTO dto);
 
+    /**
+     * 订单指定发货仓
+     * @param dto 请求参数列表
+     * @return CommonResponse
+     */
+    CommonResponse modifyWmsUpload(List<OrderModifyWmsRequestDTO> dto);
+
     /**
      * 售后上传
      * @param dto 请求参数

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

@@ -23,6 +23,7 @@ import org.springframework.stereotype.Service;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 @Slf4j
@@ -127,6 +128,15 @@ public class JstErpHttpServiceImpl implements JstErpHttpService {
         return parseCommonResponse(response);
     }
 
+    @Override
+    public CommonResponse modifyWmsUpload(List<OrderModifyWmsRequestDTO> dto) {
+        String url = BASE_URL + "open/orders/modifywms/upload";
+        log.info("订单指定发货仓 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
+
+        HttpResponse response = executeJsonPost(url, dto);
+        return parseCommonResponse(response);
+    }
+
     @Override
     public CommonResponse<AfterSaleResponseDTO> aftersaleUpload(RefundOrderDTO dto) {
         String url = BASE_URL + "open/aftersale/upload";

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

@@ -4,6 +4,8 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.utils.ExceptionUtil;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.erp.constant.AfterSalesOrderStatusEnum;
 import com.fs.erp.constant.TaskStatusEnum;
 import com.fs.erp.domain.FsJstAftersalePush;
@@ -17,10 +19,14 @@ import com.fs.his.domain.FsStoreAfterSales;
 import com.fs.his.dto.FsStoreCartDTO;
 import com.fs.his.mapper.FsStoreAfterSalesMapper;
 import com.fs.hisStore.domain.FsStoreAfterSalesScrm;
+import com.fs.hisStore.domain.FsStoreErpInfo;
 import com.fs.hisStore.domain.FsStoreOrderItemScrm;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
+import com.fs.hisStore.domain.FsStoreScrm;
 import com.fs.hisStore.mapper.FsStoreAfterSalesScrmMapper;
+import com.fs.hisStore.mapper.FsStoreErpInfoMapper;
 import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
+import com.fs.hisStore.mapper.FsStoreScrmMapper;
 import com.fs.hisStore.service.IFsStoreOrderItemScrmService;
 import com.fs.ybPay.dto.RefundOrderDTO;
 import lombok.extern.slf4j.Slf4j;
@@ -52,8 +58,18 @@ public class FsJstAftersalePushScrmServiceImpl implements FsJstAftersalePushScrm
     @Autowired
     private FsStoreAfterSalesScrmMapper fsStoreAfterSalesMapper;
 
+    /** 全局默认店铺编码(降级使用) */
     @Value("${jst.shop_code:''}")
-    private String shopId;
+    private String defaultShopCode;
+
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    @Autowired
+    private FsStoreScrmMapper fsStoreMapper;
+
+    @Autowired
+    private FsStoreErpInfoMapper fsStoreErpInfoMapper;
     @Override
     public void pushJst() {
         List<FsJstAftersalePush> fsJstAftersalePushes = fsJstAftersalePushMapper.queryPenddingData();
@@ -148,7 +164,9 @@ public class FsJstAftersalePushScrmServiceImpl implements FsJstAftersalePushScrm
         dto.setRemark("用户退款");
         dto.setType("仅退款");
 
-        dto.setShopId(Long.parseLong(shopId));
+        // 动态获取店铺编码
+        String shopCode = getDynamicShopCode(fsStoreOrder);
+        dto.setShopId(Long.parseLong(shopCode));
         dto.setTotalAmount(fsStoreOrder.getTotalPrice());
         dto.setSoId(item.getOrderId());
         dto.setRefund(fsStoreOrder.getPayMoney());
@@ -173,4 +191,35 @@ public class FsJstAftersalePushScrmServiceImpl implements FsJstAftersalePushScrm
         dto.setItems(refundItemDTOS);
         return dto;
     }
+
+    /**
+     * 动态获取店铺编码(优先使用 fs_store_erp_info 专属配置,降级使用全局配置)
+     */
+    private String getDynamicShopCode(FsStoreOrderScrm order) {
+        if (order == null) {
+            return defaultShopCode;
+        }
+        Integer type = null;
+        Long refId = null;
+        if (order.getCompanyId() != null) {
+            Company company = companyMapper.selectCompanyById(order.getCompanyId());
+            if (company != null && company.getHasErpInfo() != null && company.getHasErpInfo() == 1) {
+                type = 2;
+                refId = company.getCompanyId();
+            }
+        } else {
+            FsStoreScrm store = fsStoreMapper.selectFsStoreByStoreId(order.getStoreId());
+            if (store != null && store.getHasErpInfo() != null && store.getHasErpInfo() == 1) {
+                type = 1;
+                refId = store.getStoreId();
+            }
+        }
+        if (type != null && refId != null) {
+            FsStoreErpInfo erpInfo = fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(refId, type);
+            if (erpInfo != null && StringUtils.isNotBlank(erpInfo.getShopCode())) {
+                return erpInfo.getShopCode();
+            }
+        }
+        return defaultShopCode;
+    }
 }

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

@@ -4,6 +4,8 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.utils.ExceptionUtil;
 import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.erp.constant.AfterSalesOrderStatusEnum;
 import com.fs.erp.constant.TaskStatusEnum;
 import com.fs.erp.domain.FsJstAftersalePush;
@@ -18,9 +20,13 @@ import com.fs.his.dto.FsStoreCartDTO;
 import com.fs.his.mapper.FsStoreAfterSalesMapper;
 import com.fs.his.mapper.FsStoreOrderMapper;
 import com.fs.his.service.IFsStoreOrderItemService;
+import com.fs.hisStore.domain.FsStoreErpInfo;
 import com.fs.hisStore.domain.FsStoreOrderItemScrm;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
+import com.fs.hisStore.domain.FsStoreScrm;
+import com.fs.hisStore.mapper.FsStoreErpInfoMapper;
 import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
+import com.fs.hisStore.mapper.FsStoreScrmMapper;
 import com.fs.hisStore.service.IFsStoreOrderItemScrmService;
 import com.fs.ybPay.dto.RefundOrderDTO;
 import lombok.extern.slf4j.Slf4j;
@@ -53,8 +59,18 @@ public class FsJstAftersalePushServiceImpl implements FsJstAftersalePushService
     @Autowired
     private FsStoreAfterSalesMapper fsStoreAfterSalesMapper;
 
+    /** 全局默认店铺编码(降级使用) */
     @Value("${jst.shop_code:''}")
-    private String shopId;
+    private String defaultShopCode;
+
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    @Autowired
+    private FsStoreScrmMapper fsStoreMapper;
+
+    @Autowired
+    private FsStoreErpInfoMapper fsStoreErpInfoMapper;
     @Override
     public void pushJst() {
         List<FsJstAftersalePush> fsJstAftersalePushes = fsJstAftersalePushMapper.queryPenddingData();
@@ -149,7 +165,9 @@ public class FsJstAftersalePushServiceImpl implements FsJstAftersalePushService
         dto.setRemark("用户退款");
         dto.setType("仅退款");
 
-        dto.setShopId(Long.parseLong(shopId));
+        // 动态获取店铺编码
+        String shopCode = getDynamicShopCode(fsStoreOrder);
+        dto.setShopId(Long.parseLong(shopCode));
         dto.setTotalAmount(fsStoreOrder.getTotalPrice());
         dto.setSoId(item.getOrderId());
         dto.setRefund(fsStoreOrder.getPayMoney());
@@ -174,4 +192,35 @@ public class FsJstAftersalePushServiceImpl implements FsJstAftersalePushService
         dto.setItems(refundItemDTOS);
         return dto;
     }
+
+    /**
+     * 动态获取店铺编码(优先使用 fs_store_erp_info 专属配置,降级使用全局配置)
+     */
+    private String getDynamicShopCode(FsStoreOrderScrm order) {
+        if (order == null) {
+            return defaultShopCode;
+        }
+        Integer type = null;
+        Long refId = null;
+        if (order.getCompanyId() != null) {
+            Company company = companyMapper.selectCompanyById(order.getCompanyId());
+            if (company != null && company.getHasErpInfo() != null && company.getHasErpInfo() == 1) {
+                type = 2;
+                refId = company.getCompanyId();
+            }
+        } else {
+            FsStoreScrm store = fsStoreMapper.selectFsStoreByStoreId(order.getStoreId());
+            if (store != null && store.getHasErpInfo() != null && store.getHasErpInfo() == 1) {
+                type = 1;
+                refId = store.getStoreId();
+            }
+        }
+        if (type != null && refId != null) {
+            FsStoreErpInfo erpInfo = fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(refId, type);
+            if (erpInfo != null && StringUtils.isNotBlank(erpInfo.getShopCode())) {
+                return erpInfo.getShopCode();
+            }
+        }
+        return defaultShopCode;
+    }
 }

+ 6 - 7
fs-service/src/main/java/com/fs/erp/service/impl/JSTErpOrderServiceImpl.java

@@ -37,6 +37,7 @@ import com.fs.hisStore.service.impl.FsStoreProductScrmServiceImpl;
 import com.fs.hisStore.vo.FsStoreOrderItemVO;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.http.util.Asserts;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -121,9 +122,8 @@ public class JSTErpOrderServiceImpl implements IErpOrderService {
         } else {
             shopOrderDTO.setFreight(fsStoreOrder.getPayDelivery().doubleValue());
         }
-        // 备注
-        //shopOrderDTO.setRemark(order.getBuyer_memo());
-        shopOrderDTO.setRemark(DateUtil.format(new Date(), "dd"));
+        // 备注 - 优先使用订单备注,如果没有则使用日期
+        shopOrderDTO.setRemark(StringUtils.isNotBlank(fsStoreOrder.getRemark()) ? fsStoreOrder.getRemark() : null);
 
         // 买家留言
         shopOrderDTO.setBuyerMessage(order.getBuyer_memo());
@@ -246,11 +246,8 @@ public class JSTErpOrderServiceImpl implements IErpOrderService {
         } else {
             shopOrderDTO.setFreight(fsStoreOrder.getPayDelivery().doubleValue());
         }
-        // 备注
-        //shopOrderDTO.setRemark(order.getBuyer_memo());
-        shopOrderDTO.setRemark(DateUtil.format(new Date(), "dd"));
         // 买家留言
-        shopOrderDTO.setBuyerMessage(order.getBuyer_memo());
+        shopOrderDTO.setBuyerMessage(StringUtils.isNotBlank(fsStoreOrder.getMark())?fsStoreOrder.getMark():null);
 
         // 订单商品项列表
         List<OrderItemDTO> itemDTOList = new ArrayList<>();
@@ -727,6 +724,8 @@ public class JSTErpOrderServiceImpl implements IErpOrderService {
                    shopOrderDTO.setReceiverName(combinationValue);
                }
            }
+        }else {
+            shopOrderDTO.setRemark(null);
         }
     }
 }

+ 94 - 13
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -46,8 +46,12 @@ import com.fs.his.utils.ConfigUtil;
 import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.*;
 import com.fs.hisStore.domain.FsStoreOrderScrm;
+import com.fs.hisStore.domain.FsStoreScrm;
+import com.fs.hisStore.domain.FsStoreErpInfo;
+import com.fs.hisStore.mapper.FsStoreErpInfoMapper;
 import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
 import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
+import com.fs.hisStore.mapper.FsStoreScrmMapper;
 import com.fs.hisStore.param.FsStoreOrderRefundByProductParam;
 import com.fs.hisStore.service.IFsStoreOrderLogsScrmService;
 import com.fs.hisapi.domain.ApiResponse;
@@ -254,6 +258,10 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Autowired
     private FsStoreMapper fsStoreMapper;
     @Autowired
+    private FsStoreScrmMapper fsStoreScrmMapper;
+    @Autowired
+    private FsStoreErpInfoMapper fsStoreErpInfoMapper;
+    @Autowired
     private IFsInquiryOrderService inquiryOrderService;
     @Autowired
     private FsFollowReportMapper fsFollowReportMapper;
@@ -422,8 +430,8 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         //订单号
         erpOrder.setPlatform_code(order.getOrderCode());
 
-        // 店铺编码
-        erpOrder.setShop_code(sysConfig.getErpJstShopCode());
+        // 店铺编码(动态获取:优先 fs_store_erp_info,降级使用聚水潭全局配置)
+        erpOrder.setShop_code(getDynamicShopCodeForHis(order, sysConfig.getErpJstShopCode()));
         erpOrder.setBuyer_account(order.getUserName());
         //成交时间
         erpOrder.setDeal_datetime(order.getBeginTime());
@@ -491,6 +499,78 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         return erpOrder;
     }
 
+    /**
+     * 动态获取店铺编码(优先使用 fs_store_erp_info 专属配置,降级使用传入的全局备用值)
+     *
+     * @param order        订单信息
+     * @param fallbackCode 全局备用店铺编码
+     * @return shopCode 字符串
+     */
+    private String getDynamicShopCodeForHis(FsStoreOrder order, String fallbackCode) {
+        if (order == null) {
+            return fallbackCode;
+        }
+        Integer type = null;
+        Long refId = null;
+        // 优先判断是否存在销售公司
+        if (order.getCompanyId() != null) {
+            Company company = companyMapper.selectCompanyById(order.getCompanyId());
+            if (company != null && company.getHasErpInfo() != null && company.getHasErpInfo() == 1) {
+                type = 2;
+                refId = company.getCompanyId();
+            }
+        } else {
+            // 没有销售公司ID,属于商城订单
+            FsStoreScrm store = fsStoreScrmMapper.selectFsStoreByStoreId(order.getStoreId());
+            if (store != null && store.getHasErpInfo() != null && store.getHasErpInfo() == 1) {
+                type = 1;
+                refId = store.getStoreId();
+            }
+        }
+        if (type != null && refId != null) {
+            FsStoreErpInfo erpInfo = fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(refId, type);
+            if (erpInfo != null && StringUtils.isNotBlank(erpInfo.getShopCode())) {
+                return erpInfo.getShopCode();
+            }
+        }
+        return fallbackCode;
+    }
+
+    /**
+     * 动态获取仓库编码(优先使用 fs_store_erp_info 专属配置,降级使用传入的全局备用值)
+     *
+     * @param order        订单信息
+     * @param fallbackCode 全局备用仓库编码
+     * @return warehouseCode 字符串
+     */
+    private String getDynamicWarehouseCodeForHis(FsStoreOrder order, String fallbackCode) {
+        if (order == null) {
+            return fallbackCode;
+        }
+        Integer type = null;
+        Long refId = null;
+        if (order.getCompanyId() != null) {
+            Company company = companyMapper.selectCompanyById(order.getCompanyId());
+            if (company != null && company.getHasErpInfo() != null && company.getHasErpInfo() == 1) {
+                type = 2;
+                refId = company.getCompanyId();
+            }
+        } else {
+            FsStoreScrm store = fsStoreScrmMapper.selectFsStoreByStoreId(order.getStoreId());
+            if (store != null && store.getHasErpInfo() != null && store.getHasErpInfo() == 1) {
+                type = 1;
+                refId = store.getStoreId();
+            }
+        }
+        if (type != null && refId != null) {
+            FsStoreErpInfo erpInfo = fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(refId, type);
+            if (erpInfo != null && StringUtils.isNotBlank(erpInfo.getWarehouseCode())) {
+                return erpInfo.getWarehouseCode();
+            }
+        }
+        return fallbackCode;
+    }
+
     /**
      * 修改订单状态-收货信息
      *
@@ -1875,9 +1955,16 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         if (erpType == null) {
             return;
         }
+        // 提前加载订单,用于动态获取店铺编码
+        FsStoreOrder order = fsStoreOrderMapper.selectFsStoreOrderByOrderId(orderId);
+        if (order != null && StringUtils.isEmpty(order.getExtendOrderId()) && order.getStatus() != 2) {
+            return;
+        }
+        if (order == null) {
+            return;
+        }
         IErpOrderService erpOrderService = null;
         ErpOrder erpOrder = new ErpOrder();
-        erpOrder.setShop_code(sysConfig.getErpShopCode());
         if (erpType == 1) {
             //管易
             erpOrderService = gyOrderService;
@@ -1893,19 +1980,13 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         } else if (erpType == 5) {
             //聚水潭
             erpOrderService = jSTOrderService;
-            erpOrder.setShop_code(sysConfig.getErpJstShopCode());
         }else if (erpType == 6) {
             erpOrderService = k9OrderService;
         } else {
             return;
         }
-        FsStoreOrder order = fsStoreOrderMapper.selectFsStoreOrderByOrderId(orderId);
-        if (order != null && StringUtils.isEmpty(order.getExtendOrderId()) && order.getStatus() != 2) {
-            return;
-        }
-        if (order == null) {
-            return;
-        }
+        // 动态获取店铺编码(优先 fs_store_erp_info,降级全局配置)
+        erpOrder.setShop_code(getDynamicShopCodeForHis(order, sysConfig.getErpShopCode()));
 
         if (order.getCompanyId() != null) {
             erpOrder.setVip_code(order.getUserId().toString() + order.getCompanyId().toString());
@@ -3227,7 +3308,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         }
         erpOrder.setPlatform_code(order.getOrderCode());
 
-        erpOrder.setWarehouse_code(configUtil.getSysConfig().getErpWarehouseCode());
+        erpOrder.setWarehouse_code(getDynamicWarehouseCodeForHis(order, configUtil.getSysConfig().getErpWarehouseCode()));
         //判断是否开启erp
         FsSysConfig sysConfig = configUtil.getSysConfig();
         Integer erpOpen = sysConfig.getErpOpen();
@@ -3239,7 +3320,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                     //管易
                 } else if (erpType == 2) {
                     //旺店通
-                    erpOrder.setShop_code(sysConfig.getErpShopCode());
+                    erpOrder.setShop_code(getDynamicShopCodeForHis(order, sysConfig.getErpShopCode()));
                 }
 
             }

+ 52 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreErpInfo.java

@@ -0,0 +1,52 @@
+package com.fs.hisStore.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * ERP信息对象 fs_store_erp_info
+ * 支持店铺和销售两种类型
+ *
+ * @author fs
+ * @date 2026-05-18
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FsStoreErpInfo extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /** 类型:1-店铺 2-销售 */
+    public static final int TYPE_STORE = 1;
+    public static final int TYPE_SALES = 2;
+
+    /** 主键ID */
+    private Long id;
+
+    /** 关联ID(店铺ID或销售ID) */
+    private Long refId;
+
+    /** 类型:1-店铺 2-销售 */
+    private Integer type;
+
+    /** 店铺编码 */
+    @Excel(name = "店铺编码")
+    private String shopCode;
+
+    /** 仓库编码 */
+    @Excel(name = "仓库编码")
+    private String warehouseCode;
+
+    /** 退件收货人 */
+    @Excel(name = "退件收货人")
+    private String returnReceiver;
+
+    /** 退件收货人手机号 */
+    @Excel(name = "退件收货人手机号")
+    private String returnPhone;
+
+    /** 推荐收货地址 */
+    @Excel(name = "推荐收货地址")
+    private String returnAddress;
+}

+ 5 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreScrm.java

@@ -541,4 +541,9 @@ public class FsStoreScrm extends BaseEntity {
      **/
     private Integer daysDiffMax;
 
+    /**
+     * 是否填写ERP信息:0-否 1-是
+     **/
+    private Integer hasErpInfo;
+
 }

+ 26 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreErpInfoMapper.java

@@ -0,0 +1,26 @@
+package com.fs.hisStore.mapper;
+
+import com.fs.hisStore.domain.FsStoreErpInfo;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * ERP信息Mapper接口
+ *
+ * @author fs
+ * @date 2026-05-18
+ */
+public interface FsStoreErpInfoMapper {
+
+    FsStoreErpInfo selectFsStoreErpInfoById(Long id);
+
+    /**
+     * 根据关联ID和类型查询
+     */
+    FsStoreErpInfo selectFsStoreErpInfoByRefId(@Param("refId") Long refId, @Param("type") Integer type);
+
+    int insertFsStoreErpInfo(FsStoreErpInfo fsStoreErpInfo);
+
+    int updateFsStoreErpInfo(FsStoreErpInfo fsStoreErpInfo);
+
+    int deleteFsStoreErpInfoByRefId(@Param("refId") Long refId, @Param("type") Integer type);
+}

+ 22 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreErpInfoService.java

@@ -0,0 +1,22 @@
+package com.fs.hisStore.service;
+
+import com.fs.hisStore.domain.FsStoreErpInfo;
+
+/**
+ * ERP信息Service接口
+ *
+ * @author fs
+ * @date 2026-05-18
+ */
+public interface IFsStoreErpInfoService {
+
+    /**
+     * 根据关联ID和类型查询ERP信息
+     */
+    FsStoreErpInfo selectByRefId(Long refId, Integer type);
+
+    /**
+     * 保存或更新ERP信息(按refId+type唯一)
+     */
+    int saveOrUpdate(FsStoreErpInfo fsStoreErpInfo);
+}

+ 60 - 14
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java

@@ -17,6 +17,8 @@ import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.service.ICompanyService;
+import com.fs.company.mapper.CompanyMapper;
+import com.fs.company.domain.Company;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
@@ -156,9 +158,11 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
     @Autowired
     private JstErpHttpService jstErpHttpService;
 
-    /** 聚水潭店铺编号,用于订单查询时填充 shop_id */
-    @Value("${jst.shop_code:0}")
-    private String jstShopCode;
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    @Autowired
+    private FsStoreErpInfoMapper fsStoreErpInfoMapper;
 
     @Autowired
     private ISysConfigService configService;
@@ -1126,7 +1130,7 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
 
         //更新OMS-取消订单放到退款接口来
         IErpOrderService erpOrderService = getErpService();
-        String jstOrderStatus = queryJstOrderStatus(order.getOrderCode());
+        String jstOrderStatus = queryJstOrderStatus(order);
         boolean alreadySent = jstOrderStatus != null
                 ? "Sent".equalsIgnoreCase(jstOrderStatus)
                 : order.getStatus().equals(OrderInfoEnum.STATUS_2.getValue());
@@ -1154,11 +1158,13 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
                 refundOrderDTO.setTotalAmount(order.getTotalPrice());
                 refundOrderDTO.setRefund(order.getPayMoney());
                 refundOrderDTO.setPayment(BigDecimal.ZERO);
-                if (StringUtils.isNotBlank(jstShopCode) && !"0".equals(jstShopCode)) {
+                // 动态获取店铺编码
+                String shopCode = getDynamicShopCode(order);
+                if (StringUtils.isNotBlank(shopCode) && !"0".equals(shopCode)) {
                     try {
-                        refundOrderDTO.setShopId(Long.valueOf(jstShopCode));
+                        refundOrderDTO.setShopId(Long.valueOf(shopCode));
                     } catch (NumberFormatException ignore) {
-                        // shop_code 配置非数字时不传 shop_id,由聚水潭内部匹配
+                        // shop_code 非数字时不传 shop_id,由聚水潭内部匹配
                     }
                 }
                 // 查订单商品明细构造 items 节点
@@ -1214,13 +1220,14 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
      * 返回值为聚水潭订单状态枚举值字符串(Sent/Delivering/WaitConfirm/Cancelled 等),
      * 查不到或调用异常时返回 null,由调用方自行降级。
      *
-     * @param orderCode 线上订单号,即本地 FsStoreOrderScrm.orderCode,对应聚水潭 so_id
+     * @param order 订单信息,用于获取 orderCode 和动态 shopCode
      * @return 聚水潭订单状态值;若未查到或异常返回 null
      */
-    private String queryJstOrderStatus(String orderCode) {
-        if (StringUtils.isBlank(orderCode)) {
+    private String queryJstOrderStatus(FsStoreOrderScrm order) {
+        if (order == null || StringUtils.isBlank(order.getOrderCode())) {
             return null;
         }
+        String orderCode = order.getOrderCode();
         try {
             OrderQueryRequestDTO requestDTO = OrderQueryRequestDTO.builder()
                     .soIds(java.util.Collections.singletonList(orderCode))
@@ -1228,12 +1235,13 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
                     .pageSize(1)
                     .isGetTotal(false)
                     .build();
-            // 配置了店铺编号时一并传入,提升查询命中率
-            if (StringUtils.isNotBlank(jstShopCode) && !"0".equals(jstShopCode)) {
+            // 动态获取店铺编码
+            String shopCode = getDynamicShopCode(order);
+            if (StringUtils.isNotBlank(shopCode) && !"0".equals(shopCode)) {
                 try {
-                    requestDTO.setShopId(Integer.valueOf(jstShopCode));
+                    requestDTO.setShopId(Integer.valueOf(shopCode));
                 } catch (NumberFormatException ignore) {
-                    // shop_code 配置非数字时忽略该参数
+                    // shop_code 非数字时忽略该参数
                 }
             }
             OrderQueryResponseDTO responseDTO = jstErpHttpService.query(requestDTO);
@@ -1247,6 +1255,44 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
         }
     }
 
+    /**
+     * 动态获取店铺编码(优先使用 fs_store_erp_info 专属配置,降级使用全局配置)
+     *
+     * @param order 订单信息
+     * @return shopCode 字符串,可能为空
+     */
+    private String getDynamicShopCode(FsStoreOrderScrm order) {
+        if (order == null) {
+            return "";
+        }
+        Integer type = null;
+        Long refId = null;
+        // 优先判断是否存在销售公司
+        if (order.getCompanyId() != null) {
+            Company company = companyMapper.selectCompanyById(order.getCompanyId());
+            if (company != null && company.getHasErpInfo() != null && company.getHasErpInfo() == 1) {
+                type = 2;
+                refId = company.getCompanyId();
+            }
+        } else {
+            // 没有销售公司ID,属于商城订单
+            FsStoreScrm store = fsStoreMapper.selectFsStoreByStoreId(order.getStoreId());
+            if (store != null && store.getHasErpInfo() != null && store.getHasErpInfo() == 1) {
+                type = 1;
+                refId = store.getStoreId();
+            }
+        }
+        if (type != null && refId != null) {
+            FsStoreErpInfo erpInfo = fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(refId, type);
+            if (erpInfo != null && StringUtils.isNotBlank(erpInfo.getShopCode())) {
+                return erpInfo.getShopCode();
+            }
+        }
+        // 降级:使用全局配置
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+        return sysConfig.getErpJstShopCode();
+    }
+
     @Override
     public R audit2(FsStoreAfterSalesAudit2Param param) {
         FsStoreAfterSalesScrm storeAfterSales = fsStoreAfterSalesMapper.selectFsStoreAfterSalesById(param.getSalesId());

+ 87 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreErpInfoServiceImpl.java

@@ -0,0 +1,87 @@
+package com.fs.hisStore.service.impl;
+
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.SecurityUtils;
+import com.fs.company.domain.Company;
+import com.fs.company.mapper.CompanyMapper;
+import com.fs.hisStore.domain.FsStoreErpInfo;
+import com.fs.hisStore.domain.FsStoreScrm;
+import com.fs.hisStore.mapper.FsStoreErpInfoMapper;
+import com.fs.hisStore.mapper.FsStoreScrmMapper;
+import com.fs.hisStore.service.IFsStoreErpInfoService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * ERP信息Service实现
+ *
+ * @author fs
+ * @date 2026-05-18
+ */
+@Service
+public class FsStoreErpInfoServiceImpl implements IFsStoreErpInfoService {
+
+    @Autowired
+    private FsStoreErpInfoMapper fsStoreErpInfoMapper;
+
+    @Autowired
+    private FsStoreScrmMapper fsStoreScrmMapper;
+
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    @Override
+    public FsStoreErpInfo selectByRefId(Long refId, Integer type) {
+        if (refId == null || type == null) {
+            return null;
+        }
+        return fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(refId, type);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int saveOrUpdate(FsStoreErpInfo fsStoreErpInfo) {
+        if (fsStoreErpInfo == null || fsStoreErpInfo.getRefId() == null || fsStoreErpInfo.getType() == null) {
+            return 0;
+        }
+
+        String operator;
+        try {
+            operator = SecurityUtils.getUsername();
+        } catch (Exception e) {
+            operator = "admin";
+        }
+        FsStoreErpInfo exist = fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(
+                fsStoreErpInfo.getRefId(), fsStoreErpInfo.getType());
+        int rows;
+        if (exist == null) {
+            fsStoreErpInfo.setCreateTime(DateUtils.getNowDate());
+            fsStoreErpInfo.setUpdateTime(DateUtils.getNowDate());
+            fsStoreErpInfo.setCreateBy(operator);
+            fsStoreErpInfo.setUpdateBy(operator);
+            rows = fsStoreErpInfoMapper.insertFsStoreErpInfo(fsStoreErpInfo);
+        } else {
+            fsStoreErpInfo.setId(exist.getId());
+            fsStoreErpInfo.setUpdateTime(DateUtils.getNowDate());
+            fsStoreErpInfo.setUpdateBy(operator);
+            rows = fsStoreErpInfoMapper.updateFsStoreErpInfo(fsStoreErpInfo);
+        }
+
+        // 同步更新业务表 has_erp_info 标记
+        if (fsStoreErpInfo.getType() != null) {
+            if (fsStoreErpInfo.getType() == FsStoreErpInfo.TYPE_STORE) {
+                FsStoreScrm store = new FsStoreScrm();
+                store.setStoreId(fsStoreErpInfo.getRefId());
+                store.setHasErpInfo(1);
+                fsStoreScrmMapper.updateFsStore(store);
+            } else if (fsStoreErpInfo.getType() == FsStoreErpInfo.TYPE_SALES) {
+                Company company = new Company();
+                company.setCompanyId(fsStoreErpInfo.getRefId());
+                company.setHasErpInfo(1);
+                companyMapper.updateCompany(company);
+            }
+        }
+        return rows;
+    }
+}

+ 78 - 14
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -384,6 +384,9 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     @Autowired
     private FsStoreOrderItemScrmMapper fsStoreOrderItemScrmMapper;
 
+    @Autowired
+    private FsStoreErpInfoMapper fsStoreErpInfoMapper;
+
     @PostConstruct
     public void initErpServiceMap() {
         erpServiceMap = new HashMap<>();
@@ -2423,9 +2426,10 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             return R.error("订单:" + order.getOrderCode() + ",已推送erp/订单状态不正确");
         }
         ErpOrder erpOrder = getErpOrder(order);
-        if (erpOrderService == jSTOrderService) {
-            erpOrder.setShop_code(erpConfig.getErpJstShopCode());
-        }
+//        if (erpOrderService == jSTOrderService) {
+//            checkStoreCode(order, erpConfig, erpOrder);
+//        }
+
         ErpOrderResponse response = erpOrderService.addOrderScrm(erpOrder);
 //        ErpOrderResponse response= k9OrderService.addOmsOrder(order.getId());
 
@@ -2436,6 +2440,22 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         //写入外部订单号
         order.setExtendOrderId(response.getCode());
         fsStoreOrderMapper.updateFsStoreOrder(order);
+
+        // 聚水潭:如果设置了仓库编码,调用指定发货仓接口
+        if (erpOrderService == jSTOrderService && StringUtils.isNotBlank(erpOrder.getWarehouse_code())) {
+            try {
+                OrderModifyWmsRequestDTO wmsDto = new OrderModifyWmsRequestDTO()
+                        .setOId(Long.valueOf(response.getCode()))
+                        .setWmsCoId(Long.valueOf(erpOrder.getWarehouse_code()));
+                List<OrderModifyWmsRequestDTO> wmsList = new java.util.ArrayList<>();
+                wmsList.add(wmsDto);
+                jstErpHttpService.modifyWmsUpload(wmsList);
+                logger.info("指定发货仓成功,oId: {}, wmsCoId: {}", response.getCode(), erpOrder.getWarehouse_code());
+            } catch (Exception e) {
+                logger.error("指定发货仓失败,oId: {}, wmsCoId: {}", response.getCode(), erpOrder.getWarehouse_code(), e);
+            }
+        }
+
         return R.ok("订单:" + order.getOrderCode() + ",创建erp订单成功");
     }
 
@@ -2450,7 +2470,8 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         }
         erpOrder.setPlatform_code(order.getOrderCode());
         erpOrder.setWarehouse_code(erpConfig.getErpWarehouseCode());
-        erpOrder.setShop_code(erpConfig.getErpShopCode());
+//        erpOrder.setShop_code(erpConfig.getErpShopCode());
+        checkStoreCode(order, erpConfig, erpOrder);//获取对应店铺id
         erpOrder.setBuyer_account(order.getRealName());
 
 //      erpOrder.setPost_fee(order.getTotalPostage().doubleValue());
@@ -5332,15 +5353,20 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                     storeOrder.setStatus(OrderInfoEnum.STATUS_1.getValue());
                     storeOrder.setPayTime(new Date());
                     fsStoreOrderMapper.updateFsStoreOrder(storeOrder);
-                    //非处方直接提交OMS
-                    if (order.getIsPrescribe().equals(0)) {
-                        createOmsOrder(order.getId());
-                    } else if (order.getIsPrescribe().equals(1)) {
-                        //是否已开方
-                        FsPrescribeScrm prescribe = prescribeService.selectFsPrescribeByOrderId(order.getId());
-                        if (prescribe != null && prescribe.getStatus() == 1) {
+                    try {
+                        //非处方直接提交OMS
+                        if (order.getIsPrescribe() != null && order.getIsPrescribe().equals(0)) {
                             createOmsOrder(order.getId());
+                        } else if (order.getIsPrescribe() != null && order.getIsPrescribe().equals(1)) {
+                            //是否已开方
+                            FsPrescribeScrm prescribe = prescribeService.selectFsPrescribeByOrderId(order.getId());
+                            if (prescribe != null && prescribe.getStatus() == 1) {
+                                createOmsOrder(order.getId());
+                            }
                         }
+                    } catch (Exception e) {
+                        // 预防支付成功但上传聚水潭失败导致支付状态未改变
+                        logger.error("payConfirmMultiStore 创建ERP订单失败, orderId={}, orderCode={}", order.getId(), order.getOrderCode(), e);
                     }
                     //处理佣金 套餐不分佣金
                     if (order.getIsPackage() != 1 && order.getTuiUserId() != null && order.getTuiUserId() > 0) {
@@ -5352,9 +5378,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 }
             }
         } catch (Exception e) {
-            e.getStackTrace();
-            logger.info("payConfirm:" + e.getMessage());
-            logger.info("payConfirm:" + e.getLocalizedMessage());
+            logger.error("payConfirmMultiStore 异常, payCode={}, orderId={}", payCode, orderId, e);
             TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
             return "";
         }
@@ -6561,4 +6585,44 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
 
         return storeCount > 1;
     }
+
+    //校验获取店铺编码信息
+    public void  checkStoreCode(FsStoreOrderScrm orderScrm,FsSysConfig erpConfig,ErpOrder erpOrder){
+        Integer type = null;
+        Long refId = null;
+        //首先判断是否存在销售
+        if(orderScrm.getCompanyId() != null){
+            //获取销售
+            Company company = companyMapper.selectCompanyById(orderScrm.getCompanyId());
+            //是否设置ERP信息
+            if(company != null && company.getHasErpInfo() != null && company.getHasErpInfo() == 1){
+                type = 2;
+                refId = company.getCompanyId();
+            }
+        }else {//没有销售公司ID,属于商城订单
+            //获取店铺信息
+            FsStoreScrm storeScrm = fsStoreMapper.selectFsStoreByStoreId(orderScrm.getStoreId());
+            if(storeScrm != null && storeScrm.getHasErpInfo() != null && storeScrm.getHasErpInfo() == 1){
+                type = 1;
+                refId = storeScrm.getStoreId();
+            }
+        }
+
+        if(type != null && refId != null){
+            //获取对应ERP信息
+            FsStoreErpInfo fsStoreErpInfo = fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(refId,type);
+            // 存在则用专属配置,不存在则用全局兜底
+            if(StringUtils.isNotBlank(fsStoreErpInfo.getShopCode())){
+                erpOrder.setShop_code(fsStoreErpInfo.getShopCode());
+            }else {
+                erpOrder.setShop_code(erpConfig.getErpJstShopCode());
+            }
+            if(StringUtils.isNotBlank(fsStoreErpInfo.getWarehouseCode())){
+                erpOrder.setWarehouse_code(fsStoreErpInfo.getWarehouseCode());
+            }
+        }else {
+            //最后默认信息
+            erpOrder.setShop_code(erpConfig.getErpJstShopCode());
+        }
+    }
 }

+ 4 - 4
fs-service/src/main/resources/application-config-dev-yjb.yml

@@ -10,10 +10,10 @@ logging:
     com.fs: debug
 wx:
   open:
-#    appId: wx7796a33a71912e32 #互易享(三方入驻APP)
-#    secret: 51601ec1e3247fe1615ef7b55baf95c7 #互易享(三方入驻APP)
-    appId: wx98abee0aa8ccdd3c #鸿良(看课APP)
-    secret: 6c269d8ee939d1a241721d0dea834568 #鸿良(看课APP)
+    appId: wx7796a33a71912e32 #互易享(三方入驻APP)
+    secret: 51601ec1e3247fe1615ef7b55baf95c7 #互易享(三方入驻APP)
+#    appId: wx98abee0aa8ccdd3c #鸿良(看课APP)
+#    secret: 6c269d8ee939d1a241721d0dea834568 #鸿良(看课APP)
   miniapp:
     configs:
       - appid: wx29d26f63f836be7f

+ 77 - 0
fs-service/src/main/resources/db/20260518-店铺ERP信息表.sql

@@ -0,0 +1,77 @@
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for fs_store_erp_info
+-- ----------------------------
+DROP TABLE IF EXISTS `fs_store_erp_info`;
+CREATE TABLE `fs_store_erp_info`  (
+  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+  `ref_id` bigint NULL DEFAULT NULL COMMENT '关联ID(店铺ID或销售ID)',
+  `type` tinyint(1) NULL DEFAULT 1 COMMENT '类型:1-店铺 2-销售',
+  `shop_code` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '店铺编码',
+  `return_receiver` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '退件收货人',
+  `return_phone` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '退件收货人手机号',
+  `return_address` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '推荐收货地址',
+  `create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+  `update_time` datetime NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+  `create_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '创建人',
+  `update_by` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '更新人',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `idx_ref_id` (`ref_id`) USING BTREE,
+  KEY `idx_shop_code` (`shop_code`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = 'ERP信息表' ROW_FORMAT = Dynamic;
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+-- ----------------------------
+-- 为 fs_store_scrm 增加 has_erp_info 字段(是否已填写ERP信息:0-否 1-是)
+-- ----------------------------
+DROP PROCEDURE IF EXISTS add_fs_store_scrm_has_erp_info;
+DELIMITER $$
+CREATE PROCEDURE add_fs_store_scrm_has_erp_info()
+BEGIN
+    DECLARE CurrentDatabase VARCHAR(100);
+    SELECT DATABASE() INTO CurrentDatabase;
+
+    IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
+                   WHERE TABLE_SCHEMA = CurrentDatabase
+                     AND TABLE_NAME = 'fs_store_scrm'
+                     AND COLUMN_NAME = 'has_erp_info')
+    THEN
+        ALTER TABLE `fs_store_scrm`
+            ADD COLUMN `has_erp_info` tinyint(1) NULL DEFAULT 0 COMMENT '是否填写ERP信息:0-否 1-是';
+        -- 将已存在的历史数据初始化为 0(未填写),否则 SELECT 筛选时 ifnull(has_erp_info,0)=0 会全量命中
+        UPDATE `fs_store_scrm` SET `has_erp_info` = 0 WHERE `has_erp_info` IS NULL;
+    END IF;
+END$$
+DELIMITER ;
+
+CALL add_fs_store_scrm_has_erp_info();
+DROP PROCEDURE IF EXISTS add_fs_store_scrm_has_erp_info;
+
+-- ----------------------------
+-- 为 company 增加 has_erp_info 字段(销售公司是否已填写ERP信息:0-否 1-是)
+-- ----------------------------
+DROP PROCEDURE IF EXISTS add_company_has_erp_info;
+DELIMITER $$
+CREATE PROCEDURE add_company_has_erp_info()
+BEGIN
+    DECLARE CurrentDatabase VARCHAR(100);
+    SELECT DATABASE() INTO CurrentDatabase;
+
+    IF NOT EXISTS (SELECT 1 FROM information_schema.COLUMNS
+                   WHERE TABLE_SCHEMA = CurrentDatabase
+                     AND TABLE_NAME = 'company'
+                     AND COLUMN_NAME = 'has_erp_info')
+    THEN
+        ALTER TABLE `company`
+            ADD COLUMN `has_erp_info` tinyint(1) NULL DEFAULT 0 COMMENT '是否填写ERP信息:0-否 1-是';
+        UPDATE `company` SET `has_erp_info` = 0 WHERE `has_erp_info` IS NULL;
+    END IF;
+END$$
+DELIMITER ;
+
+CALL add_company_has_erp_info();
+DROP PROCEDURE IF EXISTS add_company_has_erp_info;
+

+ 7 - 0
fs-service/src/main/resources/mapper/company/CompanyMapper.xml

@@ -43,6 +43,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="maxPadNum"    column="max_pad_num"    />
         <result property="deptId"   column="dept_id" />
         <result property="ipadDeactivate"   column="ipad_deactivate" />
+        <result property="hasErpInfo"   column="has_erp_info" />
     </resultMap>
 
     <sql id="selectCompanyVo">
@@ -124,6 +125,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="maxPadNum != null">max_pad_num,</if>
             <if test="deptId != null">dept_id,</if>
             <if test="ipadDeactivate != null">ipad_deactivate,</if>
+            <if test="hasErpInfo != null">has_erp_info,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="companyName != null">#{companyName},</if>
@@ -161,6 +163,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="maxPadNum != null">#{maxPadNum},</if>
             <if test="deptId != null">#{deptId},</if>
             <if test="ipadDeactivate != null">#{ipadDeactivate},</if>
+            <if test="hasErpInfo != null">#{hasErpInfo},</if>
          </trim>
     </insert>
 
@@ -204,6 +207,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="maxPadNum != null">max_pad_num = #{maxPadNum},</if>
             <if test="deptId != null">dept_id = #{deptId},</if>
             <if test="ipadDeactivate != null">ipad_deactivate = #{ipadDeactivate},</if>
+            <if test="hasErpInfo != null">has_erp_info = #{hasErpInfo},</if>
         </trim>
         where company_id = #{companyId}
     </update>
@@ -323,6 +327,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <if test="ipadDeactivate != null">
            AND c.ipad_deactivate = #{ipadDeactivate}
         </if>
+            <if test="hasErpInfo != null">
+                AND ifnull(c.has_erp_info, 0) = #{hasErpInfo}
+            </if>
             GROUP BY c.company_id
             ORDER BY c.company_id DESC
     </select>

+ 90 - 0
fs-service/src/main/resources/mapper/hisStore/FsStoreErpInfoMapper.xml

@@ -0,0 +1,90 @@
+<?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.hisStore.mapper.FsStoreErpInfoMapper">
+
+    <resultMap type="com.fs.hisStore.domain.FsStoreErpInfo" id="FsStoreErpInfoResult">
+        <result property="id"             column="id"/>
+        <result property="refId"          column="ref_id"/>
+        <result property="type"           column="type"/>
+        <result property="shopCode"       column="shop_code"/>
+        <result property="warehouseCode"  column="warehouse_code"/>
+        <result property="returnReceiver" column="return_receiver"/>
+        <result property="returnPhone"    column="return_phone"/>
+        <result property="returnAddress"  column="return_address"/>
+        <result property="createTime"     column="create_time"/>
+        <result property="updateTime"     column="update_time"/>
+        <result property="createBy"       column="create_by"/>
+        <result property="updateBy"       column="update_by"/>
+    </resultMap>
+
+    <sql id="selectFsStoreErpInfoVo">
+        select id, ref_id, type, shop_code, warehouse_code, return_receiver, return_phone, return_address,
+               create_time, update_time, create_by, update_by
+        from fs_store_erp_info
+    </sql>
+
+    <select id="selectFsStoreErpInfoById" parameterType="Long" resultMap="FsStoreErpInfoResult">
+        <include refid="selectFsStoreErpInfoVo"/>
+        where id = #{id}
+    </select>
+
+    <select id="selectFsStoreErpInfoByRefId" resultMap="FsStoreErpInfoResult">
+        <include refid="selectFsStoreErpInfoVo"/>
+        where ref_id = #{refId}
+          and type = #{type}
+        limit 1
+    </select>
+
+    <insert id="insertFsStoreErpInfo" parameterType="com.fs.hisStore.domain.FsStoreErpInfo" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_store_erp_info
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="refId != null">ref_id,</if>
+            <if test="type != null">type,</if>
+            <if test="shopCode != null">shop_code,</if>
+            <if test="warehouseCode != null">warehouse_code,</if>
+            <if test="returnReceiver != null">return_receiver,</if>
+            <if test="returnPhone != null">return_phone,</if>
+            <if test="returnAddress != null">return_address,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="updateBy != null">update_by,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="refId != null">#{refId},</if>
+            <if test="type != null">#{type},</if>
+            <if test="shopCode != null">#{shopCode},</if>
+            <if test="warehouseCode != null">#{warehouseCode},</if>
+            <if test="returnReceiver != null">#{returnReceiver},</if>
+            <if test="returnPhone != null">#{returnPhone},</if>
+            <if test="returnAddress != null">#{returnAddress},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+        </trim>
+    </insert>
+
+    <update id="updateFsStoreErpInfo" parameterType="com.fs.hisStore.domain.FsStoreErpInfo">
+        update fs_store_erp_info
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="refId != null">ref_id = #{refId},</if>
+            <if test="type != null">type = #{type},</if>
+            <if test="shopCode != null">shop_code = #{shopCode},</if>
+            <if test="warehouseCode != null">warehouse_code = #{warehouseCode},</if>
+            <if test="returnReceiver != null">return_receiver = #{returnReceiver},</if>
+            <if test="returnPhone != null">return_phone = #{returnPhone},</if>
+            <if test="returnAddress != null">return_address = #{returnAddress},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsStoreErpInfoByRefId">
+        delete from fs_store_erp_info where ref_id = #{refId} and type = #{type}
+    </delete>
+
+</mapper>

+ 7 - 2
fs-service/src/main/resources/mapper/hisStore/FsStoreScrmMapper.xml

@@ -93,6 +93,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="reportUrl" column="report_url" />
         <result property="filingUrl" column="filing_url" />
         <result property="permStatus" column="perm_status" />
+        <result property="hasErpInfo" column="has_erp_info" />
     </resultMap>
 
     <sql id="selectFsStoreVo">
@@ -112,7 +113,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
                is_drug_license_permanent,is_medical_device2_expiry_permanent,is_medical_device3_expiry_permanent,is_food_license_expiry_permanent,is_medical_license_expiry_permanent,
                title_Name_one,title_Name_two,title_Name_three,settlement_agreement_file_name,quality_assurance_agreement_fileName,other_special_qualification_fileName,
                is_effective_permanent1,is_effective_permanent2,is_effective_permanent3,medical_device2_business_scope,medical_device3_business_scope,drug_license_business_scope
-            ,food_license_business_scope,drug_scope_has_frozen,report_url,filing_url,perm_status
+            ,food_license_business_scope,drug_scope_has_frozen,report_url,filing_url,perm_status,has_erp_info
         from fs_store_scrm
     </sql>
 
@@ -128,6 +129,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="queryStoreId != null "> or store_id = #{queryStoreId}</if>
             <if test="storeSeq != null  and storeSeq != ''"> and store_seq like concat('%', #{storeSeq}, '%')</if>
             <if test="merchantId != null  and merchantId != ''"> and merchant_id like concat('%', #{merchantId}, '%')</if>
+            <if test="hasErpInfo != null"> and ifnull(has_erp_info, 0) = #{hasErpInfo}</if>
         </where>
         order by store_id desc
     </select>
@@ -447,6 +449,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="reportUrl !=null ">report_url = #{reportUrl}, </if>
             <if test="filingUrl !=null ">filing_url = #{filingUrl}, </if>
             <if test="permStatus !=null ">perm_status = #{permStatus}, </if>
+            <if test="hasErpInfo !=null ">has_erp_info = #{hasErpInfo}, </if>
             <if test="medicalDevice2 !=null and medicalDevice2 != ''">medical_device2 = #{medicalDevice2} ,</if>
             <if test="medicalDevice2BusinessScope !=null and medicalDevice2BusinessScope != ''">medical_device2_business_scope = #{medicalDevice2BusinessScope} ,</if>
             <if test="medicalDevice2Code !=null and medicalDevice2Code != ''">medical_device2_code = #{medicalDevice2Code} ,</if>
@@ -460,6 +463,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="foodLicense !=null and foodLicense != ''">food_license = #{foodLicense} ,</if>
             <if test="foodLicenseExpiryStart !=null">food_license_expiry_start = #{foodLicenseExpiryStart} ,</if>
             <if test="foodLicenseExpiryEnd !=null">food_license_expiry_end = #{foodLicenseExpiryEnd} ,</if>
+            <if test="hasErpInfo !=null">has_erp_info = #{hasErpInfo} ,</if>
         </trim>
         where store_id = #{storeId}
     </update>
@@ -890,7 +894,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         other_special_qualification_start,other_special_qualification_end,is_business_license_permanent,store_seq,merchant_id,business_code,
         drug_code,medical_device1_code,medical_device2_code,medical_device3_code,food_code,medical_code,other_special_qualification_code,
         quality_assurance_agreement_code,settlement_agreement_code,title_name_one,title_Name_two,title_Name_three,
-        qualification_update_time,medical_device3,
+        qualification_update_time,medical_device3,ss.has_erp_info,
         DATE_ADD(qualification_update_time, INTERVAL 6 MONTH) as next_qualification_update_time,
         DATEDIFF(DATE_ADD(qualification_update_time, INTERVAL 6 MONTH), NOW()) AS days_diff,
         ( SELECT COUNT(*) FROM fs_store_product_scrm sps WHERE sps.store_id = ss.store_id ) AS productCount
@@ -904,6 +908,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="isAudit != null "> and is_audit = #{isAudit}</if>
             <if test="account != null  and account != ''"> and account like concat('%', #{account}, '%')</if>
             <if test="queryStoreId != null "> or store_id = #{queryStoreId}</if>
+            <if test="hasErpInfo != null "> and has_erp_info = #{hasErpInfo}</if>
             <if test="daysDiffMax != null">
                 <!-- 判断剩余天数范围 -->
                 <if test="daysDiffMax == 0">

+ 1 - 1
fs-service/src/main/resources/mapper/statis/ConsumptionBalanceMapper.xml

@@ -315,7 +315,7 @@
         course_id,
         user_id,
         MAX(CASE WHEN is_right = 1 THEN 1 ELSE 0 END) AS correct_flag
-        FROM fs_course_answer_logs
+        FROM fs_course_answer_logs FORCE INDEX (idx_create_course_user)
         <where>
             <if test="startTime != null and startTime != ''">
                 AND create_time <![CDATA[>=]]> #{startTime}

+ 50 - 0
fs-user-app/src/main/java/com/fs/app/controller/store/StoreOrderScrmController.java

@@ -20,7 +20,9 @@ import com.fs.common.utils.ip.IpUtils;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.factory.SnowflakeFactory;
+import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyDivItem;
+import com.fs.company.mapper.CompanyMapper;
 import com.fs.company.service.ICompanyDivItemService;
 import com.fs.his.domain.FsStoreOrderScrmComment;
 import com.fs.his.domain.FsUser;
@@ -33,7 +35,9 @@ import com.fs.hisStore.domain.*;
 import com.fs.hisStore.dto.FsStoreOrderComputeDTO;
 import com.fs.hisStore.enums.OrderInfoEnum;
 import com.fs.hisStore.mapper.FsStoreCartScrmMapper;
+import com.fs.hisStore.mapper.FsStoreErpInfoMapper;
 import com.fs.hisStore.mapper.FsStoreOrderScrmMapper;
+import com.fs.hisStore.mapper.FsStoreScrmMapper;
 import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
 import com.fs.hisStore.mapper.FsStoreVerifyCodeScrmMapper;
 import com.fs.hisStore.param.*;
@@ -115,6 +119,15 @@ public class StoreOrderScrmController extends AppBaseController {
     @Autowired
     private FsStorePaymentScrmMapper fsStorePaymentMapper;
 
+    @Autowired
+    private CompanyMapper companyMapper;
+
+    @Autowired
+    private FsStoreScrmMapper fsStoreScrmMapper;
+
+    @Autowired
+    private FsStoreErpInfoMapper fsStoreErpInfoMapper;
+
     @Autowired
     private IFsStoreOrderItemScrmService itemService;
 
@@ -1342,6 +1355,43 @@ public class StoreOrderScrmController extends AppBaseController {
     }
 
 
+    @Login
+    @ApiOperation("获取ERP退件信息")
+    @PostMapping("/getErpReturnInfo")
+    public R getErpReturnInfo(@Validated @RequestBody FsStoreOrderExpressParam param, HttpServletRequest request){
+        FsStoreOrderScrm order = orderService.selectFsStoreOrderById(param.getOrderId());
+        if (ObjectUtil.isNull(order)) {
+            throw new CustomException("订单不存在");
+        }
+        // 优先判断 companyId 是否存在
+        Integer type = null;
+        Long refId = null;
+        if (order.getCompanyId() != null) {
+            Company company = companyMapper.selectCompanyById(order.getCompanyId());
+            if (company != null && company.getHasErpInfo() != null && company.getHasErpInfo() == 1) {
+                type = FsStoreErpInfo.TYPE_SALES;
+                refId = company.getCompanyId();
+            }
+        } else {
+            FsStoreScrm store = fsStoreScrmMapper.selectFsStoreByStoreId(order.getStoreId());
+            if (store != null && store.getHasErpInfo() != null && store.getHasErpInfo() == 1) {
+                type = FsStoreErpInfo.TYPE_STORE;
+                refId = store.getStoreId();
+            }
+        }
+        if (type != null && refId != null) {
+            FsStoreErpInfo erpInfo = fsStoreErpInfoMapper.selectFsStoreErpInfoByRefId(refId, type);
+            if (erpInfo != null) {
+                return R.ok()
+                        .put("returnReceiver", erpInfo.getReturnReceiver())
+                        .put("returnPhone", erpInfo.getReturnPhone())
+                        .put("returnAddress", erpInfo.getReturnAddress());
+            }
+        }
+        return R.error("未设置ERP退件信息");
+    }
+
+
     @Login
     @ApiOperation("确认套餐订单")
     @PostMapping("/confirmPackageOrder")

+ 85 - 0
sql/optimize_fs_course_watch_log.sql

@@ -0,0 +1,85 @@
+-- ======================================================
+-- fs_course_watch_log 索引优化(不锁表操作)
+-- MySQL 8.0.30+,使用 ALGORITHM=INPLACE, LOCK=NONE
+-- 建议在业务低峰期执行,逐条或分批
+-- ======================================================
+
+-- ==================== 第一批:删除冗余索引 ====================
+
+-- 单列索引(被复合索引前缀覆盖,冗余)
+ALTER TABLE fs_course_watch_log DROP INDEX user_id, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX index_video_id, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX index_log_type, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX index_company_id, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX index_company_user_id, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX index_reward_type, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX index_send_msg, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX qw_user_id, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX qw_external_contact_id, ALGORITHM=INPLACE, LOCK=NONE;
+
+-- 重复/重叠复合索引
+ALTER TABLE fs_course_watch_log DROP INDEX idx_user_video_qw_user, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_company_logid, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_create_company_user, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_w_ctime_course_vid_uid_log, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX sendTypeAndCreate, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX index_0, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_fwl_video_user_logtype, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX index_2, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_send_type_log, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_covering_watch, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_covering_date_stats, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_group_company, ALGORITHM=INPLACE, LOCK=NONE;
+ALTER TABLE fs_course_watch_log DROP INDEX idx_ultimate_watch, ALGORITHM=INPLACE, LOCK=NONE;
+
+
+-- ==================== 第二批:新增核心索引 ====================
+
+-- 1. 看课状态查询 + 批量更新(video_id, user_id, company_user_id)
+-- 涵盖:getWatchLogByFsUser, batchUpdateFsUserWatchLog, batchUpdateWatchLogIsOpen
+ALTER TABLE fs_course_watch_log 
+  ADD INDEX idx_video_user_cu (video_id, user_id, company_user_id),
+  ALGORITHM=INPLACE, LOCK=NONE;
+
+-- 2. 统计列表 + 定时任务按公司统计
+-- 涵盖:selectFsCourseWatchLogStatisticsListVONew, watchCourseStatisticsGroupByCompany
+ALTER TABLE fs_course_watch_log 
+  ADD INDEX idx_send_time_company (send_type, create_time, company_id),
+  ALGORITHM=INPLACE, LOCK=NONE;
+
+-- 3. 用户维度聚合查询(7天/15天统计)
+-- 涵盖:getUserWatchStatusAndLastWatchDate, FsUserCourseCountMapper 相关查询
+ALTER TABLE fs_course_watch_log 
+  ADD INDEX idx_uid_send_time_proj (user_id, send_type, create_time, project),
+  ALGORITHM=INPLACE, LOCK=NONE;
+
+-- 4. 销售维度 count/统计(company_user_id + log_type + 时间范围)
+-- 涵盖:countByMap, queryCompanyUserWatchCount, queryCompanyUserWatchCountCompleted, queryCompanyUserInterruptCount
+ALTER TABLE fs_course_watch_log 
+  ADD INDEX idx_cu_logtype_time (company_user_id, log_type, create_time),
+  ALGORITHM=INPLACE, LOCK=NONE;
+
+-- 5. 营期 + 销售查询
+-- 涵盖:queryCompanyUserWatchCount(camp_period_time过滤)
+ALTER TABLE fs_course_watch_log 
+  ADD INDEX idx_cu_camp_log (company_user_id, camp_period_time, log_type),
+  ALGORITHM=INPLACE, LOCK=NONE;
+
+
+-- ==================== 验证 ====================
+-- 执行后查看最终索引列表
+-- SHOW INDEX FROM fs_course_watch_log;
+--
+-- 最终保留索引(共12个):
+--   1. PRIMARY              (log_id)
+--   2. UNIQUE one_user      (video_id, qw_external_contact_id, qw_user_id)
+--   3. index_finish_time    (finish_time)
+--   4. create_time          (create_time)
+--   5. idx_period_id        (period_id)
+--   6. index_1              (sop_id, log_type)
+--   7. idx_video_user_cu    (video_id, user_id, company_user_id)      [NEW]
+--   8. idx_send_time_company(send_type, create_time, company_id)      [NEW]
+--   9. idx_uid_send_time_proj(user_id, send_type, create_time, project) [NEW]
+--  10. idx_cu_logtype_time  (company_user_id, log_type, create_time)  [NEW]
+--  11. idx_cu_camp_log      (company_user_id, camp_period_time, log_type) [NEW]
+--  12. idx_finish_time      (finish_time)