Pārlūkot izejas kodu

多小程序支付

wangxy 1 mēnesi atpakaļ
vecāks
revīzija
780edd7392
78 mainītis faili ar 5458 papildinājumiem un 598 dzēšanām
  1. 24 0
      fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java
  2. 27 0
      fs-admin/src/main/java/com/fs/his/controller/FsStorePaymentController.java
  3. 107 0
      fs-admin/src/main/java/com/fs/his/controller/MerchantAppConfigController.java
  4. 65 13
      fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java
  5. 66 0
      fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java
  6. 14 0
      fs-service/src/main/java/com/fs/course/domain/FsCoursePlaySourceConfig.java
  7. 2 0
      fs-service/src/main/java/com/fs/course/mapper/FsCoursePlaySourceConfigMapper.java
  8. 12 0
      fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java
  9. 7 0
      fs-service/src/main/java/com/fs/course/service/IFsCoursePlaySourceConfigService.java
  10. 5 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCoursePlaySourceConfigServiceImpl.java
  11. 53 21
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java
  12. 42 18
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java
  13. 47 22
      fs-service/src/main/java/com/fs/course/service/impl/FsUserVipOrderServiceImpl.java
  14. 6 0
      fs-service/src/main/java/com/fs/course/vo/FsCoursePlaySourceConfigVO.java
  15. 7 0
      fs-service/src/main/java/com/fs/his/domain/FsPayConfig.java
  16. 28 0
      fs-service/src/main/java/com/fs/his/domain/FsQuestionAndAnswer.java
  17. 1 0
      fs-service/src/main/java/com/fs/his/domain/FsStoreOrder.java
  18. 9 0
      fs-service/src/main/java/com/fs/his/domain/FsStorePayment.java
  19. 5 0
      fs-service/src/main/java/com/fs/his/domain/FsStorePaymentError.java
  20. 114 0
      fs-service/src/main/java/com/fs/his/domain/FsUserInformationCollection.java
  21. 66 0
      fs-service/src/main/java/com/fs/his/domain/MerchantAppConfig.java
  22. 103 0
      fs-service/src/main/java/com/fs/his/dto/FsUserInformationCollectionDTO.java
  23. 67 0
      fs-service/src/main/java/com/fs/his/mapper/FsQuestionAndAnswerMapper.java
  24. 105 0
      fs-service/src/main/java/com/fs/his/mapper/FsUserInformationCollectionMapper.java
  25. 74 0
      fs-service/src/main/java/com/fs/his/mapper/MerchantAppConfigMapper.java
  26. 18 0
      fs-service/src/main/java/com/fs/his/param/CollectionInfoConfirmParam.java
  27. 1 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderRefundParam.java
  28. 1 0
      fs-service/src/main/java/com/fs/his/param/FsInquiryOrderCancelParam.java
  29. 1 0
      fs-service/src/main/java/com/fs/his/param/FsInquiryOrderRefundParam.java
  30. 2 0
      fs-service/src/main/java/com/fs/his/param/FsPackageOrderCreateParam.java
  31. 16 0
      fs-service/src/main/java/com/fs/his/param/FsUserInformationCollectionListDParam.java
  32. 56 0
      fs-service/src/main/java/com/fs/his/param/FsUserInformationCollectionParam.java
  33. 5 0
      fs-service/src/main/java/com/fs/his/param/PayOrderParam.java
  34. 16 0
      fs-service/src/main/java/com/fs/his/param/UserInformationDoctorType2Param.java
  35. 66 0
      fs-service/src/main/java/com/fs/his/service/IFsQuestionAndAnswerService.java
  36. 9 0
      fs-service/src/main/java/com/fs/his/service/IFsStorePaymentErrorService.java
  37. 117 0
      fs-service/src/main/java/com/fs/his/service/IFsUserInformationCollectionService.java
  38. 61 0
      fs-service/src/main/java/com/fs/his/service/IMerchantAppConfigService.java
  39. 35 6
      fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java
  40. 120 35
      fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java
  41. 113 0
      fs-service/src/main/java/com/fs/his/service/impl/FsQuestionAndAnswerServiceImpl.java
  42. 22 5
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreAfterSalesServiceImpl.java
  43. 82 65
      fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java
  44. 21 0
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentErrorServiceImpl.java
  45. 133 46
      fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java
  46. 1094 0
      fs-service/src/main/java/com/fs/his/service/impl/FsUserInformationCollectionServiceImpl.java
  47. 200 0
      fs-service/src/main/java/com/fs/his/service/impl/MerchantAppConfigServiceImpl.java
  48. 32 0
      fs-service/src/main/java/com/fs/his/vo/AnswerVO.java
  49. 15 0
      fs-service/src/main/java/com/fs/his/vo/FsQuestionAndAnswerVO.java
  50. 12 0
      fs-service/src/main/java/com/fs/his/vo/FsUserInfoCollectionAndStoreOrderVo.java
  51. 79 0
      fs-service/src/main/java/com/fs/his/vo/FsUserInfoCollectionUVO.java
  52. 22 0
      fs-service/src/main/java/com/fs/his/vo/FsUserInformationCollectionAndPatientVO.java
  53. 23 0
      fs-service/src/main/java/com/fs/his/vo/FsUserInformationCollectionListDVO.java
  54. 47 0
      fs-service/src/main/java/com/fs/his/vo/FsUserInformationCollectionVO.java
  55. 2 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsPayConfigScrm.java
  56. 3 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStorePaymentScrm.java
  57. 45 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductPurchaseLimitScrm.java
  58. 34 0
      fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductScrm.java
  59. 73 0
      fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductPurchaseLimitScrmMapper.java
  60. 4 0
      fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderOtherPayParam.java
  61. 92 0
      fs-service/src/main/java/com/fs/hisStore/service/IFsStoreProductPurchaseLimitScrmService.java
  62. 47 10
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java
  63. 117 36
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java
  64. 128 35
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java
  65. 242 0
      fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductPurchaseLimitScrmServiceImpl.java
  66. 24 17
      fs-service/src/main/java/com/fs/huifuPay/sdk/opps/core/utils/HuiFuUtils.java
  67. 40 30
      fs-service/src/main/java/com/fs/huifuPay/service/impl/HuiFuServiceImpl.java
  68. 2 0
      fs-service/src/main/java/com/fs/live/domain/LiveOrderPayment.java
  69. 194 115
      fs-service/src/main/java/com/fs/live/service/impl/LiveAfterSalesServiceImpl.java
  70. 207 56
      fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java
  71. 22 3
      fs-service/src/main/java/com/fs/ybPay/service/impl/PayServiceImpl.java
  72. 125 0
      fs-service/src/main/resources/mapper/MerchantAppConfigMapper.xml
  73. 8 0
      fs-service/src/main/resources/mapper/course/FsCoursePlaySourceConfigMapper.xml
  74. 70 0
      fs-service/src/main/resources/mapper/his/FsQuestionAndAnswerMapper.xml
  75. 81 0
      fs-service/src/main/resources/mapper/hisStore/FsStoreProductPurchaseLimitScrmMapper.xml
  76. 2 0
      fs-service/src/main/resources/mapper/live/LiveOrderPaymentMapper.xml
  77. 48 22
      fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java
  78. 373 43
      fs-user-app/src/main/java/com/fs/app/controller/live/LiveOrderController.java

+ 24 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCoursePlaySourceConfigController.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.annotation.Log;
 import com.fs.common.core.controller.BaseController;
@@ -134,6 +135,29 @@ public class FsCoursePlaySourceConfigController extends BaseController {
         return AjaxResult.success();
     }
 
+    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:bind')")
+    @Log(title = "绑定支付配置", businessType = BusinessType.UPDATE)
+    @PutMapping("/updateBindConfig")
+    public AjaxResult updateBindConfig(@RequestBody FsCoursePlaySourceConfigEditParam param) {
+
+        FsCoursePlaySourceConfig update =new FsCoursePlaySourceConfig();
+        update.setId(param.getId());
+        update.setMerchantConfigId(param.getMerchantConfigId());
+        fsCoursePlaySourceConfigService.updateById(update);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('course:playSourceConfig:unbind')")
+    @Log(title = "解绑支付配置", businessType = BusinessType.UPDATE)
+    @PutMapping("/updateUnbindConfig")
+    public AjaxResult updateUnbindConfig(@RequestBody FsCoursePlaySourceConfigEditParam param) {
+        LambdaUpdateWrapper<FsCoursePlaySourceConfig> updateWrapper = Wrappers.lambdaUpdate();
+        updateWrapper.eq(FsCoursePlaySourceConfig::getId, param.getId())
+                .set(FsCoursePlaySourceConfig::getMerchantConfigId, null);
+        fsCoursePlaySourceConfigService.update(updateWrapper);
+        return AjaxResult.success();
+    }
+
     @PreAuthorize("@ss.hasPermi('course:playSourceConfig:remove')")
     @Log(title = "点播播放源配置", businessType = BusinessType.DELETE)
     @DeleteMapping("/{ids}")

+ 27 - 0
fs-admin/src/main/java/com/fs/his/controller/FsStorePaymentController.java

@@ -6,9 +6,13 @@ import java.util.List;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.SecurityUtils;
 import com.fs.his.domain.FsExportTask;
+import com.fs.his.domain.FsPackageOrder;
+import com.fs.his.domain.FsStorePaymentError;
 import com.fs.his.mapper.FsPrescribeMapper;
 import com.fs.his.param.FsStorePaymentParam;
 import com.fs.his.service.IFsExportTaskService;
+import com.fs.his.service.IFsPackageOrderService;
+import com.fs.his.service.IFsStorePaymentErrorService;
 import com.fs.his.vo.FsStorePaymentExcelVO;
 import com.fs.his.vo.FsStorePaymentVO;
 import lombok.extern.slf4j.Slf4j;
@@ -47,8 +51,14 @@ public class FsStorePaymentController extends BaseController
     @Autowired
     FsPrescribeMapper fsPrescribeMapper;
 
+    @Autowired
+    private IFsStorePaymentErrorService fsStorePaymentErrorService;
+
     @Autowired
     private IFsExportTaskService exportTaskService;
+    @Autowired
+    private IFsPackageOrderService fsPackageOrderService;
+
     /**
      * 查询支付明细列表
      */
@@ -169,4 +179,21 @@ public class FsStorePaymentController extends BaseController
     {
         return toAjax(fsStorePaymentService.deleteFsStorePaymentByPaymentIds(paymentIds));
     }
+
+    /**
+     * 查询支付错误明细
+     */
+    @GetMapping("/error/list")
+    public TableDataInfo list(FsStorePaymentError fsStorePaymentError)
+    {
+        startPage();
+        List<FsStorePaymentError> list = fsStorePaymentErrorService.selectFsStorePaymentErrorList(fsStorePaymentError);
+        for (FsStorePaymentError vo : list){
+            if (vo.getBusinessType() != null && vo.getBusinessType()==3 &&  vo.getOrderId() != null) {
+                FsPackageOrder fsPackageOrder = fsPackageOrderService.selectFsPackageOrderByOrderId(vo.getOrderId());
+                vo.setOrderNo(fsPackageOrder.getOrderSn());
+            }
+        }
+        return getDataTable(list);
+    }
 }

+ 107 - 0
fs-admin/src/main/java/com/fs/his/controller/MerchantAppConfigController.java

@@ -0,0 +1,107 @@
+package com.fs.his.controller;
+
+import java.util.List;
+
+import com.fs.his.domain.MerchantAppConfig;
+import com.fs.his.service.IMerchantAppConfigService;
+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.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 商户应用配置Controller
+ *
+ * @author fs
+ * @date 2025-12-05
+ */
+@RestController
+@RequestMapping("/his/merchantAppConfig")
+public class MerchantAppConfigController extends BaseController
+{
+    @Autowired
+    private IMerchantAppConfigService merchantAppConfigService;
+
+    /**
+     * 查询商户应用配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:merchantAppConfig:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(MerchantAppConfig merchantAppConfig)
+    {
+        startPage();
+        List<MerchantAppConfig> list = merchantAppConfigService.selectMerchantAppConfigList(merchantAppConfig);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出商户应用配置列表
+     */
+    @PreAuthorize("@ss.hasPermi('his:merchantAppConfig:export')")
+    @Log(title = "商户应用配置", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(MerchantAppConfig merchantAppConfig)
+    {
+        List<MerchantAppConfig> list = merchantAppConfigService.selectMerchantAppConfigList(merchantAppConfig);
+        ExcelUtil<MerchantAppConfig> util = new ExcelUtil<MerchantAppConfig>(MerchantAppConfig.class);
+        return util.exportExcel(list, "商户应用配置数据");
+    }
+
+    /**
+     * 获取商户应用配置详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('his:merchantAppConfig:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(merchantAppConfigService.selectMerchantAppConfigById(id));
+    }
+
+    /**
+     * 新增商户应用配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:merchantAppConfig:add')")
+    @Log(title = "商户应用配置", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody MerchantAppConfig merchantAppConfig)
+    {
+        merchantAppConfig.setCreatedBy(getUsername());
+        merchantAppConfig.setUpdatedBy(getUsername());
+        return toAjax(merchantAppConfigService.insertMerchantAppConfig(merchantAppConfig));
+    }
+
+    /**
+     * 修改商户应用配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:merchantAppConfig:edit')")
+    @Log(title = "商户应用配置", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody MerchantAppConfig merchantAppConfig)
+    {
+        merchantAppConfig.setUpdatedBy(getUsername());
+        return toAjax(merchantAppConfigService.updateMerchantAppConfig(merchantAppConfig));
+    }
+
+    /**
+     * 删除商户应用配置
+     */
+    @PreAuthorize("@ss.hasPermi('his:merchantAppConfig:remove')")
+    @Log(title = "商户应用配置", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long ids)
+    {
+        return toAjax(merchantAppConfigService.deleteMerchantAppConfigById(ids));
+    }
+}

+ 65 - 13
fs-admin/src/main/java/com/fs/hisStore/controller/FsStorePaymentScrmController.java

@@ -1,5 +1,6 @@
 package com.fs.hisStore.controller;
 
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alipay.api.AlipayApiException;
@@ -12,15 +13,20 @@ import com.fs.common.core.domain.R;
 import com.fs.common.core.page.TableDataInfo;
 import com.fs.common.enums.BusinessType;
 import com.fs.common.utils.CloudHostUtils;
+import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.ParseUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.config.cloud.CloudHostProper;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.his.domain.FsHfpayConfig;
+import com.fs.his.domain.FsPayConfig;
+import com.fs.his.domain.MerchantAppConfig;
 import com.fs.his.mapper.FsHfpayConfigMapper;
-import com.fs.hisStore.domain.FsPayConfigScrm;
+import com.fs.his.service.IMerchantAppConfigService;
 import com.fs.huifuPay.domain.HuiFuQueryOrderResult;
 import com.fs.huifuPay.domain.HuiFuRefundResult;
 import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayQueryRequest;
@@ -32,6 +38,13 @@ import com.fs.hisStore.service.IFsStoreOrderScrmService;
 import com.fs.hisStore.service.IFsStorePaymentScrmService;
 import com.fs.hisStore.vo.FsStorePaymentVO;
 import com.fs.system.service.ISysConfigService;
+import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
 import com.ijpay.alipay.AliPayApi;
 import com.ijpay.alipay.AliPayApiConfig;
 import com.ijpay.alipay.AliPayApiConfigKit;
@@ -63,10 +76,16 @@ public class FsStorePaymentScrmController extends BaseController
     private IFsStorePaymentScrmService fsStorePaymentService;
     @Autowired
     private AliPayBean aliPayBean;
-
+    @Autowired
+    private WxPayService wxPayService;
     @Autowired
     private ICompanyService companyService;
-
+    @Autowired
+    private IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
+    @Autowired
+    private IMerchantAppConfigService merchantAppConfigService;
+    @Autowired
+    IFsStorePaymentScrmService paymentService;
     @Autowired
     private IFsStoreOrderScrmService orderService;
     @Autowired
@@ -135,6 +154,7 @@ public class FsStorePaymentScrmController extends BaseController
             V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
             request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
             request.setOrgHfSeqId(payment.getTradeNo());
+            request.setAppId(payment.getAppId());
             HuiFuQueryOrderResult o = null;
             try {
                 o = huiFuService.queryOrder(request);
@@ -193,16 +213,14 @@ public class FsStorePaymentScrmController extends BaseController
         }
 
         if(payment.getPayTypeCode().equals("weixin")){
-            String json;
-            if (CloudHostUtils.hasCloudHostName("康年堂")){
-                json = configService.selectConfigByKey("his.pay");
-            } else {
-                json = configService.selectConfigByKey("store.pay");
-            }
-            if (StringUtils.isBlank(json)) {
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+            MerchantAppConfig merchantAppConfig = merchantAppConfigService.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+
+            if (ObjectUtil.isEmpty(merchantAppConfig)) {
                 return R.error("缺少支付相关配置");
             }
-            FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+            FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+
             if (payment.getPayMode()!=null&&payment.getPayMode().equals("hf")){
                 String huifuId="";
                 FsHfpayConfigMapper fsHfpayConfigMapper = SpringUtils.getBean(FsHfpayConfigMapper.class);
@@ -223,9 +241,12 @@ public class FsStorePaymentScrmController extends BaseController
                 request.setOrdAmt(payment.getPayMoney().toString());
                 request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
                 request.setReqSeqId("refund-"+payment.getPayCode());
+                request.setAppId(payment.getAppId());
                 Map<String, Object> extendInfoMap = new HashMap<>();
                 extendInfoMap.put("org_party_order_id", payment.getBankSerialNo());
                 request.setExtendInfo(extendInfoMap);
+                logger.info("请求参数:"+request);
+                request.setAppId(payment.getAppId());
                 HuiFuRefundResult refund = huiFuService.refund(request);
                 logger.info("退款:"+refund);
                 if((refund.getResp_code().equals("00000000")||refund.getResp_code().equals("00000100"))&&(refund.getTrans_stat().equals("S")||refund.getTrans_stat().equals("P"))){
@@ -243,8 +264,39 @@ public class FsStorePaymentScrmController extends BaseController
                     return R.error(refund.getResp_desc());
                 }
 
-            }else if (payment.getPayMode()!=null&&payment.getPayMode().equals("wx")){
-
+            }
+            else if (payment.getPayMode()!=null&&payment.getPayMode().equals("wx")){
+                WxPayConfig payConfig = new WxPayConfig();
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
+                payConfig.setMchId(fsPayConfig.getWxMchId());
+                payConfig.setMchKey(fsPayConfig.getWxMchKey());
+                payConfig.setKeyPath(fsPayConfig.getKeyPath());
+                payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                wxPayService.setConfig(payConfig);
+                WxPayRefundRequest refundRequest = new WxPayRefundRequest();
+                refundRequest.setOutTradeNo("payment-"+payment.getPayCode());
+                refundRequest.setOutRefundNo("payment-"+payment.getPayCode());
+                refundRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(payment.getPayMoney().toString()));
+                refundRequest.setRefundFee(WxPayUnifiedOrderRequest.yuanToFen(fsStorePayment.getRefundMoney().toString()));
+                try {
+                    WxPayRefundResult refundResult = wxPayService.refund(refundRequest);
+                    WxPayRefundQueryResult refundQueryResult = wxPayService.refundQuery("", refundResult.getOutTradeNo(), refundResult.getOutRefundNo(), refundResult.getRefundId());
+                    if(refundQueryResult!=null&&refundQueryResult.getResultCode().equals("SUCCESS")){
+                        FsStorePaymentScrm paymentMap=new FsStorePaymentScrm();
+                        paymentMap.setPaymentId(payment.getPaymentId());
+                        paymentMap.setStatus(-1);
+                        paymentMap.setRefundTime(DateUtils.getNowDate());
+                        paymentMap.setRefundMoney(fsStorePayment.getRefundMoney());
+                        paymentService.updateFsStorePayment(paymentMap);
+                        return R.ok("退款成功");
+                    }
+                    else {
+                        return R.error("退款请求失败"+refundQueryResult.getErrCodeDes());
+                    }
+                } catch (WxPayException e) {
+                    return R.error("退款请求失败"+e.getErrCodeDes());
+                }
             }
 
             //小雨点退款

+ 66 - 0
fs-ipad-task/src/main/java/com/fs/app/service/IpadSendServer.java

@@ -1,18 +1,24 @@
 package com.fs.app.service;
 
 import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.fs.common.core.redis.RedisCache;
 import com.fs.common.exception.base.BaseException;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.date.DateUtil;
+import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.domain.CompanyMiniapp;
 import com.fs.company.service.ICompanyMiniappService;
 import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsCourseWatchLog;
+import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.course.service.IFsCourseWatchLogService;
+import com.fs.his.domain.FsUser;
+import com.fs.his.mapper.FsUserMapper;
 import com.fs.ipad.IpadSendUtils;
 import com.fs.ipad.vo.*;
+import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.domain.QwUserVideo;
 import com.fs.qw.mapper.QwExternalContactMapper;
@@ -30,8 +36,11 @@ import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.time.LocalDateTime;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
 
 @Slf4j
 @Service
@@ -47,6 +56,9 @@ public class IpadSendServer {
     private final IQwUserVideoService qwUserVideoService;
     private final RedisCache redisCache;
     private final ICompanyMiniappService companyMiniappService;
+    private final IFsCoursePlaySourceConfigService playSourceConfigService;
+    private final FsUserMapper fsUserMapper;
+    private static final List<String> PROJECT_NAMES = Arrays.asList("济南联志健康", "北京存在文化","宽益堂");
     private void sendMiniProgram(BaseVo vo, QwSopCourseFinishTempSetting.Setting content, Map<String, FsCoursePlaySourceConfig> miniMap, Long companyId) {
         // 发送参数原本的appid
         String appid = content.getMiniprogramAppid();
@@ -58,6 +70,60 @@ public class IpadSendServer {
             if(!list.isEmpty() && list.get(0) != null && StringUtils.isNotEmpty(list.get(0).getAppId())){
                 appid = list.get(0).getAppId();
             }
+            // 获取配置文件里面的项目名称
+            String signProjectName = SpringUtils.getProperty("cloud_host.company_name");
+            //区分新老用户,新用户发送备用小程序,老用户发送主小程序,TODO 需要使用的项目在参数里面加上
+            if(PROJECT_NAMES.contains(signProjectName)){
+                log.info("ID:{}, qwUserId:{},externalId:{},进入区分发小程序逻辑", vo.getId(), vo.getQwUserId(), vo.getExId());
+                // 判断消息是否是群聊,不是群聊再进去,TODO 当权无法判断群聊是否可以发送对应的小程序
+                if(!vo.isRoom()){
+                    log.info("qwUserId:{},externalId:{},不是群聊", vo.getQwUserId(), vo.getExId());
+                    try {
+                        // 获取当前外部联系人
+                        QwExternalContact qwExternalContact = qwExternalContactMapper.selectOne(new LambdaQueryWrapper<QwExternalContact>().eq(QwExternalContact::getQwUserId,vo.getQwUserId()).eq(QwExternalContact::getExternalUserId,vo.getExId()).last(" limit 1"));
+                        // 当前外部联系是否绑定用户数据,如果数据为空则是没看过小程序的新用户,不用去判断小程序,跳过判断
+                        if(qwExternalContact.getFsUserId() != null){
+                            // 根据用户绑定信息去查询用户信息
+                            FsUser fsUser = fsUserMapper.selectFsUserByUserId(qwExternalContact.getFsUserId());
+                            // 判断用户是否有看过其他的小程序多个
+                            if(StringUtils.isNotEmpty(fsUser.getAppId())){
+                                // 获取用户看过的小程序ID集合
+                                List<String> miniAppList = Arrays.asList(fsUser.getAppId().split(","));
+                                // 根据小程序ID查询小程序列表
+                                List<FsCoursePlaySourceConfig> configList = playSourceConfigService.selectByAppIds(miniAppList);
+                                // 筛选出半封禁的小程序数据,得到这个数据然后优先发这个小程序
+                                Optional<FsCoursePlaySourceConfig> optional = configList.stream().filter(e -> e.getStatus() != null && e.getStatus() == 1).findFirst();
+                                // 判断是否找到
+                                if(optional.isPresent()){
+                                    // 找到半封禁并且在appid里面存在证明这个客户是打开过小程序,优先发送这个
+                                    appid = optional.get().getAppid();
+                                }
+                            }else{
+                                // 获取用户的创建时间
+                                LocalDateTime createTime = DateUtil.dateToLocalDateTime(fsUser.getCreateTime());
+                                log.info("ID:{}, qwUserId:{},externalId:{},已绑定小程序,判断时间:{}", vo.getId(), vo.getQwUserId(), vo.getExId(), createTime);
+                                // 这个时间是写死的,目前判断的芳华封禁的时间,可以更具项目调整
+                                LocalDateTime lastTime = LocalDateTime.of(2025, 11, 6, 23, 59, 59);
+                                // 判断客户创建时间是在这个之前还是之后
+                                int listIndex = createTime.isAfter(lastTime) ? 1 : 0 ;
+                                // 获取公司里面的主备小程序,根据用户创建时间来发送主备,如果创建时间大于上看的时间就发送备用小程序,如果小于就发送主要小程序
+                                List<CompanyMiniapp> collect2 = list.stream().filter(e -> e.getType().equals(listIndex)).collect(Collectors.toList());
+                                // 判断是否获取到了配置
+                                if(!collect2.isEmpty() && collect2.get(0) != null && StringUtils.isNotEmpty(collect2.get(0).getAppId())){
+                                    appid = collect2.get(0).getAppId();
+                                    log.info("ID:{}, qwUserId:{},externalId:{},发送小程序:{}", vo.getId(), vo.getQwUserId(), vo.getExId(), appid);
+                                }
+                            }
+                        }else{
+                            log.info("ID:{}, qwUserId:{},externalId:{},未绑定小程序用户", vo.getId(), vo.getQwUserId(), vo.getExId());
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                        log.error("6.输出外部联系人ID-------------->{}",vo.getExId());
+                        log.error("7.数据异常----------------------》{}",e.getMessage());
+                    }
+                }
+            }
         }
         FsCoursePlaySourceConfig courseMaConfig = miniMap.get(appid);
         if(courseMaConfig == null){

+ 14 - 0
fs-service/src/main/java/com/fs/course/domain/FsCoursePlaySourceConfig.java

@@ -82,6 +82,10 @@ public class FsCoursePlaySourceConfig {
      */
     private Long companyId;
 
+    /**
+     * 销售公司ids 用于判定销售公司可见编辑列表
+     */
+    private String setCompanyIds;
     /**
      * 销售ID
      */
@@ -95,4 +99,14 @@ public class FsCoursePlaySourceConfig {
      * 是否是互医/商城小程序
      */
     private Integer isMall;
+
+    /**
+     * 小程序状态:0正常,1半封禁,2封禁
+     */
+    private Integer status;
+
+    /**
+     * 商户支付配置id
+     */
+    private Long merchantConfigId;
 }

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

@@ -14,4 +14,6 @@ public interface FsCoursePlaySourceConfigMapper extends BaseMapper<FsCoursePlayS
      * 查询点播配置列表
      */
     List<FsCoursePlaySourceConfigVO> selectCoursePlaySourceConfigVOListByMap(@Param("params") Map<String, Object> params);
+
+    FsCoursePlaySourceConfig selectCoursePlaySourceConfigByAppId(String appId);
 }

+ 12 - 0
fs-service/src/main/java/com/fs/course/param/FsCoursePlaySourceConfigEditParam.java

@@ -43,7 +43,19 @@ public class FsCoursePlaySourceConfigEditParam {
     @ApiModelProperty("所属公司")
     private Long companyId;
 
+    /**
+     * 销售公司ids 用于判定销售公司可见编辑列表
+     */
+    @ApiModelProperty("销售公司ids 用于判定销售公司可见编辑列表")
+    private String setCompanyIds;
+
     @ApiModelProperty("是否是互医/商城小程序")
     private Integer isMall;
     private Long createDeptId;
+
+    @ApiModelProperty("小程序状态:0正常,1半封禁,2封禁")
+    private Integer status;
+
+    @ApiModelProperty("商户支付配置id")
+    private Long merchantConfigId;
 }

+ 7 - 0
fs-service/src/main/java/com/fs/course/service/IFsCoursePlaySourceConfigService.java

@@ -15,4 +15,11 @@ public interface IFsCoursePlaySourceConfigService extends IService<FsCoursePlayS
     List<FsCoursePlaySourceConfigVO> selectCoursePlaySourceConfigVOListByMap(Map<String, Object> params);
 
     List<FsCoursePlaySourceConfig> selectByAppIds(List<String> miniAppList);
+
+    /**
+     * 根据appId查询
+     * @param appId
+     * @return
+     */
+    FsCoursePlaySourceConfig selectCoursePlaySourceConfigByAppId(String appId);
 }

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

@@ -30,4 +30,9 @@ public class FsCoursePlaySourceConfigServiceImpl extends ServiceImpl<FsCoursePla
     public List<FsCoursePlaySourceConfig> selectByAppIds(List<String> miniAppList) {
         return baseMapper.selectList(new QueryWrapper<FsCoursePlaySourceConfig>().in("appid", miniAppList));
     }
+
+    @Override
+    public FsCoursePlaySourceConfig selectCoursePlaySourceConfigByAppId(String appId) {
+        return baseMapper.selectCoursePlaySourceConfigByAppId(appId);
+    }
 }

+ 53 - 21
fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java

@@ -21,7 +21,9 @@ import com.fs.company.service.ICompanyUserService;
 import com.fs.company.util.WechatApi;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsCourseProduct;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.course.mapper.FsCourseProductMapper;
 import com.fs.course.param.FsCourseProductOrderCreateParam;
 import com.fs.course.param.FsCourseProductOrderListParam;
@@ -33,6 +35,7 @@ import com.fs.his.dto.PayConfigDTO;
 import com.fs.his.enums.FsCourseProductOrderStatusEnum;
 import com.fs.his.mapper.FsStorePaymentMapper;
 import com.fs.his.mapper.FsUserWxMapper;
+import com.fs.his.mapper.MerchantAppConfigMapper;
 import com.fs.his.param.ApplyCourseProductOrderRefundParam;
 import com.fs.his.param.FsCourseProductOrderComputeParam;
 import com.fs.his.param.FsCourseProductOrderDoPayParam;
@@ -99,6 +102,11 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 
     @Autowired FsCourseProductOrderMapper courseProductOrderMapper;
 
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+
     @Autowired
     private IFsUserService userService;
 
@@ -289,9 +297,18 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
             return R.error("订单状态不正确");
         }
         FsUser user = userService.selectFsUserByUserId(courseProductOrder.getUserId());
-
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
         String openId = null;
         String appId = param.getAppId();
         if (StringUtils.isNotBlank(appId)) {
@@ -305,7 +322,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -366,8 +383,19 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
         FsUser user = userService.selectFsUserByUserId(param.getUserId());
         logger.info("用户信息==============={}",user);
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
         String openId = null;
         String appId = param.getAppId();
         if (StringUtils.isNotBlank(appId)) {
@@ -381,7 +409,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -400,15 +428,13 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
 //        if (user != null && fsUserWx != null && StringUtils.isNotEmpty(fsUserWx.getOpenId())) {
         if (user != null && StringUtils.isNotEmpty(openId)) {
             if (courseProduct.getProductPrice().compareTo(new BigDecimal(0))==1) {
-//                String json = configService.selectConfigByKey("his.pay");
-//                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 String payCode =  OrderCodeUtils.getOrderSn();
                 if(StringUtils.isEmpty(payCode)){
                     return R.error("订单生成失败,请重试");
                 }
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(courseProductOrder.getOrderCode());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(courseProduct.getProductPrice());
@@ -422,11 +448,9 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                 storePayment.setUserId(user.getUserId());
                 storePayment.setBusinessId(courseProductOrder.getCourseOrderId().toString());
                 if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
-                    if (payConfigDTO.getType().equals("wx")) {
+                    if (merchantAppConfig.getMerchantType().equals("wx")) {
                         //创建微信订单
                         WxPayConfig payConfig = new WxPayConfig();
-                        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
                         payConfig.setAppId(appId);
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
@@ -451,7 +475,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                             e.printStackTrace();
                             throw new CustomException("支付失败" + e.getMessage());
                         }
-                    } else if (payConfigDTO.getType().equals("yb")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("yb")) {
                         WxJspayDTO p = new WxJspayDTO();
                         // 使用setter方法为对象赋值
                         p.setPayMoney(storePayment.getPayMoney().toString());
@@ -472,7 +496,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                         } else {
                             throw new CustomException("支付失败");
                         }
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("product" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -497,7 +521,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    }else if (payConfigDTO.getType().equals("hf")) {
+                    }else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         logger.info("创建汇付订单");
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_MINIAPP");
@@ -518,7 +542,8 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                     }
                 }
             } else {
-                //TODO 支付金额为0的业务
+                this.payConfirm(courseProductOrder.getOrderCode(),"","","",2,null,null);
+                return R.ok().put("isPay",1);
             }
 
         } else {
@@ -609,19 +634,25 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
         mapOrder.setRefundTime(new Date());
         courseProductOrderMapper.updateFsCourseProductOrder(mapOrder);
 
+
         if(courseProduct.getProductPrice().compareTo(new BigDecimal(0))==1){
             List<FsStorePayment> fsStorePayments = fsStorePaymentMapper.selectFsStorePaymentByPay(6, param.getCourseOrderId());
             if (fsStorePayments != null && fsStorePayments.size() == 1) {
                 FsStorePayment payment=fsStorePayments.get(0);
+                FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+                Long merConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                if(payment.getMerConfigId()!=null){
+                    merConfigId=payment.getMerConfigId();
+                }
+                MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(merConfigId);
                 if(payment.getPayMode().equals("wx")){
                     WxPayConfig payConfig = new WxPayConfig();
-                    SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                    FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                    payConfig.setAppId(fsPayConfig.getAppId());
+                    FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+                    payConfig.setAppId(param.getAppId());
                     payConfig.setMchId(fsPayConfig.getWxMchId());
                     payConfig.setMchKey(fsPayConfig.getWxMchKey());
 
-                    payConfig.setKeyPath(wxPayProperties.getKeyPath());
+                    payConfig.setKeyPath(fsPayConfig.getKeyPath());
 
                     payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
                     payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -691,6 +722,7 @@ public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProduct
                     request.setOrdAmt(payment.getPayMoney().toString());
                     request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
                     request.setReqSeqId("refund-"+payment.getPayCode());
+                    request.setAppId(payment.getAppId());
                     Map<String, Object> extendInfoMap = new HashMap<>();
                     extendInfoMap.put("org_req_seq_id", "product-"+payment.getPayCode());
                     request.setExtendInfo(extendInfoMap);

+ 42 - 18
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseOrderServiceImpl.java

@@ -80,6 +80,10 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
     @Autowired
     private FsUserCourseOrderMapper fsUserCourseOrderMapper;
     @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+    @Autowired
     private FsUserMapper fsUserMapper;
     @Autowired
     private FsUserCourseMapper fsUserCourseMapper;
@@ -374,8 +378,20 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
         }
         FsUser user=fsUserMapper.selectFsUserByUserId(param.getUserId());
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
 //        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
 //        if (StringUtils.isBlank(openId)){
@@ -400,7 +416,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -424,7 +440,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                 }
                 FsStorePayment storePayment = new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(order.getOrderCode());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(order.getPayMoney());
@@ -436,12 +452,10 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                 storePayment.setUserId(user.getUserId());
                 storePayment.setBusinessId(order.getOrderId().toString());
                 if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
-                    if (payConfigDTO.getType().equals("wx")) {
+                    if (merchantAppConfig.getMerchantType().equals("wx")) {
                         //创建微信订单
                         WxPayConfig payConfig = new WxPayConfig();
-                        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                        payConfig.setAppId(fsPayConfig.getAppId());
+                        payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
                         payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -465,7 +479,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                             e.printStackTrace();
                             throw new CustomException("支付失败" + e.getMessage());
                         }
-                    } else if (payConfigDTO.getType().equals("yb")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("yb")) {
                         WxJspayDTO p = new WxJspayDTO();
                         // 使用setter方法为对象赋值
                         p.setPayMoney(storePayment.getPayMoney().toString());
@@ -485,7 +499,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                         } else {
                             throw new CustomException("支付失败");
                         }
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("course" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -505,7 +519,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    } else if (payConfigDTO.getType().equals("hf")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_MINIAPP");
                         o.setOpenid(openId);
@@ -550,8 +564,18 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
 //        }
         FsUser user=fsUserMapper.selectFsUserByUserId(param.getUserId());
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
         String openId = null;
         String appId = param.getAppId();
         if (StringUtils.isNotBlank(appId)) {
@@ -564,7 +588,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -587,7 +611,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
 //                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(order.getOrderCode());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(order.getPayMoney());
@@ -600,9 +624,9 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                 storePayment.setBusinessId(order.getOrderId().toString());
                 if(storePaymentService.insertFsStorePayment(storePayment)>0){
 
-                    if (payConfigDTO.getType().equals("yb")) {
+                    if (merchantAppConfig.getMerchantType().equals("yb")) {
                         return R.error("支付暂不可用!");
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("course" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -623,7 +647,7 @@ public class FsUserCourseOrderServiceImpl implements IFsUserCourseOrderService
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    }else if (payConfigDTO.getType().equals("hf")) {
+                    }else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("A_NATIVE");
 //                        o.setOpenid(user.getMaOpenId());

+ 47 - 22
fs-service/src/main/java/com/fs/course/service/impl/FsUserVipOrderServiceImpl.java

@@ -10,6 +10,7 @@ import java.util.Objects;
 
 import cn.hutool.core.util.IdUtil;
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.core.domain.R;
@@ -20,8 +21,10 @@ import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.ip.IpUtils;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsUserCourseOrder;
 import com.fs.course.domain.FsUserVipPackage;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.course.mapper.FsUserVipPackageMapper;
 import com.fs.course.param.FsUserVipOrderCreateUParam;
 import com.fs.course.param.FsUserVipOrderParam;
@@ -29,10 +32,7 @@ import com.fs.course.param.FsUserVipOrderPayUParam;
 import com.fs.course.vo.FsUserVipOrderListPVO;
 import com.fs.his.domain.*;
 import com.fs.his.dto.PayConfigDTO;
-import com.fs.his.mapper.FsStorePaymentErrorMapper;
-import com.fs.his.mapper.FsStorePaymentMapper;
-import com.fs.his.mapper.FsUserMapper;
-import com.fs.his.mapper.FsUserWxMapper;
+import com.fs.his.mapper.*;
 import com.fs.his.service.IFsStorePaymentService;
 import com.fs.huifuPay.domain.HuiFuCreateOrder;
 import com.fs.huifuPay.domain.HuifuCreateOrderResult;
@@ -82,6 +82,10 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
     @Autowired
     private FsUserMapper userMapper;
 
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
     @Autowired
     private ISysConfigService configService;
 
@@ -233,8 +237,20 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
         }
         FsUser user = userMapper.selectFsUserByUserId(param.getUserId());
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
 //        String openId = Objects.isNull(user) ? "" : user.getMaOpenId();
 //        if (StringUtils.isBlank(openId)){
@@ -258,7 +274,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -282,7 +298,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                 }
                 FsStorePayment storePayment = new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(order.getOrderCode());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(order.getPayMoney());
@@ -294,12 +310,10 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                 storePayment.setUserId(user.getUserId());
                 storePayment.setBusinessId(order.getOrderId().toString());
                 if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
-                    if (payConfigDTO.getType().equals("wx")) {
+                    if (merchantAppConfig.getMerchantType().equals("wx")) {
                         //创建微信订单
                         WxPayConfig payConfig = new WxPayConfig();
-                        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                        payConfig.setAppId(fsPayConfig.getAppId());
+                        payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
                         payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -323,7 +337,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                             e.printStackTrace();
                             throw new CustomException("支付失败" + e.getMessage());
                         }
-                    } else if (payConfigDTO.getType().equals("yb")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("yb")) {
                         WxJspayDTO p = new WxJspayDTO();
                         // 使用setter方法为对象赋值
                         p.setPayMoney(storePayment.getPayMoney().toString());
@@ -343,7 +357,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                         } else {
                             throw new CustomException("支付失败");
                         }
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("appvip" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -363,7 +377,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    } else if (payConfigDTO.getType().equals("hf")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_MINIAPP");
                         o.setOpenid(openId);
@@ -399,8 +413,19 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
         }
         FsUser user = userMapper.selectFsUserByUserId(param.getUserId());
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
         String openId = null;
         String appId = param.getAppId();
@@ -414,7 +439,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -437,7 +462,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
 //                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(order.getOrderCode());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(order.getPayMoney());
@@ -450,9 +475,9 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                 storePayment.setBusinessId(order.getOrderId().toString());
                 if(storePaymentService.insertFsStorePayment(storePayment)>0){
 
-                    if (payConfigDTO.getType().equals("yb")) {
+                    if (merchantAppConfig.getMerchantType().equals("yb")) {
                         return R.error("支付暂不可用!");
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("appvip" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -473,7 +498,7 @@ public class FsUserVipOrderServiceImpl implements IFsUserVipOrderService
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    }else if (payConfigDTO.getType().equals("hf")) {
+                    }else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("A_NATIVE");
 //                        o.setOpenid(user.getMaOpenId());

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

@@ -55,4 +55,10 @@ public class FsCoursePlaySourceConfigVO {
      */
     private Integer isMall;
     private Long createDeptId;
+
+    @ApiModelProperty("小程序状态:0正常,1半封禁,2封禁")
+    private Integer status;
+
+    @ApiModelProperty("小程序支付配置id")
+    private Long merchantConfigId;
 }

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

@@ -15,6 +15,13 @@ public class FsPayConfig {
     private String appId;
     private String wxMchId;
     private String wxMchKey;
+    private String keyPath;
+    private String wxApiV3Key;
+
+    /**
+     * 微信回调地址
+     */
+    private String notifyUrlScrm;
 
     private String ybNotifyUrl;
     private String tzPayDecrypt;

+ 28 - 0
fs-service/src/main/java/com/fs/his/domain/FsQuestionAndAnswer.java

@@ -0,0 +1,28 @@
+package com.fs.his.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 问答对象 fs_question_and_answer
+ *
+ * @author fs
+ * @date 2025-09-29
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsQuestionAndAnswer extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    private String questionName;
+
+    /** 问答数据 */
+    @Excel(name = "问答数据")
+    private String jsonInfo;
+
+
+}

+ 1 - 0
fs-service/src/main/java/com/fs/his/domain/FsStoreOrder.java

@@ -265,5 +265,6 @@ public class FsStoreOrder extends BaseEntity
     private Integer source;
     private BigDecimal billPrice;
     private String erpPhone;
+    private Integer doctorType2Confirm;
 
 }

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

@@ -100,6 +100,15 @@ public class FsStorePayment extends BaseEntity
     //小程序appId
     private String appId;
 
+    private Long merConfigId;
+
+    public Long getMerConfigId() {
+        return merConfigId;
+    }
+
+    public void setMerConfigId(Long merConfigId) {
+        this.merConfigId = merConfigId;
+    }
 
     public Integer getIsShare() {
         return isShare;

+ 5 - 0
fs-service/src/main/java/com/fs/his/domain/FsStorePaymentError.java

@@ -35,4 +35,9 @@ public class FsStorePaymentError extends BaseEntity
     @Excel(name = "0未处理 1已处理")
     private Integer status;
 
+
+    private Long orderId;
+
+    private Integer businessType;
+
 }

+ 114 - 0
fs-service/src/main/java/com/fs/his/domain/FsUserInformationCollection.java

@@ -0,0 +1,114 @@
+package com.fs.his.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 用户信息采集对象 fs_user_information_collection
+ *
+ * @author fs
+ * @date 2025-10-14
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsUserInformationCollection extends BaseEntity{
+
+    /** $column.columnComment */
+    private Long id;
+
+    /** 问答id */
+    @Excel(name = "问答id")
+    private Long questionId;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 信息采集json数据 */
+    @Excel(name = "信息采集json数据")
+    private String jsonInfo;
+
+    /** 用户确认状态 0-未确认 1-已确认 */
+    @Excel(name = "用户确认状态 0-未确认 1-已确认")
+    private Integer userConfirm;
+
+    /** 医生确认状态 0-未确认 2-已确认 */
+    @Excel(name = "医生确认状态 0-未确认 2-已确认")
+    private Integer doctorConfirm;
+
+    // 医生id
+    private Long doctorId;
+
+    //销售id
+    private Long companyUserId;
+
+    //套餐包id
+    private Long packageId;
+
+    //支付类型 0-全款 1-物流代收
+    private Integer payType;
+
+    //代收金额
+    private BigDecimal amount;
+
+    //用户补充说明
+    private String userAdvice;
+
+    //医生建议
+    private String doctorAdvice;
+
+    //医生签名
+    private String doctorSign;
+
+    //是否关联套餐包 0-不关联 1-关联
+    private Integer isPackage;
+
+    //套餐包订单号
+    private String packageOrderCode;
+
+    //套餐包订单id
+    private Long packageOrderId;
+
+    //用户第二次确认状态
+    private Integer userConfirm2;
+
+    //确认状态 1第一次确认 2第二次确认
+    private Integer status;
+
+    //医生确认时间
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date doctorConfirmTime;
+
+    //用户性别 0女 1男
+    private Integer sex;
+    //用户姓名
+    private String userName;
+    //用户电话后四位
+    private String userPhoneFour;
+
+    //是否过敏
+    private String allergy;
+    //备注
+    private String remark;
+
+    private Long patientId;
+    private String patientName;
+
+    private Long companyId;
+    //药师id
+    private Long doctorType2Id;
+    //药师确认
+    private Integer doctorType2Confirm;
+    //药师签名
+    private String doctorType2Sign;
+
+    //药品订单id
+    private Long storeOrderId;
+
+}

+ 66 - 0
fs-service/src/main/java/com/fs/his/domain/MerchantAppConfig.java

@@ -0,0 +1,66 @@
+package com.fs.his.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 商户应用配置对象 merchant_app_config
+ *
+ * @author fs
+ * @date 2025-12-05
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class MerchantAppConfig extends BaseEntity{
+
+    /** 主键ID */
+    private Long id;
+
+    /** 商户类型 */
+    @Excel(name = "商户类型")
+    private String merchantType;
+
+    // 应用ID
+    @Excel(name = "应用ID")
+    private String appId;
+
+    /** 回调地址,用于接收支付结果等通知 */
+    @Excel(name = "回调地址,用于接收支付结果等通知")
+    private String callbackUrl;
+
+    /** 配置详情 */
+    @Excel(name = "配置详情")
+    private String dataJson;
+
+    /** 创建时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date createdTime;
+
+    /** 修改时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "修改时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date updatedTime;
+
+    /** 删除状态:0-正常,1-已删除 */
+    @Excel(name = "删除状态:0-正常,1-已删除")
+    private Long isDeleted;
+
+    /** 创建人ID或用户名 */
+    private String createdBy;
+
+    /** 修改人ID或用户名 */
+    private String updatedBy;
+
+    /**
+     * 商户号
+     */
+    private String merchantId;
+
+
+}

+ 103 - 0
fs-service/src/main/java/com/fs/his/dto/FsUserInformationCollectionDTO.java

@@ -0,0 +1,103 @@
+package com.fs.his.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class FsUserInformationCollectionDTO {
+    /** $column.columnComment */
+    private Long id;
+
+    /** 问答id */
+    @Excel(name = "问答id")
+    private Long questionId;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 信息采集json数据 */
+    @Excel(name = "信息采集json数据")
+    private String jsonInfo;
+
+    /** 用户确认状态 0-未确认 1-已确认 */
+    @Excel(name = "用户确认状态 0-未确认 1-已确认")
+    private Integer userConfirm;
+
+    /** 医生确认状态 0-未确认 2-已确认 */
+    @Excel(name = "医生确认状态 0-未确认 2-已确认")
+    private Integer doctorConfirm;
+
+    // 医生id
+    private Long doctorId;
+
+    //销售id
+    private Long companyUserId;
+
+    //套餐包id
+    private Long packageId;
+
+    //支付类型 0-全款 1-物流代收
+    private Integer payType;
+
+    //代收金额
+    private BigDecimal amount;
+
+    //用户补充说明
+    private String userAdvice;
+
+    //医生建议
+    private String doctorAdvice;
+
+    //是否关联套餐包 0-不关联 1-关联
+    private Integer isPackage;
+
+    //套餐包订单号
+    private String packageOrderCode;
+
+    //用户第二次确认状态
+    private Integer userConfirm2;
+
+    //确认状态 1第一次确认 2第二次确认
+    private Integer status;
+
+    //医生确认时间
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date doctorConfirmTime;
+
+    //用户性别 0女 1男
+    private Integer sex;
+    //用户姓名
+    private String userName;
+    //用户电话后四位
+    private String userPhoneFour;
+
+    //是否过敏
+    private String allergy;
+    //备注
+    private String remark;
+
+    private Long patientId;
+
+    private String patientName;
+
+    private String companyUserName;
+
+    private String doctorName;
+
+    private String packageName;
+
+    private String questionJson;
+
+    private String doctorSign;
+
+    private String doctorType2Name;
+    private Long doctorType2Id;
+    private Integer doctorType2Confirm;
+    private String doctorType2Sign;
+
+}

+ 67 - 0
fs-service/src/main/java/com/fs/his/mapper/FsQuestionAndAnswerMapper.java

@@ -0,0 +1,67 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsQuestionAndAnswer;
+import com.fs.his.vo.OptionsVO;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 问答Mapper接口
+ *
+ * @author fs
+ * @date 2025-09-29
+ */
+public interface FsQuestionAndAnswerMapper extends BaseMapper<FsQuestionAndAnswer>{
+    /**
+     * 查询问答
+     *
+     * @param id 问答主键
+     * @return 问答
+     */
+    FsQuestionAndAnswer selectFsQuestionAndAnswerById(Long id);
+
+    /**
+     * 查询问答列表
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 问答集合
+     */
+    List<FsQuestionAndAnswer> selectFsQuestionAndAnswerList(FsQuestionAndAnswer fsQuestionAndAnswer);
+
+    /**
+     * 新增问答
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 结果
+     */
+    int insertFsQuestionAndAnswer(FsQuestionAndAnswer fsQuestionAndAnswer);
+
+    /**
+     * 修改问答
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 结果
+     */
+    int updateFsQuestionAndAnswer(FsQuestionAndAnswer fsQuestionAndAnswer);
+
+    /**
+     * 删除问答
+     *
+     * @param id 问答主键
+     * @return 结果
+     */
+    int deleteFsQuestionAndAnswerById(Long id);
+
+    /**
+     * 批量删除问答
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsQuestionAndAnswerByIds(Long[] ids);
+
+    @Select("select id dictValue,question_name dictLabel from fs_question_and_answer  ")
+    List<OptionsVO> selectAllQuestionOptions();
+}

+ 105 - 0
fs-service/src/main/java/com/fs/his/mapper/FsUserInformationCollectionMapper.java

@@ -0,0 +1,105 @@
+package com.fs.his.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.FsUserInformationCollection;
+import com.fs.his.dto.FsUserInformationCollectionDTO;
+import com.fs.his.param.FsUserInformationCollectionListDParam;
+import com.fs.his.param.UserInformationDoctorType2Param;
+import com.fs.his.vo.FsUserInformationCollectionListDVO;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * 用户信息采集Mapper接口
+ *
+ * @author fs
+ * @date 2025-10-14
+ */
+public interface FsUserInformationCollectionMapper extends BaseMapper<FsUserInformationCollection>{
+    /**
+     * 查询用户信息采集
+     *
+     * @param id 用户信息采集主键
+     * @return 用户信息采集
+     */
+    FsUserInformationCollection selectFsUserInformationCollectionById(Long id);
+
+    FsUserInformationCollection selectFsUserInformationCollectionByUserId(Long userId);
+
+    /**
+     * 查询用户信息采集列表
+     *
+     * @param fsUserInformationCollection 用户信息采集
+     * @return 用户信息采集集合
+     */
+    List<FsUserInformationCollection> selectFsUserInformationCollectionList(FsUserInformationCollection fsUserInformationCollection);
+
+    /**
+     * 新增用户信息采集
+     *
+     * @param fsUserInformationCollection 用户信息采集
+     * @return 结果
+     */
+    int insertFsUserInformationCollection(FsUserInformationCollection fsUserInformationCollection);
+
+    /**
+     * 修改用户信息采集
+     *
+     * @param fsUserInformationCollection 用户信息采集
+     * @return 结果
+     */
+    int updateFsUserInformationCollection(FsUserInformationCollection fsUserInformationCollection);
+
+    @Select("UPDATE fs_user_information_collection SET package_order_code = NULL WHERE id = #{id}")
+    void collectionOderCodeNULL(@Param("id") Long id);
+    /**
+     * 删除用户信息采集
+     *
+     * @param id 用户信息采集主键
+     * @return 结果
+     */
+    int deleteFsUserInformationCollectionById(Long id);
+
+    /**
+     * 批量删除用户信息采集
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsUserInformationCollectionByIds(Long[] ids);
+
+    FsUserInformationCollection selectByUserId(Long userId);
+    FsUserInformationCollection selectByOrderCode(String orderCode);
+
+    @Select({"<script> " +
+            " SELECT uic.*,u.nickname userName FROM fs_user_information_collection uic LEFT JOIN fs_user u ON uic.user_id = u.user_id " +
+            "WHERE doctor_id = #{maps.doctorId} and is_package = 0  and user_confirm = 1 " +
+            "<if test='maps.doctorConfirm != null' > and uic.doctor_confirm = #{maps.doctorConfirm}  </if>" +
+            "<if test='maps.userConfirm != null' > and uic.user_confirm = #{maps.userConfirm}  </if>" +
+            "<if test='maps.userName != null ' > and u.nickname like concat('%',#{maps.userName},'%')</if>" +
+            "ORDER BY create_time desc" +
+            "</script>"})
+    List<FsUserInformationCollectionListDVO> selectFsUserInformationCollectionListDVO(@Param("maps") FsUserInformationCollectionListDParam param);
+
+    /**
+     * 查询需要自动退款订单(用户支付超过24小时,未第二次确认的订单号)
+     */
+    @Select("SELECT id,package_order_code FROM fs_user_information_collection uic LEFT JOIN fs_package_order po ON uic.package_order_code = po.order_sn  WHERE uic.doctor_confirm_time <= DATE_SUB(NOW(), INTERVAL 24 HOUR) and  uic.package_order_code IS NOT NULL   AND  uic.user_confirm2 = 0 AND po.is_pay = 1")
+    List<FsUserInformationCollection> selectAutoRefundOrderCode();
+
+    /**
+     * 查询需要自动确认订单(医生确认超过2小时,未第二次确认的信息采集)
+     */
+    @Select("SELECT * FROM fs_user_information_collection WHERE is_package = 0 AND user_confirm = 1 AND doctor_confirm = 1 AND user_confirm2 = 0 AND doctor_confirm_time <= DATE_SUB(NOW(), INTERVAL 2 HOUR)")
+    List<FsUserInformationCollection> selectAutoConfirm();
+
+    FsUserInformationCollectionDTO selectFsUserInformationCollectionDTOById(Long id);
+
+    List<FsUserInformationCollection>selectFsUserInformationCollectionByDoctorType2(@Param("maps") UserInformationDoctorType2Param userInformationDoctorType2Param);
+    List<FsUserInformationCollection>selectFsUserInformationCollectionByDoctorType1(@Param("maps") UserInformationDoctorType2Param userInformationDoctorType2Param);
+    FsUserInformationCollection selectFsUserInformationCollectionByOrderCode(String orderCode);
+
+    List<FsUserInformationCollection> selectListByIsPayAndConfirmStatus();
+}

+ 74 - 0
fs-service/src/main/java/com/fs/his/mapper/MerchantAppConfigMapper.java

@@ -0,0 +1,74 @@
+package com.fs.his.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.his.domain.MerchantAppConfig;
+
+/**
+ * 商户应用配置Mapper接口
+ *
+ * @author fs
+ * @date 2025-12-05
+ */
+public interface MerchantAppConfigMapper extends BaseMapper<MerchantAppConfig>{
+
+
+    /**
+     * 检查表是否存在
+     */
+    Integer checkTableExists();
+
+    /**
+     * 创建商户配置表
+     */
+    void createMerchantAppConfigTable();
+
+
+    /**
+     * 查询商户应用配置
+     *
+     * @param id 商户应用配置主键
+     * @return 商户应用配置
+     */
+    MerchantAppConfig selectMerchantAppConfigById(Long id);
+
+    /**
+     * 查询商户应用配置列表
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 商户应用配置集合
+     */
+    List<MerchantAppConfig> selectMerchantAppConfigList(MerchantAppConfig merchantAppConfig);
+
+    /**
+     * 新增商户应用配置
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 结果
+     */
+    int insertMerchantAppConfig(MerchantAppConfig merchantAppConfig);
+
+    /**
+     * 修改商户应用配置
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 结果
+     */
+    int updateMerchantAppConfig(MerchantAppConfig merchantAppConfig);
+
+    /**
+     * 删除商户应用配置
+     *
+     * @param id 商户应用配置主键
+     * @return 结果
+     */
+    int deleteMerchantAppConfigById(Long id);
+
+    /**
+     * 批量删除商户应用配置
+     *
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteMerchantAppConfigByIds(Long[] ids);
+}

+ 18 - 0
fs-service/src/main/java/com/fs/his/param/CollectionInfoConfirmParam.java

@@ -0,0 +1,18 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class CollectionInfoConfirmParam {
+    @NotNull(message = "信息id不能位空")
+    private Long id;
+
+    private Long userId;
+
+    //用户建议
+    private String userAdvice;
+
+    private Long patientId;
+}

+ 1 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderRefundParam.java

@@ -8,4 +8,5 @@ public class FsCourseProductOrderRefundParam {
     private Long courseOrderId;
 
     private String sysUserName;
+    private String appId;
 }

+ 1 - 0
fs-service/src/main/java/com/fs/his/param/FsInquiryOrderCancelParam.java

@@ -8,5 +8,6 @@ import java.io.Serializable;
 public class FsInquiryOrderCancelParam   implements Serializable {
     Long orderId;
     Integer type;//1用户取消 2未支付自动取消 3未接单自动取消 4 后台取消订单
+    String appId;
 
 }

+ 1 - 0
fs-service/src/main/java/com/fs/his/param/FsInquiryOrderRefundParam.java

@@ -8,6 +8,7 @@ import java.io.Serializable;
 public class FsInquiryOrderRefundParam implements Serializable {
     Long orderId;
     String sysUserName;
+    String appId;
 
 
 }

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

@@ -21,6 +21,8 @@ public class FsPackageOrderCreateParam implements Serializable {
     private Integer source;//订单来源 1:小程序 2:app  3:H5
     private String createPackageOrderKey;
     private Integer payType;
+    private Integer isUserInformation = 0;
+    private Long userInformationId;
 
 
 

+ 16 - 0
fs-service/src/main/java/com/fs/his/param/FsUserInformationCollectionListDParam.java

@@ -0,0 +1,16 @@
+package com.fs.his.param;
+
+import com.fs.hisStore.param.BaseParam;
+import lombok.Data;
+
+@Data
+public class FsUserInformationCollectionListDParam extends BaseParam {
+    private String userName;
+
+    private Long doctorId;
+
+    //医生确认状态 0未确认 1已确认
+    private Integer doctorConfirm;
+
+    private Integer userConfirm;
+}

+ 56 - 0
fs-service/src/main/java/com/fs/his/param/FsUserInformationCollectionParam.java

@@ -0,0 +1,56 @@
+package com.fs.his.param;
+
+import com.fs.his.vo.AnswerVO;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class FsUserInformationCollectionParam {
+
+    private Long id;
+
+    private Long questionId;
+
+    private List<AnswerVO> answers;
+
+    private Long userId;
+
+    //销售id
+    private Long companyUserId;
+
+    //是否关联套餐包 0-不关联 1-关联
+    private Integer isPackage;
+
+    //套餐包id
+    private Long packageId;
+
+    //支付类型 0-全款 1-物流代收
+    private Integer payType;
+
+    //代收金额
+    private BigDecimal amount;
+
+    //用户性别 0女 1男
+    private Integer sex;
+    //用户姓名
+    private String userName;
+    //用户电话后四位
+    private String userPhoneFour;
+
+    //是否过敏
+    private String allergy;
+    //备注
+    private String remark;
+
+    private Long patientId;
+
+    private String doctorSign;
+
+    private Long doctorId;
+
+    private Long doctorType2Id;
+
+    private String packageOrderCode;
+}

+ 5 - 0
fs-service/src/main/java/com/fs/his/param/PayOrderParam.java

@@ -36,6 +36,11 @@ public class PayOrderParam {
      * 用户ID
      */
     private Long userId;
+
+    /**
+     * appId
+     */
+    private String appId;
     /**
      * 支付方式
      */

+ 16 - 0
fs-service/src/main/java/com/fs/his/param/UserInformationDoctorType2Param.java

@@ -0,0 +1,16 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class UserInformationDoctorType2Param extends BaseParam implements Serializable {
+    private Integer doctorType2Confirm;
+    private String patientName;
+    private String packageOrderCode;
+    private Long doctorType2Id;
+    private Long doctorType;
+    private Long doctorId;
+    private Integer doctorConfirm;
+}

+ 66 - 0
fs-service/src/main/java/com/fs/his/service/IFsQuestionAndAnswerService.java

@@ -0,0 +1,66 @@
+package com.fs.his.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.FsQuestionAndAnswer;
+import com.fs.his.vo.FsQuestionAndAnswerVO;
+import com.fs.his.vo.OptionsVO;
+
+import java.util.List;
+
+/**
+ * 问答Service接口
+ *
+ * @author fs
+ * @date 2025-09-29
+ */
+public interface IFsQuestionAndAnswerService extends IService<FsQuestionAndAnswer>{
+    /**
+     * 查询问答
+     *
+     * @param id 问答主键
+     * @return 问答
+     */
+    FsQuestionAndAnswerVO selectFsQuestionAndAnswerById(Long id);
+
+    /**
+     * 查询问答列表
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 问答集合
+     */
+    List<FsQuestionAndAnswer> selectFsQuestionAndAnswerList(FsQuestionAndAnswer fsQuestionAndAnswer);
+
+    /**
+     * 新增问答
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 结果
+     */
+    int insertFsQuestionAndAnswer(FsQuestionAndAnswer fsQuestionAndAnswer);
+
+    /**
+     * 修改问答
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 结果
+     */
+    int updateFsQuestionAndAnswer(FsQuestionAndAnswer fsQuestionAndAnswer);
+
+    /**
+     * 批量删除问答
+     *
+     * @param ids 需要删除的问答主键集合
+     * @return 结果
+     */
+    int deleteFsQuestionAndAnswerByIds(Long[] ids);
+
+    /**
+     * 删除问答信息
+     *
+     * @param id 问答主键
+     * @return 结果
+     */
+    int deleteFsQuestionAndAnswerById(Long id);
+
+    List<OptionsVO> selectAllQuestionOptions();
+}

+ 9 - 0
fs-service/src/main/java/com/fs/his/service/IFsStorePaymentErrorService.java

@@ -0,0 +1,9 @@
+package com.fs.his.service;
+
+import com.fs.his.domain.FsStorePaymentError;
+
+import java.util.List;
+
+public interface IFsStorePaymentErrorService {
+    List<FsStorePaymentError> selectFsStorePaymentErrorList(FsStorePaymentError fsStorePaymentError);
+}

+ 117 - 0
fs-service/src/main/java/com/fs/his/service/IFsUserInformationCollectionService.java

@@ -0,0 +1,117 @@
+package com.fs.his.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.his.domain.FsUserInformationCollection;
+import com.fs.his.dto.FsUserInformationCollectionDTO;
+import com.fs.his.param.CollectionInfoConfirmParam;
+import com.fs.his.param.FsUserInformationCollectionListDParam;
+import com.fs.his.param.FsUserInformationCollectionParam;
+import com.fs.his.param.UserInformationDoctorType2Param;
+import com.fs.his.vo.FsUserInfoCollectionUVO;
+import com.fs.his.vo.FsUserInformationCollectionAndPatientVO;
+import com.fs.his.vo.FsUserInformationCollectionListDVO;
+import com.fs.his.vo.FsUserInformationCollectionVO;
+
+import java.util.List;
+
+/**
+ * 用户信息采集Service接口
+ *
+ * @author fs
+ * @date 2025-10-14
+ */
+public interface IFsUserInformationCollectionService extends IService<FsUserInformationCollection>{
+    /**
+     * 查询用户信息采集
+     *
+     * @param id 用户信息采集主键
+     * @return 用户信息采集
+     */
+    FsUserInformationCollection selectFsUserInformationCollectionById(Long id);
+
+
+
+    /**
+     * 查询用户信息采集列表
+     *
+     * @param fsUserInformationCollection 用户信息采集
+     * @return 用户信息采集集合
+     */
+    List<FsUserInformationCollection> selectFsUserInformationCollectionList(FsUserInformationCollection fsUserInformationCollection);
+
+    List<FsUserInformationCollection> selectFsUserInformationCollectionByDoctorType2(UserInformationDoctorType2Param userInformationDoctorType2Param);
+    List<FsUserInformationCollection> selectFsUserInformationCollectionByDoctorType1(UserInformationDoctorType2Param userInformationDoctorType2Param);
+
+    /**
+     * 新增用户信息采集
+     *
+     * @param fsUserInformationCollection 用户信息采集
+     * @return 结果
+     */
+    Long insertFsUserInformationCollection(FsUserInformationCollectionParam fsUserInformationCollection);
+
+    /**
+     * 修改用户信息采集
+     *
+     * @param fsUserInformationCollection 用户信息采集
+     * @return 结果
+     */
+    Long update(FsUserInformationCollectionParam fsUserInformationCollection);
+
+    /**
+     * 修改用户信息采集
+     *
+     * @param fsUserInformationCollection 用户信息采集
+     * @return 结果
+     */
+    Long updateFsUserInformationCollection(FsUserInformationCollectionParam fsUserInformationCollection);
+
+    /**
+     * 批量删除用户信息采集
+     *
+     * @param ids 需要删除的用户信息采集主键集合
+     * @return 结果
+     */
+    int deleteFsUserInformationCollectionByIds(Long[] ids);
+
+    /**
+     * 删除用户信息采集信息
+     *
+     * @param id 用户信息采集主键
+     * @return 结果
+     */
+    int deleteFsUserInformationCollectionById(Long id);
+
+
+    FsUserInformationCollectionVO getInfo(FsUserInformationCollection fsUserInformationCollection);
+
+    /**
+     * 查询医生端用户信息采集列表(只查询未关联套餐包的信息采集)
+     * @param param
+     * @return
+     */
+    List<FsUserInformationCollectionListDVO> selectFsUserInformationCollectionListDVO(FsUserInformationCollectionListDParam param);
+
+    FsUserInformationCollectionVO detail(Long id);
+
+    R getWxaCodePackageOrderUnLimit(Long collectionId);
+
+    R doctorConfirm(FsUserInformationCollection collection);
+    R doctorType2Confirm(FsUserInformationCollection collection);
+
+    FsUserInfoCollectionUVO info(Long id, Long userId);
+
+    R userConfirm(CollectionInfoConfirmParam param);
+
+    //自动退款
+    void autoRefund(FsUserInformationCollection collection);
+
+    FsUserInformationCollectionVO getCollectionByUserId(Long userId);
+
+    FsUserInformationCollectionDTO selectFsUserInformationCollectionDTOById(Long id);
+
+    int updatePackageOrderCode(FsUserInformationCollection fsUserInformationCollection);
+
+    FsUserInformationCollectionAndPatientVO selectFsUserInformationCollectionVoById(Long id);
+}

+ 61 - 0
fs-service/src/main/java/com/fs/his/service/IMerchantAppConfigService.java

@@ -0,0 +1,61 @@
+package com.fs.his.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.his.domain.MerchantAppConfig;
+
+/**
+ * 商户应用配置Service接口
+ *
+ * @author fs
+ * @date 2025-12-05
+ */
+public interface IMerchantAppConfigService extends IService<MerchantAppConfig>{
+    /**
+     * 查询商户应用配置
+     *
+     * @param id 商户应用配置主键
+     * @return 商户应用配置
+     */
+    MerchantAppConfig selectMerchantAppConfigById(Long id);
+
+    /**
+     * 查询商户应用配置列表
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 商户应用配置集合
+     */
+    List<MerchantAppConfig> selectMerchantAppConfigList(MerchantAppConfig merchantAppConfig);
+
+    /**
+     * 新增商户应用配置
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 结果
+     */
+    int insertMerchantAppConfig(MerchantAppConfig merchantAppConfig);
+
+    /**
+     * 修改商户应用配置
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 结果
+     */
+    int updateMerchantAppConfig(MerchantAppConfig merchantAppConfig);
+
+    /**
+     * 批量删除商户应用配置
+     *
+     * @param ids 需要删除的商户应用配置主键集合
+     * @return 结果
+     */
+    int deleteMerchantAppConfigByIds(Long[] ids);
+
+    /**
+     * 删除商户应用配置信息
+     *
+     * @param id 商户应用配置主键
+     * @return 结果
+     */
+    int deleteMerchantAppConfigById(Long id);
+}

+ 35 - 6
fs-service/src/main/java/com/fs/his/service/impl/FsInquiryOrderServiceImpl.java

@@ -32,6 +32,8 @@ import com.fs.company.util.WechatApi;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.event.TemplateBean;
 import com.fs.event.TemplateEvent;
 import com.fs.event.TemplateListenEnum;
@@ -121,6 +123,11 @@ public class FsInquiryOrderServiceImpl implements IFsInquiryOrderService
     private WxPayProperties wxPayProperties;
     @Autowired
     private RocketMQTemplate rocketMQTemplate;
+
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
     @Autowired
     private TzBankService tzBankService;
     @Autowired
@@ -331,9 +338,20 @@ public class FsInquiryOrderServiceImpl implements IFsInquiryOrderService
                     FsStorePayment payment=payments.get(0);
                     if(payment.getPayMode().equals("wx")){
                         WxPayConfig payConfig = new WxPayConfig();
-                        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                        payConfig.setAppId(fsPayConfig.getAppId());
+                        if (StringUtils.isBlank(param.getAppId())) {
+                            throw new IllegalArgumentException("appId不能为空");
+                        }
+                        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+                        if (fsCoursePlaySourceConfig == null) {
+                            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+                        }
+                        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                        if (merchantConfigId == null || merchantConfigId <= 0) {
+                            throw new CustomException("小程序没有配置商户信息");
+                        }
+                        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                        FsPayConfig fsPayConfig = com.hc.openapi.tool.fastjson.JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+                        payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
 
@@ -1500,9 +1518,20 @@ public class FsInquiryOrderServiceImpl implements IFsInquiryOrderService
 
                 if(payment.getPayMode().equals("wx")){
                     WxPayConfig payConfig = new WxPayConfig();
-                    SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                    FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                    payConfig.setAppId(fsPayConfig.getAppId());
+                    if (StringUtils.isBlank(param.getAppId())) {
+                        throw new IllegalArgumentException("appId不能为空");
+                    }
+                    FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+                    if (fsCoursePlaySourceConfig == null) {
+                        throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+                    }
+                    Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                    if (merchantConfigId == null || merchantConfigId <= 0) {
+                        throw new CustomException("小程序没有配置商户信息");
+                    }
+                    MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                    FsPayConfig fsPayConfig = com.hc.openapi.tool.fastjson.JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+                    payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                     payConfig.setMchId(fsPayConfig.getWxMchId());
                     payConfig.setMchKey(fsPayConfig.getWxMchKey());
 

+ 120 - 35
fs-service/src/main/java/com/fs/his/service/impl/FsPackageOrderServiceImpl.java

@@ -34,6 +34,8 @@ import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.dto.PackageConfigDTO;
@@ -102,6 +104,10 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
     @Autowired
     private WxPayProperties wxPayProperties;
     @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+    @Autowired
     IPayService payService;
     @Autowired
     private ConfigUtil configUtil;
@@ -175,6 +181,8 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
     @Autowired
     private WechatApi wechatApi;
 
+    @Autowired
+    private IFsUserInformationCollectionService fsUserInformationCollectionService;
     /**
      * 查询套餐订单
      *
@@ -470,7 +478,11 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                     }
                 } else {
                     payMoney = payPrice.multiply(new BigDecimal((100 - configDTO.getPayRate()))).divide(new BigDecimal(100));
-                    payMoney = new BigDecimal(payMoney.setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
+                    payMoney=new BigDecimal(payMoney.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
+                    // 如果小程序需要支付的金额小于0.01元,不能走物流代收,让走货到付款 xgb
+                    if (payMoney.compareTo(new BigDecimal("0.01")) < 0) {
+                        return R.error("物流代收计算支付金额为0,不允许选择物流代收");
+                    }
                 }
 //                if (sysConfig.getRetainer() != null && sysConfig.getRate() != null && sysConfig.getRate().compareTo(new BigDecimal(0)) > 0) {
 //                    if (payPrice.compareTo(new BigDecimal(100)) < 0) {
@@ -520,6 +532,9 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
     @Override
     public R createOrder(FsPackageOrderCreateParam param) {
         FsUser user=userService.selectFsUserByUserId(param.getUserId());
+        if (user == null){
+            return R.error("请重新登录重试");
+        }
         if(user.getStatus()!=1){
             return R.error("非法用户操作");
         }
@@ -632,7 +647,9 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         c.setTime(order.getStartTime());
         c.add(Calendar.DAY_OF_MONTH, fsPackage.getCycle());
         order.setFinishTime(c.getTime());
-        order.setFormJson(param.getFormJson());
+        if (param.getIsUserInformation() != 1){
+            order.setFormJson(param.getFormJson());
+        }
         order.setPackageJson(JSONUtil.toJsonStr(fsPackage));
         order.setCreateTime(new Date());
         if(patient!=null){
@@ -644,6 +661,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         order.setCycle(fsPackage.getCycle());
         order.setCostDiscountMoney(fsPackage.getTotalCostPrice().subtract(fsPackage.getTotalPrice()));
         if(fsPackageOrderMapper.insertFsPackageOrder(order)>0){
+            updateFsUserInformationCollectionByPackageOrder(param, order);
             String redisKey = String.valueOf(StrUtil.format("{}{}", FsConstants.REDIS_PACKAGE_ORDER_UNPAY, order.getOrderId()));
             redisCache.setCacheObject(redisKey,order.getOrderId(),30, TimeUnit.MINUTES);
             return R.ok().put("order",order);
@@ -653,6 +671,24 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         }
     }
 
+    private void updateFsUserInformationCollectionByPackageOrder(FsPackageOrderCreateParam param, FsPackageOrder order) {
+        if (param.getIsUserInformation()!=null && param.getIsUserInformation() == 1){
+            FsUserInformationCollection fsUserInformationCollection = fsUserInformationCollectionService.selectFsUserInformationCollectionById(param.getUserInformationId());
+            if (fsUserInformationCollection != null) {
+                String orderSn = "info" + order.getOrderSn();
+                fsUserInformationCollection.setPackageOrderCode(orderSn);
+                fsUserInformationCollection.setPackageOrderId(order.getOrderId());
+                fsUserInformationCollectionService.updatePackageOrderCode(fsUserInformationCollection);
+                //更新订单表
+                FsPackageOrder temp = new FsPackageOrder();
+                temp.setOrderId(order.getOrderId());
+                //添加前缀 区分信息采集订单
+                temp.setOrderSn(orderSn);
+                fsPackageOrderMapper.updateFsPackageOrder(temp);
+            }
+        }
+    }
+
     @Override
     @Transactional
     public R payOrder(FsPackageOrderPayParam param) {
@@ -883,7 +919,6 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
             List<FsStorePayment> payments = fsStorePaymentMapper.selectFsStorePaymentByPay(3,orderId);
             if(payments!=null&&payments.size()==1){
                 FsStorePayment payment=payments.get(0);
-                String json=configService.selectConfigByKey("his.pay");
                 if(payment.getPayMode().equals("wx")){
                     WxPayConfig payConfig = new WxPayConfig();
                     payConfig.setAppId(wxPayProperties.getAppId());
@@ -996,8 +1031,20 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
 
         FsUser user=userService.selectFsUserByUserId(param.getUserId());
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
         //金牛多小程序支付
         String openId = null;
@@ -1012,7 +1059,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = fsCoursePlaySourceConfig.getAppid();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -1033,7 +1080,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 }
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(fsPackageOrder.getOrderSn());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(fsPackageOrder.getPayMoney());
@@ -1047,12 +1094,12 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 storePayment.setUserId(user.getUserId());
                 storePayment.setStoreId(fsPackageOrder.getStoreId());
                 storePayment.setBusinessId(fsPackageOrder.getOrderId().toString());
+                storePayment.setAppId(appId);
+                storePayment.setMerConfigId(merchantAppConfig.getId());
                 if(storePaymentService.insertFsStorePayment(storePayment)>0){
-                    if (payConfigDTO.getType().equals("wx")) {
+                    if (merchantAppConfig.getMerchantType().equals("wx")) {
                         //创建微信订单
                         WxPayConfig payConfig = new WxPayConfig();
-                        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
                         payConfig.setAppId(appId);
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
@@ -1077,7 +1124,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                             e.printStackTrace();
                             throw new CustomException("支付失败" + e.getMessage());
                         }
-                    } else if (payConfigDTO.getType().equals("yb")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("yb")) {
                         WxJspayDTO p = new WxJspayDTO();
                         // 使用setter方法为对象赋值
                         p.setPayMoney(storePayment.getPayMoney().toString());
@@ -1098,7 +1145,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         } else {
                             throw new CustomException("支付失败");
                         }
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("package" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -1123,7 +1170,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    }else if (payConfigDTO.getType().equals("hf")) {
+                    }else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         logger.info("创建汇付订单");
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_MINIAPP");
@@ -1134,7 +1181,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         o.setAppId(appId);
                         //公司分账
                         try {
-                            HuiFuUtils.doDiv(o,fsPackageOrder.getCompanyId());
+                            HuiFuUtils.doDiv(o,fsPackageOrder.getCompanyId(),storePayment.getMerConfigId());
                             //存储分账明细
                             HuiFuUtils.saveDivItem(o, fsPackageOrder.getOrderSn(), storePayment.getPayCode());
                         } catch (Exception e) {
@@ -1228,8 +1275,18 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 if(StringUtils.isEmpty(payCode)){
                     return R.error("订单生成失败,请重试");
                 }
-                String json = configService.selectConfigByKey("his.pay");
-                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+                if (StringUtils.isBlank(param.getAppId())) {
+                    throw new IllegalArgumentException("appId不能为空");
+                }
+                FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+                if (fsCoursePlaySourceConfig == null) {
+                    throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+                }
+                Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                if (merchantConfigId == null || merchantConfigId <= 0) {
+                    throw new CustomException("小程序没有配置商户信息");
+                }
+                MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
                 String openId = null;
                 String appId = param.getAppId();
                 if (StringUtils.isNotBlank(appId)) {
@@ -1242,7 +1299,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         openId = fsUserWx.getOpenId();
                     }
                 } else {
-                    appId = payConfigDTO.getAppId();
+                    appId = merchantAppConfig.getAppId();
                     openId = Objects.isNull(user) ? "" : user.getMaOpenId();
                     if (StringUtils.isBlank(openId)){
                         Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -1257,7 +1314,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
 
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(fsPackageOrder.getOrderSn());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(fsPackageOrder.getPayMoney());
@@ -1271,11 +1328,13 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 storePayment.setUserId(user.getUserId());
                 storePayment.setStoreId(fsPackageOrder.getStoreId());
                 storePayment.setBusinessId(fsPackageOrder.getOrderId().toString());
+                storePayment.setAppId(appId);
+                storePayment.setMerConfigId(merchantAppConfig.getId());
                 if(storePaymentService.insertFsStorePayment(storePayment)>0){
 
-                    if (payConfigDTO.getType().equals("yb")) {
+                    if (merchantAppConfig.getMerchantType().equals("yb")) {
                         return R.error("支付暂不可用!");
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("package" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -1296,7 +1355,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    }else if (payConfigDTO.getType().equals("hf")) {
+                    }else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         logger.info("创建汇付订单");
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("A_NATIVE");
@@ -1337,8 +1396,19 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         //如果存在优惠券  判断优惠券是否已使用
         FsUser user=userService.selectFsUserByUserId(param.getUserId());
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
         String openId = null;
         String appId = param.getAppId();
@@ -1352,7 +1422,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -1375,7 +1445,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 }
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(fsPackageOrder.getOrderSn());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(fsPackageOrder.getPayMoney());
@@ -1389,10 +1459,12 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 storePayment.setUserId(user.getUserId());
                 storePayment.setStoreId(fsPackageOrder.getStoreId());
                 storePayment.setBusinessId(fsPackageOrder.getOrderId().toString());
+                storePayment.setAppId(appId);
+                storePayment.setMerConfigId(merchantAppConfig.getId());
                 if(storePaymentService.insertFsStorePayment(storePayment)>0){
-                    if (payConfigDTO.getType().equals("yb")) {
+                    if (merchantAppConfig.getMerchantType().equals("yb")) {
                         return R.error("支付暂不可用!");
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("package" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -1413,7 +1485,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    }else if (payConfigDTO.getType().equals("hf")) {
+                    }else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         logger.info("创建汇付订单");
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_JSAPI");
@@ -1456,8 +1528,19 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
         //如果存在优惠券  判断优惠券是否已使用
         FsUser user=userService.selectFsUserByUserId(param.getUserId());
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
         //金牛多小程序支付
         String openId = null;
@@ -1472,7 +1555,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -1495,7 +1578,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
 //                PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
                 FsStorePayment storePayment=new FsStorePayment();
                 storePayment.setStatus(0);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(fsPackageOrder.getOrderSn());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(fsPackageOrder.getPayMoney());
@@ -1509,11 +1592,13 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                 storePayment.setUserId(user.getUserId());
                 storePayment.setStoreId(fsPackageOrder.getStoreId());
                 storePayment.setBusinessId(fsPackageOrder.getOrderId().toString());
+                storePayment.setAppId(appId);
+                storePayment.setMerConfigId(merchantAppConfig.getId());
                 if(storePaymentService.insertFsStorePayment(storePayment)>0){
 
-                    if (payConfigDTO.getType().equals("yb")) {
+                    if (merchantAppConfig.getMerchantType().equals("yb")) {
                         return R.error("支付暂不可用!");
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("package" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -1534,7 +1619,7 @@ public class FsPackageOrderServiceImpl implements IFsPackageOrderService
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    }else if (payConfigDTO.getType().equals("hf")) {
+                    }else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         logger.info("创建汇付订单");
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("A_NATIVE");

+ 113 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsQuestionAndAnswerServiceImpl.java

@@ -0,0 +1,113 @@
+package com.fs.his.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.DateUtils;
+import com.fs.his.domain.FsQuestionAndAnswer;
+import com.fs.his.mapper.FsQuestionAndAnswerMapper;
+import com.fs.his.service.IFsQuestionAndAnswerService;
+import com.fs.his.vo.AnswerVO;
+import com.fs.his.vo.FsQuestionAndAnswerVO;
+import com.fs.his.vo.OptionsVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 问答Service业务层处理
+ *
+ * @author fs
+ * @date 2025-09-29
+ */
+@Service
+public class FsQuestionAndAnswerServiceImpl extends ServiceImpl<FsQuestionAndAnswerMapper, FsQuestionAndAnswer> implements IFsQuestionAndAnswerService {
+
+
+    @Autowired
+    private FsQuestionAndAnswerMapper fsQuestionAndAnswerMapper;
+    /**
+     * 查询问答
+     *
+     * @param id 问答主键
+     * @return 问答
+     */
+    @Override
+    public FsQuestionAndAnswerVO selectFsQuestionAndAnswerById(Long id)
+    {
+        FsQuestionAndAnswer fsQuestionAndAnswer = baseMapper.selectFsQuestionAndAnswerById(id);
+        FsQuestionAndAnswerVO vo = new FsQuestionAndAnswerVO();
+        vo.setQuestionName(fsQuestionAndAnswer.getQuestionName());
+        List<AnswerVO> answerVOS = JSON.parseArray(fsQuestionAndAnswer.getJsonInfo(), AnswerVO.class);
+        vo.setAnswers(answerVOS);
+        vo.setId(fsQuestionAndAnswer.getId());
+        return vo;
+    }
+
+    /**
+     * 查询问答列表
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 问答
+     */
+    @Override
+    public List<FsQuestionAndAnswer> selectFsQuestionAndAnswerList(FsQuestionAndAnswer fsQuestionAndAnswer)
+    {
+        return baseMapper.selectFsQuestionAndAnswerList(fsQuestionAndAnswer);
+    }
+
+    /**
+     * 新增问答
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 结果
+     */
+    @Override
+    public int insertFsQuestionAndAnswer(FsQuestionAndAnswer fsQuestionAndAnswer)
+    {
+        fsQuestionAndAnswer.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsQuestionAndAnswer(fsQuestionAndAnswer);
+    }
+
+    /**
+     * 修改问答
+     *
+     * @param fsQuestionAndAnswer 问答
+     * @return 结果
+     */
+    @Override
+    public int updateFsQuestionAndAnswer(FsQuestionAndAnswer fsQuestionAndAnswer)
+    {
+        fsQuestionAndAnswer.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsQuestionAndAnswer(fsQuestionAndAnswer);
+    }
+
+    /**
+     * 批量删除问答
+     *
+     * @param ids 需要删除的问答主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsQuestionAndAnswerByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsQuestionAndAnswerByIds(ids);
+    }
+
+    /**
+     * 删除问答信息
+     *
+     * @param id 问答主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsQuestionAndAnswerById(Long id)
+    {
+        return baseMapper.deleteFsQuestionAndAnswerById(id);
+    }
+
+    @Override
+    public List<OptionsVO> selectAllQuestionOptions() {
+        return fsQuestionAndAnswerMapper.selectAllQuestionOptions();
+    }
+}

+ 22 - 5
fs-service/src/main/java/com/fs/his/service/impl/FsStoreAfterSalesServiceImpl.java

@@ -31,6 +31,8 @@ import com.fs.company.service.impl.CompanyServiceImpl;
 import com.fs.company.vo.FsStoreOrderStatisticsVO;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.config.StoreConfig;
 import com.fs.erp.dto.BaseResponse;
@@ -95,6 +97,11 @@ public class FsStoreAfterSalesServiceImpl implements IFsStoreAfterSalesService {
     private FsStoreAfterSalesMapper fsStoreAfterSalesMapper;
     @Autowired
     private FsStoreAfterSalesLogsMapper fsStoreAfterSalesLogsMapper;
+
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
     @Autowired
     private FsStoreOrderMapper fsStoreOrderMapper;
     @Autowired
@@ -475,12 +482,22 @@ public class FsStoreAfterSalesServiceImpl implements IFsStoreAfterSalesService {
             if (reMoney.compareTo(payment.getPayMoney()) > 0) {
                 throw new CustomException("退款金额不能大于实际支付金额"); //退款金额不能大于实际支付金额
             }
-            String json = configService.selectConfigByKey("his.pay");
+            if (StringUtils.isBlank(payment.getAppId())) {
+                throw new IllegalArgumentException("appId不能为空");
+            }
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+            if (fsCoursePlaySourceConfig == null) {
+                throw new CustomException("未找到appId对应的小程序配置: " + payment.getAppId());
+            }
+            Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+            if (merchantConfigId == null || merchantConfigId <= 0) {
+                throw new CustomException("小程序没有配置商户信息");
+            }
+            MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+            FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
             if (payment.getPayMode().equals("wx")) {
                 WxPayConfig payConfig = new WxPayConfig();
-                SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                payConfig.setAppId(fsPayConfig.getAppId());
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                 payConfig.setMchId(fsPayConfig.getWxMchId());
                 payConfig.setMchKey(fsPayConfig.getWxMchKey());
                 payConfig.setKeyPath(wxPayProperties.getKeyPath());
@@ -762,7 +779,7 @@ public class FsStoreAfterSalesServiceImpl implements IFsStoreAfterSalesService {
         fsStoreAfterSalesLogsMapper.insertFsStoreAfterSalesLogs(logs);
         fsStoreOrderLogsService.create(order.getOrderId(), FsStoreOrderLogEnum.REFUND_ORDER_APPLY.getValue(),
                 FsStoreOrderLogEnum.REFUND_ORDER_APPLY.getDesc());
-        if (order.getExtendOrderId() != null) {
+        if (order.getExtendOrderId() != null && !"".equals(order.getExtendOrderId())) {
             ErpRefundUpdateRequest request = new ErpRefundUpdateRequest();
             request.setTid(order.getOrderCode());
             request.setOid(order.getOrderCode());

+ 82 - 65
fs-service/src/main/java/com/fs/his/service/impl/FsStoreOrderServiceImpl.java

@@ -26,9 +26,12 @@ import com.fs.company.service.ICompanyUserService;
 import com.fs.company.util.WechatApi;
 import com.fs.company.vo.FsStoreOrderStatisticsVO;
 import com.fs.company.vo.FsStoreProductStatisticsVO;
+import com.fs.config.ai.AiHostProper;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
 import com.fs.erp.dto.df.*;
@@ -62,6 +65,7 @@ import com.fs.huifuPay.sdk.opps.core.utils.HuiFuUtils;
 import com.fs.huifuPay.service.HuiFuService;
 import com.fs.im.dto.*;
 import com.fs.im.service.IImService;
+import com.fs.im.service.OpenIMService;
 import com.fs.qw.domain.QwExternalContact;
 import com.fs.qw.domain.QwUser;
 import com.fs.qw.mapper.QwExternalContactMapper;
@@ -154,6 +158,11 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Autowired
     private FsPatientMapper fsPatientMapper;
 
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+
     @Autowired
     private FsStoreOrderScrmMapper fsStoreOrderScrmMapper;
 
@@ -268,6 +277,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     @Autowired
     private ApplicationEventPublisher publisher;
 
+    @Autowired
+    AiHostProper aiHostProper;
+
     @Autowired
     private IFsUserWatchService fsUserWatchService;
     @Autowired
@@ -299,11 +311,13 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
     private com.fs.gtPush.service.uniPush2Service uniPush2Service;
 
     @Autowired
-    private WechatApi wechatApi;
+    private FsUserInformationCollectionMapper fsUserInformationCollectionMapper;
+    @Autowired
+    private OpenIMService openIMService;
 
     //ERP 类型到服务的映射
     private Map<Integer, IErpOrderService> erpServiceMap;
-
+    @Autowired
     private IFsStoreOrderScrmService orderScrmService;
 
     @PostConstruct
@@ -363,18 +377,17 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         //推送修改的互联网医院订单地址到聚水潭ERP
         try {
             pushOrderAddressToErp(fsStoreOrder);
-        } catch (Exception e) {
+        }catch (Exception e){
             log.error("修改互联网医院订单地址推送到聚水潭ERP失败,orderId: {}", fsStoreOrder.getOrderId(), e);
         }
         return fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder);
     }
-
     /**
      * 推送修改订单的最新地址到 ERP
      *
      * @param partialOrder 前端传入的部分订单对象,必须包含 id、userAddress
      */
-    public void pushOrderAddressToErp(FsStoreOrder partialOrder) {
+    public void pushOrderAddressToErp(FsStoreOrder partialOrder){
         if (partialOrder == null || partialOrder.getOrderId() == null) {
             log.info("传入订单为空或ID缺失,跳过ERP同步");
             return;
@@ -393,7 +406,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             return;
         }
         //目前只针对聚水潭ERP推送最新的修改地址
-        if (erpType != 5) {
+        if (erpType != 5){
             return;
         }
         // 2. 从数据库获取完整订单(用于补全必要字段;当前是修改商城订单接口,查询fs_store_order_scrm表)
@@ -408,22 +421,22 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             return;
         }
         // 3. 构造用于ERP推送的订单对象:订单地址用传入的新值
-        if (StrUtil.isBlank(partialOrder.getUserAddress())) {
+        if (StrUtil.isBlank(partialOrder.getUserAddress())){
             log.error("修改互联网医院订单地址为空,orderId: {}", partialOrder.getOrderId());
             return;
         }
         dbOrder.setUserAddress(partialOrder.getUserAddress());
         // 4. 构建 ERP 订单对象
         try {
-            ErpOrder erpOrder = buildErpOrder(dbOrder, sysConfig);
+        ErpOrder erpOrder = buildErpOrder(dbOrder,sysConfig);
 
-            // 5. 调用对应 ERP 服务(当前是聚水潭ERP)
-            IErpOrderService erpService = erpServiceMap.get(erpType);
+        // 5. 调用对应 ERP 服务(当前是聚水潭ERP)
+        IErpOrderService erpService = erpServiceMap.get(erpType);
 
-            //执行互联网医院订单推送逻辑
-            ErpOrderResponse response = erpService.addOrder(erpOrder);
-            log.info("ERP地址推送结果 - 互联网医院订单: {}, ERP类型: {}, 成功: {}, 外部单号: {}",
-                    dbOrder.getOrderCode(), erpType, response.getSuccess(), response.getCode());
+        //执行互联网医院订单推送逻辑
+        ErpOrderResponse response = erpService.addOrder(erpOrder);
+        log.info("ERP地址推送结果 - 互联网医院订单: {}, ERP类型: {}, 成功: {}, 外部单号: {}",
+                dbOrder.getOrderCode(), erpType, response.getSuccess(), response.getCode());
         } catch (Exception e) {
             log.error("推送修改互联网医院订单地址到ERP失败,orderId: {}", partialOrder.getOrderId(), e);
         }
@@ -518,7 +531,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         //userPhone 电话处理
         String userPhone = fsStoreOrder.getUserPhone();
         if (StringUtils.isNotBlank(userPhone)) {
-            if (!userPhone.contains("*")) {
+            if (!userPhone.contains("*")){
                 fsStoreOrder.setUserPhone(userPhone);
             } else {
                 userPhone = null;
@@ -527,7 +540,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         }
         String userAddress = fsStoreOrder.getUserAddress();
         if (StringUtils.isNotBlank(userAddress)) {
-            if (!userAddress.contains("*")) {
+            if (!userAddress.contains("*")){
                 fsStoreOrder.setUserAddress(userAddress);
             } else {
                 userAddress = null;
@@ -536,29 +549,29 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
         }
         FsStoreOrder oldOrder = fsStoreOrderMapper.selectFsStoreOrderByOrderId(fsStoreOrder.getOrderId());
         if (oldOrder == null) return R.error("修改订单不存在");
-        if (StringUtils.isNotBlank(userAddress)) {
+        if (StringUtils.isNotBlank(userAddress)){
             if (userAddress.equals(oldOrder.getUserAddress())) {
                 userAddress = null;
             }
         }
-        if (StringUtils.isNotBlank(userAddress) || StringUtils.isNotBlank(userPhone)) {
+        if (StringUtils.isNotBlank(userAddress) || StringUtils.isNotBlank(userPhone)){
             Integer status = fsStoreOrder.getStatus();
-            if (status == null) {
+            if (status == null){
                 status = oldOrder.getStatus();
-            } else if (status.equals(FsStoreOrderStatusEnum.STATUS_6.getValue())) {
+            } else if (status.equals(FsStoreOrderStatusEnum.STATUS_6.getValue())){
                 status = oldOrder.getStatus();
             }
             if (Objects.equals(FsStoreOrderStatusEnum.STATUS_1.getValue(), status) ||
                     (Objects.equals(FsStoreOrderStatusEnum.STATUS_2.getValue(), status) && StringUtils.isBlank(oldOrder.getExtendOrderId()))
-            ) {
-                fsStoreOrder.setUserAddress(StringUtils.isBlank(userAddress) ? null : userAddress);
-                fsStoreOrder.setUserPhone(StringUtils.isBlank(userPhone) ? null : userPhone);
+                ) {
+                fsStoreOrder.setUserAddress(StringUtils.isBlank(userAddress)?null:userAddress);
+                fsStoreOrder.setUserPhone(StringUtils.isBlank(userPhone)?null:userPhone);
             } else {
                 return R.error("该订单状态不支持修改收货地址/电话");
             }
         }
         fsStoreOrder.setUpdateTime(DateUtils.getNowDate());
-        return fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder) > 0 ? R.ok() : R.error();
+        return fsStoreOrderMapper.updateFsStoreOrder(fsStoreOrder)>0?R.ok():R.error();
     }
 
     /**
@@ -1800,23 +1813,6 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
             }
             storeOrder.setPayTime(new Date());
             fsStoreOrderMapper.updateFsStoreOrder(storeOrder);
-
-            try {
-                Long companyUserId = order.getCompanyUserId();
-                if (companyUserId != null) {
-                    // 从company_user表查出openid
-                    String mpOpenId = companyUserService.selectMpOpenIdByCompanyUserId(companyUserId);
-                    if (StringUtils.isNotEmpty(mpOpenId)) {
-                        wechatApi.sendTemplateMessage(wechatApi.getAccessToken(), mpOpenId, storeOrder.getPayTime(), order.getUserName(), order.getPayPrice(), order.getOrderCode());
-                        log.info("支付成功模板消息已发送给销售: {}", companyUserId);
-                    } else {
-                        log.warn("未找到 companyUserId={} 的 openId,跳过模板消息发送", companyUserId);
-                    }
-                }
-            } catch (Exception msgEx) {
-                log.error("支付成功后发送模板消息失败,订单号:{},原因:{}", order.getOrderCode(), msgEx.getMessage());
-            }
-
             try {
                 //更新用户下单次数(获取阈值,当订单总价大于等于阈值,则下单次数+1)
                 BigDecimal minThreshold = toBigDecimal(config.get("minimumThreshold"), BigDecimal.ZERO);
@@ -3062,8 +3058,18 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 //        }
         FsUser user = userService.selectFsUserByUserId(param.getUserId());
         //在线支付
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
         String openId = null;
         String appId = param.getAppId();
         if (StringUtils.isNotBlank(appId)) {
@@ -3076,14 +3082,14 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
-            if (StringUtils.isBlank(openId)) {
+            if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                         .eq(FsUserWx::getFsUserId, param.getUserId())
                         .eq(FsUserWx::getAppId, appId);
                 FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
-                if (Objects.nonNull(fsUserWx)) {
+                if (Objects.nonNull(fsUserWx)){
                     openId = fsUserWx.getOpenId();
                 }
             }
@@ -3102,7 +3108,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 FsStorePayment storePayment = new FsStorePayment();
                 storePayment.setStatus(0);
                 storePayment.setPayCode(payCode);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setPayMoney(order.getPayMoney());
                 storePayment.setBusinessCode(order.getOrderCode());
                 storePayment.setCreateTime(new Date());
@@ -3115,20 +3121,21 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 storePayment.setCompanyUserId(order.getCompanyUserId());
                 storePayment.setStoreId(order.getStoreId());
                 storePayment.setBusinessId(order.getOrderId().toString());
+                storePayment.setAppId(appId);
+                storePayment.setMerConfigId(merchantAppConfig.getId());
                 if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
 
-                    if (payConfigDTO.getType().equals("wx")) {
+                    if (merchantAppConfig.getMerchantType().equals("wx")) {
                         //创建微信订单
                         WxPayConfig payConfig = new WxPayConfig();
-                        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                        payConfig.setAppId(fsPayConfig.getAppId());
+                        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+                        payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
                         payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
                         payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
                         payConfig.setKeyPath(null);
-                        payConfig.setNotifyUrl(wxPayProperties.getNotifyUrl());
+                        payConfig.setNotifyUrl(fsPayConfig.getNotifyUrlScrm());
                         wxPayService.setConfig(payConfig);
                         WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
                         orderRequest.setOpenid(openId);//公众号支付提供用户openid
@@ -3146,7 +3153,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                             e.printStackTrace();
                             throw new CustomException("支付失败" + e.getMessage());
                         }
-                    } else if (payConfigDTO.getType().equals("yb")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("yb")) {
                         WxJspayDTO p = new WxJspayDTO();
                         // 使用setter方法为对象赋值
                         p.setPayMoney(storePayment.getPayMoney().toString());
@@ -3166,7 +3173,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                         } else {
                             throw new CustomException("支付失败");
                         }
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("store" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -3191,7 +3198,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    } else if (payConfigDTO.getType().equals("hf")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("T_MINIAPP");
                         o.setOpenid(openId);
@@ -3228,8 +3235,18 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
         FsUser user = userService.selectFsUserByUserId(param.getUserId());
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
 
         String openId = null;
         String appId = param.getAppId();
@@ -3243,14 +3260,14 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
-            if (StringUtils.isBlank(openId)) {
+            if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                         .eq(FsUserWx::getFsUserId, param.getUserId())
                         .eq(FsUserWx::getAppId, appId);
                 FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
-                if (Objects.nonNull(fsUserWx)) {
+                if (Objects.nonNull(fsUserWx)){
                     openId = fsUserWx.getOpenId();
                 }
             }
@@ -3260,7 +3277,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
 
             if (order.getPayMoney().compareTo(new BigDecimal(0)) == 0) {
                 IFsStoreOrderService fsStoreOrderService1 = (IFsStoreOrderService) AopContext.currentProxy();
-                fsStoreOrderService1.payConfirm(order.getOrderCode(), "", "", "", 2, null, null);
+                fsStoreOrderService1.payConfirm(order.getOrderCode(), "", "", "", 2,null,null);
                 return R.ok().put("data", param.getOrderId()).put("isPay", "1");
             } else {
                 //在线支付
@@ -3273,7 +3290,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 FsStorePayment storePayment = new FsStorePayment();
                 storePayment.setStatus(0);
                 storePayment.setPayCode(payCode);
-                storePayment.setPayMode(payConfigDTO.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setPayMoney(order.getPayMoney());
                 storePayment.setBusinessCode(order.getOrderCode());
                 storePayment.setCreateTime(new Date());
@@ -3287,9 +3304,9 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                 storePayment.setStoreId(order.getStoreId());
                 storePayment.setBusinessId(order.getOrderId().toString());
                 if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
-                    if (payConfigDTO.getType().equals("yb")) {
+                    if (merchantAppConfig.getMerchantType().equals("yb")) {
                         return R.error("支付暂不可用!");
-                    } else if (payConfigDTO.getType().equals("tz")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                         PayCreateOrder o = new PayCreateOrder();
                         o.setOrderNo("store" + storePayment.getPayCode()); // 业务系统订单号
                         o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -3309,7 +3326,7 @@ public class FsStoreOrderServiceImpl implements IFsStoreOrderService {
                         mt.setTradeNo(result.getBody().getOrderFlowNo());
                         fsStorePaymentMapper.updateFsStorePayment(mt);
                         return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                    } else if (payConfigDTO.getType().equals("hf")) {
+                    } else if (merchantAppConfig.getMerchantType().equals("hf")) {
                         HuiFuCreateOrder o = new HuiFuCreateOrder();
                         o.setTradeType("A_NATIVE");
                         o.setOpenid(openId);

+ 21 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentErrorServiceImpl.java

@@ -0,0 +1,21 @@
+package com.fs.his.service.impl;
+
+import com.fs.his.domain.FsStorePaymentError;
+import com.fs.his.mapper.FsStorePaymentErrorMapper;
+import com.fs.his.service.IFsStorePaymentErrorService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class FsStorePaymentErrorServiceImpl implements IFsStorePaymentErrorService {
+    @Autowired
+    private FsStorePaymentErrorMapper fsStorePaymentErrorMapper;
+
+    public List<FsStorePaymentError> selectFsStorePaymentErrorList(FsStorePaymentError fsStorePaymentError){
+        return fsStorePaymentErrorMapper.selectFsStorePaymentErrorList(fsStorePaymentError);
+    }
+
+
+}

+ 133 - 46
fs-service/src/main/java/com/fs/his/service/impl/FsStorePaymentServiceImpl.java

@@ -41,6 +41,8 @@ import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.config.RedPacketConfig;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.course.service.IFsUserCourseOrderService;
 import com.fs.course.service.IFsUserVipOrderService;
@@ -136,6 +138,11 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
     private FsStorePaymentMapper fsStorePaymentMapper;
     @Autowired
     private FsStorePaymentScrmMapper fsStorePaymentScrmMapper;
+
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
     @Autowired
     private TzBankService tzBankService;
     @Autowired
@@ -154,8 +161,8 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
     private IFsUserVipOrderService vipOrderService;
     @Autowired
     SysConfigMapper sysConfigMapper;
-    @Autowired
-    private WxPayProperties wxPayProperties;
+//    @Autowired
+//    private WxPayProperties wxPayProperties;
     @Autowired
     private WxPayService wxPayService;
     @Autowired
@@ -214,6 +221,12 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
     @Autowired
     private ICompanyDivItemService companyDivItemService;
 
+    @Value("${cloud_host.company_name}")
+    private String signProjectName;
+
+    @Autowired
+    private FsStorePaymentErrorMapper fsStorePaymentErrorMapper;
+
     /**
      * 红包账户锁
      */
@@ -385,6 +398,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             V2TradePaymentScanpayQueryRequest request = new V2TradePaymentScanpayQueryRequest();
             request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(fsStorePayment.getCreateTime()));
             request.setOrgHfSeqId(fsStorePayment.getTradeNo());
+            request.setAppId(fsStorePayment.getAppId());
             HuiFuQueryOrderResult queryOrderResult = null;
             try {
                 queryOrderResult = huiFuService.queryOrder(request);
@@ -435,12 +449,23 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
 
             if(fsStorePayment.getPayMode().equals("wx")){
                 WxPayConfig payConfig = new WxPayConfig();
-                SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                payConfig.setAppId(fsPayConfig.getAppId());
+                if (StringUtils.isBlank(fsStorePayment.getAppId())) {
+                    throw new IllegalArgumentException("appId不能为空");
+                }
+                FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(fsStorePayment.getAppId());
+                if (fsCoursePlaySourceConfig == null) {
+                    throw new CustomException("未找到appId对应的小程序配置: " + fsStorePayment.getAppId());
+                }
+                Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                if (merchantConfigId == null || merchantConfigId <= 0) {
+                    throw new CustomException("小程序没有配置商户信息");
+                }
+                MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                FsPayConfig fsPayConfig = com.alibaba.fastjson.JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                 payConfig.setMchId(fsPayConfig.getWxMchId());
                 payConfig.setMchKey(fsPayConfig.getWxMchKey());
-                payConfig.setKeyPath(wxPayProperties.getKeyPath());
+                payConfig.setKeyPath(fsPayConfig.getKeyPath());
                 payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
                 payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
                 wxPayService.setConfig(payConfig);
@@ -517,6 +542,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
                 request.setReqSeqId("refund-"+fsStorePayment.getPayCode());
                 Map<String, Object> extendInfoMap = new HashMap<>();
                 extendInfoMap.put("org_req_seq_id", orderType+"-"+fsStorePayment.getPayCode());
+                request.setAppId(fsStorePayment.getAppId());
                 request.setExtendInfo(extendInfoMap);
                 //处理分账退款
                 //1.判断是否是全额退款
@@ -1175,9 +1201,23 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             throw new CustomException("用户不存在");
         }
 
-        String json = configService.selectConfigByKey("his.pay");
-        logger.debug("支付配置 his.pay: {}", json);
-        FsPayConfig payConfig = JSONUtil.toBean(json, FsPayConfig.class);
+        if (StringUtils.isBlank(payOrderParam.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payOrderParam.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + payOrderParam.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig payConfig =JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+        payConfig.setType(merchantAppConfig.getMerchantType());
+        payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
+        logger.debug("支付配置 his.pay: {}", payConfig);
+//        FsPayConfig payConfig = JSONUtil.toBean(json, FsPayConfig.class);
 
         if (isWechatPayment(payOrderParam.getPaymentMethod())) {
             String openId = getOpenIdForPaymentMethod(user, payOrderParam.getPaymentMethod(), payConfig);
@@ -1416,7 +1456,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         payConfig.setSubAppId(StringUtils.trimToNull(null));
         payConfig.setSubMchId(StringUtils.trimToNull(null));
         payConfig.setKeyPath(null);
-        payConfig.setNotifyUrl(wxPayProperties.getNotifyUrl());
+        payConfig.setNotifyUrl(fsPayConfig.getNotifyUrlScrm());
         return payConfig;
     }
 
@@ -1600,8 +1640,19 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
             return R.error("用户不存在!");
         }
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
         String openId = null;
         String appId = param.getAppId();
         if (StringUtils.isNotBlank(appId)) {
@@ -1614,7 +1665,7 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -1659,40 +1710,76 @@ public class FsStorePaymentServiceImpl implements IFsStorePaymentService {
         storePayment.setRemark("商城收款订单支付");
         storePayment.setOpenId(openId);
         storePayment.setUserId(user.getUserId());
-        storePayment.setPayMode("hf");//目前微信收款仅支持汇付
-        fsStorePaymentMapper.insertFsStorePayment(storePayment);
-
-        //汇付支付
-        HuiFuCreateOrder o = new HuiFuCreateOrder();
-        o.setTradeType("T_MINIAPP");
-        o.setOpenid(openId);
-        o.setReqSeqId("payment-"+storePayment.getPayCode());
-        o.setTransAmt(storePayment.getPayMoney().toString());
-        o.setGoodsDesc("商城订单支付");
-        o.setAppId(appId);
-        //公司分账
-        try {
-            HuiFuUtils.doDiv(o,company.getCompanyId());
-            //存储分账明细
-            HuiFuUtils.saveDivItem(o, storePayment.getPayCode(), storePayment.getPayCode());
-        } catch (Exception e) {
-            logger.error("-------------微信收款分账出错:{}", e.getMessage());
-        }
-        HuifuCreateOrderResult result = huiFuService.createOrder(o);
-        if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
-            FsStorePayment mt=new FsStorePayment();
-            mt.setPaymentId(storePayment.getPaymentId());
-            mt.setTradeNo(result.getHf_seq_id());
-            mt.setAppId(appId);
-            fsStorePaymentMapper.updateFsStorePayment(mt);
-            Map<String, Object> resultMap = com.alibaba.fastjson.JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {});
-            String s = (String) resultMap.get("package");
-            resultMap.put("packageValue",s);
-            return R.ok().put("result",resultMap);
-        }
-        else{
-            return R.error(result.getResp_desc());
+        storePayment.setPayMode(merchantAppConfig.getMerchantType());
+
+        if (fsStorePaymentMapper.insertFsStorePayment(storePayment) > 0) {
+            if (merchantAppConfig.getMerchantType().equals("wx")) {
+                //创建微信订单
+                WxPayConfig payConfig = new WxPayConfig();
+                payConfig.setAppId(appId);
+                payConfig.setMchId(fsPayConfig.getWxMchId());
+                payConfig.setMchKey(fsPayConfig.getWxMchKey());
+                payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                payConfig.setKeyPath(null);
+                payConfig.setNotifyUrl(fsPayConfig.getNotifyUrlScrm());
+                wxPayService.setConfig(payConfig);
+                WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
+                orderRequest.setOpenid(openId);//公众号支付提供用户openid
+                orderRequest.setBody("拍商品订单支付");
+                orderRequest.setOutTradeNo("product-" + storePayment.getPayCode());
+                orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(storePayment.getPayMoney().toString()));//测试
+                //orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(money));//测试
+                orderRequest.setTradeType("JSAPI");
+                orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+                //调用统一下单接口,获取"预支付交易会话标识"
+                try {
+                    WxPayMpOrderResult orderResult = wxPayService.createOrder(orderRequest);
+                    return R.ok().put("data", orderResult).put("type", "wx").put("isPay", 0);
+                } catch (WxPayException e) {
+                    e.printStackTrace();
+                    throw new CustomException("支付失败" + e.getMessage());
+                }
+            } else if (merchantAppConfig.getMerchantType().equals("hf")) {
+
+                //汇付支付
+                HuiFuCreateOrder o = new HuiFuCreateOrder();
+                o.setTradeType("T_MINIAPP");
+                o.setOpenid(openId);
+                o.setReqSeqId("payment-"+storePayment.getPayCode());
+                o.setTransAmt(storePayment.getPayMoney().toString());
+                o.setGoodsDesc("商城订单支付");
+                o.setAppId(appId);
+                //公司分账
+                try {
+                    HuiFuUtils.doDiv(o,company.getCompanyId(), storePayment.getMerConfigId());
+                    //存储分账明细
+                    HuiFuUtils.saveDivItem(o, storePayment.getPayCode(), storePayment.getPayCode());
+                } catch (Exception e) {
+                    logger.error("-------------微信收款分账出错:{}", e.getMessage());
+                }
+                HuifuCreateOrderResult result = huiFuService.createOrder(o);
+
+                if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
+                    FsStorePayment mt=new FsStorePayment();
+                    mt.setPaymentId(storePayment.getPaymentId());
+                    mt.setTradeNo(result.getHf_seq_id());
+                    mt.setAppId(appId);
+                    fsStorePaymentMapper.updateFsStorePayment(mt);
+                    Map<String, Object> resultMap = com.alibaba.fastjson.JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {});
+                    String s = (String) resultMap.get("package");
+                    resultMap.put("packageValue",s);
+                    return R.ok().put("result",resultMap);
+                }
+                else{
+                    return R.error(result.getResp_desc());
+                }
+            }
+        }else {
+            return R.error("新增订单失败!");
         }
+        return R.error("支付失败!");
+
     }
 
 }

+ 1094 - 0
fs-service/src/main/java/com/fs/his/service/impl/FsUserInformationCollectionServiceImpl.java

@@ -0,0 +1,1094 @@
+package com.fs.his.service.impl;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.core.domain.R;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.exception.CustomException;
+import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.company.domain.CompanyUser;
+import com.fs.company.domain.CompanyUserUser;
+import com.fs.company.mapper.CompanyUserMapper;
+import com.fs.company.mapper.CompanyUserUserMapper;
+import com.fs.company.service.ICompanyService;
+import com.fs.core.config.WxMaConfiguration;
+import com.fs.core.config.WxPayProperties;
+import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
+import com.fs.his.config.FsSysConfig;
+import com.fs.his.domain.*;
+import com.fs.his.dto.FsUserInformationCollectionDTO;
+import com.fs.his.enums.FsPackageOrderStatusEnum;
+import com.fs.his.enums.FsStoreOrderStatusEnum;
+import com.fs.his.mapper.*;
+import com.fs.his.param.CollectionInfoConfirmParam;
+import com.fs.his.param.FsUserInformationCollectionListDParam;
+import com.fs.his.param.FsUserInformationCollectionParam;
+import com.fs.his.param.UserInformationDoctorType2Param;
+import com.fs.his.service.*;
+import com.fs.his.utils.ConfigUtil;
+import com.fs.his.vo.*;
+import com.fs.huifuPay.domain.HuiFuRefundResult;
+import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentDelaytransConfirmrefundRequest;
+import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayRefundRequest;
+import com.fs.huifuPay.service.HuiFuService;
+import com.fs.im.service.OpenIMService;
+import com.fs.system.oss.CloudStorageService;
+import com.fs.system.oss.OSSFactory;
+import com.fs.tzBankPay.TzBankService.TzBankService;
+import com.fs.tzBankPay.doman.RefundParam;
+import com.fs.tzBankPay.doman.RefundResult;
+import com.fs.tzBankPay.doman.TzBankResult;
+import com.fs.ybPay.dto.RefundDTO;
+import com.fs.ybPay.service.IPayService;
+import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
+import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundQueryResult;
+import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
+import com.github.binarywang.wxpay.config.WxPayConfig;
+import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.WxPayService;
+import com.google.common.collect.Lists;
+import me.chanjar.weixin.common.error.WxErrorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 用户信息采集Service业务层处理
+ *
+ * @author fs
+ * @date 2025-10-14
+ */
+@Service
+public class FsUserInformationCollectionServiceImpl extends ServiceImpl<FsUserInformationCollectionMapper, FsUserInformationCollection> implements IFsUserInformationCollectionService {
+    Logger logger= LoggerFactory.getLogger(getClass());
+
+
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+
+    @Autowired
+    private WxPayProperties wxPayProperties;
+
+    @Autowired
+    private WxPayService wxPayService;
+
+    @Autowired
+    IPayService payService;
+
+    @Autowired
+    private TzBankService tzBankService;
+
+    @Autowired
+    private HuiFuService huiFuService;
+
+    @Autowired
+    private CompanyUserMapper companyUserMapper;
+
+    @Autowired
+    private FsDoctorMapper doctorMapper;
+
+    @Autowired
+    private IFsDoctorService iFsDoctorService;
+
+    @Autowired
+    private IFsQuestionAndAnswerService questionAndAnswerService;
+
+    @Autowired
+    private FsUserInformationCollectionMapper fsUserInformationCollectionMapper;
+
+    @Autowired
+    private ConfigUtil configUtil;
+
+
+    @Autowired
+    RedisCache redisCache;
+
+    @Autowired
+    private FsPackageMapper packageMapper;
+
+    @Autowired
+    private IFsStoreOrderService storeOrderService;
+
+    @Autowired
+    private FsPackageOrderMapper packageOrderMapper;
+    @Autowired
+    private FsPatientMapper fsPatientMapper;
+
+    @Autowired
+    private FsPrescribeMapper fsPrescribeMapper;
+
+    @Autowired
+    private IFsPrescribeService prescribeService;
+
+    @Autowired
+    private ICompanyService companyService;
+
+    @Autowired
+    private FsStorePaymentMapper fsStorePaymentMapper;
+
+    @Autowired
+    private FsStoreOrderLogsMapper fsStoreOrderLogsMapper;
+
+    @Autowired
+    private IFsInquiryOrderService fsInquiryOrderService;
+    @Autowired
+    private OpenIMService openIMService;
+    @Autowired
+    private CompanyUserUserMapper companyUserUserMapper;
+    @Autowired
+    private FsPackageMapper fsPackageMapper;
+
+    /**
+     * 查询用户信息采集
+     *
+     * @param id 用户信息采集主键
+     * @return 用户信息采集
+     */
+    @Override
+    public FsUserInformationCollection selectFsUserInformationCollectionById(Long id)
+    {
+        return baseMapper.selectFsUserInformationCollectionById(id);
+    }
+
+    /**
+     * 查询用户信息采集列表
+     *
+     * @param fsUserInformationCollection 用户信息采集
+     * @return 用户信息采集
+     */
+    @Override
+    public List<FsUserInformationCollection> selectFsUserInformationCollectionList(FsUserInformationCollection fsUserInformationCollection)
+    {
+        return baseMapper.selectFsUserInformationCollectionList(fsUserInformationCollection);
+    }
+
+    @Override
+    public List<FsUserInformationCollection> selectFsUserInformationCollectionByDoctorType2(UserInformationDoctorType2Param userInformationDoctorType2Param) {
+        return fsUserInformationCollectionMapper.selectFsUserInformationCollectionByDoctorType2(userInformationDoctorType2Param);
+
+    }
+    @Override
+    public List<FsUserInformationCollection> selectFsUserInformationCollectionByDoctorType1(UserInformationDoctorType2Param userInformationDoctorType2Param) {
+        return fsUserInformationCollectionMapper.selectFsUserInformationCollectionByDoctorType1(userInformationDoctorType2Param);
+
+    }
+
+    /**
+     * 新增用户信息采集
+     *
+     * @param param 用户信息采集
+     * @return 结果
+     */
+    @Override
+    public Long insertFsUserInformationCollection(FsUserInformationCollectionParam param)
+    {
+
+        FsUserInformationCollection fsUserInformationCollection = getFsUserInformationCollection(param);
+        fsUserInformationCollection.setCreateTime(DateUtils.getNowDate());
+        baseMapper.insertFsUserInformationCollection(fsUserInformationCollection);
+        return fsUserInformationCollection.getId();
+    }
+
+    /**
+     * 修改用户信息采集
+     *
+     * @param param 用户信息采集
+     * @return 结果
+     */
+    @Override
+    public Long update(FsUserInformationCollectionParam param)
+    {
+        if (param.getId() == null || param.getId() < 1) {
+            throw new CustomException("参数错误");
+        }
+        FsUserInformationCollection collection = fsUserInformationCollectionMapper.selectFsUserInformationCollectionById(param.getId());
+        if (collection == null) {
+            throw new CustomException("没有用户采集信息");
+        }
+        if (collection.getUserConfirm() == 1 && collection.getUserConfirm2() == 0) {
+            throw new CustomException("确认中,暂无法修改");
+        }
+        param.setDoctorId(collection.getDoctorId());
+        param.setDoctorType2Id(collection.getDoctorType2Id());
+        param.setPackageId(collection.getPackageId());
+        FsUserInformationCollection fsUserInformationCollection = getFsUserInformationCollection(param);
+        fsUserInformationCollection.setUpdateTime(DateUtils.getNowDate());
+        baseMapper.updateFsUserInformationCollection(fsUserInformationCollection);
+        return fsUserInformationCollection.getId();
+    }
+
+    /**
+     * 修改用户信息采集
+     *
+     * @param param 用户信息采集
+     * @return 结果
+     */
+    @Override
+    public Long updateFsUserInformationCollection(FsUserInformationCollectionParam param)
+    {
+        if (param.getId() == null || param.getId() < 1) {
+            throw new CustomException("参数错误");
+        }
+        FsUserInformationCollection collection = fsUserInformationCollectionMapper.selectFsUserInformationCollectionById(param.getId());
+        if (collection == null) {
+            throw new CustomException("没有用户采集信息");
+        }
+        if (collection.getUserConfirm() == 1 && collection.getUserConfirm2() == 0) {
+            throw new CustomException("确认中,暂无法修改");
+        }
+        //清空订单号
+        fsUserInformationCollectionMapper.collectionOderCodeNULL(param.getId());
+        param.setDoctorId(collection.getDoctorId());
+        param.setDoctorType2Id(collection.getDoctorType2Id());
+        param.setPackageId(collection.getPackageId());
+        FsUserInformationCollection fsUserInformationCollection = getFsUserInformationCollection(param);
+        fsUserInformationCollection.setUserConfirm2(0);
+        fsUserInformationCollection.setUserConfirm(0);
+        fsUserInformationCollection.setDoctorConfirm(0);
+        fsUserInformationCollection.setStatus(1);
+        fsUserInformationCollection.setUpdateTime(DateUtils.getNowDate());
+        baseMapper.updateFsUserInformationCollection(fsUserInformationCollection);
+        return fsUserInformationCollection.getId();
+    }
+
+    /**
+     * 批量删除用户信息采集
+     *
+     * @param ids 需要删除的用户信息采集主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserInformationCollectionByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsUserInformationCollectionByIds(ids);
+    }
+
+    /**
+     * 删除用户信息采集信息
+     *
+     * @param id 用户信息采集主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsUserInformationCollectionById(Long id)
+    {
+        return baseMapper.deleteFsUserInformationCollectionById(id);
+    }
+
+    @Override
+    public FsUserInformationCollectionVO getInfo(FsUserInformationCollection map) {
+        FsUserInformationCollectionVO vo = new FsUserInformationCollectionVO();
+        Long userId = map.getUserId();
+        Long questionId = map.getQuestionId();
+//        FsUserInformationCollection fsUserInformationCollection = baseMapper.selectByUserId(userId);
+        FsUserInformationCollection fsUserInformationCollection = null;
+        if (map.getId() != null){
+            fsUserInformationCollection = baseMapper.selectFsUserInformationCollectionById(map.getId());
+        }
+        if (fsUserInformationCollection != null) {
+            //组装返回数据
+            vo.setQuestionId(fsUserInformationCollection.getQuestionId());
+            vo.setId(fsUserInformationCollection.getId());
+            vo.setAmount(fsUserInformationCollection.getAmount());
+            vo.setPackageId(fsUserInformationCollection.getPackageId());
+            vo.setPayType(fsUserInformationCollection.getPayType());
+            vo.setIsPackage(fsUserInformationCollection.getIsPackage());
+            vo.setSex(fsUserInformationCollection.getSex());
+            vo.setUserPhoneFour(fsUserInformationCollection.getUserPhoneFour());
+            vo.setUserName(fsUserInformationCollection.getUserName());
+            vo.setRemark(fsUserInformationCollection.getRemark());
+            vo.setAllergy(fsUserInformationCollection.getAllergy());
+            if (map.getQuestionId() == null) {
+                FsQuestionAndAnswerVO questionAndAnswerVO = questionAndAnswerService.selectFsQuestionAndAnswerById(fsUserInformationCollection.getQuestionId());
+                List<AnswerVO> answerVOS = JSON.parseArray(fsUserInformationCollection.getJsonInfo(), AnswerVO.class);
+                List<AnswerVO> collect = getAnswerVOs(answerVOS, questionAndAnswerVO.getAnswers());
+                vo.setAnswers(collect);
+            } else {
+                vo.setAnswers(JSON.parseArray(fsUserInformationCollection.getJsonInfo(), AnswerVO.class));
+            }
+        }
+        if (questionId != null) {
+            vo.setQuestionId(questionId);
+            //问答数据
+            FsQuestionAndAnswerVO questionAndAnswerVO = questionAndAnswerService.selectFsQuestionAndAnswerById(questionId);
+            if (questionAndAnswerVO != null) {
+                questionAndAnswerVO.getAnswers().forEach(answerVO -> {
+                    answerVO.setFlag(false);
+                });
+                if (fsUserInformationCollection != null) {
+                    vo.getAnswers().addAll(questionAndAnswerVO.getAnswers());
+                    vo.setAnswers(getAnswerVOs(vo.getAnswers(),questionAndAnswerVO.getAnswers()));
+                } else {
+                    //返回问答
+                    vo.setAnswers(questionAndAnswerVO.getAnswers());
+                }
+            }
+        }
+        if (ObjectUtil.isNotEmpty(vo.getAnswers())){
+            vo.getAnswers().forEach(answerVO -> {
+                if (answerVO.getSort() == null) {
+                    if (answerVO.getTitle().contains("糖尿病")) {
+                        answerVO.setSort(1);
+                    } else if (answerVO.getTitle().contains("心脑血管")) {
+                        answerVO.setSort(2);
+                    } else if (answerVO.getTitle().contains("风湿骨病")) {
+                        answerVO.setSort(3);
+                    } else if (answerVO.getTitle().contains("肝胆")) {
+                        answerVO.setSort(4);
+                    } else if (answerVO.getTitle().contains("其他")) {
+                        answerVO.setSort(5);
+                    } else if (answerVO.getTitle().contains("特殊")) {
+                        answerVO.setSort(6);
+                    }
+                }
+                if(answerVO.getFlag() == null) {
+                    answerVO.setFlag(false);
+                }
+                if (answerVO.getValue() == null) {
+                    answerVO.setValue(new ArrayList<>());
+                }
+            });
+            //有值且为true排前面
+//            List<AnswerVO> collect = vo.getAnswers().stream()
+//                    .sorted(Comparator.comparing(AnswerVO::getValue, Comparator.nullsFirst(Integer::compareTo)).reversed()).collect(Collectors.toList())
+//                    .stream()
+//                    .sorted((a,b)-> Boolean.compare(b.getFlag(),a.getFlag())).collect(Collectors.toList());
+            //List<AnswerVO> collect = vo.getAnswers().stream()
+            //        .sorted(Comparator.comparing(AnswerVO::getValue, Comparator.nullsFirst(List::indexOf)).reversed()).collect(Collectors.toList())
+            //        .stream()
+            //        .sorted((a,b)-> Boolean.compare(b.getFlag(),a.getFlag())).collect(Collectors.toList());
+            List<AnswerVO> collect = vo.getAnswers().stream()
+                    .sorted(Comparator.comparing(AnswerVO::getSort)).collect(Collectors.toList());
+
+            vo.setAnswers(collect);
+        }
+        return vo;
+    }
+
+    @Override
+    public List<FsUserInformationCollectionListDVO> selectFsUserInformationCollectionListDVO(FsUserInformationCollectionListDParam param) {
+        return fsUserInformationCollectionMapper.selectFsUserInformationCollectionListDVO(param);
+    }
+
+    @Override
+    public FsUserInformationCollectionVO detail(Long id) {
+        FsUserInformationCollectionVO vo = new FsUserInformationCollectionVO();
+        FsUserInformationCollection collection = fsUserInformationCollectionMapper.selectFsUserInformationCollectionById(id);
+        if (collection != null) {
+            vo.setAllergy(collection.getAllergy());
+            vo.setRemark(collection.getRemark());
+            vo.setAnswers(JSON.parseArray(collection.getJsonInfo(), AnswerVO.class));
+            List<AnswerVO> answers = vo.getAnswers();
+            if (!CollectionUtils.isEmpty(answers)){
+                List<AnswerVO> collect = answers
+                        .stream()
+                        .filter(answerVO -> !answerVO.getValue().isEmpty())
+                        .collect(Collectors.toList());
+                if (!CollectionUtils.isEmpty(collect)) {
+                    collect.forEach(answerVO -> {
+                        List<Integer> value = answerVO.getValue();
+                        List<AnswerVO.Options> options = answerVO.getOptions();
+                        List<AnswerVO.Options> filterOptions = Lists.newArrayList();
+                        for (AnswerVO.Options option : options) {
+                            if (value.contains(option.getValue())) {
+                                filterOptions.add(option);
+                            }
+                        }
+                        answerVO.setOptions(filterOptions);
+                    });
+                }
+                vo.setAnswers(collect);
+            }
+        }
+        return vo;
+    }
+
+    @Override
+    public R getWxaCodePackageOrderUnLimit(Long collectionId) {
+        logger.info("生成用户信息采集二维码");
+        FsSysConfig sysConfig = configUtil.getSysConfig();
+
+        final WxMaService wxMaService = WxMaConfiguration.getMaService(sysConfig.getAppid());
+
+        String scene="collectionId="+ collectionId ;
+        byte[] file;
+        try {
+            file = wxMaService.getQrcodeService().createWxaCodeUnlimitBytes(
+                    scene,
+                    "pages_order/confirmUserinfo",
+                    true,
+                    "release",//release trial
+                    430,
+                    true,
+                    null,
+                    false);
+
+            // 上传图片到存储桶
+            String suffix = ".png";
+            CloudStorageService storage = OSSFactory.build();
+            String url;
+            try {
+                url = storage.uploadSuffix(file, suffix);
+            }  catch (Exception e) {
+                // 记录错误日志
+                logger.error("生成图片失败:{}",e.getMessage(),e);
+                return R.error("生成图片失败");
+            }
+            // 返回成功信息
+            return R.ok().put("url",url);
+
+        } catch (WxErrorException e) {
+            logger.error(e.getMessage(), e);
+            return R.error("微信接口调用失败: " + e.getMessage());
+        }
+    }
+
+    @Override
+    @Transactional
+    public R doctorConfirm(FsUserInformationCollection collection) {
+        FsUserInformationCollection fsUserInformationCollection = fsUserInformationCollectionMapper.selectFsUserInformationCollectionById(collection.getId());
+        if (fsUserInformationCollection == null) {
+            return R.error("没有用户采集信息");
+        }
+        if (fsUserInformationCollection.getUserConfirm() == 0){
+            return R.error("用户未确认");
+        }
+        if (fsUserInformationCollection.getDoctorConfirm() == 1){
+            return R.error("医生已确认");
+        }
+        List<AnswerVO> answerVOS = null;
+        //医生确认确认状态为true(用于封档)
+        if (StringUtils.isNotEmpty(fsUserInformationCollection.getJsonInfo()) ){
+            answerVOS = JSONArray.parseArray(fsUserInformationCollection.getJsonInfo(), AnswerVO.class);
+            answerVOS.forEach(answerVO -> {
+                answerVO.setFlag(true);
+            });
+        }
+        FsUserInformationCollection map = new FsUserInformationCollection();
+        map.setId(collection.getId());
+        map.setDoctorAdvice(collection.getDoctorAdvice());
+        map.setDoctorConfirm(1);
+        //医生确认时间
+        map.setDoctorConfirmTime(DateUtils.getNowDate());
+        //写入医生签名
+        FsDoctor fsDoctor = doctorMapper.selectFsDoctorByDoctorId(fsUserInformationCollection.getDoctorId());
+        map.setDoctorSign(fsDoctor.getSignUrl());
+        map.setDoctorAdvice(collection.getDoctorAdvice());
+        if (answerVOS != null && !answerVOS.isEmpty()) {
+            map.setJsonInfo(JSON.toJSONString(answerVOS));
+        }
+//        if (fsUserInformationCollection.getIsPackage() == 1) {
+//            //插入生成处方签定时任务数据
+//            if(fsUserInformationCollection.getPackageOrderCode() != null) {
+//                //套餐包订单
+//                FsPackageOrder fsPackageOrder = packageOrderMapper.selectByOderCode(fsUserInformationCollection.getPackageOrderCode());
+//                if (fsPackageOrder != null && fsPackageOrder.getIsPay() == 1) {
+//                    //套餐包信息
+//                    FsPackage fsPackage = JSON.parseObject(fsPackageOrder.getPackageJson(), FsPackage.class);
+//
+//                    //套餐包为药品生成处方信息
+//                    if(fsPackage != null && (fsPackage.getProductType() == 1 || fsPackage.getProductType() == 2 || fsPackage.getProductType() == 3)) {
+//                        FsStoreOrder fsStoreOrder = storeOrderService.selectFsStoreOrderByOrderCode(fsUserInformationCollection.getPackageOrderCode());
+//                        if (fsStoreOrder != null && fsStoreOrder.getIsPay() == 1 ) {
+//                            if (fsStoreOrder.getPrescribeId() != null) {
+////                                FsPrescribeParam fsPrescribeParam = new FsPrescribeParam();
+////                                fsPrescribeParam.setPrescribeId(fsStoreOrder.getPrescribeId());
+////                                prescribeService.confirmPrescribe(fsPrescribeParam);
+//                                prescribeService.collectionPrescribe(fsStoreOrder.getPrescribeId());
+//                            }
+//                        } else {
+//                            throw new CustomException("生成处方信息中......");
+//                        }
+//                    }
+//                }
+//            }
+//        } else {
+//            //没有关联套餐包医生确认清空所有状态
+//            map.setUserConfirm2(1);
+//        }
+
+        if (fsUserInformationCollectionMapper.updateFsUserInformationCollection(map) > 0) {
+
+            //更新医生确认信息
+//            FsDoctorConfirm doctorConfirm = redisCache.getCacheObject("doctorConfirm:" + collection.getId());
+//            if(doctorConfirm == null) {
+//                return R.error("没有医生确认信息");
+//            }
+//            doctorConfirm.setDoctorEndTime(DateUtils.getNowDate());
+//            Long seconds = DateUtil.between(doctorConfirm.getStartTime(), doctorConfirm.getDoctorEndTime(), DateUnit.SECOND);
+//            doctorConfirm.setConfirmSecond(seconds);
+//            doctorConfirmService.updateFsDoctorConfirm(doctorConfirm);
+//            redisCache.deleteObject("doctorConfirm:" + collection.getId());
+
+            openIMService.doctorSendMsgToUser(collection.getUserId(),collection.getDoctorId());
+            return R.ok();
+        }
+        return R.error("医生确认失败");
+    }
+
+    @Override
+    @Transactional
+    public R doctorType2Confirm(FsUserInformationCollection collection) {
+        FsUserInformationCollection fsUserInformationCollection = fsUserInformationCollectionMapper.selectFsUserInformationCollectionById(collection.getId());
+        if (fsUserInformationCollection == null) {
+            return R.error("没有用户采集信息");
+        }
+        if (fsUserInformationCollection.getUserConfirm() == 0){
+            return R.error("用户未确认");
+        }
+        if (fsUserInformationCollection.getDoctorType2Confirm() == 1){
+            return R.error("药师已确认");
+        }
+        if (fsUserInformationCollection.getDoctorConfirm() != 1) {
+            return R.error("医生未签字无法确认");
+        }
+        if(StringUtils.isEmpty(fsUserInformationCollection.getPackageOrderCode())){
+            return R.error("用户未下单,无需确认");
+        }
+        List<AnswerVO> answerVOS = null;
+        //医生确认确认状态为true(用于封档)
+        if (StringUtils.isNotEmpty(fsUserInformationCollection.getJsonInfo()) ){
+            answerVOS = JSONArray.parseArray(fsUserInformationCollection.getJsonInfo(), AnswerVO.class);
+            answerVOS.forEach(answerVO -> {
+                answerVO.setFlag(true);
+            });
+        }
+        FsUserInformationCollection map = new FsUserInformationCollection();
+        map.setId(collection.getId());
+        map.setDoctorType2Confirm(1);
+        //医生确认时间
+        map.setDoctorConfirmTime(DateUtils.getNowDate());
+        //写入药师签名
+        FsDoctor fsDoctor = doctorMapper.selectFsDoctorByDoctorId(fsUserInformationCollection.getDoctorType2Id());
+        if(fsDoctor.getDoctorType()!=2){
+            return R.error("不是药师身份,无法确认");
+        }
+        map.setDoctorType2Sign(fsDoctor.getSignUrl());
+        map.setDoctorAdvice(collection.getDoctorAdvice());
+        if (answerVOS != null && !answerVOS.isEmpty()) {
+            map.setJsonInfo(JSON.toJSONString(answerVOS));
+        }
+//
+        openIMService.doctorSendMsgToUser(collection.getUserId(),collection.getDoctorType2Id());
+        if (fsUserInformationCollectionMapper.updateFsUserInformationCollection(map) > 0) {
+            FsPackageOrder fsPackageOrder = packageOrderMapper.selectFsPackageOrderByOrderSn(collection.getPackageOrderCode());
+            if(fsPackageOrder.getStoreOrderId()==null||fsPackageOrder.getStoreOrderId()==0){
+                return R.error("用户未支付,无需确认");
+            }
+            FsStoreOrder fsStoreOrder = storeOrderService.selectFsStoreOrderByOrderId(fsPackageOrder.getStoreOrderId());
+            fsStoreOrder.setDoctorType2Confirm(1);
+            storeOrderService.updateFsStoreOrder(fsStoreOrder);
+            return R.ok();
+        }
+        return R.error("药师确认失败");
+    }
+
+    @Override
+    public FsUserInfoCollectionUVO info(Long id, Long userId) {
+        FsUserInfoCollectionUVO vo = new FsUserInfoCollectionUVO();
+        FsUserInformationCollection collection = fsUserInformationCollectionMapper.selectFsUserInformationCollectionById(id);
+
+        if (collection != null) {
+
+//            if (!Objects.equals(collection.getUserId(), userId)) {
+//                return vo;
+//            }
+            if (collection.getIsPackage() == 1) {
+                vo.setPackageId(collection.getPackageId());
+                vo.setPayType(collection.getPayType());
+                vo.setAmount(collection.getAmount());
+                FsPackage fsPackage = new FsPackage();
+                FsPackage fsPackage1 = packageMapper.selectFsPackageByPackageId(collection.getPackageId());
+                if (fsPackage1 != null) {
+                    fsPackage = fsPackage1;
+                }
+                vo.setFsPackage(fsPackage);
+                CompanyUser companyUser = companyUserMapper.selectCompanyUserById(collection.getCompanyUserId());
+                if (companyUser == null) {
+                    throw new CustomException("销售不存在");
+                }
+                vo.setCompanyUserId(collection.getCompanyUserId());
+                vo.setCompanyId(companyUser.getCompanyId());
+                vo.setPackageOrderCode(collection.getPackageOrderCode());
+                FsPackageOrder fsPackageOrder = packageOrderMapper.selectFsPackageOrderByOrderSn(collection.getPackageOrderCode());
+                if(fsPackageOrder!=null) {
+                    vo.setOrderStatus(fsPackageOrder.getIsPay());
+                    vo.setOrderId(fsPackageOrder.getOrderId());
+                    vo.setPatientJson(fsPackageOrder.getPatientJson());
+                    if((fsPackage.getProductType() == 1 || fsPackage.getProductType() == 2 || fsPackage.getProductType() == 3) && fsPackageOrder.getIsPay() == 1) {
+                        //套餐包为药品且已支付的查询处方订单拿到处方签
+                        FsStoreOrder fsStoreOrder = storeOrderService.selectFsStoreOrderByOrderCode(collection.getPackageOrderCode());
+                        if (fsStoreOrder != null) {
+                            Long prescribeId = fsStoreOrder.getPrescribeId();
+                            FsPrescribe fsPrescribe = fsPrescribeMapper.selectFsPrescribeByPrescribeId(prescribeId);
+                            if (fsPrescribe != null) {
+                                vo.setPrescribeImgUrl(fsPrescribe.getPrescribeImgUrl());
+                                vo.setPrescribeStatus(fsPrescribe.getStatus());
+                            }
+                        } else {
+                            throw new CustomException("没有处方订单");
+                        }
+                    }
+                }
+            }
+            vo.setIsPackage(collection.getIsPackage());
+            vo.setId(collection.getId());
+            vo.setAnswers(JSON.parseArray(collection.getJsonInfo(), AnswerVO.class));
+            vo.setStatus(collection.getStatus());
+            vo.setUserConfirm(collection.getUserConfirm());
+            vo.setUserConfirm2(collection.getUserConfirm2());
+            vo.setDoctorConfirm(collection.getDoctorConfirm());
+            vo.setUserAdvice(collection.getUserAdvice());
+            vo.setDoctorAdvice(collection.getDoctorAdvice());
+            vo.setDoctor(doctorMapper.selectFsDoctorByDoctorId(collection.getDoctorId()));
+            vo.setAllergy(collection.getAllergy());
+            vo.setRemark(collection.getRemark());
+            vo.setSex(collection.getSex());
+            vo.setUserPhoneFour(collection.getUserPhoneFour());
+            vo.setUserName(collection.getUserName());
+        }
+        return vo;
+    }
+
+    @Override
+    @Transactional
+    public R userConfirm(CollectionInfoConfirmParam param) {
+
+        if (param.getId() == null) {
+            return R.error("参数错误");
+        }
+        FsUserInformationCollection collection = fsUserInformationCollectionMapper.selectFsUserInformationCollectionById(param.getId());
+        if (collection == null) {
+            return R.error("没有用户采集信息");
+        }
+        if (collection.getStatus() == 1 ){
+            if (collection.getUserConfirm() == 1){
+                return R.error("用户已确认");
+            }
+        }
+        if (!Objects.equals(collection.getUserId(), param.getUserId())) {
+            return R.error("用户信息不匹配,无法确认");
+        }
+        //绑定用户
+        CompanyUserUser companyUserUserMap=new CompanyUserUser();
+        companyUserUserMap.setCompanyUserId(collection.getCompanyUserId());
+        companyUserUserMap.setUserId(collection.getUserId());
+        List<CompanyUserUser> list= companyUserUserMapper.selectCompanyUserUserList(companyUserUserMap);
+        if(list==null|| list.isEmpty()){
+            CompanyUser companyUser=companyUserMapper.selectCompanyUserById(collection.getCompanyUserId());
+            if(companyUser!=null&&companyUser.getStatus().equals("0")){
+                companyUserUserMap.setCompanyId(companyUser.getCompanyId());
+                companyUserUserMap.setCreateTime(new Date());
+                companyUserUserMapper.insertCompanyUserUser(companyUserUserMap);
+            }
+        }
+
+        FsUserInformationCollection map = new FsUserInformationCollection();
+        map.setId(param.getId());
+        map.setUserConfirm(1);
+        map.setUserAdvice(param.getUserAdvice());
+        if (param.getPatientId() == null|| param.getPatientId() == 0) {
+            return R.error("请提交就诊人信息");
+        }
+        map.setPatientId(param.getPatientId());
+        if (collection.getStatus() == 1) {
+
+            openIMService.sendUserInformation(collection.getUserId(),collection.getDoctorId(),collection.getId());
+            //用户确认后创建一个问诊订单,待医生接单
+//            FsInquiryOrderCreateParam fsInquiryOrderCreateParam = new FsInquiryOrderCreateParam();
+//            fsInquiryOrderCreateParam.setIsUserInformation(1);
+//            fsInquiryOrderCreateParam.setUserId(collection.getUserId());
+//            fsInquiryOrderCreateParam.setPatientId(collection.getPatientId());
+//            fsInquiryOrderCreateParam.setOrderType(1);
+//            fsInquiryOrderCreateParam.setInquiryType(1);
+//            fsInquiryOrderCreateParam.setIsVisit("1");
+//            fsInquiryOrderCreateParam.setInquirySubType(3);
+//            fsInquiryOrderService.createOrder(fsInquiryOrderCreateParam);
+//            //用户第一次确认添加医生消息
+//            DoctorMsg msg = new DoctorMsg();
+//            String name = collection.getUserName() != null ? collection.getUserName() : "-";
+//            //没套餐包的添加医生信息采集建议消息
+//            msg.setTitle("用户采集信息建议");
+//            msg.setType(3);
+//            msg.setContent("患者:" + name + "的信息采集,前往建议");
+//            msg.setDoctorId(collection.getDoctorId());
+//            msg.setCreateTime(DateUtils.getNowDate());
+//            //插入医生消息
+//            doctorMsgMapper.insertDoctorMsg(msg);
+//            //第一次确认
+            map.setStatus(2);
+            baseMapper.updateFsUserInformationCollection(map);
+        }
+//        if (fsUserInformationCollectionMapper.updateFsUserInformationCollection(map) > 0) {
+//            //存入医生确认统计时间数据
+//            FsDoctorConfirm doctorConfirm = new FsDoctorConfirm();
+//            doctorConfirm.setCollectionId(collection.getId());
+//            doctorConfirm.setDoctorId(collection.getDoctorId());
+//            doctorConfirm.setStartTime(DateUtils.getNowDate());
+//            doctorConfirmService.insertFsDoctorConfirm(doctorConfirm);
+//            //医生确认时间存入缓存 医生确认后删除
+//            redisCache.setCacheObject("doctorConfirm:" + collection.getId(), doctorConfirm);
+//            return R.ok();
+//        }
+        return R.ok();
+    }
+
+
+    @Override
+    @Transactional
+    public void autoRefund(FsUserInformationCollection collection) {
+
+        //清空订单号
+        fsUserInformationCollectionMapper.collectionOderCodeNULL(collection.getId());
+
+        //更新采集信息状态
+        FsUserInformationCollection map = new FsUserInformationCollection();
+        map.setId(collection.getId());
+        map.setUserConfirm2(0);
+        map.setStatus(1);
+        map.setUserConfirm(0);
+        map.setDoctorConfirm(0);
+        //更新用户信息采集状态
+        fsUserInformationCollectionMapper.updateFsUserInformationCollection(map);
+
+        //退款操作
+        FsStoreOrder fsStoreOrder = storeOrderService.selectFsStoreOrderByOrderCode(collection.getPackageOrderCode());
+        if (fsStoreOrder == null) {
+            throw new CustomException("没有处方订单");
+        }
+
+        //更新处方单信息
+        FsStoreOrder mapStoreOrder = new FsStoreOrder();
+        mapStoreOrder.setOrderId(fsStoreOrder.getOrderId());
+        mapStoreOrder.setStatus(-2);
+        mapStoreOrder.setRefundTime(DateUtils.getNowDate());
+        storeOrderService.updateFsStoreOrder(mapStoreOrder);
+
+        //订单日志
+        FsStoreOrderLogs Logs = new FsStoreOrderLogs();
+        Logs.setChangeMessage(FsStoreOrderStatusEnum.REFUND_STATUS_2.getDesc());
+        Logs.setOrderId(fsStoreOrder.getOrderId());
+        Logs.setChangeTime(new DateTime());
+        Logs.setChangeType(FsStoreOrderStatusEnum.REFUND_STATUS_2.getValue().toString());
+        fsStoreOrderLogsMapper.insertFsStoreOrderLogs(Logs);
+
+        String orderType = "store";
+        Long orderId = fsStoreOrder.getOrderId();
+        if (fsStoreOrder.getPackageOrderId() != null) {
+            orderType = "package";
+
+            FsPackageOrder fsPackageOrder = packageOrderMapper.selectFsPackageOrderByOrderSn(collection.getPackageOrderCode());
+            if (fsPackageOrder == null) {
+                throw new CustomException("没有套餐订单");
+            }
+            orderId = fsStoreOrder.getPackageOrderId();
+
+            //更新套餐单信息
+            FsPackageOrder mapPackageOrder = new FsPackageOrder();
+            mapPackageOrder.setOrderId(fsPackageOrder.getOrderId());
+            mapPackageOrder.setStatus(-2);
+            mapPackageOrder.setRefundStatus(2);
+            packageOrderMapper.updateFsPackageOrder(fsPackageOrder);
+        }
+
+        if (fsStoreOrder.getCompanyId() != null) {
+            companyService.refundCompanyMoney(fsStoreOrder);
+        }
+
+        //获取支付明细
+        List<FsStorePayment> payments = fsStorePaymentMapper.selectFsStorePaymentByPay(2, fsStoreOrder.getOrderId());
+        if (fsStoreOrder.getPackageOrderId() != null) {
+
+            payments = fsStorePaymentMapper.selectFsStorePaymentByPay(3, fsStoreOrder.getPackageOrderId());
+        }
+
+        if (payments != null && !payments.isEmpty()) {
+            FsStorePayment payment = payments.get(0);
+            if (payment.getPayMode().equals("wx")) {
+                WxPayConfig payConfig = new WxPayConfig();
+                if (StringUtils.isBlank(payment.getAppId())) {
+                    throw new IllegalArgumentException("appId不能为空");
+                }
+                FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+                if (fsCoursePlaySourceConfig == null) {
+                    throw new CustomException("未找到appId对应的小程序配置: " + payment.getAppId());
+                }
+                Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                if (merchantConfigId == null || merchantConfigId <= 0) {
+                    throw new CustomException("小程序没有配置商户信息");
+                }
+                MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
+                payConfig.setMchId(fsPayConfig.getWxMchId());
+                payConfig.setMchKey(fsPayConfig.getWxMchKey());
+                payConfig.setKeyPath(wxPayProperties.getKeyPath());
+                payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                wxPayService.setConfig(payConfig);
+                WxPayRefundRequest refundRequest = new WxPayRefundRequest();
+                refundRequest.setOutTradeNo(orderType + "-" + payment.getPayCode());
+                refundRequest.setOutRefundNo(orderType + "-" + payment.getPayCode());
+                refundRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(payment.getPayMoney().toString()));
+                refundRequest.setRefundFee(WxPayUnifiedOrderRequest.yuanToFen(payment.getPayMoney().toString()));
+                try {
+                    WxPayRefundResult refundResult = wxPayService.refund(refundRequest);
+                    WxPayRefundQueryResult refundQueryResult = wxPayService.refundQuery("", refundResult.getOutTradeNo(), refundResult.getOutRefundNo(), refundResult.getRefundId());
+                    if (refundQueryResult != null && refundQueryResult.getResultCode().equals("SUCCESS")) {
+                        FsStorePayment paymentMap = new FsStorePayment();
+                        paymentMap.setPaymentId(payment.getPaymentId());
+                        paymentMap.setStatus(-1);
+                        paymentMap.setRefundTime(DateUtils.getNowDate());
+                        paymentMap.setRefundMoney(payment.getPayMoney());
+                        fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                    } else {
+                        throw new CustomException("退款请求失败" + refundQueryResult.getReturnMsg());
+                    }
+                } catch (WxPayException e) {
+                    throw new CustomException("退款请求失败" + e.getReturnMsg());
+                }
+            } else if (payment.getPayMode().equals("yb")) {
+                //易宝
+                RefundDTO refundDTO = new RefundDTO();
+                refundDTO.setRefundMoney(payment.getPayMoney().toString());
+                refundDTO.setLowRefundNo(orderType + "-" + payment.getPayCode());
+                refundDTO.setUpOrderId(payment.getTradeNo());
+                com.fs.ybPay.domain.RefundResult result = payService.refund(refundDTO);
+                logger.info("订单退款返回结果:退款订单id:" + orderId + result);
+                if (result.getState().equals("5")) {
+                    FsStorePayment paymentMap = new FsStorePayment();
+                    paymentMap.setPaymentId(payment.getPaymentId());
+                    paymentMap.setStatus(-1);
+                    paymentMap.setRefundTime(DateUtils.getNowDate());
+                    paymentMap.setRefundMoney(payment.getPayMoney());
+                    fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                } else {
+                    throw new CustomException("退款请求失败" + result.getMessage());
+                }
+            } else if (payment.getPayMode().equals("tz")) {
+                RefundParam tzBankResult = new RefundParam();
+                // 使用set方法为对象的字段赋值
+                //商户原支付订单号
+                tzBankResult.setOldPayOutOrderNo(orderType + payment.getPayCode());
+                // 商户退款订单号 对接平台系统里自己生成的退款订单号
+                tzBankResult.setRefundOrderNo(orderType + payment.getPayCode());
+                // 交易发送时间 yyyyMMddHHmmss
+                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+                tzBankResult.setTrxSendTime(sdf.format(new Date()));
+                // 退款金额
+                tzBankResult.setRefundOrdTransAmt(payment.getPayMoney().doubleValue());
+                TzBankResult<RefundResult> result = tzBankService.refund(tzBankResult);
+                logger.info("订单退款返回结果:退款订单id:" + orderId + result);
+                if (result.getBody().getRefundOrdStatus().equals("90") || result.getBody().getRefundOrdStatus().equals("60")) {
+                    FsStorePayment paymentMap = new FsStorePayment();
+                    paymentMap.setPaymentId(payment.getPaymentId());
+                    paymentMap.setStatus(-1);
+                    paymentMap.setRefundTime(DateUtils.getNowDate());
+                    paymentMap.setRefundMoney(payment.getPayMoney());
+                    fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                } else {
+                    throw new CustomException("退款请求失败" + result.getRetMsg());
+                }
+            } else if (payment.getPayMode().equals("hf")) {
+                if (payment.getIsShare() == 1 && payment.getShareStatus() == 1) {
+                    V2TradePaymentDelaytransConfirmrefundRequest confirmRefundRequest = new V2TradePaymentDelaytransConfirmrefundRequest();
+                    //Map<String, Object> extendInfoMap = new HashMap<>();
+                    String orderCode = OrderCodeUtils.getOrderSn();
+                    if (StringUtils.isEmpty(orderCode)) {
+                        throw new CustomException("订单生成失败,请重试");
+                    }
+                    confirmRefundRequest.setReqSeqId(orderCode);
+                    confirmRefundRequest.setOrgReqSeqId(payment.getShareCode());
+//                    confirmRefundRequest.setOrgReqDate(payment.getShareDate());
+                    //多汇付使用appID todo
+//                    HuifuConfirmrefundResult result = huiFuService.confirmRefund(confirmRefundRequest, null);
+//                    if (result.getResp_code().equals("00000000") && (result.getTrans_stat().equals("S") || result.getTrans_stat().equals("P"))) {
+//                        refund(payment, orderType, orderId);
+//                    } else {
+//                        throw new CustomException("交易确认退款请求失败" + result.getResp_desc());
+//                    }
+                } else {
+                    refund(payment, orderType, orderId);
+                }
+            }
+        } else {
+            throw new CustomException("未找的支付明细");
+        }
+
+
+    }
+    private void refund(FsStorePayment payment, String orderType, Long orderId) {
+        V2TradePaymentScanpayRefundRequest request = new V2TradePaymentScanpayRefundRequest();
+        request.setOrdAmt(payment.getPayMoney().toString());
+        request.setOrgReqDate(new SimpleDateFormat("yyyyMMdd").format(payment.getCreateTime()));
+        request.setReqSeqId("refund-" + payment.getPayCode());
+        Map<String, Object> extendInfoMap = new HashMap<>();
+        extendInfoMap.put("org_req_seq_id", orderType + "-" + payment.getPayCode());
+        request.setExtendInfo(extendInfoMap);
+        request.setAppId(payment.getAppId());
+        HuiFuRefundResult refund = huiFuService.refund(request);
+        logger.info("订单退款返回结果:退款订单id:" + orderId + refund);
+        if ((refund.getResp_code().equals("00000000") || refund.getResp_code().equals("00000100")) && (refund.getTrans_stat().equals("S") || refund.getTrans_stat().equals("P"))) {
+            FsStorePayment paymentMap = new FsStorePayment();
+            paymentMap.setPaymentId(payment.getPaymentId());
+            paymentMap.setStatus(-1);
+            paymentMap.setRefundTime(DateUtils.getNowDate());
+            paymentMap.setRefundMoney(payment.getPayMoney());
+            fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+        } else {
+            throw new CustomException("退款请求失败" + refund.getResp_desc());
+        }
+    }
+    @Override
+    public FsUserInformationCollectionVO getCollectionByUserId(Long userId) {
+        FsUserInformationCollectionVO vo = new FsUserInformationCollectionVO();
+        FsUserInformationCollection collection = fsUserInformationCollectionMapper.selectFsUserInformationCollectionByUserId(userId);
+        if (collection != null) {
+            vo.setAnswers(JSON.parseArray(collection.getJsonInfo(), AnswerVO.class));
+            //医生建议
+            if (collection.getDoctorAdvice() != null){
+                vo.setDoctorAdvice(collection.getDoctorAdvice());
+            }
+        }
+        return vo;
+    }
+
+    @Override
+    public FsUserInformationCollectionDTO selectFsUserInformationCollectionDTOById(Long id) {
+        return fsUserInformationCollectionMapper.selectFsUserInformationCollectionDTOById(id);
+    }
+
+    @Override
+    public int updatePackageOrderCode(FsUserInformationCollection fsUserInformationCollection) {
+        return fsUserInformationCollectionMapper.updateFsUserInformationCollection(fsUserInformationCollection);
+    }
+
+    @Override
+    public FsUserInformationCollectionAndPatientVO selectFsUserInformationCollectionVoById(Long id) {
+        FsUserInformationCollection info = baseMapper.selectFsUserInformationCollectionById(id);
+        FsUserInformationCollectionAndPatientVO vo = new FsUserInformationCollectionAndPatientVO();
+        BeanUtils.copyProperties(info, vo);
+        Long patientId = info.getPatientId();
+        if(patientId != null){
+            FsPatient fsPatient = fsPatientMapper.selectFsPatientByPatientId(patientId);
+            if (fsPatient != null){
+
+                vo.setPatientInfo(fsPatient);
+                //查询是否支付
+                Integer isPay = 0;
+                Long packageOrderId = info.getPackageOrderId();
+                if (packageOrderId != null){
+                    FsPackageOrder order = packageOrderMapper.selectFsPackageOrderByOrderId(packageOrderId);
+                    if (order != null && order.getStatus() > 1){
+                        isPay = 1;
+                        vo.setStoreOrderId(order.getStoreOrderId());
+                        Integer status = order.getStatus();
+                        vo.setOrderStatus(FsPackageOrderStatusEnum.toType(status).getDesc()); //订单状态
+                        vo.setPackageJson(order.getPackageJson());
+                    }
+                }
+                vo.setIsPay(isPay);
+            }
+        }
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(info.getCompanyUserId());
+        vo.setCompanyId(companyUser.getCompanyId());
+        return vo;
+    }
+
+    private List<AnswerVO> getAnswerVOs(List<AnswerVO> target,List<AnswerVO> source) {
+        target.addAll(source);
+        return target.stream()
+                .collect(Collectors.groupingBy(AnswerVO::getTitle))
+                .values().stream()
+                .map(group -> group.stream().reduce((a, b) -> a).orElse(null))
+                .collect(Collectors.toList());
+    }
+
+    private FsUserInformationCollection getFsUserInformationCollection(FsUserInformationCollectionParam param) {
+        FsUserInformationCollection fsUserInformationCollection = new FsUserInformationCollection();
+        if (!CollectionUtils.isEmpty(param.getAnswers())) {
+            param.getAnswers().forEach(answer -> {
+                if (answer.getFlag() == null) {
+                    answer.setFlag(false);
+                }
+            });
+        }
+        fsUserInformationCollection.setJsonInfo(JSON.toJSONString(param.getAnswers()));
+        fsUserInformationCollection.setUserId(param.getUserId());
+        fsUserInformationCollection.setCompanyUserId(param.getCompanyUserId());
+        fsUserInformationCollection.setQuestionId(param.getQuestionId());
+        fsUserInformationCollection.setId(param.getId());
+        fsUserInformationCollection.setPackageId(param.getPackageId());
+        fsUserInformationCollection.setPayType(param.getPayType());
+        fsUserInformationCollection.setAmount(param.getAmount());
+        fsUserInformationCollection.setIsPackage(param.getIsPackage());
+        fsUserInformationCollection.setUserName(param.getUserName());
+        fsUserInformationCollection.setUserPhoneFour(param.getUserPhoneFour());
+        fsUserInformationCollection.setSex(param.getSex());
+        fsUserInformationCollection.setAllergy(param.getAllergy());
+        fsUserInformationCollection.setRemark(param.getRemark());
+        fsUserInformationCollection.setPatientId(param.getPatientId());
+        fsUserInformationCollection.setDoctorSign(param.getDoctorSign());
+        //获取医生信息
+        CompanyUser companyUser = companyUserMapper.selectCompanyUserById(param.getCompanyUserId());
+        if (companyUser == null) {
+            throw new CustomException("销售不存在");
+        }
+        //医生
+        Long doctorId = companyUser.getDoctorId();
+        fsUserInformationCollection.setDoctorId(getDoctorId(doctorId,1,param.getPackageId()));
+        //药师
+        Long doctorType2Id = param.getDoctorType2Id();
+        fsUserInformationCollection.setDoctorType2Id(getDoctorId(doctorType2Id,2,param.getPackageId()));
+        return fsUserInformationCollection;
+    }
+
+    /**
+     *  如果是药师 需要根据套餐类型查询药师
+     * @param doctorId
+     * @param doctorType 1医生 2药师
+     * @return
+     */
+    private Long getDoctorId(Long doctorId,Integer doctorType,Long packageId) {
+        FsDoctor doctor = null;
+        if (doctorId != null) {
+            doctor = doctorMapper.selectFsDoctorByDoctorId(doctorId);
+        }
+        if (doctorId == null || doctor == null) {
+            if (doctorType == 1){
+                //随机获取医生id
+                doctorId = iFsDoctorService.selectFsDoctorDoctorByPackage();
+            } else if (doctorType == 2){
+                //随机获取药师id
+                FsPackage fsPackage = fsPackageMapper.selectFsPackageByPackageId(packageId);
+                if (fsPackage != null){
+                    doctor =doctorMapper.selectPackageFsDoctorType2Ids(fsPackage.getProductType());
+                }
+                if (doctor != null) {
+                    doctorId = doctor.getDoctorId();
+                }
+            }
+
+        }
+        return doctorId;
+    }
+
+}

+ 200 - 0
fs-service/src/main/java/com/fs/his/service/impl/MerchantAppConfigServiceImpl.java

@@ -0,0 +1,200 @@
+package com.fs.his.service.impl;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.fastjson.JSON;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.core.domain.entity.SysDictType;
+import com.fs.his.domain.FsPayConfig;
+import com.fs.his.domain.MerchantAppConfig;
+import com.fs.his.mapper.MerchantAppConfigMapper;
+import com.fs.his.service.IMerchantAppConfigService;
+import com.fs.hisStore.domain.FsPayConfigScrm;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import com.fs.system.mapper.SysDictTypeMapper;
+import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * 商户应用配置Service业务层处理
+ *
+ * @author fs
+ * @date 2025-12-05
+ */
+@Service
+@Slf4j
+public class MerchantAppConfigServiceImpl extends ServiceImpl<MerchantAppConfigMapper, MerchantAppConfig> implements IMerchantAppConfigService {
+
+    @Autowired
+    private SysConfigMapper sysConfigMapper;
+
+    /**
+     * 异步初始化方法
+     */
+    @PostConstruct
+    @Async("merchantInitExecutor")
+    public void init() {
+        log.info("开始异步初始化商户配置表...");
+
+        // 使用CompletableFuture进行异步初始化
+        CompletableFuture.runAsync(() -> {
+            try {
+                // 延迟5秒,等待数据库连接就绪
+                Thread.sleep(5000);
+                Integer count = baseMapper.checkTableExists();
+                if (ObjectUtil.isNotNull(count)&&count>0) {
+                    return;
+                }
+                // 1. 检查并创建表
+                initMerchantTable();
+
+            } catch (Exception e) {
+                log.error("初始化商户配置表失败", e);
+            }
+        });
+    }
+
+    /**
+     * 初始化商户配置表
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public void initMerchantTable() {
+        try {
+            // 检查表是否存在
+            log.info("商户配置表不存在,开始创建...");
+            baseMapper.createMerchantAppConfigTable();
+            log.info("商户配置表创建成功");
+        } catch (Exception e) {
+            log.error("初始化商户配置表失败", e);
+            throw e;
+        }
+    }
+    /**
+     * 查询商户应用配置
+     *
+     * @param id 商户应用配置主键
+     * @return 商户应用配置
+     */
+    @Override
+    public MerchantAppConfig selectMerchantAppConfigById(Long id)
+    {
+        return baseMapper.selectMerchantAppConfigById(id);
+    }
+
+    /**
+     * 查询商户应用配置列表
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 商户应用配置
+     */
+    @Override
+    public List<MerchantAppConfig> selectMerchantAppConfigList(MerchantAppConfig merchantAppConfig)
+    {
+        return baseMapper.selectMerchantAppConfigList(merchantAppConfig);
+    }
+
+    /**
+     * 新增商户应用配置
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 结果
+     */
+    @Override
+    public int insertMerchantAppConfig(MerchantAppConfig merchantAppConfig)
+    {
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+        switch (merchantAppConfig.getMerchantType()){
+            case "yb": // 易宝
+                merchantAppConfig.setMerchantId(fsPayConfig.getYbAccount());
+                merchantAppConfig.setCallbackUrl(fsPayConfig.getYbNotifyUrl());
+
+                break;
+            case "tz": // 台州
+                merchantAppConfig.setMerchantId(fsPayConfig.getTzPlatMerCstNo());
+                merchantAppConfig.setCallbackUrl(fsPayConfig.getTzPayDecrypt());
+                break;
+            case "wx": // 微信
+                merchantAppConfig.setMerchantId(fsPayConfig.getWxMchId());
+                merchantAppConfig.setCallbackUrl(fsPayConfig.getNotifyUrlScrm());
+                break;
+            case "hf": // 汇付
+                merchantAppConfig.setMerchantId(fsPayConfig.getHuifuId());
+                merchantAppConfig.setCallbackUrl(fsPayConfig.getHfPayNotifyUrl());
+                break;
+            default:
+                throw new RuntimeException("商户类型错误");
+        }
+
+        return baseMapper.insertMerchantAppConfig(merchantAppConfig);
+    }
+
+    /**
+     * 修改商户应用配置
+     *
+     * @param merchantAppConfig 商户应用配置
+     * @return 结果
+     */
+    @Override
+    public int updateMerchantAppConfig(MerchantAppConfig merchantAppConfig)
+    {
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+        switch (merchantAppConfig.getMerchantType()){
+            case "yb": // 易宝
+                merchantAppConfig.setMerchantId(fsPayConfig.getYbAccount());
+                merchantAppConfig.setCallbackUrl(fsPayConfig.getYbNotifyUrl());
+
+                break;
+            case "tz": // 台州
+                merchantAppConfig.setMerchantId(fsPayConfig.getTzPlatMerCstNo());
+                merchantAppConfig.setCallbackUrl(fsPayConfig.getTzPayDecrypt());
+                break;
+            case "wx": // 微信
+                merchantAppConfig.setMerchantId(fsPayConfig.getWxMchId());
+                merchantAppConfig.setCallbackUrl(fsPayConfig.getNotifyUrlScrm());
+                break;
+            case "hf": // 汇付
+                merchantAppConfig.setMerchantId(fsPayConfig.getHuifuId());
+                merchantAppConfig.setCallbackUrl(fsPayConfig.getHfPayNotifyUrl());
+                break;
+            default:
+                throw new RuntimeException("商户类型错误");
+        }
+        return baseMapper.updateMerchantAppConfig(merchantAppConfig);
+    }
+
+    /**
+     * 批量删除商户应用配置
+     *
+     * @param ids 需要删除的商户应用配置主键
+     * @return 结果
+     */
+    @Override
+    public int deleteMerchantAppConfigByIds(Long[] ids)
+    {
+        return baseMapper.deleteMerchantAppConfigByIds(ids);
+    }
+
+    /**
+     * 删除商户应用配置信息
+     *
+     * @param id 商户应用配置主键
+     * @return 结果
+     */
+    @Override
+    public int deleteMerchantAppConfigById(Long id)
+    {
+        MerchantAppConfig merchantAppConfig = new MerchantAppConfig();
+        merchantAppConfig.setId( id);
+        merchantAppConfig.setIsDeleted(1L);
+        return baseMapper.updateMerchantAppConfig(merchantAppConfig);
+    }
+}

+ 32 - 0
fs-service/src/main/java/com/fs/his/vo/AnswerVO.java

@@ -0,0 +1,32 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class AnswerVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private String title;
+
+    private List<Options> options;
+
+    //已选择数据(多选)
+    private List<Integer> value;
+
+    //排序
+    private Integer sort;
+    //private Integer value;
+
+
+    //是否医生已确认
+    private Boolean flag;
+
+   @Data
+    public static class Options implements Serializable{
+        private String name;
+        private Integer value;
+    }
+}

+ 15 - 0
fs-service/src/main/java/com/fs/his/vo/FsQuestionAndAnswerVO.java

@@ -0,0 +1,15 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FsQuestionAndAnswerVO {
+
+    private Long id;
+
+    private String questionName;
+
+    private List<AnswerVO> answers;
+}

+ 12 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserInfoCollectionAndStoreOrderVo.java

@@ -0,0 +1,12 @@
+package com.fs.his.vo;
+
+import com.fs.his.domain.FsUserInformationCollection;
+import lombok.Data;
+
+
+@Data
+public class FsUserInfoCollectionAndStoreOrderVo extends FsUserInformationCollection {
+    private String storeOrderCode;
+
+
+}

+ 79 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserInfoCollectionUVO.java

@@ -0,0 +1,79 @@
+package com.fs.his.vo;
+
+import com.fs.his.domain.FsDoctor;
+import com.fs.his.domain.FsPackage;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class FsUserInfoCollectionUVO {
+    private Long id;
+
+    //套餐包id
+    private Long packageId;
+
+    //支付类型 0-全款 1-物流代收
+    private Integer payType;
+
+    //代收金额
+    private BigDecimal amount;
+
+    private List<AnswerVO> answers;
+
+    //是否关联套餐包 0-不关联 1-关联
+    private Integer isPackage;
+
+    //确认状态 1第一次确认 2第二次确认
+    private Integer status;
+
+    private Integer doctorConfirm;
+
+    private Integer userConfirm;
+
+    private Integer userConfirm2;
+
+    private FsPackage fsPackage;
+
+    //销售id
+    private Long companyUserId;
+
+    //销售公司id
+    private Long companyId;
+
+    //套餐包订单号
+    private String packageOrderCode;
+
+    //订单状态 0-待支付 1-待发货 2-待收货 3-已完成 4-已取消
+    private Integer orderStatus;
+
+    private Long orderId;
+
+    private String userAdvice;
+
+    private String doctorAdvice;
+
+
+    private String patientJson;
+
+    //处方图片
+    private String prescribeImgUrl;
+
+    private FsDoctor doctor;
+
+    //处方审核状态 0待审核 1通过 2拒绝
+    private Integer prescribeStatus;
+
+    //是否过敏
+    private String allergy;
+    //备注
+    private String remark;
+
+    //用户性别 0女 1男
+    private Integer sex;
+    //用户姓名
+    private String userName;
+    //用户电话后四位
+    private String userPhoneFour;
+}

+ 22 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserInformationCollectionAndPatientVO.java

@@ -0,0 +1,22 @@
+package com.fs.his.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.his.domain.FsPatient;
+import com.fs.his.domain.FsUserInformationCollection;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class FsUserInformationCollectionAndPatientVO extends FsUserInformationCollection {
+    private FsPatient patientInfo; //病人信息
+    private Integer isPay;
+    private Long storeOrderId;
+    private String orderStatus;
+    private String packageJson;
+
+
+}

+ 23 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserInformationCollectionListDVO.java

@@ -0,0 +1,23 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+@Data
+public class FsUserInformationCollectionListDVO {
+
+    private Long id;
+
+    //用户信息
+    private String userName;
+
+    //医生确认状态 0未确认 1已确认
+    private Integer doctorConfirm;
+
+
+    private Integer userConfirm;
+
+    //用户补充说明
+    private String userAdvice;
+
+    private String doctorAdvice;
+}

+ 47 - 0
fs-service/src/main/java/com/fs/his/vo/FsUserInformationCollectionVO.java

@@ -0,0 +1,47 @@
+package com.fs.his.vo;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class FsUserInformationCollectionVO {
+
+    private Long id;
+
+    private Long questionId;
+
+    //套餐包id
+    private Long packageId;
+
+    //支付类型 0-全款 1-物流代收
+    private Integer payType;
+
+    //代收金额
+    private BigDecimal amount;
+
+    private List<AnswerVO> answers;
+
+    //是否关联套餐包 0-不关联 1-关联
+    private Integer isPackage;
+
+    //用户性别 0女 1男
+    private Integer sex;
+    //用户姓名
+    private String userName;
+    //用户电话后四位
+    private String userPhoneFour;
+
+    //是否过敏
+    private String allergy;
+
+    //备注
+    private String remark;
+
+    //医生建议
+    private String doctorAdvice;
+
+    private Long patientId;
+
+}

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

@@ -35,4 +35,6 @@ public class FsPayConfigScrm {
     private String notifyUrlScrm;
     private String publicKeyPath;
     private String publicKeyId;
+
+
 }

+ 3 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStorePaymentScrm.java

@@ -104,4 +104,7 @@ public class FsStorePaymentScrm extends BaseEntity
     //小程序appId(用于多汇付支付/退款)
     private String appId;
 
+    // 商户配置ID (用于多汇付支付/退款) 切换汇付后需要查询历史汇付配置信息退款
+    private Long merConfigId;
+
 }

+ 45 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductPurchaseLimitScrm.java

@@ -0,0 +1,45 @@
+package com.fs.hisStore.domain;
+
+import com.fs.common.annotation.Excel;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 商品限购对象 fs_store_product_purchase_limit
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+@Data
+public class FsStoreProductPurchaseLimitScrm implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /** 限购ID */
+    private Long id;
+
+    /** 商品ID */
+    @Excel(name = "商品ID")
+    private Long productId;
+
+    /** 用户ID */
+    @Excel(name = "用户ID")
+    private Long userId;
+
+    /** 已购买数量 */
+    @Excel(name = "已购买数量")
+    private Integer num;
+
+    /** 创建时间 */
+    @Excel(name = "创建时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 更新时间 */
+    @Excel(name = "更新时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+}
+

+ 34 - 0
fs-service/src/main/java/com/fs/hisStore/domain/FsStoreProductScrm.java

@@ -1,7 +1,9 @@
 package com.fs.hisStore.domain;
 
 import java.math.BigDecimal;
+import java.util.Date;
 
+import com.baidu.dev2.thirdparty.jackson.annotation.JsonFormat;
 import com.baomidou.mybatisplus.annotation.FieldStrategy;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.fs.common.annotation.Excel;
@@ -310,4 +312,36 @@ public class FsStoreProductScrm extends BaseEntity
     @Excel(name = "是否药品")
     private String isDrug;
 
+    /**
+     * 退货地址
+     */
+    @Excel(name = "退货地址")
+    private String returnAddress;
+
+
+    /** 原产地 */
+    @Excel(name = "原产地")
+    private String originPlace;
+
+    /** 净含量 */
+    @Excel(name = "净含量")
+    private String netContent;
+
+    /** 有效日期 */
+    @Excel(name = "有效日期")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date shelfLife;
+
+    /** 国产或进口 */
+    @Excel(name = "国产或进口")
+    private String domesticImported;
+
+    /** 所属小程序app_id,多个用逗号隔开 */
+    @Excel(name = "所属小程序app_id")
+    private String appIds;
+
+    /** 限购数量 */
+    @Excel(name = "限购数量")
+    private Integer purchaseLimit;
+
 }

+ 73 - 0
fs-service/src/main/java/com/fs/hisStore/mapper/FsStoreProductPurchaseLimitScrmMapper.java

@@ -0,0 +1,73 @@
+package com.fs.hisStore.mapper;
+
+import com.fs.hisStore.domain.FsStoreProductPurchaseLimitScrm;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 商品限购Mapper接口
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+public interface FsStoreProductPurchaseLimitScrmMapper
+{
+    /**
+     * 查询商品限购
+     *
+     * @param id 商品限购ID
+     * @return 商品限购
+     */
+    public FsStoreProductPurchaseLimitScrm selectFsStoreProductPurchaseLimitById(Long id);
+
+    /**
+     * 查询商品限购列表
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 商品限购集合
+     */
+    public List<FsStoreProductPurchaseLimitScrm> selectFsStoreProductPurchaseLimitList(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 根据商品ID和用户ID查询限购记录
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @return 商品限购
+     */
+    public FsStoreProductPurchaseLimitScrm selectByProductIdAndUserId(@Param("productId") Long productId, @Param("userId") Long userId);
+
+    /**
+     * 新增商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    public int insertFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 修改商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    public int updateFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 删除商品限购
+     *
+     * @param id 商品限购ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductPurchaseLimitById(Long id);
+
+    /**
+     * 批量删除商品限购
+     *
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductPurchaseLimitByIds(Long[] ids);
+}
+

+ 4 - 0
fs-service/src/main/java/com/fs/hisStore/param/FsStoreOrderOtherPayParam.java

@@ -17,5 +17,9 @@ public class FsStoreOrderOtherPayParam implements Serializable
     @NotNull(message = "code")
     private String code;
 
+    /**
+     * appId
+     */
+    private String appId;
 
 }

+ 92 - 0
fs-service/src/main/java/com/fs/hisStore/service/IFsStoreProductPurchaseLimitScrmService.java

@@ -0,0 +1,92 @@
+package com.fs.hisStore.service;
+
+import com.fs.hisStore.domain.FsStoreProductPurchaseLimitScrm;
+
+import java.util.List;
+
+/**
+ * 商品限购Service接口
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+public interface IFsStoreProductPurchaseLimitScrmService
+{
+    /**
+     * 查询商品限购
+     *
+     * @param id 商品限购ID
+     * @return 商品限购
+     */
+    public FsStoreProductPurchaseLimitScrm selectFsStoreProductPurchaseLimitById(Long id);
+
+    /**
+     * 查询商品限购列表
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 商品限购集合
+     */
+    public List<FsStoreProductPurchaseLimitScrm> selectFsStoreProductPurchaseLimitList(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 根据商品ID和用户ID查询限购记录
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @return 商品限购
+     */
+    public FsStoreProductPurchaseLimitScrm selectByProductIdAndUserId(Long productId, Long userId);
+
+    /**
+     * 新增商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    public int insertFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 修改商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    public int updateFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit);
+
+    /**
+     * 批量删除商品限购
+     *
+     * @param ids 需要删除的商品限购ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductPurchaseLimitByIds(Long[] ids);
+
+    /**
+     * 删除商品限购信息
+     *
+     * @param id 商品限购ID
+     * @return 结果
+     */
+    public int deleteFsStoreProductPurchaseLimitById(Long id);
+
+    /**
+     * 增加用户限购数量
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @param num 增加的数量
+     * @return 结果
+     */
+    public int increasePurchaseLimit(Long productId, Long userId, Integer num);
+
+    /**
+     * 减少用户限购数量
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @param num 减少的数量
+     * @return 结果
+     */
+    public int decreasePurchaseLimit(Long productId, Long userId, Integer num);
+}
+

+ 47 - 10
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreAfterSalesScrmServiceImpl.java

@@ -19,6 +19,8 @@ import com.fs.company.service.ICompanyService;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.erp.constant.AfterSalesOrderStatusEnum;
 import com.fs.erp.domain.FsJstAftersalePush;
 import com.fs.erp.dto.BaseResponse;
@@ -42,6 +44,7 @@ import com.fs.hisStore.param.*;
 import com.fs.huifuPay.domain.HuiFuRefundResult;
 import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayRefundRequest;
 import com.fs.huifuPay.service.HuiFuService;
+import com.fs.live.vo.LiveOrderItemListUVO;
 import com.fs.pay.service.IPayService;
 import com.fs.hisStore.config.StoreConfig;
 import com.fs.hisStore.domain.*;
@@ -84,6 +87,7 @@ import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.time.LocalDateTime;
 import java.util.*;
+import java.util.stream.Collectors;
 
 /**
  * 售后记录Service业务层处理
@@ -103,6 +107,10 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
     @Autowired
     private FsStoreAfterSalesScrmMapper fsStoreAfterSalesMapper;
     @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+    @Autowired
     private IFsStoreAfterSalesItemScrmService afterSalesItemService;
     @Autowired
     private IFsStoreAfterSalesStatusScrmService afterSalesStatusService;
@@ -390,6 +398,7 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
         request.setOid(order.getOrderCode());
         request.setRefund_state(1);
         request.setStoreAfterSalesId(storeAfterSales.getId());
+        request.setOrderStatus(orderStatus);
         if (StringUtils.isNotBlank(order.getExtendOrderId())){
             BaseResponse response=erpOrderService.refundUpdateScrm(request);
             if(response.getSuccess()){
@@ -745,12 +754,25 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
         if(order.getPayMoney().compareTo(BigDecimal.ZERO)==1){
             List<FsStorePaymentScrm> payments=paymentService.selectFsStorePaymentByOrderId(order.getId());
             if(payments!=null){
-                String json = configService.selectConfigByKey("his.pay");
-                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+
                 for(FsStorePaymentScrm payment:payments){
+                    if (StringUtils.isBlank(payment.getAppId())) {
+                        throw new IllegalArgumentException("appId不能为空");
+                    }
+                    FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+                    if (fsCoursePlaySourceConfig == null) {
+                        throw new CustomException("未找到appId对应的小程序配置: " + payment.getAppId());
+                    }
+                    Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                    if (merchantConfigId == null || merchantConfigId <= 0) {
+                        throw new CustomException("小程序没有配置商户信息");
+                    }
+                    MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                    FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+
                     if (payment.getPayMode()==null||payment.getPayMode().equals("wx")){
                         WxPayConfig payConfig = new WxPayConfig();
-                        payConfig.setAppId(fsPayConfig.getAppId());
+                        payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
                         payConfig.setKeyPath(fsPayConfig.getKeyPath());
@@ -784,7 +806,11 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
                         FsHfpayConfigMapper fsHfpayConfigMapper = SpringUtils.getBean(FsHfpayConfigMapper.class);
                         if (payment.getAppId() != null) {
                             FsHfpayConfig fsHfpayConfig = fsHfpayConfigMapper.selectByAppId(payment.getAppId());
-                            huifuId = fsHfpayConfig.getHuifuId();
+                            if (fsHfpayConfig == null){
+                                huifuId = fsPayConfig.getHuifuId();
+                            }else {
+                                huifuId = fsHfpayConfig.getHuifuId();
+                            }
                         } else {
                             if (("益善缘".equals(cloudHostProper.getCompanyName()))) {
 
@@ -1423,16 +1449,26 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
         }
         if (payments != null && payments.size() > 0) {
             FsStorePaymentScrm payment = payments.get(0);
-            String json = configService.selectConfigByKey("store.pay");
-            FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+//            String json = configService.selectConfigByKey("store.pay");
+            if (StringUtils.isBlank(payment.getAppId())) {
+                throw new IllegalArgumentException("appId不能为空");
+            }
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+            if (fsCoursePlaySourceConfig == null) {
+                throw new CustomException("未找到appId对应的小程序配置: " + payment.getAppId());
+            }
+            Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+            if (merchantConfigId == null || merchantConfigId <= 0) {
+                throw new CustomException("小程序没有配置商户信息");
+            }
+            MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+            FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
             if (payment.getPayMode().equals("wx")) {
                 WxPayConfig payConfig = new WxPayConfig();
-                //SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                //FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
-                payConfig.setAppId(fsPayConfig.getAppId());
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                 payConfig.setMchId(fsPayConfig.getWxMchId());
                 payConfig.setMchKey(fsPayConfig.getWxMchKey());
-                payConfig.setKeyPath(wxPayProperties.getKeyPath());
+                payConfig.setKeyPath(fsPayConfig.getKeyPath());
                 payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
                 payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
                 wxPayService.setConfig(payConfig);
@@ -1522,6 +1558,7 @@ public class FsStoreAfterSalesScrmServiceImpl implements IFsStoreAfterSalesScrmS
                 Map<String, Object> extendInfoMap = new HashMap<>();
                 extendInfoMap.put("org_req_seq_id", orderType + "-" + payment.getPayCode());
                 request.setExtendInfo(extendInfoMap);
+                request.setAppId(payment.getAppId());
                 HuiFuRefundResult refund = huiFuService.refund(request);
                 logger.info("订单退款返回结果:退款订单id:" + order.getOrderId() + refund);
                 if ((refund.getResp_code().equals("00000000") || refund.getResp_code().equals("00000100")) && (refund.getTrans_stat().equals("S") || refund.getTrans_stat().equals("P"))) {

+ 117 - 36
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreOrderScrmServiceImpl.java

@@ -47,8 +47,10 @@ import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.course.dto.OrderOpenIdTransDTO;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
 import com.fs.erp.dto.df.*;
@@ -65,6 +67,7 @@ import com.fs.his.enums.FsStoreOrderStatusEnum;
 import com.fs.his.mapper.*;
 import com.fs.his.param.FsStoreOrderSalesParam;
 import com.fs.his.service.IFsPrescribeService;
+import com.fs.his.service.IFsUserIntegralLogsService;
 import com.fs.his.service.IFsUserWatchService;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.his.vo.FsInquiryOrderVO;
@@ -104,6 +107,7 @@ import com.fs.hisStore.domain.*;
 import com.fs.hisStore.enums.*;
 import com.fs.hisStore.service.*;
 import com.fs.system.service.ISysConfigService;
+import com.fs.system.service.ISysDictTypeService;
 import com.fs.wx.miniapp.config.WxMaProperties;
 import com.fs.wx.order.domain.FsWxExpressTask;
 import com.fs.wx.order.dto.*;
@@ -183,6 +187,10 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     @Autowired
     private CompanyUserUserMapper companyUserUserMapper;
     @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+    @Autowired
     private IFsStoreOrderStatusScrmService orderStatusService;
     @Autowired
     private FsStoreCartScrmMapper cartMapper;
@@ -379,6 +387,14 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     @Autowired
     private IFsStoreCartScrmService fsStoreCartScrmService;
 
+    @Autowired
+    private ISysDictTypeService sysDictTypeService;
+    @Autowired
+    private IFsUserIntegralLogsService userIntegralLogsService;
+    @Autowired
+    private FsStoreProductPackageScrmMapper fsStoreProductPackageMapper;
+
+
     @PostConstruct
     public void initErpServiceMap() {
         erpServiceMap = new HashMap<>();
@@ -615,8 +631,11 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     public List<FsStoreOrderVO> selectFsStoreOrderListVO(FsStoreOrderParam param) {
         List<FsStoreOrderVO> list = fsStoreOrderMapper.selectFsStoreOrderListVO(param);
         for (FsStoreOrderVO vo : list) {
-            String nickName = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
-            vo.setNickname(nickName);
+            if (StringUtils.isNotEmpty(vo.getUserPhone())){
+                String nickName = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
+                vo.setNickname(nickName);
+            }
+
             if (StringUtils.isNotEmpty(vo.getItemJson())) {
                 JSONArray jsonArray = JSONUtil.parseArray(vo.getItemJson());
                 List<FsStoreOrderItemVO> items = JSONUtil.toList(jsonArray, FsStoreOrderItemVO.class);
@@ -634,8 +653,11 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
     public List<FsStoreOrderVO> selectFsStoreOrderAllListVO(FsStoreOrderParam param) {
         List<FsStoreOrderVO> list = fsStoreOrderMapper.selectFsStoreOrderAllListVO(param);
         for (FsStoreOrderVO vo : list) {
-            String nickName = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
-            vo.setNickname(nickName);
+            if (StringUtils.isNotEmpty(vo.getUserPhone())){
+                String nickName = vo.getUserPhone().replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
+                vo.setNickname(nickName);
+            }
+
             if (StringUtils.isNotEmpty(vo.getItemJson())) {
                 JSONArray jsonArray = JSONUtil.parseArray(vo.getItemJson());
                 List<FsStoreOrderItemVO> items = JSONUtil.toList(jsonArray, FsStoreOrderItemVO.class);
@@ -827,7 +849,8 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             //获取地址
             FsUserAddressScrm address = userAddressMapper.selectFsUserAddressById(param.getAddressId());
             //生成分布式唯一值
-            String orderSn = IdUtil.getSnowflake(0, 0).nextIdStr();
+
+            String orderSn = OrderCodeUtils.getOrderSn();
             //是否使用积分
             Boolean isIntegral = false;
             //组合数据
@@ -2318,6 +2341,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             request.setTid(order.getOrderCode());
             request.setOid(order.getOrderCode());
             request.setRefund_state(1);
+            request.setOrderStatus(order.getStatus());
             //BaseResponse response=erpOrderService.refundUpdate(request);
 //            if(response.getSuccess()){
 //            }
@@ -2368,13 +2392,24 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             //将钱退还给用户
             List<FsStorePaymentScrm> payments = paymentService.selectFsStorePaymentByOrderId(order.getId());
             if (payments != null) {
-                String json = configService.selectConfigByKey("his.pay");
-
-                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
                 for (FsStorePaymentScrm payment : payments) {
+                    if (StringUtils.isBlank(payment.getAppId())) {
+                        throw new IllegalArgumentException("appId不能为空");
+                    }
+                    FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+                    if (fsCoursePlaySourceConfig == null) {
+                        throw new CustomException("未找到appId对应的小程序配置: " + payment.getAppId());
+                    }
+                    Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                    if (merchantConfigId == null || merchantConfigId <= 0) {
+                        throw new CustomException("小程序没有配置商户信息");
+                    }
+                    MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                    FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+
                     if (payment.getPayMode() == null || payment.getPayMode().equals("wx")) {
                         WxPayConfig payConfig = new WxPayConfig();
-                        payConfig.setAppId(fsPayConfig.getAppId());
+                        payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                         payConfig.setMchId(fsPayConfig.getWxMchId());
                         payConfig.setMchKey(fsPayConfig.getWxMchKey());
                         payConfig.setKeyPath(fsPayConfig.getKeyPath());
@@ -2432,6 +2467,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                         Map<String, Object> extendInfoMap = new HashMap<>();
                         extendInfoMap.put("org_party_order_id", payment.getBankSerialNo());
                         request.setExtendInfo(extendInfoMap);
+                        request.setAppId(payment.getAppId());
                         HuiFuRefundResult refund = huiFuService.refund(request);
                         logger.info("退款:" + refund);
                         if ((refund.getResp_code().equals("00000000") || refund.getResp_code().equals("00000100")) && (refund.getTrans_stat().equals("S") || refund.getTrans_stat().equals("P"))) {
@@ -4077,7 +4113,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 else if(param.getPayType().equals(2)){
                     order.setPayType("2");
                     BigDecimal payMoney=order.getPayPrice().multiply(new BigDecimal(storeConfig.getPayRate())).divide(new BigDecimal(100));
-                    payMoney=new BigDecimal(payMoney.setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
+                    payMoney=new BigDecimal(payMoney.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                     // 如果小程序需要支付的金额小于0.01元,不能走物流代收,让走货到付款 xgb
                     if (payMoney.compareTo(new BigDecimal("0.01")) < 0) {
                         return R.error("物流代收计算支付金额为0,不允许选择物流代收");
@@ -4111,12 +4147,23 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             }
             String payCode = IdUtil.getSnowflake(0, 0).nextIdStr();
             if((order.getPayType().equals("1")||order.getPayType().equals("2")||order.getPayType().equals("3")) && order.getPayMoney().compareTo(new BigDecimal(0))>0){
-                String json = configService.selectConfigByKey(STORE_PAY_CONF);
-                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+                if (StringUtils.isBlank(param.getAppId())) {
+                    throw new IllegalArgumentException("appId不能为空");
+                }
+                FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+                if (fsCoursePlaySourceConfig == null) {
+                    throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+                }
+                Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                if (merchantConfigId == null || merchantConfigId <= 0) {
+                    throw new CustomException("小程序没有配置商户信息");
+                }
+                MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
                 FsStorePaymentScrm storePayment=new FsStorePaymentScrm();
                 storePayment.setCompanyId(order.getCompanyId());
                 storePayment.setCompanyUserId(order.getCompanyUserId());
-                storePayment.setPayMode(fsPayConfig.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setStatus(0);
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(order.getPayMoney());
@@ -4128,10 +4175,10 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 storePayment.setUserId(user.getUserId());
                 storePayment.setBusinessOrderId(order.getId().toString());
                 storePayment.setOrderId(order.getId());
-                storePayment.setAppId(fsPayConfig.getAppId() == null ? "" : fsPayConfig.getAppId());
+                storePayment.setAppId(fsCoursePlaySourceConfig.getAppid() == null ? "" : fsCoursePlaySourceConfig.getAppid());
                 fsStorePaymentMapper.insertFsStorePayment(storePayment);
 
-                if (fsPayConfig.getType().equals("hf")){
+                if (merchantAppConfig.getMerchantType().equals("hf")){
                     HuiFuCreateOrder o = new HuiFuCreateOrder();
                     o.setTradeType("T_MINIAPP");
                     o.setOpenid(user.getMaOpenId());
@@ -4140,7 +4187,8 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                     o.setGoodsDesc("商城订单支付");
                     o.setAppId(param.getAppId());
                     try {
-                        HuiFuUtils.doDiv(o,order.getCompanyId());
+
+                        HuiFuUtils.doDiv(o,order.getCompanyId(), storePayment.getMerConfigId());
                         //存储分账明细
                         HuiFuUtils.saveDivItem(o, order.getOrderCode(), storePayment.getPayCode());
                     } catch (Exception e) {
@@ -4163,9 +4211,9 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                     else{
                         return R.error(result.getResp_desc());
                     }
-                }else  if (fsPayConfig.getType().equals("wx")){
+                }else  if (merchantAppConfig.getMerchantType().equals("wx")){
                     WxPayConfig payConfig = new WxPayConfig();
-                    payConfig.setAppId(fsPayConfig.getAppId());
+                    payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                     payConfig.setMchId(fsPayConfig.getWxMchId());
                     payConfig.setMchKey(fsPayConfig.getWxMchKey());
                     payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -4249,13 +4297,24 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 return R.error("此订单已支付");
             }
             String payCode = IdUtil.getSnowflake(0, 0).nextIdStr();
-            String json = configService.selectConfigByKey(STORE_PAY_CONF);
-            FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+            if (StringUtils.isBlank(param.getAppId())) {
+                throw new IllegalArgumentException("appId不能为空");
+            }
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+            if (fsCoursePlaySourceConfig == null) {
+                throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+            }
+            Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+            if (merchantConfigId == null || merchantConfigId <= 0) {
+                throw new CustomException("小程序没有配置商户信息");
+            }
+            MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+            FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
             FsStorePaymentScrm storePayment=new FsStorePaymentScrm();
             storePayment.setCompanyId(order.getCompanyId());
             storePayment.setCompanyUserId(order.getCompanyUserId());
             storePayment.setStatus(0);
-            storePayment.setPayMode(fsPayConfig.getType());
+            storePayment.setPayMode(merchantAppConfig.getMerchantType());
             storePayment.setPayCode(payCode);
             storePayment.setPayMoney(order.getPayDelivery());
             storePayment.setCreateTime(new Date());
@@ -4269,7 +4328,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             storePayment.setIsPayRemain(1);
             fsStorePaymentMapper.insertFsStorePayment(storePayment);
 
-            if (fsPayConfig.getType().equals("hf")){
+            if (merchantAppConfig.getMerchantType().equals("hf")){
                 HuiFuCreateOrder o = new HuiFuCreateOrder();
                 o.setTradeType("T_MINIAPP");
                 o.setOpenid(user.getMaOpenId());
@@ -4292,10 +4351,10 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 else{
                     return R.error(result.getResp_desc());
                 }
-            }else  if (fsPayConfig.getType().equals("wx")){
+            }else  if (merchantAppConfig.getMerchantType().equals("wx")){
                 //创建微信订单
                 WxPayConfig payConfig = new WxPayConfig();
-                payConfig.setAppId(fsPayConfig.getAppId());
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                 payConfig.setMchId(fsPayConfig.getWxMchId());
                 payConfig.setMchKey(fsPayConfig.getWxMchKey());
                 payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -4365,8 +4424,19 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 return R.error("正在支付中...");
             }
 
-            String json = configService.selectConfigByKey(STORE_PAY_CONF);
-            FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+            if (StringUtils.isBlank(param.getAppId())) {
+                throw new IllegalArgumentException("appId不能为空");
+            }
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+            if (fsCoursePlaySourceConfig == null) {
+                throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+            }
+            Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+            if (merchantConfigId == null || merchantConfigId <= 0) {
+                throw new CustomException("小程序没有配置商户信息");
+            }
+            MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+            FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
             String payCode = IdUtil.getSnowflake(0, 0).nextIdStr();
             //易宝支付
             FsStorePaymentScrm storePayment=new FsStorePaymentScrm();
@@ -4374,7 +4444,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             storePayment.setCompanyUserId(order.getCompanyUserId());
             storePayment.setStatus(0);
             storePayment.setPayCode(payCode);
-            storePayment.setPayMode(fsPayConfig.getType());
+            storePayment.setPayMode(merchantAppConfig.getMerchantType());
             storePayment.setPayMoney(order.getPayMoney());
             storePayment.setCreateTime(new Date());
             storePayment.setPayTypeCode("weixin");
@@ -4386,7 +4456,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             storePayment.setOrderId(order.getId());
             fsStorePaymentMapper.insertFsStorePayment(storePayment);
 
-            if (fsPayConfig.getType().equals("hf")){
+            if (merchantAppConfig.getMerchantType().equals("hf")){
                 HuiFuCreateOrder o = new HuiFuCreateOrder();
                 o.setTradeType("T_MINIAPP");
                 o.setOpenid(user.getMaOpenId());
@@ -4409,10 +4479,10 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 else{
                     return R.error(result.getResp_desc());
                 }
-            }else  if (fsPayConfig.getType().equals("wx")){
+            }else  if (merchantAppConfig.getMerchantType().equals("wx")){
                 //创建微信订单
                 WxPayConfig payConfig = new WxPayConfig();
-                payConfig.setAppId(fsPayConfig.getAppId());
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                 payConfig.setMchId(fsPayConfig.getWxMchId());
                 payConfig.setMchKey(fsPayConfig.getWxMchKey());
                 payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -4467,13 +4537,24 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
         FsUserScrm user=userService.selectFsUserById(order.getUserId());
         if(user!=null){
             String payCode = IdUtil.getSnowflake(0, 0).nextIdStr();
-            String json = configService.selectConfigByKey(STORE_PAY_CONF);
-            FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+            if (StringUtils.isBlank(param.getAppId())) {
+                throw new IllegalArgumentException("appId不能为空");
+            }
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+            if (fsCoursePlaySourceConfig == null) {
+                throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+            }
+            Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+            if (merchantConfigId == null || merchantConfigId <= 0) {
+                throw new CustomException("小程序没有配置商户信息");
+            }
+            MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+            FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
             FsStorePaymentScrm storePayment=new FsStorePaymentScrm();
             storePayment.setCompanyId(order.getCompanyId());
             storePayment.setCompanyUserId(order.getCompanyUserId());
             storePayment.setStatus(0);
-            storePayment.setPayMode(fsPayConfig.getType());
+            storePayment.setPayMode(merchantAppConfig.getMerchantType());
             storePayment.setPayCode(payCode);
             storePayment.setPayMoney(order.getPayDelivery());
             storePayment.setCreateTime(new Date());
@@ -4487,7 +4568,7 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
             storePayment.setIsPayRemain(1);
             fsStorePaymentMapper.insertFsStorePayment(storePayment);
 
-            if (fsPayConfig.getType().equals("hf")){
+            if (merchantAppConfig.getMerchantType().equals("hf")){
                 HuiFuCreateOrder o = new HuiFuCreateOrder();
                 o.setTradeType("T_MINIAPP");
                 o.setOpenid(user.getMaOpenId());
@@ -4511,9 +4592,9 @@ public class FsStoreOrderScrmServiceImpl implements IFsStoreOrderScrmService {
                 else{
                     return R.error(result.getResp_desc());
                 }
-            }else if(fsPayConfig.getType().equals("wx")) {
+            }else if(merchantAppConfig.getMerchantType().equals("wx")) {
                 WxPayConfig payConfig = new WxPayConfig();
-                payConfig.setAppId(fsPayConfig.getAppId());
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                 payConfig.setMchId(fsPayConfig.getWxMchId());
                 payConfig.setMchKey(fsPayConfig.getWxMchKey());
                 payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));

+ 128 - 35
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStorePaymentScrmServiceImpl.java

@@ -13,12 +13,17 @@ import cn.hutool.json.JSONUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.TypeReference;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.common.annotation.DataScope;
 import com.fs.common.config.FSSysConfig;
 import com.fs.common.core.domain.R;
 import com.fs.common.core.redis.RedisCache;
+import com.fs.common.exception.CustomException;
 import com.fs.common.utils.DateUtils;
+import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
+import com.fs.common.utils.ip.IpUtils;
 import com.fs.company.domain.Company;
 import com.fs.company.domain.CompanyUser;
 import com.fs.company.mapper.CompanyConfigMapper;
@@ -27,12 +32,18 @@ import com.fs.company.service.ICompanyUserService;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.utils.OrderCodeUtils;
 import com.fs.course.config.RedPacketConfig;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.domain.FsCourseRedPacketLog;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.course.mapper.FsCourseRedPacketLogMapper;
 import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.his.config.FsSysConfig;
+import com.fs.his.domain.FsPayConfig;
 import com.fs.his.domain.FsUser;
 import com.fs.his.domain.FsUserWx;
+import com.fs.his.domain.MerchantAppConfig;
+import com.fs.his.mapper.FsUserWxMapper;
+import com.fs.his.mapper.MerchantAppConfigMapper;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.service.IFsUserWxService;
 import com.fs.his.utils.ConfigUtil;
@@ -58,6 +69,7 @@ import com.fs.ybPay.domain.CreateWxOrderResult;
 import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
 import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
 import com.github.binarywang.wxpay.bean.notify.WxPayTransferBatchesNotifyV3Result;
+import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
 import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
 import com.github.binarywang.wxpay.bean.transfer.*;
 import com.github.binarywang.wxpay.config.WxPayConfig;
@@ -67,6 +79,7 @@ import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
 import com.google.common.reflect.TypeToken;
 import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.error.WxErrorException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -87,15 +100,17 @@ import javax.servlet.http.HttpServletRequest;
  * @date 2022-06-20
  */
 @Service
+@Slf4j
 public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
 {
     Logger logger = LoggerFactory.getLogger(getClass());
     @Autowired
-    private WxMaProperties properties;
+    private WxPayService wxPayService;
+
     @Autowired
-    private IPayService payService;
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
     @Autowired
-    private FSSysConfig sysConfig;
+    private MerchantAppConfigMapper merchantAppConfigMapper;
     @Autowired
     private FsStorePaymentScrmMapper fsStorePaymentMapper;
     @Autowired
@@ -787,7 +802,7 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
             }
         }
         return R.ok();
-        }
+    }
 
 
     @Override
@@ -844,6 +859,8 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
 
     @Autowired
     private IFsUserService fsUserService;
+    @Autowired
+    private FsUserWxMapper fsUserWxMapper;
 
     @Override
     public R paymentByWxaCode(FsStorePaymentPayParam param) {
@@ -864,9 +881,41 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
                 return R.error("注册失败客服已停用,或不存在!");
             }
         }
-
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = com.hc.openapi.tool.fastjson.JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
         //生成支付流水
         String orderSn = IdUtil.getSnowflake(0, 0).nextIdStr();
+
+        //获取用户openid
+        String openId = null;
+        String appId = param.getAppId();
+
+        //查询fs_user_wx的openId
+        Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
+                .eq(FsUserWx::getFsUserId, param.getUserId())
+                .eq(FsUserWx::getAppId, appId);
+        FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
+        if (fsUserWx != null) {
+            openId = fsUserWx.getOpenId();
+        }else {
+            openId = user.getMaOpenId();
+        }
+
+        if (StringUtils.isEmpty(openId)){
+            return R.error("openId参数错误!");
+        }
+
         FsStorePaymentScrm storePayment=new FsStorePaymentScrm();
         storePayment.setCompanyId(param.getCompanyId());
         //判断销售是否存在
@@ -882,38 +931,82 @@ public class FsStorePaymentScrmServiceImpl implements IFsStorePaymentScrmService
         storePayment.setRemark("商城收款订单支付");
         storePayment.setOpenId(user.getMaOpenId());
         storePayment.setUserId(user.getUserId());
-        storePayment.setPayMode("hf");//目前微信收款仅支持汇付
-        fsStorePaymentMapper.insertFsStorePayment(storePayment);
 
-        //汇付支付
-        HuiFuCreateOrder o = new HuiFuCreateOrder();
-        o.setTradeType("T_MINIAPP");
-        o.setOpenid(user.getMaOpenId());
-        o.setReqSeqId("payment-"+storePayment.getPayCode());
-        o.setTransAmt(storePayment.getPayMoney().toString());
-        o.setGoodsDesc("商城订单支付");
-        o.setAppId(param.getAppId());
-        //公司分账
-        try {
-            HuiFuUtils.doDiv(o,company.getCompanyId());
-            //存储分账明细
-            HuiFuUtils.saveDivItem(o, storePayment.getPayCode(), storePayment.getPayCode());
-        } catch (Exception e) {
-            logger.error("-------------微信收款分账出错:{}", e.getMessage());
-        }
-        HuifuCreateOrderResult result = huiFuService.createOrder(o);
-        if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
-            FsStorePaymentScrm mt=new FsStorePaymentScrm();
-            mt.setPaymentId(storePayment.getPaymentId());
-            mt.setTradeNo(result.getHf_seq_id());
-            fsStorePaymentMapper.updateFsStorePayment(mt);
-            Map<String, Object> resultMap = JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {});
-            String s = (String) resultMap.get("package");
-            resultMap.put("packageValue",s);
-            return R.ok().put("result",resultMap);
+        if (merchantAppConfig.getMerchantType().equals("wx")){
+            storePayment.setPayMode("wx");
+        }else if (merchantAppConfig.getMerchantType().equals("hf")) {
+            storePayment.setPayMode("hf");
         }
-        else{
-            return R.error(result.getResp_desc());
+        storePayment.setAppId(param.getAppId());
+        if (fsStorePaymentMapper.insertFsStorePayment(storePayment) > 0) {
+            if (merchantAppConfig.getMerchantType().equals("wx")) {
+                //创建微信订单
+                WxPayConfig payConfig = new WxPayConfig();
+                payConfig.setAppId(appId);
+                payConfig.setMchId(fsPayConfig.getWxMchId());
+                payConfig.setMchKey(fsPayConfig.getWxMchKey());
+                payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                payConfig.setKeyPath(null);
+                payConfig.setNotifyUrl(fsPayConfig.getNotifyUrlScrm());
+                wxPayService.setConfig(payConfig);
+                WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
+                orderRequest.setOpenid(openId);//公众号支付提供用户openid
+                orderRequest.setBody("收款支付");
+                orderRequest.setOutTradeNo("payment-" + storePayment.getPayCode());
+                orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(storePayment.getPayMoney().toString()));//测试
+                //orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(money));//测试
+                orderRequest.setTradeType("JSAPI");
+                orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+                //调用统一下单接口,获取"预支付交易会话标识"
+                try {
+                    WxPayMpOrderResult orderResult = wxPayService.createOrder(orderRequest);
+                    return R.ok().put("result", orderResult).put("type", "wx").put("isPay", 0);
+                } catch (WxPayException e) {
+                    e.printStackTrace();
+                    throw new CustomException("支付失败" + e.getMessage());
+                }
+            } else if (merchantAppConfig.getMerchantType().equals("hf")) {
+
+                //汇付支付
+                HuiFuCreateOrder o = new HuiFuCreateOrder();
+                o.setTradeType("T_MINIAPP");
+                o.setOpenid(openId);
+                o.setReqSeqId("payment-"+storePayment.getPayCode());
+                o.setTransAmt(storePayment.getPayMoney().toString());
+                o.setGoodsDesc("商城订单支付");
+                o.setAppId(appId);
+                //公司分账
+                try {
+                    HuiFuUtils.doDiv(o,company.getCompanyId(), storePayment.getMerConfigId());
+                    //存储分账明细
+                    HuiFuUtils.saveDivItem(o, storePayment.getPayCode(), storePayment.getPayCode());
+                } catch (Exception e) {
+                    logger.error("-------------微信收款分账出错:{}", e.getMessage());
+                }
+                HuifuCreateOrderResult result = huiFuService.createOrder(o);
+
+                if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
+                    FsStorePaymentScrm mt=new FsStorePaymentScrm();
+                    mt.setPaymentId(storePayment.getPaymentId());
+                    mt.setTradeNo(result.getHf_seq_id());
+                    mt.setAppId(appId);
+                    fsStorePaymentMapper.updateFsStorePayment(mt);
+                    Map<String, Object> resultMap = com.alibaba.fastjson.JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {});
+                    String s = (String) resultMap.get("package");
+                    resultMap.put("packageValue",s);
+                    return R.ok().put("result",resultMap);
+                }
+                else{
+                    return R.error(result.getResp_desc());
+                }
+            }
+        }else {
+            return R.error("新增订单失败!");
         }
+        return R.error("支付失败!");
+
     }
+
+
 }

+ 242 - 0
fs-service/src/main/java/com/fs/hisStore/service/impl/FsStoreProductPurchaseLimitScrmServiceImpl.java

@@ -0,0 +1,242 @@
+package com.fs.hisStore.service.impl;
+
+import com.fs.common.constant.LiveKeysConstant;
+import com.fs.common.core.redis.RedisCache;
+import com.fs.common.utils.DateUtils;
+import com.fs.hisStore.domain.FsStoreProductAttrScrm;
+import com.fs.hisStore.domain.FsStoreProductAttrValueScrm;
+import com.fs.hisStore.domain.FsStoreProductPurchaseLimitScrm;
+import com.fs.hisStore.domain.FsStoreProductScrm;
+import com.fs.hisStore.mapper.FsStoreProductAttrScrmMapper;
+import com.fs.hisStore.mapper.FsStoreProductAttrValueScrmMapper;
+import com.fs.hisStore.mapper.FsStoreProductPurchaseLimitScrmMapper;
+import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
+import com.fs.hisStore.service.IFsStoreProductPurchaseLimitScrmService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 商品限购Service业务层处理
+ *
+ * @author fs
+ * @date 2024-01-01
+ */
+@Service
+public class FsStoreProductPurchaseLimitScrmServiceImpl implements IFsStoreProductPurchaseLimitScrmService
+{
+    @Autowired
+    private FsStoreProductPurchaseLimitScrmMapper fsStoreProductPurchaseLimitMapper;
+
+    @Autowired
+    private RedisCache redisCache;
+    @Autowired
+    private FsStoreProductScrmMapper fsStoreProductScrmMapper;
+    @Autowired
+    private FsStoreProductAttrScrmMapper fsStoreProductAttrScrmMapper;
+    @Autowired
+    private FsStoreProductAttrValueScrmMapper fsStoreProductAttrValueScrmMapper;
+
+
+    /**
+     * 查询商品限购
+     *
+     * @param id 商品限购ID
+     * @return 商品限购
+     */
+    @Override
+    public FsStoreProductPurchaseLimitScrm selectFsStoreProductPurchaseLimitById(Long id)
+    {
+        return fsStoreProductPurchaseLimitMapper.selectFsStoreProductPurchaseLimitById(id);
+    }
+
+    /**
+     * 查询商品限购列表
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 商品限购
+     */
+    @Override
+    public List<FsStoreProductPurchaseLimitScrm> selectFsStoreProductPurchaseLimitList(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit)
+    {
+        return fsStoreProductPurchaseLimitMapper.selectFsStoreProductPurchaseLimitList(fsStoreProductPurchaseLimit);
+    }
+
+    /**
+     * 根据商品ID和用户ID查询限购记录
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @return 商品限购
+     */
+    @Override
+    public FsStoreProductPurchaseLimitScrm selectByProductIdAndUserId(Long productId, Long userId)
+    {
+        return fsStoreProductPurchaseLimitMapper.selectByProductIdAndUserId(productId, userId);
+    }
+
+    /**
+     * 新增商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    @Override
+    public int insertFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit)
+    {
+        fsStoreProductPurchaseLimit.setCreateTime(DateUtils.getNowDate());
+        return fsStoreProductPurchaseLimitMapper.insertFsStoreProductPurchaseLimit(fsStoreProductPurchaseLimit);
+    }
+
+    /**
+     * 修改商品限购
+     *
+     * @param fsStoreProductPurchaseLimit 商品限购
+     * @return 结果
+     */
+    @Override
+    public int updateFsStoreProductPurchaseLimit(FsStoreProductPurchaseLimitScrm fsStoreProductPurchaseLimit)
+    {
+        fsStoreProductPurchaseLimit.setUpdateTime(DateUtils.getNowDate());
+        return fsStoreProductPurchaseLimitMapper.updateFsStoreProductPurchaseLimit(fsStoreProductPurchaseLimit);
+    }
+
+    /**
+     * 批量删除商品限购
+     *
+     * @param ids 需要删除的商品限购ID
+     * @return 结果
+     */
+    @Override
+    public int deleteFsStoreProductPurchaseLimitByIds(Long[] ids)
+    {
+        return fsStoreProductPurchaseLimitMapper.deleteFsStoreProductPurchaseLimitByIds(ids);
+    }
+
+    /**
+     * 删除商品限购信息
+     *
+     * @param id 商品限购ID
+     * @return 结果
+     */
+    @Override
+    public int deleteFsStoreProductPurchaseLimitById(Long id)
+    {
+        return fsStoreProductPurchaseLimitMapper.deleteFsStoreProductPurchaseLimitById(id);
+    }
+
+    /**
+     * 增加用户限购数量
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @param num 增加的数量
+     * @return 结果
+     */
+    @Override
+    public int increasePurchaseLimit(Long productId, Long userId, Integer num)
+    {
+        String cacheKey = String.format(LiveKeysConstant.PRODUCT_DETAIL_CACHE, productId);
+        Map<String, Object> cachedData = redisCache.getCacheObject(cacheKey);
+
+        FsStoreProductScrm product;
+        List<FsStoreProductAttrScrm> productAttr;
+        List<FsStoreProductAttrValueScrm> productValues;
+
+        if (cachedData != null) {
+            // 从缓存中获取数据
+            product = (FsStoreProductScrm) cachedData.get("product");
+        } else {
+            // 缓存中没有,从数据库查询
+            product = fsStoreProductScrmMapper.selectFsStoreProductById(productId);
+            if(product==null){
+                return -1;
+            }
+            productAttr = fsStoreProductAttrScrmMapper.selectFsStoreProductAttrByProductId(productId);
+            productValues = fsStoreProductAttrValueScrmMapper.selectFsStoreProductAttrValueByProductId(productId);
+
+            // 将数据存入缓存
+            Map<String, Object> cacheData = new HashMap<>();
+            cacheData.put("product", product);
+            cacheData.put("productAttr", productAttr);
+            cacheData.put("productValues", productValues);
+            redisCache.setCacheObject(cacheKey, cacheData, LiveKeysConstant.PRODUCT_DETAIL_CACHE_EXPIRE, TimeUnit.SECONDS);
+        }
+        if (product != null && product.getPurchaseLimit() != null && product.getPurchaseLimit() > 0) {
+            FsStoreProductPurchaseLimitScrm limit = selectByProductIdAndUserId(productId, userId);
+            if (limit == null) {
+                // 创建新记录
+                limit = new FsStoreProductPurchaseLimitScrm();
+                limit.setProductId(productId);
+                limit.setUserId(userId);
+                limit.setNum(num);
+                return insertFsStoreProductPurchaseLimit(limit);
+            } else {
+                // 更新现有记录
+                limit.setNum(limit.getNum() + num);
+                return updateFsStoreProductPurchaseLimit(limit);
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * 减少用户限购数量
+     *
+     * @param productId 商品ID
+     * @param userId 用户ID
+     * @param num 减少的数量
+     * @return 结果
+     */
+    @Override
+    public int decreasePurchaseLimit(Long productId, Long userId, Integer num)
+    {
+        String cacheKey = String.format(LiveKeysConstant.PRODUCT_DETAIL_CACHE, productId);
+        Map<String, Object> cachedData = redisCache.getCacheObject(cacheKey);
+
+        FsStoreProductScrm product;
+        List<FsStoreProductAttrScrm> productAttr;
+        List<FsStoreProductAttrValueScrm> productValues;
+
+        if (cachedData != null) {
+            // 从缓存中获取数据
+            product = (FsStoreProductScrm) cachedData.get("product");
+        } else {
+            // 缓存中没有,从数据库查询
+            product = fsStoreProductScrmMapper.selectFsStoreProductById(productId);
+            if(product==null){
+                return -1;
+            }
+            productAttr = fsStoreProductAttrScrmMapper.selectFsStoreProductAttrByProductId(productId);
+            productValues = fsStoreProductAttrValueScrmMapper.selectFsStoreProductAttrValueByProductId(productId);
+
+            // 将数据存入缓存
+            Map<String, Object> cacheData = new HashMap<>();
+            cacheData.put("product", product);
+            cacheData.put("productAttr", productAttr);
+            cacheData.put("productValues", productValues);
+            redisCache.setCacheObject(cacheKey, cacheData, LiveKeysConstant.PRODUCT_DETAIL_CACHE_EXPIRE, TimeUnit.SECONDS);
+        }
+        if (product != null && product.getPurchaseLimit() != null && product.getPurchaseLimit() > 0) {
+            FsStoreProductPurchaseLimitScrm limit = selectByProductIdAndUserId(productId, userId);
+            if (limit != null) {
+                int newNum = limit.getNum() - num;
+                if (newNum <= 0) {
+                    // 如果数量为0或负数,删除记录
+                    return deleteFsStoreProductPurchaseLimitById(limit.getId());
+                } else {
+                    // 更新数量
+                    limit.setNum(newNum);
+                    return updateFsStoreProductPurchaseLimit(limit);
+                }
+            }
+            return 0;
+        }
+        return -1;
+    }
+}
+

+ 24 - 17
fs-service/src/main/java/com/fs/huifuPay/sdk/opps/core/utils/HuiFuUtils.java

@@ -6,28 +6,22 @@ import com.fs.common.utils.DateUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.domain.CompanyDivItem;
-import com.fs.company.mapper.CompanyDivConfigMapper;
 import com.fs.company.param.CompanyAcctInfo;
 import com.fs.company.service.ICompanyDivConfigService;
 import com.fs.company.service.ICompanyDivItemService;
-import com.fs.company.service.impl.CompanyDivConfigServiceImpl;
 import com.fs.company.vo.CompanyDivConfigVo;
-import com.fs.his.domain.FsPackageOrder;
-import com.fs.his.domain.FsPayConfig;
-import com.fs.his.domain.FsStoreOrder;
-import com.fs.his.domain.FsStorePayment;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
+import com.fs.his.domain.*;
 import com.fs.his.mapper.FsStorePaymentMapper;
+import com.fs.his.mapper.MerchantAppConfigMapper;
 import com.fs.hisStore.domain.FsStorePaymentScrm;
 import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
 import com.fs.huifuPay.domain.HuiFuConfirmOrder;
 import com.fs.huifuPay.domain.HuiFuCreateOrder;
 import com.fs.huifuPay.domain.HuiFuQueryOrderResult;
 import com.fs.huifuPay.service.HuiFuService;
-import com.fs.system.domain.SysConfig;
-import com.fs.system.mapper.SysConfigMapper;
-import com.google.gson.Gson;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.beans.factory.annotation.Autowired;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -46,12 +40,19 @@ public class HuiFuUtils {
      *
      * @param huiFuCreateOrder
      * @param companyId
+     * @param merConfigId
      */
-    public static void doDiv(HuiFuCreateOrder huiFuCreateOrder, Long companyId) throws Exception {
+    public static void doDiv(HuiFuCreateOrder huiFuCreateOrder, Long companyId, Long merConfigId) throws Exception {
         //默认汇付账户
-        SysConfigMapper sysConfigMapper = SpringUtils.getBean(SysConfigMapper.class);
-        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
+        FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper = SpringUtils.getBean(FsCoursePlaySourceConfigMapper.class);
+        MerchantAppConfigMapper merchantAppConfigMapper = SpringUtils.getBean(MerchantAppConfigMapper.class);
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(huiFuCreateOrder.getAppId());
+        Long merConfigIds = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if(merConfigId!=null){
+            merConfigIds=merConfigId;
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(merConfigIds);
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
         String defaultHuifuId = fsPayConfig.getHuifuId();
         //查询是否开启分账
         if (companyId != null) {
@@ -230,9 +231,15 @@ public class HuiFuUtils {
             if (payPrice.compareTo(reMoney) > 0) {
                 //部分退款
                 if (companyDivItem != null) {
-                    SysConfigMapper sysConfigMapper = SpringUtils.getBean(SysConfigMapper.class);
-                    SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                    FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
+                    FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper = SpringUtils.getBean(FsCoursePlaySourceConfigMapper.class);
+                    MerchantAppConfigMapper merchantAppConfigMapper = SpringUtils.getBean(MerchantAppConfigMapper.class);
+                    FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+                    Long merConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                    if(payment.getMerConfigId()!=null){
+                        merConfigId=payment.getMerConfigId();
+                    }
+                    MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(merConfigId);
+                    FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
                     String defaultHuiFuId = fsPayConfig.getHuifuId(); //默认汇付id
 
                     String detail = companyDivItem.getDetail();

+ 40 - 30
fs-service/src/main/java/com/fs/huifuPay/service/impl/HuiFuServiceImpl.java

@@ -5,9 +5,13 @@ import com.alibaba.fastjson.JSONObject;
 import com.fs.common.exception.CustomException;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.spring.SpringUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.his.domain.FsHfpayConfig;
 import com.fs.his.domain.FsPayConfig;
+import com.fs.his.domain.MerchantAppConfig;
 import com.fs.his.mapper.FsHfpayConfigMapper;
+import com.fs.his.mapper.MerchantAppConfigMapper;
 import com.fs.huifuPay.domain.*;
 import com.fs.huifuPay.sdk.opps.core.config.MerConfig;
 import com.fs.huifuPay.sdk.opps.core.request.*;
@@ -20,6 +24,7 @@ import com.google.gson.Gson;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
@@ -35,7 +40,10 @@ import static com.fs.huifuPay.demo.init.BaseCommon.doInit;
 public class HuiFuServiceImpl implements HuiFuService {
     FsPayConfig config;
     Logger logger= LoggerFactory.getLogger(getClass());
-
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
     @Override
     public HuifuCreateOrderResult createOrder(HuiFuCreateOrder order) {
         logger.info("汇付传参HuiFuCreateOrder==============>{}",order);
@@ -43,15 +51,8 @@ public class HuiFuServiceImpl implements HuiFuService {
         try {
 
             if (order.getAppId() != null) {
-                FsHfpayConfigMapper fsHfpayConfigMapper = SpringUtils.getBean(FsHfpayConfigMapper.class);
-                FsHfpayConfig fsHfpayConfig = fsHfpayConfigMapper.selectByAppId(order.getAppId());
-                if (fsHfpayConfig != null) {
-                    //多汇付支付获取配置
-                    doInit(getMerConfig(fsHfpayConfig));
-                } else {
-                    //多小程序
-                    doInit(getMerConfig());
-                }
+                //多小程序
+                doInit(getMerConfig(order.getAppId()));
             } else {
                 doInit(getMerConfig());
             }
@@ -131,7 +132,12 @@ public class HuiFuServiceImpl implements HuiFuService {
 
     @Override
     public HuiFuQueryOrderResult queryOrder(V2TradePaymentScanpayQueryRequest request) throws Exception{
-        doInit(getMerConfig());
+        if (request.getAppId() != null) {
+            //多汇付支付获取配置
+            doInit(getMerConfig(request.getAppId()));
+        } else {
+            doInit(getMerConfig());
+        }
         Map<String, Object> response = doExecute(request);
         String jsonString = JSONObject.toJSONString(response);
         HuiFuQueryOrderResult huiFuQueryOrderResult = JSON.parseObject(jsonString, HuiFuQueryOrderResult.class);
@@ -152,7 +158,7 @@ public class HuiFuServiceImpl implements HuiFuService {
     public HuiFuRefundResult refund(V2TradePaymentScanpayRefundRequest request) {
         HuiFuRefundResult huiFuRefundResult=null;
         try {
-            doInit(getMerConfig());
+            doInit(getMerConfig(request.getAppId()));
             request.setReqDate(DateTools.getCurrentDateYYYYMMDD());
             Map<String, Object> response = doExecute(request);
             String jsonString = JSONObject.toJSONString(response);
@@ -281,15 +287,8 @@ public class HuiFuServiceImpl implements HuiFuService {
         HuiFuQueryOrderResult result =null;
         try {
             if (order.getAppId() != null) {
-                FsHfpayConfigMapper fsHfpayConfigMapper = SpringUtils.getBean(FsHfpayConfigMapper.class);
-                FsHfpayConfig fsHfpayConfig = fsHfpayConfigMapper.selectByAppId(order.getAppId());
-                if (fsHfpayConfig != null) {
-                    //多汇付支付获取配置
-                    doInit(getMerConfig(fsHfpayConfig));
-                } else {
-                    //多小程序
-                    doInit(getMerConfig());
-                }
+                //多汇付支付获取配置
+                doInit(getMerConfig(order.getAppId()));
             } else {
                 doInit(getMerConfig());
             }
@@ -352,16 +351,27 @@ public class HuiFuServiceImpl implements HuiFuService {
         return merConfig;
     }
 
-    public MerConfig getMerConfig(FsHfpayConfig fsHfpayConfig) {
+    public MerConfig getMerConfig(String appId) {
+        if (StringUtils.isBlank(appId)) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(appId);
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + appId);
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = com.hc.openapi.tool.fastjson.JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+
         MerConfig merConfig = new MerConfig();
-        merConfig.setProcutId(fsHfpayConfig.getHfProductId());
-        merConfig.setSysId(fsHfpayConfig.getHfSysId());
-        merConfig.setRsaPrivateKey(fsHfpayConfig.getHfRsaPrivateKey());
-        merConfig.setRsaPublicKey(fsHfpayConfig.getHfRsaPublicKey());
-        merConfig.setHuifuId(fsHfpayConfig.getHuifuId());
-
-        FsPayConfig fsPayConfig = new FsPayConfig();
-        BeanUtils.copyProperties(fsHfpayConfig,fsPayConfig);
+        merConfig.setProcutId(fsPayConfig.getHfProductId());
+        merConfig.setSysId(fsPayConfig.getHfSysId());
+        merConfig.setRsaPrivateKey(fsPayConfig.getHfRsaPrivateKey());
+        merConfig.setRsaPublicKey(fsPayConfig.getHfRsaPublicKey());
+        merConfig.setHuifuId(fsPayConfig.getHuifuId());
 
         config = fsPayConfig;
         return merConfig;

+ 2 - 0
fs-service/src/main/java/com/fs/live/domain/LiveOrderPayment.java

@@ -118,4 +118,6 @@ public class LiveOrderPayment extends BaseEntity{
 
     //小程序appId(用于多汇付支付/退款)
     private String appId;
+
+    private Long merConfigId;
 }

+ 194 - 115
fs-service/src/main/java/com/fs/live/service/impl/LiveAfterSalesServiceImpl.java

@@ -26,6 +26,8 @@ import com.fs.common.utils.spring.SpringUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.erp.constant.AfterSalesOrderStatusEnum;
 import com.fs.erp.domain.FsJstAftersalePush;
 import com.fs.erp.dto.BaseResponse;
@@ -36,8 +38,11 @@ import com.fs.erp.mapper.FsJstAftersalePushMapper;
 import com.fs.erp.service.IErpOrderService;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.FsHfpayConfig;
+import com.fs.his.domain.FsPayConfig;
 import com.fs.his.domain.FsUser;
+import com.fs.his.domain.MerchantAppConfig;
 import com.fs.his.mapper.FsHfpayConfigMapper;
+import com.fs.his.mapper.MerchantAppConfigMapper;
 import com.fs.his.service.IFsUserService;
 import com.fs.his.utils.ConfigUtil;
 import com.fs.hisStore.config.FsErpConfig;
@@ -85,6 +90,9 @@ import com.fs.live.service.ILiveAfterSalesService;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
+import java.util.concurrent.TimeUnit;
 
 /**
  * 售后记录Service业务层处理
@@ -96,6 +104,12 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
 @Service
 public class LiveAfterSalesServiceImpl implements ILiveAfterSalesService {
 
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+
     @Autowired
     private ILiveOrderService liveOrderService;
 
@@ -162,6 +176,9 @@ public class LiveAfterSalesServiceImpl implements ILiveAfterSalesService {
 //    @Autowired
 //    private FsStoreDeliversMapper fsStoreDeliversMapper;
 
+    @Autowired
+    private RedissonClient redissonClient;
+
 
     /**
      * 查询售后记录
@@ -388,139 +405,189 @@ public class LiveAfterSalesServiceImpl implements ILiveAfterSalesService {
     @Transactional
     public R applyForAfterSales(String userId, LiveAfterSalesParam param) {
         log.info("申请退款请求信息:"+JSONUtil.toJsonStr(param));
-        LiveOrder order=liveOrderService.selectOrderIdByOrderCode(param.getOrderCode());
-        if(!order.getUserId().equals(userId)){
-            throw new CustomException("非法操作");
-        }
-        if(order.getStatus()==0){
-            return R.error("未支付订单不能申请售后");
-        }
-        if("1".equals(configUtil.generateConfigByKey(SysConfigEnum.HIS_CONFIG.getKey()).getString("erpOpen"))
-                && StringUtils.isEmpty(order.getExtendOrderId())
-                && !CloudHostUtils.hasCloudHostName("康年堂")){
-            log.info("erpOpen:{}",configUtil.generateConfigByKey(SysConfigEnum.HIS_CONFIG.getKey()).getString("erpOpen"));
-            return R.error("仓库未生成订单,暂时不能申请退款,请联系客服");
-        }
-        if(order.getStatus()== OrderInfoEnum.STATUS_NE3.getValue()){
-            return R.error("已取消订单不能申请售后");
-        }
-        if(order.getStatus()== OrderInfoEnum.STATUS_NE1.getValue()){
-            return R.error("已提交申请,等待处理");
-        }
+
+        // 使用Redis分布式锁,确保同一订单只能有一个服务器处理申请售后 因为卓美有一个订单生成了三个售后订单,数据一摸一样,除了id
+        String lockKey = "live:afterSales:apply:" + param.getOrderCode();
+        RLock lock = redissonClient.getLock(lockKey);
+
+        try {
+            // 尝试获取锁,等待时间3秒,锁过期时间30秒
+            boolean locked = lock.tryLock(3, 30, TimeUnit.SECONDS);
+            if (!locked) {
+                log.warn("申请售后订单锁获取失败,订单号:{}", param.getOrderCode());
+                return R.error("系统繁忙,请稍后重试");
+            }
+
+            log.info("申请售后订单锁获取成功,订单号:{}", param.getOrderCode());
+
+            LiveOrder order=liveOrderService.selectOrderIdByOrderCode(param.getOrderCode());
+
+            // 查询配置:是否删除历史售后数据
+            try {
+                String deleteAfterSalesConfig = configService.selectConfigByKey("delete_after_sales");
+                if (StringUtils.isNotEmpty(deleteAfterSalesConfig) && "true".equalsIgnoreCase(deleteAfterSalesConfig.trim())) {
+                    // 查询历史售后数据,将 is_del 设置为 1
+                    if (order != null && order.getOrderId() != null) {
+                        LiveAfterSales queryAfterSales = new LiveAfterSales();
+                        queryAfterSales.setOrderId(order.getOrderId());
+                        List<LiveAfterSales> historyAfterSalesList = baseMapper.selectLiveAfterSalesList(queryAfterSales);
+                        if (historyAfterSalesList != null && !historyAfterSalesList.isEmpty()) {
+                            for (LiveAfterSales historyAfterSales : historyAfterSalesList) {
+                                if (historyAfterSales.getIsDel() != null && historyAfterSales.getIsDel() == 0) {
+                                    LiveAfterSales updateAfterSales = new LiveAfterSales();
+                                    updateAfterSales.setId(historyAfterSales.getId());
+                                    updateAfterSales.setIsDel(1);
+                                    baseMapper.updateLiveAfterSales(updateAfterSales);
+                                    log.info("删除历史售后数据,售后ID:{},订单ID:{}", historyAfterSales.getId(), order.getOrderId());
+                                }
+                            }
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                log.error("查询或更新历史售后数据失败", e);
+            }
+            if(!order.getUserId().equals(userId)){
+                throw new CustomException("非法操作");
+            }
+            if(order.getStatus()==0){
+                return R.error("未支付订单不能申请售后");
+            }
+            if("1".equals(configUtil.generateConfigByKey(SysConfigEnum.HIS_CONFIG.getKey()).getString("erpOpen"))
+                    && StringUtils.isEmpty(order.getExtendOrderId())
+                    && !CloudHostUtils.hasCloudHostName("康年堂")){
+                log.info("erpOpen:{}",configUtil.generateConfigByKey(SysConfigEnum.HIS_CONFIG.getKey()).getString("erpOpen"));
+                return R.error("仓库未生成订单,暂时不能申请退款,请联系客服");
+            }
+            if(order.getStatus()== OrderInfoEnum.STATUS_NE3.getValue()){
+                return R.error("已取消订单不能申请售后");
+            }
+            if(order.getStatus()== OrderInfoEnum.STATUS_NE1.getValue()){
+                return R.error("已提交申请,等待处理");
+            }
 //        if(storeAfterSalesParam.getRefundAmount().compareTo(order.getPayPrice())==1){
 //            return R.error("退款金额不能大于支付金额");
 //        }
-        //已完成订单七天后不能申请退款
-        if(order.getStatus().equals(OrderInfoEnum.STATUS_3.getValue())) {
-            String json=configService.selectConfigByKey("store.config");
-            com.fs.hisStore.config.StoreConfig config=JSONUtil.toBean(json, com.fs.hisStore.config.StoreConfig.class);
-            //已完成订单
-            if (order.getFinishTime() != null) {
-                if (config.getStoreAfterSalesDay() != null && config.getStoreAfterSalesDay() > 0) {
-                    //判断完成时间是否超过指定时间
-                    Calendar calendarAfterSales = new GregorianCalendar();
-                    calendarAfterSales.setTime(order.getFinishTime());
-                    calendarAfterSales.add(calendarAfterSales.DATE, config.getStoreAfterSalesDay()); //把日期往后增加一天,整数  往后推,负数往前移动
-                    if (calendarAfterSales.getTime().getTime() < new Date().getTime()) {
-                        return R.error("此订单已超过售后时间,不能提交售后");
-                    }
+            //已完成订单七天后不能申请退款
+            if(order.getStatus().equals(OrderInfoEnum.STATUS_3.getValue())) {
+                String json=configService.selectConfigByKey("store.config");
+                com.fs.hisStore.config.StoreConfig config=JSONUtil.toBean(json, com.fs.hisStore.config.StoreConfig.class);
+                //已完成订单
+                if (order.getFinishTime() != null) {
+                    if (config.getStoreAfterSalesDay() != null && config.getStoreAfterSalesDay() > 0) {
+                        //判断完成时间是否超过指定时间
+                        Calendar calendarAfterSales = new GregorianCalendar();
+                        calendarAfterSales.setTime(order.getFinishTime());
+                        calendarAfterSales.add(calendarAfterSales.DATE, config.getStoreAfterSalesDay()); //把日期往后增加一天,整数  往后推,负数往前移动
+                        if (calendarAfterSales.getTime().getTime() < new Date().getTime()) {
+                            return R.error("此订单已超过售后时间,不能提交售后");
+                        }
 
+                    }
                 }
             }
-        }
-        //商品除去优惠后的总价格
-        //BigDecimal totalPrice = BigDecimal.ZERO;
-        //拿到所有的商品
-        List<LiveOrderItem> orderItems = liveOrderItemService.selectCheckedByOrderId(order.getOrderId());
-        for (LiveOrderItem item : orderItems) {
-            StoreOrderProductDTO cartInfo = JSONObject.parseObject(item.getJsonInfo(), StoreOrderProductDTO.class);
-            LiveAfterSalesProductParam prosuctParam = param.getProductList().stream().filter(p -> p.getProductId().equals(item.getProductId())).findFirst().orElse(new LiveAfterSalesProductParam());
-            if (prosuctParam.getProductId() != null) {
+            //商品除去优惠后的总价格
+            //BigDecimal totalPrice = BigDecimal.ZERO;
+            //拿到所有的商品
+            List<LiveOrderItem> orderItems = liveOrderItemService.selectCheckedByOrderId(order.getOrderId());
+            for (LiveOrderItem item : orderItems) {
+                StoreOrderProductDTO cartInfo = JSONObject.parseObject(item.getJsonInfo(), StoreOrderProductDTO.class);
+                LiveAfterSalesProductParam prosuctParam = param.getProductList().stream().filter(p -> p.getProductId().equals(item.getProductId())).findFirst().orElse(new LiveAfterSalesProductParam());
+                if (prosuctParam.getProductId() != null) {
 //                //商品优惠前总金额
 //                BigDecimal totalAmountOfGoods = NumberUtil.mul(cartInfo.getPrice(), item.getNum());
 //                //商品优惠总金额
 //                BigDecimal commodityDiscountAmount = NumberUtil.mul(NumberUtil.div(totalAmountOfGoods, NumberUtil.sub(order.getTotalPrice(), order.getPayPostage())), order.getCouponPrice());
 //                //商品优惠后总金额
 //                totalPrice = NumberUtil.add(totalPrice, NumberUtil.sub(totalAmountOfGoods, commodityDiscountAmount));
-                item.setIsAfterSales(1);
-                LiveOrderItem orderItem=new LiveOrderItem();
+                    item.setIsAfterSales(1);
+                    LiveOrderItem orderItem=new LiveOrderItem();
 //                BeanUtil.copyProperties(item, orderItem);
-                try {
-                    BeanUtils.copyProperties(orderItem,item);
-                } catch (IllegalAccessException e) {
-                    throw new RuntimeException(e);
-                } catch (InvocationTargetException e) {
-                    throw new RuntimeException(e);
-                }
-                liveOrderItemService.updateLiveOrderItem(orderItem);
+                    try {
+                        BeanUtils.copyProperties(orderItem,item);
+                    } catch (IllegalAccessException e) {
+                        throw new RuntimeException(e);
+                    } catch (InvocationTargetException e) {
+                        throw new RuntimeException(e);
+                    }
+                    liveOrderItemService.updateLiveOrderItem(orderItem);
 
+                }
             }
-        }
-        //更新订单状态
-        Integer orderStatus=order.getStatus();
-        order.setStatus(OrderInfoEnum.STATUS_NE1.getValue());
-        order.setRefundStatus(String.valueOf(OrderInfoEnum.REFUND_STATUS_1.getValue()));
-        order.setRefundExplain(param.getReasons());
-        order.setCancelReason(param.getExplains());
-        order.setIsAfterSales(1);
-        order.setRefundTime(new Date());
-        liveOrderService.updateLiveOrder(order);
-        //生成售后订单
-        LiveAfterSales storeAfterSales = new LiveAfterSales();
-        storeAfterSales.setOrderId(order.getOrderId());
-        storeAfterSales.setRefundAmount(param.getRefundAmount());
-        storeAfterSales.setRefundType(param.getServiceType());
-        storeAfterSales.setReasons(param.getReasons());
-        storeAfterSales.setExplains(param.getExplains());
-        storeAfterSales.setExplainImg(param.getExplainImg());
-        storeAfterSales.setStatus(AfterSalesStatusEnum.STATUS_0.getValue());
-        storeAfterSales.setSalesStatus(0);
-        storeAfterSales.setCreateTime(Timestamp.valueOf(LocalDateTime.now()));
-        storeAfterSales.setIsDel(0);
-        storeAfterSales.setOrderStatus(orderStatus);
-        storeAfterSales.setUserId(Long.valueOf(userId));
-        storeAfterSales.setCompanyId(order.getCompanyId());
-        storeAfterSales.setCompanyUserId(order.getCompanyUserId());
-        liveAfterSalesService.insertLiveAfterSales(storeAfterSales);
-        //售后商品详情
-        for (LiveAfterSalesProductParam productParam : param.getProductList()) {
-            LiveOrderItem item = orderItems.stream().filter(p -> p.getProductId().equals(productParam.getProductId())).findFirst().orElse(new LiveOrderItem());
-            LiveAfterSalesItem storeAfterSalesItem = new LiveAfterSalesItem();
-            storeAfterSalesItem.setAfterSalesId(storeAfterSales.getId());
-            storeAfterSalesItem.setProductId(item.getProductId());
-            storeAfterSalesItem.setJsonInfo(item.getJsonInfo());
-            storeAfterSalesItem.setIsDel(0);
-            liveAfterSalesItemMapper.insertLiveAfterSalesItem(storeAfterSalesItem);
-        }
-        //操作记录
-        LiveAfterSalesLogs storeAfterSalesStatus = new LiveAfterSalesLogs();
-        storeAfterSalesStatus.setStoreAfterSalesId(storeAfterSales.getId());
-        storeAfterSalesStatus.setChangeType(0);
-        storeAfterSalesStatus.setChangeMessage(AfterSalesStatusEnum.STATUS_0.getDesc());
-        storeAfterSalesStatus.setChangeTime(Timestamp.valueOf(LocalDateTime.now()));
-        FsUserScrm user=userService.selectFsUserById(Long.valueOf(userId));
-        storeAfterSalesStatus.setOperator(user.getNickname());
-        liveAfterSalesLogsMapper.insertLiveAfterSalesLogs(storeAfterSalesStatus);
+            //更新订单状态
+            Integer orderStatus=order.getStatus();
+            order.setStatus(OrderInfoEnum.STATUS_NE1.getValue());
+            order.setRefundStatus(String.valueOf(OrderInfoEnum.REFUND_STATUS_1.getValue()));
+            order.setRefundExplain(param.getReasons());
+            order.setCancelReason(param.getExplains());
+            order.setIsAfterSales(1);
+            order.setRefundTime(new Date());
+            liveOrderService.updateLiveOrder(order);
+            //生成售后订单
+            LiveAfterSales storeAfterSales = new LiveAfterSales();
+            storeAfterSales.setOrderId(order.getOrderId());
+            storeAfterSales.setRefundAmount(param.getRefundAmount());
+            storeAfterSales.setRefundType(param.getServiceType());
+            storeAfterSales.setReasons(param.getReasons());
+            storeAfterSales.setExplains(param.getExplains());
+            storeAfterSales.setExplainImg(param.getExplainImg());
+            storeAfterSales.setStatus(AfterSalesStatusEnum.STATUS_0.getValue());
+            storeAfterSales.setSalesStatus(0);
+            storeAfterSales.setCreateTime(Timestamp.valueOf(LocalDateTime.now()));
+            storeAfterSales.setIsDel(0);
+            storeAfterSales.setOrderStatus(orderStatus);
+            storeAfterSales.setUserId(Long.valueOf(userId));
+            storeAfterSales.setCompanyId(order.getCompanyId());
+            storeAfterSales.setCompanyUserId(order.getCompanyUserId());
+            liveAfterSalesService.insertLiveAfterSales(storeAfterSales);
+            //售后商品详情
+            for (LiveAfterSalesProductParam productParam : param.getProductList()) {
+                LiveOrderItem item = orderItems.stream().filter(p -> p.getProductId().equals(productParam.getProductId())).findFirst().orElse(new LiveOrderItem());
+                LiveAfterSalesItem storeAfterSalesItem = new LiveAfterSalesItem();
+                storeAfterSalesItem.setAfterSalesId(storeAfterSales.getId());
+                storeAfterSalesItem.setProductId(item.getProductId());
+                storeAfterSalesItem.setJsonInfo(item.getJsonInfo());
+                storeAfterSalesItem.setIsDel(0);
+                liveAfterSalesItemMapper.insertLiveAfterSalesItem(storeAfterSalesItem);
+            }
+            //操作记录
+            LiveAfterSalesLogs storeAfterSalesStatus = new LiveAfterSalesLogs();
+            storeAfterSalesStatus.setStoreAfterSalesId(storeAfterSales.getId());
+            storeAfterSalesStatus.setChangeType(0);
+            storeAfterSalesStatus.setChangeMessage(AfterSalesStatusEnum.STATUS_0.getDesc());
+            storeAfterSalesStatus.setChangeTime(Timestamp.valueOf(LocalDateTime.now()));
+            FsUserScrm user=userService.selectFsUserById(Long.valueOf(userId));
+            storeAfterSalesStatus.setOperator(user.getNickname());
+            liveAfterSalesLogsMapper.insertLiveAfterSalesLogs(storeAfterSalesStatus);
 
 //        //更新OMS
-        IErpOrderService erpOrderService = getErpService();
-        ErpRefundUpdateRequest request=new ErpRefundUpdateRequest();
-        request.setTid(order.getOrderCode());
-        request.setOid(order.getOrderCode());
-        request.setRefund_state(1);
-        request.setStoreAfterSalesId(storeAfterSales.getId());
-        request.setOrderStatus(orderStatus);
-        if (StringUtils.isNotBlank(order.getExtendOrderId())){
-            BaseResponse response=erpOrderService.refundUpdateLive(request);
-            if(response.getSuccess()){
-                return R.ok();
+            IErpOrderService erpOrderService = getErpService();
+            ErpRefundUpdateRequest request=new ErpRefundUpdateRequest();
+            request.setTid(order.getOrderCode());
+            request.setOid(order.getOrderCode());
+            request.setRefund_state(1);
+            request.setStoreAfterSalesId(storeAfterSales.getId());
+            request.setOrderStatus(orderStatus);
+            if (StringUtils.isNotBlank(order.getExtendOrderId())){
+                BaseResponse response=erpOrderService.refundUpdateLive(request);
+                if(response.getSuccess()){
+                    return R.ok();
+                }
+                else{
+                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+                    return R.error(response.getErrorDesc());
+                }
             }
-            else{
-                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
-                return R.error(response.getErrorDesc());
+            return R.ok();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        } finally {
+            // 释放锁
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+                log.info("申请售后订单锁释放成功,订单号:{}", param.getOrderCode());
             }
         }
-        return R.ok();
     }
 
     @Override
@@ -1067,9 +1134,21 @@ public class LiveAfterSalesServiceImpl implements ILiveAfterSalesService {
             //将钱退还给用户
             List<LiveOrderPayment> payments = liveOrderPaymentMapper.selectLiveOrderPaymentByPay(5, order.getOrderId());
             if (payments != null && !payments.isEmpty()) {
-                String json = configService.selectConfigByKey("his.pay");
-                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+
                 for (LiveOrderPayment payment : payments) {
+                    FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+                    if (fsCoursePlaySourceConfig == null) {
+                        throw new CustomException("未找到appId对应的小程序配置: " + payment.getAppId());
+                    }
+                    Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                    if (merchantConfigId == null || merchantConfigId <= 0) {
+                        throw new CustomException("小程序没有配置商户信息");
+                    }
+                    MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                    FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+
                     if (payment.getPayMode() == null || "wx".equals(payment.getPayMode())) {
                         WxPayConfig payConfig = new WxPayConfig();
                         payConfig.setAppId(fsPayConfig.getAppId());

+ 207 - 56
fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -54,8 +54,10 @@ import com.fs.company.service.ICompanyUserService;
 import com.fs.config.cloud.CloudHostProper;
 import com.fs.core.config.WxMaConfiguration;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
 import com.fs.course.dto.FsOrderDeliveryNoteDTO;
 import com.fs.course.dto.OrderOpenIdTransDTO;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.erp.domain.*;
 import com.fs.erp.dto.*;
 import com.fs.erp.mapper.FsErpFinishPushMapper;
@@ -63,10 +65,7 @@ import com.fs.erp.service.IErpOrderService;
 import com.fs.his.config.FsSysConfig;
 import com.fs.his.domain.*;
 import com.fs.his.enums.FsStoreOrderLogEnum;
-import com.fs.his.mapper.FsHfpayConfigMapper;
-import com.fs.his.mapper.FsStoreProductAttrValueMapper;
-import com.fs.his.mapper.FsUserMapper;
-import com.fs.his.mapper.FsUserWxMapper;
+import com.fs.his.mapper.*;
 import com.fs.his.service.IFsExpressService;
 import com.fs.his.service.IFsStoreProductService;
 import com.fs.his.service.IFsUserService;
@@ -81,6 +80,8 @@ import com.fs.hisStore.mapper.FsStoreProductScrmMapper;
 import com.fs.hisStore.mapper.FsUserScrmMapper;
 import com.fs.hisStore.param.*;
 import com.fs.hisStore.service.*;
+import com.fs.hisStore.service.IFsStoreProductPurchaseLimitScrmService;
+import com.fs.hisStore.domain.FsStoreProductPurchaseLimitScrm;
 import com.fs.hisStore.vo.*;
 import com.fs.huifuPay.domain.HuiFuCreateOrder;
 import com.fs.huifuPay.domain.HuiFuQueryOrderResult;
@@ -151,6 +152,12 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
     @Autowired
     private FsUserWxMapper fsUserWxMapper;
 
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
+
 
 
     @Autowired
@@ -198,6 +205,9 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
     @Autowired
     private LiveUserLotteryRecordMapper liveUserLotteryRecordMapper;
 
+    @Autowired
+    private IFsStoreProductPurchaseLimitScrmService purchaseLimitService;
+
     @Autowired
     ICompanyUserService companyUserService;
 
@@ -692,8 +702,27 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
     @Override
     @Transactional
     public String payConfirm(Integer type,Long orderId,String payCode,String tradeNo,String bankTransactionId,String bankSerialNo) {
+        // 使用 Redis setNx 加分布式锁,基于订单ID或支付单号
+        String lockKey;
+        if (type.equals(1) && StringUtils.isNotEmpty(payCode)) {
+            lockKey = "livePayConfirm:lock:" + payCode;
+        } else if (orderId != null) {
+            lockKey = "livePayConfirm:lock:" + orderId;
+        } else {
+            lockKey = "livePayConfirm:lock:" + System.currentTimeMillis();
+        }
+
+        boolean lockAcquired = false;
         Object savePoint = TransactionAspectSupport.currentTransactionStatus().createSavepoint();
         try {
+            // 尝试获取锁,锁过期时间设置为30秒
+            lockAcquired = redisCache.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
+            if (!lockAcquired) {
+                // 如果获取锁失败,说明有其他线程正在处理该订单,直接返回
+                log.info("支付确认处理中,订单ID: {}, 支付单号: {}", orderId, payCode);
+                return "SUCCESS";
+            }
+
             LiveOrder order=null;
             if(type.equals(1)){
                 LiveOrderPayment storePayment = liveOrderPaymentMapper.selectLiveOrderPaymentByPaymentCode(payCode);
@@ -732,14 +761,16 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             }
 
             // 佣金处理
-            if (order.getCompanyUserId() == -1L) {
-                companyService.addCompanyTuiLiveMoney(order);
-            } else {
-                // 目前是一级佣金
-                FsStoreProduct product = JSONUtil.toBean(order.getItemJson(), FsStoreProduct.class);
-                List<FsStoreProductAttrValueScrm> productAttrValues = fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueByProductId(product.getProductId());
-                if (productAttrValues != null && !productAttrValues.isEmpty()) {
-                    userService.addTuiLiveMoney(order, productAttrValues);
+            if (order.getCompanyUserId() != null || order.getCompanyId() != null) {
+                if (order.getCompanyUserId() == -1L) {
+                    companyService.addCompanyTuiLiveMoney(order);
+                } else {
+                    // 目前是一级佣金
+                    FsStoreProduct product = JSONUtil.toBean(order.getItemJson(), FsStoreProduct.class);
+                    List<FsStoreProductAttrValueScrm> productAttrValues = fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueByProductId(product.getProductId());
+                    if (productAttrValues != null && !productAttrValues.isEmpty()) {
+                        userService.addTuiLiveMoney(order, productAttrValues);
+                    }
                 }
             }
 
@@ -755,6 +786,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             baseMapper.updateLiveOrder(order);
             try {
                 this.updateLiveWatchLog(order);
+                // 记录限购数量(订单创建成功后记录)
+                purchaseLimitService.increasePurchaseLimit(order.getProductId(), Long.valueOf(order.getUserId()), Integer.valueOf(order.getTotalNum()));
                 this.createOmsOrderCall(order);
             } catch (Exception e) {
                 log.error("推送erp失败:{}",e.getMessage());
@@ -770,6 +803,11 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             err.setMsg("支付错误:"+e.getMessage());
             err.setCreateTime(DateUtils.getNowDate());
             liveOrderPaymentErrorMapper.insertLiveOrderPaymentError(err);
+        } finally {
+            // 释放锁
+            if (lockAcquired) {
+                redisCache.deleteObject(lockKey);
+            }
         }
         return "SUCCESS";
     }
@@ -792,10 +830,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                         List<LiveWatchLog> logs = liveWatchLogService.selectLiveWatchLogList(queryLog);
                         if (logs != null && !logs.isEmpty()) {
                             for (LiveWatchLog log : logs) {
-                                if (log.getLogType() == null || log.getLogType() != 2) {
-                                    log.setLiveBuy(1);
-                                    liveWatchLogService.updateLiveWatchLog(log);
-                                }
+                                log.setLiveBuy(1);
+                                liveWatchLogService.updateLiveWatchLog(log);
                             }
                         }
                     }
@@ -1156,15 +1192,15 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
 
 
             //模板消息支付成功发布事件
-            TemplateBean templateBean = TemplateBean.builder()
-                    .orderId(order.getOrderId().toString())
-                    .orderCode(order.getOrderCode().toString())
-                    .remark("您的订单已签收成功")
-                    .finishTime(order.getFinishTime())
-                    .userId(Long.valueOf(order.getUserId()))
-                    .templateType(TemplateListenEnum.TYPE_3.getValue())
-                    .build();
-            publisher.publishEvent(new TemplateEvent(this, templateBean));
+//            TemplateBean templateBean = TemplateBean.builder()
+//                    .orderId(order.getOrderId().toString())
+//                    .orderCode(order.getOrderCode().toString())
+//                    .remark("您的订单已签收成功")
+//                    .finishTime(order.getFinishTime())
+//                    .userId(Long.valueOf(order.getUserId()))
+//                    .templateType(TemplateListenEnum.TYPE_3.getValue())
+//                    .build();
+//            publisher.publishEvent(new TemplateEvent(this, templateBean));
             return R.ok("操作成功");
         } else {
             return R.error("非法操作");
@@ -1284,9 +1320,21 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             //将钱退还给用户
             List<LiveOrderPayment> payments = liveOrderPaymentMapper.selectLiveOrderPaymentByPay(5, order.getOrderId());
             if (payments != null && !payments.isEmpty()) {
-                String json = configService.selectConfigByKey("his.pay");
-                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+
                 for (LiveOrderPayment payment : payments) {
+                    FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+                    if (fsCoursePlaySourceConfig == null) {
+                        throw new CustomException("未找到appId对应的小程序配置: " + payment.getAppId());
+                    }
+                    Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                    if (merchantConfigId == null || merchantConfigId <= 0) {
+                        throw new CustomException("小程序没有配置商户信息");
+                    }
+                    MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+                    FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+
                     if (payment.getPayMode() == null || "wx".equals(payment.getPayMode())) {
                         WxPayConfig payConfig = new WxPayConfig();
                         payConfig.setAppId(fsPayConfig.getAppId());
@@ -1385,6 +1433,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 userService.subTuiMoney(storeOrder);
             }
         }
+        // 删除限购记录
+        deletePurchaseLimitRecordsForLiveOrder(order);
 
         return R.ok();
     }
@@ -1488,9 +1538,25 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             //将钱退还给用户
             List<LiveOrderPayment> payments = liveOrderPaymentMapper.selectLiveOrderPaymentByPay(5, order.getOrderId());
             if (payments != null && !payments.isEmpty()) {
-                String json = configService.selectConfigByKey("his.pay");
-                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+//                String json = configService.selectConfigByKey("his.pay");
+//                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+
                 for (LiveOrderPayment payment : payments) {
+                    FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(payment.getAppId());
+                    if (fsCoursePlaySourceConfig == null) {
+                        throw new CustomException("未找到appId对应的小程序配置: " + payment.getAppId());
+                    }
+                    Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                    if (merchantConfigId == null || merchantConfigId <= 0) {
+                        throw new CustomException("小程序没有配置商户信息");
+                    }
+                    Long merConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+                    if(payment.getMerConfigId()!=null){
+                        merConfigId=payment.getMerConfigId();
+                    }
+                    MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(merConfigId);
+                    FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+
                     if (payment.getPayMode() == null || "wx".equals(payment.getPayMode())) {
                         WxPayConfig payConfig = new WxPayConfig();
                         payConfig.setAppId(fsPayConfig.getAppId());
@@ -1588,6 +1654,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 userService.subLiveTuiMoney(liveOrder);
             }
         }
+        // 删除限购记录
+        deletePurchaseLimitRecordsForLiveOrder(order);
 
         return R.ok();
     }
@@ -2982,8 +3050,19 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             FsUserScrm user = userMapper.selectFsUserById(Long.valueOf(liveOrder.getUserId()));
             if(user == null) return R.error("用户不存在");
 //            String json = configService.selectConfigByKey("store.pay");
-            String json = configService.selectConfigByKey("his.pay");
-            FsPayConfig fsPayConfig = JSON.parseObject(json, FsPayConfig.class);
+//            String json = configService.selectConfigByKey("his.pay");
+//            FsPayConfig fsPayConfig = JSON.parseObject(json, FsPayConfig.class);
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(appId);
+            if (fsCoursePlaySourceConfig == null) {
+                throw new CustomException("未找到appId对应的小程序配置: " + appId);
+            }
+            Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+            if (merchantConfigId == null || merchantConfigId <= 0) {
+                throw new CustomException("小程序没有配置商户信息");
+            }
+            MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+
+
             String payCode =  OrderCodeUtils.getOrderSn();
             if(StringUtils.isEmpty(payCode)){
                 return R.error("订单生成失败,请重试");
@@ -2996,7 +3075,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             } else {
                 storePayment = new LiveOrderPayment();
                 storePayment.setStatus(1);
-                storePayment.setPayMode(fsPayConfig.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setBusinessCode(liveOrder.getOrderCode());
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(liveOrder.getPayMoney());
@@ -3008,6 +3087,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 storePayment.setOpenId(user.getMaOpenId());
                 storePayment.setUserId(user.getUserId());
                 storePayment.setBusinessId(liveOrder.getOrderId().toString());
+                storePayment.setAppId(appId);
+                storePayment.setMerConfigId(merchantAppConfig.getId());
                 liveOrderPaymentMapper.insertLiveOrderPayment(storePayment);
             }
 
@@ -3084,16 +3165,28 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         if(user == null){
             return R.error("未找到用户信息,请联系管理员!");
         }
-        String json = configService.selectConfigByKey("his.pay");
-        FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+//        String json = configService.selectConfigByKey("his.pay");
+//        FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+
         String openId;
+        String appId = param.getAppId();
         if(StringUtils.isNotEmpty(user.getMaOpenId())){
             log.info("用户信息有openid:{}", user.getMaOpenId());
             openId = user.getMaOpenId();
         }else{
             Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                     .eq(FsUserWx::getFsUserId, order.getUserId())
-                    .eq(FsUserWx::getAppId, fsPayConfig.getAppId());
+                    .eq(FsUserWx::getAppId, appId);
             FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
             log.info("查到的openId信息:{}", fsUserWx);
             openId = fsUserWx.getOpenId();
@@ -3115,7 +3208,11 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 else if(param.getPayType().equals(2)){
                     order.setPayType("2");
                     BigDecimal payMoney=order.getPayPrice().multiply(new BigDecimal(storeConfig.getPayRate())).divide(new BigDecimal(100));
-                    payMoney=new BigDecimal(payMoney.setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
+                    payMoney=new BigDecimal(payMoney.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
+                    // 如果小程序需要支付的金额小于0.01元,不能走物流代收,让走货到付款 xgb
+                    if (payMoney.compareTo(new BigDecimal("0.01")) < 0) {
+                        return R.error("物流代收计算支付金额为0,不允许选择物流代收");
+                    }
                     order.setPayDelivery(order.getPayPrice().subtract(payMoney));
                     order.setPayMoney(payMoney);
                 }
@@ -3155,7 +3252,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 LiveOrderPayment storePayment = new LiveOrderPayment();
                 storePayment.setCompanyId(order.getCompanyId());
                 storePayment.setCompanyUserId(order.getCompanyUserId());
-                storePayment.setPayMode(fsPayConfig.getType());
+                storePayment.setPayMode(merchantAppConfig.getMerchantType());
                 storePayment.setStatus(0);
                 storePayment.setPayCode(payCode);
                 storePayment.setPayMoney(order.getPayMoney());
@@ -3166,10 +3263,11 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 storePayment.setOpenId(openId);
                 storePayment.setUserId(user.getUserId());
                 storePayment.setBusinessId(String.valueOf(order.getOrderId()));
-                storePayment.setAppId(param.getAppId());
+                storePayment.setAppId(appId);
+                storePayment.setMerConfigId(merchantAppConfig.getId());
                 liveOrderPaymentMapper.insertLiveOrderPayment(storePayment);
 
-                if (fsPayConfig.getType().equals("hf")) {
+                if (merchantAppConfig.getMerchantType().equals("hf")) {
                     HuiFuCreateOrder o = new HuiFuCreateOrder();
                     o.setTradeType("T_MINIAPP");
                     o.setOpenid(storePayment.getOpenId());
@@ -3197,9 +3295,9 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                     } else {
                         return R.error(result.getResp_desc());
                     }
-                } else if (fsPayConfig.getType().equals("wx")) {
+                } else if (merchantAppConfig.getMerchantType().equals("wx")) {
                     WxPayConfig payConfig = new WxPayConfig();
-                    payConfig.setAppId(fsPayConfig.getAppId());
+                    payConfig.setAppId(appId);
                     payConfig.setMchId(fsPayConfig.getWxMchId());
                     payConfig.setMchKey(fsPayConfig.getWxMchKey());
                     payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -3594,22 +3692,19 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         if(!"1".equals(fsStoreProduct.getIsAudit()) ) return R.error("商品已下架,购买失败");
         if(liveOrder.getTotalNum() == null || StringUtils.isEmpty(liveOrder.getTotalNum())) liveOrder.setTotalNum("1");
         if(goods.getStock() == null) return R.error("直播间商品库存不足");
-        if(fsStoreProduct.getStock() < Integer.parseInt(liveOrder.getTotalNum()) || goods.getStock() < Integer.parseInt(liveOrder.getTotalNum())) return R.error("抱歉,这款商品已被抢光,暂时无库存~");
-
-        FsStoreProductAttrValueScrm attrValue = null;
-        if (!Objects.isNull(liveOrder.getAttrValueId())) {
-            attrValue = fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueById(liveOrder.getAttrValueId());
-        }
-        if (attrValue != null) {
-            attrValue.setStock(attrValue.getStock() - Integer.parseInt(liveOrder.getTotalNum()));
-            attrValue.setSales(attrValue.getSales() + Integer.parseInt(liveOrder.getTotalNum()));
-            fsStoreProductAttrValueMapper.updateFsStoreProductAttrValue(attrValue);
+        FsStoreProductAttrValueScrm attrValue = fsStoreProductAttrValueMapper.selectFsStoreProductAttrValueById(liveOrder.getAttrValueId());
+        if(fsStoreProduct.getStock() < Integer.parseInt(liveOrder.getTotalNum()) || goods.getStock() < Integer.parseInt(liveOrder.getTotalNum()) || attrValue.getStock() < Integer.parseInt(liveOrder.getTotalNum())){
+            return R.error("抱歉,这款商品已被抢光,暂时无库存~");
         }
-        // 更改店铺库存
-        fsStoreProduct.setStock(fsStoreProduct.getStock()-Integer.parseInt(liveOrder.getTotalNum()));
-        fsStoreProduct.setSales(fsStoreProduct.getSales()+Integer.parseInt(liveOrder.getTotalNum()));
-        fsStoreProductScrmMapper.incStockDecSales(Long.valueOf("-" + liveOrder.getTotalNum()),fsStoreProduct.getProductId());
 
+
+        // 检查限购
+        Long userId = Long.parseLong(liveOrder.getUserId());
+        Integer purchaseNum = Integer.parseInt(liveOrder.getTotalNum());
+        checkPurchaseLimitForLiveOrder(userId, liveOrder.getProductId(), purchaseNum);
+
+        // 使用 deStockIncSale 方法处理库存和销量
+        deStockIncSale(liveOrder.getProductId(), liveOrder.getAttrValueId(), purchaseNum);
         // 更新直播间库存
         goods.setStock(goods.getStock()-Integer.parseInt(liveOrder.getTotalNum()));
         goods.setSales(goods.getSales()+Integer.parseInt(liveOrder.getTotalNum()));
@@ -3637,6 +3732,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         BigDecimal payPrice = fsStoreProduct.getPrice().multiply(new BigDecimal(liveOrder.getTotalNum()));
         if (attrValue != null) {
             payPrice = attrValue.getPrice().multiply(new BigDecimal(liveOrder.getTotalNum()));
+            fsStoreProduct.setPrice(payPrice);
         }
         // 直播不需要服务费 0915 1735 左
 //        String config=configService.selectConfigByKey("store.config");
@@ -3695,11 +3791,13 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                     dto.setBarCode(fsStoreProductAttrValue.getBarCode());
                     dto.setGroupBarCode(fsStoreProductAttrValue.getGroupBarCode());
                 }
+                dto.setPrice(fsStoreProduct.getPrice());
                 if (attrValue != null) {
                     dto.setBarCode(attrValue.getBarCode());
                     dto.setGroupBarCode(attrValue.getGroupBarCode());
+                    dto.setPrice(attrValue.getPrice());
                 }
-                dto.setPrice(fsStoreProduct.getPrice());
+                //dto.setPrice(fsStoreProduct.getPrice());
                 dto.setProductName(fsStoreProduct.getProductName());
                 dto.setNum(Long.valueOf(liveOrder.getTotalNum()));
 
@@ -3710,6 +3808,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 liveOrderItem.setNum(Long.valueOf(liveOrder.getTotalNum()));
                 liveOrderItem.setJsonInfo(JSON.toJSONString(dto));
                 liveOrderItemMapper.insertLiveOrderItem(liveOrderItem);
+
+
                 redisCache.deleteObject("orderKey:" + liveOrder.getOrderKey());
                 //添加支付到期时间
                 Calendar calendar = Calendar.getInstance();
@@ -3897,6 +3997,57 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         }
     }
 
+    /**
+     * 检查限购(用于直播订单)
+     * @param userId 用户ID
+     * @param productId 商品ID
+     * @param num 购买数量
+     */
+    /**
+     * 减库存加销量(直播订单)
+     */
+    private void deStockIncSale(Long productId, Long attrValueId, Integer num) {
+        // 使用 productService.decProductStock 方法,该方法已包含库存检查逻辑
+        fsStoreProductService.decProductStock(productId, attrValueId, num);
+    }
+
+    private void checkPurchaseLimitForLiveOrder(Long userId, Long productId, Integer num) {
+        // 查询商品信息
+        FsStoreProductScrm product = fsStoreProductService.selectFsStoreProductById(productId);
+        if (product == null) {
+            return;
+        }
+
+        // 如果商品没有设置限购,直接返回
+        if (product.getPurchaseLimit() == null || product.getPurchaseLimit() <= 0) {
+            return;
+        }
+
+        // 查询用户已购买的数量
+        FsStoreProductPurchaseLimitScrm purchaseLimit = purchaseLimitService.selectByProductIdAndUserId(productId, userId);
+        int purchasedNum = 0;
+        if (purchaseLimit != null) {
+            purchasedNum = purchaseLimit.getNum();
+        }
+
+        // 检查是否超过限购数量
+        if (purchasedNum + num > product.getPurchaseLimit()) {
+            int productTotalNum = purchasedNum + num;
+            throw new CustomException("该商品限购" + product.getPurchaseLimit() + "件,您已购买" + productTotalNum + "件,无法继续购买");
+        }
+    }
+
+    /**
+     * 删除限购记录(用于直播订单)
+     * @param liveOrder 订单
+     */
+    private void deletePurchaseLimitRecordsForLiveOrder(LiveOrder liveOrder) {
+        // 减少限购数量
+        Long userId = Long.parseLong(liveOrder.getUserId());
+        Integer num = Integer.parseInt(liveOrder.getTotalNum());
+        purchaseLimitService.decreasePurchaseLimit(liveOrder.getProductId(), userId, num);
+    }
+
     private void refundCoupon(LiveOrder order) {
         if(order.getCouponUserId()!=null){
             LiveCouponUser couponUser=liveCouponUserService.selectLiveCouponUserById(order.getUserCouponId());

+ 22 - 3
fs-service/src/main/java/com/fs/ybPay/service/impl/PayServiceImpl.java

@@ -1,7 +1,13 @@
 package com.fs.ybPay.service.impl;
 
+import com.fs.common.exception.CustomException;
+import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.spring.SpringUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
 import com.fs.his.domain.FsPayConfig;
+import com.fs.his.domain.MerchantAppConfig;
+import com.fs.his.mapper.MerchantAppConfigMapper;
 import com.fs.system.domain.SysConfig;
 import com.fs.system.mapper.SysConfigMapper;
 import com.fs.tzBankPay.form.GetTokenForm;
@@ -27,11 +33,24 @@ public class PayServiceImpl implements IPayService {
     @Override
     public CreateWxOrderResult createWxOrder(WxJspayDTO wxJspayDTO) {
         SysConfigMapper sysConfigMapper= SpringUtils.getBean(SysConfigMapper.class);
-        SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-        FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
+        FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper= SpringUtils.getBean(FsCoursePlaySourceConfigMapper.class);
+        MerchantAppConfigMapper merchantAppConfigMapper= SpringUtils.getBean(MerchantAppConfigMapper.class);
+        if (StringUtils.isBlank(wxJspayDTO.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(wxJspayDTO.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + wxJspayDTO.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = com.hc.openapi.tool.fastjson.JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
         String account = fsPayConfig.getYbAccount();
         wxJspayDTO.setAccount(account);
-        wxJspayDTO.setAppId(fsPayConfig.getAppId());
+        wxJspayDTO.setAppId(fsCoursePlaySourceConfig.getAppid());
         wxJspayDTO.setNotifyUrl(fsPayConfig.getYbNotifyUrl());
         wxJspayDTO.setIsMinipg("1");
         wxJspayDTO.setStoreid("0");

+ 125 - 0
fs-service/src/main/resources/mapper/MerchantAppConfigMapper.xml

@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.MerchantAppConfigMapper">
+
+    <resultMap type="MerchantAppConfig" id="MerchantAppConfigResult">
+        <result property="id"    column="id"    />
+        <result property="merchantType"    column="merchant_type"    />
+        <result property="appId"    column="app_id"    />
+        <result property="callbackUrl"    column="callback_url"    />
+        <result property="dataJson"    column="data_json"    />
+        <result property="createdTime"    column="created_time"    />
+        <result property="updatedTime"    column="updated_time"    />
+        <result property="isDeleted"    column="is_deleted"    />
+        <result property="createdBy"    column="created_by"    />
+        <result property="updatedBy"    column="updated_by"    />
+        <result property="merchantId"    column="merchant_id"    />
+    </resultMap>
+
+    <!-- 检查表是否存在 -->
+    <select id="checkTableExists" resultType="java.lang.Integer">
+        SELECT COUNT(*) FROM information_schema.tables
+        WHERE table_schema = DATABASE() AND table_name = 'merchant_app_config'
+    </select>
+
+    <!-- 创建商户配置表 -->
+    <update id="createMerchantAppConfigTable">
+        CREATE TABLE `merchant_app_config` (
+        `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+        `merchant_type` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商户类型:如WECHAT_PAY、ALIPAY等',
+        `app_id` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '应用ID',
+        `callback_url` varchar(512) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '回调地址,用于接收支付结果等通知',
+        `data_json` json DEFAULT NULL COMMENT '扩展配置数据,JSON格式存储其他配置信息',
+        `created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+        `updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+        `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除状态:0-正常,1-已删除',
+        `created_by` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '创建人ID或用户名',
+        `updated_by` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '修改人ID或用户名',
+        `merchant_id` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '商户号',
+        PRIMARY KEY (`id`),
+        KEY `idx_merchant_type` (`merchant_type`),
+        KEY `idx_app_id` (`app_id`),
+        KEY `idx_created_time` (`created_time`),
+        KEY `merchant_app_config_merchant_type_IDX` (`merchant_type`,`is_deleted`,`merchant_id`) USING BTREE
+        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='商户应用配置表'
+    </update>
+
+
+    <sql id="selectMerchantAppConfigVo">
+        select id, merchant_type, app_id, merchant_id,callback_url, data_json, created_time, updated_time, is_deleted, created_by, updated_by from merchant_app_config
+    </sql>
+
+    <select id="selectMerchantAppConfigList" parameterType="MerchantAppConfig" resultMap="MerchantAppConfigResult">
+        <include refid="selectMerchantAppConfigVo"/>
+        <where>
+            <if test="merchantId != null and merchantId != ''"> and merchant_id = #{merchantId}</if>
+            <if test="merchantType != null  and merchantType != ''"> and merchant_type = #{merchantType}</if>
+            <if test="appId != null  and appId != ''"> and app_id = #{appId}</if>
+            <if test="params.beginCreatedTime != null and params.beginCreatedTime != '' and params.endCreatedTime != null and params.endCreatedTime != ''"> and created_time between #{params.beginCreatedTime} and #{params.endCreatedTime}</if>
+            <if test="isDeleted != null "> and is_deleted = #{isDeleted}</if>
+        </where>
+    </select>
+
+    <select id="selectMerchantAppConfigById" parameterType="Long" resultMap="MerchantAppConfigResult">
+        <include refid="selectMerchantAppConfigVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertMerchantAppConfig" parameterType="MerchantAppConfig" useGeneratedKeys="true" keyProperty="id">
+        insert into merchant_app_config
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="merchantType != null and merchantType != ''">merchant_type,</if>
+            <if test="appId != null and appId != ''">app_id,</if>
+            <if test="callbackUrl != null">callback_url,</if>
+            <if test="dataJson != null">data_json,</if>
+            <if test="createdTime != null">created_time,</if>
+            <if test="updatedTime != null">updated_time,</if>
+            <if test="isDeleted != null">is_deleted,</if>
+            <if test="createdBy != null and createdBy != ''">created_by,</if>
+            <if test="updatedBy != null and updatedBy != ''">updated_by,</if>
+            <if test="merchantId != null and merchantId != ''">merchant_id,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="merchantType != null and merchantType != ''">#{merchantType},</if>
+            <if test="appId != null and appId != ''">#{appId},</if>
+            <if test="callbackUrl != null">#{callbackUrl},</if>
+            <if test="dataJson != null">#{dataJson},</if>
+            <if test="createdTime != null">#{createdTime},</if>
+            <if test="updatedTime != null">#{updatedTime},</if>
+            <if test="isDeleted != null">#{isDeleted},</if>
+            <if test="createdBy != null and createdBy != ''">#{createdBy},</if>
+            <if test="updatedBy != null and updatedBy != ''">#{updatedBy},</if>
+            <if test="merchantId != null and merchantId != ''">#{merchantId},</if>
+         </trim>
+    </insert>
+
+    <update id="updateMerchantAppConfig" parameterType="MerchantAppConfig">
+        update merchant_app_config
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="merchantType != null and merchantType != ''">merchant_type = #{merchantType},</if>
+            <if test="appId != null and appId != ''">app_id = #{appId},</if>
+            <if test="callbackUrl != null">callback_url = #{callbackUrl},</if>
+            <if test="dataJson != null">data_json = #{dataJson},</if>
+            <if test="createdTime != null">created_time = #{createdTime},</if>
+            <if test="updatedTime != null">updated_time = #{updatedTime},</if>
+            <if test="isDeleted != null">is_deleted = #{isDeleted},</if>
+            <if test="createdBy != null and createdBy != ''">created_by = #{createdBy},</if>
+            <if test="updatedBy != null and updatedBy != ''">updated_by = #{updatedBy},</if>
+            <if test="merchantId != null and merchantId != ''">merchant_id = #{merchantId},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteMerchantAppConfigById" parameterType="Long">
+        delete from merchant_app_config where id = #{id}
+    </delete>
+
+    <delete id="deleteMerchantAppConfigByIds" parameterType="String">
+        delete from merchant_app_config where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 8 - 0
fs-service/src/main/resources/mapper/course/FsCoursePlaySourceConfigMapper.xml

@@ -29,4 +29,12 @@
         </if>
         order by fcpsc.id desc
     </select>
+
+    <select id="selectCoursePlaySourceConfigByAppId" resultType="com.fs.course.domain.FsCoursePlaySourceConfig">
+        select
+            fcpsc.*
+        from fs_course_play_source_config fcpsc
+        where fcpsc.is_del = 0 and fcpsc.appid= #{appid}
+       limit 1
+    </select>
 </mapper>

+ 70 - 0
fs-service/src/main/resources/mapper/his/FsQuestionAndAnswerMapper.xml

@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.his.mapper.FsQuestionAndAnswerMapper">
+
+    <resultMap type="FsQuestionAndAnswer" id="FsQuestionAndAnswerResult">
+        <result property="id"    column="id"    />
+        <result property="jsonInfo"    column="json_info"    />
+        <result property="questionName"    column="question_name"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectFsQuestionAndAnswerVo">
+        select id,question_name ,json_info, create_time, update_time from fs_question_and_answer
+    </sql>
+
+    <select id="selectFsQuestionAndAnswerList" parameterType="FsQuestionAndAnswer" resultMap="FsQuestionAndAnswerResult">
+        <include refid="selectFsQuestionAndAnswerVo"/>
+        <where>
+            <if test="jsonInfo != null  and jsonInfo != ''"> and json_info = #{jsonInfo}</if>
+        </where>
+    </select>
+
+    <select id="selectFsQuestionAndAnswerById" parameterType="Long" resultMap="FsQuestionAndAnswerResult">
+        <include refid="selectFsQuestionAndAnswerVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertFsQuestionAndAnswer" parameterType="FsQuestionAndAnswer">
+        insert into fs_question_and_answer
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">id,</if>
+            <if test="jsonInfo != null">json_info,</if>
+            <if test="questionName != null">question_name,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="jsonInfo != null">#{jsonInfo},</if>
+            <if test="questionName != null">#{questionName},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsQuestionAndAnswer" parameterType="FsQuestionAndAnswer">
+        update fs_question_and_answer
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="jsonInfo != null">json_info = #{jsonInfo},</if>
+            <if test="questionName != null">question_name = #{questionName},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsQuestionAndAnswerById" parameterType="Long">
+        delete from fs_question_and_answer where id = #{id}
+    </delete>
+
+    <delete id="deleteFsQuestionAndAnswerByIds" parameterType="String">
+        delete from fs_question_and_answer where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 81 - 0
fs-service/src/main/resources/mapper/hisStore/FsStoreProductPurchaseLimitScrmMapper.xml

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fs.hisStore.mapper.FsStoreProductPurchaseLimitScrmMapper">
+
+    <resultMap type="FsStoreProductPurchaseLimitScrm" id="FsStoreProductPurchaseLimitResult">
+        <result property="id"    column="id"    />
+        <result property="productId"    column="product_id"    />
+        <result property="userId"    column="user_id"    />
+        <result property="num"    column="num"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectFsStoreProductPurchaseLimitVo">
+        select id, product_id, user_id, num, create_time, update_time from fs_store_product_purchase_limit_scrm
+    </sql>
+
+    <select id="selectFsStoreProductPurchaseLimitList" parameterType="FsStoreProductPurchaseLimitScrm" resultMap="FsStoreProductPurchaseLimitResult">
+        <include refid="selectFsStoreProductPurchaseLimitVo"/>
+        <where>
+            <if test="productId != null "> and product_id = #{productId}</if>
+            <if test="userId != null "> and user_id = #{userId}</if>
+            <if test="num != null "> and num = #{num}</if>
+        </where>
+    </select>
+
+    <select id="selectFsStoreProductPurchaseLimitById" parameterType="Long" resultMap="FsStoreProductPurchaseLimitResult">
+        <include refid="selectFsStoreProductPurchaseLimitVo"/>
+        where id = #{id}
+    </select>
+
+    <select id="selectByProductIdAndUserId" resultMap="FsStoreProductPurchaseLimitResult">
+        <include refid="selectFsStoreProductPurchaseLimitVo"/>
+        where product_id = #{productId} and user_id = #{userId}
+    </select>
+
+    <insert id="insertFsStoreProductPurchaseLimit" parameterType="FsStoreProductPurchaseLimitScrm" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_store_product_purchase_limit_scrm
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="productId != null">product_id,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="num != null">num,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="productId != null">#{productId},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="num != null">#{num},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsStoreProductPurchaseLimit" parameterType="FsStoreProductPurchaseLimitScrm">
+        update fs_store_product_purchase_limit_scrm
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="productId != null">product_id = #{productId},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="num != null">num = #{num},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsStoreProductPurchaseLimitById" parameterType="Long">
+        delete from fs_store_product_purchase_limit_scrm where id = #{id}
+    </delete>
+
+    <delete id="deleteFsStoreProductPurchaseLimitByIds" parameterType="String">
+        delete from fs_store_product_purchase_limit_scrm where id in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+</mapper>
+

+ 2 - 0
fs-service/src/main/resources/mapper/live/LiveOrderPaymentMapper.xml

@@ -147,6 +147,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="shareMoney != null">share_money,</if>
             <if test="isShare != null">is_share,</if>
             <if test="appId != null">app_id,</if>
+            <if test="merConfigId != null">mer_config_id,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="payCode != null">#{payCode},</if>
@@ -175,6 +176,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="shareMoney != null">#{shareMoney},</if>
             <if test="isShare != null">#{isShare},</if>
             <if test="appId != null">#{appId},</if>
+            <if test="merConfigId != null">#{merConfigId},</if>
          </trim>
     </insert>
 

+ 48 - 22
fs-user-app/src/main/java/com/fs/app/controller/InquiryOrderController.java

@@ -2,6 +2,7 @@ package com.fs.app.controller;
 
 
 import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.Wrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.fs.app.annotation.Login;
@@ -15,6 +16,8 @@ import com.fs.common.utils.ip.IpUtils;
 import com.fs.company.service.ICompanyService;
 import com.fs.core.config.WxPayProperties;
 import com.fs.core.utils.OrderCodeUtils;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.service.IFsCoursePlaySourceConfigService;
 import com.fs.his.domain.*;
 import com.fs.his.dto.FsInquiryOrderPatientDTO;
 import com.fs.his.dto.PayConfigDTO;
@@ -26,6 +29,7 @@ import com.fs.his.utils.PhoneUtil;
 import com.fs.his.vo.FsInquiryOrderListUVO;
 import com.fs.his.vo.FsInquiryOrderPingListUVO;
 import com.fs.his.vo.FsInquiryOrderReportUVO;
+import com.fs.hisStore.domain.FsPayConfigScrm;
 import com.fs.huifuPay.domain.HuiFuCreateOrder;
 import com.fs.huifuPay.domain.HuifuCreateOrderResult;
 import com.fs.huifuPay.service.HuiFuService;
@@ -93,8 +97,11 @@ public class InquiryOrderController extends  AppBaseController {
     private IFsInquiryTempService inquiryTempService;
     @Autowired
     private IFsInquiryOrderReportService orderReportService;
+
+    @Autowired
+    private IFsCoursePlaySourceConfigService fsCoursePlaySourceConfigService;
     @Autowired
-    private IFsInquiryOrderLogsService fsInquiryOrderLogsService;
+    private IMerchantAppConfigService merchantAppConfigService;
     @Autowired
     private IFsStorePaymentService storePaymentService;
     @Autowired
@@ -173,9 +180,6 @@ public class InquiryOrderController extends  AppBaseController {
     )
     {
         logger.info("支付"+param.getOrderId()+":"+param.getAppId());
-        String json=configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO= JSONUtil.toBean(json, PayConfigDTO.class);
-
         FsInquiryOrder order=inquiryOrderService.selectFsInquiryOrderByOrderId(param.getOrderId());
         if(order==null){
             return R.error("订单不存在");
@@ -256,8 +260,20 @@ public class InquiryOrderController extends  AppBaseController {
         param.setUserId(userId);
         FsUser user = userService.selectFsUserByUserId(userId);
         //在线支付
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigService.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 //        String openId = "";
 //        if (StringUtils.isNotEmpty(param.getAppId())) {
 //            FsUserWx fsUserWx = userWxService.selectByAppIdAndUserId(param.getAppId(), param.getUserId(), 1);
@@ -289,7 +305,7 @@ public class InquiryOrderController extends  AppBaseController {
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = merchantAppConfig.getAppId();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -334,7 +350,7 @@ public class InquiryOrderController extends  AppBaseController {
             }
             FsStorePayment storePayment=new FsStorePayment();
             storePayment.setStatus(0);
-            storePayment.setPayMode(payConfigDTO.getType());
+            storePayment.setPayMode(merchantAppConfig.getMerchantId());
             storePayment.setPayCode(payCode);
             storePayment.setCompanyId(order.getCompanyId());
             storePayment.setCompanyUserId(order.getCompanyUserId());
@@ -348,11 +364,9 @@ public class InquiryOrderController extends  AppBaseController {
             storePayment.setUserId(user.getUserId());
             storePayment.setBusinessId(order.getOrderId().toString());
             if(storePaymentService.insertFsStorePayment(storePayment)>0){
-                if(payConfigDTO.getType().equals("wx")){
+                if(merchantAppConfig.getMerchantId().equals("wx")){
                     //创建微信订单
                     WxPayConfig payConfig = new WxPayConfig();
-                    SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
-                    FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
                     payConfig.setAppId(appId);
                     payConfig.setMchId(fsPayConfig.getWxMchId());
                     payConfig.setMchKey(fsPayConfig.getWxMchKey());
@@ -378,7 +392,7 @@ public class InquiryOrderController extends  AppBaseController {
                         throw new CustomException("支付失败"+e.getMessage());
                     }
                 }
-                else if(payConfigDTO.getType().equals("yb")){
+                else if(merchantAppConfig.getMerchantId().equals("yb")){
                     WxJspayDTO p = new WxJspayDTO();
                     // 使用setter方法为对象赋值
                     p.setPayMoney(storePayment.getPayMoney().toString());
@@ -400,7 +414,7 @@ public class InquiryOrderController extends  AppBaseController {
                         throw new CustomException("支付失败");
                     }
                 }
-                else if(payConfigDTO.getType().equals("tz")){
+                else if(merchantAppConfig.getMerchantId().equals("tz")){
                     PayCreateOrder o = new PayCreateOrder();
                     o.setOrderNo("inquiry"+storePayment.getPayCode()); // 业务系统订单号
                     o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -425,7 +439,7 @@ public class InquiryOrderController extends  AppBaseController {
                     mt.setTradeNo(result.getBody().getOrderFlowNo());
                     storePaymentService.updateFsStorePayment(mt);
                     return R.ok().put("isPay",0).put("data",result).put("type","tz");
-                }else if(payConfigDTO.getType().equals("hf")){
+                }else if(merchantAppConfig.getMerchantId().equals("hf")){
                     HuiFuCreateOrder o = new HuiFuCreateOrder();
                     o.setTradeType("T_MINIAPP");
                     o.setOpenid(openId);
@@ -460,8 +474,20 @@ public class InquiryOrderController extends  AppBaseController {
         FsInquiryOrder order=inquiryOrderService.selectFsInquiryOrderByOrderId(param.getOrderId());
         FsUser user=userService.selectFsUserByUserId(Long.parseLong(getUserId()));
 
-        String json = configService.selectConfigByKey("his.pay");
-        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
+        if (StringUtils.isBlank(param.getAppId())) {
+            throw new IllegalArgumentException("appId不能为空");
+        }
+        FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigService.selectCoursePlaySourceConfigByAppId(param.getAppId());
+        if (fsCoursePlaySourceConfig == null) {
+            throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+        }
+        Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+        if (merchantConfigId == null || merchantConfigId <= 0) {
+            throw new CustomException("小程序没有配置商户信息");
+        }
+        MerchantAppConfig merchantAppConfig = merchantAppConfigService.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+        FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+//        PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
 
         String openId = null;
         String appId = param.getAppId();
@@ -475,7 +501,7 @@ public class InquiryOrderController extends  AppBaseController {
                 openId = fsUserWx.getOpenId();
             }
         } else {
-            appId = payConfigDTO.getAppId();
+            appId = fsCoursePlaySourceConfig.getAppid();
             openId = Objects.isNull(user) ? "" : user.getMaOpenId();
             if (StringUtils.isBlank(openId)){
                 Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
@@ -501,7 +527,7 @@ public class InquiryOrderController extends  AppBaseController {
 //            PayConfigDTO payConfigDTO = JSONUtil.toBean(json, PayConfigDTO.class);
             FsStorePayment storePayment=new FsStorePayment();
             storePayment.setStatus(0);
-            storePayment.setPayMode(payConfigDTO.getType());
+            storePayment.setPayMode(merchantAppConfig.getMerchantType());
             storePayment.setPayCode(payCode);
             storePayment.setCompanyId(order.getCompanyId());
             storePayment.setCompanyUserId(order.getCompanyUserId());
@@ -515,9 +541,9 @@ public class InquiryOrderController extends  AppBaseController {
             storePayment.setUserId(user.getUserId());
             storePayment.setBusinessId(order.getOrderId().toString());
             if(storePaymentService.insertFsStorePayment(storePayment)>0){
-                if (payConfigDTO.getType().equals("yb")) {
+                if (merchantAppConfig.getMerchantType().equals("yb")) {
                     return R.error("支付暂不可用!");
-                } else if (payConfigDTO.getType().equals("tz")) {
+                } else if (merchantAppConfig.getMerchantType().equals("tz")) {
                     PayCreateOrder o = new PayCreateOrder();
                     o.setOrderNo("inquiry" + storePayment.getPayCode()); // 业务系统订单号
                     o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
@@ -537,7 +563,7 @@ public class InquiryOrderController extends  AppBaseController {
                     mt.setTradeNo(result.getBody().getOrderFlowNo());
                     storePaymentService.updateFsStorePayment(mt);
                     return R.ok().put("isPay", 0).put("data", result).put("type", "tz");
-                }else if (payConfigDTO.getType().equals("hf")) {
+                }else if (merchantAppConfig.getMerchantType().equals("hf")) {
                     HuiFuCreateOrder o = new HuiFuCreateOrder();
                     o.setTradeType("A_NATIVE");
                     o.setOpenid(openId);
@@ -548,7 +574,7 @@ public class InquiryOrderController extends  AppBaseController {
                     if (o.getAppId()!=null&& !o.getAppId().isEmpty()){
                         Wrapper<FsUserWx> queryWrapper = Wrappers.<FsUserWx>lambdaQuery()
                                 .eq(FsUserWx::getFsUserId, Long.parseLong(getUserId()))
-                                .eq(FsUserWx::getAppId, payConfigDTO.getAppId());
+                                .eq(FsUserWx::getAppId, fsCoursePlaySourceConfig.getAppid());
                         FsUserWx fsUserWx = fsUserWxMapper.selectOne(queryWrapper);
                         if (fsUserWx!=null){
                             o.setOpenid(fsUserWx.getOpenId());

+ 373 - 43
fs-user-app/src/main/java/com/fs/app/controller/live/LiveOrderController.java

@@ -24,14 +24,12 @@ import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.ip.IpUtils;
 import com.fs.common.utils.poi.ExcelUtil;
 import com.fs.core.config.WxMaConfiguration;
-import com.fs.core.utils.OrderCodeUtils;
-import com.fs.erp.service.IErpOrderService;
-import com.fs.his.dto.ExpressInfoDTO;
-import com.fs.his.enums.ShipperCodeEnum;
-import com.fs.his.service.IFsExpressService;
-import com.fs.his.utils.ConfigUtil;
-import com.fs.hisStore.domain.*;
-import com.fs.hisStore.dto.FsStoreOrderComputeDTO;
+import com.fs.course.domain.FsCoursePlaySourceConfig;
+import com.fs.course.mapper.FsCoursePlaySourceConfigMapper;
+import com.fs.his.domain.FsPayConfig;
+import com.fs.his.domain.MerchantAppConfig;
+import com.fs.his.mapper.MerchantAppConfigMapper;
+import com.fs.hisStore.domain.FsUserScrm;
 import com.fs.hisStore.enums.OrderInfoEnum;
 import com.fs.hisStore.mapper.FsStorePaymentScrmMapper;
 import com.fs.hisStore.param.*;
@@ -48,7 +46,10 @@ import com.fs.live.domain.LiveOrderPayment;
 import com.fs.live.dto.LiveOrderComputeDTO;
 import com.fs.live.enums.LiveOrderCancleReason;
 import com.fs.live.mapper.LiveOrderPaymentMapper;
-import com.fs.live.param.*;
+import com.fs.live.param.FsMyLiveOrderQueryParam;
+import com.fs.live.param.LiveOrderComputedParam;
+import com.fs.live.param.LiveOrderConfirmParam;
+import com.fs.live.param.LiveOrderPayParam;
 import com.fs.live.service.ILiveAfterSalesService;
 import com.fs.live.service.ILiveOrderItemService;
 import com.fs.live.service.ILiveOrderService;
@@ -130,9 +131,10 @@ public class LiveOrderController extends AppBaseController
     IPayService ybPayService;
     @Autowired
     private HuiFuService huiFuService;
-
-
-
+    @Autowired
+    private FsCoursePlaySourceConfigMapper fsCoursePlaySourceConfigMapper;
+    @Autowired
+    private MerchantAppConfigMapper merchantAppConfigMapper;
 
     /**
      * 查询订单列表
@@ -280,10 +282,6 @@ public class LiveOrderController extends AppBaseController
     @RepeatSubmit
     public R createReward(@RequestBody LiveOrder liveOrder)
     {
-        // 校验appId
-        if (StringUtils.isEmpty(liveOrder.getAppId())) {
-            return R.error("appId不能为空");
-        }
         log.info("新增中奖订单: {}", JSON.toJSONString(liveOrder));
 
         liveOrder.setUserId(getUserId());
@@ -299,10 +297,6 @@ public class LiveOrderController extends AppBaseController
     @RepeatSubmit
     public R payConfirmReward(@RequestBody LiveOrder liveOrder)
     {
-        // 校验appId
-        if (StringUtils.isEmpty(liveOrder.getAppId())) {
-            return R.error("appId不能为空");
-        }
         log.info("新增订单: {}", JSON.toJSONString(liveOrder));
 
         liveOrder.setUserId(getUserId());
@@ -313,16 +307,334 @@ public class LiveOrderController extends AppBaseController
     @ApiOperation("创建订单")
     @PostMapping("/create")
     public R create(@Validated @RequestBody LiveOrder param, HttpServletRequest request){
-        // 校验appId
-        if (StringUtils.isEmpty(param.getAppId())) {
-            return R.error("appId不能为空");
-        }
         String userId= getUserId();
         log.info("开始创建订单,登录用户id:{}", userId);
         param.setUserId(userId);
         return orderService.createLiveOrder(param);
     }
 
+//    @Login
+//    @ApiOperation("支付")
+//    @PostMapping("/pay")
+//    @Transactional
+//    //@Synchronized
+//    public R pay(HttpServletRequest request, @Validated @RequestBody LiveOrderPayParam param)
+//    {
+//        LiveOrder order=orderService.selectLiveOrderByOrderId(String.valueOf(param.getOrderId()));
+//        if(order==null){
+//            return R.error("订单不存在");
+//        }
+//        if(order.getStatus()!= OrderInfoEnum.STATUS_0.getValue()){
+//            return R.error("订单状态不正确");
+//        }
+//        String orderId=redisCache.getCacheObject("isPaying:"+order.getOrderId());
+//        if(StringUtils.isNotEmpty(orderId)&&orderId.equals(order.getOrderId().toString())){
+//            return R.error("正在支付中...");
+//        }
+//
+//        FsUserScrm user=userService.selectFsUserById(Long.valueOf(order.getUserId()));
+//        if(user!=null&& StringUtils.isNotEmpty(user.getMaOpenId())){
+//            //已改价处理
+//            if(order.getIsEditMoney()!=null&&order.getIsEditMoney()==1){
+//                //改过价不做处理
+//
+//            }
+//            else{
+//                String config=configService.selectConfigByKey("his.store");
+//                StoreConfig storeConfig= JSONUtil.toBean(config,StoreConfig.class);
+//                if(param.getPayType().equals(1)){
+//                    order.setPayType("1");
+//                    order.setPayMoney(order.getPayPrice());
+//                    order.setPayDelivery(BigDecimal.ZERO);
+//                }
+//                else if(param.getPayType().equals(2)){
+//                    order.setPayType("2");
+//                    BigDecimal payMoney=order.getPayPrice().multiply(new BigDecimal(storeConfig.getPayRate())).divide(new BigDecimal(100));
+//                    payMoney=new BigDecimal(payMoney.setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
+//                    order.setPayDelivery(order.getPayPrice().subtract(payMoney));
+//                    order.setPayMoney(payMoney);
+//                }
+//                else if(param.getPayType().equals(3)){
+//                    //货到付款
+//                    order.setPayType("3");
+//                    BigDecimal amount=redisCache.getCacheObject("orderAmount:"+order.getOrderId());
+//                    BigDecimal payMoney = BigDecimal.ZERO;
+//                    if (amount != null){
+//                        payMoney=amount;
+//                    }
+//                    order.setPayMoney(payMoney);
+//                    order.setPayDelivery(order.getPayPrice().subtract(payMoney) );
+////                    order.setPayMoney(BigDecimal.ZERO);
+//                }
+//                orderService.updateLiveOrder(order);
+//            }
+//            String payCode = IdUtil.getSnowflake(0, 0).nextIdStr();
+////            order.setOrderCode(orderCode);
+////            if(order.getPayType().equals("1")||order.getPayType().equals("2")){
+//            if((order.getPayType().equals("1")||order.getPayType().equals("2")||order.getPayType().equals("3")) && order.getPayMoney().compareTo(new BigDecimal(0))>0){
+//                String json = configService.selectConfigByKey("his.pay");
+//                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+//                LiveOrderPayment storePayment=new LiveOrderPayment();
+//                storePayment.setCompanyId(order.getCompanyId());
+//                storePayment.setCompanyUserId(order.getCompanyUserId());
+//                storePayment.setPayMode(fsPayConfig.getType());
+//                storePayment.setStatus(0);
+//                storePayment.setPayCode(payCode);
+//                storePayment.setPayMoney(order.getPayMoney());
+//                storePayment.setCreateTime(new Date());
+//                storePayment.setPayTypeCode("weixin");
+//                storePayment.setBusinessType(2);
+//                storePayment.setRemark("直播订单支付");
+//                storePayment.setOpenId(user.getRealName());
+//                storePayment.setUserId(user.getUserId());
+//                storePayment.setBusinessId(String.valueOf(order.getOrderId()));
+//                liveOrderPaymentMapper.insertLiveOrderPayment(storePayment);
+//
+//                if (fsPayConfig.getType().equals("hf")){
+//                    HuiFuCreateOrder o = new HuiFuCreateOrder();
+//                    o.setTradeType("T_MINIAPP");
+//                    o.setOpenid(user.getMaOpenId());
+//                    o.setReqSeqId("live-"+storePayment.getPayCode());
+//                    o.setTransAmt(storePayment.getPayMoney().toString());
+//                    o.setGoodsDesc("直播订单支付");
+//                    if (param != null && StringUtils.isNotBlank(param.getAppId())) {
+//                        o.setAppId(param.getAppId());
+//                    }
+//                    HuifuCreateOrderResult result = huiFuService.createOrder(o);
+//                    if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
+//                        LiveOrderPayment mt=new LiveOrderPayment();
+//                        mt.setPaymentId(storePayment.getPaymentId());
+//                        mt.setTradeNo(result.getHf_seq_id());
+//                        liveOrderPaymentMapper.updateLiveOrderPayment(mt);
+//                        redisCache.setCacheObject("isPaying:"+order.getOrderId(),order.getOrderId().toString(),1, TimeUnit.MINUTES);
+//                        Map<String, Object> resultMap = JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {});
+//                        String s = (String) resultMap.get("package");
+//                        resultMap.put("packageValue",s);
+//                        return R.ok().put("payType",param.getPayType()).put("result",resultMap);
+//                    }
+//                    else{
+//                        return R.error(result.getResp_desc());
+//                    }
+//                }else  if (fsPayConfig.getType().equals("wx")){
+//                    WxPayConfig payConfig = new WxPayConfig();
+//                    payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
+//                    payConfig.setMchId(fsPayConfig.getWxMchId());
+//                    payConfig.setMchKey(fsPayConfig.getWxMchKey());
+//                    payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+//                    payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+//                    payConfig.setKeyPath(fsPayConfig.getKeyPath());
+//                    payConfig.setNotifyUrl(fsPayConfig.getNotifyUrlScrm());
+//                    wxPayService.setConfig(payConfig);
+//                    WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
+//                    orderRequest.setOpenid(user.getMaOpenId());//公众号支付提供用户openid
+//                    orderRequest.setBody("直播订单支付");
+//                    orderRequest.setOutTradeNo("live-" + storePayment.getPayCode());
+//                    orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(storePayment.getPayMoney().toString()));//测试
+//                    //orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(money));//测试
+//                    orderRequest.setTradeType("JSAPI");
+//                    orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+//                    //调用统一下单接口,获取"预支付交易会话标识"
+//                    try {
+//                        WxPayMpOrderResult orderResult = wxPayService.createOrder(orderRequest);
+//                        return R.ok().put("result", orderResult).put("type", "wx").put("isPay", 0).put("payType",param.getPayType());
+//                    } catch (WxPayException e) {
+//                        e.printStackTrace();
+//                        throw new CustomException("支付失败" + e.getMessage());
+//                    }
+//                }
+//            }
+////            else if(order.getPayType().equals("3")){
+//            else if(order.getPayType().equals("3") && order.getPayMoney().compareTo(new BigDecimal(0))<=0){
+//                //货到付款
+//                orderService.payConfirm(2,order.getOrderId(),null,null,null,null);
+//                return R.ok().put("payType",param.getPayType());
+//            }
+//            return R.error();
+//        }
+//        else{
+//            return R.error("用户OPENID不存在");
+//        }
+//
+//    }
+
+    /*
+    @Login
+    @ApiOperation("支付")
+    @PostMapping("/pay")
+    @Transactional
+    //@Synchronized
+    public R pay(HttpServletRequest request, @Validated @RequestBody LiveOrderPayParam param)
+    {
+        Long orderId = param.getOrderId();
+        logger.info("开始处理支付请求, 订单号: {}, 支付类型: {}", orderId, param.getPayType());
+
+        RLock lock = redissonClient.getLock(String.format(LOCK_KEY_PAY,orderId));
+        R result = null;
+
+        try {
+            boolean locked = lock.tryLock(100, 30000, TimeUnit.MILLISECONDS);
+
+            if (!locked) {
+                logger.warn("订单正在处理中,获取锁失败, 订单号: {}", orderId);
+                return R.error("订单正在处理中,请勿重复提交");
+            }
+
+            result = orderService.pay(param);
+
+        } catch (InterruptedException e) {
+            logger.error("获取支付锁的过程被中断, 订单号: {}", orderId, e);
+            Thread.currentThread().interrupt();
+            return R.error("支付处理被中断,请稍后重试");
+        } catch (Throwable e) {
+            logger.error("支付过程中发生异常, 订单号: {}", orderId, e);
+            throw e;
+        } finally {
+            if (lock.isHeldByCurrentThread()) {
+                lock.unlock();
+                logger.debug("支付锁已释放, 订单号: {}", orderId);
+            }
+        }
+
+        return result;
+        LiveOrder order=orderService.selectLiveOrderByOrderId(String.valueOf(param.getOrderId()));
+        if(order==null){
+            return R.error("订单不存在");
+        }
+        if(order.getStatus()!= OrderInfoEnum.STATUS_0.getValue()){
+            return R.error("订单状态不正确");
+        }
+        String orderId=redisCache.getCacheObject("isPaying:"+order.getOrderId());
+        if(StringUtils.isNotEmpty(orderId)&&orderId.equals(order.getOrderId().toString())){
+            return R.error("正在支付中...");
+        }
+
+        FsUserScrm user=userService.selectFsUserById(Long.valueOf(order.getUserId()));
+        if(user!=null&& StringUtils.isNotEmpty(user.getMaOpenId())){
+            //已改价处理
+            if(order.getIsEditMoney()!=null&&order.getIsEditMoney()==1){
+                //改过价不做处理
+
+            }
+            else{
+                String config=configService.selectConfigByKey("his.store");
+                StoreConfig storeConfig= JSONUtil.toBean(config,StoreConfig.class);
+                if(param.getPayType().equals(1)){
+                    order.setPayType("1");
+                    order.setPayMoney(order.getPayPrice());
+                    order.setPayDelivery(BigDecimal.ZERO);
+                }
+                else if(param.getPayType().equals(2)){
+                    order.setPayType("2");
+                    BigDecimal payMoney=order.getPayPrice().multiply(new BigDecimal(storeConfig.getPayRate())).divide(new BigDecimal(100));
+                    payMoney=new BigDecimal(payMoney.setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
+                    order.setPayDelivery(order.getPayPrice().subtract(payMoney));
+                    order.setPayMoney(payMoney);
+                }
+                else if(param.getPayType().equals(3)){
+                    //货到付款
+                    order.setPayType("3");
+                    BigDecimal amount=redisCache.getCacheObject("orderAmount:"+order.getOrderId());
+                    BigDecimal payMoney = BigDecimal.ZERO;
+                    if (amount != null){
+                        payMoney=amount;
+                    }
+                    order.setPayMoney(payMoney);
+                    order.setPayDelivery(order.getPayPrice().subtract(payMoney) );
+//                    order.setPayMoney(BigDecimal.ZERO);
+                }
+                orderService.updateLiveOrder(order);
+            }
+            String payCode = IdUtil.getSnowflake(0, 0).nextIdStr();
+//            order.setOrderCode(orderCode);
+//            if(order.getPayType().equals("1")||order.getPayType().equals("2")){
+            if((order.getPayType().equals("1")||order.getPayType().equals("2")||order.getPayType().equals("3")) && order.getPayMoney().compareTo(new BigDecimal(0))>0){
+                String json = configService.selectConfigByKey("his.pay");
+                FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+                LiveOrderPayment storePayment=new LiveOrderPayment();
+                storePayment.setCompanyId(order.getCompanyId());
+                storePayment.setCompanyUserId(order.getCompanyUserId());
+                storePayment.setPayMode(fsPayConfig.getType());
+                storePayment.setStatus(0);
+                storePayment.setPayCode(payCode);
+                storePayment.setPayMoney(order.getPayMoney());
+                storePayment.setCreateTime(new Date());
+                storePayment.setPayTypeCode("weixin");
+                storePayment.setBusinessType(2);
+                storePayment.setRemark("直播订单支付");
+                storePayment.setOpenId(user.getRealName());
+                storePayment.setUserId(user.getUserId());
+                storePayment.setBusinessId(String.valueOf(order.getOrderId()));
+                liveOrderPaymentMapper.insertLiveOrderPayment(storePayment);
+
+                if (fsPayConfig.getType().equals("hf")){
+                    HuiFuCreateOrder o = new HuiFuCreateOrder();
+                    o.setTradeType("T_MINIAPP");
+                    o.setOpenid(user.getMaOpenId());
+                    o.setReqSeqId("live-"+storePayment.getPayCode());
+                    o.setTransAmt(storePayment.getPayMoney().toString());
+                    o.setGoodsDesc("直播订单支付");
+                    if (param != null && StringUtils.isNotBlank(param.getAppId())) {
+                        o.setAppId(param.getAppId());
+                    }
+                    HuifuCreateOrderResult result = huiFuService.createOrder(o);
+                    if(result.getResp_code()!=null&&(result.getResp_code().equals("00000000")||result.getResp_code().equals("00000100"))){
+                        LiveOrderPayment mt=new LiveOrderPayment();
+                        mt.setPaymentId(storePayment.getPaymentId());
+                        mt.setTradeNo(result.getHf_seq_id());
+                        liveOrderPaymentMapper.updateLiveOrderPayment(mt);
+                        redisCache.setCacheObject("isPaying:"+order.getOrderId(),order.getOrderId().toString(),1, TimeUnit.MINUTES);
+                        Map<String, Object> resultMap = JSON.parseObject(result.getPay_info(), new TypeReference<Map<String, Object>>() {});
+                        String s = (String) resultMap.get("package");
+                        resultMap.put("packageValue",s);
+                        return R.ok().put("payType",param.getPayType()).put("result",resultMap);
+                    }
+                    else{
+                        return R.error(result.getResp_desc());
+                    }
+                }else  if (fsPayConfig.getType().equals("wx")){
+                    WxPayConfig payConfig = new WxPayConfig();
+                    payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
+                    payConfig.setMchId(fsPayConfig.getWxMchId());
+                    payConfig.setMchKey(fsPayConfig.getWxMchKey());
+                    payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                    payConfig.setSubMchId(org.apache.commons.lang3.StringUtils.trimToNull(null));
+                    payConfig.setKeyPath(fsPayConfig.getKeyPath());
+                    payConfig.setNotifyUrl(fsPayConfig.getNotifyUrlScrm());
+                    wxPayService.setConfig(payConfig);
+                    WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
+                    orderRequest.setOpenid(user.getMaOpenId());//公众号支付提供用户openid
+                    orderRequest.setBody("直播订单支付");
+                    orderRequest.setOutTradeNo("live-" + storePayment.getPayCode());
+                    orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(storePayment.getPayMoney().toString()));//测试
+                    //orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(money));//测试
+                    orderRequest.setTradeType("JSAPI");
+                    orderRequest.setSpbillCreateIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
+                    //调用统一下单接口,获取"预支付交易会话标识"
+                    try {
+                        WxPayMpOrderResult orderResult = wxPayService.createOrder(orderRequest);
+                        return R.ok().put("result", orderResult).put("type", "wx").put("isPay", 0).put("payType",param.getPayType());
+                    } catch (WxPayException e) {
+                        e.printStackTrace();
+                        throw new CustomException("支付失败" + e.getMessage());
+                    }
+                }
+            }
+//            else if(order.getPayType().equals("3")){
+            else if(order.getPayType().equals("3") && order.getPayMoney().compareTo(new BigDecimal(0))<=0){
+                //货到付款
+                orderService.payConfirm(2,order.getOrderId(),null,null,null,null);
+                return R.ok().put("payType",param.getPayType());
+            }
+            return R.error();
+        }
+        else{
+            return R.error("用户OPENID不存在");
+        }
+
+    }
+        /**
+     * 获取订单详细信息
+     */
     @Login
     @GetMapping(value = "/info/{orderId}")
     public AjaxResult getInfo(@PathVariable("orderId") String orderId)
@@ -338,10 +650,6 @@ public class LiveOrderController extends AppBaseController
     @Transactional
     public R pay(HttpServletRequest request, @Validated @RequestBody LiveOrderPayParam param)
     {
-        // 校验appId
-        if (StringUtils.isEmpty(param.getAppId())) {
-            return R.error("appId不能为空");
-        }
         Long orderId = param.getOrderId();
         logger.info("开始处理支付请求, 订单号: {}, 支付类型: {}", orderId, param.getPayType());
         try{
@@ -581,7 +889,7 @@ public class LiveOrderController extends AppBaseController
 //                }
 //            }else if(fsPayConfig.getType().equals("wx")) {
 //                WxPayConfig payConfig = new WxPayConfig();
-//                payConfig.setAppId(fsPayConfig.getAppId());
+//                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
 //                payConfig.setMchId(fsPayConfig.getWxMchId());
 //                payConfig.setMchKey(fsPayConfig.getWxMchKey());
 //                payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -653,16 +961,27 @@ public class LiveOrderController extends AppBaseController
                 return R.error("正在支付中...");
             }
 
-            String json = configService.selectConfigByKey("his.pay");
-            FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
-            String payCode =  OrderCodeUtils.getOrderSn();
+            if (StringUtils.isBlank(param.getAppId())) {
+                throw new IllegalArgumentException("appId不能为空");
+            }
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+            if (fsCoursePlaySourceConfig == null) {
+                throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+            }
+            Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+            if (merchantConfigId == null || merchantConfigId <= 0) {
+                throw new CustomException("小程序没有配置商户信息");
+            }
+            MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+            FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
+            String payCode = IdUtil.getSnowflake(0, 0).nextIdStr();
             //易宝支付
             LiveOrderPayment storePayment=new LiveOrderPayment();
             storePayment.setCompanyId(order.getCompanyId());
             storePayment.setCompanyUserId(order.getCompanyUserId());
             storePayment.setStatus(0);
             storePayment.setPayCode(payCode);
-            storePayment.setPayMode(fsPayConfig.getType());
+            storePayment.setPayMode(merchantAppConfig.getMerchantType());
             storePayment.setPayMoney(order.getPayMoney());
             storePayment.setCreateTime(new Date());
             storePayment.setPayTypeCode("weixin");
@@ -673,7 +992,7 @@ public class LiveOrderController extends AppBaseController
             storePayment.setBusinessId(order.getOrderId().toString());
             liveOrderPaymentMapper.insertLiveOrderPayment(storePayment);
 
-            if (fsPayConfig.getType().equals("hf")){
+            if (merchantAppConfig.getMerchantType().equals("hf")){
                 HuiFuCreateOrder o = new HuiFuCreateOrder();
                 o.setTradeType("T_MINIAPP");
                 o.setOpenid(user.getMaOpenId());
@@ -696,10 +1015,10 @@ public class LiveOrderController extends AppBaseController
                 else{
                     return R.error(result.getResp_desc());
                 }
-            }else  if (fsPayConfig.getType().equals("wx")){
+            }else  if (merchantAppConfig.getMerchantType().equals("wx")){
                 //创建微信订单
                 WxPayConfig payConfig = new WxPayConfig();
-                payConfig.setAppId(fsPayConfig.getAppId());
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                 payConfig.setMchId(fsPayConfig.getWxMchId());
                 payConfig.setMchKey(fsPayConfig.getWxMchKey());
                 payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));
@@ -769,14 +1088,25 @@ public class LiveOrderController extends AppBaseController
                 return R.error("只有顺丰物流支持尾款支付");
             }
 
-            String payCode =  OrderCodeUtils.getOrderSn();
-            String json = configService.selectConfigByKey("his.pay");
-            FsPayConfigScrm fsPayConfig = JSON.parseObject(json, FsPayConfigScrm.class);
+            String payCode = IdUtil.getSnowflake(0, 0).nextIdStr();
+            if (StringUtils.isBlank(param.getAppId())) {
+                throw new IllegalArgumentException("appId不能为空");
+            }
+            FsCoursePlaySourceConfig fsCoursePlaySourceConfig = fsCoursePlaySourceConfigMapper.selectCoursePlaySourceConfigByAppId(param.getAppId());
+            if (fsCoursePlaySourceConfig == null) {
+                throw new CustomException("未找到appId对应的小程序配置: " + param.getAppId());
+            }
+            Long merchantConfigId = fsCoursePlaySourceConfig.getMerchantConfigId();
+            if (merchantConfigId == null || merchantConfigId <= 0) {
+                throw new CustomException("小程序没有配置商户信息");
+            }
+            MerchantAppConfig merchantAppConfig = merchantAppConfigMapper.selectMerchantAppConfigById(fsCoursePlaySourceConfig.getMerchantConfigId());
+            FsPayConfig fsPayConfig = JSON.parseObject(merchantAppConfig.getDataJson(), FsPayConfig.class);
             LiveOrderPayment storePayment=new LiveOrderPayment();
             storePayment.setCompanyId(order.getCompanyId());
             storePayment.setCompanyUserId(order.getCompanyUserId());
             storePayment.setStatus(0);
-            storePayment.setPayMode(fsPayConfig.getType());
+            storePayment.setPayMode(merchantAppConfig.getMerchantType());
             storePayment.setPayCode(payCode);
             storePayment.setPayMoney(order.getPayDelivery());
             storePayment.setCreateTime(new Date());
@@ -788,7 +1118,7 @@ public class LiveOrderController extends AppBaseController
             storePayment.setBusinessId(order.getOrderId().toString());
             liveOrderPaymentMapper.insertLiveOrderPayment(storePayment);
 
-            if (fsPayConfig.getType().equals("hf")){
+            if (merchantAppConfig.getMerchantType().equals("hf")){
                 HuiFuCreateOrder o = new HuiFuCreateOrder();
                 o.setTradeType("T_MINIAPP");
                 o.setOpenid(user.getMaOpenId());
@@ -811,10 +1141,10 @@ public class LiveOrderController extends AppBaseController
                 else{
                     return R.error(result.getResp_desc());
                 }
-            }else  if (fsPayConfig.getType().equals("wx")){
+            }else  if (merchantAppConfig.getMerchantType().equals("wx")){
                 //创建微信订单
                 WxPayConfig payConfig = new WxPayConfig();
-                payConfig.setAppId(fsPayConfig.getAppId());
+                payConfig.setAppId(fsCoursePlaySourceConfig.getAppid());
                 payConfig.setMchId(fsPayConfig.getWxMchId());
                 payConfig.setMchKey(fsPayConfig.getWxMchKey());
                 payConfig.setSubAppId(org.apache.commons.lang3.StringUtils.trimToNull(null));