Prechádzať zdrojové kódy

拍商品订单,拍商品,课程关联拍商品信息

wjj 1 týždeň pred
rodič
commit
e4b8a1fefe
34 zmenil súbory, kde vykonal 2214 pridanie a 1 odobranie
  1. 103 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseProductController.java
  2. 124 0
      fs-admin/src/main/java/com/fs/course/controller/FsCourseProductOrderController.java
  3. 2 1
      fs-service/src/main/java/com/fs/core/utils/OrderCodeUtils.java
  4. 56 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseProduct.java
  5. 99 0
      fs-service/src/main/java/com/fs/course/domain/FsCourseProductOrder.java
  6. 9 0
      fs-service/src/main/java/com/fs/course/domain/FsUserCourseVideo.java
  7. 61 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseProductMapper.java
  8. 81 0
      fs-service/src/main/java/com/fs/course/mapper/FsCourseProductOrderMapper.java
  9. 32 0
      fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderCreateParam.java
  10. 52 0
      fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderListParam.java
  11. 16 0
      fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderListUParam.java
  12. 87 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseProductOrderService.java
  13. 61 0
      fs-service/src/main/java/com/fs/course/service/IFsCourseProductService.java
  14. 646 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java
  15. 93 0
      fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductServiceImpl.java
  16. 14 0
      fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java
  17. 76 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderListUVO.java
  18. 100 0
      fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderVO.java
  19. 7 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoH5DVO.java
  20. 13 0
      fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java
  21. 29 0
      fs-service/src/main/java/com/fs/his/enums/FsCourseProductOrderStatusEnum.java
  22. 10 0
      fs-service/src/main/java/com/fs/his/param/ApplyCourseProductOrderRefundParam.java
  23. 8 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderCancelParam.java
  24. 11 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderComputeParam.java
  25. 14 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderDoPayParam.java
  26. 11 0
      fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderRefundParam.java
  27. 14 0
      fs-service/src/main/java/com/fs/huifuPay/service/impl/HuiFuServiceImpl.java
  28. 99 0
      fs-service/src/main/resources/mapper/course/FsCourseProductMapper.xml
  29. 145 0
      fs-service/src/main/resources/mapper/course/FsCourseProductOrderMapper.xml
  30. 12 0
      fs-service/src/main/resources/mapper/course/FsUserCourseVideoMapper.xml
  31. 30 0
      fs-user-app/src/main/java/com/fs/app/controller/CourseProductController.java
  32. 87 0
      fs-user-app/src/main/java/com/fs/app/controller/CourseProductOrderController.java
  33. 6 0
      fs-user-app/src/main/java/com/fs/app/controller/HuifuPayController.java
  34. 6 0
      fs-user-app/src/main/java/com/fs/app/controller/WxPayController.java

+ 103 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseProductController.java

@@ -0,0 +1,103 @@
+package com.fs.course.controller;
+
+import java.util.List;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.enums.BusinessType;
+import com.fs.course.domain.FsCourseProduct;
+import com.fs.course.service.IFsCourseProductService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 拍单商品Controller
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+@RestController
+@RequestMapping("/course/fsCourseProduct")
+public class FsCourseProductController extends BaseController
+{
+    @Autowired
+    private IFsCourseProductService fsCourseProductService;
+
+    /**
+     * 查询拍单商品列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseProduct fsCourseProduct)
+    {
+        startPage();
+        List<FsCourseProduct> list = fsCourseProductService.selectFsCourseProductList(fsCourseProduct);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出拍单商品列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:export')")
+    @Log(title = "拍单商品", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseProduct fsCourseProduct)
+    {
+        List<FsCourseProduct> list = fsCourseProductService.selectFsCourseProductList(fsCourseProduct);
+        ExcelUtil<FsCourseProduct> util = new ExcelUtil<FsCourseProduct>(FsCourseProduct.class);
+        return util.exportExcel(list, "拍单商品数据");
+    }
+
+    /**
+     * 获取拍单商品详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return AjaxResult.success(fsCourseProductService.selectFsCourseProductById(id));
+    }
+
+    /**
+     * 新增拍单商品
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:add')")
+    @Log(title = "拍单商品", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseProduct fsCourseProduct)
+    {
+        return toAjax(fsCourseProductService.insertFsCourseProduct(fsCourseProduct));
+    }
+
+    /**
+     * 修改拍单商品
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:edit')")
+    @Log(title = "拍单商品", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseProduct fsCourseProduct)
+    {
+        return toAjax(fsCourseProductService.updateFsCourseProduct(fsCourseProduct));
+    }
+
+    /**
+     * 删除拍单商品
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProduct:remove')")
+    @Log(title = "拍单商品", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(fsCourseProductService.deleteFsCourseProductByIds(ids));
+    }
+}

+ 124 - 0
fs-admin/src/main/java/com/fs/course/controller/FsCourseProductOrderController.java

@@ -0,0 +1,124 @@
+package com.fs.course.controller;
+
+import java.util.List;
+
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.domain.R;
+import com.fs.course.param.FsCourseProductOrderListParam;
+import com.fs.course.vo.FsCourseProductOrderVO;
+import com.fs.his.param.FsCourseProductOrderRefundParam;
+import com.fs.his.param.FsInquiryOrderRefundParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+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.course.domain.FsCourseProductOrder;
+import com.fs.course.service.IFsCourseProductOrderService;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.common.core.page.TableDataInfo;
+
+/**
+ * 拍单商品订单Controller
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+@RestController
+@RequestMapping("/course/fsCourseProductOrder")
+public class FsCourseProductOrderController extends BaseController
+{
+    @Autowired
+    private IFsCourseProductOrderService fsCourseProductOrderService;
+
+    /**
+     * 查询拍单商品订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(FsCourseProductOrderListParam param)
+    {
+        startPage();
+        List<FsCourseProductOrderVO> list = fsCourseProductOrderService.selectFsCourseProductOrderList(param);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出拍单商品订单列表
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:export')")
+    @Log(title = "拍单商品订单", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(FsCourseProductOrderListParam param)
+    {
+        List<FsCourseProductOrderVO> list = fsCourseProductOrderService.selectFsCourseProductOrderList(param);
+        ExcelUtil<FsCourseProductOrderVO> util = new ExcelUtil<FsCourseProductOrderVO>(FsCourseProductOrderVO.class);
+        return util.exportExcel(list, "拍单商品订单数据");
+    }
+
+    /**
+     * 获取拍单商品订单详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:query')")
+    @GetMapping(value = "/{courseOrderId}")
+    public AjaxResult getInfo(@PathVariable("courseOrderId") Long courseOrderId)
+    {
+        return AjaxResult.success(fsCourseProductOrderService.selectFsCourseProductOrderByCourseOrderId(courseOrderId));
+    }
+
+    /**
+     * 新增拍单商品订单
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:add')")
+    @Log(title = "拍单商品订单", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody FsCourseProductOrder fsCourseProductOrder)
+    {
+        return toAjax(fsCourseProductOrderService.insertFsCourseProductOrder(fsCourseProductOrder));
+    }
+
+    /**
+     * 修改拍单商品订单
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:edit')")
+    @Log(title = "拍单商品订单", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody FsCourseProductOrder fsCourseProductOrder)
+    {
+        return toAjax(fsCourseProductOrderService.updateFsCourseProductOrder(fsCourseProductOrder));
+    }
+
+    /**
+     * 删除拍单商品订单
+     */
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:remove')")
+    @Log(title = "拍单商品订单", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{courseOrderIds}")
+    public AjaxResult remove(@PathVariable Long[] courseOrderIds)
+    {
+        return toAjax(fsCourseProductOrderService.deleteFsCourseProductOrderByCourseOrderIds(courseOrderIds));
+    }
+
+    @Transactional
+    @RepeatSubmit
+    @ApiOperation("退款拍商品订单")
+    @PreAuthorize("@ss.hasPermi('course:fsCourseProductOrder:refund')")
+    @PostMapping("/refund")
+    public R refundOrder(@Validated @RequestBody FsCourseProductOrderRefundParam param){
+        param.setSysUserName(getLoginUser().getUsername());
+        logger.info("退款拍商品订单:"+param.getCourseOrderId()+":操作人:总后台:"+ getLoginUser().getUsername());
+        return fsCourseProductOrderService.refund(param);
+    }
+}

+ 2 - 1
fs-service/src/main/java/com/fs/core/utils/OrderCodeUtils.java

@@ -44,7 +44,8 @@ public class OrderCodeUtils {
 
     }
     public static String getOrderSn(){
-        String url= FSConfig.getCommonApi()+ "/app/common/genOrderCode";
+        //String url= FSConfig.getCommonApi()+ "/app/common/genOrderCode";
+        String url= "42.194.245.189:8010/app/common/genOrderCode";
         String json = HttpRequest.get(url)
                 .execute().body();
         OrderCodeVO vo= JSONUtil.toBean(json, OrderCodeVO.class);

+ 56 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseProduct.java

@@ -0,0 +1,56 @@
+package com.fs.course.domain;
+
+import java.math.BigDecimal;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fs.common.annotation.Excel;
+import lombok.Data;
+import com.fs.common.core.domain.BaseEntity;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 拍单商品对象 fs_course_product
+ *
+ * @author fs
+ * @date 2025-07-28
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsCourseProduct extends BaseEntity{
+
+    /** 拍单商品id */
+    private Long id;
+
+    /** 商品图片 */
+    @Excel(name = "商品图片")
+    private String imgUrl;
+
+    /** 商品组图 */
+    @Excel(name = "商品组图")
+    private String images;
+
+    /** 产品条码 */
+    @Excel(name = "产品条码")
+    private String barCode;
+
+    /** 排序 */
+    @Excel(name = "排序")
+    private Long sort;
+
+    /** 库存 */
+    @Excel(name = "库存")
+    private Long stock;
+
+    /** 商品介绍 */
+    @Excel(name = "商品介绍")
+    private String productContent;
+
+    /** 商品价格 */
+    @Excel(name = "商品价格")
+    private BigDecimal productPrice;
+
+    /** 商品名称 */
+    @Excel(name = "商品名称")
+    private String productName;
+
+
+}

+ 99 - 0
fs-service/src/main/java/com/fs/course/domain/FsCourseProductOrder.java

@@ -0,0 +1,99 @@
+package com.fs.course.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;
+
+/**
+ * 拍单商品订单对象 fs_course_product_order
+ *
+ * @author fs
+ * @date 2025-07-28
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class FsCourseProductOrder extends BaseEntity{
+
+    /** 拍单商品订单表id */
+    private Long courseOrderId;
+
+    /** 订单编号 */
+    @Excel(name = "订单编号")
+    private String orderCode;
+
+    /** 用户id */
+    @Excel(name = "用户id")
+    private Long userId;
+
+    /** 用户名称 */
+    @Excel(name = "用户名称")
+    private String userName;
+
+    /** 用户电话 */
+    @Excel(name = "用户电话")
+    private String userPhone;
+
+    /** 拍单商品id */
+    @Excel(name = "拍单商品id")
+    private Long courseProductId;
+
+    /** 商品json */
+    @Excel(name = "商品json")
+    private String productJson;
+
+    /** 课程id */
+    @Excel(name = "课程id")
+    private Long courseId;
+
+    /** 视频小节id */
+    @Excel(name = "视频小节id")
+    private Long videoId;
+
+    /** 支付状态 0 待支付 1已支付 */
+    @Excel(name = "支付状态 0 待支付 1已支付")
+    private Long isPay;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 支付方式 微信 */
+    @Excel(name = "支付方式 微信")
+    private Long payType;
+
+    /** 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功 */
+    @Excel(name = "1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功")
+    private Long status;
+
+    /** 申请退款时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "申请退款时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date refundTime;
+
+    /** 申请退款理由 */
+    @Excel(name = "申请退款理由")
+    private String refundExplain;
+
+    /** 核销码 */
+    @Excel(name = "核销码")
+    private String verifyCode;
+
+    /** 公司id */
+    @Excel(name = "公司id")
+    private Long companyId;
+
+    /** 销售id */
+    @Excel(name = "销售id")
+    private Long companyUserId;
+
+    /** 企微外部联系人id */
+    @Excel(name = "企微外部联系人id")
+    private Long extId;
+
+
+}

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

@@ -104,4 +104,13 @@ public class FsUserCourseVideo extends BaseEntity
      * 项目ID
      */
     private Long projectId;
+    private Integer isProduct;//是否关联拍商品 0:否 1:是
+
+    private Long productId;//拍商品id
+
+    private Long listingStartTime;//商品售卖时间
+
+    private Long listingEndTime;//商品结束售卖时间
+
+
 }

+ 61 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseProductMapper.java

@@ -0,0 +1,61 @@
+package com.fs.course.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsCourseProduct;
+
+/**
+ * 拍单商品Mapper接口
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+public interface FsCourseProductMapper extends BaseMapper<FsCourseProduct>{
+    /**
+     * 查询拍单商品
+     * 
+     * @param id 拍单商品主键
+     * @return 拍单商品
+     */
+    FsCourseProduct selectFsCourseProductById(Long id);
+
+    /**
+     * 查询拍单商品列表
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 拍单商品集合
+     */
+    List<FsCourseProduct> selectFsCourseProductList(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 新增拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    int insertFsCourseProduct(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 修改拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    int updateFsCourseProduct(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 删除拍单商品
+     * 
+     * @param id 拍单商品主键
+     * @return 结果
+     */
+    int deleteFsCourseProductById(Long id);
+
+    /**
+     * 批量删除拍单商品
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsCourseProductByIds(Long[] ids);
+}

+ 81 - 0
fs-service/src/main/java/com/fs/course/mapper/FsCourseProductOrderMapper.java

@@ -0,0 +1,81 @@
+package com.fs.course.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fs.course.domain.FsCourseProductOrder;
+import com.fs.course.param.FsCourseProductOrderListParam;
+import com.fs.course.param.FsCourseProductOrderListUParam;
+import com.fs.course.vo.FsCourseProductOrderListUVO;
+import com.fs.course.vo.FsCourseProductOrderVO;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * 拍单商品订单Mapper接口
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+public interface FsCourseProductOrderMapper extends BaseMapper<FsCourseProductOrder>{
+    /**
+     * 查询拍单商品订单
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 拍单商品订单
+     */
+    FsCourseProductOrder selectFsCourseProductOrderByCourseOrderId(Long courseOrderId);
+
+    /**
+     * 查询拍单商品订单列表
+     * 
+     * @param param 拍单商品订单
+     * @return 拍单商品订单集合
+     */
+    List<FsCourseProductOrderVO> selectFsCourseProductOrderList(FsCourseProductOrderListParam param);
+
+    /**
+     * 新增拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    int insertFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder);
+
+    /**
+     * 修改拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    int updateFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder);
+
+    /**
+     * 删除拍单商品订单
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 结果
+     */
+    int deleteFsCourseProductOrderByCourseOrderId(Long courseOrderId);
+
+    /**
+     * 批量删除拍单商品订单
+     * 
+     * @param courseOrderIds 需要删除的数据主键集合
+     * @return 结果
+     */
+    int deleteFsCourseProductOrderByCourseOrderIds(Long[] courseOrderIds);
+
+    @Select({"<script>" +
+            "SELECT cpo.*,cp.product_name,cp.img_url FROM fs_course_product_order cpo" +
+            "LEFT JOIN fs_course_product cp ON cp.id =  cpo.course_product_id" +
+            "WHERE 1=1" +
+            "<if test='maps.status != null'> AND cpo.status = #{maps.status}</if>" +
+            "<if test='maps.userId != null'> AND cpo.user_id = #{maps.userId}</if>" +
+            "ORDER BY cpo.course_order_id" +
+            "</script>"})
+    List<FsCourseProductOrderListUVO> selectFsCourseProductOrderListUVO(@Param("maps") FsCourseProductOrderListUParam param);
+
+    @Select({"SELECT * FROM fs_course_product_order where order_code = #{orderCode}"})
+    FsCourseProductOrder selectFsCourseProductOrderByOrderCode(String orderCode);
+
+}

+ 32 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderCreateParam.java

@@ -0,0 +1,32 @@
+package com.fs.course.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsCourseProductOrderCreateParam {
+
+    private Long userId;
+
+    @ApiModelProperty(value = "用户名")
+    private String userName;
+
+    private String userPhone;
+
+    private Long companyUserId;
+
+    private Long courseProductId;
+
+    private Long courseId;
+
+    private Long videoId;
+
+    @NotNull(message = "支付类型不能为空")
+    private Integer payType;
+
+    private Long companyId;
+
+    private Long extId;
+}

+ 52 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderListParam.java

@@ -0,0 +1,52 @@
+package com.fs.course.param;
+
+import lombok.Data;
+
+@Data
+public class FsCourseProductOrderListParam {
+
+    /**
+     * 订单号
+     */
+    private String orderCode;
+
+    /**
+     * 用户名称
+     */
+    private String userName;
+
+    /**
+     * 用户电话
+     */
+    private String userPhone;
+
+    /**
+     * 支付状态 0 待支付 1已支付
+     */
+    private Integer isPay;
+
+    /**
+     * 订单状态 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功
+     */
+    private Integer status;
+
+    /**
+     * 支付开始时间
+     */
+    private String payStartTime;
+
+    /**
+     * 支付结束时间
+     */
+    private String payEndTime;
+
+    /**
+     * 退款开始时间
+     */
+    private String refundStartTime;
+
+    /**
+     * 退款结束时间
+     */
+    private String refundEndTime;
+}

+ 16 - 0
fs-service/src/main/java/com/fs/course/param/FsCourseProductOrderListUParam.java

@@ -0,0 +1,16 @@
+package com.fs.course.param;
+
+import com.fs.his.param.BaseParam;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FsCourseProductOrderListUParam extends BaseParam {
+
+    private Long userId;
+    /**
+     * 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功
+     */
+    private Integer status;
+}

+ 87 - 0
fs-service/src/main/java/com/fs/course/service/IFsCourseProductOrderService.java

@@ -0,0 +1,87 @@
+package com.fs.course.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.common.core.domain.R;
+import com.fs.course.domain.FsCourseProductOrder;
+import com.fs.course.param.FsCourseProductOrderCreateParam;
+import com.fs.course.param.FsCourseProductOrderListParam;
+import com.fs.course.param.FsCourseProductOrderListUParam;
+import com.fs.course.vo.FsCourseProductOrderListUVO;
+import com.fs.course.vo.FsCourseProductOrderVO;
+import com.fs.his.param.ApplyCourseProductOrderRefundParam;
+import com.fs.his.param.FsCourseProductOrderComputeParam;
+import com.fs.his.param.FsCourseProductOrderDoPayParam;
+import com.fs.his.param.FsCourseProductOrderRefundParam;
+
+/**
+ * 拍单商品订单Service接口
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+public interface IFsCourseProductOrderService extends IService<FsCourseProductOrder>{
+    /**
+     * 查询拍单商品订单
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 拍单商品订单
+     */
+    FsCourseProductOrder selectFsCourseProductOrderByCourseOrderId(Long courseOrderId);
+
+    /**
+     * 查询拍单商品订单列表
+     * 
+     * @param param 拍单商品订单
+     * @return 拍单商品订单集合
+     */
+    List<FsCourseProductOrderVO> selectFsCourseProductOrderList(FsCourseProductOrderListParam param);
+
+    /**
+     * 新增拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    int insertFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder);
+
+    /**
+     * 修改拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    int updateFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder);
+
+    /**
+     * 批量删除拍单商品订单
+     * 
+     * @param courseOrderIds 需要删除的拍单商品订单主键集合
+     * @return 结果
+     */
+    int deleteFsCourseProductOrderByCourseOrderIds(Long[] courseOrderIds);
+
+    /**
+     * 删除拍单商品订单信息
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 结果
+     */
+    int deleteFsCourseProductOrderByCourseOrderId(Long courseOrderId);
+
+    R createOrder(FsCourseProductOrderCreateParam param);
+
+    FsCourseProductOrderListUVO selectCourseProductByCourseOrderId(Long courseOrderId);
+
+    R computeOrder(FsCourseProductOrderComputeParam param);
+
+    List<FsCourseProductOrderListUVO> selectFsCourseProductOrderListUVO(FsCourseProductOrderListUParam param);
+
+    R payment(FsCourseProductOrderDoPayParam param);
+
+    R  payConfirm(String orderSn,String payCode, String tradeNo,String payType,Integer type);
+
+    R refund(FsCourseProductOrderRefundParam param);
+
+    R applyRefund(ApplyCourseProductOrderRefundParam param);
+}

+ 61 - 0
fs-service/src/main/java/com/fs/course/service/IFsCourseProductService.java

@@ -0,0 +1,61 @@
+package com.fs.course.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fs.course.domain.FsCourseProduct;
+
+/**
+ * 拍单商品Service接口
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+public interface IFsCourseProductService extends IService<FsCourseProduct>{
+    /**
+     * 查询拍单商品
+     * 
+     * @param id 拍单商品主键
+     * @return 拍单商品
+     */
+    FsCourseProduct selectFsCourseProductById(Long id);
+
+    /**
+     * 查询拍单商品列表
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 拍单商品集合
+     */
+    List<FsCourseProduct> selectFsCourseProductList(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 新增拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    int insertFsCourseProduct(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 修改拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    int updateFsCourseProduct(FsCourseProduct fsCourseProduct);
+
+    /**
+     * 批量删除拍单商品
+     * 
+     * @param ids 需要删除的拍单商品主键集合
+     * @return 结果
+     */
+    int deleteFsCourseProductByIds(Long[] ids);
+
+    /**
+     * 删除拍单商品信息
+     * 
+     * @param id 拍单商品主键
+     * @return 结果
+     */
+    int deleteFsCourseProductById(Long id);
+}

+ 646 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductOrderServiceImpl.java

@@ -0,0 +1,646 @@
+package com.fs.course.service.impl;
+
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.fs.common.core.domain.R;
+import com.fs.common.exception.CustomException;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fs.common.utils.ServletUtils;
+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.FsCourseProduct;
+import com.fs.course.mapper.FsCourseProductMapper;
+import com.fs.course.param.FsCourseProductOrderCreateParam;
+import com.fs.course.param.FsCourseProductOrderListParam;
+import com.fs.course.param.FsCourseProductOrderListUParam;
+import com.fs.course.vo.FsCourseProductOrderListUVO;
+import com.fs.course.vo.FsCourseProductOrderVO;
+import com.fs.his.domain.*;
+import com.fs.his.dto.PayConfigDTO;
+import com.fs.his.enums.FsCourseProductOrderStatusEnum;
+import com.fs.his.mapper.FsStorePaymentMapper;
+import com.fs.his.param.ApplyCourseProductOrderRefundParam;
+import com.fs.his.param.FsCourseProductOrderComputeParam;
+import com.fs.his.param.FsCourseProductOrderDoPayParam;
+import com.fs.his.param.FsCourseProductOrderRefundParam;
+import com.fs.his.service.IFsStorePaymentService;
+import com.fs.his.service.IFsUserService;
+import com.fs.his.utils.PhoneUtil;
+import com.fs.huifuPay.domain.HuiFuCreateOrder;
+import com.fs.huifuPay.domain.HuiFuRefundResult;
+import com.fs.huifuPay.domain.HuifuCreateOrderResult;
+import com.fs.huifuPay.sdk.opps.core.request.V2TradePaymentScanpayRefundRequest;
+import com.fs.huifuPay.service.HuiFuService;
+import com.fs.system.domain.SysConfig;
+import com.fs.system.mapper.SysConfigMapper;
+import com.fs.system.service.ISysConfigService;
+import com.fs.tzBankPay.TzBankService.TzBankService;
+import com.fs.tzBankPay.doman.*;
+import com.fs.ybPay.domain.CreateWxOrderResult;
+import com.fs.ybPay.domain.OrderResult;
+import com.fs.ybPay.domain.RefundResult;
+import com.fs.ybPay.dto.OrderQueryDTO;
+import com.fs.ybPay.dto.RefundDTO;
+import com.fs.ybPay.dto.WxJspayDTO;
+import com.fs.ybPay.service.IPayService;
+import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
+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.Maps;
+import com.google.gson.Gson;
+import org.apache.commons.collections4.CollectionUtils;
+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 com.fs.course.mapper.FsCourseProductOrderMapper;
+import com.fs.course.domain.FsCourseProductOrder;
+import com.fs.course.service.IFsCourseProductOrderService;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+
+/**
+ * 拍单商品订单Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+@Service
+public class FsCourseProductOrderServiceImpl extends ServiceImpl<FsCourseProductOrderMapper, FsCourseProductOrder> implements IFsCourseProductOrderService {
+    Logger logger= LoggerFactory.getLogger(getClass());
+    @Autowired
+    private WxPayProperties wxPayProperties;
+
+    @Autowired
+    private FsCourseProductMapper courseProductMapper;
+
+    @Autowired FsCourseProductOrderMapper courseProductOrderMapper;
+
+    @Autowired
+    private IFsUserService userService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private IFsStorePaymentService storePaymentService;
+
+    @Autowired
+    SysConfigMapper sysConfigMapper;
+
+    @Autowired
+    private WxPayService wxPayService;
+
+    @Autowired
+    IPayService payService;
+
+    @Autowired
+    private FsStorePaymentMapper fsStorePaymentMapper;
+
+    @Autowired
+    private TzBankService tzBankService;
+
+    @Autowired
+    private HuiFuService huiFuService;
+
+    @Autowired
+    private IPayService ybPayService;
+
+    private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+
+    private static final int CODE_LENGTH = 12;
+
+
+    /**
+     * 查询拍单商品订单
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 拍单商品订单
+     */
+    @Override
+    public FsCourseProductOrder selectFsCourseProductOrderByCourseOrderId(Long courseOrderId)
+    {
+        return baseMapper.selectFsCourseProductOrderByCourseOrderId(courseOrderId);
+    }
+
+    /**
+     * 查询拍单商品订单列表
+     * 
+     * @param param 拍单商品订单
+     * @return 拍单商品订单
+     */
+    @Override
+    public List<FsCourseProductOrderVO> selectFsCourseProductOrderList(FsCourseProductOrderListParam param)
+    {
+        List<FsCourseProductOrderVO> productOrderVOS = baseMapper.selectFsCourseProductOrderList(param);
+        if (CollectionUtils.isNotEmpty(productOrderVOS)) {
+            productOrderVOS.forEach(productOrderVO -> {
+                if (StringUtils.isNotEmpty(productOrderVO.getProductJson())) {
+                    FsCourseProduct courseProduct = JSONUtil.toBean(productOrderVO.getProductJson(), FsCourseProduct.class);
+                    productOrderVO.setProductName(courseProduct.getProductName());
+                }
+            });
+        }
+        return productOrderVOS;
+    }
+
+    /**
+     * 新增拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    @Override
+    public int insertFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder)
+    {
+        fsCourseProductOrder.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsCourseProductOrder(fsCourseProductOrder);
+    }
+
+    /**
+     * 修改拍单商品订单
+     * 
+     * @param fsCourseProductOrder 拍单商品订单
+     * @return 结果
+     */
+    @Override
+    public int updateFsCourseProductOrder(FsCourseProductOrder fsCourseProductOrder)
+    {
+        fsCourseProductOrder.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsCourseProductOrder(fsCourseProductOrder);
+    }
+
+    /**
+     * 批量删除拍单商品订单
+     * 
+     * @param courseOrderIds 需要删除的拍单商品订单主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseProductOrderByCourseOrderIds(Long[] courseOrderIds)
+    {
+        return baseMapper.deleteFsCourseProductOrderByCourseOrderIds(courseOrderIds);
+    }
+
+    /**
+     * 删除拍单商品订单信息
+     * 
+     * @param courseOrderId 拍单商品订单主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseProductOrderByCourseOrderId(Long courseOrderId)
+    {
+        return baseMapper.deleteFsCourseProductOrderByCourseOrderId(courseOrderId);
+    }
+
+    @Override
+    public R createOrder(FsCourseProductOrderCreateParam param) {
+        FsCourseProduct courseProduct = courseProductMapper.selectFsCourseProductById(param.getCourseProductId());
+        if (courseProduct == null) {
+            return R.error("商品不存在");
+        }
+
+        FsCourseProductOrder courseProductOrder = new FsCourseProductOrder();
+        BeanUtils.copyProperties(param, courseProductOrder);
+        String orderCode =  OrderCodeUtils.getOrderSn();
+        if(StringUtils.isEmpty(orderCode)){
+            return R.error("订单生成失败,请重试");
+        }
+        courseProductOrder.setOrderCode(orderCode);
+        courseProductOrder.setIsPay(0L);
+        courseProductOrder.setCreateTime(new Date());
+        courseProductOrder.setProductJson(JSON.toJSONString(courseProduct));
+        courseProductOrder.setStatus(1L);
+        courseProductOrder.setVerifyCode(VerificationCodeGenerator());
+        try {
+            if (baseMapper.insertFsCourseProductOrder(courseProductOrder) > 0) {
+                return R.ok("下单成功").put("order",courseProductOrder);
+            } else {
+                return R.error("订单创建失败");
+            }
+        } catch (Exception e) {
+            // 异常处理
+            return R.error("订单创建失败:" + e.getMessage());
+        }
+    }
+
+    @Override
+    public FsCourseProductOrderListUVO selectCourseProductByCourseOrderId(Long courseOrderId) {
+        FsCourseProductOrderListUVO productOrderListUVO = new FsCourseProductOrderListUVO();
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(courseOrderId);
+        if (ObjectUtil.isNotEmpty(courseProductOrder)) {
+            BeanUtils.copyProperties(courseProductOrder, productOrderListUVO);
+            productOrderListUVO.setProductJson(courseProductOrder.getProductJson());
+        }
+        return productOrderListUVO;
+    }
+
+    @Override
+    public R computeOrder(FsCourseProductOrderComputeParam param) {
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(param.getOrderId());
+        if (courseProductOrder == null) {
+            return R.error("订单不存在");
+        }
+        if (courseProductOrder.getStatus() != 1) {
+            return R.error("订单状态不正确");
+        }
+        FsUser user = userService.selectFsUserByUserId(courseProductOrder.getUserId());
+        if (user != null && StringUtils.isNotEmpty(user.getMaOpenId())) {
+            Map<String,Object> moneys= Maps.newHashMap();
+            FsCourseProduct courseProduct = JSONUtil.toBean(courseProductOrder.getProductJson(), FsCourseProduct.class);
+            moneys.put("payPrice",courseProduct.getProductPrice());
+            moneys.put("product",courseProduct);
+            return R.ok().put("moneys",moneys);
+        } else {
+            return R.error("用户不存在");
+        }
+
+    }
+
+    @Override
+    public List<FsCourseProductOrderListUVO> selectFsCourseProductOrderListUVO(FsCourseProductOrderListUParam param) {
+
+        List<FsCourseProductOrderListUVO> productOrderListUVOS = baseMapper.selectFsCourseProductOrderListUVO(param);
+        //订单商品价格
+        if (CollectionUtils.isNotEmpty(productOrderListUVOS)) {
+            productOrderListUVOS.forEach(item -> {
+                FsCourseProduct courseProduct = JSONUtil.toBean(item.getProductJson(), FsCourseProduct.class);
+                if (courseProduct != null) {
+                    item.setPrice(courseProduct.getProductPrice());
+                }
+            });
+        }
+        return productOrderListUVOS;
+    }
+
+    @Override
+    @Transactional
+    public R payment(FsCourseProductOrderDoPayParam param) {
+        logger.info("支付参数==============={}",param);
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(param.getOrderId());
+        logger.info("订单信息==============={}",courseProductOrder);
+        if (!FsCourseProductOrderStatusEnum.STATUS_1.getValue().equals(courseProductOrder.getStatus())) {
+            return R.error("非法操作");
+        }
+        FsCourseProduct courseProduct = JSONUtil.toBean(courseProductOrder.getProductJson(), FsCourseProduct.class);
+        if (courseProduct == null) {
+            return R.error("订单商品不存在");
+        }
+        FsUser user = userService.selectFsUserByUserId(param.getUserId());
+        logger.info("用户信息==============={}",user);
+        if (user != null && StringUtils.isNotEmpty(user.getCourseMaOpenId())) {
+            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.setBusinessCode(courseProductOrder.getOrderCode());
+                storePayment.setPayCode(payCode);
+                storePayment.setPayMoney(courseProduct.getProductPrice());
+                storePayment.setCreateTime(new Date());
+                storePayment.setPayTypeCode("weixin");
+                storePayment.setBusinessType(6);
+                storePayment.setCompanyId(courseProductOrder.getCompanyId());
+                storePayment.setCompanyUserId(courseProductOrder.getCompanyUserId());
+                storePayment.setRemark("拍商品订单支付");
+                storePayment.setOpenId(user.getCourseMaOpenId());
+                storePayment.setUserId(user.getUserId());
+                storePayment.setBusinessId(courseProductOrder.getCourseOrderId().toString());
+                if (storePaymentService.insertFsStorePayment(storePayment) > 0) {
+                    if (payConfigDTO.getType().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.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());
+                        wxPayService.setConfig(payConfig);
+                        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
+                        orderRequest.setOpenid(user.getCourseMaOpenId());//公众号支付提供用户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 (payConfigDTO.getType().equals("yb")) {
+                        WxJspayDTO p = new WxJspayDTO();
+                        // 使用setter方法为对象赋值
+                        p.setPayMoney(storePayment.getPayMoney().toString());
+                        p.setLowOrderId("product-" + storePayment.getPayCode());
+                        p.setBody("拍商品订单支付");
+                        p.setIsMinipg("1");
+                        p.setOpenId(user.getCourseMaOpenId());
+                        p.setAttach("");
+                        p.setStoreid("0");
+                        CreateWxOrderResult wxOrder = payService.createWxOrder(p);
+                        logger.info("易宝返回"+wxOrder);
+                        if (wxOrder.getStatus().equals("100")) {
+                            FsStorePayment mt=new FsStorePayment();
+                            mt.setPaymentId(storePayment.getPaymentId());
+                            mt.setTradeNo(wxOrder.getUpOrderId());
+                            fsStorePaymentMapper.updateFsStorePayment(mt);
+                            return R.ok().put("isPay", 0).put("data", wxOrder).put("type", "yb");
+                        } else {
+                            throw new CustomException("支付失败");
+                        }
+                    } else if (payConfigDTO.getType().equals("tz")) {
+                        PayCreateOrder o = new PayCreateOrder();
+                        o.setOrderNo("product" + storePayment.getPayCode()); // 业务系统订单号
+                        o.setTrxAmt(storePayment.getPayMoney().doubleValue()); // 交易金额
+                        o.setBusinessCstNo(courseProductOrder.getUserId().toString()); // 业务平台客户号
+                        String phone="";
+                        if (user.getPhone()!=null&&user.getPhone().length()>4){
+                            phone=user.getPhone().substring(user.getPhone().length()-4);
+                            if (user.getPhone().length()>11){
+                                o.setPayerMobileNo(PhoneUtil.decryptPhone(user.getPhone()));
+                            }else {
+                                o.setPayerMobileNo(user.getPhone());
+                            }
+                        }
+                        o.setPayerName("微信用户"+phone);
+                        o.setGoodsInfo("拍商品订单支付"); // 订单信息
+                        o.setOpenId(user.getCourseMaOpenId());
+                        o.setOrderType(3);
+                        o.setOrderId(courseProductOrder.getCourseOrderId().toString());
+                        TzBankResult<PayCreateOrderResult> result = tzBankService.createOrder(o);
+                        FsStorePayment mt=new FsStorePayment();
+                        mt.setPaymentId(storePayment.getPaymentId());
+                        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")) {
+                        logger.info("创建汇付订单");
+                        HuiFuCreateOrder o = new HuiFuCreateOrder();
+                        o.setTradeType("T_MINIAPP");
+                        o.setOpenid(user.getCourseMaOpenId());
+                        o.setReqSeqId("product-"+storePayment.getPayCode());
+                        o.setTransAmt(storePayment.getPayMoney().toString());
+                        o.setGoodsDesc("拍商品订单支付");
+                        HuifuCreateOrderResult result = huiFuService.createOrder(o);
+                        logger.info("创建汇付支付:"+result);
+                        FsStorePayment mt=new FsStorePayment();
+                        mt.setPaymentId(storePayment.getPaymentId());
+                        mt.setTradeNo(result.getHf_seq_id());
+                        storePaymentService.updateFsStorePayment(mt);
+                        return R.ok().put("isPay", 0).put("data", result).put("type", "hf");
+                    }
+                }
+            } else {
+                //TODO 支付金额为0的业务
+            }
+
+        } else {
+           return R.error("用户OPENID不存在");
+        }
+        return R.error();
+    }
+
+    @Override
+    public R payConfirm(String orderSn, String payCode, String tradeNo, String payType, Integer type) {
+        logger.info("进入拍商品订单支付回调 orderSn: {}, payCode: {}, tradeNo: {}, payType: {}, type: {}",
+                orderSn, payCode, tradeNo, payType, type);
+        FsCourseProductOrder order = null;
+        if(type.equals(1)){
+            FsStorePayment storePayment = fsStorePaymentMapper.selectFsStorePaymentByPaymentCode(payCode);
+            if (storePayment!=null){
+                if(storePayment.getStatus().equals(0)){
+                    FsStorePayment paymentMap=new FsStorePayment();
+                    paymentMap.setPaymentId(storePayment.getPaymentId());
+                    paymentMap.setStatus(1);
+                    paymentMap.setPayTime(new Date());
+                    paymentMap.setTradeNo(tradeNo);
+                    if(payType.equals(PayType.WECHAT_MINI_PROGRAM_PAYMENT.getCode())){
+                        paymentMap.setPayTypeCode(PayType.WECHAT_MINI_PROGRAM_PAYMENT.name());
+                    }
+                    else if(payType.equals(PayType.ALIPAY_BARCODE_PAYMENT.getCode())){
+                        paymentMap.setPayTypeCode(PayType.ALIPAY_BARCODE_PAYMENT.name());
+                    }
+                    if (storePayment.getPayMode().equals("yb")){
+                        OrderQueryDTO orderQueryDTO = new OrderQueryDTO();
+                        orderQueryDTO.setUpOrderId(tradeNo);
+                        OrderResult orderResult = ybPayService.getOrder(orderQueryDTO);
+                        paymentMap.setBankSerialNo(orderResult.getBankOrderId());
+                        paymentMap.setBankTransactionId(orderResult.getBankTrxId());
+                    }
+                    logger.info("更新支付记录");
+                    fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                    order = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(Long.parseLong(storePayment.getBusinessId()));
+                }
+            }
+            else{
+                logger.info("支付单号不存在:"+payCode);
+                return R.error("支付单号不存在");
+            }
+        } else if(type.equals(2)){
+            order=courseProductOrderMapper.selectFsCourseProductOrderByOrderCode(orderSn);
+        }
+        FsCourseProduct courseProduct = JSONUtil.toBean(order.getProductJson(), FsCourseProduct.class);
+
+        if (!order.getStatus().equals(FsCourseProductOrderStatusEnum.STATUS_1.getValue()) && courseProduct == null){
+            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+            return R.error("非法操作");
+        }
+
+        logger.info("更新拍商品订单支付状态");
+        FsCourseProductOrder map = new FsCourseProductOrder();
+        map.setCourseOrderId(order.getCourseOrderId());
+        map.setIsPay(1L);
+        map.setStatus(FsCourseProductOrderStatusEnum.STATUS_2.getValue());
+        map.setPayTime(new Date());
+        courseProductOrderMapper.updateFsCourseProductOrder(map);
+        return R.ok();
+    }
+
+    @Transactional
+    @Override
+    public R refund(FsCourseProductOrderRefundParam param) {
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(param.getCourseOrderId());
+        if (courseProductOrder == null) {
+            throw new CustomException("订单不存在");
+        }
+
+        if (courseProductOrder.getIsPay() != 1 || !Objects.equals(courseProductOrder.getStatus(), FsCourseProductOrderStatusEnum.STATUS_NE1.getValue())) {
+            throw new CustomException("此状态的订单不可退款");
+        }
+
+        FsCourseProduct courseProduct = JSONUtil.toBean(courseProductOrder.getProductJson(), FsCourseProduct.class);
+        if (courseProduct == null) {
+            throw new CustomException("订单商品不存在");
+        }
+
+        //修改拍商品订单状态
+        FsCourseProductOrder mapOrder = new FsCourseProductOrder();
+        mapOrder.setCourseOrderId(param.getCourseOrderId());
+        mapOrder.setStatus(FsCourseProductOrderStatusEnum.STATUS_NE2.getValue());
+        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);
+                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.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("product-"+payment.getPayCode());
+                    refundRequest.setOutRefundNo("product-"+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("product-"+payment.getPayCode());
+                    refundDTO.setUpOrderId(payment.getTradeNo());
+                    RefundResult result=payService.refund(refundDTO);
+                    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 if(payment.getPayMode().equals("tz")){
+                    RefundParam tzBankResult = new RefundParam();
+                    // 使用set方法为对象的字段赋值
+                    //商户原支付订单号
+                    tzBankResult.setOldPayOutOrderNo("product"+payment.getPayCode());
+                    // 商户退款订单号 对接平台系统里自己生成的退款订单号
+                    tzBankResult.setRefundOrderNo("product"+payment.getPayCode());
+                    // 交易发送时间 yyyyMMddHHmmss
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+                    tzBankResult.setTrxSendTime(sdf.format(new Date()));
+
+                    // 退款金额
+                    tzBankResult.setRefundOrdTransAmt(payment.getPayMoney().doubleValue());
+                    TzBankResult<com.fs.tzBankPay.doman.RefundResult> result = tzBankService.refund(tzBankResult);
+                    if(result.getBody().getRefundOrdStatus().equals("90")){
+                        FsStorePayment paymentMap=new FsStorePayment();
+                        paymentMap.setPaymentId(payment.getPaymentId());
+                        paymentMap.setStatus(-1);
+                        paymentMap.setRefundTime(DateUtils.getNowDate());
+                        paymentMap.setRefundMoney(payment.getPayMoney());
+                        fsStorePaymentMapper.updateFsStorePayment(paymentMap);
+                    }
+                } else if (payment.getPayMode().equals("hf")){
+
+                    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", "product-"+payment.getPayCode());
+                    request.setExtendInfo(extendInfoMap);
+                    HuiFuRefundResult refund = huiFuService.refund(request);
+                    logger.info("拍商品订单退款返回结果:问诊订单id:"+courseProductOrder.getCourseOrderId()+refund);
+                    if(refund.getResp_code().equals("00000000")&&(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);
+                    }
+                }
+
+            }
+        }
+
+        return R.ok();
+    }
+
+    @Override
+    public R applyRefund(ApplyCourseProductOrderRefundParam param) {
+        FsCourseProductOrder courseProductOrder = courseProductOrderMapper.selectFsCourseProductOrderByCourseOrderId(param.getCourseOderId());
+        if (courseProductOrder == null) {
+            return R.error("订单不存在");
+        }
+        if (!Objects.equals(courseProductOrder.getStatus(), FsCourseProductOrderStatusEnum.STATUS_2.getValue())) {
+            return R.error("订单状态异常,申请退款失败");
+        }
+        FsCourseProductOrder map = new FsCourseProductOrder();
+        map.setCourseOrderId(courseProductOrder.getCourseOrderId());
+        map.setRefundExplain(param.getRefundReason());
+        map.setRefundTime(new Date());
+        map.setStatus(FsCourseProductOrderStatusEnum.STATUS_NE1.getValue());
+        if (courseProductOrderMapper.updateFsCourseProductOrder(map) > 0) {
+            return R.ok();
+        }
+        return R.error();
+    }
+
+    //生成核销码
+    private String VerificationCodeGenerator(){
+        Random random = new Random();
+        StringBuilder codeBuilder = new StringBuilder(CODE_LENGTH);
+        for (int i = 0; i < CODE_LENGTH; i++) {
+            int index = random.nextInt(CHARACTERS.length());
+            codeBuilder.append(CHARACTERS.charAt(index));
+        }
+        return codeBuilder.toString();
+    }
+
+}

+ 93 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsCourseProductServiceImpl.java

@@ -0,0 +1,93 @@
+package com.fs.course.service.impl;
+
+import java.util.List;
+import com.fs.common.utils.DateUtils;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import com.fs.course.mapper.FsCourseProductMapper;
+import com.fs.course.domain.FsCourseProduct;
+import com.fs.course.service.IFsCourseProductService;
+
+/**
+ * 拍单商品Service业务层处理
+ * 
+ * @author fs
+ * @date 2025-07-28
+ */
+@Service
+public class FsCourseProductServiceImpl extends ServiceImpl<FsCourseProductMapper, FsCourseProduct> implements IFsCourseProductService {
+
+    /**
+     * 查询拍单商品
+     * 
+     * @param id 拍单商品主键
+     * @return 拍单商品
+     */
+    @Override
+    public FsCourseProduct selectFsCourseProductById(Long id)
+    {
+        return baseMapper.selectFsCourseProductById(id);
+    }
+
+    /**
+     * 查询拍单商品列表
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 拍单商品
+     */
+    @Override
+    public List<FsCourseProduct> selectFsCourseProductList(FsCourseProduct fsCourseProduct)
+    {
+        return baseMapper.selectFsCourseProductList(fsCourseProduct);
+    }
+
+    /**
+     * 新增拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    @Override
+    public int insertFsCourseProduct(FsCourseProduct fsCourseProduct)
+    {
+        fsCourseProduct.setCreateTime(DateUtils.getNowDate());
+        return baseMapper.insertFsCourseProduct(fsCourseProduct);
+    }
+
+    /**
+     * 修改拍单商品
+     * 
+     * @param fsCourseProduct 拍单商品
+     * @return 结果
+     */
+    @Override
+    public int updateFsCourseProduct(FsCourseProduct fsCourseProduct)
+    {
+        fsCourseProduct.setUpdateTime(DateUtils.getNowDate());
+        return baseMapper.updateFsCourseProduct(fsCourseProduct);
+    }
+
+    /**
+     * 批量删除拍单商品
+     * 
+     * @param ids 需要删除的拍单商品主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseProductByIds(Long[] ids)
+    {
+        return baseMapper.deleteFsCourseProductByIds(ids);
+    }
+
+    /**
+     * 删除拍单商品信息
+     * 
+     * @param id 拍单商品主键
+     * @return 结果
+     */
+    @Override
+    public int deleteFsCourseProductById(Long id)
+    {
+        return baseMapper.deleteFsCourseProductById(id);
+    }
+}

+ 14 - 0
fs-service/src/main/java/com/fs/course/service/impl/FsUserCourseVideoServiceImpl.java

@@ -195,6 +195,8 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     @Autowired
     private IFsUserWxService fsUserWxService;
     @Autowired
+    private FsCourseProductMapper courseProductMapper;
+    @Autowired
     private IFsUserCompanyUserService userCompanyUserService;
     @Autowired
     private SysDictDataMapper dictDataMapper;
@@ -225,6 +227,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
             List<FsCourseQuestionBank> fsCourseQuestionBanks = courseQuestionBankMapper.selectFsCourseQuestionBankByIdVO(courseVideo.getQuestionBankId().split(","));
             fsUserCourseVideoQVO.setQuestionBankList(fsCourseQuestionBanks);
         }
+        //返回课程关联的拍商品
+        if(courseVideo.getIsProduct() != null && courseVideo.getIsProduct() == 1 && courseVideo.getProductId() != null){
+            FsCourseProduct courseProduct = courseProductMapper.selectFsCourseProductById(courseVideo.getProductId());
+            List<FsCourseProduct> courseProducts = Arrays.asList(courseProduct);
+            fsUserCourseVideoQVO.setCourseProducts(courseProducts);
+        }
         return fsUserCourseVideoQVO;
     }
 
@@ -263,6 +271,12 @@ public class FsUserCourseVideoServiceImpl implements IFsUserCourseVideoService
     public int updateFsUserCourseVideo(FsUserCourseVideo fsUserCourseVideo)
     {
         fsUserCourseVideo.setUpdateTime(DateUtils.getNowDate());
+        //无关联商品的课程 清除脏数据
+        if (fsUserCourseVideo.getIsProduct() != null && fsUserCourseVideo.getIsProduct() == 0 && fsUserCourseVideo.getProductId() != null) {
+            fsUserCourseVideo.setProductId(null);
+            fsUserCourseVideo.setListingStartTime(null);
+            fsUserCourseVideo.setListingEndTime(null);
+        }
         return fsUserCourseVideoMapper.updateFsUserCourseVideo(fsUserCourseVideo);
     }
 

+ 76 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderListUVO.java

@@ -0,0 +1,76 @@
+package com.fs.course.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fs.common.annotation.Excel;
+import com.fs.course.domain.FsCourseProduct;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class FsCourseProductOrderListUVO {
+
+    /** 拍单商品订单表id */
+    private Long courseOrderId;
+
+    /** 订单编号 */
+    private String orderCode;
+
+    /** 用户id */
+    private Long userId;
+
+    /** 用户名称 */
+    private String userName;
+
+    /** 用户电话 */
+    private String userPhone;
+
+    /** 拍单商品id */
+    private Long courseProductId;
+
+    /** 商品json */
+    private String productJson;
+
+    /** 课程id */
+    private Long courseId;
+
+    /** 视频小节id */
+    private Long videoId;
+
+    /** 支付状态 0 待支付 1已支付 */
+    private Long isPay;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 支付方式 微信 */
+    private Long payType;
+
+    /** 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功 */
+    private Long status;
+
+    /** 申请退款时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date refundTime;
+
+    /** 申请退款理由 */
+    private String refundExplain;
+
+    /** 核销码 */
+    private String verifyCode;
+
+    /** 公司id */
+    private Long companyId;
+
+    /** 销售id */
+    private Long companyUserId;
+
+    /** 企微外部联系人id */
+    private Long extId;
+
+    private BigDecimal price;
+
+    private FsCourseProduct courseProduct;
+}

+ 100 - 0
fs-service/src/main/java/com/fs/course/vo/FsCourseProductOrderVO.java

@@ -0,0 +1,100 @@
+package com.fs.course.vo;
+
+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.util.Date;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class FsCourseProductOrderVO extends BaseEntity {
+    /** 拍单商品订单表id */
+    private Long courseOrderId;
+
+    /** 订单编号 */
+    @Excel(name = "订单编号")
+    private String orderCode;
+
+    /** 用户id */
+    private Long userId;
+
+    /** 用户名称 */
+    @Excel(name = "用户名称")
+    private String userName;
+
+    /** 用户电话 */
+    @Excel(name = "用户电话")
+    private String userPhone;
+
+    /** 拍单商品id */
+    private Long courseProductId;
+
+    /** 商品json */
+    private String productJson;
+
+    /** 课程id */
+    private Long courseId;
+
+    /** 视频小节id */
+    private Long videoId;
+
+    /** 支付状态 0 待支付 1已支付 */
+    @Excel(name = "支付状态",readConverterExp = "0=待支付,1=已支付")
+    private Long isPay;
+
+    /** 支付时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "支付时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date payTime;
+
+    /** 支付方式 微信 */
+    private Long payType;
+
+    /** 1 待支付 2已支付 3 已完成 -1 申请退款 -2 : 退款成功 */
+    @Excel(name = "订单状态",readConverterExp = "1=待支付,2=已支付,3=已完成,-1=申请退款,-2=退款成功")
+    private Long status;
+
+    /** 申请退款时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "申请退款时间", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date refundTime;
+
+    /** 申请退款理由 */
+    @Excel(name = "申请退款理由")
+    private String refundExplain;
+
+    /** 核销码 */
+    @Excel(name = "核销码")
+    private String verifyCode;
+
+    /** 公司id */
+    private Long companyId;
+
+    /** 销售id */
+
+    private Long companyUserId;
+
+    /** 企微外部联系人id */
+    private Long extId;
+
+    @Excel(name = "课程")
+    private String courseName;
+
+    @Excel(name = "视频")
+    private String title;
+
+    @Excel(name = "公司名称")
+    private String companyName;
+
+    @Excel(name = "销售")
+    private String companyUserName;
+
+    @Excel(name = "企微外部联系人")
+    private String extName;
+
+    @Excel(name = "商品名称")
+    private String productName;
+}

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

@@ -43,5 +43,12 @@ public class FsUserCourseVideoH5DVO extends BaseEntity
     private String lineThree; //线路三 华为云obs
     private Integer uploadType;
 
+    private Integer isProduct;//是否关联拍商品 0:否 1:是
+
+    private Long productId;//拍商品id
+
+    private Long listingStartTime;//商品售卖时间
+
+    private Long listingEndTime;//商品结束售卖时间
 
 }

+ 13 - 0
fs-service/src/main/java/com/fs/course/vo/FsUserCourseVideoQVO.java

@@ -2,6 +2,7 @@ package com.fs.course.vo;
 
 import com.fs.common.annotation.Excel;
 import com.fs.common.core.domain.BaseEntity;
+import com.fs.course.domain.FsCourseProduct;
 import com.fs.course.domain.FsCourseQuestionBank;
 import lombok.Data;
 
@@ -82,4 +83,16 @@ public class FsUserCourseVideoQVO extends BaseEntity {
 
     private String packageJson;
     private Integer isFirst;
+    private Integer isProduct;//是否关联拍商品 0:否 1:是
+
+    private Long productId;//拍商品id
+
+    private Long listingStartTime;//商品售卖时间
+
+    private Long listingEndTime;//商品结束售卖时间
+
+    /**
+     * 课程关联的拍商品
+     */
+    private List<FsCourseProduct>  courseProducts;
 }

+ 29 - 0
fs-service/src/main/java/com/fs/his/enums/FsCourseProductOrderStatusEnum.java

@@ -0,0 +1,29 @@
+package com.fs.his.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.stream.Stream;
+
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+public enum FsCourseProductOrderStatusEnum {
+
+    STATUS_NE1(-1L,"申请退款"),
+    STATUS_NE2(-2L,"退款成功"),
+    STATUS_1(1L,"待支付"),
+    STATUS_2(2L,"已支付"),
+    STATUS_3(3L,"已完成");
+
+    private Long value;
+    private String desc;
+
+    public static FsCourseProductOrderStatusEnum toType(int value) {
+        return Stream.of(FsCourseProductOrderStatusEnum.values())
+                .filter(p -> p.value == value)
+                .findAny()
+                .orElse(null);
+    }
+}

+ 10 - 0
fs-service/src/main/java/com/fs/his/param/ApplyCourseProductOrderRefundParam.java

@@ -0,0 +1,10 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class ApplyCourseProductOrderRefundParam {
+
+    private Long courseOderId;
+    private String refundReason;
+}

+ 8 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderCancelParam.java

@@ -0,0 +1,8 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class FsCourseProductOrderCancelParam {
+    private Long courseOrderId;
+}

+ 11 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderComputeParam.java

@@ -0,0 +1,11 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class FsCourseProductOrderComputeParam {
+
+    private Long userId;
+
+    private Long orderId;
+}

+ 14 - 0
fs-service/src/main/java/com/fs/his/param/FsCourseProductOrderDoPayParam.java

@@ -0,0 +1,14 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class FsCourseProductOrderDoPayParam {
+
+    @NotNull(message = "订单id不能为空")
+    private Long orderId;
+
+    private Long userId;
+}

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

@@ -0,0 +1,11 @@
+package com.fs.his.param;
+
+import lombok.Data;
+
+@Data
+public class FsCourseProductOrderRefundParam {
+
+    private Long courseOrderId;
+
+    private String sysUserName;
+}

+ 14 - 0
fs-service/src/main/java/com/fs/huifuPay/service/impl/HuiFuServiceImpl.java

@@ -81,6 +81,7 @@ public class HuiFuServiceImpl implements HuiFuService {
             // 商品描述
             request.setGoodsDesc(order.getGoodsDesc());
             extendInfoMap.put("fq_mer_discount_flag", "N");
+            logger.info("汇付回调地址=================:"+config.getHfPayNotifyUrl());
             extendInfoMap.put("notify_url", config.getHfPayNotifyUrl());
             extendInfoMap.put("remark", "string");
             request.setExtendInfo(extendInfoMap);
@@ -252,6 +253,7 @@ public class HuiFuServiceImpl implements HuiFuService {
         SysConfigMapper sysConfigMapper= SpringUtils.getBean(SysConfigMapper.class);
         SysConfig sysConfig = sysConfigMapper.selectConfigByConfigKey("his.pay");
         FsPayConfig fsPayConfig = new Gson().fromJson(sysConfig.getConfigValue(), FsPayConfig.class);
+
 //        FsPayConfig fsPayConfig = new FsPayConfig();
 //        fsPayConfig.setAppId("wxc3f0a952b7bc2b94");
 //        fsPayConfig.setHfProductId("KAZX");
@@ -262,6 +264,18 @@ public class HuiFuServiceImpl implements HuiFuService {
 //        fsPayConfig.setHfRsaPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCijLcYLMJEe16TS6BtEG9hUezZyYvp2qgpPVGWaaBbb6lud89ILMUC7jyTWufCo2fUQ0nJzYhVlNeMzmGFtg/zFwhkjJIkuCOW+/Koy1ow66Rom8/sNQLb82szHoeklbv17AnD7WJis7cGyy1+3E6jzfaPOB7PTzidK6KyfCWDByOt0JcGe3+6+9+loQFbFRXJ2RpWPQeN72n9FVtSKSvgkGtJNUzh/qBwMPN6ol6xcU/Z2o1sYrRfKC4tcMqccRi/DvvZFJPVlN+YqkJ6lhgAmJg7eZ2fhIgrmzqc96UKp2YUNm+1v8XHCflD9Wv94E6D2JgL4VbF4Zyf+fKYuR7pAgMBAAECggEAfy5UL6ENmuFgHSVF7y+1xdKA2+IbC60ed63XgTVB12jli15Im3MT7ngSg0TUIvERUv4W5MNgkX10rWHo4eKSViPGWE24JuzAQ+j7cuAwwCgPKh4HMAxGIWwyivuvK7JQL1kwRtEccpekc7dS8HhVO0rySBqj2JZmeGrk0HvcKciSWuMjhjT4dJUwSntD07REV6rVjrpQXuvmY40vH88uvHLdH1IcjmJs2yJRNawUNtd+8FvpOCjami7zpB+er+AQ6S2fvpljNqfE5Kadm3MvzBngDdMS3xRvMHfjCifVwFpLP0rLDP6cSn6PJWbkNYQVZi12w8+wb5f7AVlaKXnfdQKBgQDh7VC5+MOqfcUr9h/n2vhFFhQOaGAZCOBc65n8VBj9aRht8ViXFvRrIRmM+QvUbV9/7taFbtAnZXIzu+12T4vnlZv9DTsy6kKloV5923xZ4CpzIVG8crlwJz1wdALeO6M485RtRLjz6nlNKn2m2VJ1d5XFBDhIz5rWUzagPwwpwwKBgQC4L8Eyu6Yn/zQmv8l6rfAsEfUJzfYtojf1PerPYilARtgFuD20cppcOP5oAk2TTX3qaz0Y9atCfL2z2qxtrgKtw2etfhDBmT6l6+pg04SLuyTrVeZ5dxXHt+LRLJnvBbGgnvAM6rSRKdHXT0gfqiRIMw2qIUtndgRr4RK5hqcd4wKBgBYBFh620t/VFhIdC6h6VDnuV4+7rLhje+6w57OCwVhVFxMGMZmtm6qfc6yeSP+sk2OTcINYcp+TqtbNE+i1AKxSjvnLgxuHY2xcViat7OOYCKpj8WEIT3VT7RD5y5m3d0NBvhASZG0lRiE05T4N5pEYT5b7vTuiNLNxMV3UJiwfAoGBAIb2/1QEqwmN+RIX4TSTNnWkpvELSkRAJU8Akwpp/J5MC0mNqzGJ9NB1Nv7SCTRSSV04PaoHgvoSXBPpvgYUx4O6t0MrKG4ktAJzL+jJtcuKU9Bavqrs9znE5mCulRHQE0wGixJ7/dqNUWW7g7coPrPlLTMoeI+UrEK8x7LJF7ZPAoGALHvtu6zzWVeCdELIPUTersVQrH1R3yZuf6rgubg4XFw3meFcd4W8BvXm4EKGRZxdiyZvCtKlkV9u110Rx3RNSbZCOb3MClmkcow8vPIhmyGWIGymAIxr9JcD0p6HogzPvbjRsLh1nFg/+95OL2E353Bp4/oPIgYIfnYNUfD+0gA=");
 //        fsPayConfig.setHfRsaPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjbkiiy2ewzuPsM5uZbAFMJOBWCRRQ2RtH7Dbr9Evbow6IEyvGoen8XKpiuXzapeps3b2eogETHVFQtLooqRHpVRppFKtU1AHZXA7C6wPocfMldJbTykDCowyJwOSYEaFPBjr9cw6dQcBJMIEHj0YWjBPR1dPVzf+y4sUohbrkS/FANBpp24j+Mu0qEqh8TuVuKlvig7jbmXJiJkAmUJ+Tb3Caj20fFTen6juPd3zR/KM3twki06wZZbb4KyCiM/NwozEqJ9PkWSs6rG7aW+BEfzlo3m1a7MlL0vpKNR3f0lbywq09rFAwtA7R2lssWwLMma4LOqtMMqo3yZdv4vObQIDAQAB");
 //        fsPayConfig.setHfPayOnlineNotifyUrl("https://userapp.his.cdwjyyh.com//app/hfPay/payNotifyUrl");
+
+//        FsPayConfig fsPayConfig = new FsPayConfig();
+//        fsPayConfig.setAppId("wxb48fe0acfdc70a92");
+//        fsPayConfig.setHfProductId("KAZX");
+//        fsPayConfig.setHfSysId("6666000173104153");
+//        fsPayConfig.setHuifuId("6666000173104153");
+//        fsPayConfig.setHfRsaPrivateKey("MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCYzLmE2qBlRQbAosIjPxTZwRItgMgOTT99bRYxa3xQhiq2+YPj2R5lOKu5Y74Po43cg5UG8+7z7r4hV2q+sS3DwvnifHrkytXrnwDuW4ijagiMhr0Am9cEP6WqmuCyy8cMS+MtZ8eBCFefXjDsO4zXDk9/jxpywZ59i85q5Ka03S6lJOW+cq7RToEGJoxF1E98UtewbcPL2FxU5eQnte51RiGGly3drAQh+Tbdt8brjycnfR1SAhEFe/cFAOG6zC1XyJwkCfFynpvihA7SGSrTozBvIxg5ylGTx+HiRPDlYBABzWZkZgtvSGF0V7DQy5Tia/kuksOuePXb59MrUyIBAgMBAAECggEALWH44/2vUAS9aa+tq5xLzBUtGfi68ox9A/rHcaw0AxKmUywuwRi2j2fSkUCPrcNtGga215bR7P+G1w5ItRSYvCEH6P4B3jxkZxQVybXEEo0mtt45+plOtoNU6CQSAujFWOCdO9osBiX9KGdobnGNdj5Y3FEbkOPy9+TzTQpWfTcSWXi3qwsWz05jb04NpqV+xAPDIotAGvDIKJ99kH7/ewlyADvI7axj4JJaHnQOU/UcNHX8gtFgPTxf4e+UGLoPz3TRqFkVM9UIgejFilUUbIcwoCl1sLo3tjdoomYzEYxHPVrtk/8YRRUnzcvThSgydDhO+0GLa8qMCYk+XYrPAQKBgQDaTg+AQqRVQHH2KxYwUmfZXj+RfgBbR1L/v0j5NuxKSdxytBZA6K4I4fX8D/o2PXpkKiGaqyLnf5/wQsmj3fxIzXKyZWcU3lgHE7L18NWl6wPqpz5zJwgKstFcZqJ4HXZgSZw9/iNktIS5K6PZUgsGy+QJ0e4SFqKUED/zRoVKUQKBgQCzLxMsA2rl1n9q93PGOLE9bS0uahtpTePKVLn+ceQ/acDdokCf0MtM3uWJd5ti8BWTMECg4JVXIBUrYeLHwVlZMKvijGZRDYGJUF8hfjWU2pTDI6b2+vSQSVWLkyOdznvzUxrhKDbj21lQNPrKqL/nDfWKH/5QfScfjHviEQ7AsQKBgFXQTaObjsG8XY/pDAXevtfhhpeIslcvSF8kMGlWv7fMJQ4p4H2PeaogOPPmy/K6Y/wv25nTIBtkPdjSSDVUM7HioO2jksvPQ0c05Spsi293XMjHCXN2qmCaPlZWOhOBcWEUTojH993EYE/x6ayp5Y+8Yl3B2hXeM/aEFL9qv0ahAoGADaa7fjHwdfxGjt61aletYTGtLIkW94ngneygkvsYWaBz+i6/X62nn36n3DZJl1sVObaGZftWRWIDWt/FSFS5uurTXZo2vVwbD1wZM1MLQAD7LnbL5Ksv8MI1i0G1h/NQTDR7qsXGkMuIXWz74m7C2BafK1vOo1E1ptisI4gLKLECgYBdCCxkf/jCXcsQEs+hmYWm4gvHahvPIDVI5s2qX/hrJsFx6LaorC1iSmwwJQ7zM/AFqwc/NlCGo2NE44MKFPqIp/08fM4Tx2i8BFQQF3G1Y8oAr/xusqJVSI3CHvw2yD6DDgwTOeQ2TD1v3lnOEB6g0JaamTQQ6NQ0iUNRsDXAPQ==");
+//        fsPayConfig.setHfRsaPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuziAvRIul3mwBlEDSMMvi3v83HEebLpEWoBhcqL/Vlg90tjT51lEO4OksGDU08ypESMaby+Rpvw9rRTFBbdm9oZiiKyKrYChoW9s/Tu5gDIt6k1+YP3204/lOz4Pat9hlRetIhDcgbAiChwDWS/+shfdi6vMX31fO5m5oyo1XlwL477pZYykwxalxgXjWHUkyDRvYGDFquLTELSEq+vpQthYwZ0ghamIkxQV7syjNp06bCMzLmnB9jVEilQuDGqRrlDJpLjKqZkkTwp5JJJRJPLIJag0iLZMJjfdHKmTojcd+y9KRUU+KW0OMUeC2T8SBKpz918ioBKJtuzmUD6YNwIDAQAB");
+//        //fsPayConfig.setHfRsaPrivateKey("MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCijLcYLMJEe16TS6BtEG9hUezZyYvp2qgpPVGWaaBbb6lud89ILMUC7jyTWufCo2fUQ0nJzYhVlNeMzmGFtg/zFwhkjJIkuCOW+/Koy1ow66Rom8/sNQLb82szHoeklbv17AnD7WJis7cGyy1+3E6jzfaPOB7PTzidK6KyfCWDByOt0JcGe3+6+9+loQFbFRXJ2RpWPQeN72n9FVtSKSvgkGtJNUzh/qBwMPN6ol6xcU/Z2o1sYrRfKC4tcMqccRi/DvvZFJPVlN+YqkJ6lhgAmJg7eZ2fhIgrmzqc96UKp2YUNm+1v8XHCflD9Wv94E6D2JgL4VbF4Zyf+fKYuR7pAgMBAAECggEAfy5UL6ENmuFgHSVF7y+1xdKA2+IbC60ed63XgTVB12jli15Im3MT7ngSg0TUIvERUv4W5MNgkX10rWHo4eKSViPGWE24JuzAQ+j7cuAwwCgPKh4HMAxGIWwyivuvK7JQL1kwRtEccpekc7dS8HhVO0rySBqj2JZmeGrk0HvcKciSWuMjhjT4dJUwSntD07REV6rVjrpQXuvmY40vH88uvHLdH1IcjmJs2yJRNawUNtd+8FvpOCjami7zpB+er+AQ6S2fvpljNqfE5Kadm3MvzBngDdMS3xRvMHfjCifVwFpLP0rLDP6cSn6PJWbkNYQVZi12w8+wb5f7AVlaKXnfdQKBgQDh7VC5+MOqfcUr9h/n2vhFFhQOaGAZCOBc65n8VBj9aRht8ViXFvRrIRmM+QvUbV9/7taFbtAnZXIzu+12T4vnlZv9DTsy6kKloV5923xZ4CpzIVG8crlwJz1wdALeO6M485RtRLjz6nlNKn2m2VJ1d5XFBDhIz5rWUzagPwwpwwKBgQC4L8Eyu6Yn/zQmv8l6rfAsEfUJzfYtojf1PerPYilARtgFuD20cppcOP5oAk2TTX3qaz0Y9atCfL2z2qxtrgKtw2etfhDBmT6l6+pg04SLuyTrVeZ5dxXHt+LRLJnvBbGgnvAM6rSRKdHXT0gfqiRIMw2qIUtndgRr4RK5hqcd4wKBgBYBFh620t/VFhIdC6h6VDnuV4+7rLhje+6w57OCwVhVFxMGMZmtm6qfc6yeSP+sk2OTcINYcp+TqtbNE+i1AKxSjvnLgxuHY2xcViat7OOYCKpj8WEIT3VT7RD5y5m3d0NBvhASZG0lRiE05T4N5pEYT5b7vTuiNLNxMV3UJiwfAoGBAIb2/1QEqwmN+RIX4TSTNnWkpvELSkRAJU8Akwpp/J5MC0mNqzGJ9NB1Nv7SCTRSSV04PaoHgvoSXBPpvgYUx4O6t0MrKG4ktAJzL+jJtcuKU9Bavqrs9znE5mCulRHQE0wGixJ7/dqNUWW7g7coPrPlLTMoeI+UrEK8x7LJF7ZPAoGALHvtu6zzWVeCdELIPUTersVQrH1R3yZuf6rgubg4XFw3meFcd4W8BvXm4EKGRZxdiyZvCtKlkV9u110Rx3RNSbZCOb3MClmkcow8vPIhmyGWIGymAIxr9JcD0p6HogzPvbjRsLh1nFg/+95OL2E353Bp4/oPIgYIfnYNUfD+0gA=");
+//        //fsPayConfig.setHfRsaPublicKey("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjbkiiy2ewzuPsM5uZbAFMJOBWCRRQ2RtH7Dbr9Evbow6IEyvGoen8XKpiuXzapeps3b2eogETHVFQtLooqRHpVRppFKtU1AHZXA7C6wPocfMldJbTykDCowyJwOSYEaFPBjr9cw6dQcBJMIEHj0YWjBPR1dPVzf+y4sUohbrkS/FANBpp24j+Mu0qEqh8TuVuKlvig7jbmXJiJkAmUJ+Tb3Caj20fFTen6juPd3zR/KM3twki06wZZbb4KyCiM/NwozEqJ9PkWSs6rG7aW+BEfzlo3m1a7MlL0vpKNR3f0lbywq09rFAwtA7R2lssWwLMma4LOqtMMqo3yZdv4vObQIDAQAB");
+//        fsPayConfig.setHfPayNotifyUrl("https://userapp.baohetangjinyue.cn//app/hfPay/payNotifyUrl");
+
         config=fsPayConfig;
         MerConfig merConfig = new MerConfig();
         merConfig.setProcutId(fsPayConfig.getHfProductId());

+ 99 - 0
fs-service/src/main/resources/mapper/course/FsCourseProductMapper.xml

@@ -0,0 +1,99 @@
+<?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.course.mapper.FsCourseProductMapper">
+    
+    <resultMap type="FsCourseProduct" id="FsCourseProductResult">
+        <result property="id"    column="id"    />
+        <result property="imgUrl"    column="img_url"    />
+        <result property="images"    column="images"    />
+        <result property="barCode"    column="bar_code"    />
+        <result property="sort"    column="sort"    />
+        <result property="stock"    column="stock"    />
+        <result property="productContent"    column="product_content"    />
+        <result property="productPrice"    column="product_price"    />
+        <result property="productName"    column="product_name"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+
+    <sql id="selectFsCourseProductVo">
+        select id, img_url, images, bar_code, sort, stock, product_content, product_price, product_name, create_time, update_time from fs_course_product
+    </sql>
+
+    <select id="selectFsCourseProductList" parameterType="FsCourseProduct" resultMap="FsCourseProductResult">
+        <include refid="selectFsCourseProductVo"/>
+        <where>  
+            <if test="imgUrl != null  and imgUrl != ''"> and img_url = #{imgUrl}</if>
+            <if test="images != null  and images != ''"> and images = #{images}</if>
+            <if test="barCode != null  and barCode != ''"> and bar_code = #{barCode}</if>
+            <if test="sort != null "> and sort = #{sort}</if>
+            <if test="stock != null "> and stock = #{stock}</if>
+            <if test="productContent != null  and productContent != ''"> and product_content = #{productContent}</if>
+            <if test="productPrice != null "> and product_price = #{productPrice}</if>
+            <if test="productName != null  and productName != ''"> and product_name like concat('%', #{productName}, '%')</if>
+        </where>
+    </select>
+    
+    <select id="selectFsCourseProductById" parameterType="Long" resultMap="FsCourseProductResult">
+        <include refid="selectFsCourseProductVo"/>
+        where id = #{id}
+    </select>
+        
+    <insert id="insertFsCourseProduct" parameterType="FsCourseProduct" useGeneratedKeys="true" keyProperty="id">
+        insert into fs_course_product
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="imgUrl != null">img_url,</if>
+            <if test="images != null">images,</if>
+            <if test="barCode != null">bar_code,</if>
+            <if test="sort != null">sort,</if>
+            <if test="stock != null">stock,</if>
+            <if test="productContent != null">product_content,</if>
+            <if test="productPrice != null">product_price,</if>
+            <if test="productName != null">product_name,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateTime != null">update_time,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="imgUrl != null">#{imgUrl},</if>
+            <if test="images != null">#{images},</if>
+            <if test="barCode != null">#{barCode},</if>
+            <if test="sort != null">#{sort},</if>
+            <if test="stock != null">#{stock},</if>
+            <if test="productContent != null">#{productContent},</if>
+            <if test="productPrice != null">#{productPrice},</if>
+            <if test="productName != null">#{productName},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsCourseProduct" parameterType="FsCourseProduct">
+        update fs_course_product
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="imgUrl != null">img_url = #{imgUrl},</if>
+            <if test="images != null">images = #{images},</if>
+            <if test="barCode != null">bar_code = #{barCode},</if>
+            <if test="sort != null">sort = #{sort},</if>
+            <if test="stock != null">stock = #{stock},</if>
+            <if test="productContent != null">product_content = #{productContent},</if>
+            <if test="productPrice != null">product_price = #{productPrice},</if>
+            <if test="productName != null">product_name = #{productName},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteFsCourseProductById" parameterType="Long">
+        delete from fs_course_product where id = #{id}
+    </delete>
+
+    <delete id="deleteFsCourseProductByIds" parameterType="String">
+        delete from fs_course_product where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>

+ 145 - 0
fs-service/src/main/resources/mapper/course/FsCourseProductOrderMapper.xml

@@ -0,0 +1,145 @@
+<?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.course.mapper.FsCourseProductOrderMapper">
+    
+    <resultMap type="FsCourseProductOrder" id="FsCourseProductOrderResult">
+        <result property="courseOrderId"    column="course_order_id"    />
+        <result property="orderCode"    column="order_code"    />
+        <result property="userId"    column="user_id"    />
+        <result property="userName"    column="user_name"    />
+        <result property="userPhone"    column="user_phone"    />
+        <result property="courseProductId"    column="course_product_id"    />
+        <result property="productJson"    column="product_json"    />
+        <result property="courseId"    column="course_id"    />
+        <result property="videoId"    column="video_id"    />
+        <result property="isPay"    column="is_pay"    />
+        <result property="payTime"    column="pay_time"    />
+        <result property="payType"    column="pay_type"    />
+        <result property="status"    column="status"    />
+        <result property="createTime"    column="create_time"    />
+        <result property="refundTime"    column="refund_time"    />
+        <result property="refundExplain"    column="refund_explain"    />
+        <result property="verifyCode"    column="verify_code"    />
+        <result property="updateTime"    column="update_time"    />
+        <result property="companyId"    column="company_id"    />
+        <result property="companyUserId"    column="company_user_id"    />
+        <result property="extId"    column="ext_id"    />
+    </resultMap>
+
+    <sql id="selectFsCourseProductOrderVo">
+        select course_order_id, order_code, user_id, user_name, user_phone, course_product_id, product_json, course_id, video_id, is_pay, pay_time, pay_type, status, create_time, refund_time, refund_explain, verify_code, update_time, company_id, company_user_id, ext_id from fs_course_product_order
+    </sql>
+
+    <select id="selectFsCourseProductOrderList"  resultType="com.fs.course.vo.FsCourseProductOrderVO">
+        SELECT cpo.*,ucv.title,uc.course_name,c.company_name,cu.user_name as company_user_name,qec.name as ext_name
+        FROM fs_course_product_order cpo
+        LEFT JOIN fs_user_course_video ucv ON ucv.video_id = cpo.video_id
+        LEFT JOIN fs_user_course uc ON uc.course_id = cpo.course_id
+        LEFT JOIN company c ON c.company_id = cpo.company_id
+        LEFT JOIN company_user cu ON cu.user_id = cpo.company_user_id
+        LEFT JOIN qw_external_contact qec ON qec.id = cpo.ext_id
+        <where>  
+            <if test="orderCode != null  and orderCode != ''"> and cpo.order_code = #{orderCode}</if>
+            <if test="userName != null  and userName != ''"> and cpo.user_name like concat('%', #{userName}, '%')</if>
+            <if test="userPhone != null  and userPhone != ''"> and cpo.user_phone = #{userPhone}</if>
+            <if test="isPay != null "> and cpo.is_pay = #{isPay}</if>
+            <if test="payStartTime != null and payEndTime != null"> and cpo.pay_time BETWEEN #{payStartTime} AND #{payEndTime}</if>
+            <if test="status != null "> and cpo.status = #{status}</if>
+            <if test="refundStartTime != null and refundEndTime != null"> and cpo.refund_time BETWEEN #{refundStartTime} AND #{refundEndTime}</if>
+        </where>
+        ORDER BY create_time DESC
+    </select>
+    
+    <select id="selectFsCourseProductOrderByCourseOrderId" parameterType="Long" resultMap="FsCourseProductOrderResult">
+        <include refid="selectFsCourseProductOrderVo"/>
+        where course_order_id = #{courseOrderId}
+    </select>
+        
+    <insert id="insertFsCourseProductOrder" parameterType="FsCourseProductOrder" useGeneratedKeys="true" keyProperty="courseOrderId">
+        insert into fs_course_product_order
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="orderCode != null">order_code,</if>
+            <if test="userId != null">user_id,</if>
+            <if test="userName != null">user_name,</if>
+            <if test="userPhone != null">user_phone,</if>
+            <if test="courseProductId != null">course_product_id,</if>
+            <if test="productJson != null">product_json,</if>
+            <if test="courseId != null">course_id,</if>
+            <if test="videoId != null">video_id,</if>
+            <if test="isPay != null">is_pay,</if>
+            <if test="payTime != null">pay_time,</if>
+            <if test="payType != null">pay_type,</if>
+            <if test="status != null">status,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="refundTime != null">refund_time,</if>
+            <if test="refundExplain != null">refund_explain,</if>
+            <if test="verifyCode != null">verify_code,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="companyId != null">company_id,</if>
+            <if test="companyUserId != null">company_user_id,</if>
+            <if test="extId != null">ext_id,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="orderCode != null">#{orderCode},</if>
+            <if test="userId != null">#{userId},</if>
+            <if test="userName != null">#{userName},</if>
+            <if test="userPhone != null">#{userPhone},</if>
+            <if test="courseProductId != null">#{courseProductId},</if>
+            <if test="productJson != null">#{productJson},</if>
+            <if test="courseId != null">#{courseId},</if>
+            <if test="videoId != null">#{videoId},</if>
+            <if test="isPay != null">#{isPay},</if>
+            <if test="payTime != null">#{payTime},</if>
+            <if test="payType != null">#{payType},</if>
+            <if test="status != null">#{status},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="refundTime != null">#{refundTime},</if>
+            <if test="refundExplain != null">#{refundExplain},</if>
+            <if test="verifyCode != null">#{verifyCode},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="companyId != null">#{companyId},</if>
+            <if test="companyUserId != null">#{companyUserId},</if>
+            <if test="extId != null">#{extId},</if>
+         </trim>
+    </insert>
+
+    <update id="updateFsCourseProductOrder" parameterType="FsCourseProductOrder">
+        update fs_course_product_order
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="orderCode != null">order_code = #{orderCode},</if>
+            <if test="userId != null">user_id = #{userId},</if>
+            <if test="userName != null">user_name = #{userName},</if>
+            <if test="userPhone != null">user_phone = #{userPhone},</if>
+            <if test="courseProductId != null">course_product_id = #{courseProductId},</if>
+            <if test="productJson != null">product_json = #{productJson},</if>
+            <if test="courseId != null">course_id = #{courseId},</if>
+            <if test="videoId != null">video_id = #{videoId},</if>
+            <if test="isPay != null">is_pay = #{isPay},</if>
+            <if test="payTime != null">pay_time = #{payTime},</if>
+            <if test="payType != null">pay_type = #{payType},</if>
+            <if test="status != null">status = #{status},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="refundTime != null">refund_time = #{refundTime},</if>
+            <if test="refundExplain != null">refund_explain = #{refundExplain},</if>
+            <if test="verifyCode != null">verify_code = #{verifyCode},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="companyId != null">company_id = #{companyId},</if>
+            <if test="companyUserId != null">company_user_id = #{companyUserId},</if>
+            <if test="extId != null">ext_id = #{extId},</if>
+        </trim>
+        where course_order_id = #{courseOrderId}
+    </update>
+
+    <delete id="deleteFsCourseProductOrderByCourseOrderId" parameterType="Long">
+        delete from fs_course_product_order where course_order_id = #{courseOrderId}
+    </delete>
+
+    <delete id="deleteFsCourseProductOrderByCourseOrderIds" parameterType="String">
+        delete from fs_course_product_order where course_order_id in 
+        <foreach item="courseOrderId" collection="array" open="(" separator="," close=")">
+            #{courseOrderId}
+        </foreach>
+    </delete>
+</mapper>

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

@@ -101,6 +101,10 @@
             <if test="lastJoinTime != null">last_join_time,</if>
             <if test="userId != null">user_id,</if>
             <if test="projectId != null">project_id,</if>
+            <if test="isProduct != null">is_product,</if>
+            <if test="productId != null">product_id,</if>
+            <if test="listingStartTime != null">listing_start_time,</if>
+            <if test="listingEndTime != null">listing_end_time,</if>
         </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="fileId != null">#{fileId},</if>
@@ -132,6 +136,10 @@
             <if test="viewStartTime != null">#{viewStartTime},</if>
             <if test="viewEndTime != null">#{viewEndTime},</if>
             <if test="lastJoinTime != null">#{lastJoinTime},</if>
+            <if test="isProduct != null">#{isProduct},</if>
+            <if test="productId != null">#{productId},</if>
+            <if test="listingStartTime != null">#{listingStartTime},</if>
+            <if test="listingEndTime != null">#{listingEndTime},</if>
             <if test="userId != null">#{userId},</if>
             <if test="projectId != null">#{projectId},</if>
         </trim>
@@ -215,6 +223,10 @@
             <if test="viewStartTime != null">view_start_time = #{viewStartTime},</if>
             <if test="viewEndTime != null">view_end_time = #{viewEndTime},</if>
             <if test="lastJoinTime != null">last_join_time = #{lastJoinTime},</if>
+            <if test="isProduct != null">is_product = #{isProduct},</if>
+            <if test="productId != null">product_id = #{productId},</if>
+            <if test="listingStartTime != null">listing_start_time = #{listingStartTime},</if>
+            <if test="listingEndTime != null">listing_end_time = #{listingEndTime},</if>
             <if test="userId != null">user_id = #{userId},</if>
             <if test="projectId != null">project_id = #{projectId},</if>
         </trim>

+ 30 - 0
fs-user-app/src/main/java/com/fs/app/controller/CourseProductController.java

@@ -0,0 +1,30 @@
+package com.fs.app.controller;
+
+import com.fs.common.core.domain.R;
+import com.fs.course.domain.FsCourseProduct;
+import com.fs.course.service.IFsCourseProductService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+@Api("拍商品订单接口")
+@RestController
+@RequestMapping(value="/app/courseProduct")
+public class CourseProductController extends AppBaseController{
+
+    @Autowired
+    private IFsCourseProductService courseProductService;
+
+
+
+    @ApiOperation("获取拍商品详情")
+    @GetMapping("/getCourseProductById")
+    public R getCourseProductById(@RequestParam("productId") Long productId) {
+        FsCourseProduct courseProduct = courseProductService.selectFsCourseProductById(productId);
+        return R.ok().put("data", courseProduct);
+    }
+}

+ 87 - 0
fs-user-app/src/main/java/com/fs/app/controller/CourseProductOrderController.java

@@ -0,0 +1,87 @@
+package com.fs.app.controller;
+
+import com.fs.app.annotation.Login;
+import com.fs.common.annotation.RepeatSubmit;
+import com.fs.common.core.domain.R;
+import com.fs.course.param.FsCourseProductOrderCreateParam;
+import com.fs.course.param.FsCourseProductOrderListUParam;
+import com.fs.course.service.IFsCourseProductOrderService;
+import com.fs.course.vo.FsCourseProductOrderListUVO;
+import com.fs.his.param.ApplyCourseProductOrderRefundParam;
+import com.fs.his.param.FsCourseProductOrderComputeParam;
+import com.fs.his.param.FsCourseProductOrderDoPayParam;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+@Api("拍商品订单接口")
+@RestController
+@RequestMapping(value="/app/courseProductOrder")
+public class CourseProductOrderController extends AppBaseController {
+
+    @Autowired
+    private IFsCourseProductOrderService courseProductOrderService;
+
+    @Login
+    @ApiOperation("订单列表")
+    @GetMapping("/getCourseProductOrderList")
+    public R getCourseOrderList(FsCourseProductOrderListUParam param)
+    {
+        PageHelper.startPage(param.getPageNum(), param.getPageSize());
+        param.setUserId(Long.parseLong(getUserId()));
+        List<FsCourseProductOrderListUVO> productOrderListUVOS = courseProductOrderService.selectFsCourseProductOrderListUVO(param);
+        PageInfo<FsCourseProductOrderListUVO> pageInfo = new PageInfo<>(productOrderListUVOS);
+        return R.ok().put("data",pageInfo);
+    }
+
+    @ApiOperation("获取拍商品订单详情")
+    @GetMapping("/getCourseProductByCourseOrderId")
+    public R getCourseProductByCourseOrderId(@RequestParam("courseOrderId") Long courseOrderId) {
+        FsCourseProductOrderListUVO productOrderListUVO = courseProductOrderService.selectCourseProductByCourseOrderId(courseOrderId);
+        return R.ok().put("data", productOrderListUVO);
+    }
+
+    @Login
+    @ApiOperation("创建订单")
+    @PostMapping("/createOrder")
+    public R createOrder(@Validated @RequestBody FsCourseProductOrderCreateParam param, HttpServletRequest request){
+        param.setUserId(Long.parseLong(getUserId()));
+        //param.setCompanyUserId(getCompanyUserId());
+        return courseProductOrderService.createOrder(param);
+    }
+
+    @Login
+    @ApiOperation("计算订单")
+    @PostMapping("/compute")
+    public R payment(HttpServletRequest request, @Validated @RequestBody FsCourseProductOrderComputeParam param)
+    {
+        param.setUserId(Long.parseLong(getUserId()));
+        return courseProductOrderService.computeOrder(param);
+    }
+
+    @Login
+    @RepeatSubmit
+    @ApiOperation("支付")
+    @PostMapping("/payment")
+    public R payment(HttpServletRequest request, @Validated @RequestBody FsCourseProductOrderDoPayParam param)
+    {
+        param.setUserId(Long.parseLong(getUserId()));
+        return courseProductOrderService.payment(param);
+    }
+
+    @Login
+    @RepeatSubmit
+    @ApiOperation("申请退款")
+    @PostMapping("/applyRefund")
+    public R applyRefund(HttpServletRequest request, @Validated @RequestBody ApplyCourseProductOrderRefundParam param)
+    {
+        return courseProductOrderService.applyRefund(param);
+    }
+}

+ 6 - 0
fs-user-app/src/main/java/com/fs/app/controller/HuifuPayController.java

@@ -1,6 +1,7 @@
 package com.fs.app.controller;
 
 import com.alibaba.fastjson.JSON;
+import com.fs.course.service.IFsCourseProductOrderService;
 import com.fs.course.service.IFsUserCourseOrderService;
 import com.fs.course.service.IFsUserVipOrderService;
 import com.fs.his.service.IFsInquiryOrderService;
@@ -31,6 +32,8 @@ public class HuifuPayController {
     private IFsUserVipOrderService vipOrderService;
     @Autowired
     private IFsIntegralOrderService integralOrderService;
+    @Autowired
+    private IFsCourseProductOrderService courseProductOrderService;
 
     org.slf4j.Logger logger= LoggerFactory.getLogger(getClass());
     @RequestMapping("/payNotifyUrl")
@@ -58,6 +61,9 @@ public class HuifuPayController {
                 case "integral":
                     integralOrderService.payConfirm("",orderId[1],huiFuResult.getHf_seq_id(),"",1);
                     break;
+                case "product":
+                    courseProductOrderService.payConfirm("",orderId[1],huiFuResult.getHf_seq_id(),"",1);
+                    break;
             }
         }
 

+ 6 - 0
fs-user-app/src/main/java/com/fs/app/controller/WxPayController.java

@@ -4,6 +4,7 @@ package com.fs.app.controller;
 import cn.hutool.json.JSONUtil;
 import com.fs.course.config.RedPacketConfig;
 import com.fs.course.domain.FsCourseRedPacketLog;
+import com.fs.course.service.IFsCourseProductOrderService;
 import com.fs.course.service.IFsCourseRedPacketLogService;
 import com.fs.his.param.WxSendRedPacketParam;
 import com.fs.common.core.controller.BaseController;
@@ -72,6 +73,9 @@ public class WxPayController {
     @Autowired
     private IFsIntegralOrderService integralOrderService;
 
+    @Autowired
+    private IFsCourseProductOrderService courseProductOrderService;
+
 
     /**
      * 微信回调
@@ -109,6 +113,8 @@ public class WxPayController {
                     case "integral":
                         integralOrderService.payConfirm("",orderId[1],tradeNo,"",1);
                         break;
+                    case "product":
+                        courseProductOrderService.payConfirm("",orderId[1],tradeNo,"",1);
                 }
                 return WxPayNotifyResponse.success("处理成功!");
             }else{