feat(glt): 添加送水订单模块并优化经销商结算功能
- 新增送水订单实体类 GltTicketOrder 及其相关控制器、服务、映射器 - 添加送水订单参数类 GltTicketOrderParam 和 XML 映射配置 - 实现送水订单的增删改查、分页查询等完整 CRUD 功能 - 在经销商结算任务中引入分销设置功能,支持按级别控制分佣 - 更新总经销商分润计算逻辑,使用动态费率替代固定值 - 删除不再使用的中文字体修复脚本文件 - 重构经销商推荐佣金结算逻辑,支持最多三级分佣 - 优化订单状态检查逻辑,在退款流程中排除已完成订单
This commit is contained in:
119
src/main/java/com/gxwebsoft/common/core/web/ImportParams.java
Normal file
119
src/main/java/com/gxwebsoft/common/core/web/ImportParams.java
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* Copyright 2013-2015 JueYue (qrb.jueyue@gmail.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.gxwebsoft.common.core.web;
|
||||
|
||||
import cn.afterturn.easypoi.excel.entity.ExcelBaseParams;
|
||||
import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 导入参数设置
|
||||
*
|
||||
* @author JueYue
|
||||
* 2013-9-24
|
||||
* @version 1.0
|
||||
*/
|
||||
@Data
|
||||
public class ImportParams extends ExcelBaseParams {
|
||||
|
||||
public static final String SAVE_URL = "/excel/upload/excelUpload";
|
||||
|
||||
/**
|
||||
* 表格标题行数,默认0
|
||||
*/
|
||||
private int titleRows = 0;
|
||||
/**
|
||||
* 表头行数,默认1
|
||||
*/
|
||||
private int headRows = 1;
|
||||
/**
|
||||
* 字段真正值和列标题之间的距离 默认0
|
||||
*/
|
||||
private int startRows = 0;
|
||||
|
||||
/**
|
||||
* 主键设置,如何这个cell没有值,就跳过 或者认为这个是list的下面的值
|
||||
* 大家不理解,去掉这个
|
||||
*/
|
||||
|
||||
private Integer keyIndex = null;
|
||||
/**
|
||||
* 开始读取的sheet位置,默认为0
|
||||
*/
|
||||
private int startSheetIndex = 0;
|
||||
/**
|
||||
* 上传表格需要读取的sheet 数量,默认为1
|
||||
*/
|
||||
private int sheetNum = 1;
|
||||
/**
|
||||
* 是否需要保存上传的Excel,默认为false
|
||||
*/
|
||||
private boolean needSave = false;
|
||||
/**
|
||||
* 校验组
|
||||
*/
|
||||
private Class[] verifyGroup = null;
|
||||
/**
|
||||
* 是否需要校验上传的Excel,默认为false
|
||||
*/
|
||||
private boolean needVerify = false;
|
||||
/**
|
||||
* 返回文件是否分割,默认是分割
|
||||
*/
|
||||
private boolean verifyFileSplit = true;
|
||||
/**
|
||||
* 校验处理接口
|
||||
*/
|
||||
private IExcelVerifyHandler verifyHandler;
|
||||
/**
|
||||
* 保存上传的Excel目录,默认是 如 TestEntity这个类保存路径就是
|
||||
* upload/excelUpload/Test/yyyyMMddHHmss_***** 保存名称上传时间_五位随机数
|
||||
*/
|
||||
private String saveUrl = SAVE_URL;
|
||||
/**
|
||||
* 最后的无效行数
|
||||
*/
|
||||
private int lastOfInvalidRow = 0;
|
||||
/**
|
||||
* 手动控制读取的行数
|
||||
*/
|
||||
private int readRows = 0;
|
||||
/**
|
||||
* 导入时校验数据模板,是不是正确的Excel
|
||||
*/
|
||||
private String[] importFields;
|
||||
/**
|
||||
* 导入时校验excel的标题列顺序。依赖于importFields的配置顺序
|
||||
*/
|
||||
private boolean needCheckOrder = false;
|
||||
/**
|
||||
* Key-Value 读取标记,以这个为Key,后面一个Cell 为Value,多个改为ArrayList
|
||||
*/
|
||||
private String keyMark = ":";
|
||||
/**
|
||||
* 按照Key-Value 规则读取全局扫描Excel,但是跳过List读取范围提升性能
|
||||
* 仅仅支持titleRows + headRows + startRows 以及 lastOfInvalidRow
|
||||
*/
|
||||
private boolean readSingleCell = false;
|
||||
/**
|
||||
* 是否并行计算
|
||||
*/
|
||||
private boolean concurrentTask = false;
|
||||
/**
|
||||
* 最小截取大小
|
||||
*/
|
||||
private Integer critical = 1000;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package com.gxwebsoft.glt.controller;
|
||||
|
||||
import com.gxwebsoft.common.core.annotation.OperationLog;
|
||||
import com.gxwebsoft.common.core.web.ApiResult;
|
||||
import com.gxwebsoft.common.core.web.BaseController;
|
||||
import com.gxwebsoft.common.core.web.BatchParam;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.glt.entity.GltTicketOrder;
|
||||
import com.gxwebsoft.glt.param.GltTicketOrderParam;
|
||||
import com.gxwebsoft.glt.service.GltTicketOrderService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 送水订单控制器
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-02-05 18:50:21
|
||||
*/
|
||||
@Tag(name = "送水订单管理")
|
||||
@RestController
|
||||
@RequestMapping("/api/glt/glt-ticket-order")
|
||||
public class GltTicketOrderController extends BaseController {
|
||||
@Resource
|
||||
private GltTicketOrderService gltTicketOrderService;
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:list')")
|
||||
@Operation(summary = "分页查询送水订单")
|
||||
@GetMapping("/page")
|
||||
public ApiResult<PageResult<GltTicketOrder>> page(GltTicketOrderParam param) {
|
||||
// 使用关联查询
|
||||
return success(gltTicketOrderService.pageRel(param));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:list')")
|
||||
@Operation(summary = "查询全部送水订单")
|
||||
@GetMapping()
|
||||
public ApiResult<List<GltTicketOrder>> list(GltTicketOrderParam param) {
|
||||
// 使用关联查询
|
||||
return success(gltTicketOrderService.listRel(param));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:list')")
|
||||
@Operation(summary = "根据id查询送水订单")
|
||||
@GetMapping("/{id}")
|
||||
public ApiResult<GltTicketOrder> get(@PathVariable("id") Integer id) {
|
||||
// 使用关联查询
|
||||
return success(gltTicketOrderService.getByIdRel(id));
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:save')")
|
||||
@OperationLog
|
||||
@Operation(summary = "添加送水订单")
|
||||
@PostMapping()
|
||||
public ApiResult<?> save(@RequestBody GltTicketOrder gltTicketOrder) {
|
||||
// 记录当前登录用户id
|
||||
// User loginUser = getLoginUser();
|
||||
// if (loginUser != null) {
|
||||
// gltTicketOrder.setUserId(loginUser.getUserId());
|
||||
// }
|
||||
if (gltTicketOrderService.save(gltTicketOrder)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
return fail("添加失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:update')")
|
||||
@OperationLog
|
||||
@Operation(summary = "修改送水订单")
|
||||
@PutMapping()
|
||||
public ApiResult<?> update(@RequestBody GltTicketOrder gltTicketOrder) {
|
||||
if (gltTicketOrderService.updateById(gltTicketOrder)) {
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:remove')")
|
||||
@OperationLog
|
||||
@Operation(summary = "删除送水订单")
|
||||
@DeleteMapping("/{id}")
|
||||
public ApiResult<?> remove(@PathVariable("id") Integer id) {
|
||||
if (gltTicketOrderService.removeById(id)) {
|
||||
return success("删除成功");
|
||||
}
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:save')")
|
||||
@OperationLog
|
||||
@Operation(summary = "批量添加送水订单")
|
||||
@PostMapping("/batch")
|
||||
public ApiResult<?> saveBatch(@RequestBody List<GltTicketOrder> list) {
|
||||
if (gltTicketOrderService.saveBatch(list)) {
|
||||
return success("添加成功");
|
||||
}
|
||||
return fail("添加失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:update')")
|
||||
@OperationLog
|
||||
@Operation(summary = "批量修改送水订单")
|
||||
@PutMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody BatchParam<GltTicketOrder> batchParam) {
|
||||
if (batchParam.update(gltTicketOrderService, "id")) {
|
||||
return success("修改成功");
|
||||
}
|
||||
return fail("修改失败");
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAuthority('glt:gltTicketOrder:remove')")
|
||||
@OperationLog
|
||||
@Operation(summary = "批量删除送水订单")
|
||||
@DeleteMapping("/batch")
|
||||
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
|
||||
if (gltTicketOrderService.removeByIds(ids)) {
|
||||
return success("删除成功");
|
||||
}
|
||||
return fail("删除失败");
|
||||
}
|
||||
|
||||
}
|
||||
84
src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java
Normal file
84
src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package com.gxwebsoft.glt.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 送水订单
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-02-05 18:50:20
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Schema(name = "GltTicketOrder对象", description = "送水订单")
|
||||
public class GltTicketOrder implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
@Schema(description = "用户水票ID")
|
||||
private Integer userTicketId;
|
||||
|
||||
@Schema(description = "门店ID")
|
||||
private Integer storeId;
|
||||
|
||||
@Schema(description = "配送员")
|
||||
private Integer riderId;
|
||||
|
||||
@Schema(description = "仓库ID")
|
||||
private Integer warehouseId;
|
||||
|
||||
@Schema(description = "关联收货地址")
|
||||
private Integer addressId;
|
||||
|
||||
@Schema(description = "收货地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "买家留言")
|
||||
private String buyerRemarks;
|
||||
|
||||
@Schema(description = "用于统计")
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "购买数量")
|
||||
private Integer totalNum;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Integer userId;
|
||||
|
||||
@Schema(description = "排序(数字越小越靠前)")
|
||||
private Integer sortNumber;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String comments;
|
||||
|
||||
@Schema(description = "状态, 0正常, 1冻结")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否删除, 0否, 1是")
|
||||
@TableLogic
|
||||
private Integer deleted;
|
||||
|
||||
@Schema(description = "租户id")
|
||||
private Integer tenantId;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "修改时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.gxwebsoft.glt.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.gxwebsoft.glt.entity.GltTicketOrder;
|
||||
import com.gxwebsoft.glt.param.GltTicketOrderParam;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 送水订单Mapper
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-02-05 18:50:20
|
||||
*/
|
||||
public interface GltTicketOrderMapper extends BaseMapper<GltTicketOrder> {
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param param 查询参数
|
||||
* @return List<GltTicketOrder>
|
||||
*/
|
||||
List<GltTicketOrder> selectPageRel(@Param("page") IPage<GltTicketOrder> page,
|
||||
@Param("param") GltTicketOrderParam param);
|
||||
|
||||
/**
|
||||
* 查询全部
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return List<User>
|
||||
*/
|
||||
List<GltTicketOrder> selectListRel(@Param("param") GltTicketOrderParam param);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.gxwebsoft.glt.mapper.GltTicketOrderMapper">
|
||||
|
||||
<!-- 关联查询sql -->
|
||||
<sql id="selectSql">
|
||||
SELECT a.*
|
||||
FROM glt_ticket_order a
|
||||
<where>
|
||||
<if test="param.id != null">
|
||||
AND a.id = #{param.id}
|
||||
</if>
|
||||
<if test="param.userTicketId != null">
|
||||
AND a.user_ticket_id = #{param.userTicketId}
|
||||
</if>
|
||||
<if test="param.storeId != null">
|
||||
AND a.store_id = #{param.storeId}
|
||||
</if>
|
||||
<if test="param.riderId != null">
|
||||
AND a.rider_id = #{param.riderId}
|
||||
</if>
|
||||
<if test="param.warehouseId != null">
|
||||
AND a.warehouse_id = #{param.warehouseId}
|
||||
</if>
|
||||
<if test="param.addressId != null">
|
||||
AND a.address_id = #{param.addressId}
|
||||
</if>
|
||||
<if test="param.address != null">
|
||||
AND a.address LIKE CONCAT('%', #{param.address}, '%')
|
||||
</if>
|
||||
<if test="param.buyerRemarks != null">
|
||||
AND a.buyer_remarks LIKE CONCAT('%', #{param.buyerRemarks}, '%')
|
||||
</if>
|
||||
<if test="param.price != null">
|
||||
AND a.price = #{param.price}
|
||||
</if>
|
||||
<if test="param.totalNum != null">
|
||||
AND a.total_num = #{param.totalNum}
|
||||
</if>
|
||||
<if test="param.userId != null">
|
||||
AND a.user_id = #{param.userId}
|
||||
</if>
|
||||
<if test="param.sortNumber != null">
|
||||
AND a.sort_number = #{param.sortNumber}
|
||||
</if>
|
||||
<if test="param.comments != null">
|
||||
AND a.comments LIKE CONCAT('%', #{param.comments}, '%')
|
||||
</if>
|
||||
<if test="param.status != null">
|
||||
AND a.status = #{param.status}
|
||||
</if>
|
||||
<if test="param.deleted != null">
|
||||
AND a.deleted = #{param.deleted}
|
||||
</if>
|
||||
<if test="param.deleted == null">
|
||||
AND a.deleted = 0
|
||||
</if>
|
||||
<if test="param.createTimeStart != null">
|
||||
AND a.create_time >= #{param.createTimeStart}
|
||||
</if>
|
||||
<if test="param.createTimeEnd != null">
|
||||
AND a.create_time <= #{param.createTimeEnd}
|
||||
</if>
|
||||
<if test="param.keywords != null">
|
||||
AND (a.comments LIKE CONCAT('%', #{param.keywords}, '%')
|
||||
)
|
||||
</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 分页查询 -->
|
||||
<select id="selectPageRel" resultType="com.gxwebsoft.glt.entity.GltTicketOrder">
|
||||
<include refid="selectSql"></include>
|
||||
</select>
|
||||
|
||||
<!-- 查询全部 -->
|
||||
<select id="selectListRel" resultType="com.gxwebsoft.glt.entity.GltTicketOrder">
|
||||
<include refid="selectSql"></include>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -0,0 +1,82 @@
|
||||
package com.gxwebsoft.glt.param;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import com.gxwebsoft.common.core.annotation.QueryField;
|
||||
import com.gxwebsoft.common.core.annotation.QueryType;
|
||||
import com.gxwebsoft.common.core.web.BaseParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 送水订单查询参数
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-02-05 18:50:19
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||
@Schema(name = "GltTicketOrderParam对象", description = "送水订单查询参数")
|
||||
public class GltTicketOrderParam extends BaseParam {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer id;
|
||||
|
||||
@Schema(description = "用户水票ID")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer userTicketId;
|
||||
|
||||
@Schema(description = "门店ID")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer storeId;
|
||||
|
||||
@Schema(description = "配送员")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer riderId;
|
||||
|
||||
@Schema(description = "仓库ID")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer warehouseId;
|
||||
|
||||
@Schema(description = "关联收货地址")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer addressId;
|
||||
|
||||
@Schema(description = "收货地址")
|
||||
private String address;
|
||||
|
||||
@Schema(description = "买家留言")
|
||||
private String buyerRemarks;
|
||||
|
||||
@Schema(description = "用于统计")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private BigDecimal price;
|
||||
|
||||
@Schema(description = "购买数量")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer totalNum;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer userId;
|
||||
|
||||
@Schema(description = "排序(数字越小越靠前)")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer sortNumber;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String comments;
|
||||
|
||||
@Schema(description = "状态, 0正常, 1冻结")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "是否删除, 0否, 1是")
|
||||
@QueryField(type = QueryType.EQ)
|
||||
private Integer deleted;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.gxwebsoft.glt.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.glt.entity.GltTicketOrder;
|
||||
import com.gxwebsoft.glt.param.GltTicketOrderParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 送水订单Service
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-02-05 18:50:20
|
||||
*/
|
||||
public interface GltTicketOrderService extends IService<GltTicketOrder> {
|
||||
|
||||
/**
|
||||
* 分页关联查询
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return PageResult<GltTicketOrder>
|
||||
*/
|
||||
PageResult<GltTicketOrder> pageRel(GltTicketOrderParam param);
|
||||
|
||||
/**
|
||||
* 关联查询全部
|
||||
*
|
||||
* @param param 查询参数
|
||||
* @return List<GltTicketOrder>
|
||||
*/
|
||||
List<GltTicketOrder> listRel(GltTicketOrderParam param);
|
||||
|
||||
/**
|
||||
* 根据id查询
|
||||
*
|
||||
* @param id
|
||||
* @return GltTicketOrder
|
||||
*/
|
||||
GltTicketOrder getByIdRel(Integer id);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.gxwebsoft.glt.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.gxwebsoft.common.core.web.PageParam;
|
||||
import com.gxwebsoft.common.core.web.PageResult;
|
||||
import com.gxwebsoft.glt.entity.GltTicketOrder;
|
||||
import com.gxwebsoft.glt.mapper.GltTicketOrderMapper;
|
||||
import com.gxwebsoft.glt.param.GltTicketOrderParam;
|
||||
import com.gxwebsoft.glt.service.GltTicketOrderService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 送水订单Service实现
|
||||
*
|
||||
* @author 科技小王子
|
||||
* @since 2026-02-05 18:50:20
|
||||
*/
|
||||
@Service
|
||||
public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper, GltTicketOrder> implements GltTicketOrderService {
|
||||
|
||||
@Override
|
||||
public PageResult<GltTicketOrder> pageRel(GltTicketOrderParam param) {
|
||||
PageParam<GltTicketOrder, GltTicketOrderParam> page = new PageParam<>(param);
|
||||
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||
List<GltTicketOrder> list = baseMapper.selectPageRel(page, param);
|
||||
return new PageResult<>(list, page.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GltTicketOrder> listRel(GltTicketOrderParam param) {
|
||||
List<GltTicketOrder> list = baseMapper.selectListRel(param);
|
||||
// 排序
|
||||
PageParam<GltTicketOrder, GltTicketOrderParam> page = new PageParam<>();
|
||||
page.setDefaultOrder("sort_number asc, create_time desc");
|
||||
return page.sortRecords(list);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GltTicketOrder getByIdRel(Integer id) {
|
||||
GltTicketOrderParam param = new GltTicketOrderParam();
|
||||
param.setId(id);
|
||||
return param.getOne(baseMapper.selectListRel(param));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import com.gxwebsoft.common.core.annotation.IgnoreTenant;
|
||||
import com.gxwebsoft.shop.entity.ShopDealerCapital;
|
||||
import com.gxwebsoft.shop.entity.ShopDealerOrder;
|
||||
import com.gxwebsoft.shop.entity.ShopDealerReferee;
|
||||
import com.gxwebsoft.shop.entity.ShopDealerSetting;
|
||||
import com.gxwebsoft.shop.entity.ShopDealerUser;
|
||||
import com.gxwebsoft.shop.entity.ShopGoods;
|
||||
import com.gxwebsoft.shop.entity.ShopOrder;
|
||||
@@ -15,11 +16,13 @@ import com.gxwebsoft.common.system.mapper.UserMapper;
|
||||
import com.gxwebsoft.shop.service.ShopDealerCapitalService;
|
||||
import com.gxwebsoft.shop.service.ShopDealerOrderService;
|
||||
import com.gxwebsoft.shop.service.ShopDealerRefereeService;
|
||||
import com.gxwebsoft.shop.service.ShopDealerSettingService;
|
||||
import com.gxwebsoft.shop.service.ShopDealerUserService;
|
||||
import com.gxwebsoft.shop.service.ShopGoodsService;
|
||||
import com.gxwebsoft.shop.service.ShopOrderService;
|
||||
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
|
||||
import com.gxwebsoft.shop.util.UpstreamUserFinder;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -72,6 +75,9 @@ public class DealerOrderSettlement10584Task {
|
||||
@Resource
|
||||
private ShopDealerOrderService shopDealerOrderService;
|
||||
|
||||
@Resource
|
||||
private ShopDealerSettingService shopDealerSettingService;
|
||||
|
||||
@Resource
|
||||
private ShopGoodsService shopGoodsService;
|
||||
|
||||
@@ -96,10 +102,12 @@ public class DealerOrderSettlement10584Task {
|
||||
// Per-run caches to reduce DB chatter across orders.
|
||||
Map<Integer, Integer> level1ParentCache = new HashMap<>();
|
||||
Map<Integer, Boolean> shopRoleCache = new HashMap<>();
|
||||
Integer totalDealerUserId = findTotalDealerUserId();
|
||||
if (totalDealerUserId == null) {
|
||||
DealerBasicSetting dealerBasicSetting = findDealerBasicSetting();
|
||||
ShopDealerUser totalDealerUser = findTotalDealerUser();
|
||||
if (totalDealerUser == null || totalDealerUser.getUserId() == null) {
|
||||
log.warn("未找到总经销商账号,订单仍可结算但不会发放总经销商分润 - tenantId={}", TENANT_ID);
|
||||
}
|
||||
log.debug("租户{}分销设置 - level={}", TENANT_ID, dealerBasicSetting.level);
|
||||
|
||||
log.info("租户{}待结算订单数: {}, orderNos(sample)={}",
|
||||
TENANT_ID,
|
||||
@@ -113,7 +121,7 @@ public class DealerOrderSettlement10584Task {
|
||||
if (!claimOrderToSettle(order.getOrderId())) {
|
||||
return;
|
||||
}
|
||||
settleOneOrder(order, level1ParentCache, shopRoleCache, totalDealerUserId);
|
||||
settleOneOrder(order, level1ParentCache, shopRoleCache, totalDealerUser, dealerBasicSetting.level);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("订单结算失败,将回滚本订单并在下次任务重试 - orderId={}, orderNo={}", order.getOrderId(), order.getOrderNo(), e);
|
||||
@@ -150,7 +158,8 @@ public class DealerOrderSettlement10584Task {
|
||||
ShopOrder order,
|
||||
Map<Integer, Integer> level1ParentCache,
|
||||
Map<Integer, Boolean> shopRoleCache,
|
||||
Integer totalDealerUserId
|
||||
ShopDealerUser totalDealerUser,
|
||||
int dealerLevel
|
||||
) {
|
||||
if (order.getUserId() == null || order.getOrderNo() == null) {
|
||||
throw new IllegalStateException("订单关键信息缺失,无法结算 - orderId=" + order.getOrderId());
|
||||
@@ -188,13 +197,13 @@ public class DealerOrderSettlement10584Task {
|
||||
commissionConfig.storeSimpleValue);
|
||||
|
||||
// 1) 直推/间推(shop_dealer_referee)
|
||||
DealerRefereeCommission dealerRefereeCommission = settleDealerRefereeCommission(order, baseAmount, goodsQty, commissionConfig);
|
||||
DealerRefereeCommission dealerRefereeCommission = settleDealerRefereeCommission(order, baseAmount, goodsQty, commissionConfig, dealerLevel);
|
||||
|
||||
// 2) 门店分红上级:从下单用户开始逐级向上找,命中 ShopDealerUser.type=1 的最近两级(直推门店/间推门店)。
|
||||
ShopRoleCommission shopRoleCommission = settleShopRoleRefereeCommission(order, baseAmount, goodsQty, commissionConfig, level1ParentCache, shopRoleCache);
|
||||
|
||||
// 3) 总经销商分润:固定比率,每个订单都分。
|
||||
TotalDealerCommission totalDealerCommission = settleTotalDealerCommission(order, baseAmount, goodsQty, totalDealerUserId);
|
||||
TotalDealerCommission totalDealerCommission = settleTotalDealerCommission(order, baseAmount, goodsQty, totalDealerUser);
|
||||
|
||||
// 4) 写入分销订单记录(用于排查/统计;详细分佣以 ShopDealerCapital 为准)
|
||||
createDealerOrderRecord(order, baseAmount, dealerRefereeCommission, shopRoleCommission, totalDealerCommission);
|
||||
@@ -202,18 +211,38 @@ public class DealerOrderSettlement10584Task {
|
||||
log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), baseAmount);
|
||||
}
|
||||
|
||||
private DealerRefereeCommission settleDealerRefereeCommission(ShopOrder order, BigDecimal baseAmount, int goodsQty, CommissionConfig commissionConfig) {
|
||||
private DealerRefereeCommission settleDealerRefereeCommission(
|
||||
ShopOrder order,
|
||||
BigDecimal baseAmount,
|
||||
int goodsQty,
|
||||
CommissionConfig commissionConfig,
|
||||
int dealerLevel
|
||||
) {
|
||||
// 兼容两种数据形态:
|
||||
// 1) 同一 userId 下有 level=1/2 的多级关系(直接按 level 取);
|
||||
// 1) 同一 userId 下有 level=1/2/3 的多级关系(直接按 level 取);
|
||||
// 2) 仅维护 level=1(用“查两次”回退获取上级)。
|
||||
Integer directDealerId = getDealerRefereeId(order.getUserId(), 1);
|
||||
Integer simpleDealerId = getDealerRefereeId(order.getUserId(), 2);
|
||||
if (simpleDealerId == null && directDealerId != null) {
|
||||
simpleDealerId = getDealerRefereeId(directDealerId, 1);
|
||||
//
|
||||
// 严格按“分销设置 level”决定发放到第几级,避免 level=2 时仍触发第3级发放逻辑。
|
||||
int normalizedLevel = normalizeDealerLevel(dealerLevel);
|
||||
|
||||
Integer directDealerId = null;
|
||||
Integer simpleDealerId = null;
|
||||
Integer thirdDealerId = null;
|
||||
|
||||
if (normalizedLevel >= 1) {
|
||||
directDealerId = getDealerRefereeId(order.getUserId(), 1);
|
||||
}
|
||||
Integer thirdDealerId = getDealerRefereeId(order.getUserId(), 3);
|
||||
if (thirdDealerId == null && simpleDealerId != null) {
|
||||
thirdDealerId = getDealerRefereeId(simpleDealerId, 1);
|
||||
if (normalizedLevel >= 2) {
|
||||
simpleDealerId = getDealerRefereeId(order.getUserId(), 2);
|
||||
if (simpleDealerId == null && directDealerId != null) {
|
||||
simpleDealerId = getDealerRefereeId(directDealerId, 1);
|
||||
}
|
||||
}
|
||||
if (normalizedLevel >= 3) {
|
||||
thirdDealerId = getDealerRefereeId(order.getUserId(), 3);
|
||||
if (thirdDealerId == null && simpleDealerId != null) {
|
||||
thirdDealerId = getDealerRefereeId(simpleDealerId, 1);
|
||||
}
|
||||
}
|
||||
|
||||
BigDecimal directMoney =
|
||||
@@ -228,27 +257,33 @@ public class DealerOrderSettlement10584Task {
|
||||
order.getOrderNo(), order.getUserId(), directDealerId, directMoney, simpleDealerId, simpleMoney, thirdDealerId, thirdMoney);
|
||||
|
||||
// 直推:对方=买家;推荐奖(5%):对方=直推分销商(便于在资金明细中看出“来自哪个下级分销商/团队订单”)
|
||||
creditDealerCommission(
|
||||
directDealerId,
|
||||
directMoney,
|
||||
order,
|
||||
order.getUserId(),
|
||||
buildCommissionComment("直推佣金", commissionConfig.commissionType, commissionConfig.dealerDirectValue, goodsQty)
|
||||
);
|
||||
creditDealerCommission(
|
||||
simpleDealerId,
|
||||
simpleMoney,
|
||||
order,
|
||||
directDealerId,
|
||||
buildCommissionComment("推荐奖", commissionConfig.commissionType, commissionConfig.dealerSimpleValue, goodsQty)
|
||||
);
|
||||
creditDealerCommission(
|
||||
thirdDealerId,
|
||||
thirdMoney,
|
||||
order,
|
||||
simpleDealerId,
|
||||
buildCommissionComment("分润收入", commissionConfig.commissionType, commissionConfig.dealerThirdValue, goodsQty)
|
||||
);
|
||||
if (normalizedLevel >= 1) {
|
||||
creditDealerCommission(
|
||||
directDealerId,
|
||||
directMoney,
|
||||
order,
|
||||
order.getUserId(),
|
||||
buildCommissionComment("直推佣金", commissionConfig.commissionType, commissionConfig.dealerDirectValue, goodsQty)
|
||||
);
|
||||
}
|
||||
if (normalizedLevel >= 2) {
|
||||
creditDealerCommission(
|
||||
simpleDealerId,
|
||||
simpleMoney,
|
||||
order,
|
||||
directDealerId,
|
||||
buildCommissionComment("推荐奖", commissionConfig.commissionType, commissionConfig.dealerSimpleValue, goodsQty)
|
||||
);
|
||||
}
|
||||
if (normalizedLevel >= 3) {
|
||||
creditDealerCommission(
|
||||
thirdDealerId,
|
||||
thirdMoney,
|
||||
order,
|
||||
simpleDealerId,
|
||||
buildCommissionComment("分润收入", commissionConfig.commissionType, commissionConfig.dealerThirdValue, goodsQty)
|
||||
);
|
||||
}
|
||||
|
||||
return new DealerRefereeCommission(directDealerId, directMoney, simpleDealerId, simpleMoney, thirdDealerId, thirdMoney);
|
||||
}
|
||||
@@ -340,26 +375,30 @@ public class DealerOrderSettlement10584Task {
|
||||
ShopOrder order,
|
||||
BigDecimal baseAmount,
|
||||
int goodsQty,
|
||||
Integer totalDealerUserId
|
||||
ShopDealerUser totalDealerUser
|
||||
) {
|
||||
if (totalDealerUserId == null) {
|
||||
if (totalDealerUser == null || totalDealerUser.getUserId() == null) {
|
||||
return TotalDealerCommission.empty();
|
||||
}
|
||||
BigDecimal money = calcMoneyByCommissionType(baseAmount, TOTAL_DEALER_DIVIDEND_RATE, goodsQty, DIVIDEND_SCALE, 20);
|
||||
BigDecimal rate = safePositive(totalDealerUser.getRate());
|
||||
if (rate.signum() <= 0) {
|
||||
rate = TOTAL_DEALER_DIVIDEND_RATE;
|
||||
}
|
||||
BigDecimal money = calcMoneyByCommissionType(baseAmount, rate, goodsQty, DIVIDEND_SCALE, 20);
|
||||
log.info("总经销商分润发放 - orderNo={}, totalDealerUserId={}, rate={}, money={}",
|
||||
order.getOrderNo(), totalDealerUserId, TOTAL_DEALER_DIVIDEND_RATE, money);
|
||||
order.getOrderNo(), totalDealerUser.getUserId(), rate, money);
|
||||
creditDealerCommission(
|
||||
totalDealerUserId,
|
||||
totalDealerUser.getUserId(),
|
||||
money,
|
||||
order,
|
||||
order.getUserId(),
|
||||
buildCommissionComment("总经销商分润", 20, TOTAL_DEALER_DIVIDEND_RATE, goodsQty)
|
||||
buildCommissionComment("总经销商分润", 20, rate, goodsQty)
|
||||
);
|
||||
return new TotalDealerCommission(totalDealerUserId, money);
|
||||
return new TotalDealerCommission(totalDealerUser.getUserId(), money);
|
||||
}
|
||||
|
||||
private Integer findTotalDealerUserId() {
|
||||
ShopDealerUser dealerUser = shopDealerUserService.getOne(
|
||||
private ShopDealerUser findTotalDealerUser() {
|
||||
return shopDealerUserService.getOne(
|
||||
new LambdaQueryWrapper<ShopDealerUser>()
|
||||
.eq(ShopDealerUser::getTenantId, TENANT_ID)
|
||||
.eq(ShopDealerUser::getType, 2)
|
||||
@@ -367,7 +406,46 @@ public class DealerOrderSettlement10584Task {
|
||||
.orderByAsc(ShopDealerUser::getId)
|
||||
.last("limit 1")
|
||||
);
|
||||
return dealerUser != null ? dealerUser.getUserId() : null;
|
||||
}
|
||||
|
||||
private DealerBasicSetting findDealerBasicSetting() {
|
||||
int level = 2;
|
||||
ShopDealerSetting setting = shopDealerSettingService.getOne(
|
||||
new LambdaQueryWrapper<ShopDealerSetting>()
|
||||
.eq(ShopDealerSetting::getTenantId, TENANT_ID)
|
||||
.eq(ShopDealerSetting::getKey, "basic")
|
||||
.last("limit 1")
|
||||
);
|
||||
if (setting != null && setting.getValues() != null && !setting.getValues().isBlank()) {
|
||||
try {
|
||||
JSONObject json = JSONObject.parseObject(setting.getValues());
|
||||
Integer levelVal = json.getInteger("level");
|
||||
if (levelVal != null && levelVal > 0) {
|
||||
level = Math.min(levelVal, 3);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("解析分销设置失败,将使用默认等级 - tenantId={}, values={}", TENANT_ID, setting.getValues(), e);
|
||||
}
|
||||
}
|
||||
return new DealerBasicSetting(level);
|
||||
}
|
||||
|
||||
private int normalizeDealerLevel(int dealerLevel) {
|
||||
if (dealerLevel <= 0) {
|
||||
return 2;
|
||||
}
|
||||
return Math.min(dealerLevel, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* shop_dealer_setting(key=basic) 的关键配置(仅取结算任务需要的字段)。
|
||||
*/
|
||||
private static class DealerBasicSetting {
|
||||
private final int level;
|
||||
|
||||
private DealerBasicSetting(int level) {
|
||||
this.level = level;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -265,7 +265,7 @@ public class ShopOrderController extends BaseController {
|
||||
return fail("订单不存在");
|
||||
}
|
||||
// 退款相关操作单独走退款接口,便于做财务权限隔离
|
||||
if (Objects.equals(shopOrder.getOrderStatus(), 4) || Objects.equals(shopOrder.getOrderStatus(), 6)) {
|
||||
if (Objects.equals(shopOrder.getOrderStatus(), 6)) {
|
||||
return fail("退款相关操作请使用退款接口: PUT /api/shop/shop-order/refund");
|
||||
}
|
||||
ShopOrder shopOrderNow = shopOrderService.getById(shopOrder.getOrderId());
|
||||
|
||||
Reference in New Issue
Block a user