ソースを参照

Merge branch 'master' into 红德堂APP调试

# Conflicts:
#	fs-service/src/main/java/com/fs/his/domain/FsIntegralOrder.java
#	fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java
#	fs-user-app/src/main/java/com/fs/app/controller/CourseController.java
Long 2 日 前
コミット
68410856be
100 ファイル変更5971 行追加207 行削除
  1. 2 2
      .gitignore
  2. 2 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserCoursePeriodController.java
  3. 12 0
      fs-admin/src/main/java/com/fs/course/controller/FsUserVideoController.java
  4. 1 1
      fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderController.java
  5. 12 1
      fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java
  6. 74 7
      fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java
  7. 6 9
      fs-admin/src/main/java/com/fs/his/controller/FsUserController.java
  8. 45 12
      fs-admin/src/main/java/com/fs/his/controller/HzOMSErpApiController.java
  9. 15 0
      fs-admin/src/main/java/com/fs/his/task/Task.java
  10. 103 0
      fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerController.java
  11. 118 0
      fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerLogController.java
  12. 118 0
      fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerUserController.java
  13. 1 1
      fs-admin/src/main/resources/application.yml
  14. 13 4
      fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java
  15. 3 29
      fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java
  16. 0 1
      fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptRoleController.java
  17. 1 1
      fs-company/src/main/java/com/fs/company/controller/qw/QwUserVoiceLogController.java
  18. 19 15
      fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsInfoController.java
  19. 29 3
      fs-company/src/main/java/com/fs/company/controller/store/FsInquiryOrderController.java
  20. 4 3
      fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java
  21. 34 0
      fs-ipad-task/src/main/java/com/fs/app/service/CustomThreadPoolConfig.java
  22. 7 3
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  23. 36 47
      fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java
  24. 1 0
      fs-ipad-task/src/main/java/com/fs/framework/config/DataSourceConfig.java
  25. 13 13
      fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java
  26. 1 1
      fs-qw-task/src/main/resources/application.yml
  27. 18 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwUserController.java
  28. 18 0
      fs-qwhook-sop/src/main/java/com/fs/app/controller/QwUserController.java
  29. 1 1
      fs-qwhook-sop/src/main/resources/application.yml
  30. 20 0
      fs-qwhook/src/main/java/com/fs/app/controller/ApisQwUserController.java
  31. 16 0
      fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java
  32. 2 0
      fs-service/src/main/java/com/fs/common/param/LoginParam.java
  33. 4 1
      fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java
  34. 4 1
      fs-service/src/main/java/com/fs/config/ai/AiHostProper.java
  35. 1 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseMapper.java
  36. 19 1
      fs-service/src/main/java/com/fs/course/mapper/FsUserCourseVideoMapper.java
  37. 3 0
      fs-service/src/main/java/com/fs/course/mapper/FsVideoResourceMapper.java
  38. 4 0
      fs-service/src/main/java/com/fs/course/param/FsUserCourseVideoParam.java
  39. 6 0
      fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java
  40. 49 22
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  41. 52 12
      fs-service/src/main/java/com/fs/course/service/impl/TencentCloudCosService.java
  42. 118 0
      fs-service/src/main/java/com/fs/erp/constant/AfterSalesOrderStatusEnum.java
  43. 111 0
      fs-service/src/main/java/com/fs/erp/constant/ErpQueryOrderStatusEnum.java
  44. 90 0
      fs-service/src/main/java/com/fs/erp/constant/OrderStatusEnum.java
  45. 87 0
      fs-service/src/main/java/com/fs/erp/constant/TaskStatusEnum.java
  46. 2 0
      fs-service/src/main/java/com/fs/erp/domain/ErpOrder.java
  47. 85 0
      fs-service/src/main/java/com/fs/erp/domain/FsJstAftersalePush.java
  48. 77 0
      fs-service/src/main/java/com/fs/erp/domain/FsJstCodPush.java
  49. 40 0
      fs-service/src/main/java/com/fs/erp/dto/AfterSaleConfirmRequestDTO.java
  50. 69 0
      fs-service/src/main/java/com/fs/erp/dto/AfterSaleResponseDTO.java
  51. 45 0
      fs-service/src/main/java/com/fs/erp/dto/AssetProcessDetailDTO.java
  52. 42 0
      fs-service/src/main/java/com/fs/erp/dto/AssetProcessResultDTO.java
  53. 35 0
      fs-service/src/main/java/com/fs/erp/dto/CommonResponse.java
  54. 56 0
      fs-service/src/main/java/com/fs/erp/dto/ErpOrderResponseDTO.java
  55. 22 0
      fs-service/src/main/java/com/fs/erp/dto/ExtDataDTO.java
  56. 62 0
      fs-service/src/main/java/com/fs/erp/dto/FinanceDataDTO.java
  57. 51 0
      fs-service/src/main/java/com/fs/erp/dto/GetInitTokenRequestDTO.java
  58. 41 0
      fs-service/src/main/java/com/fs/erp/dto/GetInitTokenResponseDTO.java
  59. 297 0
      fs-service/src/main/java/com/fs/erp/dto/GoodsInfoDTO.java
  60. 38 0
      fs-service/src/main/java/com/fs/erp/dto/OrderCancelRequestDTO.java
  61. 33 0
      fs-service/src/main/java/com/fs/erp/dto/OrderExtDTO.java
  62. 52 0
      fs-service/src/main/java/com/fs/erp/dto/OrderExtDataDTO.java
  63. 58 0
      fs-service/src/main/java/com/fs/erp/dto/OrderItemDTO.java
  64. 137 0
      fs-service/src/main/java/com/fs/erp/dto/OrderQueryRequestDTO.java
  65. 799 0
      fs-service/src/main/java/com/fs/erp/dto/OrderQueryResponseDTO.java
  66. 42 0
      fs-service/src/main/java/com/fs/erp/dto/PaymentDTO.java
  67. 112 0
      fs-service/src/main/java/com/fs/erp/dto/ProductQueryRequestDTO.java
  68. 405 0
      fs-service/src/main/java/com/fs/erp/dto/ProductResponseDTO.java
  69. 37 0
      fs-service/src/main/java/com/fs/erp/dto/ProductUploadResultDTO.java
  70. 63 0
      fs-service/src/main/java/com/fs/erp/dto/RefreshTokenRequestDTO.java
  71. 65 0
      fs-service/src/main/java/com/fs/erp/dto/RefundItemDTO.java
  72. 158 0
      fs-service/src/main/java/com/fs/erp/dto/ShopOrderDTO.java
  73. 11 0
      fs-service/src/main/java/com/fs/erp/dto/df/DFCancelOrderResultRequest.java
  74. 1 0
      fs-service/src/main/java/com/fs/erp/dto/df/DFConfigVo.java
  75. 11 0
      fs-service/src/main/java/com/fs/erp/dto/df/DFOrderStatusResultRequest.java
  76. 1 0
      fs-service/src/main/java/com/fs/erp/dto/sdk/df/enums/RequestUrlEnum.java
  77. 79 0
      fs-service/src/main/java/com/fs/erp/http/JstErpHttpService.java
  78. 296 0
      fs-service/src/main/java/com/fs/erp/http/JstErpHttpServiceImpl.java
  79. 110 0
      fs-service/src/main/java/com/fs/erp/mapper/FsJstAftersalePushMapper.java
  80. 77 0
      fs-service/src/main/java/com/fs/erp/mapper/FsJstCodPushMapper.java
  81. 5 0
      fs-service/src/main/java/com/fs/erp/service/FsJstAftersalePushService.java
  82. 5 0
      fs-service/src/main/java/com/fs/erp/service/FsJstCodPushService.java
  83. 3 0
      fs-service/src/main/java/com/fs/erp/service/IErpOrderService.java
  84. 104 10
      fs-service/src/main/java/com/fs/erp/service/impl/DfOrderServiceImpl.java
  85. 6 0
      fs-service/src/main/java/com/fs/erp/service/impl/ErpOrderServiceImpl.java
  86. 172 0
      fs-service/src/main/java/com/fs/erp/service/impl/FsJstAftersalePushServiceImpl.java
  87. 53 0
      fs-service/src/main/java/com/fs/erp/service/impl/FsJstCodPushServiceImpl.java
  88. 5 0
      fs-service/src/main/java/com/fs/erp/service/impl/HzOMSErpOrderServiceImpl.java
  89. 52 0
      fs-service/src/main/java/com/fs/erp/service/impl/JSTErpGoodsServiceImpl.java
  90. 369 0
      fs-service/src/main/java/com/fs/erp/service/impl/JSTErpOrderServiceImpl.java
  91. 193 0
      fs-service/src/main/java/com/fs/erp/service/impl/JstTokenService.java
  92. 5 0
      fs-service/src/main/java/com/fs/erp/service/impl/WdtErpOrderServiceImpl.java
  93. 149 0
      fs-service/src/main/java/com/fs/erp/utils/SignUtil.java
  94. 7 2
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java
  95. 5 1
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiNewServiceImpl.java
  96. 6 1
      fs-service/src/main/java/com/fs/fastGpt/service/impl/AiServiceImpl.java
  97. 7 0
      fs-service/src/main/java/com/fs/his/config/FsSysConfig.java
  98. 10 0
      fs-service/src/main/java/com/fs/his/domain/FsIntegralOrder.java
  99. 7 0
      fs-service/src/main/java/com/fs/his/domain/FsStoreOrderDf.java
  100. 6 1
      fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java

+ 2 - 2
.gitignore

@@ -6,8 +6,8 @@ target/
 !**/src/main/**/target/
 !**/src/test/**/target/
 #logback.xml
-application-druid-rt.yml
-application-druid-yjf.yml
+application.yml
+
 
 ### STS ###
 .apt_generated

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

@@ -189,6 +189,7 @@ public class FsUserCoursePeriodController extends BaseController {
         return R.ok().put("data", periodRedPacketList);
     }
 
+    @Log(title = "按课程批量保存设置红包金额", businessType = BusinessType.UPDATE)
     @PreAuthorize("@ss.hasPermi('course:period:setCourseRedPacket')")
     @ApiOperation("按课程批量保存设置红包金额")
     @PostMapping("/batchRedPacket")
@@ -202,6 +203,7 @@ public class FsUserCoursePeriodController extends BaseController {
         return R.ok();
     }
 
+    @Log(title = "按营期批量保存设置红包金额", businessType = BusinessType.UPDATE)
     @PreAuthorize("@ss.hasPermi('course:period:setRedPacket')")
     @ApiOperation("按营期批量保存设置红包金额")
     @PostMapping("/batchRedPacket/byPeriod")

+ 12 - 0
fs-admin/src/main/java/com/fs/course/controller/FsUserVideoController.java

@@ -9,9 +9,11 @@ import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.domain.FsUserVideo;
 import com.fs.course.domain.FsVideoResource;
 import com.fs.course.param.*;
+import com.fs.course.service.IFsUserCourseVideoService;
 import com.fs.course.service.IFsUserVideoService;
 import com.fs.course.service.IFsVideoResourceService;
 import com.fs.course.service.impl.TencentCloudCosService;
@@ -55,6 +57,9 @@ public class FsUserVideoController extends BaseController
     @Autowired
     private IFsVideoResourceService iFsVideoResourceService;
 
+    @Autowired
+    private IFsUserCourseVideoService fsUserCourseVideoService;
+
     /**
      * 查询课堂视频列表
      */
@@ -354,6 +359,13 @@ public class FsUserVideoController extends BaseController
             iFsVideoResourceService.updateById(videoMap);
             log.info("成功更新视频转码状态,视频ID: {}", video.getId());
 
+
+            FsUserCourseVideo fsUserCourseVideo = fsUserCourseVideoService.selectByFileKey(video.getFileKey());
+            fsUserCourseVideo.setLineOne(video.getLine1().replace(inputPath,transcodeFileKey));
+            fsUserCourseVideo.setTranscodeFileKey(transcodeFileKey);
+            fsUserCourseVideo.setIsTranscode(1);
+            fsUserCourseVideoService.updateFsUserCourseVideo(fsUserCourseVideo);
+
             return R.ok();
         } catch (Exception e) {
             log.error("处理视频转码请求时发生异常", e);

+ 1 - 1
fs-admin/src/main/java/com/fs/his/controller/FsInquiryOrderController.java

@@ -157,7 +157,7 @@ public class FsInquiryOrderController extends BaseController
     @GetMapping(value = "/sendMsg/{orderId}")
     public AjaxResult sendMsg(@PathVariable("orderId") Long orderId)
     {
-        ;
+
         return AjaxResult.success(fsInquiryOrderService.sendStartMsg(orderId));
     }
     /**

+ 12 - 1
fs-admin/src/main/java/com/fs/his/controller/FsIntegralOrderController.java

@@ -1,6 +1,7 @@
 package com.fs.his.controller;
 
 import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSONObject;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
@@ -16,6 +17,7 @@ import com.fs.his.enums.ShipperCodeEnum;
 import com.fs.his.param.FsIntegralOrderParam;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsIntegralOrderService;
+import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -66,8 +68,17 @@ public class FsIntegralOrderController extends BaseController
     {
         List<FsIntegralOrder> list = fsIntegralOrderService.selectFsIntegralOrderList(fsIntegralOrder);
         for (FsIntegralOrder vo : list) {
+            //商品名称以及原价赋值
+            String itemJson = vo.getItemJson();
+            if(StringUtils.isNotBlank(itemJson)){
+                JSONObject jsonObject = JSONObject.parseObject(itemJson);
+                vo.setGoodsName(jsonObject.getString("goodsName"));
+                vo.setOtPrice(jsonObject.getBigDecimal("otPrice"));
+            }
             if (vo.getUserPhone()!=null&&!vo.getUserPhone().equals("")){
-                vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                if(vo.getUserPhone().chars().allMatch(Character::isDigit)){continue;}
+//                vo.setUserPhone(vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2"));
+                vo.setUserPhone(PhoneUtil.decryptPhone(vo.getUserPhone()));
             }
         }
         ExcelUtil<FsIntegralOrder> util = new ExcelUtil<FsIntegralOrder>(FsIntegralOrder.class);

+ 74 - 7
fs-admin/src/main/java/com/fs/his/controller/FsStoreOrderController.java

@@ -17,6 +17,7 @@ import com.fs.common.utils.StringUtils;
 import com.fs.company.param.CompanyStoreOrderMoneyLogsListParam;
 import com.fs.company.service.ICompanyMoneyLogsService;
 import com.fs.company.vo.CompanyStoreOrderMoneyLogsVO;
+import com.fs.config.cloud.CloudHostProper;
 import com.fs.erp.domain.ErpDeliverys;
 import com.fs.erp.domain.ErpOrderQuery;
 import com.fs.erp.dto.ErpDeliverysRequest;
@@ -42,6 +43,7 @@ import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.*;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
+import com.github.pagehelper.PageHelper;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -105,18 +107,41 @@ public class FsStoreOrderController extends BaseController
 
     @Autowired
     private IFsStoreOrderDfService fsStoreOrderDfService;
+
+    @Autowired
+    private CloudHostProper cloudHostProper;
     /**
      * 查询订单列表
      */
-    @GetMapping("/list")
-    public TableDataInfo list(FsStoreOrderParam fsStoreOrder)
+    @PostMapping("/list")
+    public TableDataInfo list(@RequestBody FsStoreOrderParam fsStoreOrder)
     {
-        startPage();
-        if (fsStoreOrder.getUserPhoneMk()!=null&&fsStoreOrder.getUserPhoneMk()!=""){
+        PageHelper.startPage(fsStoreOrder);
+        if (fsStoreOrder.getUserPhoneMk()!=null&& !fsStoreOrder.getUserPhoneMk().isEmpty()){
             fsStoreOrder.setUserPhone(encryptPhone(fsStoreOrder.getUserPhoneMk()));
         }
-        List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVO(fsStoreOrder);
-        return getDataTable(list);
+        List<FsStoreOrderListVO> list;
+        if (StringUtils.isNotBlank(fsStoreOrder.getErpAccount())){
+            //金牛erp查询
+            list = fsStoreOrderService.selectFsStoreOrderListVOByErpAccount(fsStoreOrder);
+        } else {
+            list = fsStoreOrderService.selectFsStoreOrderListVO(fsStoreOrder);
+        }
+        //金牛需求 区别其他项目 status = 6 (金牛代服管家) ,其他项目请避免使用订单状态status = 6
+        TableDataInfo dataTable = getDataTable(list);
+        if ("金牛明医".equals(cloudHostProper.getCompanyName())){
+            if (fsStoreOrder.getStatus() !=null && fsStoreOrder.getStatus() != 1){
+                list.forEach(vo->{
+                    //查询顺丰代服账号
+                    FsStoreOrderDf df = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(vo.getOrderId());
+                    if (df != null){
+                        vo.setErpAccount(df.getLoginAccount());
+                    }
+                });
+            }
+            dataTable.setMsg("jnmy");
+        }
+        return dataTable;
     }
 
     /**
@@ -526,7 +551,10 @@ public class FsStoreOrderController extends BaseController
         orderIds.forEach(orderId->{
             try {
                 df.setOrderId(orderId);
-                fsStoreOrderDfService.insertFsStoreOrderDf(df);
+                FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
+                if (temp == null){
+                    fsStoreOrderDfService.insertFsStoreOrderDf(df);
+                }
                 fsStoreOrderService.createOmsOrder(orderId);
             } catch (ParseException e) {
                 throw new RuntimeException(e);
@@ -536,6 +564,44 @@ public class FsStoreOrderController extends BaseController
         return R.ok();
     }
 
+
+    @ApiOperation("批量设置订单账户")
+    @PreAuthorize("@ss.hasPermi('his:storeOrder:createErpOrder')")
+    @PostMapping(value = "/batchSetErpOrder")
+    public R batchSetErpOrder(@RequestBody FsStoreOrderSetErpPhoneParam param)
+    {
+        String loginAccount = param.getLoginAccount();
+        if (StringUtils.isBlank(loginAccount)){
+            return R.error("未选择erp账户");
+        }
+        FsStoreOrderDf df = getDFInfo(loginAccount);
+        if (df.getLoginAccount() == null){
+            return R.error("未查询到所选erp账户");
+        }
+        List<Long> orderIds = param.getOrderIds();
+        if (orderIds  == null || orderIds.isEmpty()) {
+            if (param.getUserPhoneMk() != null && !param.getUserPhoneMk().isEmpty()) {
+                param.setUserPhone(encryptPhone(param.getUserPhoneMk()));
+            }
+            List<FsStoreOrderListVO> list = fsStoreOrderService.selectFsStoreOrderListVO(param);
+            orderIds = list.stream().map(FsStoreOrderListVO::getOrderId).collect(Collectors.toList());
+        }
+        if (orderIds.isEmpty()){
+            return R.ok();
+        }
+        orderIds.forEach(orderId->{
+            df.setOrderId(orderId);
+            FsStoreOrderDf temp = fsStoreOrderDfService.selectFsStoreOrderDfByOrderId(df.getOrderId());
+            if (temp != null){
+                df.setUpdateTime(new Date());
+                fsStoreOrderDfService.updateFsStoreOrderDf(df);
+            } else {
+                fsStoreOrderDfService.insertFsStoreOrderDf(df);
+            }
+        });
+        return R.ok();
+    }
+
     private FsStoreOrderDf getDFInfo(String loginAccount) {
         //查询订单账户 判断是否存在该订单账户
         List<DFConfigVo> erpAccounts = fsStoreOrderService.getErpAccount();
@@ -547,6 +613,7 @@ public class FsStoreOrderController extends BaseController
                 df.setAppSecret(erpAccount.getDfAppsecret());
                 df.setLoginAccount(loginAccount);
                 df.setMonthlyCard(erpAccount.getMonthlyCard());
+                df.setExpressProductCode(erpAccount.getExpressProductCode());
                 df.setStatus(0);
                 break;
             }

+ 6 - 9
fs-admin/src/main/java/com/fs/his/controller/FsUserController.java

@@ -212,16 +212,13 @@ public class FsUserController extends BaseController
 //        startPage();
 //        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
-        if(ObjectUtils.isNotNull(fsUserPageListVOPageInfo)){
-            for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOPageInfo.getList()) {
-                fsUserPageListVO.setPhone(ParseUtils.parsePhone(fsUserPageListVO.getPhone()));
-            }
-            Map<String, Object> map = new HashMap<String, Object>();
-            map.put("rows", fsUserPageListVOPageInfo.getList());
-            map.put("total", fsUserPageListVOPageInfo.getList().size());
-            return R.ok(map);
+        for (FsUserPageListVO fsUserPageListVO : fsUserPageListVOPageInfo.getList()) {
+            fsUserPageListVO.setPhone(ParseUtils.parsePhone(fsUserPageListVO.getPhone()));
         }
-        return R.ok();
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("rows", fsUserPageListVOPageInfo.getList());
+        map.put("total", fsUserPageListVOPageInfo.getTotal());
+        return R.ok(map);
     }
 
     @PreAuthorize("@ss.hasPermi('his:user:enabledUsers')")

+ 45 - 12
fs-admin/src/main/java/com/fs/his/controller/HzOMSErpApiController.java

@@ -2,26 +2,23 @@ package com.fs.his.controller;
 
 
 import com.fs.common.core.domain.R;
-import com.fs.erp.domain.ErpOrder;
-import com.fs.erp.dto.ErpOrderResponse;
-import com.fs.erp.dto.df.BspOrderResponse;
-import com.fs.erp.dto.sdk.HzOMS.utils.HzOMSUtils;
+import com.fs.common.utils.StringUtils;
 import com.fs.erp.service.IErpOrderService;
-import com.fs.his.domain.FsStoreOrder;
-import com.fs.his.domain.FsVessel;
 import com.fs.his.param.HzOMSErpApiParam;
 import com.fs.his.service.ErpApiService;
 import com.fs.his.service.IFsStoreOrderService;
-import com.fs.his.service.impl.FsStoreOrderServiceImpl;
 import com.fs.his.vo.HzOMSErpResponseVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.io.IOUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
-import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
 
 /**
  * 瀚智OMS Erp系统推送平数据接口
@@ -29,6 +26,7 @@ import java.util.List;
 
 @RestController
 @RequestMapping("/erp/call")
+@Slf4j
 public class HzOMSErpApiController {
 
     @Autowired
@@ -132,8 +130,43 @@ public class HzOMSErpApiController {
      * 代服管家订单回调
      */
     @PostMapping("/dfNotifyUrl")
-    public R dfOrderResult(@RequestBody BspOrderResponse param)
-    {
-        return fsStoreOrderService.dfOrderResult(param);
+    public R dfOrderResult(HttpServletRequest request){
+        String body = null;
+        try {
+            // 1. 先设置编码
+            request.setCharacterEncoding("UTF-8");
+            // 3. 按 UTF-8 解码
+            body = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            log.error("读取 body 失败", e);
+            return null;
+        }
+        log.info("Body UTF-8: {}", body);
+
+        return StringUtils.isNotBlank(body)
+                ? fsStoreOrderService.dfOrderResult(body)
+                : R.ok();
+    }
+
+    /**
+     * 代服管家订单状态回调
+     */
+    @PostMapping("/receiveWaybillPush")
+    public R receiveWaybillPush(HttpServletRequest request) {
+        String body = null;
+        try {
+            // 1. 先设置编码
+            request.setCharacterEncoding("UTF-8");
+            // 3. 按 UTF-8 解码
+            body = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8);
+        } catch (IOException e) {
+            log.error("读取 body 失败", e);
+            return null;
+        }
+        log.info("Body UTF-8: {}", body);
+
+        return StringUtils.isNotBlank(body)
+                ? fsStoreOrderService.receiveWaybillPush(body)
+                : R.ok();
     }
 }

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

@@ -302,6 +302,21 @@ public class Task {
 
     }
 
+
+    public void getOrderDeliveryStatus()
+    {
+        IErpOrderService erpOrderService = getErpService();
+        List<FsStoreOrder> orders = null;
+        if (erpOrderService !=null && erpOrderService == dfOrderService){
+            orders = fsStoreOrderMapper.selectShippedOrder();
+            if(orders!=null&& !orders.isEmpty()){
+                for(FsStoreOrder order:orders){
+                    erpOrderService.getOrderDeliveryStatus(order);
+                }
+            }
+        }
+    }
+
     public void CreateOmsAndHis()
     {
         List<Long> omsList = fsStoreOrderMapper.selectFsStoreOrderNoCreateOms();

+ 103 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerController.java

@@ -0,0 +1,103 @@
+package com.fs.qw.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+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.qw.domain.QwIpadServer;
+import com.fs.qw.service.IQwIpadServerService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * ipad服务器Controller
+ *
+ * @author fs
+ * @date 2025-07-23
+ */
+@RestController
+@RequestMapping("/qw/qwIpadServer")
+public class QwIpadServerController extends BaseController
+{
+    @Autowired
+    private IQwIpadServerService qwIpadServerService;
+
+    /**
+     * 查询ipad服务器列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwIpadServer qwIpadServer)
+    {
+        startPage();
+        List<QwIpadServer> list = qwIpadServerService.selectQwIpadServerList(qwIpadServer);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出ipad服务器列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:export')")
+    @Log(title = "ipad服务器", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(QwIpadServer qwIpadServer)
+    {
+        List<QwIpadServer> list = qwIpadServerService.selectQwIpadServerList(qwIpadServer);
+        ExcelUtil<QwIpadServer> util = new ExcelUtil<QwIpadServer>(QwIpadServer.class);
+        return util.exportExcel(list, "ipad服务器数据");
+    }
+
+    /**
+     * 获取ipad服务器详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwIpadServerService.selectQwIpadServerById(id));
+    }
+
+    /**
+     * 新增ipad服务器
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:add')")
+    @Log(title = "ipad服务器", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwIpadServer qwIpadServer)
+    {
+        return toAjax(qwIpadServerService.insertQwIpadServer(qwIpadServer));
+    }
+
+    /**
+     * 修改ipad服务器
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:edit')")
+    @Log(title = "ipad服务器", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwIpadServer qwIpadServer)
+    {
+        return toAjax(qwIpadServerService.updateQwIpadServer(qwIpadServer));
+    }
+
+    /**
+     * 删除ipad服务器
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServer:remove')")
+    @Log(title = "ipad服务器", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwIpadServerService.deleteQwIpadServerByIds(ids));
+    }
+}

+ 118 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerLogController.java

@@ -0,0 +1,118 @@
+package com.fs.qw.controller;
+
+import java.util.List;
+
+import com.fs.qw.param.IPadServerLogParam;
+import com.fs.qw.vo.QwIPadServerLogVO;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+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.qw.domain.QwIpadServerLog;
+import com.fs.qw.service.IQwIpadServerLogService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * ipad服务器日志Controller
+ *
+ * @author fs
+ * @date 2025-07-23
+ */
+@RestController
+@RequestMapping("/qw/qwIpadServerLog")
+public class QwIpadServerLogController extends BaseController
+{
+    @Autowired
+    private IQwIpadServerLogService qwIpadServerLogService;
+
+    /**
+     * 查询ipad服务器日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwIpadServerLog qwIpadServerLog)
+    {
+        startPage();
+        List<QwIpadServerLog> list = qwIpadServerLogService.selectQwIpadServerLogList(qwIpadServerLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询ipad服务器日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:list')")
+    @GetMapping("/ipadServerLogList")
+    public TableDataInfo ipadServerLogList(IPadServerLogParam iPadServerLogParam)
+    {
+        startPage();
+        List<QwIPadServerLogVO> list = qwIpadServerLogService.selectIpadServerLogList(iPadServerLogParam);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出ipad服务器日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:export')")
+    @Log(title = "ipad服务器日志", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(IPadServerLogParam qwIpadServerLog)
+    {
+        List<QwIPadServerLogVO> list = qwIpadServerLogService.selectIpadServerLogList(qwIpadServerLog);
+        ExcelUtil<QwIPadServerLogVO> util = new ExcelUtil<QwIPadServerLogVO>(QwIPadServerLogVO.class);
+        return util.exportExcel(list, "ipad服务器日志数据");
+    }
+
+    /**
+     * 获取ipad服务器日志详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwIpadServerLogService.selectQwIpadServerLogById(id));
+    }
+
+    /**
+     * 新增ipad服务器日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:add')")
+    @Log(title = "ipad服务器日志", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwIpadServerLog qwIpadServerLog)
+    {
+        return toAjax(qwIpadServerLogService.insertQwIpadServerLog(qwIpadServerLog));
+    }
+
+    /**
+     * 修改ipad服务器日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:edit')")
+    @Log(title = "ipad服务器日志", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwIpadServerLog qwIpadServerLog)
+    {
+        return toAjax(qwIpadServerLogService.updateQwIpadServerLog(qwIpadServerLog));
+    }
+
+    /**
+     * 删除ipad服务器日志
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerLog:remove')")
+    @Log(title = "ipad服务器日志", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwIpadServerLogService.deleteQwIpadServerLogByIds(ids));
+    }
+}

+ 118 - 0
fs-admin/src/main/java/com/fs/qw/controller/QwIpadServerUserController.java

@@ -0,0 +1,118 @@
+package com.fs.qw.controller;
+
+import java.util.List;
+
+import com.fs.qw.param.IPadServerUserParam;
+import com.fs.qw.vo.QwIPadServerUserVO;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+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.qw.domain.QwIpadServerUser;
+import com.fs.qw.service.IQwIpadServerUserService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * ipad用户Controller
+ *
+ * @author fs
+ * @date 2025-07-23
+ */
+@RestController
+@RequestMapping("/qw/qwIpadServerUser")
+public class QwIpadServerUserController extends BaseController
+{
+    @Autowired
+    private IQwIpadServerUserService qwIpadServerUserService;
+
+    /**
+     * 查询ipad用户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(QwIpadServerUser qwIpadServerUser)
+    {
+        startPage();
+        List<QwIpadServerUser> list = qwIpadServerUserService.selectQwIpadServerUserList(qwIpadServerUser);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询ipad用户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:list')")
+    @GetMapping("/ipadServerUserList")
+    public TableDataInfo list(IPadServerUserParam iPadServerUserParam)
+    {
+        startPage();
+        List<QwIPadServerUserVO> list = qwIpadServerUserService.selectIpadServerUserList(iPadServerUserParam);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出ipad用户列表
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:export')")
+    @Log(title = "ipad用户", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(IPadServerUserParam iPadServerUserParam)
+    {
+        List<QwIPadServerUserVO> list = qwIpadServerUserService.selectIpadServerUserList(iPadServerUserParam);
+        ExcelUtil<QwIPadServerUserVO> util = new ExcelUtil<QwIPadServerUserVO>(QwIPadServerUserVO.class);
+        return util.exportExcel(list, "ipad用户数据");
+    }
+
+    /**
+     * 获取ipad用户详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(qwIpadServerUserService.selectQwIpadServerUserById(id));
+    }
+
+    /**
+     * 新增ipad用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:add')")
+    @Log(title = "ipad用户", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody QwIpadServerUser qwIpadServerUser)
+    {
+        return toAjax(qwIpadServerUserService.insertQwIpadServerUser(qwIpadServerUser));
+    }
+
+    /**
+     * 修改ipad用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:edit')")
+    @Log(title = "ipad用户", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody QwIpadServerUser qwIpadServerUser)
+    {
+        return toAjax(qwIpadServerUserService.updateQwIpadServerUser(qwIpadServerUser));
+    }
+
+    /**
+     * 删除ipad用户
+     */
+    @PreAuthorize("@ss.hasPermi('qw:qwIpadServerUser:remove')")
+    @Log(title = "ipad用户", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(qwIpadServerUserService.deleteQwIpadServerUserByIds(ids));
+    }
+}

+ 1 - 1
fs-admin/src/main/resources/application.yml

@@ -4,7 +4,7 @@ server:
 # Spring配置
 spring:
   profiles:
-    active: dev
+    active: druid-myhk-test
 #    active: druid-hdt
 #    active: druid-yzt
 #    active: druid-sxjz

+ 13 - 4
fs-company-app/src/main/java/com/fs/app/controller/FsUserController.java

@@ -5,7 +5,6 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.fs.app.annotation.Login;
 import com.fs.app.config.ImageStorageConfig;
-
 import com.fs.app.param.FsUserTagUpdateParam;
 import com.fs.app.param.FsUserUpdateParam;
 import com.fs.common.core.domain.R;
@@ -42,7 +41,10 @@ import java.io.InputStream;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 @Slf4j
 @Api(tags = "用户会员相关接口")
@@ -78,6 +80,7 @@ public class FsUserController extends AppBaseController {
         param.setUserId(Long.parseLong(getUserId()));
 //        PageHelper.startPage(param.getPageNum(), param.getPageSize());
         PageInfo<FsUserPageListVO> fsUserPageListVOPageInfo = fsUserService.selectFsUserPageList(param);
+//        PageInfo<FsUserPageListVO> pageInfo = new PageInfo<>(list);
         return ResponseResult.ok(fsUserPageListVOPageInfo);
     }
 
@@ -299,7 +302,7 @@ public class FsUserController extends AppBaseController {
         return ResponseResult.ok(fsUserService.companyUserSummaryCount(userId, companyUserId));
     }
 
-    @Login
+//    @Login
     @ApiOperation("会员关联绑定销售")
     @PostMapping("/beMember")
     public ResponseResult<Boolean> becomeMember(@Valid @RequestBody FsUserCourseBeMemberParam param) {
@@ -326,7 +329,7 @@ public class FsUserController extends AppBaseController {
             String userPosterImage = jsonObject.getString("userPosterImage");
             String backgroundImagePath;
             if(StringUtils.isEmpty(userPosterImage)){
-                backgroundImagePath = "https://drk-1363981074.cos.ap-chongqing.myqcloud.com/fs/logo/30d7a0d1ec31e5ac16c6e96d5ca76ad.png";
+                backgroundImagePath = "https://fbylive.obs.cn-southwest-2.myhuaweicloud.com/fs/20250430/1745980979886.png";
             } else {
                 backgroundImagePath = userPosterImage;
             }
@@ -341,4 +344,10 @@ public class FsUserController extends AppBaseController {
         }
     }
 
+    @PostMapping("/test")
+    @ApiOperation("测试定时任务")
+    public void userCourseCountTask() {
+        userCourseCountService.insertFsUserCourseCountTask();
+    }
+
 }

+ 3 - 29
fs-company-app/src/main/java/com/fs/app/controller/FsUserCourseVideoController.java

@@ -1,7 +1,5 @@
 package com.fs.app.controller;
 
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.json.JSONUtil;
 import com.fs.app.annotation.Login;
 import com.fs.app.config.ImageStorageConfig;
 import com.fs.common.core.domain.R;
@@ -9,7 +7,6 @@ import com.fs.common.core.domain.ResponseResult;
 import com.fs.common.utils.StringUtils;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.service.ICompanyUserService;
-import com.fs.course.config.CourseConfig;
 import com.fs.course.domain.FsUserCoursePeriod;
 import com.fs.course.param.FsCourseLinkCreateParam;
 import com.fs.course.param.FsWatchCourseTimeParam;
@@ -20,13 +17,11 @@ import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsUserCoursePeriodService;
 import com.fs.course.service.IFsUserCourseService;
 import com.fs.course.service.IFsUserCourseVideoService;
-import com.fs.course.service.impl.FsUserCourseServiceImpl;
 import com.fs.course.vo.FsUserCourseParticipationRecordVO;
 import com.fs.course.vo.newfs.FsUserCourseListVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoDetailsVO;
 import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.course.vo.newfs.FsUserVideoListVO;
-import com.fs.system.service.ISysConfigService;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -37,7 +32,6 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.InputStream;
-import java.time.LocalDate;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -56,8 +50,6 @@ public class FsUserCourseVideoController extends AppBaseController {
 
     @Autowired
     private IFsUserCourseService fsUserCourseService;
-    @Autowired
-    private ISysConfigService configService;
 
     @Autowired
     private IFsCourseLinkService courseLinkService;
@@ -165,15 +157,8 @@ public class FsUserCourseVideoController extends AppBaseController {
 
         R courseSortLink = fsUserCourseService.createCourseSortLink(fsCourseLinkCreateParam);
         String link = courseSortLink.get("link").toString();
-//        R r = courseLinkService.getRealLink(link);
-//        String realLink = r.get("realLink").toString();
-        String json = configService.selectConfigByKey("course.config");
-        CourseConfig config = JSONUtil.toBean(json, CourseConfig.class);
-        //验证是否有分配二级域名
-        CompanyUser companyUser=companyUserService.selectCompanyUserById(param.getCompanyUserId());
-        String realLink = (ObjectUtil.isNotNull(companyUser) && ObjectUtil.isNotNull(companyUser.getDomain())?companyUser.getDomain():config.getRealLinkDomainName()) + FsUserCourseServiceImpl.shortLink + link;
-
-        log.info("二维码生成地址:{}", realLink);
+        R r = courseLinkService.getRealLink(link);
+        String realLink = r.get("realLink").toString();
         try {
             String path = imageConfig.getServerPath();
             log.info("获取的logo图片路径,fileUrl:{}", path);
@@ -229,7 +214,7 @@ public class FsUserCourseVideoController extends AppBaseController {
 
         Map<String, Object> params = new HashMap<>();
         params.put("companyId", companyId);
-        params.put("dayDate", LocalDate.now());
+//        params.put("dayDate", LocalDate.now());
         params.put("companyUserId", Long.parseLong(getUserId()));
 
         PageHelper.startPage(pageNum, pageSize);
@@ -249,16 +234,5 @@ public class FsUserCourseVideoController extends AppBaseController {
         return fsUserCourseVideoService.setWatchCourseTime(collect);
     }
 
-    /**
-     * 获取跳转微信小程序的链接地址
-     * @param linkStr
-     * @return
-     */
-    @Login
-    @GetMapping("/getGotoWxAppLink")
-    @ApiOperation("获取跳转微信小程序的链接地址")
-    public ResponseResult<String> getGotoWxAppLink(String linkStr,String appid) {
-        return ResponseResult.ok(courseLinkService.getGotoWxAppLink(linkStr,appid));
-    }
 
 }

+ 0 - 1
fs-company/src/main/java/com/fs/company/controller/fastGpt/FastGptRoleController.java

@@ -61,7 +61,6 @@ public class FastGptRoleController extends BaseController
     @GetMapping("/getAllRoleType")
     public R list()
     {
-
         List<OptionsVO> list = fastGptRoleService.selectFastGptRoleType();
         return R.ok().put("data",list);
     }

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

@@ -107,7 +107,7 @@ public class QwUserVoiceLogController extends BaseController
         return getDataTable(list);
     }
 
-    @PreAuthorize("@ss.hasPermi('qw:qwUserVoiceLog:sellTotalList')")
+
     @GetMapping("/sellTotalList")
     public TableDataInfo sellTotalList(QwUserVoiceLogTotalVo qwUserVoiceLog)
     {

+ 19 - 15
fs-company/src/main/java/com/fs/company/controller/qw/SopUserLogsInfoController.java

@@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.Predicate;
@@ -114,12 +115,6 @@ public class SopUserLogsInfoController extends BaseController
                 });
             }
 
-
-//            Predicate<SopUserLogsInfo> tagFilter = item ->
-//                    sopUserLogsInfo.getTagIds() == null ||
-//                            sopUserLogsInfo.getTagIds().isEmpty() ||
-//                            item.getTagIds().contains(sopUserLogsInfo.getTagIds());
-
             Predicate<SopUserLogsInfo> tagFilter = item -> {
                 String queryTagIds = sopUserLogsInfo.getTagIds();
                 String itemTagIds = item.getTagIds();
@@ -148,25 +143,34 @@ public class SopUserLogsInfoController extends BaseController
 
 
             Predicate<SopUserLogsInfo> timeFilter = item -> {
-                if (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getEntryTime())) {
+
+                if (StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
+                        && StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime()) ) {
                     return true;
                 }
                 try {
-                    LocalDate entryDate = LocalDate.parse(
-                            sopUserLogsInfo.getEntryTime(),
-                            DateTimeFormatter.ofPattern("yyyy-MM-dd")
+                    LocalDateTime entryDate = LocalDateTime.parse(item.getInComTime(),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
+                    );
+                    LocalDateTime inComingSTime = LocalDateTime.parse(sopUserLogsInfo.getInComingSTime(),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                     );
-                    LocalDate createDate = LocalDate.parse(
-                            item.getInComTime().substring(0, 10),
-                            DateTimeFormatter.ofPattern("yyyy-MM-dd")
+
+                    LocalDateTime inComingETime = LocalDateTime.parse(sopUserLogsInfo.getInComingETime(),
+                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                     );
-                    return entryDate.equals(createDate);
+
+                    return !entryDate.isBefore(inComingSTime) && !entryDate.isAfter(inComingETime);
                 } catch (Exception e) {
                     return false;
                 }
             };
 
-            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty || !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getEntryTime()) ||!isLevelEmpty) {
+
+            boolean hasTimeFilter = !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingSTime())
+                    && !StringUtil.strIsNullOrEmpty(sopUserLogsInfo.getInComingETime());
+
+            if (sopUserLogsInfo.getTagIds() != null || !isRemarkEmpty || hasTimeFilter ||!isLevelEmpty) {
                 list = list.stream()
                         .filter(tagFilter.and(remarkFilter).and(timeFilter).and(levelFilter))
                         .collect(Collectors.toList());

+ 29 - 3
fs-company/src/main/java/com/fs/company/controller/store/FsInquiryOrderController.java

@@ -1,5 +1,6 @@
 package com.fs.company.controller.store;
 
+import cn.hutool.core.util.IdUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Log;
 import com.fs.common.annotation.RepeatSubmit;
@@ -7,6 +8,7 @@ import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.AjaxResult;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.core.redis.RedisCache;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.StringUtils;
 import com.fs.framework.security.LoginUser;
@@ -16,6 +18,7 @@ import com.fs.his.domain.FsInquiryOrder;
 import com.fs.his.domain.FsInquiryOrderMsg;
 import com.fs.his.domain.FsStoreOrderLogs;
 import com.fs.his.param.FsInquiryOrderCancelParam;
+import com.fs.his.param.FsInquiryOrderCreateParam;
 import com.fs.his.param.FsInquiryOrderParam;
 import com.fs.his.param.FsInquiryOrderRefundParam;
 import com.fs.his.service.IFsDoctorService;
@@ -32,9 +35,11 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.Base64;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 问诊订单Controller
@@ -247,16 +252,24 @@ public class FsInquiryOrderController extends BaseController
         }
         return AjaxResult.success(fsInquiryOrderVO);
     }
-
+    @Autowired
+    RedisCache redisCache;
     /**
      * 新增问诊订单
      */
     @PreAuthorize("@ss.hasPermi('store:inquiryOrder:add')")
     @Log(title = "问诊订单", businessType = BusinessType.INSERT)
     @PostMapping
-    public AjaxResult add(@RequestBody FsInquiryOrder fsInquiryOrder)
+    public R add(@RequestBody FsInquiryOrderCreateParam param)
     {
-        return toAjax(fsInquiryOrderService.insertFsInquiryOrder(fsInquiryOrder));
+        String uuid = IdUtil.randomUUID();
+        redisCache.setCacheObject("orderKey:"+uuid,uuid,200, TimeUnit.MINUTES);
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        param.setOrderKey(uuid);
+        param.setCompanyId(loginUser.getCompany().getCompanyId());
+        param.setCompanyUserId(loginUser.getUser().getUserId());
+        param.setIsVisit("就诊过");
+        return fsInquiryOrderService.createOrder(param);
     }
 
     /**
@@ -350,4 +363,17 @@ public class FsInquiryOrderController extends BaseController
     }
 
 
+    /**
+    * 生成订单二维码
+    */
+    @PreAuthorize("@ss.hasPermi('store:inquiryOrder:wxaCodeInquiryOrder')")
+    @GetMapping("/getWxaCodeInquiryOrderUnLimit/{orderId}")
+    public AjaxResult getWxaCodeInquiryOrderUnLimit(@PathVariable("orderId") Long orderId)
+    {
+
+        byte[] bytes = fsInquiryOrderService.getWxaCodeInquiryOrderUnLimit(orderId);
+        String base64 = Base64.getEncoder().encodeToString(bytes);
+        return AjaxResult.success("成功",base64);
+
+    }
 }

+ 4 - 3
fs-company/src/main/java/com/fs/company/controller/store/FsUserController.java

@@ -76,9 +76,10 @@ public class FsUserController extends BaseController
     public TableDataInfo userList(FsUserParam fsUser)
     {
         startPage();
-        if(fsUser.getPhoneMk()!=null&&fsUser.getPhone()!=""){
-            fsUser.setPhone(encryptPhone(fsUser.getPhoneMk()));
-        }
+
+
+        fsUser.setPhone(encryptPhone(fsUser.getPhone()));
+
         List<FsUserVO> list = fsUserService.selectFsUserListVOByComponent(fsUser);
         for (FsUserVO fsUserVO : list) {
             fsUserVO.setPhone(decryptAutoPhoneMk(fsUserVO.getPhone()));

+ 34 - 0
fs-ipad-task/src/main/java/com/fs/app/service/CustomThreadPoolConfig.java

@@ -0,0 +1,34 @@
+package com.fs.app.service;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @author MixLiu
+ * @date 2025/7/11 上午11:04)
+ */
+@Configuration
+public class CustomThreadPoolConfig {
+    @Bean(name = "customThreadPool", destroyMethod = "shutdown")
+    public ThreadPoolTaskExecutor customThreadPool() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        // 核心线程数
+        executor.setCorePoolSize(300);
+        // 最大线程数
+        executor.setMaxPoolSize(300);
+        // 线程名前缀
+        executor.setThreadNamePrefix("custom-pool-");
+        // 拒绝策略:直接丢弃新任务
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
+        // 非核心线程空闲存活时间(秒)
+        executor.setKeepAliveSeconds(60);
+        // 等待所有任务完成后关闭线程池
+        executor.setWaitForTasksToCompleteOnShutdown(true);
+        // 初始化
+        executor.initialize();
+        return executor;
+    }
+}

+ 7 - 3
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -141,10 +141,10 @@ public class IpadSendServer {
         }
     }
 
-    public boolean isSend(QwUser qwUser) {
+    public boolean isSend(QwUser qwUser, BaseVo parentVo) {
         // 判断企微发送方式是否是ipad
         if (qwUser.getSendMsgType() == 0) {
-            log.debug("企微用户:ID:{} 名称:{} 发送方式:{}", qwUser.getId(), qwUser.getQwUserName(), qwUser.getSendMsgType().toString());
+            log.debug("发送方式是侧边栏企微用户:ID:{} 名称:{}", qwUser.getId(), qwUser.getQwUserName());
             return false;
         }
         // 判断是否信息准确
@@ -188,6 +188,7 @@ public class IpadSendServer {
                 qwUserMapper.updateById(updateQwUser);
                 return false;
             }
+            parentVo.setCorpId(login.getUser_info().getObject().getCorp_id());
             log.debug("QwUserID:{}, AI主机信息:{}", qwUser.getId(), login);
         } catch (Exception e) {
             updateQwUser.setId(qwUser.getId());
@@ -196,6 +197,7 @@ public class IpadSendServer {
             qwUserMapper.updateById(updateQwUser);
             return false;
         }
+
         return true;
     }
 
@@ -277,13 +279,15 @@ public class IpadSendServer {
         return true;
     }
 
-    public void send(QwSopCourseFinishTempSetting.Setting content, QwUser qwUser, QwSopLogs qwSopLogs, Map<String, CourseMaConfig> miniMap) {
+    public void send(QwSopCourseFinishTempSetting.Setting content, QwUser qwUser, QwSopLogs qwSopLogs, Map<String, CourseMaConfig> miniMap, BaseVo parentVo) {
         BaseVo vo = new BaseVo();
         vo.setId(Long.parseLong(qwSopLogs.getId()));
         vo.setRoom(qwSopLogs.getSendType() == 12);
         vo.setUuid(qwUser.getUid());
         vo.setExId(qwSopLogs.getExternalUserId());
         vo.setServerId(qwUser.getServerId());
+        vo.setCorpCode(parentVo.getCorpCode());
+        vo.setCorpId(parentVo.getCorpId());
         try {
             content.setSendStatus(1);
             switch (content.getContentType()) {

+ 36 - 47
fs-ipad-task/src/main/java/com/fs/app/task/SendMsg.java

@@ -15,7 +15,6 @@ import com.fs.qw.mapper.QwIpadServerMapper;
 import com.fs.qw.mapper.QwUserMapper;
 import com.fs.qw.service.impl.AsyncSopTestService;
 import com.fs.qw.vo.QwSopCourseFinishTempSetting;
-import com.fs.qw.vo.QwSopTempSetting;
 import com.fs.sop.domain.QwSopLogs;
 import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.service.IQwSopLogsService;
@@ -37,7 +36,6 @@ import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
 
 @Component
 @Slf4j
@@ -56,7 +54,6 @@ public class SendMsg {
     private String groupNo;
     private final List<QwUser> qwUserList = Collections.synchronizedList(new ArrayList<>());
     private final Map<Long, Long> qwMap = new ConcurrentHashMap<>();
-    private final Map<Long, Long> removeQwMap = new ConcurrentHashMap<>();
 
     @Autowired
     @Qualifier("customThreadPool")
@@ -75,7 +72,7 @@ public class SendMsg {
     private List<QwUser> getQwUserList() {
         if (qwUserList.isEmpty()) {
             List<QwIpadServer> serverList = qwIpadServerMapper.selectList(new QueryWrapper<QwIpadServer>().eq("group_no", groupNo));
-            if(serverList.isEmpty()){
+            if (serverList.isEmpty()) {
                 return new ArrayList<>();
             }
             List<Long> serverIds = PubFun.listToNewList(serverList, QwIpadServer::getId);
@@ -117,45 +114,36 @@ public class SendMsg {
             delayEnd = config.getDelayEnd();
         }
         Map<String, CourseMaConfig> miniMap = getMiniMap();
-        // 清空需要删除的
-        List<Long> keyList = new ArrayList<>(removeQwMap.keySet());
-        keyList.forEach(key -> {
-            removeQwMap.remove(key);
-            qwMap.remove(key);
-        });
-        log.info("删除id:{}", JSON.toJSONString(keyList));
         getQwUserList().forEach(e -> {
-            synchronized (e.getId()){
-                if (qwMap.containsKey(e.getId())) {
-                    log.error("用户:{}已在处理中,跳过重复执行", e.getQwUserName());
-                    return;
-                }
-                qwMap.computeIfAbsent(e.getId(), k -> {
-                    CompletableFuture.runAsync(() -> {
-                        try {
-                            processUser(e, delayStart, delayEnd, miniMap);
-                        } catch (Exception exception){
-                            log.error("发送错误:", exception);
-                        }finally {
-                            removeQwMap.putIfAbsent(e.getId(), System.currentTimeMillis());
-                        }
-                    }, customThreadPool);
-                    return System.currentTimeMillis(); // 占位值
-                });
-            }
+            qwMap.computeIfAbsent(e.getId(), k -> {
+                CompletableFuture.runAsync(() -> {
+                    try {
+                        log.info("开始任务:{}", e.getQwUserName());
+                        processUser(e, delayStart, delayEnd, miniMap);
+                    } catch (Exception exception) {
+                        log.error("发送错误:", exception);
+                    } finally {
+                        log.info("删除任务:{}", e.getQwUserName());
+                        qwMap.remove(e.getId());
+//                        removeQwMap.putIfAbsent(e.getId(), System.currentTimeMillis());
+                    }
+                }, customThreadPool);
+                return System.currentTimeMillis(); // 占位值
+            });
         });
     }
 
     private void processUser(QwUser qwUser, int delayStart, int delayEnd, Map<String, CourseMaConfig> miniMap) {
         long start1 = System.currentTimeMillis();
         List<QwSopLogs> qwSopLogList = qwSopLogsMapper.selectByQwUserId(qwUser.getId());
-        if(qwSopLogList.isEmpty()){
+        if (qwSopLogList.isEmpty()) {
             return;
         }
         QwUser user = qwUserMapper.selectById(qwUser.getId());
         BaseVo parentVo = new BaseVo();
+        parentVo.setCorpCode(qwUser.getCorpId());
         long end1 = System.currentTimeMillis();
-        if (!sendServer.isSend(user)) {
+        if (!sendServer.isSend(user, parentVo)) {
             return;
         }
         log.info("销售:{}, 消息:{}, 耗时: {}, 时间:{}", user.getQwUserName(), qwSopLogList.size(), end1 - start1, qwMap.get(qwUser.getId()));
@@ -171,24 +159,27 @@ public class SendMsg {
             log.info("进入发送消息状态:{}", qwSopLogs.getId());
             String key = "qw:logs:pad:send:id:" + qwSopLogs.getId();
             Long time = redisCache.getCacheObject(key);
-            if(redisCache.getCacheObject(key) != null){
+            if (redisCache.getCacheObject(key) != null) {
                 log.error("{}已有发送:{}, :{}", qwUser.getQwUserName(), qwSopLogs.getId(), time);
                 return;
             }
             redisCache.setCacheObject(key, System.currentTimeMillis(), 10, TimeUnit.MINUTES);
             for (QwSopCourseFinishTempSetting.Setting content : setting.getSetting()) {
-                sendServer.send(content, user, qwSopLogs, miniMap);
-//                if(content.getSendStatus() == 2 && "请求失败:消息发送过于频繁,请稍后再试".equals(content.getSendRemarks())){
-//                    QwUser update = new QwUser();
-//                    update.setRemark("请求频率异常,暂停发送,三小时后恢复继续发送");
-//                    update.setUpdateTime(new Date());
-//                    qwUserMapper.update(update, new QueryWrapper<QwUser>().eq("id", user.getId()));
-//                    redisCache.setCacheObject("qw:user:id:" + user.getId(), user.getId(), 3, TimeUnit.HOURS);
-//                    return;
-//                }
+                long start4 = System.currentTimeMillis();
+                sendServer.send(content, user, qwSopLogs, miniMap, parentVo);
+                long end4 = System.currentTimeMillis();
+                log.info("请求pad发送完成:{}, {}, 时长4:{}", user.getQwUserName(), qwSopLogs.getId(), end4 - start4);
+                if(content.getSendStatus() == 2 && "请求失败:消息发送过于频繁,请稍后再试".equals(content.getSendRemarks())){
+                    QwUser update = new QwUser();
+                    update.setRemark("请求频率异常,暂停发送,三小时后恢复继续发送");
+                    update.setUpdateTime(new Date());
+                    qwUserMapper.update(update, new QueryWrapper<QwUser>().eq("id", user.getId()));
+                    redisCache.setCacheObject("qw:user:id:" + user.getId(), user.getId(), 3, TimeUnit.HOURS);
+                    return;
+                }
                 try {
                     int delay = ThreadLocalRandom.current().nextInt(300, 1000);
-                    log.debug("等待:{}ms", delay);
+                    log.debug("pad发送消息等待:{}ms", delay);
                     Thread.sleep(delay);
                 } catch (InterruptedException e) {
                     log.error("线程等待错误!");
@@ -214,15 +205,13 @@ public class SendMsg {
                 updateQwSop.setRemark("全部发送成功");
                 updateQwSop.setRealSendTime(sdf.format(new Date()));
             }
-//            updateQwSop.setReceivingStatus(1L);
-//            updateQwSop.setSendStatus(1L);
-//            updateQwSop.setRealSendTime(sdf.format(new Date()));
+            updateQwSop.setContentJson(JSON.toJSONString(setting));
             long end2 = System.currentTimeMillis();
             int i = qwSopLogsService.updateQwSopLogsSendType(updateQwSop);
-            log.info("销售:{}, 修改条数{}, 发送方消息完成:{}, 耗时: {}", user.getQwUserName(), i, qwSopLogs.getId(),end2 - start2);
+            log.info("销售:{}, 修改条数{}, 发送方消息完成:{}, 耗时: {}", user.getQwUserName(), i, qwSopLogs.getId(), end2 - start2);
             try {
                 int delay = ThreadLocalRandom.current().nextInt(delayStart, delayEnd);
-                log.debug("等待:{}ms", delay);
+                log.debug("企微发送消息等待:{}ms", delay);
                 Thread.sleep(delay);
             } catch (InterruptedException e) {
                 log.error("线程等待错误!");

+ 1 - 0
fs-ipad-task/src/main/java/com/fs/framework/config/DataSourceConfig.java

@@ -66,6 +66,7 @@ public class DataSourceConfig {
 
         targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
         targetDataSources.put(DataSourceType.SOP.name(), sopDataSource);
+        targetDataSources.put(DataSourceType.SopREAD.name(), sopReadDataSource);
         targetDataSources.put(DataSourceType.CLICKHOUSE.name(), clickhouseDataSource); // Ensure matching key
         return new DynamicDataSource(masterDataSource, targetDataSources);
     }

+ 13 - 13
fs-qw-task/src/main/java/com/fs/app/controller/CommonController.java

@@ -12,6 +12,8 @@ import com.fs.course.service.IFsCourseLinkService;
 import com.fs.course.service.IFsCourseWatchLogService;
 import com.fs.course.service.IFsUserVideoService;
 import com.fs.course.service.IHuaweiObsService;
+import com.fs.his.service.IFsInquiryOrderService;
+import com.fs.his.service.IFsPackageOrderService;
 import com.fs.qw.mapper.QwExternalContactMapper;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qwApi.service.QwApiService;
@@ -19,6 +21,7 @@ import com.fs.sop.mapper.QwSopLogsMapper;
 import com.fs.sop.mapper.QwSopMapper;
 import com.fs.sop.mapper.SopUserLogsMapper;
 import com.fs.sop.service.*;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.fs.sop.vo.QwSopLogsDoSendListTVO;
 import com.fs.store.service.IFsUserCourseCountService;
 import io.swagger.annotations.Api;
@@ -33,6 +36,7 @@ import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
+import java.util.Base64;
 import java.util.List;
 
 @Api("公共接口")
@@ -89,6 +93,12 @@ public class CommonController {
     @Autowired
     private IFsUserCourseCountService userCourseCountService;
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
+    @Autowired
+    private IFsInquiryOrderService inquiryOrderService;
+
 
     /**
     * 发官方通连
@@ -129,19 +139,9 @@ public class CommonController {
     @GetMapping("/testSop")
     public R testSop() throws Exception {
 
-//        iSopUserLogsService.repairSopUserLogsTimer();
-//        List<QwSopLogsDoSendListTVO> expireded = iQwSopLogsService.expiredMessagesByQwSopLogs();
-//        if (!expireded.isEmpty()) {
-//            processAndInsertQwSopLogs(expireded);
-//        }
-//
-//        // 将标签字符串解析为 List    //客户总标签
-//        List<String> tagIdsList = new ArrayList<>();
-//        tagIdsList.add("etW3ylWQAAcHQ4wJdAOMMZRfQnn3Sp2w");
-//        tagIdsList.add("etW3ylWQAAdRYbwUx0P1kkL7695Vxn3g");
-//        tagIdsList.add("etW3ylWQAAZyu1C9XwtKNaCLJDE8PlBQ");
-
-        return R.ok();
+        byte[] bytes = inquiryOrderService.getWxaCodeInquiryOrderUnLimit(2582616L);
+        String base64 = Base64.getEncoder().encodeToString(bytes);
+        return R.ok().put("data",base64);
     }
 
     @GetMapping("/testRatingSop")

+ 1 - 1
fs-qw-task/src/main/resources/application.yml

@@ -10,4 +10,4 @@ spring:
 #    active: druid-hcl
 #    active: druid-sxjz
 #    active: druid-hdt
-    active: druid-fcky-test
+    active: druid-myhk-test

+ 18 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/ApisQwUserController.java

@@ -7,10 +7,13 @@ import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.service.IQwExternalContactInfoService;
 import com.fs.qw.service.IQwExternalContactService;
 import com.fs.qw.vo.ExternalContactDetailsVO;
 import com.fs.qw.vo.QwExternalListByHeavyVO;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -36,6 +39,9 @@ public class ApisQwUserController extends BaseController {
     @Autowired
     private IQwExternalContactInfoService qwExternalContactInfoService;
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -98,4 +104,16 @@ public class ApisQwUserController extends BaseController {
         PageInfo<QwExternalListByHeavyVO> result = new PageInfo<>(qwExternalListByHeavy);
         return R.ok().put("data", result);
     }
+
+    @PostMapping("/extCourseSopWatchLog")
+    @ApiOperation("获取外部联系人按照 营期天数 获取到的今天该看的课")
+    public R getExtCourseSopWatchLog(@RequestBody QwExtCourseSopWatchLog param) {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExtCourseSopWatchLogVO> list = iSopUserLogsInfoService.getExtCourseSopWatchLog(param);
+        PageInfo<ExtCourseSopWatchLogVO> result = new PageInfo<>(list);
+
+        return R.ok().put("data", result);
+    }
+
 }

+ 18 - 0
fs-qwhook-sop/src/main/java/com/fs/app/controller/QwUserController.java

@@ -7,6 +7,7 @@ import com.fs.common.exception.CustomException;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
@@ -17,6 +18,8 @@ import com.fs.qw.vo.ExternalContactDetailsVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -45,6 +48,9 @@ public class QwUserController extends BaseController {
     @Autowired
     private IQwTagGroupService qwTagGroupService;
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -81,6 +87,18 @@ public class QwUserController extends BaseController {
         return R.ok();
     }
 
+    @PostMapping("/extCourseSopWatchLog")
+    @ApiOperation("获取外部联系人按照 营期天数 获取到的今天该看的课")
+    public R getExtCourseSopWatchLog(@RequestBody QwExtCourseSopWatchLog param) {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExtCourseSopWatchLogVO> list = iSopUserLogsInfoService.getExtCourseSopWatchLog(param);
+        PageInfo<ExtCourseSopWatchLogVO> result = new PageInfo<>(list);
+
+        return R.ok().put("data", result);
+    }
+
+
     @GetMapping("/externalContact")
     @ApiOperation("获取侧边栏外部联系人信息")
     public R getExternalContactInfo(@RequestParam(value = "qwExternalContactId") Long qwExternalContactId) {

+ 1 - 1
fs-qwhook-sop/src/main/resources/application.yml

@@ -10,4 +10,4 @@ spring:
 #    active: druid-yzt
 #    active: druid-hdt
 #    active: druid-sxjz
-    active: druid-sft
+    active: druid-myhk-test

+ 20 - 0
fs-qwhook/src/main/java/com/fs/app/controller/ApisQwUserController.java

@@ -3,12 +3,14 @@ package com.fs.app.controller;
 import com.fs.common.BeanCopyUtils;
 import com.fs.common.core.controller.BaseController;
 import com.fs.common.core.domain.R;
+import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.exception.CustomException;
 import com.fs.course.param.FsCourseListBySidebarParam;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
@@ -21,6 +23,8 @@ import com.fs.qw.vo.QwExternalListByHeavyVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -49,6 +53,10 @@ public class ApisQwUserController extends BaseController {
     @Autowired
     private IQwTagGroupService qwTagGroupService;
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
+
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -112,6 +120,18 @@ public class ApisQwUserController extends BaseController {
         return R.ok().put("data", result);
     }
 
+
+    @PostMapping("/extCourseSopWatchLog")
+    @ApiOperation("获取外部联系人按照 营期天数 获取到的今天该看的课")
+    public R getExtCourseSopWatchLog(@RequestBody QwExtCourseSopWatchLog param) {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExtCourseSopWatchLogVO> list = iSopUserLogsInfoService.getExtCourseSopWatchLog(param);
+        PageInfo<ExtCourseSopWatchLogVO> result = new PageInfo<>(list);
+
+        return R.ok().put("data", result);
+    }
+
     @GetMapping("/externalContact")
     @ApiOperation("获取侧边栏外部联系人信息")
     public R getExternalContactInfo(@RequestParam(value = "qwExternalContactId") Long qwExternalContactId) {

+ 16 - 0
fs-qwhook/src/main/java/com/fs/app/controller/QwUserController.java

@@ -7,6 +7,7 @@ import com.fs.common.exception.CustomException;
 import com.fs.qw.domain.QwExternalContactInfo;
 import com.fs.qw.domain.QwTagGroup;
 import com.fs.qw.param.ExternalContactDetailsParam;
+import com.fs.qw.param.QwExtCourseSopWatchLog;
 import com.fs.qw.param.sidebar.ExternalContactInfoParam;
 import com.fs.qw.param.sidebar.TagGroupListParam;
 import com.fs.qw.param.sidebar.TagGroupUpdateParam;
@@ -17,6 +18,8 @@ import com.fs.qw.vo.ExternalContactDetailsVO;
 import com.fs.qw.vo.QwTagGroupListVO;
 import com.fs.qw.vo.sidebar.ExternalContactInfoVO;
 import com.fs.qw.vo.sidebar.ExternalContactTagVO;
+import com.fs.sop.service.ISopUserLogsInfoService;
+import com.fs.sop.vo.ExtCourseSopWatchLogVO;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -45,6 +48,9 @@ public class QwUserController extends BaseController {
     @Autowired
     private IQwTagGroupService qwTagGroupService;
 
+    @Autowired
+    private ISopUserLogsInfoService iSopUserLogsInfoService;
+
     @GetMapping("/details")
     @ApiOperation("会员看课详情")
     public R getUserDetails(@ApiParam(value = "外部联系人id", required = true) @RequestParam Long contactId,
@@ -81,6 +87,16 @@ public class QwUserController extends BaseController {
         return R.ok();
     }
 
+    @PostMapping("/extCourseSopWatchLog")
+    @ApiOperation("获取外部联系人按照 营期天数 获取到的今天该看的课")
+    public R getExtCourseSopWatchLog(@RequestBody QwExtCourseSopWatchLog param) {
+
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        List<ExtCourseSopWatchLogVO> list = iSopUserLogsInfoService.getExtCourseSopWatchLog(param);
+        PageInfo<ExtCourseSopWatchLogVO> result = new PageInfo<>(list);
+
+        return R.ok().put("data", result);
+    }
 
     @GetMapping("/externalContact")
     @ApiOperation("获取侧边栏外部联系人信息")

+ 2 - 0
fs-service/src/main/java/com/fs/common/param/LoginParam.java

@@ -13,4 +13,6 @@ public class LoginParam implements Serializable {
     private String iv;
     private String rawData;
     private String signature;
+    private String appId;
+    private Integer authType;
 }

+ 4 - 1
fs-service/src/main/java/com/fs/company/service/impl/CompanyServiceImpl.java

@@ -510,7 +510,10 @@ public class CompanyServiceImpl implements ICompanyService
                 SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.store");
                 StoreConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), StoreConfig.class);
                 Integer DeductMoneyRate = fsPayConfig.getDeductMoneyRate();
-                BigDecimal money = order.getPrescribePrice().multiply(new BigDecimal(DeductMoneyRate).multiply(new BigDecimal("0.01")));
+                BigDecimal money = BigDecimal.ZERO;
+                if (DeductMoneyRate != null && DeductMoneyRate > 0) {
+                    money = order.getPrescribePrice().multiply(new BigDecimal(DeductMoneyRate).multiply(new BigDecimal("0.01")));
+                }
                 logger.info("扣除成本:"+order.getOrderCode()+":"+money);
                 company.setMoney(company.getMoney().subtract(money));
                 companyMapper.updateCompany(company);

+ 4 - 1
fs-service/src/main/java/com/fs/config/ai/AiHostProper.java

@@ -9,5 +9,8 @@ import org.springframework.stereotype.Component;
 public class AiHostProper {
     @Value("${ipad.ipadUrl}")
     private String ipadUrl;
-    
+
+    @Value("${ipad.aiApi}")
+    private String aiApi;
+
 }

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

@@ -246,7 +246,7 @@ public interface FsUserCourseMapper
             "        LEFT JOIN fs_user_course_period_days fcpd ON fcpd.period_id = fcp.period_id\n" +
             "        LEFT JOIN fs_user_course c ON c.course_id = fcpd.course_id\n" +
             "        WHERE\n" +
-            "        c.is_del = 0\n" +
+            "        c.is_del = 0 and fcp.del_flag = '0'\n" +
             "        AND FIND_IN_SET(#{companyId}, fcp.company_id)\n" +
             "        <if test=\"keyword != null and keyword !='' \">\n" +
             "            AND fcp.period_name LIKE concat('%',#{keyword},'%'\n" +

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

@@ -14,6 +14,7 @@ import com.fs.course.vo.newfs.FsUserCourseVideoPageListVO;
 import com.fs.his.vo.OptionsVO;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 
 import java.math.BigDecimal;
 import java.util.List;
@@ -140,7 +141,8 @@ public interface FsUserCourseVideoMapper
     List<OptionsVO> selectFsUserCourseVodeAllList(Long id);
 
     @Select({"<script> " +
-            "select v.*,p.red_packet_money company_red_packet_money from fs_user_course_video v LEFT JOIN fs_user_course_video_red_package p on p.video_id= v.video_id and p.company_id =#{maps.companyId} " +
+            "select v.*,p.red_packet_money company_red_packet_money from fs_user_course_video v " +
+            "LEFT JOIN fs_user_course_video_red_package p on p.video_id= v.video_id and p.company_id =#{maps.companyId} and p.data_type = 1 " +
             "where v.is_del = 0 and  v.course_id = #{maps.courseId}   " +
             "<if test = ' maps.title!=null and maps.title != \"\" '> " +
             "and v.title = #{maps.title} " +
@@ -198,4 +200,20 @@ public interface FsUserCourseVideoMapper
     List<FsCourseVideoListBySidebarVO> getFsCourseVideoListBySidebar(@Param("data") FsCourseListBySidebarParam param);
 
     List<FsUserCourseVideoPageListVO> selectFsUserCourseVideoListByMap(@Param("params") Map<String, Object> params);
+
+    FsUserCourseVideo selectByFileKey(@Param("params")String fileKey);
+
+    @Select("select * from fs_user_course_video where file_key = #{fileKey} ")
+    List<FsUserCourseVideo> selectVideoByFileKey(@Param("fileKey") String fileKey);
+
+    @Update("UPDATE fs_user_course_video " +
+            "SET line_one = #{lineOne}, " +
+            "    transcode_file_key = #{transcodeFileKey}, " +
+            "    is_transcode = 1, " +
+            "    update_time = NOW() " +  // 添加更新时间
+            "WHERE file_key = #{fileKey}")
+    void updateFsUserCourseVideoByFileKey(FsUserCourseVideo courseVideo);
+
+    @Select("select title from fs_user_course_video WHERE video_id=#{videoId}")
+    String selectFsUserCourseVideoByVideoForTitle(@Param("videoId") Long videoId);
 }

+ 3 - 0
fs-service/src/main/java/com/fs/course/mapper/FsVideoResourceMapper.java

@@ -24,4 +24,7 @@ public interface FsVideoResourceMapper extends BaseMapper<FsVideoResource> {
 
     @Select("select * from fs_video_resource where is_transcode = 1 and is_del = 0 and transcode_file_key is null")
     List<FsVideoResource> selectVideoIsTranscode();
+
+    @Select("select * from fs_video_resource where file_key = #{fileKey} limit 1")
+    FsVideoResource selectByFileKey(String fileKey);
 }

+ 4 - 0
fs-service/src/main/java/com/fs/course/param/FsUserCourseVideoParam.java

@@ -16,8 +16,12 @@ public class FsUserCourseVideoParam {
     private String title;
     private String redPacketMoney;
     private Long companyId;
+
+    private Integer dataType;
+
     @ApiModelProperty(value = "页码,默认为1")
     private Integer pageNum =1;
+
     @ApiModelProperty(value = "页大小,默认为10")
     private Integer pageSize = 10;
 }

+ 6 - 0
fs-service/src/main/java/com/fs/course/service/IFsUserCourseVideoService.java

@@ -176,4 +176,10 @@ public interface IFsUserCourseVideoService
     ResponseResult<Boolean> setWatchCourseTime(List<FsWatchCourseTimeParam> collect);
 
     R createRoomMiniLink(FsCourseLinkMiniParam param);
+
+    FsUserCourseVideo selectByFileKey(String fileKey);
+
+    String selectFsUserCourseVideoByVideoForTitle(Long videoId);
+
+    R updateVideo();
 }

+ 49 - 22
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -78,6 +78,7 @@ import org.springframework.transaction.annotation.Transactional;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
 import java.net.SocketTimeoutException;
+import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
@@ -654,6 +655,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             QwExternalContact contact = new QwExternalContact();
             contact.setId(param.getQwExternalId());
             contact.setFsUserId(param.getUserId());
+            contact.setRegisterTime(new Date());
             qwExternalContactMapper.updateQwExternalContact(contact);
 
             iSopUserLogsInfoService.updateSopUserInfoByExternalId(qwExternalId,param.getUserId());
@@ -665,14 +667,22 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             fsUserMapper.updateFsUser(user);
 
 
-            //小访客特有
+//            //小访客特有
 //            SendXfkParam xfkParam=new SendXfkParam();
 //            xfkParam.setCorpId(externalContact.getCorpId());
 //            xfkParam.setUserId(externalContact.getUserId());
 //            xfkParam.setName(externalContact.getName());
 //            xfkParam.setAddWay(externalContact.getAddWay());
 //            xfkParam.setState(externalContact.getState());
-//            xfkParam.setCreateTime(externalContact.getCreateTime().toString());
+//            if (externalContact.getCreateTime()!=null){
+//                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+//                String formattedTime = sdf.format(externalContact.getCreateTime());
+//                xfkParam.setCreateTime(formattedTime);
+//            }else {
+//                xfkParam.setCreateTime("");
+//            }
+//
+//
 //            xfkService.executeSopByIds(xfkParam);
 
             iSopUserLogsInfoService.updateSopUserInfoByExternalId(qwExternalId,param.getUserId());
@@ -950,23 +960,6 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
      * @return 处理结果
      */
     private R sendRedPacketReward(FsCourseSendRewardUParam param, FsUser user, FsCourseWatchLog log, FsUserCourseVideo video, CourseConfig config) {
-        // 判断是否属于领取红包时间(会员看课发放红包)
-        if (param.getPeriodId()!=null && param.getPeriodId()>0) {
-            FsUserCoursePeriodDays periodDays = new FsUserCoursePeriodDays();
-            periodDays.setVideoId(param.getVideoId());
-            periodDays.setPeriodId(param.getPeriodId());
-            //正常情况是只能查询到一条,之前可能存在重复的脏数据,暂使用查询list的方式
-            List<FsUserCoursePeriodDays> fsUserCoursePeriodDays = fsUserCoursePeriodDaysMapper.selectFsUserCoursePeriodDaysList(periodDays);
-            if(fsUserCoursePeriodDays != null && !fsUserCoursePeriodDays.isEmpty()){
-                periodDays = fsUserCoursePeriodDays.get(0);
-            }
-            if(periodDays != null && periodDays.getLastJoinTime() !=null && LocalDateTime.now().isAfter(periodDays.getLastJoinTime())) {
-                return R.error(403,"已超过领取红包时间");
-            }
-        }
-
-
-
 
         // 确定红包金额
         BigDecimal amount = BigDecimal.ZERO;
@@ -980,12 +973,18 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
         // 准备发送红包参数
         WxSendRedPacketParam packetParam = new WxSendRedPacketParam();
-//        packetParam.setOpenId(getOpenId(user.getUserId(), param.getCompanyId(), param.getSource()));
         packetParam.setOpenId(user.getMpOpenId());
         // 来源是小程序切换openId
         if (param.getSource() == 2) {
-            System.out.println("小程序id"+user.getCourseMaOpenId());
-            packetParam.setOpenId(user.getCourseMaOpenId());
+            //处理多小程序问题
+            FsUserWx fsUserWx = fsUserWxService.selectByAppIdAndUserId(param.getAppId(),user.getUserId(),1);
+            if (fsUserWx ==null || fsUserWx.getOpenId()==null){
+                packetParam.setOpenId(user.getCourseMaOpenId());
+            }else {
+                packetParam.setOpenId(fsUserWx.getOpenId());
+            }
+            //查出公司绑定openid并赋值
+
         }
         packetParam.setAmount(amount);
         packetParam.setSource(param.getSource());
@@ -1840,6 +1839,7 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
 
             //存看课记录
             courseWatchLogMapper.insertOrUpdateFsCourseWatchLog(watchLog);
+
         }catch (Exception e){
             logger.error("一键群发失败-插入观看记录失败:"+e.getMessage());
         }
@@ -2043,6 +2043,17 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
         return R.ok().put("data",news);
     }
 
+    @Override
+    public FsUserCourseVideo selectByFileKey(String fileKey) {
+        FsUserCourseVideo fsUserCourseVideo = fsUserCourseVideoMapper.selectByFileKey(fileKey);
+        return fsUserCourseVideo;
+    }
+
+    @Override
+    public String selectFsUserCourseVideoByVideoForTitle(Long videoId) {
+        return fsUserCourseVideoMapper.selectFsUserCourseVideoByVideoForTitle(videoId);
+    }
+
     /**
      * 获取视频时长(优先从Redis获取,不存在则查数据库)
      */
@@ -2143,4 +2154,20 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
                 videoDuration/60, config.getMinutesNum()));
     }
 
+
+    @Override
+    public R updateVideo() {
+        FsUserCourseVideo param = new FsUserCourseVideo();
+        param.setCourseId(144L);
+        List<FsUserCourseVideo> videos = selectFsUserCourseVideoListByCourseId(param);
+        for (FsUserCourseVideo courseVideo :  videos){
+            FsVideoResource resource = fsVideoResourceMapper.selectByFileKey(courseVideo.getFileKey());
+            if (resource==null){
+                continue;
+            }
+            courseVideo.setLineOne(resource.getLine1());
+            fsUserCourseVideoMapper.updateFsUserCourseVideo(courseVideo);
+        }
+        return R.ok();
+    }
 }

+ 52 - 12
fs-service/src/main/java/com/fs/course/service/impl/TencentCloudCosService.java

@@ -26,6 +26,7 @@ import com.tencentcloudapi.mps.v20190612.models.*;
 import lombok.AllArgsConstructor;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.io.IOException;
@@ -159,25 +160,64 @@ public class TencentCloudCosService implements ITencentCloudCosService {
         return config;
     }
 
+//    @Override
+//    @Transactional
+//    public R updateUrl() {
+//        try {
+//            //查出已转码的视频并且没有文件key的
+//            List<FsVideoResource> videos =  videoResourceMapper.selectVideoIsTranscode();
+//            for (FsVideoResource video : videos ){
+//                String newUrl = replaceCourse(video.getLine1());
+//                FsVideoResource videoMap = new FsVideoResource();
+//                videoMap.setId(video.getId());
+//                videoMap.setLine1(newUrl);
+//                videoMap.setTranscodeFileKey(replaceCourse(video.getFileKey()));
+//                videoResourceMapper.updateById(videoMap);
+//                //更新课程管理目录的视频
+//                FsUserCourseVideo courseVideo = new FsUserCourseVideo();
+//                courseVideo.setFileKey(video.getFileKey());
+//                courseVideo.setLineOne(newUrl);
+//                courseVideo.setTranscodeFileKey(videoMap.getTranscodeFileKey());
+//                courseVideoMapper.updateFsUserCourseVideoByFileKey(courseVideo);
+//
+//            }
+//            return R.ok();
+//        }catch (Exception e){
+//            return R.error();
+//        }
+//
+//    }
+
     @Override
-    @Transactional
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
     public R updateUrl() {
         try {
-            //查出已转码的视频并且没有文件key的
-            List<FsVideoResource> videos =  videoResourceMapper.selectVideoIsTranscode();
-            for (FsVideoResource video : videos ){
-                String newUrl = replaceCourse(video.getLine1());
-                FsVideoResource videoMap = new FsVideoResource();
-                videoMap.setId(video.getId());
-                videoMap.setLine1(newUrl);
-                videoMap.setTranscodeFileKey(replaceCourse(video.getFileKey()));
-                videoResourceMapper.updateById(videoMap);
+            List<FsVideoResource> videos = videoResourceMapper.selectVideoIsTranscode();
+            for (FsVideoResource video : videos) {
+                updateSingleVideo(video); // 将单个视频更新逻辑提取到方法
             }
             return R.ok();
-        }catch (Exception e){
-            return R.error();
+        } catch (Exception e) {
+            return R.error(e.getMessage());
         }
+    }
 
+    // 为每个视频更新使用独立事务
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    public void updateSingleVideo(FsVideoResource video) {
+        String newUrl = replaceCourse(video.getLine1());
+
+        FsVideoResource videoMap = new FsVideoResource();
+        videoMap.setId(video.getId());
+        videoMap.setLine1(newUrl);
+        videoMap.setTranscodeFileKey(replaceCourse(video.getFileKey()));
+        videoResourceMapper.updateById(videoMap);
+
+        FsUserCourseVideo courseVideo = new FsUserCourseVideo();
+        courseVideo.setFileKey(video.getFileKey());
+        courseVideo.setLineOne(newUrl);
+        courseVideo.setTranscodeFileKey(videoMap.getTranscodeFileKey());
+        courseVideoMapper.updateFsUserCourseVideoByFileKey(courseVideo);
     }
 
     private byte[] getObjectInputStream() throws IOException {

+ 118 - 0
fs-service/src/main/java/com/fs/erp/constant/AfterSalesOrderStatusEnum.java

@@ -0,0 +1,118 @@
+package com.fs.erp.constant;
+
+/**
+ * 平台单据状态枚举
+ *
+ * 定义售后单据在不同阶段的状态常量
+ */
+public enum AfterSalesOrderStatusEnum {
+
+    /**
+     * 买家已经申请,等待卖家同意
+     */
+    WAIT_SELLER_AGREE(0, "WAIT_SELLER_AGREE", "买家已经申请,等待卖家同意"),
+
+    /**
+     * 卖家已经同意,等待买家退货
+     */
+    WAIT_BUYER_RETURN_GOODS(1, "WAIT_BUYER_RETURN_GOODS", "卖家已经同意,等待买家退货"),
+
+    /**
+     * 买家已经退货,等待卖家确认收货
+     */
+    WAIT_SELLER_CONFIRM_GOODS(2, "WAIT_SELLER_CONFIRM_GOODS", "买家已经退货,等待卖家确认收货"),
+
+    /**
+     * 卖家拒绝售后
+     */
+    SELLER_REFUSE_BUYER(3, "SELLER_REFUSE_BUYER", "卖家拒绝售后"),
+
+    /**
+     * 等待卖家发货
+     */
+    WAIT_SELLER_DELIVER_GOODS(4, "WAIT_SELLER_DELIVER_GOODS", "等待卖家发货"),
+
+    /**
+     * 补发卖家发货
+     */
+    REISSUE_SELLER_DELIVERY(5, "REISSUE_SELLER_DELIVERY", "补发卖家发货"),
+
+    /**
+     * 售后关闭(售后单未确认前填写该状态erp的售后单自动作废)
+     */
+    CLOSED(6, "CLOSED", "售后关闭"),
+
+    /**
+     * 退款成功
+     * 补发、换货售后单确认时需在系统中手动确认
+     * 注意:抖音、拼多多、淘系等线上平台换货单据,通过接口修改状态为SUCCESS且发出的快递单号是空,
+     * 平台会判定为换货单超时未处理,会被平台强制退款,线上售后类型会变为普通退货
+     */
+    SUCCESS(7, "SUCCESS", "退款成功"),
+    CONFIRM(10, "CONFIRM", "确认");
+
+    private final Integer index;
+    private final String code;
+    private final String description;
+
+    AfterSalesOrderStatusEnum(Integer index, String code, String description) {
+        this.index = index;
+        this.code = code;
+        this.description = description;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public Integer getIndex() {
+        return index;
+    }
+
+    /**
+     * 根据状态码获取枚举实例
+     *
+     * @param code 状态码
+     * @return 对应的枚举实例,如果未找到则返回null
+     */
+    public static AfterSalesOrderStatusEnum getByCode(String code) {
+        if (code == null) {
+            return null;
+        }
+
+        for (AfterSalesOrderStatusEnum status : AfterSalesOrderStatusEnum.values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 根据状态码获取枚举实例
+     *
+     * @param index 状态码
+     * @return 对应的枚举实例,如果未找到则返回null
+     */
+    public static AfterSalesOrderStatusEnum getByIndex(Integer index) {
+        if (index == null) {
+            return null;
+        }
+
+        for (AfterSalesOrderStatusEnum status : AfterSalesOrderStatusEnum.values()) {
+            if (status.getIndex().equals(index)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String toString() {
+        return this.code;
+    }
+}

+ 111 - 0
fs-service/src/main/java/com/fs/erp/constant/ErpQueryOrderStatusEnum.java

@@ -0,0 +1,111 @@
+package com.fs.erp.constant;
+
+import lombok.Getter;
+
+/**
+ * 订单状态枚举类
+ */
+@Getter
+public enum ErpQueryOrderStatusEnum {
+
+    /**
+     * 待付款
+     */
+    WAIT_PAY("WaitPay", "待付款"),
+
+    /**
+     * 发货中
+     */
+    DELIVERING("Delivering", "发货中"),
+
+    /**
+     * 被合并
+     */
+    MERGED("Merged", "被合并"),
+
+    /**
+     * 异常
+     */
+    QUESTION("Question", "异常"),
+
+    /**
+     * 被拆分
+     */
+    SPLIT("Split", "被拆分"),
+
+    /**
+     * 等供销商|外仓发货
+     */
+    WAIT_OUTER_SENT("WaitOuterSent", "等供销商|外仓发货"),
+
+    /**
+     * 已付款待审核
+     */
+    WAIT_CONFIRM("WaitConfirm", "已付款待审核"),
+
+    /**
+     * 已客审待财审
+     */
+    WAIT_FCONFIRM("WaitFConfirm", "已客审待财审"),
+
+    /**
+     * 已发货
+     */
+    SENT("Sent", "已发货"),
+
+    /**
+     * 取消
+     */
+    CANCELLED("Cancelled", "取消");
+
+    /**
+     * 状态码
+     */
+    private final String code;
+
+    /**
+     * 状态描述
+     */
+    private final String description;
+
+    /**
+     * 构造方法
+     *
+     * @param code        状态码
+     * @param description 状态描述
+     */
+    ErpQueryOrderStatusEnum(String code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据状态码获取对应的枚举值
+     *
+     * @param code 状态码
+     * @return 对应的枚举值,若未找到则返回null
+     */
+    public static ErpQueryOrderStatusEnum getByCode(String code) {
+        for (ErpQueryOrderStatusEnum status : values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 判断给定的状态码是否有效
+     *
+     * @param code 状态码
+     * @return 若有效返回true,否则返回false
+     */
+    public static boolean isValidCode(String code) {
+        return getByCode(code) != null;
+    }
+
+    @Override
+    public String toString() {
+        return this.code + ":" + this.description;
+    }
+}

+ 90 - 0
fs-service/src/main/java/com/fs/erp/constant/OrderStatusEnum.java

@@ -0,0 +1,90 @@
+package com.fs.erp.constant;
+
+import lombok.Getter;
+
+/**
+ * 商城系统订单状态枚举
+ * 包含订单流转的各个状态及其说明
+ */
+@Getter
+public enum OrderStatusEnum {
+
+    /**
+     * 等待买家付款
+     */
+    WAIT_BUYER_PAY("等待买家付款"),
+
+    /**
+     * 等待卖家发货
+     * 传此状态时,实际支付金额(pay节点支付金额=应付金额)ERP才会显示已付款待审核
+     */
+    WAIT_SELLER_SEND_GOODS("等待卖家发货"),
+
+    /**
+     * 等待买家确认收货
+     */
+    WAIT_BUYER_CONFIRM_GOODS("等待买家确认收货"),
+
+    /**
+     * 交易成功
+     */
+    TRADE_FINISHED("交易成功"),
+
+    /**
+     * 付款后交易关闭
+     */
+    TRADE_CLOSED("付款后交易关闭"),
+
+    /**
+     * 付款前交易关闭
+     */
+    TRADE_CLOSED_BY_TAOBAO("付款前交易关闭");
+
+    /**
+     * 订单状态描述
+     */
+    private final String description;
+
+    /**
+     * 构造函数
+     * @param description 订单状态描述
+     */
+    OrderStatusEnum(String description) {
+        this.description = description;
+    }
+
+    /**
+     * 判断订单状态是否可以更新
+     * @return 所有状态均可更新,返回true
+     */
+    public boolean canUpdate() {
+        return true;
+    }
+
+    /**
+     * 根据状态码获取枚举实例
+     * @param code 状态码
+     * @return 对应的枚举实例,如果不存在则返回null
+     */
+    public static OrderStatusEnum getByCode(String code) {
+        try {
+            return OrderStatusEnum.valueOf(code);
+        } catch (IllegalArgumentException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 检查给定的状态码是否为有效的订单状态
+     * @param code 状态码
+     * @return 是否有效
+     */
+    public static boolean isValidCode(String code) {
+        return getByCode(code) != null;
+    }
+
+    @Override
+    public String toString() {
+        return this.name() + "(" + this.description + ")";
+    }
+}

+ 87 - 0
fs-service/src/main/java/com/fs/erp/constant/TaskStatusEnum.java

@@ -0,0 +1,87 @@
+package com.fs.erp.constant;
+
+/**
+ * 任务状态枚举
+ */
+public enum TaskStatusEnum {
+
+    /**
+     * 待处理
+     */
+    PENDING(0, "待处理"),
+
+    /**
+     * 成功
+     */
+    SUCCESS(1, "成功"),
+
+    /**
+     * 失败
+     */
+    FAILED(2, "失败"),
+
+    /**
+     * 正在处理
+     */
+    PROCESSING(3, "正在处理"),
+
+    /**
+     * 已取消
+     */
+    CANCELLED(4, "已取消");
+
+    private final Integer code; // 状态码
+    private final String description; // 状态描述
+
+    /**
+     * 构造方法
+     *
+     * @param code        状态码
+     * @param description 状态描述
+     */
+    TaskStatusEnum(Integer code, String description) {
+        this.code = code;
+        this.description = description;
+    }
+
+    /**
+     * 根据状态码获取枚举值
+     *
+     * @param code 状态码
+     * @return 对应的枚举值,如果没有匹配的则返回 null
+     */
+    public static TaskStatusEnum getByCode(Integer code) {
+        for (TaskStatusEnum status : TaskStatusEnum.values()) {
+            if (status.getCode().equals(code)) {
+                return status;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 获取状态码
+     *
+     * @return 状态码
+     */
+    public Integer getCode() {
+        return code;
+    }
+
+    /**
+     * 获取状态描述
+     *
+     * @return 状态描述
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    @Override
+    public String toString() {
+        return "TaskStatusEnum{" +
+                "code=" + code +
+                ", description='" + description + '\'' +
+                '}';
+    }
+}

+ 2 - 0
fs-service/src/main/java/com/fs/erp/domain/ErpOrder.java

@@ -32,4 +32,6 @@ public class ErpOrder {
 
     Integer isPackage;
     List<ErpOrderPayment> payments;
+
+    String buyer_account;
 }

+ 85 - 0
fs-service/src/main/java/com/fs/erp/domain/FsJstAftersalePush.java

@@ -0,0 +1,85 @@
+package com.fs.erp.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * 订阅物流
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FsJstAftersalePush {
+
+    /**
+     * 主键,自增
+     */
+    private Long id;
+
+    /**
+     * 订单号
+     */
+    private String orderId;
+    /**
+     * 售后id
+     */
+    private String afterSaleId;
+
+    /**
+     * 平台单据状态:
+     * 0 WAIT_SELLER_AGREE:买家已经申请,等待卖家同意,
+     * 1 WAIT_BUYER_RETURN_GOODS:卖家已经同意,等待买家退货,
+     * 2 WAIT_SELLER_CONFIRM_GOODS:买家已经退货,等待卖家确认收货,
+     * 3 SELLER_REFUSE_BUYER:卖家拒绝售后,
+     * 4 WAIT_SELLER_DELIVER_GOODS:等待卖家发货,
+     * 5 REISSUE_SELLER_DELIVERY:补发卖家发货,
+     * 6 CLOSED:售后关闭(售后单未确认前填写该状态erp的售后单自动作废),
+     * 7 SUCCESS:退款成功;可更新,补发、换货售后单确认时需在系统中手动确认;抖音、拼多多、淘系等线上平台换货换货单据,通过接口修改状态为SUCCESS且发出的快递单号是空,平台会判定为换货单超时未处理,会被平台强制退款,线上售后类型会变为普通退货
+     */
+    private String type;
+
+    /**
+     * 任务状态:0-待处理,1-成功,2-失败,3-正在处理,4-已取消
+     */
+    private Integer taskStatus;
+
+    /**
+     * 重试次数,默认为 0
+     */
+    private Integer retryCount;
+
+    /**
+     * 上次执行时间,用于记录任务执行的最后时间
+     */
+    private LocalDateTime lastExecuteTime;
+
+    /**
+     * 记录创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 记录更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 调用接口时传入的参数(JSON 格式)
+     */
+    private String params;
+
+    /**
+     * 调用接口返回的结果(JSON 格式)
+     */
+    private String result;
+
+    /**
+     * 错误信息(记录失败原因)
+     */
+    private String errorMessage;
+}

+ 77 - 0
fs-service/src/main/java/com/fs/erp/domain/FsJstCodPush.java

@@ -0,0 +1,77 @@
+package com.fs.erp.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+
+/**
+ * jst货到付款推送
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class FsJstCodPush {
+    /**
+     * 主键,自增
+     */
+    private Long id;
+
+    /**
+     * 订单id
+     */
+    private String orderId;
+
+    /**
+     * 售后id
+     */
+    private String afterSaleId;
+
+    /**
+     * 0创建订单 1后续金额
+     */
+    private String type;
+
+    /**
+     * 任务状态:0-待处理,1-成功,2-失败,3-正在处理,4-已取消
+     */
+    private Integer taskStatus;
+
+    /**
+     * 重试次数,默认为 0
+     */
+    private Integer retryCount;
+
+    /**
+     * 上次执行时间,用于记录任务执行的最后时间
+     */
+    private LocalDateTime lastExecuteTime;
+
+    /**
+     * 记录创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 记录更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 调用接口时传入的参数(JSON 格式)
+     */
+    private String params;
+
+    /**
+     * 调用接口返回的结果(JSON 格式)
+     */
+    private String result;
+
+    /**
+     * 错误信息(记录失败原因)
+     */
+    private String errorMessage;
+}

+ 40 - 0
fs-service/src/main/java/com/fs/erp/dto/AfterSaleConfirmRequestDTO.java

@@ -0,0 +1,40 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 售后确认请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AfterSaleConfirmRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 售后单id数组
+     */
+    private List<Long> asIds;
+
+    /**
+     * 换货售后单是否强制确认
+     */
+    private Boolean exchangeForce;
+
+    /**
+     * 是否同步确认退款单
+     */
+    private Boolean confirmRefund;
+}

+ 69 - 0
fs-service/src/main/java/com/fs/erp/dto/AfterSaleResponseDTO.java

@@ -0,0 +1,69 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 售后单响应DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AfterSaleResponseDTO implements Serializable {
+
+    private static final long serialVersionUID = -1L;
+
+    /**
+     * 响应消息
+     */
+    private String msg;
+
+    /**
+     * 售后单ID
+     */
+    private Long asId;
+
+    /**
+     * 是否成功
+     */
+    private Boolean issuccess;
+
+    /**
+     * 订单号
+     */
+    private String soId;
+
+    /**
+     * 外部售后单号
+     */
+    private String outerAsId;
+
+    /**
+     * 订单ID
+     */
+    private Long oId;
+
+    /**
+     * ID
+     */
+    private Long id;
+
+    /**
+     * 订单类型
+     */
+    private String orderType;
+
+    /**
+     * 订单授权ID
+     */
+    private String oaid;
+}

+ 45 - 0
fs-service/src/main/java/com/fs/erp/dto/AssetProcessDetailDTO.java

@@ -0,0 +1,45 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 资产处理详情对象
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AssetProcessDetailDTO {
+
+    /**
+     * 资产ID
+     */
+    private Long asId;
+
+    /**
+     * 外部资产ID
+     */
+    private String outerAsId;
+
+    /**
+     * 处理详情
+     */
+    private String details;
+
+    /**
+     * 处理消息
+     */
+    private String message;
+
+    /**
+     * 是否处理成功
+     */
+    private Boolean isSuccess;
+}

+ 42 - 0
fs-service/src/main/java/com/fs/erp/dto/AssetProcessResultDTO.java

@@ -0,0 +1,42 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+
+/**
+ * 资产处理结果响应对象
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class AssetProcessResultDTO {
+
+    /**
+     * 处理失败的资产列表
+     */
+    private List<AssetProcessDetailDTO> fail;
+
+    /**
+     * 处理成功的资产列表
+     */
+    private List<AssetProcessDetailDTO> success;
+
+    /**
+     * 成功处理的资产数量
+     */
+    private Integer successCount;
+
+    /**
+     * 处理失败的资产数量
+     */
+    private Integer failCount;
+}

+ 35 - 0
fs-service/src/main/java/com/fs/erp/dto/CommonResponse.java

@@ -0,0 +1,35 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 通用响应DTO
+ *
+ * @author xdd
+ * @since 2025-02-27
+ * @version 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class CommonResponse<T> implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 错误码
+     */
+    private Integer code;
+
+    /**
+     * 错误描述
+     */
+    private String msg;
+
+    /**
+     * 响应数据
+     */
+    private T data;
+}

+ 56 - 0
fs-service/src/main/java/com/fs/erp/dto/ErpOrderResponseDTO.java

@@ -0,0 +1,56 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * ERP订单返回结果DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Accessors(chain = true)
+public class ErpOrderResponseDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 订单数据列表
+     */
+    private List<OrderData> datas;
+
+    /**
+     * 订单数据实体
+     */
+    @Data
+    @Accessors(chain = true)
+    public static class OrderData implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * ERP订单界面-内部单号
+         */
+        private Integer oId;
+
+        /**
+         * ERP订单界面-线上单号
+         */
+        private String soId;
+
+        /**
+         * 是否成功
+         */
+        private Boolean issuccess;
+
+        /**
+         * 返回结果描述
+         */
+        private String msg;
+    }
+}

+ 22 - 0
fs-service/src/main/java/com/fs/erp/dto/ExtDataDTO.java

@@ -0,0 +1,22 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 扩展数据DTO
+ */
+@Data
+class ExtDataDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 公司名称
+     */
+    private String companyName;
+
+    /**
+     * 门牌号
+     */
+    private String doorPlate;
+}

+ 62 - 0
fs-service/src/main/java/com/fs/erp/dto/FinanceDataDTO.java

@@ -0,0 +1,62 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 财务数据DTO
+ */
+@Data
+class FinanceDataDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 返点费用
+     */
+    private Double rebateFee;
+
+    /**
+     * 商品税
+     */
+    private Double productTax;
+
+    /**
+     * 运输税
+     */
+    private Double shippingTax;
+
+    /**
+     * 其他收入
+     */
+    private Double otherIncome;
+
+    /**
+     * 卖家代金券
+     */
+    private Double voucherFromSeller;
+
+    /**
+     * 平台佣金
+     */
+    private Double platformCommission;
+
+    /**
+     * 过渡费
+     */
+    private Double transitionFee;
+
+    /**
+     * 交易费
+     */
+    private Double transactionFee;
+
+    /**
+     * 不透明包装费
+     */
+    private Double opaqueBaggingFee;
+
+    /**
+     * 其他支出
+     */
+    private Double otherExpense;
+}

+ 51 - 0
fs-service/src/main/java/com/fs/erp/dto/GetInitTokenRequestDTO.java

@@ -0,0 +1,51 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 获取初始化Token请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @date 2025-02-27
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class GetInitTokenRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 开发者应用Key
+     */
+    private String app_key;
+
+    /**
+     * 当前请求的时间戳(单位:秒)
+     */
+    private String timestamp;
+
+    /**
+     * 授权类型(固定值:authorization_code)
+     */
+    private String grant_type;
+
+    /**
+     * 交互数据编码(固定值:utf-8)
+     */
+    private String charset;
+
+    /**
+     * 随机码(六位随机字符串)
+     */
+    private String code;
+
+    /**
+     * 数字签名
+     */
+    private String sign;
+}

+ 41 - 0
fs-service/src/main/java/com/fs/erp/dto/GetInitTokenResponseDTO.java

@@ -0,0 +1,41 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 获取初始化Token响应DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @date 2025-02-27
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class GetInitTokenResponseDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 访问令牌
+     */
+    private String access_token;
+
+    /**
+     * access_token访问过期时间(单位:秒)
+     */
+    private Integer expires_in;
+
+    /**
+     * 更新令牌
+     */
+    private String refresh_token;
+
+    /**
+     * 权限范围(固定值:all)
+     */
+    private String scope;
+}

+ 297 - 0
fs-service/src/main/java/com/fs/erp/dto/GoodsInfoDTO.java

@@ -0,0 +1,297 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 商品信息DTO
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0.0
+ */
+@Data
+public class GoodsInfoDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 商品列表
+     */
+    private List<GoodsItem> items;
+
+    @Data
+    public static class GoodsItem implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 商品编码
+         */
+        private String skuId;
+
+        /**
+         * 款式编码
+         */
+        private String iId;
+
+        /**
+         * 品牌
+         */
+        private String brand;
+
+        /**
+         * 虚拟分类
+         */
+        private String vcName;
+
+        /**
+         * 商品分类
+         */
+        private String cName;
+
+        /**
+         * 基本售价
+         */
+        private BigDecimal sPrice;
+
+        /**
+         * 商品属性
+         */
+        private String itemType;
+
+        /**
+         * 长度
+         */
+        private BigDecimal l;
+
+        /**
+         * 宽度
+         */
+        private BigDecimal w;
+
+        /**
+         * 高度
+         */
+        private BigDecimal h;
+
+        /**
+         * 图片地址(款图片)
+         */
+        private String pic;
+
+        /**
+         * 大图地址
+         */
+        private String picBig;
+
+        /**
+         * 商品图片(SKU图片)
+         */
+        private String skuPic;
+
+        /**
+         * 商品名称
+         */
+        private String name;
+
+        /**
+         * 备注
+         */
+        private String remark;
+
+        /**
+         * 颜色及规格
+         */
+        private String propertiesValue;
+
+        /**
+         * 简称
+         */
+        private String shortName;
+
+        /**
+         * 重量
+         */
+        private BigDecimal weight;
+
+        /**
+         * 是否启用 -1=禁用,0=备用,1=启用
+         */
+        private Integer enabled;
+
+        /**
+         * 供应商名称
+         */
+        private String supplierName;
+
+        /**
+         * 国标码
+         */
+        private String skuCode;
+
+        /**
+         * 供应商商品编码
+         */
+        private String supplierSkuId;
+
+        /**
+         * 供应商款式编码
+         */
+        private String supplierIId;
+
+        /**
+         * 其它价格1
+         */
+        private BigDecimal otherPrice1;
+
+        /**
+         * 其它价格2
+         */
+        private BigDecimal otherPrice2;
+
+        /**
+         * 其它价格3
+         */
+        private BigDecimal otherPrice3;
+
+        /**
+         * 其它价格4
+         */
+        private BigDecimal otherPrice4;
+
+        /**
+         * 其它价格5
+         */
+        private BigDecimal otherPrice5;
+
+        /**
+         * 其它属性1
+         */
+        private String other1;
+
+        /**
+         * 其它属性2
+         */
+        private String other2;
+
+        /**
+         * 其它属性3
+         */
+        private String other3;
+
+        /**
+         * 其它属性4
+         */
+        private String other4;
+
+        /**
+         * 其它属性5
+         */
+        private String other5;
+
+        /**
+         * 禁止同步
+         */
+        private Boolean stockDisabled;
+
+        /**
+         * 成本价
+         */
+        private BigDecimal cPrice;
+
+        /**
+         * 市场价/吊牌价
+         */
+        private BigDecimal marketPrice;
+
+        /**
+         * 单位
+         */
+        private String unit;
+
+        /**
+         * 标签列表
+         */
+        private List<String> labels;
+
+        /**
+         * 是否启用生产批次
+         */
+        private Boolean batchEnabled;
+
+        /**
+         * 是否启用序列号
+         */
+        private Boolean isSeriesNumber;
+
+        /**
+         * 辅助码
+         */
+        private String otherCode;
+
+        /**
+         * 保质期天数
+         */
+        private Integer shelfLife;
+
+        /**
+         * 临期天数
+         */
+        private Integer handDay;
+
+        /**
+         * 保质期禁收天数
+         */
+        private Integer rejectLifecycle;
+
+        /**
+         * 保质期禁售天数
+         */
+        private Integer lockupLifecycle;
+
+        /**
+         * 保质期临期预警天数
+         */
+        private Integer adventLifecycle;
+
+        /**
+         * 商品类目属性
+         */
+        private CategoryProperty categoryPropertys;
+
+        /**
+         * 移除标签列表
+         */
+        private List<String> deletedlabels;
+
+        /**
+         * 生产许可证
+         */
+        private String productionLicence;
+
+        /**
+         * 采购价
+         */
+        private BigDecimal purchasePrice;
+
+        /**
+         * 是否校验组合装商品编码
+         */
+        private Boolean isNormal;
+    }
+
+    @Data
+    public static class CategoryProperty implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 年份
+         */
+        private String year;
+    }
+}

+ 38 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderCancelRequestDTO.java

@@ -0,0 +1,38 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 订单取消请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Accessors(chain = true)
+public class OrderCancelRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 内部订单号列表
+     * 一次最大支持50条
+     */
+    private List<Integer> oIds;
+
+    /**
+     * 取消类型
+     * 示例值:不需要了
+     */
+    private String cancelType;
+
+    /**
+     * 备注信息
+     */
+    private String remark;
+}

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

@@ -0,0 +1,33 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 订单扩展信息DTO
+ */
+@Data
+class OrderExtDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 跟踪号
+     */
+    private String trackingNo;
+
+    /**
+     * 跟踪类型
+     */
+    private String trackingType;
+
+    /**
+     * PDF URL
+     */
+    private String pdfUrl;
+
+    /**
+     * 扩展数据列表
+     */
+    private List<OrderExtDataDTO> datas;
+}

+ 52 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderExtDataDTO.java

@@ -0,0 +1,52 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 订单扩展数据DTO
+ */
+@Data
+class OrderExtDataDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private String autoId;
+    private String iid;
+    private String skuId;
+    private String skuCode;
+    private String name;
+    private String declareNameZN;
+    private String declareNameEN;
+    private String declareAmount;
+    private String declareWeight;
+    private String hsCode;
+    private String postTaxNum;
+    private Boolean isBattery;
+    private Boolean isLiquid;
+    private Boolean isDisable;
+    private String creator;
+    private String created;
+    private String modifier;
+    private String modified;
+    private String unit;
+    private Boolean isSetSkubin;
+    private Boolean isJoinSkuid;
+    private Boolean isPaste;
+    private Boolean isMagnetic;
+    private Boolean isFluid;
+    private Boolean isGetPrice;
+    private Boolean isGetWeight;
+    private String specialAttr;
+    private String country;
+    private String tempName;
+    private String tempId;
+    private Boolean isDefault;
+    private String shopId;
+    private Boolean isOAmount;
+    private String cid;
+    private Boolean isPowder;
+    private Boolean isSpecialCargo;
+    private Boolean isJoinSkubin;
+    private String saveType;
+    private Integer declareType;
+}

+ 58 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderItemDTO.java

@@ -0,0 +1,58 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 订单商品项DTO
+ */
+@Data
+public class OrderItemDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * SKU ID
+     */
+    private String skuId;
+
+    /**
+     * 店铺SKU ID
+     */
+    private String shopSkuId;
+
+    /**
+     * 金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 基础价格
+     */
+    private Double basePrice;
+
+    /**
+     * 数量
+     */
+    private Integer qty;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 外部订单项ID
+     */
+    private String outerOiId;
+
+    /**
+     * 批次ID
+     */
+    private String batchId;
+
+    /**
+     * 生产日期
+     */
+    private String producedDate;
+}

+ 137 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderQueryRequestDTO.java

@@ -0,0 +1,137 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 订单查询请求参数DTO
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0
+ * @description 订单查询相关参数封装对象
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class OrderQueryRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = -1L;
+
+    /**
+     * 店铺编号
+     */
+    private Integer shopId;
+
+    /**
+     * 是否线下店铺
+     * shop_id为0且is_offline_shop为true查询线下店铺单据
+     */
+    private Boolean isOfflineShop;
+
+    /**
+     * 线上单号列表
+     * 与时间条件、内部单号不能同时为空,最大限制20条
+     */
+    private List<String> soIds;
+
+    /**
+     * 起始时间
+     * 和结束时间必须同时存在,时间间隔不能超过七天
+     * 与线上单号、内部单号不能同时为空
+     */
+    private String modifiedBegin;
+
+    /**
+     * 结束时间
+     * 和起始时间必须同时存在,时间间隔不能超过七天
+     * 与线上单号、内部单号不能同时为空
+     */
+    private String modifiedEnd;
+
+    /**
+     * 日期类型
+     * 0:修改时间modified
+     * 2:订单日期order_date
+     * 3:发货时间send_date
+     * 非必填,默认0
+     */
+    private Integer dateType;
+
+    /**
+     * 订单状态
+     * 待付款:WaitPay
+     * 发货中:Delivering
+     * 被合并:Merged
+     * 异常:Question
+     * 被拆分:Split
+     * 等供销商|外仓发货:WaitOuterSent
+     * 已付款待审核:WaitConfirm
+     * 已客审待财审:WaitFConfirm
+     * 已发货:Sent
+     * 取消:Cancelled
+     */
+    private String status;
+
+    /**
+     * 第几页,从1开始
+     */
+    private Integer pageIndex;
+
+    /**
+     * 每页条数,最大100条
+     */
+    private Integer pageSize;
+
+    /**
+     * ts时间戳
+     * sql server中的行版本号,该字段查询防止分页过程中漏单
+     * 查询条件值是大于等于的关系
+     */
+    private Integer startTs;
+
+    /**
+     * 是否查询总条数
+     * 默认true,如果使用start_ts查询,该值传false否则影响查询效率
+     */
+    private Boolean isGetTotal;
+
+    /**
+     * 内部订单号列表
+     * 商家维度下订单信息的唯一值
+     * 与时间条件、线上单号不能同时为空
+     */
+    private List<Long> oIds;
+
+    /**
+     * 是否查询跨境财务信息
+     */
+    private Boolean isGetCbfinance;
+
+    /**
+     * 订单自定义查询字段列表
+     * 可选值:volume(体积),package(包材),outer_drp_co_id(货主分销),
+     * cus_id(货通客户id),oaid(oaid)
+     */
+    private List<String> orderFlds;
+
+    /**
+     * 订单明细自定义查询字段列表
+     * 可选值:src_combine_sku_id(原组合商品编码),referrer_name(主播名称),
+     * presale_date(预售时间),drp_price(采购价),item_plan_delivery_date(最晚发货时间)
+     */
+    private List<String> orderItemFlds;
+
+    /**
+     * 订单类型列表
+     * 如:"普通订单","普通订单,供销Plus"
+     */
+    private List<String> orderTypes;
+
+}

+ 799 - 0
fs-service/src/main/java/com/fs/erp/dto/OrderQueryResponseDTO.java

@@ -0,0 +1,799 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 订单查询响应对象
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class OrderQueryResponseDTO {
+
+    /**
+     * 每页大小
+     */
+    private Integer pageSize;
+
+    /**
+     * 页码
+     */
+    private Integer pageIndex;
+
+    /**
+     * 总数据条数
+     */
+    private Integer dataCount;
+
+    /**
+     * 总页数
+     */
+    private Integer pageCount;
+
+    /**
+     * 是否有下一页
+     */
+    private Boolean hasNext;
+
+    /**
+     * 订单列表
+     */
+    private List<Order> orders;
+
+    /**
+     * 响应码
+     */
+    private Integer code;
+
+    /**
+     * 是否成功
+     */
+    private Boolean issuccess;
+
+    /**
+     * 响应信息
+     */
+    private String msg;
+
+    /**
+     * 请求ID
+     */
+    private String requestId;
+
+    /**
+     * 订单信息
+     */
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class Order {
+        /**
+         * 公司订单ID
+         */
+        private Long coId;
+
+        /**
+         * 订单ID
+         */
+        private Long oId;
+
+        /**
+         * 店铺ID
+         */
+        private Long shopId;
+
+        /**
+         * 销售订单号
+         */
+        private String soId;
+
+        /**
+         * 下单时间
+         */
+        private String orderDate;
+
+        /**
+         * 店铺状态
+         */
+        private String shopStatus;
+
+        /**
+         * 问题类型
+         */
+        private String questionType;
+
+        /**
+         * 问题描述
+         */
+        private String questionDesc;
+
+        /**
+         * 订单状态
+         */
+        private String status;
+
+        /**
+         * 收件人国家
+         */
+        private String receiverCountry;
+
+        /**
+         * 收件人州/省
+         */
+        private String receiverState;
+
+        /**
+         * 收件人城市
+         */
+        private String receiverCity;
+
+        /**
+         * 收件人区域
+         */
+        private String receiverDistrict;
+
+        /**
+         * 收件人地址
+         */
+        private String receiverAddress;
+
+        /**
+         * 收件人镇/街道
+         */
+        private String receiverTown;
+
+        /**
+         * 收件人邮编
+         */
+        private String receiverZip;
+
+        /**
+         * 买家ID
+         */
+        private Long buyerId;
+
+        /**
+         * 发货日期
+         */
+        private String sendDate;
+
+        /**
+         * 支付金额
+         */
+        private BigDecimal payAmount;
+
+        /**
+         * 运费
+         */
+        private BigDecimal freight;
+
+        /**
+         * 转运费
+         */
+        private BigDecimal fFreight;
+
+        /**
+         * 重量
+         */
+        private BigDecimal weight;
+
+        /**
+         * 实际重量
+         */
+        private BigDecimal fWeight;
+
+        /**
+         * 买家留言
+         */
+        private String buyerMessage;
+
+        /**
+         * 备注
+         */
+        private String remark;
+
+        /**
+         * 发票抬头
+         */
+        private String invoiceTitle;
+
+        /**
+         * 是否货到付款
+         */
+        private Boolean isCod;
+
+        /**
+         * 订单类型
+         */
+        private String type;
+
+        /**
+         * 店铺站点
+         */
+        private String shopSite;
+
+        /**
+         * 优惠金额
+         */
+        private BigDecimal freeAmount;
+
+        /**
+         * 实付金额
+         */
+        private BigDecimal paidAmount;
+
+        /**
+         * 支付时间
+         */
+        private String payDate;
+
+        /**
+         * 外部支付ID
+         */
+        private String outerPayId;
+
+        /**
+         * 修改时间
+         */
+        private String modified;
+
+        /**
+         * 订单来源
+         */
+        private String orderFrom;
+
+        /**
+         * 店铺名称
+         */
+        private String shopName;
+
+        /**
+         * 卖家标记
+         */
+        private String sellerFlag;
+
+        /**
+         * 计划发货日期
+         */
+        private String planDeliveryDate;
+
+        /**
+         * 物流公司编码
+         */
+        private String lcId;
+
+        /**
+         * 物流ID
+         */
+        private String lId;
+
+        /**
+         * 物流公司
+         */
+        private String logisticsCompany;
+
+        /**
+         * 折扣率
+         */
+        private BigDecimal discountRate;
+
+        /**
+         * 标签
+         */
+        private String tag;
+
+        /**
+         * 仓库订单ID
+         */
+        private Long wmsCoId;
+
+        /**
+         * 币种
+         */
+        private String currency;
+
+        /**
+         * 节点
+         */
+        private String node;
+
+        /**
+         * 标签列表
+         */
+        private String labels;
+
+        /**
+         * 订单金额
+         */
+        private BigDecimal amount;
+
+        /**
+         * 分销来源订单ID
+         */
+        private Long drpCoIdFrom;
+
+        /**
+         * 是否拆分
+         */
+        private Boolean isSplit;
+
+        /**
+         * 是否合并
+         */
+        private Boolean isMerge;
+
+        /**
+         * 创建人
+         */
+        private String creatorName;
+
+        /**
+         * 买家税号
+         */
+        private String buyerTaxNo;
+
+        /**
+         * 发票类型
+         */
+        private String invoiceType;
+
+        /**
+         * 签收时间
+         */
+        private String signTime;
+
+        /**
+         * SKU列表
+         */
+        private String skus;
+
+        /**
+         * 结束时间
+         */
+        private String endTime;
+
+        /**
+         * 收件人邮箱
+         */
+        private String receiverEmail;
+
+        /**
+         * 推荐人ID
+         */
+        private String referrerId;
+
+        /**
+         * 推荐人名称
+         */
+        private String referrerName;
+
+        /**
+         * 创建时间
+         */
+        private String created;
+
+        /**
+         * 物流单号
+         */
+        private String shipment;
+
+        /**
+         * 开放平台ID
+         */
+        private String openId;
+
+        /**
+         * 售后ID
+         */
+        private String outerAsId;
+
+        /**
+         * 时间戳
+         */
+        private Long ts;
+
+        /**
+         * 买家实付金额
+         */
+        private BigDecimal buyerPaidAmount;
+
+        /**
+         * 卖家实收金额
+         */
+        private BigDecimal sellerIncomeAmount;
+
+        /**
+         * 关联订单ID
+         */
+        private String linkOId;
+
+        /**
+         * 合并订单号
+         */
+        private String mergeSoId;
+
+        /**
+         * 外部订单号
+         */
+        private String outerSoId;
+
+        /**
+         * 分销目标订单ID
+         */
+        private Long drpCoIdTo;
+
+        /**
+         * 店铺买家ID
+         */
+        private String shopBuyerId;
+
+        /**
+         * 收件人姓名
+         */
+        private String receiverName;
+
+        /**
+         * 收件人手机
+         */
+        private String receiverMobile;
+
+        /**
+         * 收件人电话
+         */
+        private String receiverPhone;
+
+        /**
+         * 扩展数据
+         */
+        private String extDatas;
+
+        /**
+         * 售后ID
+         */
+        private String asId;
+
+        /**
+         * 原始订单号列表
+         */
+        private List<String> rawSoIds;
+
+        /**
+         * 未知ID
+         */
+        private String unLid;
+
+        /**
+         * 选择的物流渠道
+         */
+        private String chosenChannel;
+
+        /**
+         * 订单明细
+         */
+        private List<OrderItem> items;
+
+        /**
+         * 支付信息
+         */
+        private List<OrderPay> pays;
+
+        /**
+         * 分销来源
+         */
+        private String drpFrom;
+
+        /**
+         * 分销目标
+         */
+        private String drpTo;
+
+        /**
+         * 财务信息
+         */
+        private List<CbFinance> cbFinances;
+
+        /**
+         * 眼镜信息
+         */
+        private String glasses;
+    }
+
+    /**
+     * 订单明细
+     */
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class OrderItem {
+        /**
+         * 订单明细ID
+         */
+        private Long oiId;
+
+        /**
+         * SKU ID
+         */
+        private String skuId;
+
+        /**
+         * 商品ID
+         */
+        private String iId;
+
+        /**
+         * 店铺SKU ID
+         */
+        private String shopSkuId;
+
+        /**
+         * 店铺商品ID
+         */
+        private String shopIId;
+
+        /**
+         * 商品属性
+         */
+        private String propertiesValue;
+
+        /**
+         * 商品金额
+         */
+        private BigDecimal amount;
+
+        /**
+         * 基础价格
+         */
+        private BigDecimal basePrice;
+
+        /**
+         * 数量
+         */
+        private Integer qty;
+
+        /**
+         * 商品名称
+         */
+        private String name;
+
+        /**
+         * 价格
+         */
+        private BigDecimal price;
+
+        /**
+         * 外部明细ID
+         */
+        private String outerOiId;
+
+        /**
+         * 退款ID
+         */
+        private String refundId;
+
+        /**
+         * 退款数量
+         */
+        private Integer refundQty;
+
+        /**
+         * 退款状态
+         */
+        private String refundStatus;
+
+        /**
+         * 原始订单号
+         */
+        private String rawSoId;
+
+        /**
+         * 是否预售
+         */
+        private Boolean isPresale;
+
+        /**
+         * 是否赠品
+         */
+        private Boolean isGift;
+
+        /**
+         * 商品状态
+         */
+        private String itemStatus;
+
+        /**
+         * 发货仓库
+         */
+        private Integer sendWarehouse;
+
+        /**
+         * 商品支付金额
+         */
+        private BigDecimal itemPayAmount;
+
+        /**
+         * 推荐人ID
+         */
+        private String referrerId;
+
+        /**
+         * 折扣率
+         */
+        private BigDecimal discountRate;
+
+        /**
+         * 商品图片
+         */
+        private String pic;
+
+        /**
+         * SKU类型
+         */
+        private String skuType;
+
+        /**
+         * 备注
+         */
+        private String remark;
+
+        /**
+         * 源组合SKU ID
+         */
+        private String srcCombineSkuId;
+
+        /**
+         * 商品扩展数据
+         */
+        private String itemExtData;
+
+        /**
+         * 买家实付金额
+         */
+        private BigDecimal buyerPaidAmount;
+
+        /**
+         * 卖家实收金额
+         */
+        private BigDecimal sellerIncomeAmount;
+
+        /**
+         * 订单ID
+         */
+        private Long oId;
+    }
+
+    /**
+     * 支付信息
+     */
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class OrderPay {
+        /**
+         * 支付ID
+         */
+        private Long payId;
+
+        /**
+         * 外部支付ID
+         */
+        private String outerPayId;
+
+        /**
+         * 支付时间
+         */
+        private String payDate;
+
+        /**
+         * 支付金额
+         */
+        private BigDecimal amount;
+
+        /**
+         * 支付方式
+         */
+        private String payment;
+
+        /**
+         * 买家账号
+         */
+        private String buyerAccount;
+
+        /**
+         * 是否订单支付
+         */
+        private Boolean isOrderPay;
+
+        /**
+         * 支付状态
+         */
+        private String status;
+
+        /**
+         * 支付类型
+         */
+        private Integer payType;
+
+        /**
+         * 订单ID
+         */
+        private Long oId;
+    }
+
+    /**
+     * 财务信息
+     */
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class CbFinance {
+        /**
+         * 订单ID
+         */
+        private Long oId;
+
+        /**
+         * 返点费用
+         */
+        private BigDecimal rebateFee;
+
+        /**
+         * 商品税费
+         */
+        private BigDecimal productTax;
+
+        /**
+         * 运费税费
+         */
+        private BigDecimal shippingTax;
+
+        /**
+         * 其他收入
+         */
+        private BigDecimal otherIncome;
+
+        /**
+         * 卖家代金券
+         */
+        private BigDecimal voucherFromSeller;
+
+        /**
+         * 平台佣金
+         */
+        private BigDecimal platformCommission;
+
+        /**
+         * 过渡费用
+         */
+        private BigDecimal transitionFee;
+
+        /**
+         * 交易费用
+         */
+        private BigDecimal transactionFee;
+
+        /**
+         * 不透明包装费
+         */
+        private BigDecimal opaqueBaggingFee;
+
+        /**
+         * 其他支出
+         */
+        private BigDecimal otherExpense;
+    }
+}

+ 42 - 0
fs-service/src/main/java/com/fs/erp/dto/PaymentDTO.java

@@ -0,0 +1,42 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 支付信息DTO
+ */
+@Data
+public class PaymentDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 外部支付ID
+     */
+    private String outerPayId;
+
+    /**
+     * 支付日期
+     */
+    private String payDate;
+
+    /**
+     * 支付方式
+     */
+    private String payment;
+
+    /**
+     * 卖家账户
+     */
+    private String sellerAccount;
+
+    /**
+     * 买家账户
+     */
+    private String buyerAccount;
+
+    /**
+     * 支付金额
+     */
+    private Double amount;
+}

+ 112 - 0
fs-service/src/main/java/com/fs/erp/dto/ProductQueryRequestDTO.java

@@ -0,0 +1,112 @@
+package com.fs.erp.dto;
+
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+/**
+ * 商品查询请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Accessors(chain = true)
+@ApiModel(value = "商品查询请求对象", description = "商品查询请求参数")
+public class ProductQueryRequestDTO {
+
+    /**
+     * 第几页,从第一页开始,默认1
+     */
+    @ApiModelProperty(value = "第几页,从第一页开始,默认1", example = "1")
+    private Integer pageIndex;
+
+    /**
+     * 每页多少条,默认30,最大100
+     */
+    @ApiModelProperty(value = "每页多少条,默认30,最大100", example = "10")
+    private Integer pageSize;
+
+    /**
+     * 修改起始时间
+     */
+    @ApiModelProperty(value = "修改起始时间,和结束时间必须同时存在,时间间隔不能超过七天", example = "2021-12-01 18:34:13")
+    private String modifiedBegin;
+
+    /**
+     * 修改结束时间
+     */
+    @ApiModelProperty(value = "修改结束时间,和起始时间必须同时存在,时间间隔不能超过七天", example = "2021-12-08 18:34:13")
+    private String modifiedEnd;
+
+    /**
+     * 商品编码列表,最多20个
+     */
+    @ApiModelProperty(value = "商品编码,与修改时间不能同时为空,最多20个", example = "D0005J15101,D0005J20101")
+    private String skuIds;
+
+    /**
+     * 商品名称(精确搜索)
+     */
+    @ApiModelProperty(value = "商品名称,与修改时间不能同时为空,仅支持传一个名称(精确搜索)", example = "A01")
+    private String exactlyName;
+
+    /**
+     * 商品名称(模糊查询)
+     */
+    @ApiModelProperty(value = "商品名称,与修改时间不能同时为空,仅支持传一个名称(模糊查询)")
+    private String name;
+
+    /**
+     * 品牌列表
+     */
+    @ApiModelProperty(value = "品牌列表")
+    private List<String> brand;
+
+    /**
+     * 款式编码列表
+     */
+    @ApiModelProperty(value = "款式编码列表")
+    private List<String> iIds;
+
+    /**
+     * 查询字段类型
+     */
+    @ApiModelProperty(value = "可传created,modified。默认按照modified查询")
+    private String dateField;
+
+    /**
+     * 自定义查询字段,多个字段用逗号分开
+     */
+    @ApiModelProperty(value = "可传:purchase_price 采购价,多个字段用逗号分开")
+    private String flds;
+
+    /**
+     * 辅助码
+     */
+    @ApiModelProperty(value = "辅助码,与修改时间不能同时为空")
+    private String skuCodes;
+
+    /**
+     * 包含标签列表
+     */
+    @ApiModelProperty(value = "包含标签列表")
+    private List<String> labels;
+
+    /**
+     * 排除标签列表
+     */
+    @ApiModelProperty(value = "排除标签列表")
+    private List<String> notLabels;
+
+    /**
+     * 是否查询库容信息
+     */
+    @ApiModelProperty(value = "是否查询库容信息")
+    private Boolean loadSkuBin;
+}

+ 405 - 0
fs-service/src/main/java/com/fs/erp/dto/ProductResponseDTO.java

@@ -0,0 +1,405 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 商品信息响应DTO
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ProductResponseDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 每页多少条
+     */
+    private Integer pageSize;
+
+    /**
+     * 第几页
+     */
+    private Integer pageIndex;
+
+    /**
+     * 总条数
+     */
+    private Integer dataCount;
+
+    /**
+     * 总页数
+     */
+    private Integer pageCount;
+
+    /**
+     * 是否有下一页
+     */
+    private Boolean hasNext;
+
+    /**
+     * 数据集合
+     */
+    private List<ProductInfo> datas;
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class ProductInfo implements Serializable {
+
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * 商品编码
+         */
+        private String skuId;
+
+        /**
+         * 款式编码
+         */
+        private String iId;
+
+        /**
+         * 商品名称
+         */
+        private String name;
+
+        /**
+         * 商品简称
+         */
+        private String shortName;
+
+        /**
+         * 销售价
+         */
+        private BigDecimal salePrice;
+
+        /**
+         * 成本价
+         */
+        private BigDecimal costPrice;
+
+        /**
+         * 颜色规格
+         */
+        private String propertiesValue;
+
+        /**
+         * 颜色
+         */
+        private String color;
+
+        /**
+         * 类目id
+         */
+        private Integer cId;
+
+        /**
+         * 分类
+         */
+        private String category;
+
+        /**
+         * 大图地址
+         */
+        private String picBig;
+
+        /**
+         * 图片地址
+         */
+        private String pic;
+
+        /**
+         * 是否启用,0:备用,1:启用,-1:禁用
+         */
+        private Integer enabled;
+
+        /**
+         * 重量
+         */
+        private BigDecimal weight;
+
+        /**
+         * 市场价
+         */
+        private BigDecimal marketPrice;
+
+        /**
+         * 品牌
+         */
+        private String brand;
+
+        /**
+         * 供应商编号
+         */
+        private String supplierId;
+
+        /**
+         * 供应商名称
+         */
+        private String supplierName;
+
+        /**
+         * 修改时间
+         */
+        private String modified;
+
+        /**
+         * 国标码
+         */
+        private String skuCode;
+
+        /**
+         * 供应商商品编码
+         */
+        private String supplierSkuId;
+
+        /**
+         * 供应商商品款号
+         */
+        private String supplierIId;
+
+        /**
+         * 虚拟分类
+         */
+        private String vcName;
+
+        /**
+         * 商品类型
+         */
+        private String skuType;
+
+        /**
+         * 创建者
+         */
+        private Integer creator;
+
+        /**
+         * 创建时间
+         */
+        private String created;
+
+        /**
+         * 备注
+         */
+        private String remark;
+
+        /**
+         * 商品属性,成品,半成品,原材料,包材
+         */
+        private String itemType;
+
+        /**
+         * 是否禁止同步,0=启用同步,1=禁用同步,2=部分禁用
+         */
+        private Integer stockDisabled;
+
+        /**
+         * 单位
+         */
+        private String unit;
+
+        /**
+         * 保质期
+         */
+        private Integer shelfLife;
+
+        /**
+         * 商品标签,多个标签时以逗号分隔
+         */
+        private String labels;
+
+        /**
+         * 生产许可证
+         */
+        private String productionLicence;
+
+        /**
+         * 长
+         */
+        private BigDecimal l;
+
+        /**
+         * 宽
+         */
+        private BigDecimal w;
+
+        /**
+         * 高
+         */
+        private BigDecimal h;
+
+        /**
+         * 是否开启序列号
+         */
+        private Boolean isSeriesNumber;
+
+        /**
+         * 其他价格1
+         */
+        private BigDecimal otherPrice1;
+
+        /**
+         * 其他价格2
+         */
+        private BigDecimal otherPrice2;
+
+        /**
+         * 其他价格3
+         */
+        private BigDecimal otherPrice3;
+
+        /**
+         * 其他价格4
+         */
+        private BigDecimal otherPrice4;
+
+        /**
+         * 其他价格5
+         */
+        private BigDecimal otherPrice5;
+
+        /**
+         * 其他价格6
+         */
+        private BigDecimal otherPrice6;
+
+        /**
+         * 其他价格7
+         */
+        private BigDecimal otherPrice7;
+
+        /**
+         * 其他价格8
+         */
+        private BigDecimal otherPrice8;
+
+        /**
+         * 其他价格9
+         */
+        private BigDecimal otherPrice9;
+
+        /**
+         * 其他价格10
+         */
+        private BigDecimal otherPrice10;
+
+        /**
+         * 其他属性1
+         */
+        private String other1;
+
+        /**
+         * 其他属性2
+         */
+        private String other2;
+
+        /**
+         * 其他属性3
+         */
+        private String other3;
+
+        /**
+         * 其他属性4
+         */
+        private String other4;
+
+        /**
+         * 其他属性5
+         */
+        private String other5;
+
+        /**
+         * 其他属性6
+         */
+        private String other6;
+
+        /**
+         * 其他属性7
+         */
+        private String other7;
+
+        /**
+         * 其他属性8
+         */
+        private String other8;
+
+        /**
+         * 其他属性9
+         */
+        private String other9;
+
+        /**
+         * 其他属性10
+         */
+        private String other10;
+
+        /**
+         * 链接同步状态
+         */
+        private String stockType;
+
+        /**
+         * 辅助码
+         */
+        private String skuCodes;
+
+        /**
+         * 唯一id,系统自增id(若商品编码有被修改可以用此字段判断唯一)
+         */
+        private Integer autoid;
+
+        /**
+         * 是否开启生产批次开关
+         */
+        private String batchEnabled;
+
+        /**
+         * 主仓位
+         */
+        private String bin;
+
+        /**
+         * 补充仓位
+         */
+        private String otherBin;
+
+        /**
+         * 库容下限
+         */
+        private BigDecimal minQty;
+
+        /**
+         * 库容上限
+         */
+        private BigDecimal maxQty;
+
+        /**
+         * 溢出数量
+         */
+        private BigDecimal overflowQty;
+
+        /**
+         * 标准装箱数量
+         */
+        private BigDecimal packQty;
+
+        /**
+         * 标准装箱体积
+         */
+        private BigDecimal packVolume;
+    }
+}

+ 37 - 0
fs-service/src/main/java/com/fs/erp/dto/ProductUploadResultDTO.java

@@ -0,0 +1,37 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 商品上传结果DTO
+ *
+ * @author xdd
+ * @date 2025-02-27
+ * @version 1.0
+ * @since 1.0
+ */
+@Data
+@Accessors(chain = true)
+public class ProductUploadResultDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 是否上传成功
+     */
+    private String isSuccess;
+
+    /**
+     * 商品编码
+     */
+    private String skuId;
+
+    /**
+     * 执行信息
+     */
+    private String msg;
+
+}

+ 63 - 0
fs-service/src/main/java/com/fs/erp/dto/RefreshTokenRequestDTO.java

@@ -0,0 +1,63 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * 刷新令牌请求DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Accessors(chain = true)
+public class RefreshTokenRequestDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 开发者应用Key
+     * 示例值: 0ecde8631431a5ed6b3e7368afbabdadss
+     */
+    private String app_key;
+
+    /**
+     * 当前请求的时间戳(单位:秒)
+     * 示例值: 1577771730
+     */
+    private String timestamp;
+
+    /**
+     * 授权类型
+     * 固定值: refresh_token
+     */
+    private String grant_type = "refresh_token";
+
+    /**
+     * 交互数据的编码
+     * 固定值: utf-8
+     */
+    private String charset = "utf-8";
+
+    /**
+     * 更新令牌
+     * 示例值: eb1964a9d142423a9f0de88b97bb38fc
+     */
+    private String refresh_token;
+
+    /**
+     * 授权范围
+     * 固定值: all
+     */
+    private String scope = "all";
+
+    /**
+     * 请求的数字签名
+     * 通过所有请求参数通过摘要生成,保证请求参数没有被篡改
+     * 示例值: 0ecde8631431a5ed6b3e7368afbabdaoas
+     */
+    private String sign;
+}

+ 65 - 0
fs-service/src/main/java/com/fs/erp/dto/RefundItemDTO.java

@@ -0,0 +1,65 @@
+package com.fs.erp.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 退货商品DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class RefundItemDTO implements Serializable {
+
+    private static final long serialVersionUID = -1L;
+
+    /**
+     * 商品金额
+     */
+    private BigDecimal amount;
+
+    /**
+     * 商品属性
+     */
+    private String propertiesValue;
+
+    /**
+     * 商品数量
+     */
+    private Integer qty;
+
+    /**
+     * 商品名称
+     */
+    private String name;
+
+    /**
+     * 商品SKU ID
+     */
+    private String skuId;
+
+    /**
+     * 商品图片
+     */
+    private String pic;
+
+    /**
+     * 退货类型
+     */
+    private String type;
+
+    /**
+     * 外部订单项ID
+     */
+    private String outerOiId;
+}

+ 158 - 0
fs-service/src/main/java/com/fs/erp/dto/ShopOrderDTO.java

@@ -0,0 +1,158 @@
+package com.fs.erp.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * 店铺订单信息DTO
+ *
+ * @author xdd
+ * @version 1.0
+ * @since 2025-02-27
+ */
+@Data
+public class ShopOrderDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+    /**
+     * 店铺ID
+     */
+    private Long shopId;
+
+    /**
+     * 订单ID
+     */
+    private String soId;
+
+    /**
+     * 订单日期
+     */
+    private String orderDate;
+
+    /**
+     * 店铺订单状态
+     */
+    private String shopStatus;
+
+    /**
+     * 是否货到付款
+     */
+    private Boolean isCod;
+
+    /**
+     * 总买家实付
+     */
+    private BigDecimal buyerPaidAmount;
+
+    /**
+     * 买家ID
+     */
+    private String shopBuyerId;
+
+    /**
+     * 收货人省份
+     */
+    private String receiverState;
+
+    /**
+     * 收货人城市
+     */
+    private String receiverCity;
+
+    /**
+     * 收货人区域
+     */
+    private String receiverDistrict;
+
+    /**
+     * 收货人详细地址
+     */
+    private String receiverAddress;
+
+    /**
+     * 收货人姓名
+     */
+    private String receiverName;
+
+    /**
+     * 收货人电话
+     */
+    private String receiverPhone;
+
+    /**
+     * 收货人邮编
+     */
+    private String receiverZip;
+
+    /**
+     * 支付金额
+     */
+    private Double payAmount;
+
+    /**
+     * 运费
+     */
+    private Double freight;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 买家留言
+     */
+    private String buyerMessage;
+
+    /**
+     * 订单修改时间
+     */
+    private String shopModified;
+
+    /**
+     * 物流ID
+     */
+    private String lId;
+
+    /**
+     * 物流公司
+     */
+    private String logisticsCompany;
+
+    /**
+     * 标签
+     */
+    private String labels;
+
+    /**
+     * 物流公司ID
+     */
+    private String lcId;
+
+    /**
+     * 订单商品项列表
+     */
+    private List<OrderItemDTO> items;
+
+    /**
+     * 支付信息
+     */
+    private PaymentDTO pay;
+
+    /**
+     * 扩展数据
+     */
+    private ExtDataDTO extDatas;
+
+    /**
+     * 订单扩展信息
+     */
+    private OrderExtDTO orderExt;
+
+    /**
+     * 财务数据
+     */
+    private FinanceDataDTO financeData;
+}

+ 11 - 0
fs-service/src/main/java/com/fs/erp/dto/df/DFCancelOrderResultRequest.java

@@ -0,0 +1,11 @@
+package com.fs.erp.dto.df;
+
+import lombok.Data;
+
+@Data
+public class DFCancelOrderResultRequest {
+    private Integer isCancelSuss;
+    private String loginAccount;
+    private String mailNumber;
+    private String orderNumber;
+}

+ 1 - 0
fs-service/src/main/java/com/fs/erp/dto/df/DFConfigVo.java

@@ -9,6 +9,7 @@ public class DFConfigVo {
     String loginAccount; //登录账号
     String callBackUrl; //回调地址
     String monthlyCard; //月结账号
+    String expressProductCode; //物流产品编码
     String senderName; //寄件人姓名
     String senderPhone;  //寄件人手机
     String senderProvince;  //寄件人省

+ 11 - 0
fs-service/src/main/java/com/fs/erp/dto/df/DFOrderStatusResultRequest.java

@@ -0,0 +1,11 @@
+package com.fs.erp.dto.df;
+
+import lombok.Data;
+
+@Data
+public class DFOrderStatusResultRequest {
+    private Integer status;
+    private Long acceptTime;
+    private String mailNumber; //运单号
+    private String acceptTimeStr;
+}

+ 1 - 0
fs-service/src/main/java/com/fs/erp/dto/sdk/df/enums/RequestUrlEnum.java

@@ -6,6 +6,7 @@ public enum RequestUrlEnum {
     CREAT_ORDER("order/create", "POST"),
     ORDER_RESULT("query/order", "POST"),
     ORDER_DELIVERY("query/route", "GET"),
+    ORDER_DELIVERY_STATUS("query/waybill", "POST"),
     ORDER_CANCEL("order/cancel", "POST");
 
     private final String url;

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

@@ -0,0 +1,79 @@
+package com.fs.erp.http;
+
+import com.fs.erp.dto.*;
+import com.fs.ybPay.dto.RefundOrderDTO;
+
+/**
+ * JST ERP 接口服务类
+ */
+public interface JstErpHttpService {
+    /**
+     * 获取access_token、refresh_token
+     *
+     * 开放平台对token的过期时间默认设置为<strong>30天</strong>
+     * 过期前12小时内调用才会有效,
+     * 调用成功后生成新的access_token原access_token有5分钟的过期时间,5分钟后失效
+     * @param dto 请求参数
+     * @return GetInitTokenResponseDTO
+     */
+    GetInitTokenResponseDTO getInitToken(GetInitTokenRequestDTO dto);
+
+    /**
+     * 更新access_token、refresh_token
+     * 开放平台对token的过期时间默认设置为30天,如开发者的token过期未换,无法再调用更新token这个接口需要返回上一步骤重新授权。
+     * 15天内刷新无效,刷新成功后原access_token有5分钟的过期时间
+     * @param dto 请求参数
+     * @return GetInitTokenResponseDTO
+     */
+    GetInitTokenResponseDTO refreshToken(RefreshTokenRequestDTO dto);
+
+    /**
+     * 普通商品资料上传
+     * @param dto 请求参数
+     * @return ProductUploadResultDTO
+     */
+    ProductUploadResultDTO uploadGoods(GoodsInfoDTO dto);
+
+    /**
+     * 普通商品资料查询(按sku查询)
+     * @param dto 请求参数
+     * @return ProductResponseDTO
+     */
+    ProductResponseDTO queryGoods(ProductQueryRequestDTO dto);
+
+    /**
+     * 订单上传(商家自有商城、跨境线下)
+     * @param dto 请求参数
+     * @return ErpOrderResponseDTO
+     */
+    ErpOrderResponseDTO upload(ShopOrderDTO dto);
+
+    /**
+     * 订单查询(自有商城、跨境线下)
+     * @param dto 请求参数
+     * @return OrderQueryResponseDTO
+     */
+    OrderQueryResponseDTO query(OrderQueryRequestDTO dto);
+
+    /**
+     * 订单取消-按内部单号取消
+     * @param dto 请求参数
+     * @return CommonResponse
+     */
+    CommonResponse cancel(OrderCancelRequestDTO dto);
+
+    /**
+     * 售后上传
+     * @param dto 请求参数
+     * @return CommonResponse<AfterSaleResponseDTO>
+     */
+    CommonResponse<AfterSaleResponseDTO> aftersaleUpload(RefundOrderDTO dto);
+
+    /**
+     * 售后单确认
+     * @param dto 请求参数
+     * @return CommonResponse<AssetProcessResultDTO>
+     */
+    CommonResponse<AssetProcessResultDTO> aftersaleConfirm(AfterSaleConfirmRequestDTO dto);
+
+}

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

@@ -0,0 +1,296 @@
+package com.fs.erp.http;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.PropertyNamingStrategy;
+import com.alibaba.fastjson.TypeReference;
+import com.alibaba.fastjson.serializer.SerializeConfig;
+import com.fs.erp.dto.*;
+import com.fs.erp.service.impl.JstTokenService;
+import com.fs.erp.utils.SignUtil;
+import com.fs.ybPay.dto.RefundOrderDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.ObjectUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Service
+public class JstErpHttpServiceImpl implements JstErpHttpService {
+
+    private static final String BASE_URL = "https://openapi.jushuitan.com/";
+    /**
+     * 获取access_token、refresh_token url
+     */
+    private static final String GET_INIT_TOKEN_URL = BASE_URL + "openWeb/auth/getInitToken";
+
+    /**
+     * 更新access_token、refresh_token url
+     */
+    private static final String REFRESH_TOKEN_URL = BASE_URL + "openWeb/auth/refreshToken";
+
+
+    @Value("${jst.app_key:''}")
+    private String appKey;
+
+    @Value("${jst.app_secret:''}")
+    private String appSecret;
+
+    @Autowired
+    private JstTokenService jstTokenService;
+
+    @Override
+    public GetInitTokenResponseDTO getInitToken(GetInitTokenRequestDTO dto) {
+        // 将DTO转换为表单参数
+        Map<String, Object> formParams = BeanUtil.beanToMap(dto);
+        log.info("请求初始化token - URL: {}, 参数: {}", GET_INIT_TOKEN_URL, JSON.toJSONString(formParams));
+
+        HttpResponse response = executeFormPost(GET_INIT_TOKEN_URL, formParams);
+        return parseResponse(response, new TypeReference<CommonResponse<GetInitTokenResponseDTO>>() {});
+    }
+
+    @Override
+    public GetInitTokenResponseDTO refreshToken(RefreshTokenRequestDTO dto) {
+        log.info("刷新token - URL: {}, 请求体: {}", REFRESH_TOKEN_URL, JSON.toJSONString(dto));
+        Map<String, Object> formParams = BeanUtil.beanToMap(dto);
+
+        HttpResponse response = executeFormPost(REFRESH_TOKEN_URL, formParams);
+        return parseResponse(response, new TypeReference<CommonResponse<GetInitTokenResponseDTO>>() {});
+    }
+
+    @Override
+    public ProductUploadResultDTO uploadGoods(GoodsInfoDTO dto) {
+        String url = BASE_URL + "/open/jushuitan/itemsku/upload";
+        log.info("上传商品信息 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
+
+        HttpResponse response = executeJsonPost(url, dto);
+        return parseResponse(response, new TypeReference<CommonResponse<ProductUploadResultDTO>>() {});
+    }
+
+    @Override
+    public ProductResponseDTO queryGoods(ProductQueryRequestDTO dto) {
+        String url = BASE_URL + "/open/sku/query";
+        log.info("查询商品信息 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
+
+        HttpResponse response = executeJsonPost(url, dto);
+        return parseResponse(response, new TypeReference<CommonResponse<ProductResponseDTO>>() {});
+    }
+
+    @Override
+    public ErpOrderResponseDTO upload(ShopOrderDTO dto) {
+        String url = BASE_URL + "open/jushuitan/orders/upload";
+        log.info("上传订单信息 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
+
+        HttpResponse response = executeJsonPost(url, Arrays.asList(dto));
+        return parseResponse(response, new TypeReference<CommonResponse<ErpOrderResponseDTO>>() {});
+    }
+
+    @Override
+    public OrderQueryResponseDTO query(OrderQueryRequestDTO dto) {
+        String url = BASE_URL + "/open/orders/single/query";
+        log.info("查询订单信息 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
+
+        HttpResponse response = executeJsonPost(url, dto);
+        return parseResponse(response, new TypeReference<CommonResponse<OrderQueryResponseDTO>>() {});
+    }
+
+    @Override
+    public CommonResponse cancel(OrderCancelRequestDTO dto) {
+        String url = BASE_URL + "/open/jushuitan/orderbyoid/cancel";
+        log.info("取消订单 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
+
+        HttpResponse response = executeJsonPost(url, dto);
+        // 这里直接返回CommonResponse类型
+        return parseCommonResponse(response);
+    }
+
+    @Override
+    public CommonResponse<AfterSaleResponseDTO> aftersaleUpload(RefundOrderDTO dto) {
+        String url = BASE_URL + "/open/aftersale/upload";
+        log.info("售后上传 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
+
+        HttpResponse response = executeJsonPost(url, Collections.singletonList(dto));
+        // 这里直接返回CommonResponse类型
+        return parseCommonResponse(response);
+    }
+
+    @Override
+    public CommonResponse<AssetProcessResultDTO> aftersaleConfirm(AfterSaleConfirmRequestDTO dto) {
+        String url = BASE_URL + "/open/webapi/aftersaleapi/open/confirm";
+        log.info("售后单确认 - URL: {}, 请求体: {}", url, JSON.toJSONString(dto));
+
+        HttpResponse response = executeJsonPost(url, dto);
+        // 这里直接返回CommonResponse类型
+        return parseCommonResponse(response);
+    }
+
+    /**
+     * 执行JSON格式的POST请求
+     *
+     * @param url 请求URL
+     * @param dto 请求对象
+     * @param needToken 是否需要添加access_token(认证相关请求不需要)
+     * @return HttpResponse响应
+     */
+    private HttpResponse executeJsonPost(String url, Object dto, boolean needToken) {
+        SerializeConfig serializeConfig = new SerializeConfig();
+        serializeConfig.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
+        String jsonBody = JSON.toJSONString(dto, serializeConfig);
+        Map<String, Object> map = new HashMap<>();
+
+        // 只有在需要token的请求中才添加access_token
+        if (needToken) {
+            String accessToken = jstTokenService.getAccessToken();
+            map.put("access_token", accessToken);
+        }
+
+        map.put("app_key", appKey);
+        map.put("timestamp", System.currentTimeMillis() / 1000);
+        map.put("version", "2");
+        map.put("charset", "utf-8");
+        map.put("biz", jsonBody);
+        map.put("sign", SignUtil.getSignNew(appSecret, map));
+        Map<String, String> headers = MapUtil.builder(new HashMap<String, String>())
+                .put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")
+                .build();
+        log.debug("发送JSON请求 - URL: {}, Headers: {}, Body: {}", url, headers, JSON.toJSONString(map));
+        HttpResponse response = HttpRequest.post(url)
+                .headerMap(headers, true)
+                .form(map)
+                .execute();
+        logResponse(response);
+        return response;
+    }
+
+    /**
+     * 执行JSON格式的POST请求
+     *
+     * @param url 请求URL
+     * @param dto 请求对象
+     * @return HttpResponse响应
+     */
+    private HttpResponse executeJsonPost(String url, Object dto) {
+        SerializeConfig serializeConfig = new SerializeConfig();
+        serializeConfig.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;
+
+        String jsonBody = JSON.toJSONString(dto, serializeConfig);
+
+        Map<String,Object> map = new HashMap<>();
+
+        String accessToken = jstTokenService.getAccessToken();
+
+        map.put("access_token",accessToken);
+        map.put("app_key",appKey);
+        map.put("timestamp",System.currentTimeMillis()/1000);
+        map.put("version","2");
+        map.put("charset","utf-8");
+        map.put("biz", jsonBody);
+
+        map.put("sign",SignUtil.getSignNew(appSecret, map));
+
+
+        Map<String, String> headers = MapUtil.builder(new HashMap<String, String>())
+                .put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")
+                .build();
+
+
+        log.debug("发送JSON请求 - URL: {}, Headers: {}, Body: {}", url, headers, JSON.toJSONString(map));
+
+        HttpResponse response = HttpRequest.post(url)
+                .headerMap(headers, true)
+                .form(map)
+                .execute();
+
+        logResponse(response);
+        return response;
+    }
+
+
+    /**
+     * 执行表单格式的POST请求
+     *
+     * @param url 请求URL
+     * @param formParams 表单参数
+     * @return HttpResponse响应
+     */
+    private HttpResponse executeFormPost(String url, Map<String, Object> formParams) {
+        Map<String, String> headers = MapUtil.builder(new HashMap<String, String>())
+                .put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8")
+                .build();
+
+        log.debug("发送表单请求 - URL: {}, Headers: {}, Form: {}", url, headers, formParams);
+
+        HttpResponse response = HttpRequest.post(url)
+                .headerMap(headers, true)
+                .form(formParams)
+                .execute();
+
+        logResponse(response);
+        return response;
+    }
+
+    /**
+     * 记录HTTP响应日志
+     *
+     * @param response HTTP响应
+     */
+    private void logResponse(HttpResponse response) {
+        log.debug("收到响应 - Status: {}, Headers: {}", response.getStatus(), response.headers());
+        log.debug("响应体: {}", response.body());
+    }
+
+    /**
+     * 解析带有泛型的HTTP响应
+     *
+     * @param response HTTP响应
+     * @param typeReference 响应类型引用
+     * @param <T> 期望的响应数据类型
+     * @return 解析后的数据
+     */
+    private <T> T parseResponse(HttpResponse response, TypeReference<CommonResponse<T>> typeReference) {
+        String body = response.body();
+        log.debug("解析响应体: {}", body);
+
+        CommonResponse<T> commonResponse = JSON.parseObject(body, typeReference);
+
+//        if (ObjectUtils.notEqual(commonResponse.getCode(), 0)) {
+        if (!Integer.valueOf(0).equals(commonResponse.getCode())) {
+            log.error("API请求失败 - 错误码: {}, 错误信息: {}", commonResponse.getCode(), commonResponse.getMsg());
+            throw new RuntimeException("请求接口失败!原因:" + commonResponse.getMsg());
+        }
+
+        T result = commonResponse.getData();
+        log.info("API请求成功 - 结果: {}", JSON.toJSONString(result));
+        return result;
+    }
+
+    /**
+     * 解析普通CommonResponse响应(无泛型)
+     *
+     * @param response HTTP响应
+     * @return CommonResponse对象
+     */
+    private CommonResponse parseCommonResponse(HttpResponse response) {
+        String body = response.body();
+        log.debug("解析响应体: {}", body);
+
+        CommonResponse commonResponse = JSON.parseObject(body, CommonResponse.class);
+
+        if (ObjectUtils.notEqual(commonResponse.getCode(), 0)) {
+            log.error("API请求失败 - 错误码: {}, 错误信息: {}", commonResponse.getCode(), commonResponse.getMsg());
+            throw new RuntimeException("请求接口失败!原因:" + commonResponse.getMsg());
+        }
+
+        log.info("API请求成功 - 结果: {}", JSON.toJSONString(commonResponse));
+        return commonResponse;
+    }
+}

+ 110 - 0
fs-service/src/main/java/com/fs/erp/mapper/FsJstAftersalePushMapper.java

@@ -0,0 +1,110 @@
+package com.fs.erp.mapper;
+
+import com.fs.erp.domain.FsJstAftersalePush;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+/**
+ * 订阅物流Mapper
+ */
+@Mapper
+public interface FsJstAftersalePushMapper {
+
+    /**
+     * 根据ID查询
+     */
+    @Select("SELECT * FROM fs_jst_aftersale_push WHERE id = #{id}")
+    FsJstAftersalePush selectById(Long id);
+
+    /**
+     * 根据订单ID查询
+     */
+    @Select("SELECT * FROM fs_jst_aftersale_push WHERE order_id = #{orderId}")
+    FsJstAftersalePush selectByOrderId(String orderId);
+
+    /**
+     * 查询待处理的任务
+     */
+    @Select("SELECT * FROM fs_jst_aftersale_push WHERE task_status = #{status} AND retry_count < #{maxRetry} LIMIT #{limit}")
+    List<FsJstAftersalePush> selectByStatusAndRetry(Byte status, Integer maxRetry, Integer limit);
+
+    /**
+     * 插入记录
+     */
+    @Insert("INSERT INTO fs_jst_aftersale_push(order_id,after_sale_id, type, task_status, retry_count, last_execute_time, params) " +
+            "VALUES(#{orderId},#{afterSaleId}, #{type}, #{taskStatus}, #{retryCount}, #{lastExecuteTime}, #{params})")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+    int insert(FsJstAftersalePush push);
+
+    /**
+     * 更新记录
+     */
+    @Update("UPDATE fs_jst_aftersale_push SET params=#{params},task_status = #{taskStatus}, retry_count = #{retryCount}, " +
+            "last_execute_time = #{lastExecuteTime}, result = #{result}, error_message = #{errorMessage} " +
+            "WHERE id = #{id}")
+    int update(FsJstAftersalePush push);
+
+    /**
+     * 更新任务状态
+     */
+    @Update("UPDATE fs_jst_aftersale_push SET task_status = #{taskStatus}, " +
+            "last_execute_time = now() WHERE id = #{id}")
+    int updateStatus(@Param("id") Long id, @Param("taskStatus") Byte taskStatus);
+
+    @Select("WITH OrderWithNextTaskType AS (\n" +
+            "    SELECT \n" +
+            "        id,\n" +
+            "        order_id,\n" +
+            "        after_sale_id,\n" +
+            "        type,\n" +
+            "        task_status,\n" +
+            "        retry_count,\n" +
+            "        ROW_NUMBER() OVER(PARTITION BY order_id ORDER BY CAST(type AS UNSIGNED)) AS task_seq\n" +
+            "    FROM \n" +
+            "        fs_jst_aftersale_push\n" +
+            "),\n" +
+            "PendingTasks AS (\n" +
+            "    SELECT \n" +
+            "        o.id,\n" +
+            "        o.order_id,\n" +
+            "        o.after_sale_id,\n" +
+            "        o.type,\n" +
+            "        o.task_status,\n" +
+            "        o.retry_count,\n" +
+            "        o.task_seq,\n" +
+            "        (\n" +
+            "            SELECT MAX(p.task_status)  \n" +
+            "            FROM OrderWithNextTaskType p\n" +
+            "            WHERE p.order_id = o.order_id\n" +
+            "              AND p.task_seq = o.task_seq - 1\n" +
+            "        ) AS prev_task_status,\n" +
+            "        EXISTS (\n" +
+            "            SELECT 1\n" +
+            "            FROM OrderWithNextTaskType p\n" +
+            "            WHERE p.order_id = o.order_id\n" +
+            "              AND p.task_seq < o.task_seq\n" +
+            "              AND p.task_status != 1\n" +
+            "        ) AS has_pending_prev_task\n" +
+            "    FROM \n" +
+            "        OrderWithNextTaskType o\n" +
+            "    WHERE \n" +
+            "        o.task_status = 0 OR (o.task_status = 2 AND o.retry_count < 3)\n" +
+            ")\n" +
+            "SELECT \n" +
+            "    id,\n" +
+            "    order_id,\n" +
+            "    after_sale_id,\n" +
+            "    type,\n" +
+            "    task_status,\n" +
+            "    retry_count\n" +
+            "FROM \n" +
+            "    PendingTasks\n" +
+            "WHERE \n" +
+            "    (task_seq = 1 OR prev_task_status = 1)\n" +
+            "    AND has_pending_prev_task = 0\n" +
+            "ORDER BY\n" +
+            "    order_id,\n" +
+            "    task_seq;\n")
+    List<FsJstAftersalePush> queryPenddingData();
+}

+ 77 - 0
fs-service/src/main/java/com/fs/erp/mapper/FsJstCodPushMapper.java

@@ -0,0 +1,77 @@
+package com.fs.erp.mapper;
+
+import com.fs.erp.domain.FsJstCodPush;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+@Mapper
+public interface FsJstCodPushMapper {
+
+    /**
+     * 根据ID查询记录
+     */
+    @Select("SELECT * FROM fs_jst_cod_push WHERE id = #{id}")
+    FsJstCodPush selectById(@Param("id") Long id);
+
+    /**
+     * 根据订单ID查询记录
+     */
+    @Select("SELECT * FROM fs_jst_cod_push WHERE order_id = #{orderId}")
+    List<FsJstCodPush> selectByOrderId(@Param("orderId") String orderId);
+
+    /**
+     * 根据售后ID查询记录
+     */
+    @Select("SELECT * FROM fs_jst_cod_push WHERE after_sale_id = #{afterSaleId}")
+    List<FsJstCodPush> selectByAfterSaleId(@Param("afterSaleId") String afterSaleId);
+
+    /**
+     * 查询待处理的任务
+     */
+    @Select("SELECT * FROM fs_jst_cod_push WHERE task_status = 0 ORDER BY id ASC LIMIT #{limit}")
+    List<FsJstCodPush> selectPendingTasks(@Param("limit") int limit);
+
+
+    /**
+     * 查询待处理的数据
+     * @return List<FsJstCodPush>
+     */
+    @Select("SELECT * from fs_jst_cod_push where task_status = 0 OR (task_status = 2 AND retry_count < 3) ")
+    List<FsJstCodPush> queryPenddingData();
+    /**
+     * 插入新记录
+     */
+    @Insert("INSERT INTO fs_jst_cod_push(order_id, after_sale_id, type, task_status, params) " +
+            "VALUES(#{orderId}, #{afterSaleId}, #{type}, #{taskStatus}, #{params})")
+    @Options(useGeneratedKeys = true, keyProperty = "id")
+    int insert(FsJstCodPush record);
+
+    /**
+     * 更新任务状态
+     */
+    @Update("UPDATE fs_jst_cod_push SET task_status = #{taskStatus}, retry_count = #{retryCount}, " +
+            "last_execute_time = NOW(), result = #{result}, error_message = #{errorMessage} " +
+            "WHERE id = #{id}")
+    int updateTaskStatus(FsJstCodPush record);
+
+    /**
+     * 根据ID更新记录
+     */
+    @Update("<script>" +
+            "UPDATE fs_jst_cod_push " +
+            "<set>" +
+            "  <if test='orderId != null'>order_id = #{orderId},</if>" +
+            "  <if test='afterSaleId != null'>after_sale_id = #{afterSaleId},</if>" +
+            "  <if test='type != null'>type = #{type},</if>" +
+            "  <if test='taskStatus != null'>task_status = #{taskStatus},</if>" +
+            "  <if test='retryCount != null'>retry_count = #{retryCount},</if>" +
+            "  <if test='lastExecuteTime != null'>last_execute_time = #{lastExecuteTime},</if>" +
+            "  <if test='params != null'>params = #{params},</if>" +
+            "  <if test='result != null'>result = #{result},</if>" +
+            "  <if test='errorMessage != null'>error_message = #{errorMessage},</if>" +
+            "</set>" +
+            "WHERE id = #{id}" +
+            "</script>")
+    int updateById(FsJstCodPush record);
+}

+ 5 - 0
fs-service/src/main/java/com/fs/erp/service/FsJstAftersalePushService.java

@@ -0,0 +1,5 @@
+package com.fs.erp.service;
+
+public interface FsJstAftersalePushService {
+    void pushJst();
+}

+ 5 - 0
fs-service/src/main/java/com/fs/erp/service/FsJstCodPushService.java

@@ -0,0 +1,5 @@
+package com.fs.erp.service;
+
+public interface FsJstCodPushService {
+    public void jstCodPush();
+}

+ 3 - 0
fs-service/src/main/java/com/fs/erp/service/IErpOrderService.java

@@ -3,6 +3,7 @@ package com.fs.erp.service;
 import com.fs.erp.domain.ErpOrder;
 import com.fs.erp.domain.ErpRefundOrder;
 import com.fs.erp.dto.*;
+import com.fs.his.domain.FsStoreOrder;
 
 public interface IErpOrderService
 {
@@ -14,5 +15,7 @@ public interface IErpOrderService
     ErpOrderQueryResponse getOrder(ErpOrderQueryRequert param);
     BaseResponse refundUpdate(ErpRefundUpdateRequest param);
     ErpOrderResponse finishOrder(ErpOrder order);
+    //代服管家查物流状态
+    void getOrderDeliveryStatus(FsStoreOrder order);
 }
 

+ 104 - 10
fs-service/src/main/java/com/fs/erp/service/impl/DfOrderServiceImpl.java

@@ -15,16 +15,16 @@ import com.fs.erp.domain.ErpRefundOrder;
 import com.fs.erp.dto.*;
 import com.fs.erp.dto.df.*;
 import com.fs.erp.dto.sdk.df.DfClient;
-import com.fs.erp.dto.sdk.df.enums.ExpressProductCodeEnum;
 import com.fs.erp.dto.sdk.df.enums.RequestUrlEnum;
 import com.fs.erp.service.IErpOrderService;
-import com.fs.erp.utils.CommonUtils;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.enums.FsStoreOrderLogEnum;
 import com.fs.his.mapper.*;
+import com.fs.his.param.FsStoreOrderSalesParam;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsStoreOrderLogsService;
+import com.fs.his.service.IFsStoreOrderService;
 import com.fs.his.utils.ConfigUtil;
 import com.hc.openapi.tool.util.StringUtils;
 import lombok.extern.slf4j.Slf4j;
@@ -75,6 +75,8 @@ public class DfOrderServiceImpl implements IErpOrderService
 
     @Autowired
     private IFsExpressService expressService;
+    @Autowired
+    private IFsStoreOrderService fsStoreOrderService;
 
 
     @Override
@@ -153,7 +155,7 @@ public class DfOrderServiceImpl implements IErpOrderService
                         if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
                             dfApiResponse.setCode(mailNumber);
                             Object result = dfApiResponse.getResult();
-                            String jsonStr = JSONUtil.toJsonStr(result);
+                            String jsonStr = JSON.toJSONString(JSON.parseObject(JSONUtil.toJsonStr(result), HashMap.class).get("list"));
                             List<ErpDeliverys> dfDeliveryResponse = null;
                             try {
                                 dfDeliveryResponse = JSON.parseArray(jsonStr, ErpDeliverys.class);
@@ -205,6 +207,9 @@ public class DfOrderServiceImpl implements IErpOrderService
             if (order != null) {
                 //获取下单账户
                 FsStoreOrderDf df = fsStoreOrderDfMapper.selectFsStoreOrderDfByOrderId(order.getOrderId());
+                if(df == null){
+                    return null;
+                }
                 Integer sfAccountIndex = getSFAccountIndex(order.getOrderId());
                 if (sfAccountIndex > -1) {
                     Map<String, Object> orderResultQueryParam = new HashMap<>();
@@ -233,6 +238,68 @@ public class DfOrderServiceImpl implements IErpOrderService
         return null;
     }
 
+    @Override
+    public void getOrderDeliveryStatus(FsStoreOrder order) {
+        Map<String, Object> map = new HashMap<>();
+        Integer sfAccountIndex = getSFAccountIndex(order.getOrderId());
+        map.put("orderNumber", order.getOrderCode());
+        map.put("mailNumber", order.getDeliverySn());
+        try {
+            String response = client.execute(RequestUrlEnum.ORDER_DELIVERY_STATUS, map, sfAccountIndex);
+            DFApiResponse dfApiResponse = JSON.parseObject(response, DFApiResponse.class);
+            if ("运单不存在".equals(dfApiResponse.getMsg())){
+                //取消订单
+                FsStoreOrderSalesParam afterSalesParam = new FsStoreOrderSalesParam();
+                afterSalesParam.setOrderId(order.getOrderId());
+                afterSalesParam.setReasons("代服管家取消订单");
+                afterSalesParam.setOperator("代服管家");
+                fsStoreOrderService.afterSales(afterSalesParam);
+                FsStoreOrderDf df = new FsStoreOrderDf();
+                df.setOrderId(order.getOrderId());
+                df.setStatus(2);
+                df.setUpdateTime(new Date());
+                fsStoreOrderDfMapper.updateFsStoreOrderDf(df);
+                log.info("代服管家 订单取消成功: {}", response);
+            }
+            //3.处理请求结果
+            if (dfApiResponse != null && "ok".equals(dfApiResponse.getCode())) {
+                String jsonString = JSON.toJSONString(dfApiResponse.getResult());
+//                List<DFOrderStatusResultRequest> requestList = JSON.parseArray(jsonString, DFOrderStatusResultRequest.class);
+                DFOrderStatusResultRequest temp = JSON.parseObject(jsonString, DFOrderStatusResultRequest.class);
+//                if (requestList != null && !requestList.isEmpty()){
+                    //0待揽收 1已揽收 2运输中 3派送中 4异常件 5退回件 6退回签收 7转寄件 8作废件 9已签收 10 已取消
+//                    for (DFOrderStatusResultRequest temp : requestList) {
+                        if (temp.getStatus() == 10){
+                            //取消订单
+                            String mailNumber = temp.getMailNumber();
+                            List<FsStoreOrder> fsStoreOrders = fsStoreOrderMapper.selectFsStoreOrderListByDeliverySn(mailNumber);
+                            if (fsStoreOrders != null && !fsStoreOrders.isEmpty()){
+                                fsStoreOrders.forEach(tempOrder -> {
+                                    FsStoreOrderSalesParam afterSalesParam = new FsStoreOrderSalesParam();
+                                    afterSalesParam.setOrderId(tempOrder.getOrderId());
+                                    afterSalesParam.setReasons("代服管家取消订单");
+                                    afterSalesParam.setOperator("代服管家");
+                                    fsStoreOrderService.afterSales(afterSalesParam);
+                                    FsStoreOrderDf df = new FsStoreOrderDf();
+                                    df.setOrderId(order.getOrderId());
+                                    df.setStatus(2);
+                                    df.setUpdateTime(new Date());
+                                    fsStoreOrderDfMapper.updateFsStoreOrderDf(df);
+                                    log.info("代服管家 订单取消成功: {}", response);
+                                });
+                            }
+                        } else if (temp.getStatus() == 9){
+                            //已签收
+                            fsStoreOrderService.getGoods(order.getOrderId());
+                        }
+                    }
+//                }
+//            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
     /**
      * 获取erp推送参数
      *
@@ -266,11 +333,11 @@ public class DfOrderServiceImpl implements IErpOrderService
                 Map<String, Object> orderResultQueryParam = new HashMap<>();
                 orderResultQueryParam.put("orderNumber", order.getPlatform_code());
                 orderResultQueryParam.put("exInterfaceType", df.getStatus());
-//                try {
-//                    getOrderResult(orderResultQueryParam,sfAccountIndex);
-//                } catch (Exception e) {
-//
-//                }
+                try {
+                    getOrderResult(orderResultQueryParam,sfAccountIndex);
+                } catch (Exception e) {
+                    log.info("推送订单完成,查询订单问题{}", e.getMessage());
+                }
                 ErpOrderResponse erpOrderResponse = new ErpOrderResponse();
                 erpOrderResponse.setCode(order.getPlatform_code());
                 erpOrderResponse.setSuccess(true);
@@ -293,6 +360,7 @@ public class DfOrderServiceImpl implements IErpOrderService
         df.setAppSecret(config.getDfAppsecret());
         df.setLoginAccount(config.getLoginAccount());
         df.setMonthlyCard(config.getMonthlyCard());
+        df.setExpressProductCode(config.getExpressProductCode());
         df.setTotalPrice(fsStoreOrder.getPayMoney());
         df.setPlatformPrice(fsStoreOrder.getPayPrice());
         df.setStatus(1);
@@ -323,6 +391,7 @@ public class DfOrderServiceImpl implements IErpOrderService
         }
         String loginAccount = config.getLoginAccount();
         vo.setMonthlyCard(config.getMonthlyCard()); //月结卡号
+        vo.setExpressProductCode(config.getExpressProductCode()); //物流产品编码
 
 
         vo.setLoginAccount(loginAccount); //代服系统登录账号
@@ -345,11 +414,11 @@ public class DfOrderServiceImpl implements IErpOrderService
             orderPayMethod = 2;
             // 货到付款金额 = 物流代收金额-优惠金额
             vo.setCollectingMoney(fsStoreOrder.getPayDelivery().subtract(couponPrice).doubleValue());
+            vo.setCollectionCardNumber(config.getMonthlyCard()); // 就是月结账号
         }
         //订单付款方式 1:在线支付 2:货到付款
         //如果填了2,代收金额必须大于0,代收卡号必填
         vo.setOrderPayMethod(orderPayMethod);
-        vo.setExpressProductCode(ExpressProductCodeEnum.LAND.getValue()); //物流产品编码 默认陆运包裹
 
         vo.setConsignmentNumber(Integer.valueOf(Math.toIntExact(fsStoreOrder.getTotalNum()))); //托寄物数量 必填
 
@@ -468,7 +537,17 @@ public class DfOrderServiceImpl implements IErpOrderService
                         //下单结果
                         BspOrderResponseWrapper bspOrderResponse = JSONUtil.toBean(jsonString, BspOrderResponseWrapper.class);
                         if (bspOrderResponse != null) {
-                            setExpress(bspOrderResponse);
+                            String failMsg = bspOrderResponse.getFailMsg();
+                            if (StringUtils.isNotBlank(failMsg)) {
+                                if (failMsg.equals("暂未结果, 请稍后再查")){
+                                    return;
+                                }
+                                //下单失败 返回未推送状态
+                                String  orderNumber = bspOrderResponse.getOrderNumber();
+                                rollBackOrder(orderNumber,failMsg);
+                            } else {
+                                setExpress(bspOrderResponse);
+                            }
                         }
                     } else if ("2".equals(status)) {
                         //取消订单
@@ -491,6 +570,21 @@ public class DfOrderServiceImpl implements IErpOrderService
         }
     }
 
+    private void rollBackOrder(String orderNumber,String failMsg) {
+        FsStoreOrder fsStoreOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderCode(orderNumber);
+        FsStoreOrder tempOrder = new FsStoreOrder();
+        tempOrder.setOrderId(fsStoreOrder.getOrderId());
+        tempOrder.setExtendOrderId("");
+        fsStoreOrderMapper.updateFsStoreOrder(tempOrder);
+        FsStoreOrderDf df = new FsStoreOrderDf();
+        df.setOrderId(fsStoreOrder.getOrderId());
+        df.setStatus(0); //回到默认
+        df.setFailMsg(failMsg); //失败消息
+        df.setUpdateTime(new Date());
+        fsStoreOrderDfMapper.updateFsStoreOrderDf(df);
+        //推送失败消息
+    }
+
     /**
      * 顺丰会有自己的轨迹推送 不使用快递鸟(代服务管家设置推送地址)
      *

+ 6 - 0
fs-service/src/main/java/com/fs/erp/service/impl/ErpOrderServiceImpl.java

@@ -9,6 +9,7 @@ import com.fs.erp.dto.*;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.erp.utils.CommonUtils;
 import com.fs.his.config.FsSysConfig;
+import com.fs.his.domain.FsStoreOrder;
 import com.fs.his.utils.ConfigUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -132,4 +133,9 @@ public class ErpOrderServiceImpl implements IErpOrderService
     public ErpOrderResponse finishOrder(ErpOrder order) {
         return null;
     }
+
+    @Override
+    public void getOrderDeliveryStatus(FsStoreOrder order) {
+
+    }
 }

+ 172 - 0
fs-service/src/main/java/com/fs/erp/service/impl/FsJstAftersalePushServiceImpl.java

@@ -0,0 +1,172 @@
+package com.fs.erp.service.impl;
+
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.fs.common.utils.ExceptionUtil;
+import com.fs.erp.constant.AfterSalesOrderStatusEnum;
+import com.fs.erp.constant.TaskStatusEnum;
+import com.fs.erp.domain.FsJstAftersalePush;
+import com.fs.erp.dto.*;
+import com.fs.erp.http.JstErpHttpService;
+import com.fs.erp.mapper.FsJstAftersalePushMapper;
+import com.fs.erp.service.FsJstAftersalePushService;
+import com.fs.his.domain.FsStoreAfterSales;
+import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.domain.FsStoreOrderItem;
+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.ybPay.dto.RefundOrderDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+@Slf4j
+@Service
+public class FsJstAftersalePushServiceImpl implements FsJstAftersalePushService {
+
+    @Autowired
+    private FsJstAftersalePushMapper fsJstAftersalePushMapper;
+
+    @Autowired
+    private JstErpHttpService jstErpHttpService;
+
+    @Autowired
+    private FsStoreOrderMapper fsStoreOrderMapper;
+
+    @Autowired
+    private IFsStoreOrderItemService storeOrderItemService;
+
+    @Autowired
+    private FsStoreAfterSalesMapper fsStoreAfterSalesMapper;
+
+    @Value("${jst.shop_code:''}")
+    private String shopId;
+    @Override
+    public void pushJst() {
+        List<FsJstAftersalePush> fsJstAftersalePushes = fsJstAftersalePushMapper.queryPenddingData();
+
+        for (FsJstAftersalePush item : fsJstAftersalePushes) {
+            item.setTaskStatus(TaskStatusEnum.PROCESSING.getCode());
+            int update = fsJstAftersalePushMapper.update(item);
+            if(update <= 0){
+                log.info("获取记录{} 锁失败!",item.getId());
+                continue;
+            }
+
+            FsStoreOrder fsStoreOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderCode(item.getOrderId());
+
+            item.setRetryCount(item.getRetryCount()+1);
+
+            if(fsStoreOrder == null){
+                item.setErrorMessage("该订单未找到!");
+                item.setTaskStatus(TaskStatusEnum.FAILED.getCode());
+                log.info("该订单未找到!");
+                fsJstAftersalePushMapper.update(item);
+                continue;
+            }
+            Asserts.notNull(fsStoreOrder,"该订单未找到!");
+            RefundOrderDTO dto;
+            dto = getAfterSaleDTO(item, fsStoreOrder);
+            // 买家已经申请,等待卖家同意
+            if(StringUtils.equals(AfterSalesOrderStatusEnum.WAIT_SELLER_AGREE.getIndex().toString()
+                    ,item.getType())){
+
+            // 买家已经退货,等待卖家确认收货
+            } else if(StringUtils.equals(AfterSalesOrderStatusEnum.WAIT_SELLER_CONFIRM_GOODS.getIndex().toString(),
+                    item.getType())){
+                // 查询售后单 同步快递单号过去
+                FsStoreAfterSales fsStoreAfterSales = fsStoreAfterSalesMapper.selectFsStoreAfterSalesById(item.getId());
+//                dto.setLogisticsCompany(fsStoreAfterSales.getDeliverySn());
+                dto.setLogisticsCompany(fsStoreAfterSales.getDeliveryName());
+//                dto.setLId(fsStoreAfterSales.getDeliveryId());
+                dto.setLId(fsStoreAfterSales.getDeliverySn());
+
+            // 售后关闭
+            } else if(StringUtils.equals(AfterSalesOrderStatusEnum.CLOSED.getIndex().toString(),item.getType())) {
+
+            // 退款成功
+            } else if(StringUtils.equals(AfterSalesOrderStatusEnum.SUCCESS.getIndex().toString(),item.getType())) {
+
+            // 确认
+            }
+
+
+            if(!StringUtils.equals(AfterSalesOrderStatusEnum.CONFIRM.getIndex().toString(),item.getType())) {
+                try{
+                    CommonResponse<AfterSaleResponseDTO> response = jstErpHttpService.aftersaleUpload(dto);
+                    item.setParams(JSON.toJSONString(dto));
+                    item.setResult(JSON.toJSONString(response));
+                    item.setTaskStatus(TaskStatusEnum.SUCCESS.getCode());
+                }catch (Exception e) {
+                    item.setErrorMessage(ExceptionUtil.getExceptionMessage(e));
+                    item.setTaskStatus(TaskStatusEnum.FAILED.getCode());
+                }
+
+            // 如果是确认类型
+            } else{
+                AfterSaleConfirmRequestDTO requestDTO = new AfterSaleConfirmRequestDTO();
+
+                requestDTO.setAsIds(Collections.singletonList(Long.valueOf(item.getAfterSaleId())));
+                requestDTO.setExchangeForce(true);
+                requestDTO.setConfirmRefund(true);
+
+                try{
+                    CommonResponse<AssetProcessResultDTO> response = jstErpHttpService.aftersaleConfirm(requestDTO);
+                    item.setParams(JSON.toJSONString(dto));
+                    item.setResult(JSON.toJSONString(response));
+                    item.setTaskStatus(TaskStatusEnum.SUCCESS.getCode());
+                }catch (Exception e){
+                    item.setErrorMessage(ExceptionUtil.getExceptionMessage(e));
+                    item.setTaskStatus(TaskStatusEnum.FAILED.getCode());
+                }
+            }
+
+            fsJstAftersalePushMapper.update(item);
+        }
+    }
+
+    private RefundOrderDTO getAfterSaleDTO(FsJstAftersalePush item, FsStoreOrder fsStoreOrder) {
+        RefundOrderDTO dto = new RefundOrderDTO();
+        AfterSalesOrderStatusEnum statusEnum = AfterSalesOrderStatusEnum.getByIndex(Integer.valueOf(item.getType()));
+
+        dto.setShopStatus(statusEnum.getCode());
+        dto.setQuestionType("可更新");
+        dto.setOuterAsId(item.getAfterSaleId());
+        dto.setRemark("用户退款");
+        dto.setType("仅退款");
+
+        dto.setShopId(Long.parseLong(shopId));
+        dto.setTotalAmount(fsStoreOrder.getTotalPrice());
+        dto.setSoId(item.getOrderId());
+        dto.setRefund(fsStoreOrder.getPayMoney());
+
+
+        FsStoreOrderItem itemMap=new FsStoreOrderItem();
+//        itemMap.setOrderId(fsStoreOrder.getId());
+        itemMap.setOrderId(fsStoreOrder.getOrderId());
+        List<FsStoreOrderItem> orderItems=storeOrderItemService.selectFsStoreOrderItemList(itemMap);
+        List<RefundItemDTO> refundItemDTOS=new ArrayList<>();
+
+        for(FsStoreOrderItem orderItem: orderItems) {
+            FsStoreCartDTO cartDTO = JSONUtil.toBean(orderItem.getJsonInfo(), FsStoreCartDTO.class);
+
+            RefundItemDTO itemDTO = new RefundItemDTO();
+            itemDTO.setSkuId(cartDTO.getBarCode());
+            itemDTO.setQty(cartDTO.getNum());
+            itemDTO.setAmount(cartDTO.getPrice());
+            itemDTO.setType("退货");
+            refundItemDTOS.add(itemDTO);
+        }
+        dto.setItems(refundItemDTOS);
+        return dto;
+    }
+}

+ 53 - 0
fs-service/src/main/java/com/fs/erp/service/impl/FsJstCodPushServiceImpl.java

@@ -0,0 +1,53 @@
+package com.fs.erp.service.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fs.erp.constant.TaskStatusEnum;
+import com.fs.erp.domain.FsJstCodPush;
+import com.fs.erp.dto.ErpOrderResponseDTO;
+import com.fs.erp.dto.ShopOrderDTO;
+import com.fs.erp.http.JstErpHttpService;
+import com.fs.erp.mapper.FsJstCodPushMapper;
+import com.fs.erp.service.FsJstCodPushService;
+import com.hc.openapi.tool.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Slf4j
+@Service
+public class FsJstCodPushServiceImpl implements FsJstCodPushService {
+    @Autowired
+    private FsJstCodPushMapper fsJstCodPushMapper;
+
+    @Autowired
+    private JstErpHttpService jstErpHttpService;
+
+    @Override
+    public void jstCodPush() {
+        List<FsJstCodPush> fsJstCodPushes = fsJstCodPushMapper.queryPenddingData();
+        for (FsJstCodPush fsJstCodPush : fsJstCodPushes) {
+            fsJstCodPush.setTaskStatus(TaskStatusEnum.PROCESSING.getCode());
+            int lock = fsJstCodPushMapper.updateById(fsJstCodPush);
+            if(lock <= 0) {
+                log.info("获取当前记录锁失败! 已跳过");
+                continue;
+            }
+
+            try{
+                String params = fsJstCodPush.getParams();
+                ShopOrderDTO shopOrderDTO = JSONObject.parseObject(params, ShopOrderDTO.class);
+                ErpOrderResponseDTO upload = jstErpHttpService.upload(shopOrderDTO);
+                fsJstCodPush.setResult(JSON.toJSONString(upload));
+                fsJstCodPush.setTaskStatus(TaskStatusEnum.SUCCESS.getCode());
+
+            }catch (Exception e) {
+                fsJstCodPush.setErrorMessage(JSON.toJSONString(e));
+                fsJstCodPush.setRetryCount(fsJstCodPush.getRetryCount()+1);
+            }
+
+            fsJstCodPushMapper.updateById(fsJstCodPush);
+        }
+    }
+}

+ 5 - 0
fs-service/src/main/java/com/fs/erp/service/impl/HzOMSErpOrderServiceImpl.java

@@ -151,6 +151,11 @@ public class HzOMSErpOrderServiceImpl implements IErpOrderService {
         return null;
     }
 
+    @Override
+    public void getOrderDeliveryStatus(FsStoreOrder order) {
+
+    }
+
     /**
      * 构建瀚智创建订单参数
      *

+ 52 - 0
fs-service/src/main/java/com/fs/erp/service/impl/JSTErpGoodsServiceImpl.java

@@ -0,0 +1,52 @@
+package com.fs.erp.service.impl;
+
+import com.fs.erp.domain.ErpGoods;
+import com.fs.erp.dto.*;
+import com.fs.erp.http.JstErpHttpService;
+import com.fs.erp.service.IErpGoodsService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service("JSTErpGoodsServiceImpl")
+public class JSTErpGoodsServiceImpl implements IErpGoodsService {
+    @Autowired
+    private JstErpHttpService jstErpHttpService;
+    @Override
+    public BaseResponse addGoods(ErpGoods goods) {
+        return null;
+    }
+
+    @Override
+    public ErpGoodsQueryResponse getGoods(ErpGoodsQueryRequert param) {
+        ProductQueryRequestDTO requestDTO = new ProductQueryRequestDTO();
+        requestDTO.setSkuIds(param.getCode());
+        ProductResponseDTO productResponseDTO = jstErpHttpService.queryGoods(requestDTO);
+        List<ProductResponseDTO.ProductInfo> datas = productResponseDTO.getDatas();
+        ErpGoodsQueryResponse erpGoodsQueryResponse = new ErpGoodsQueryResponse();
+        if(CollectionUtils.isNotEmpty(datas)){
+            List<ErpGoods> erpGoodsList = new ArrayList<>();
+            for (ProductResponseDTO.ProductInfo data : datas) {
+                ErpGoods erpGoods = new ErpGoods();
+                erpGoods.setCode(data.getSkuCode());
+                erpGoods.setName(data.getName());
+                erpGoods.setSimple_name(data.getShortName());
+                erpGoods.setCategory_code(data.getCategory());
+                erpGoods.setCost_price(data.getCostPrice());
+                erpGoods.setSales_price(data.getSalePrice());
+                erpGoods.setPurchase_price(data.getMarketPrice());
+                erpGoodsList.add(erpGoods);
+            }
+            erpGoodsQueryResponse.setItems(erpGoodsList);
+        }
+        return erpGoodsQueryResponse;
+    }
+
+    @Override
+    public ErpGoodsStockQueryResponse getGoodsStock(ErpGoodsStockQueryRequert param) {
+        return null;
+    }
+}

+ 369 - 0
fs-service/src/main/java/com/fs/erp/service/impl/JSTErpOrderServiceImpl.java

@@ -0,0 +1,369 @@
+package com.fs.erp.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.erp.constant.ErpQueryOrderStatusEnum;
+import com.fs.erp.constant.OrderStatusEnum;
+import com.fs.erp.constant.TaskStatusEnum;
+import com.fs.erp.domain.*;
+import com.fs.erp.dto.*;
+import com.fs.erp.http.JstErpHttpService;
+import com.fs.erp.mapper.FsJstAftersalePushMapper;
+import com.fs.erp.mapper.FsJstCodPushMapper;
+import com.fs.erp.service.IErpOrderService;
+import com.fs.his.domain.FsStoreOrder;
+import com.fs.his.domain.FsStoreOrderItem;
+import com.fs.his.domain.FsStoreProduct;
+import com.fs.his.mapper.FsStoreAfterSalesMapper;
+import com.fs.his.service.IFsStoreOrderItemService;
+import com.fs.his.service.IFsStoreOrderService;
+import com.fs.his.service.IFsStoreProductService;
+import com.fs.his.vo.FsStoreOrderItemVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.util.Asserts;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class JSTErpOrderServiceImpl implements IErpOrderService {
+    @Autowired
+    private JstErpHttpService jstErpHttpService;
+
+    @Autowired
+    private IFsStoreOrderService fsStoreOrderService;
+
+    @Autowired
+    private FsJstAftersalePushMapper fsJstAftersalePushMapper;
+
+    @Autowired
+    private IFsStoreOrderItemService fsStoreOrderItemService;
+
+    @Autowired
+    private IFsStoreProductService fsStoreProductService;
+
+//    @Autowired
+//    private FsStoreDeliversMapper fsStoreDeliversMapper;
+
+    @Autowired
+    private FsStoreAfterSalesMapper fsStoreAfterSalesMapper;
+
+    @Autowired
+    private FsJstCodPushMapper fsJstCodPushMapper;
+
+    @Override
+    public ErpOrderResponse addOrder(ErpOrder order) {
+        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(order.getPlatform_code());
+
+        ErpOrderPayment erpOrderPayment = order.getPayments().get(0);
+
+        ShopOrderDTO shopOrderDTO = new ShopOrderDTO();
+
+        shopOrderDTO.setShopId(Long.valueOf(order.getShop_code()));
+        shopOrderDTO.setSoId(order.getPlatform_code());
+        shopOrderDTO.setOrderDate(order.getDeal_datetime());
+        // 待发货
+        shopOrderDTO.setShopStatus(OrderStatusEnum.WAIT_SELLER_SEND_GOODS.name());
+        // 买家账号
+        shopOrderDTO.setShopBuyerId(order.getBuyer_account());
+        // 收货人省份
+        shopOrderDTO.setReceiverState(order.getReceiver_province());
+        // 收货人城市
+        shopOrderDTO.setReceiverCity(order.getReceiver_city());
+        // 收货人区域
+        shopOrderDTO.setReceiverDistrict(order.getReceiver_district());
+        // 收货人详细地址
+        shopOrderDTO.setReceiverAddress(order.getReceiver_address());
+        // 收货人详细地址
+        shopOrderDTO.setReceiverName(order.getReceiver_name());
+        // 收货人电话
+        shopOrderDTO.setReceiverPhone(order.getReceiver_mobile());
+        // 支付金额
+        shopOrderDTO.setPayAmount(erpOrderPayment.getPayment());
+        // 运费 改
+//        if(ObjectUtil.isNull(fsStoreOrder.getPayPostage())) {
+//            shopOrderDTO.setFreight(Double.valueOf("0.00"));
+//        } else {
+//            shopOrderDTO.setFreight(fsStoreOrder.getPayPostage().doubleValue());
+//        }
+        if (ObjectUtil.isNull(fsStoreOrder.getPayDelivery())) {
+            shopOrderDTO.setFreight(Double.valueOf("0.00"));
+        } else {
+            shopOrderDTO.setFreight(fsStoreOrder.getPayDelivery().doubleValue());
+        }
+        // 备注
+        shopOrderDTO.setRemark(order.getBuyer_memo());
+        // 买家留言
+        shopOrderDTO.setBuyerMessage(order.getBuyer_memo());
+
+        // 订单商品项列表
+        List<OrderItemDTO> itemDTOList = new ArrayList<>();
+    // 改
+//        List<FsStoreOrderItemVO> fsStoreOrderItemVOS = fsStoreOrderItemService.selectFsStoreOrderItemListByOrderId(fsStoreOrder.getId());
+//        for (FsStoreOrderItemVO item : fsStoreOrderItemVOS) {
+//            OrderItemDTO orderItemDTO = new OrderItemDTO();
+//            JSONObject jsonObject = JSON.parseObject(item.getJsonInfo());
+//
+//            String barCode = jsonObject.getString("barCode");
+//            String productName = jsonObject.getString("productName");
+//
+//            orderItemDTO.setSkuId(barCode);
+//            orderItemDTO.setShopSkuId(barCode);
+//            orderItemDTO.setName(productName);
+//
+//            FsStoreProduct fsStoreProduct = fsStoreProductService.selectFsStoreProductById(item.getProductId());
+//
+//            orderItemDTO.setAmount(fsStoreProduct.getPrice());
+//
+//            orderItemDTO.setQty(item.getNum().intValue());
+//            orderItemDTO.setOuterOiId(String.format("%s%s",item.getOrderCode(),item.getItemId()));
+//            itemDTOList.add(orderItemDTO);
+//        }
+
+        List<FsStoreOrderItem> fsStoreOrderItemVOS = fsStoreOrderItemService.selectFsStoreOrderItemListByOrderId(fsStoreOrder.getOrderId());
+        for (FsStoreOrderItem item : fsStoreOrderItemVOS) {
+            OrderItemDTO orderItemDTO = new OrderItemDTO();
+            JSONObject jsonObject = JSON.parseObject(item.getJsonInfo());
+
+            String barCode = jsonObject.getString("barCode");
+            String productName = jsonObject.getString("productName");
+
+            orderItemDTO.setSkuId(barCode);
+            orderItemDTO.setShopSkuId(barCode);
+            orderItemDTO.setName(productName);
+
+            FsStoreProduct fsStoreProduct = fsStoreProductService.selectFsStoreProductById(item.getProductId());
+
+            orderItemDTO.setAmount(fsStoreProduct.getPrice());
+
+            orderItemDTO.setQty(item.getNum().intValue());
+            orderItemDTO.setOuterOiId(String.format("%s%s",fsStoreOrder.getOrderCode(),item.getItemId()));
+            itemDTOList.add(orderItemDTO);
+        }
+        shopOrderDTO.setItems(itemDTOList);
+
+        // 实际支付金额
+        PaymentDTO paymentDTO = new PaymentDTO();
+        paymentDTO.setAmount(fsStoreOrder.getPayMoney().doubleValue());
+        paymentDTO.setOuterPayId(order.getPlatform_code());
+        paymentDTO.setPayDate(order.getDeal_datetime());
+        paymentDTO.setPayment("微信支付");
+        paymentDTO.setBuyerAccount(order.getBuyer_account());
+        paymentDTO.setSellerAccount("平台销售");
+        shopOrderDTO.setPay(paymentDTO);
+
+
+        // 如果是货到付款
+        if("2".equals(fsStoreOrder.getPayType()) || "3".equals(fsStoreOrder.getPayType())){
+            shopOrderDTO.setIsCod(true);
+            // 货到付款金额 = 物流代收金额-优惠金额
+            shopOrderDTO.setBuyerPaidAmount(fsStoreOrder.getPayDelivery());
+            shopOrderDTO.setPayAmount(fsStoreOrder.getPayPrice().doubleValue());
+
+            // 货到付款要推两次
+            PaymentDTO paymentDTO2 = new PaymentDTO();
+            // 物流代收金额
+            paymentDTO2.setAmount(fsStoreOrder.getPayDelivery().doubleValue());
+            paymentDTO2.setOuterPayId(String.format("%s%d",order.getPlatform_code(),1));
+            paymentDTO2.setPayDate(order.getDeal_datetime());
+            paymentDTO2.setPayment("货到付款");
+            paymentDTO2.setBuyerAccount(order.getBuyer_account());
+            paymentDTO2.setSellerAccount("平台销售");
+            shopOrderDTO.setPay(paymentDTO2);
+
+            FsJstCodPush fsJstCodPush = new FsJstCodPush();
+            fsJstCodPush.setOrderId(fsStoreOrder.getOrderCode());
+            fsJstCodPush.setType("0");
+            fsJstCodPush.setParams(JSON.toJSONString(shopOrderDTO));
+            fsJstCodPush.setRetryCount(0);
+            fsJstCodPush.setTaskStatus(TaskStatusEnum.PENDING.getCode());
+            fsJstCodPushMapper.insert(fsJstCodPush);
+
+            shopOrderDTO.setPay(paymentDTO);
+        }
+
+        ErpOrderResponseDTO upload = jstErpHttpService.upload(shopOrderDTO);
+
+        if(CollectionUtils.isEmpty(upload.getDatas())) {
+            log.info("推送ERP返回结果: {}",upload);
+            throw new IllegalArgumentException("推送ERP返回数不应该为0");
+        }
+        ErpOrderResponseDTO.OrderData orderData = upload.getDatas().get(0);
+
+        ErpOrderResponse erpOrderResponse = new ErpOrderResponse();
+        erpOrderResponse.setSuccess(true);
+        erpOrderResponse.setCode(String.valueOf(orderData.getOId()));
+        return erpOrderResponse;
+    }
+
+
+
+    @Override
+    public ErpOrderResponse refundOrder(ErpRefundOrder order) {
+        return null;
+    }
+
+    @Override
+    public ErpDeliverysResponse getDeliver(ErpDeliverysRequest param) {
+        return null;
+    }
+
+    @Override
+    public ErpOrderQueryResponse getOrder(ErpOrderQueryRequert param) {
+        // 1. 构建查询请求DTO
+        OrderQueryRequestDTO requestDTO = new OrderQueryRequestDTO();
+        requestDTO.setOIds(Collections.singletonList(Long.valueOf(param.getCode())));
+
+
+        // 2. 调用ERP服务查询订单
+        OrderQueryResponseDTO query = jstErpHttpService.query(requestDTO);
+
+        // 3. 构建响应对象
+        ErpOrderQueryResponse response = new ErpOrderQueryResponse();
+
+        // 4. 设置基本响应信息
+
+        // 5. 转换订单数据
+        if (query.getOrders() != null && !query.getOrders().isEmpty()) {
+            List<ErpOrderQuery> erpOrders = query.getOrders().stream()
+                    .map(this::convertToErpOrderQuery)
+                    .collect(Collectors.toList());
+
+            response.setOrders(erpOrders);
+        } else {
+            response.setOrders(Collections.emptyList());
+        }
+
+        return response;
+    }
+
+    /**
+     * 将OrderQueryResponseDTO.Order转换为ErpOrderQuery
+     *
+     * @param order 订单数据
+     * @return ErpOrderQuery 转换后的订单数据
+     */
+    private ErpOrderQuery convertToErpOrderQuery(OrderQueryResponseDTO.Order order) {
+        ErpOrderQuery erpOrder = new ErpOrderQuery();
+
+        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(order.getSoId());
+        Asserts.notNull(fsStoreOrder,"该订单号没有找到!");
+
+        // 设置基本订单信息
+        erpOrder.setCode(order.getSoId());
+
+        // 计算订单总数量
+        if (order.getItems() != null && !order.getItems().isEmpty()) {
+            int totalQty = order.getItems().stream()
+                    .mapToInt(OrderQueryResponseDTO.OrderItem::getQty)
+                    .sum();
+            erpOrder.setQty(totalQty);
+        }
+
+        // 设置金额相关信息
+        erpOrder.setAmount(order.getAmount() != null ? order.getAmount().doubleValue() : null);
+        erpOrder.setPayment(order.getPaidAmount() != null ? order.getPaidAmount().doubleValue() : null);
+
+        // 设置其他订单属性
+        erpOrder.setCod(order.getIsCod());
+        erpOrder.setPlatform_code(order.getOrderFrom());
+
+        // 尝试解析创建时间
+        try {
+            if (order.getCreated() != null) {
+                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                erpOrder.setCreatetime(formatter.parse(order.getCreated()));
+            }
+        } catch (Exception e) {
+            // 日期解析异常处理
+            // 可以记录日志或保持为null
+        }
+
+        // 设置店铺信息
+        erpOrder.setShop_name(order.getShopName());
+        erpOrder.setShop_code(String.valueOf(order.getShopId()));
+
+        // 设置物流信息
+        erpOrder.setExpress_name(order.getLogisticsCompany());
+        erpOrder.setExpress_code(order.getLId());
+
+        // 设置收件人信息
+//        erpOrder.setReceiver_name(fsStoreOrder.getRealName());
+        erpOrder.setReceiver_name(fsStoreOrder.getUserName());
+        erpOrder.setReceiver_phone(fsStoreOrder.getUserPhone());
+        erpOrder.setReceiver_mobile(fsStoreOrder.getUserPhone());
+
+        // 构建完整地址
+        erpOrder.setReceiver_address(fsStoreOrder.getUserAddress());
+
+        // 如果是已发货
+        if(ObjectUtil.equal(order.getStatus(), ErpQueryOrderStatusEnum.SENT.getCode())){
+            List<ErpDeliverys> deliverysList = new ArrayList<>();
+
+            ErpDeliverys delivery = new ErpDeliverys();
+            delivery.setMail_no(order.getLId());
+            delivery.setExpress_code(order.getLcId());
+            delivery.setExpress_name(order.getLogisticsCompany());
+            delivery.setDelivery(true);
+            delivery.setCode(order.getSoId());
+
+            deliverysList.add(delivery);
+            erpOrder.setDeliverys(deliverysList);
+
+            // 设置发货状态,假设有物流单号就是已发货状态
+            erpOrder.setDelivery_state(1);
+        } else {
+            erpOrder.setDelivery_state(0);
+        }
+
+        return erpOrder;
+    }
+
+
+    @Override
+    public BaseResponse refundUpdate(ErpRefundUpdateRequest param) {
+
+        FsStoreOrder fsStoreOrder = fsStoreOrderService.selectFsStoreOrderByOrderCode(param.getTid());
+        //todo 待合并
+//        FsStoreDelivers byOrderCode = fsStoreDeliversMapper.findByOrderCode(fsStoreOrder.getOrderCode());
+        //todo
+        // 发货后退款
+//        if(ObjectUtil.isNotNull(byOrderCode)){
+
+//        } else {
+            // 如果是发货前退款,直接走取消订单流程
+            // 如果是发货后退款,走售后流程
+            OrderCancelRequestDTO requestDTO = new OrderCancelRequestDTO();
+            requestDTO.setOIds(Collections.singletonList(Integer.valueOf(fsStoreOrder.getExtendOrderId())));
+            requestDTO.setCancelType("用户退款");
+            requestDTO.setRemark("用户退款");
+
+            jstErpHttpService.cancel(requestDTO);
+//        }
+
+
+        BaseResponse baseResponse = new BaseResponse();
+        baseResponse.setSuccess(true);
+
+        return baseResponse;
+    }
+
+    @Override
+    public ErpOrderResponse finishOrder(ErpOrder order) {
+        return null;
+    }
+
+    @Override
+    public void getOrderDeliveryStatus(FsStoreOrder order) {
+
+    }
+}
+

+ 193 - 0
fs-service/src/main/java/com/fs/erp/service/impl/JstTokenService.java

@@ -0,0 +1,193 @@
+package com.fs.erp.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.fs.erp.dto.GetInitTokenRequestDTO;
+import com.fs.erp.dto.GetInitTokenResponseDTO;
+import com.fs.erp.dto.RefreshTokenRequestDTO;
+import com.fs.erp.http.JstErpHttpService;
+import com.fs.erp.utils.SignUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class JstTokenService {
+    private static final Logger log = LoggerFactory.getLogger(JstTokenService.class);
+
+    private static final String JST_TOKEN_KEY = "jst:access_token";
+    private static final String JST_REFRESH_TOKEN_KEY = "jst:refresh_token";
+    private static final String JST_TOKEN_EXPIRE_KEY = "jst:token_expire";
+
+    @Value("${jst.app_key:''}")
+    private String appKey;
+
+    @Value("${jst.app_secret:''}")
+    private String appSecret;
+
+    @Value("${jst.authorization_code:''}")
+    private String authorizationCode;
+
+    @Autowired
+    private JstErpHttpService httpService;
+
+    @Autowired
+    private StringRedisTemplate redisTemplate;
+
+    /**
+     * 获取访问令牌,如果缓存中存在有效令牌则直接返回,否则重新获取
+     * @return 有效的访问令牌
+     */
+    public String getAccessToken() {
+        String accessToken = redisTemplate.opsForValue().get(JST_TOKEN_KEY);
+
+        if (accessToken != null && !accessToken.isEmpty()) {
+            log.debug("从缓存中获取到有效的access_token");
+            return accessToken;
+        }
+
+        log.info("缓存中没有有效的access_token,重新获取");
+        return refreshAccessToken();
+    }
+
+    /**
+     * 强制刷新访问令牌
+     * @return 新的访问令牌
+     */
+    public String refreshAccessToken() {
+        // 检查是否有刷新令牌
+        String refreshToken = redisTemplate.opsForValue().get(JST_REFRESH_TOKEN_KEY);
+
+        if (refreshToken != null && !refreshToken.isEmpty()) {
+            log.info("使用refresh_token刷新令牌");
+            try {
+                return refreshTokenWithApi(refreshToken);
+            } catch (Exception e) {
+                log.error("使用refresh_token刷新失败,尝试重新初始化", e);
+            }
+        }
+
+        // 如果没有刷新令牌或刷新失败,则重新初始化
+        return initToken();
+    }
+
+    /**
+     * 初始化令牌
+     * @return 新的访问令牌
+     */
+    private String initToken() {
+        GetInitTokenRequestDTO requestDTO = new GetInitTokenRequestDTO();
+        requestDTO.setApp_key(appKey);
+        requestDTO.setGrant_type("authorization_code");
+        requestDTO.setCharset("utf-8");
+        requestDTO.setCode(authorizationCode);
+        requestDTO.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000));
+
+        // 计算签名
+        requestDTO.setSign(SignUtil.getSignNew(appSecret, requestDTO));
+
+        log.info("初始化token请求参数: {}", JSON.toJSONString(requestDTO));
+
+        GetInitTokenResponseDTO response = httpService.getInitToken(requestDTO);
+        if (response == null || response.getAccess_token() == null) {
+            throw new RuntimeException("初始化token失败: " + (response != null ? JSON.toJSONString(response) : "响应为空"));
+        }
+
+        // 缓存token信息
+        storeTokenInfo(response);
+
+        log.info("初始化token成功,token将在{}秒后过期", response.getExpires_in());
+        return response.getAccess_token();
+    }
+
+    /**
+     * 使用刷新令牌API刷新令牌
+     * @param refreshToken 刷新令牌
+     * @return 新的访问令牌
+     */
+    private String refreshTokenWithApi(String refreshToken) {
+        RefreshTokenRequestDTO requestDTO = new RefreshTokenRequestDTO();
+        requestDTO.setApp_key(appKey);
+        requestDTO.setGrant_type("refresh_token");
+        requestDTO.setCharset("utf-8");
+        requestDTO.setRefresh_token(refreshToken);
+        requestDTO.setTimestamp(String.valueOf(System.currentTimeMillis() / 1000));
+
+        // 计算签名
+        requestDTO.setSign(SignUtil.getSignNew(appSecret, requestDTO));
+
+        log.info("刷新token请求参数: {}", JSON.toJSONString(requestDTO));
+
+        GetInitTokenResponseDTO response = httpService.refreshToken(requestDTO);
+        if (response == null || response.getAccess_token() == null) {
+            throw new RuntimeException("刷新token失败: " + (response != null ? JSON.toJSONString(response) : "响应为空"));
+        }
+
+        // 缓存token信息
+        storeTokenInfo(response);
+
+        log.info("刷新token成功,token将在{}秒后过期", response.getExpires_in());
+        return response.getAccess_token();
+    }
+
+    /**
+     * 将令牌信息存储到Redis
+     * @param tokenInfo 令牌信息
+     */
+    private void storeTokenInfo(GetInitTokenResponseDTO tokenInfo) {
+        // 默认30天过期时间,转换为秒
+        long expiresIn = tokenInfo.getExpires_in() != null ?
+                          Long.parseLong(String.valueOf(tokenInfo.getExpires_in())) : 30 * 24 * 60 * 60;
+
+        // 存储令牌,设置比官方少一天的过期时间,以确保安全
+        redisTemplate.opsForValue().set(JST_TOKEN_KEY, tokenInfo.getAccess_token(), expiresIn - 86400, TimeUnit.SECONDS);
+
+        // 存储刷新令牌,有效期与访问令牌相同
+        if (tokenInfo.getRefresh_token() != null) {
+            redisTemplate.opsForValue().set(JST_REFRESH_TOKEN_KEY, tokenInfo.getRefresh_token(), expiresIn, TimeUnit.SECONDS);
+        }
+
+        // 存储过期时间戳
+        long expireAt = System.currentTimeMillis() + (expiresIn * 1000);
+        redisTemplate.opsForValue().set(JST_TOKEN_EXPIRE_KEY, String.valueOf(expireAt), expiresIn, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 定时任务,每20天刷新一次令牌
+     * 根据文档说明,刷新token必须在有效期小于15天时进行,所以这里设置20天刷新一次
+     */
+//    @Scheduled(fixedRate = 20 * 24 * 60 * 60 * 1000)
+    public void scheduleTokenRefresh() {
+        log.info("定时任务:刷新聚水潭API令牌");
+        try {
+            refreshAccessToken();
+        } catch (Exception e) {
+            log.error("定时刷新令牌失败", e);
+        }
+    }
+
+    /**
+     * 启动时初始化令牌
+     */
+//    @PostConstruct
+    public void init() {
+        try {
+            // 检查Redis中是否已有有效token
+            String accessToken = redisTemplate.opsForValue().get(JST_TOKEN_KEY);
+            if (accessToken == null || accessToken.isEmpty()) {
+                log.info("系统启动,初始化聚水潭API令牌");
+                initToken();
+            } else {
+                log.info("系统启动,发现缓存中已有有效的聚水潭API令牌");
+            }
+        } catch (Exception e) {
+            log.error("初始化聚水潭API令牌失败", e);
+        }
+    }
+}

+ 5 - 0
fs-service/src/main/java/com/fs/erp/service/impl/WdtErpOrderServiceImpl.java

@@ -883,6 +883,11 @@ public class WdtErpOrderServiceImpl implements IErpOrderService {
         return new ErpOrderResponse();
     }
 
+    @Override
+    public void getOrderDeliveryStatus(FsStoreOrder order) {
+
+    }
+
     public static String convertToSnakeCase(Object obj) {
         SerializeConfig config = new SerializeConfig();
         config.propertyNamingStrategy = PropertyNamingStrategy.SnakeCase;

+ 149 - 0
fs-service/src/main/java/com/fs/erp/utils/SignUtil.java

@@ -0,0 +1,149 @@
+package com.fs.erp.utils;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.fs.common.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.UnsupportedEncodingException;
+import java.security.MessageDigest;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+@Slf4j
+public class SignUtil {
+    private SignUtil() {}
+
+    /**
+     * 获取签名 - 支持Map<String, Object>类型参数
+     *
+     * @param app_secret 密钥
+     * @param params 参数Map,支持Object类型值
+     * @return 签名字符串
+     */
+    public static String getSignNew(String app_secret, Map<String, Object> params) {
+        try {
+            String sortedStr = getSortedParamStrNew(params);
+            String paraStr = app_secret + sortedStr;
+
+            log.info("paraStr: {}",paraStr);
+            return createSign(paraStr);
+        } catch (UnsupportedEncodingException e) {
+            log.warn("getSign UnsupportedEncodingException ", e);
+        }
+
+        return StringUtils.EMPTY;
+    }
+
+    public static String getSignNew(String app_secret, Object obj) {
+        try {
+            String sortedStr = getSortedParamStrNew(BeanUtil.beanToMap(obj));
+            String paraStr = app_secret + sortedStr;
+
+            return createSign(paraStr);
+        } catch (UnsupportedEncodingException e) {
+            log.warn("getSign UnsupportedEncodingException ", e);
+        }
+
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 构造自然排序请求参数 - 支持Map<String, Object>类型参数
+     *
+     * @param params 请求参数
+     * @return 排序后的字符串
+     */
+    private static String getSortedParamStrNew(Map<String, Object> params) throws UnsupportedEncodingException {
+        Set<String> sortedParams = new TreeSet<>(params.keySet());
+
+        StringBuilder strB = new StringBuilder();
+        // 排除sign和空值参数
+        for (String key : sortedParams) {
+            if ("sign".equalsIgnoreCase(key)) {
+                continue;
+            }
+
+            Object valueObj = params.get(key);
+
+            // 处理Object类型值,转换为字符串
+            String value = valueObj != null ? valueObj.toString() : null;
+
+            if (StringUtils.isNotEmpty(value)) {
+                strB.append(key).append(value);
+            }
+        }
+        return strB.toString();
+    }
+
+    /**
+     * 生成新sign
+     *
+     * @param str 字符串
+     * @return String
+     */
+    private static String createSign(String str) {
+        if (str == null || str.length() == 0) {
+            return null;
+        }
+        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+        try {
+            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
+            mdTemp.update(str.getBytes("UTF-8"));
+
+            byte[] md = mdTemp.digest();
+            int j = md.length;
+            char[] buf = new char[j * 2];
+            int k = 0;
+            int i = 0;
+            while (i < j) {
+                byte byte0 = md[i];
+                buf[k++] = hexDigits[byte0 >>> 4 & 0xf];
+                buf[k++] = hexDigits[byte0 & 0xf];
+                i++;
+            }
+            return new String(buf);
+        } catch (Exception e) {
+            log.warn("create sign was failed", e);
+            return null;
+        }
+    }
+
+    /**
+     * 原有方法保留,保持向后兼容
+     */
+    public static String getSign(String app_secret, Map<String, String> params) {
+        try {
+            String sortedStr = getSortedParamStr(params);
+            String paraStr = app_secret + sortedStr;
+
+            return createSign(paraStr);
+        } catch (UnsupportedEncodingException e) {
+            log.warn("getSign UnsupportedEncodingException ", e);
+        }
+
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 原有方法保留,保持向后兼容
+     */
+    private static String getSortedParamStr(Map<String, String> params) throws UnsupportedEncodingException {
+        Set<String> sortedParams = new TreeSet<>(params.keySet());
+
+        StringBuilder strB = new StringBuilder();
+        // 排除sign和空值参数
+        for (String key : sortedParams) {
+            if ("sign".equalsIgnoreCase(key)) {
+                continue;
+            }
+
+            String value = params.get(key);
+
+            if (StringUtils.isNotEmpty(value)) {
+                strB.append(key).append(value);
+            }
+        }
+        return strB.toString();
+    }
+}

+ 7 - 2
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiHookServiceImpl.java

@@ -3,8 +3,10 @@ package com.fs.fastGpt.service.impl;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Excel;
+import com.fs.common.config.FSConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.config.ai.AiHostProper;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
@@ -123,6 +125,9 @@ public class AiHookServiceImpl implements AiHookService {
     @Autowired
     WxWorkService wxWorkService;
 
+    @Autowired
+    AiHostProper aiHostProper;
+
 //    @Autowired
 //    private IFastGptKeywordSendService fastGptKeywordSendService;
 
@@ -406,7 +411,7 @@ public class AiHookServiceImpl implements AiHookService {
             //存聊天记录
             addSaveAiMsg(2,2,contentKh,user,fastGptChatSession.getSessionId(),role.getRoleId(),qwExternalContacts,fastGptChatSession.getUserId(),result.getUsage().prompt_tokens,result.getUsage().completion_tokens,token);
             Integer replyOne = redisCache.getCacheObject("reply:" + fastGptChatSession.getSessionId());
-            if (replyOne == 1){
+            if (replyOne!=null && replyOne == 1){
                 QwUser qwUser = qwUserService.selectQwUserById(fastGptChatSession.getQwUserId());
                 if (ObjectUtils.isNotEmpty(qwUser)&&ObjectUtils.isNotEmpty(qwUser.getIpadStatus())&&qwUser.getIpadStatus() == 1){
                     addQwAutoTags(qwUser,qwExternalContacts.getUserId(),qwExternalContacts.getExternalUserId());
@@ -988,7 +993,7 @@ public class AiHookServiceImpl implements AiHookService {
             String msgC = (String)redisCache.getCacheObject("msg:" + fastGptChatSession.getSessionId());
             //添加关键词
             addPromptWord(messageList,msgC,qwExternalContactsId,role.getReminderWords(), role.getContactInfo(),fastGptChatSession.getSessionId());
-            R r = chatService.initiatingTakeChat(param,"http://154.8.194.176:3000/api",appKey);
+            R r = chatService.initiatingTakeChat(param, aiHostProper.getAiApi(), appKey);
             Integer reply2 = (Integer)redisCache.getCacheObject("reply:" + fastGptChatSession.getSessionId());
             //次数变动 重新等待5秒
             if (reply2!=i){

+ 5 - 1
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiNewServiceImpl.java

@@ -3,8 +3,10 @@ package com.fs.fastGpt.service.impl;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Excel;
+import com.fs.common.config.FSConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.config.ai.AiHostProper;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
@@ -102,6 +104,8 @@ public class AiNewServiceImpl implements AiNewService {
     private FastGptChatReplaceWordsMapper fastGptChatReplaceWordsMapper;
     @Autowired
     RedisTemplate<String, String> redisTemplate;
+    @Autowired
+    private AiHostProper aiHostProper;
 
 
     /** Ai半小时未回复提醒 **/
@@ -623,7 +627,7 @@ public class AiNewServiceImpl implements AiNewService {
             String msgC = (String)redisCache.getCacheObject("msg:" + fastGptChatSession.getSessionId());
             //添加关键词
             addPromptWord(messageList,msgC,qwExternalContactsId,role.getReminderWords(), role.getContactInfo(),fastGptChatSession.getSessionId());
-            R r = chatService.initiatingTakeChat(param,"http://154.8.194.176:3000/api",appKey);
+            R r = chatService.initiatingTakeChat(param, aiHostProper.getAiApi(),appKey);
             Integer reply2 = (Integer)redisCache.getCacheObject("reply:" + fastGptChatSession.getSessionId());
             //次数变动 重新等待5秒
             if (reply2!=i){

+ 6 - 1
fs-service/src/main/java/com/fs/fastGpt/service/impl/AiServiceImpl.java

@@ -3,8 +3,10 @@ package com.fs.fastGpt.service.impl;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.annotation.Excel;
+import com.fs.common.config.FSConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.config.ai.AiHostProper;
 import com.fs.course.domain.FsUserCourseVideo;
 import com.fs.course.mapper.FsCourseWatchLogMapper;
 import com.fs.course.mapper.FsUserCourseVideoMapper;
@@ -97,6 +99,9 @@ public class AiServiceImpl implements AiService {
     @Autowired
     RedisTemplate<String, String> redisTemplate;
 
+    @Autowired
+    AiHostProper aiHostProper;
+
 
     /** Ai半小时未回复提醒 **/
     @Override
@@ -600,7 +605,7 @@ public class AiServiceImpl implements AiService {
             String msgC = (String)redisCache.getCacheObject("msg:" + fastGptChatSession.getSessionId());
             //添加关键词
             addPromptWord(messageList,msgC,qwExternalContactsId,role.getReminderWords(), role.getContactInfo(),fastGptChatSession.getSessionId());
-            R r = chatService.initiatingTakeChat(param,"http://154.8.194.176:3000/api",appKey);
+            R r = chatService.initiatingTakeChat(param, aiHostProper.getAiApi(),appKey);
             Integer reply2 = (Integer)redisCache.getCacheObject("reply:" + fastGptChatSession.getSessionId());
             //次数变动 重新等待5秒
             if (reply2!=i){

+ 7 - 0
fs-service/src/main/java/com/fs/his/config/FsSysConfig.java

@@ -38,6 +38,13 @@ public class FsSysConfig {
     String erpHzOMSItenantid;
     String erpHzOMTokenUrl;
     String erpHzOMBaseUrl;
+    //erp 聚水潭
+    String erpJstAppKey;
+    String erpJstAppsecret;
+    String erpJstSid;
+    String erpJstShopCode;
+    String erpJstBaseUrl;
+    String erpJstrehouseCode;
     //非erp 代服管家(多个账号) List<DFConfigVo>
     String dfAccounts;
 

+ 10 - 0
fs-service/src/main/java/com/fs/his/domain/FsIntegralOrder.java

@@ -47,6 +47,12 @@ public class FsIntegralOrder extends BaseEntity
     @Excel(name = "商品信息")
     private String itemJson;
 
+    @Excel(name = "商品名称")
+    private String goodsName;
+
+    @Excel(name = "原价")
+    private BigDecimal otPrice;
+
     /** 支付积分 */
     @Excel(name = "支付积分")
     private String integral;
@@ -89,6 +95,7 @@ public class FsIntegralOrder extends BaseEntity
     @Excel(name = "发货时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
     private Date deliveryTime;
 
+
     /**
      * 企业微信ID
      * **/
@@ -106,4 +113,7 @@ public class FsIntegralOrder extends BaseEntity
      * **/
     @Excel(name = "销售公司ID")
     private Long companyId;
+
+
+
 }

+ 7 - 0
fs-service/src/main/java/com/fs/his/domain/FsStoreOrderDf.java

@@ -38,6 +38,10 @@ public class FsStoreOrderDf extends BaseEntity{
     @Excel(name = "顺丰月结账户")
     private String monthlyCard;
 
+    /** 顺丰月结账户 */
+    @Excel(name = "顺丰月结账户")
+    private String expressProductCode;
+
     /** 订单总价 */
     @Excel(name = "订单总价")
     private BigDecimal totalPrice;
@@ -50,5 +54,8 @@ public class FsStoreOrderDf extends BaseEntity{
     @Excel(name = "0:默认 1下单 2取消订单")
     private Integer status;
 
+    /** 失败原因 */
+    private String failMsg;
+
 
 }

+ 6 - 1
fs-service/src/main/java/com/fs/his/mapper/FsStoreOrderMapper.java

@@ -1082,7 +1082,7 @@ public interface FsStoreOrderMapper
             "</script>"})
     Integer selectFsStoreOrderCountByType(@Param("companyId") Long companyId,@Param("userId") long userId, @Param("type")int type);
 
-    @Select("select * from fs_store_order where  `status`=2 and extend_order_id is not null ")
+    @Select("select * from fs_store_order where  `status`=2 and extend_order_id is not null and extend_order_id != '' ")
     List<FsStoreOrder> selectWdtOmsOrderdeliveryOp();
 
     int batchUpdateErpByOrderIds(@Param("maps") List<Map<String, String>> maps);
@@ -1094,4 +1094,9 @@ public interface FsStoreOrderMapper
     int updateStoreOrderDeliveryInfo(@Param("order") FsStoreOrder order);
     @Update("UPDATE fs_store_order SET delivery_code = #{deliveryCode} WHERE extend_order_id = #{extendOrderId}")
     int updateFsStoreOrderByExtendOrderId(@Param("extendOrderId")String extendOrderId,@Param("deliveryCode")String deliveryCode);
+
+    @Select("select * from fs_store_order where  `status`=3 and extend_order_id is not null and delivery_sn is not null")
+    List<FsStoreOrder> selectShippedOrder();
+
+    List<FsStoreOrderListVO> selectFsStoreOrderListVOByErpAccount(@Param("maps") FsStoreOrderParam fsStoreOrder);
 }

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません