Compare commits

54 Commits

Author SHA1 Message Date
xm
48ae0ddfe6 优化分红金额计算业务 2026-06-02 15:11:00 +08:00
xm
5b3506fa00 商品增加分享图业务 2026-06-01 17:05:28 +08:00
xm
471927ccfc 商品订单增加配送时间业务 2026-06-01 11:34:04 +08:00
xm
2f1c95401f 优化商品股东分红批量更新业务 2026-05-30 17:28:53 +08:00
xm
3a874e84f5 Merge branch 'glt_xm' into dev_xm
# Conflicts:
#	src/main/java/com/gxwebsoft/shop/service/impl/ShopFlashSaleActivityServiceImpl.java
#	src/main/java/com/gxwebsoft/shop/vo/ShopFlashSaleActivityVO.java
2026-05-30 15:46:26 +08:00
xm
c3a50306ba 优化秒杀活动用户下单能力业务 2026-05-30 15:26:39 +08:00
xm
8d1a91cee7 Merge remote-tracking branch 'origin/dev_xm' into glt_xm
# Conflicts:
#	src/main/resources/application-dev.yml
#	src/main/resources/application-local.yml
2026-05-30 14:50:16 +08:00
xm
e511df0f8b 优化秒杀活动用户下单能力业务 2026-05-30 14:46:44 +08:00
xm
dd889dd7a2 1、增加股东/合伙人分红功能
2、优化原有订单分销算法,去掉原有股东分红制
3、优化收益明细查询业务
4、优化订单分佣解冻业务
2026-05-30 10:55:32 +08:00
xm
61b1d16937 1、优化配送派单消息推送功能
2、优化送水订单配送状态、水票标识查询,回显品名、水票标识、订单状态业务
3、优化送水订单接单、送达业务
4、优化资金表、资金流水表资金变更同步业务
2026-05-28 17:01:35 +08:00
xm
30363735df 增加商品分润基础业务功能 2026-05-27 10:59:00 +08:00
xm
b9d0d6b036 1、增加配送师傅订单派送发送消息通知功能
2、增加普通商品配完成送结算步梯费用给到配送师傅业务功能
3、增加分销商查询个人资金流水功能
2026-05-27 10:56:55 +08:00
xm
ba3748d2f9 1、调整微信消息推送模板业务
2、增加普通商品配送自动发单功能
3、增加核销员管理功能
4、开发配送员转单功能
5、优化送水订单查询业务
6、优化配送订单自动分配配送师傅业务
7、增加普通商品下单配送支付步梯费功能
2026-05-25 18:08:47 +08:00
xm
18148ddb8d 1、优化配送费分佣计算方式,按百分比/固定金额计算
2、增加自提订单核销数据统计功能
3、增加现场核销推广指定人分佣业务
2026-05-21 18:14:35 +08:00
xm
4d455e2ba2 增加分销员推广核销能力业务 2026-05-20 16:54:57 +08:00
xm
74bf6dd8d2 1、推广码底图增加分享底图业务
2、优化订单核销码、核销人查询业务
2026-05-20 14:28:30 +08:00
xm
5b876d29eb 1、关闭原有定时结算、手动结算业务,因新业务已完成流程结算功能
2、优化秒杀订单查询活动名称、核销码业务
3、优化订单状态查询业务
2026-05-20 11:29:24 +08:00
xm
032c936f42 local启动配置修改 2026-05-19 17:52:19 +08:00
xm
bbb26b44a9 优化配送订单完成结算配送金业务 2026-05-19 17:40:08 +08:00
xm
52af00170a 1、优化送水订单同步记录水票订单号业务
2、分销用户分销明细增加结算标识业务
3、增加分销用户个人当日收益数据统计
2026-05-19 16:47:42 +08:00
xm
b5d4274d97 1、修改测试、本地环境证书加载路径业务
2、优化配送结算业务,配送完成即计算
3、优化门店、服务商结算任务
4、秒杀活动增加弹窗业务
2026-05-19 10:32:17 +08:00
xm
2fbcf16a48 增加门店、服务商佣金定时结算功能,默认每天凌晨一点执行 2026-05-16 15:10:14 +08:00
xm
7de53327d6 修改配置 2026-05-14 17:45:04 +08:00
xm
f86bf8df4b 修改配置了 2026-05-14 08:21:10 +08:00
xm
65f1fa861d 配置修改 2026-05-14 01:33:58 +08:00
xm
cdabd5d446 优化水票释放业务 2026-05-13 17:29:45 +08:00
xm
86d27db76d Merge branch 'dev' into dev_xm
# Conflicts:
#	src/test/java/com/gxwebsoft/generator/ShopGenerator.java
2026-05-13 16:33:42 +08:00
xm
c3fcb36f66 增加退款按订单号回退分销用户钱包流水及同步生产回退流水功能 2026-05-13 16:32:09 +08:00
xm
f3d6bbef63 1.优化分销员计算一级、二级分销佣金业务
2.优化送水订单获取用户收货地址业务
3.优化收益明细订单号、用户ID查询业务
4.提现业务增加订单号,避免使用订单ID传入会与生产ID重复,导致都是已使用订单号
2026-05-13 09:55:49 +08:00
xm
92ca45a5c1 1.优化分佣算法业务
2.修改配置
2026-05-12 16:47:41 +08:00
xm
991b6fe529 1.调整订单分销、分润、分红结算算法功能
2.商品订单支付成功增加执行分销员分销、统计门店/服务商分销业务、执行总分红业务功能
3.配送员完成配送增加解冻商品订单业务功能
4.订单分销记录增加关联结算单号、结算状态字段,方便门店/服务商做计算做准备
2026-05-11 17:55:48 +08:00
xm
bc88f54c24 优化商品下单业务、水票解冻业务 2026-05-09 14:56:53 +08:00
xm
c6cec21d12 1.优化链接配置
2.关闭套票发放任务【支付成功回调取代】
3.优化定时解冻水票业务,每月1号即可释放本月水票
2026-05-09 14:36:40 +08:00
xm
81a9974e64 1.优化配置
2.商品订单支付成功后增加执行发放水票业务功能
3.送水订单、商品订单优化生产订单号业务
2026-05-08 15:00:06 +08:00
xm
3c7ee5057f swagger增加glt包扫描,获取接口文档 2026-05-08 09:58:23 +08:00
xm
82ce775807 1.调整开发端微信支付回调参数,保证测试环境能正常使用微信支付功能
2.调整送水订单显示用户具体收货地址业务
2026-05-08 09:36:05 +08:00
xm
f3dc242b5c 1.增加更新分销用户资金变更api,此功能提供统一分销资金结算、分销资金解冻、扫码直返佣等业务功能,变更账户同时生成对应流水
2.分销资金明细表增加:订单号、变动类型、变更后金额、创建人、删除等字段及相关功能
3.商品增加推广核验佣金比率业务
4.商品订单增加统计推广核销佣金、查询用户收货详细地址业务
5.增加订单扫码核销功能
6.新增统一获取订单工具类
2026-05-07 16:09:34 +08:00
xm
1a68b70591 调整订单取消任务每5分钟执行一次 2026-05-06 09:52:45 +08:00
xm
587caa78d7 1.优化小程序端用户待付款、待发货、待收货、已完成、退货/售后总单量数据及对应订单明细查询功能
2.新增分销用户查询团队成员订单数、订单金额、团队成员数查询业务功能
2026-05-05 17:39:26 +08:00
xm
a575907623 1.下单增加商品判断是否水票优化、默认订单类型功能
2.订单增加生成核销码功能
3.自提订单下单不校验电子围栏;配送订单如在电子围栏内默认自配送,在电子围栏外默认发快递
4.商品增加:配送方式、水票标识业务;商品订单增加:订单类型、水票标识、核销码业务
2026-05-05 09:31:45 +08:00
xm
044bb24b57 优化用户收货地址修改默认属性业务,一个地址设置为默认其他地址同步设置非默认 2026-04-30 10:39:58 +08:00
xm
53c0dc9cd7 常用实体类增加表名称对应名称,方便快速查询业务 2026-04-29 15:34:35 +08:00
xm
fb46af7bc3 增加步梯费用设置业务功能 2026-04-29 09:46:03 +08:00
1350250847@qq.com
8a22ad771a Merge branch 'dev' into dev_xm 2026-04-28 15:21:05 +08:00
1350250847@qq.com
68d2a99b77 秒杀活动增加商品图片、单位信息 2026-04-28 14:31:29 +08:00
1350250847@qq.com
359c080023 增加活动底图功能 2026-04-28 09:43:58 +08:00
1350250847@qq.com
70b299eda6 代码生成调整ID查询回退为Integer类型 2026-04-27 17:47:04 +08:00
1350250847@qq.com
9eeb0c5682 秒杀活动主键类型切换 2026-04-27 17:45:00 +08:00
1350250847@qq.com
818be01c7c 1.商品下单优化秒杀订单以秒杀价格为准
2.修改水票套票释放逻辑,个人水票发放以次月以1日凌晨为时间节点
3.增加以订单号形式发送水票套票信息
2026-04-27 17:23:08 +08:00
1350250847@qq.com
1ae7a76901 调整秒杀业务ID类型 2026-04-27 17:09:39 +08:00
1350250847@qq.com
95964219a5 优化秒杀活动限购数量业务 2026-04-23 17:17:05 +08:00
1350250847@qq.com
9344f3750c 1.修改数据库链接配置
2.增加系统异常码常量池
3.调整代码生产业务
4.增加秒杀活动业务功能
2026-04-23 15:59:10 +08:00
1350250847@qq.com
bc3842faee 变更数据库链接 2026-04-20 16:38:04 +08:00
1350250847@qq.com
8d2a0c46b7 常量注释 2026-04-14 16:57:34 +08:00
178 changed files with 7507 additions and 535 deletions

View File

@@ -32,7 +32,7 @@ public class CertificateProperties {
/** /**
* 开发环境证书路径前缀 * 开发环境证书路径前缀
*/ */
private String devCertPath = "dev"; private String devCertPath = "local";
/** /**
* 微信支付证书配置 * 微信支付证书配置

View File

@@ -60,7 +60,7 @@ public class ConfigProperties {
/** /**
* token过期时间, 单位秒 * token过期时间, 单位秒
*/ */
private Long tokenExpireTime = 60 * 60 * 365 * 24L; private Long tokenExpireTime = 60 * 60 * 30 * 24L;
/** /**
* token快要过期自动刷新时间, 单位分钟 * token快要过期自动刷新时间, 单位分钟

View File

@@ -80,6 +80,7 @@ public class MybatisPlusConfig {
@Override @Override
public boolean ignoreTable(String tableName) { public boolean ignoreTable(String tableName) {
// TenantContext.setIgnoreTenant(Boolean.TRUE);
// 如果当前上下文设置了忽略租户隔离,则忽略所有表的租户隔离 // 如果当前上下文设置了忽略租户隔离,则忽略所有表的租户隔离
if (TenantContext.isIgnoreTenant()) { if (TenantContext.isIgnoreTenant()) {
return true; return true;
@@ -91,18 +92,19 @@ public class MybatisPlusConfig {
"sys_dictionary", "sys_dictionary",
"sys_dictionary_data", "sys_dictionary_data",
"apps_test_data", "apps_test_data",
"cms_lang" "cms_lang",
// "hjm_car", "shop_goods",
// "hjm_fence" "shop_order" ,
// "cms_website" "shop_order_goods",
// "sys_user" "glt_ticket_template",
// "cms_domain" "glt_user_ticket",
// "shop_order_goods", "glt_user_ticket_release",
// "shop_goods" "glt_user_ticket_log",
// "shop_users", "shop_dealer_user",
// "shop_order" // 移除shop_order改为通过注解控制 "shop_dealer_order",
// "shop_order_info", "shop_dealer_referee",
// "booking_user_invoice" "shop_store_rider",
"shop_goods_profit"
).contains(tableName); ).contains(tableName);
} }
}; };

View File

@@ -87,14 +87,15 @@ public class SwaggerConfig {
} }
/** /**
* OA 模块分组 * Glt 模块分组
*/ */
@Bean @Bean
public GroupedOpenApi oaApi() { public GroupedOpenApi gltApi() {
return GroupedOpenApi.builder() return GroupedOpenApi.builder()
.group("oa") .group("glt")
.pathsToMatch("/api/oa/**") // 订单等用户侧接口在 shop 包内,但路径使用 /api/user/**(前端统一 user 侧 API 前缀)
.packagesToScan("com.gxwebsoft.oa") .pathsToMatch("/api/glt/**", "/api/user/**")
.packagesToScan("com.gxwebsoft.glt")
.build(); .build();
} }

View File

@@ -2,4 +2,7 @@ package com.gxwebsoft.common.core.constants;
public class BaseConstants { public class BaseConstants {
public static final String[] STATUS = {"未定义","显示","隐藏"}; public static final String[] STATUS = {"未定义","显示","隐藏"};
public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";
} }

View File

@@ -30,7 +30,7 @@ import java.util.Map;
@Tag(name = "数据库修复工具") @Tag(name = "数据库修复工具")
@RestController @RestController
@RequestMapping("/api/database-fix") @RequestMapping("/api/database-fix")
// @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev") // @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "local")
public class DatabaseFixController extends BaseController { public class DatabaseFixController extends BaseController {
@Autowired @Autowired

View File

@@ -28,7 +28,7 @@ import java.util.Map;
@Tag(name = "开发环境管理") @Tag(name = "开发环境管理")
@RestController @RestController
@RequestMapping("/api/dev") @RequestMapping("/api/dev")
// @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "dev") // @ConditionalOnProperty(name = "spring.profiles.active", havingValue = "local")
public class DevEnvironmentController extends BaseController { public class DevEnvironmentController extends BaseController {
@Autowired @Autowired

View File

@@ -0,0 +1,41 @@
package com.gxwebsoft.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户分销钱包交易业务分类
* @author xm
*/
@AllArgsConstructor
@Getter
public enum ShopDealerCapitalUpdateEnum {
DISTRIBUTION_INCOME(10, "分销收入", true),
MANAGEMENT_INCOME(11, "团队管理津贴收入", true),
DIVIDEND_INCOME(12, "分红收入", true),
PROMOTION_INCOME(13, "现场推广收入", true),
PROMOTION_PARENT_INCOME(14, "现场推广分佣", true),
WITHDRAW_PAYMENT(20, "提现支出", false),
TRANSFER_PAYMENT(30, "转账支出", false),
TRANSFER_INCOME(40, "转账收入", true),
FREEZE_MONEY_THAW(50, "佣金解冻", true),
DELIVERY_REWARD(60, "配送奖励", true),
DELIVERY_INCOME(61, "配送提成", true),
DELIVERY_FLOOR_FEE(62, "配送步梯费", true),
ORDER_REFUND(70, "佣金退回(退单)", false),
;
/**
* 业务分类
*/
private final Integer type;
/**
* 说明
*/
private final String description;
/**
* 是否为增加余额
*/
private final boolean add;
}

View File

@@ -0,0 +1,29 @@
package com.gxwebsoft.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 订单状态枚举
*/
@AllArgsConstructor
@Getter
public enum ShopDealerTypeEnum {
FREEZE_ACCOUNT(1, "操作冻结账户余额"),
WITHDRAW_ACCOUNT(2, "操作提现账户余额【直接结算】"),
DEFROST(3, "解冻"),
ORDER_REFUND(4, "退单");
private final Integer code;
private final String desc;
public Integer getCode() {
return code;
}
public String getDesc() {
return desc;
}
}

View File

@@ -0,0 +1,43 @@
package com.gxwebsoft.common.core.enums;
import cn.hutool.core.util.ArrayUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 全局用户类型枚举
*/
@AllArgsConstructor
@Getter
public enum UserTypeEnum {
// 面向 a 端,管理后台
RIDER(0, "骑手"),
// 面向 c 端,普通用户
MEMBER(1, "会员"),
STORE(3, "门店"),
// 面向 b 端,管理后台
ADMIN(2, "管理员"),
CHAT(4, "群聊");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(UserTypeEnum::getValue).toArray();
/**
* 类型
*/
private final Integer value;
/**
* 类型名
*/
private final String name;
public static UserTypeEnum valueOf(Integer value) {
return ArrayUtil.firstMatch(userType -> userType.getValue().equals(value), UserTypeEnum.values());
}
}

View File

@@ -0,0 +1,27 @@
package com.gxwebsoft.common.core.exception;
import lombok.Data;
/**
* 错误码对象
*
* 全局错误码,占用 [0, 999], 参见 {@link com.gxwebsoft.common.core.exception.enums.GlobalErrorCodeConstants}
*
*/
@Data
public class ErrorCode {
/**
* 错误码
*/
private final Integer code;
/**
* 错误提示
*/
private final String msg;
public ErrorCode(Integer code, String message) {
this.code = code;
this.msg = message;
}
}

View File

@@ -0,0 +1,40 @@
package com.gxwebsoft.common.core.exception.enums;
import com.gxwebsoft.common.core.exception.ErrorCode;
/**
* 全局错误码枚举
* 0-999 系统异常编码保留
*
* 一般情况下,使用 HTTP 响应状态码 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
* 虽然说HTTP 响应状态码作为业务使用表达能力偏弱,但是使用在系统层面还是非常不错的
* 比较特殊的是,因为之前一直使用 0 作为成功,就不使用 200 啦。
*
* @author xm
*/
public interface GlobalErrorCodeConstants {
ErrorCode SUCCESS = new ErrorCode(0, "成功");
// ========== 客户端错误段 ==========
ErrorCode BAD_REQUEST = new ErrorCode(400, "请求参数不正确");
ErrorCode UNAUTHORIZED = new ErrorCode(401, "账号未登录");
ErrorCode FORBIDDEN = new ErrorCode(403, "没有该操作权限");
ErrorCode NOT_FOUND = new ErrorCode(404, "查询无此数据");
ErrorCode METHOD_NOT_ALLOWED = new ErrorCode(405, "请求方法不正确");
ErrorCode LOCKED = new ErrorCode(423, "请求失败,请稍后重试"); // 并发请求,不允许
ErrorCode TOO_MANY_REQUESTS = new ErrorCode(429, "请求过于频繁,请稍后重试");
// ========== 服务端错误段 ==========
ErrorCode INTERNAL_SERVER_ERROR = new ErrorCode(500, "系统异常");
ErrorCode NOT_IMPLEMENTED = new ErrorCode(501, "功能未实现/未开启");
// ========== 自定义错误段 ==========
ErrorCode REPEATED_REQUESTS = new ErrorCode(900, "重复请求,请稍后重试"); // 重复请求
ErrorCode DEMO_DENY = new ErrorCode(901, "演示模式,禁止写操作");
ErrorCode UNKNOWN = new ErrorCode(999, "未知错误");
ErrorCode FINANCE_BILL_NOT_EXISTS = new ErrorCode(600, "门店财务账单不存在");
}

View File

@@ -70,7 +70,7 @@ public class EnvironmentAwarePaymentService {
* 根据当前环境获取回调地址 * 根据当前环境获取回调地址
*/ */
private String getEnvironmentNotifyUrl() { private String getEnvironmentNotifyUrl() {
if ("dev".equals(activeProfile) || "test".equals(activeProfile)) { if ("local".equals(activeProfile) || "test".equals(activeProfile)) {
// 开发/测试环境使用本地回调地址 // 开发/测试环境使用本地回调地址
return devNotifyUrl; return devNotifyUrl;
} else if ("prod".equals(activeProfile)) { } else if ("prod".equals(activeProfile)) {
@@ -135,7 +135,7 @@ public class EnvironmentAwarePaymentService {
* 是否为开发环境 * 是否为开发环境
*/ */
public boolean isDevelopmentEnvironment() { public boolean isDevelopmentEnvironment() {
return "dev".equals(activeProfile) || "test".equals(activeProfile); return "local".equals(activeProfile) || "test".equals(activeProfile);
} }
/** /**

View File

@@ -0,0 +1,29 @@
package com.gxwebsoft.common.core.utils;
import com.gxwebsoft.common.system.entity.User;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
public class LoginUserUtil {
/**
* 获取当前登录的user
*
* @return User
*/
public static User getLoginUser() {
try {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
Object object = authentication.getPrincipal();
if (object instanceof User) {
return (User) object;
}
}
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
return null;
}
}

View File

@@ -84,7 +84,7 @@ public class WechatCertAutoConfig {
String apiV3Key = "0kF5OlPr482EZwtn9zGufUcqa7ovgxRL"; String apiV3Key = "0kF5OlPr482EZwtn9zGufUcqa7ovgxRL";
// 根据环境选择证书路径 // 根据环境选择证书路径
if ("dev".equals(activeProfile)) { if ("local".equals(activeProfile)) {
// 开发环境使用配置文件upload-path拼接证书路径 // 开发环境使用配置文件upload-path拼接证书路径
String uploadPath = configProperties.getUploadPath(); // 配置文件路径 String uploadPath = configProperties.getUploadPath(); // 配置文件路径
String tenantId = "10550"; // 租户ID String tenantId = "10550"; // 租户ID

View File

@@ -105,7 +105,7 @@ public class WechatPayCertificateDiagnostic {
* 检查证书文件 * 检查证书文件
*/ */
private void checkCertificateFiles(Payment payment, Integer tenantId, String environment, DiagnosticResult result) { private void checkCertificateFiles(Payment payment, Integer tenantId, String environment, DiagnosticResult result) {
if ("dev".equals(environment)) { if ("local".equals(environment)) {
// 开发环境证书检查 // 开发环境证书检查
String tenantCertPath = "dev/wechat/" + tenantId; String tenantCertPath = "dev/wechat/" + tenantId;
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
@@ -152,7 +152,7 @@ public class WechatPayCertificateDiagnostic {
*/ */
private void validateCertificateContent(Payment payment, Integer tenantId, String environment, DiagnosticResult result) { private void validateCertificateContent(Payment payment, Integer tenantId, String environment, DiagnosticResult result) {
try { try {
if ("dev".equals(environment)) { if ("local".equals(environment)) {
String tenantCertPath = "dev/wechat/" + tenantId; String tenantCertPath = "dev/wechat/" + tenantId;
String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile();

View File

@@ -103,7 +103,7 @@ public class WechatPayCertificateFixer {
* 修复证书文件问题 * 修复证书文件问题
*/ */
private void fixCertificateFiles(Payment payment, Integer tenantId, String environment, FixResult result) { private void fixCertificateFiles(Payment payment, Integer tenantId, String environment, FixResult result) {
if ("dev".equals(environment)) { if ("local".equals(environment)) {
fixDevCertificateFiles(tenantId, result); fixDevCertificateFiles(tenantId, result);
} else { } else {
fixProdCertificateFiles(payment, result); fixProdCertificateFiles(payment, result);
@@ -169,7 +169,7 @@ public class WechatPayCertificateFixer {
} }
// 在开发环境中,尝试从证书文件中提取序列号进行验证 // 在开发环境中,尝试从证书文件中提取序列号进行验证
if ("dev".equals(environment)) { if ("local".equals(environment)) {
try { try {
String tenantCertPath = "dev/wechat/" + tenantId; String tenantCertPath = "dev/wechat/" + tenantId;
String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile(); String apiclientCertPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getApiclientCertFile();

View File

@@ -115,7 +115,7 @@ public class WechatPayConfigValidator {
* 验证证书文件 * 验证证书文件
*/ */
private void validateCertificateFiles(Integer tenantId, ValidationResult result) { private void validateCertificateFiles(Integer tenantId, ValidationResult result) {
if ("dev".equals(activeProfile)) { if ("local".equals(activeProfile)) {
// 开发环境证书验证 // 开发环境证书验证
String tenantCertPath = "dev/wechat/" + tenantId; String tenantCertPath = "dev/wechat/" + tenantId;
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
@@ -195,7 +195,7 @@ public class WechatPayConfigValidator {
// 证书文件检查 // 证书文件检查
report.append("当前环境: ").append(activeProfile).append("\n"); report.append("当前环境: ").append(activeProfile).append("\n");
if ("dev".equals(activeProfile)) { if ("local".equals(activeProfile)) {
String tenantCertPath = "dev/wechat/" + tenantId; String tenantCertPath = "dev/wechat/" + tenantId;
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
boolean certExists = certificateLoader.certificateExists(privateKeyPath); boolean certExists = certificateLoader.certificateExists(privateKeyPath);

View File

@@ -78,7 +78,7 @@ public class WechatPayDiagnostic {
} }
// 生产环境检查证书文件 // 生产环境检查证书文件
if (!"dev".equals(environment)) { if (!"local".equals(environment)) {
if (payment.getApiclientCert() != null) { if (payment.getApiclientCert() != null) {
log.info("商户证书文件配置: {}", payment.getApiclientCert()); log.info("商户证书文件配置: {}", payment.getApiclientCert());
} }

View File

@@ -262,6 +262,9 @@ public class User implements UserDetails {
@Schema(description = "微信unionid") @Schema(description = "微信unionid")
private String unionid; private String unionid;
@Schema(description = "核销权限是否开启 0-未开启 1-已开启")
private Integer verifyFlag;
@Schema(description = "关联用户ID") @Schema(description = "关联用户ID")
@TableField(exist = false) @TableField(exist = false)
private Integer sysUserId; private Integer sysUserId;

View File

@@ -49,6 +49,9 @@ public interface UserMapper extends BaseMapper<User> {
@InterceptorIgnore(tenantLine = "true") @InterceptorIgnore(tenantLine = "true")
List<User> getOne(@Param("param") UserParam param); List<User> getOne(@Param("param") UserParam param);
@InterceptorIgnore(tenantLine = "true")
User getById(@Param("userId") Integer userId);
List<User> selectListStatisticsRel(@Param("param") UserParam param); List<User> selectListStatisticsRel(@Param("param") UserParam param);
@InterceptorIgnore(tenantLine = "true") @InterceptorIgnore(tenantLine = "true")
@@ -67,4 +70,11 @@ public interface UserMapper extends BaseMapper<User> {
@InterceptorIgnore(tenantLine = "true") @InterceptorIgnore(tenantLine = "true")
List<User> listByAlert(); List<User> listByAlert();
/**
* 批量查询用户信息
* @param userIdList 用户ID集合
* @return
*/
List<User> selectByUserIdList(@Param("userIdList") List<Integer> userIdList);
} }

View File

@@ -260,5 +260,25 @@
WHERE a.user_id = #{userId} WHERE a.user_id = #{userId}
AND a.deleted = 0 AND a.deleted = 0
</select> </select>
<select id="getById" resultType="com.gxwebsoft.common.system.entity.User">
SELECT * FROM gxwebsoft_core.sys_user WHERE user_id = #{userId} and deleted = 0
</select>
<select id="selectByUserIdList" resultType="com.gxwebsoft.common.system.entity.User">
SELECT
user_id,
username,
nickname,
phone,
real_name,
create_time
FROM
gxwebsoft_core.sys_user
WHERE
deleted = 0
AND user_id IN
<foreach collection="userIdList" item="item" index="index" open="(" close=")" separator=",">
#{item}
</foreach>
</select>
</mapper> </mapper>

View File

@@ -0,0 +1,38 @@
package com.gxwebsoft.common.system.redis;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
/**
* 支付序号的 Redis DAO
*
* @author 芋道源码
*/
@Repository
public class OrderNoUtils {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 生成序号
* @param prefix 前缀
* @return 序号
*/
public String generate(String prefix) {
// 递增序号
String noPrefix = prefix + DateUtil.format(LocalDateTime.now(), DatePattern.PURE_DATETIME_PATTERN);
String key = noPrefix;
Long no = stringRedisTemplate.opsForValue().increment(key);
// 设置过期时间
stringRedisTemplate.expire(key, Duration.ofMinutes(1L));
return noPrefix + no;
}
}

View File

@@ -143,7 +143,7 @@ public class SettingServiceImpl extends ServiceImpl<SettingMapper, Setting> impl
final String apiV3key = jsonObject.getString("wechatApiKey"); final String apiV3key = jsonObject.getString("wechatApiKey");
if(config == null){ if(config == null){
// 根据环境选择不同的证书路径配置 // 根据环境选择不同的证书路径配置
if ("dev".equals(activeProfile)) { if ("local".equals(activeProfile)) {
// 开发环境使用配置文件的upload-path拼接证书路径 - 租户ID 10550 // 开发环境使用配置文件的upload-path拼接证书路径 - 租户ID 10550
System.out.println("=== 开发环境使用配置文件upload-path拼接证书路径 ==="); System.out.println("=== 开发环境使用配置文件upload-path拼接证书路径 ===");
String uploadPath = pathConfig.getUploadPath(); // 获取配置的upload-path String uploadPath = pathConfig.getUploadPath(); // 获取配置的upload-path

View File

@@ -9,6 +9,8 @@ import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.mapper.UserMapper; import com.gxwebsoft.common.system.mapper.UserMapper;
import com.gxwebsoft.glt.dto.GltTransferOrderDto;
import com.gxwebsoft.glt.dto.NoticeRiderNewOrderDto;
import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.param.GltTicketOrderDeliveredParam; import com.gxwebsoft.glt.param.GltTicketOrderDeliveredParam;
import com.gxwebsoft.glt.param.GltTicketOrderParam; import com.gxwebsoft.glt.param.GltTicketOrderParam;
@@ -23,6 +25,7 @@ import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -56,7 +59,7 @@ public class GltTicketOrderController extends BaseController {
@Operation(summary = "分页查询送水订单") @Operation(summary = "分页查询送水订单")
@GetMapping("/page") @GetMapping("/page")
public ApiResult<PageResult<GltTicketOrder>> page(GltTicketOrderParam param) { public ApiResult<PageResult<GltTicketOrder>> page(@ParameterObject GltTicketOrderParam param) {
// 使用关联查询 // 使用关联查询
return success(gltTicketOrderService.pageRel(param)); return success(gltTicketOrderService.pageRel(param));
} }
@@ -176,14 +179,6 @@ public class GltTicketOrderController extends BaseController {
} }
gltTicketOrderService.createWithWriteOff(gltTicketOrder, loginUser.getUserId(), loginUser.getTenantId()); gltTicketOrderService.createWithWriteOff(gltTicketOrder, loginUser.getUserId(), loginUser.getTenantId());
// 订单创建成功后,异步通知所有在线配送员有新订单
try {
notifyRidersOfNewOrder(gltTicketOrder, loginUser.getTenantId());
} catch (Exception e) {
log.warn("通知配送员失败(不影响下单): {}", e.getMessage());
}
return success("下单成功"); return success("下单成功");
} }
@@ -242,8 +237,14 @@ public class GltTicketOrderController extends BaseController {
} }
} }
} }
}
log.info("已向 {} 位配送员发送新订单通知", riders.size()); @PreAuthorize("isAuthenticated()")
@Operation(summary = "配送员调度单通知")
@PostMapping("/sendRiderNewOrderNotice")
public ApiResult<?> sendRiderNewOrderNotice(@RequestBody NoticeRiderNewOrderDto noticeRiderNewOrderDto) {
gltSubscribeMessageService.sendRiderNewOrderNotice(noticeRiderNewOrderDto);
return success("发送消息成功!");
} }
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@@ -260,6 +261,13 @@ public class GltTicketOrderController extends BaseController {
return success("接单成功"); return success("接单成功");
} }
@PreAuthorize("isAuthenticated()")
@Operation(summary = "配送员转单")
@PostMapping("/transferOrder")
public ApiResult<Boolean> transferOrder(@RequestBody GltTransferOrderDto orderDto) {
return success(gltTicketOrderService.transferOrder(orderDto));
}
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@Operation(summary = "配送员开始配送") @Operation(summary = "配送员开始配送")
@PostMapping("/{id}/start") @PostMapping("/{id}/start")
@@ -291,6 +299,13 @@ public class GltTicketOrderController extends BaseController {
return success("确认送达"); return success("确认送达");
} }
@Operation(summary = "订单调度")
@PostMapping("/dispatchOrder")
public ApiResult<?> dispatchOrder(@RequestParam("orderNo") String orderNo, @RequestParam("tenantId") Integer tenantId) {
gltTicketOrderService.dispatchOrder(orderNo, tenantId);
return success("success!");
}
@PreAuthorize("isAuthenticated()") @PreAuthorize("isAuthenticated()")
@Operation(summary = "用户确认收货") @Operation(summary = "用户确认收货")
@PostMapping("/{id}/confirm-receive") @PostMapping("/{id}/confirm-receive")
@@ -329,16 +344,14 @@ public class GltTicketOrderController extends BaseController {
if (addr == null) { if (addr == null) {
return null; return null;
} }
if (StrUtil.isNotBlank(addr.getFullAddress())) {
return addr.getFullAddress();
}
// 兼容旧数据fullAddress 为空时,拼接省市区 + 详细地址 // 兼容旧数据fullAddress 为空时,拼接省市区 + 详细地址
return StrUtil.blankToDefault( return StrUtil.blankToDefault(
StrUtil.join("", StrUtil.join("",
StrUtil.nullToEmpty(addr.getProvince()), StrUtil.nullToEmpty(addr.getProvince()),
StrUtil.nullToEmpty(addr.getCity()), StrUtil.nullToEmpty(addr.getCity()),
StrUtil.nullToEmpty(addr.getRegion()), StrUtil.nullToEmpty(addr.getRegion()),
StrUtil.nullToEmpty(addr.getAddress()) StrUtil.nullToEmpty(addr.getAddress()),
StrUtil.nullToEmpty(addr.getFullAddress())
), ),
addr.getAddress() addr.getAddress()
); );
@@ -376,23 +389,14 @@ public class GltTicketOrderController extends BaseController {
} }
if (gltTicketOrderService.updateById(gltTicketOrder)) { if (gltTicketOrderService.updateById(gltTicketOrder)) {
// 后台指派配送员(直接改 riderId同步商城订单为“已发货”(deliveryStatus=20) gltTicketOrderService.markShopOrderShippedAfterRiderAssigned(gltTicketOrder.getId(), tenantId, gltTicketOrder.getRiderId());
if (gltTicketOrder != null
&& gltTicketOrder.getId() != null
&& gltTicketOrder.getRiderId() != null
&& gltTicketOrder.getRiderId() > 0) {
gltTicketOrderService.markShopOrderShippedAfterRiderAssigned(
gltTicketOrder.getId(),
tenantId,
gltTicketOrder.getRiderId()
);
}
// 后台直接改“已完成”(deliveryStatus=40)时,同步商城订单为“已完成”(orderStatus=1) // 后台直接改“已完成”(deliveryStatus=40)时,同步商城订单为“已完成”(orderStatus=1)
if (gltTicketOrder != null if (gltTicketOrder != null
&& gltTicketOrder.getId() != null && gltTicketOrder.getId() != null
&& gltTicketOrder.getDeliveryStatus() != null && gltTicketOrder.getDeliveryStatus() != null
&& gltTicketOrder.getDeliveryStatus() == GltTicketOrderService.DELIVERY_STATUS_FINISHED) { && gltTicketOrder.getDeliveryStatus() == GltTicketOrderService.DELIVERY_STATUS_FINISHED) {
gltTicketOrderService.markShopOrderCompletedAfterTicketFinished(gltTicketOrder.getId(), tenantId); gltTicketOrderService.markShopOrderCompletedAfterTicketFinished(gltTicketOrder.getId());
} }
return success("修改成功"); return success("修改成功");
} }

View File

@@ -79,6 +79,7 @@ public class GltTicketTemplateController extends BaseController {
User loginUser = getLoginUser(); User loginUser = getLoginUser();
if (loginUser != null) { if (loginUser != null) {
gltTicketTemplate.setUserId(loginUser.getUserId()); gltTicketTemplate.setUserId(loginUser.getUserId());
gltTicketTemplate.setTenantId(loginUser.getTenantId());
} }
if (gltTicketTemplateService.save(gltTicketTemplate)) { if (gltTicketTemplateService.save(gltTicketTemplate)) {
return success("添加成功"); return success("添加成功");

View File

@@ -1,15 +1,15 @@
package com.gxwebsoft.glt.controller; 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.BaseController;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.glt.service.GltUserTicketReleaseService;
import com.gxwebsoft.glt.entity.GltUserTicketRelease; import com.gxwebsoft.glt.entity.GltUserTicketRelease;
import com.gxwebsoft.glt.param.GltUserTicketReleaseParam; import com.gxwebsoft.glt.param.GltUserTicketReleaseParam;
import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.glt.service.GltUserTicketReleaseService;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.glt.service.impl.GltUserTicketAutoReleaseServiceImpl;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
@@ -31,6 +31,9 @@ public class GltUserTicketReleaseController extends BaseController {
@Resource @Resource
private GltUserTicketReleaseService gltUserTicketReleaseService; private GltUserTicketReleaseService gltUserTicketReleaseService;
@Resource
private GltUserTicketAutoReleaseServiceImpl gltUserTicketAutoReleaseService;
@PreAuthorize("hasAuthority('glt:gltUserTicketRelease:list')") @PreAuthorize("hasAuthority('glt:gltUserTicketRelease:list')")
@Operation(summary = "分页查询水票释放") @Operation(summary = "分页查询水票释放")
@GetMapping("/page") @GetMapping("/page")
@@ -126,4 +129,11 @@ public class GltUserTicketReleaseController extends BaseController {
return fail("删除失败"); return fail("删除失败");
} }
@Operation(summary = "水票释放测试")
@PostMapping("/releaseTask")
public ApiResult<?> releaseTask() {
gltUserTicketAutoReleaseService.releaseTask();
return success(true);
}
} }

View File

@@ -0,0 +1,25 @@
package com.gxwebsoft.glt.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* 转单请求类
*
*/
@Data
@Schema(name = "ShopOrderMyVerifyDto", description = "转单请求类")
public class GltTransferOrderDto {
@Schema(description = "订单ID")
@NotEmpty(message = "订单ID不能为空")
private Integer id;
@Schema(description = "转单用户ID")
@NotEmpty(message = "转单用户ID不能为空")
private Integer userId;
}

View File

@@ -0,0 +1,35 @@
package com.gxwebsoft.glt.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 配送员新订单配送通知
*
*/
@Data
@Schema(name = "ShopOrderMyVerifyDto", description = "配送员新订单配送通知")
public class NoticeRiderNewOrderDto {
@Schema(description = "订单号")
private String orderNo;
@Schema(description = "商品名称")
private String goodsName;
@Schema(description = "配送数量")
private Integer productCount;
@Schema(description = "期望送达时间")
private LocalDateTime createTime;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "openID")
private String openId;
}

View File

@@ -1,9 +1,6 @@
package com.gxwebsoft.glt.entity; package com.gxwebsoft.glt.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -22,17 +19,20 @@ import java.time.LocalDateTime;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "GltTicketOrder对象", description = "送水订单") @Schema(name = "GltTicketOrder对象", description = "送水订单")
@TableName("glt_ticket_order")
public class GltTicketOrder implements Serializable { public class GltTicketOrder implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Integer id; private Integer id;
@Schema(description = "订单编号")
private String no;
@Schema(description = "用户水票ID") @Schema(description = "用户水票ID")
private Integer userTicketId; private Integer userTicketId;
@Schema(description = "订单编号") @Schema(description = "关联订单编号")
@TableField(exist = false)
private String orderNo; private String orderNo;
@Schema(description = "订单状态") @Schema(description = "订单状态")
@@ -46,6 +46,10 @@ public class GltTicketOrder implements Serializable {
@TableField(exist = false) @TableField(exist = false)
private String storeName; private String storeName;
@Schema(description = "品名")
@TableField(exist = false)
private String goodsName;
@Schema(description = "门店地址") @Schema(description = "门店地址")
@TableField(exist = false) @TableField(exist = false)
private String storeAddress; private String storeAddress;
@@ -197,6 +201,10 @@ public class GltTicketOrder implements Serializable {
@Schema(description = "楼层(步梯+送上楼时有值从2开始") @Schema(description = "楼层(步梯+送上楼时有值从2开始")
private Integer deliveryFloor; private Integer deliveryFloor;
@Schema(description = "详细地址")
@TableField(exist = false)
private String fullAddress;
@Schema(description = "配送费(步梯+送上楼时计算:数量 × (楼层-1)") @Schema(description = "配送费(步梯+送上楼时计算:数量 × (楼层-1)")
private BigDecimal deliveryFee; private BigDecimal deliveryFee;
@@ -209,6 +217,9 @@ public class GltTicketOrder implements Serializable {
@Schema(description = "状态, 0正常, 1冻结") @Schema(description = "状态, 0正常, 1冻结")
private Integer status; private Integer status;
@Schema(description = "水票标识 0-非 1-是")
private Integer waterTicketFlag;
@Schema(description = "是否删除, 0否, 1是") @Schema(description = "是否删除, 0否, 1是")
@TableLogic @TableLogic
private Integer deleted; private Integer deleted;

View File

@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable; import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@@ -19,6 +21,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "GltTicketTemplate对象", description = "水票") @Schema(name = "GltTicketTemplate对象", description = "水票")
@TableName("glt_ticket_template")
public class GltTicketTemplate implements Serializable { public class GltTicketTemplate implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -1,12 +1,9 @@
package com.gxwebsoft.glt.entity; package com.gxwebsoft.glt.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable; import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -22,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "GltUserTicket对象", description = "我的水票") @Schema(name = "GltUserTicket对象", description = "我的水票")
@TableName("glt_user_ticket")
public class GltUserTicket implements Serializable { public class GltUserTicket implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -1,10 +1,8 @@
package com.gxwebsoft.glt.entity; package com.gxwebsoft.glt.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable; import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -20,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "GltUserTicketLog对象", description = "消费日志") @Schema(name = "GltUserTicketLog对象", description = "消费日志")
@TableName("glt_user_ticket_log")
public class GltUserTicketLog implements Serializable { public class GltUserTicketLog implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -1,10 +1,8 @@
package com.gxwebsoft.glt.entity; package com.gxwebsoft.glt.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable; import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -20,6 +18,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "GltUserTicketRelease对象", description = "水票释放") @Schema(name = "GltUserTicketRelease对象", description = "水票释放")
@TableName("glt_user_ticket_release")
public class GltUserTicketRelease implements Serializable { public class GltUserTicketRelease implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -27,7 +26,7 @@ public class GltUserTicketRelease implements Serializable {
private Long id; private Long id;
@Schema(description = "水票ID") @Schema(description = "水票ID")
private Long userTicketId; private Integer userTicketId;
@Schema(description = "用户ID") @Schema(description = "用户ID")
private Integer userId; private Integer userId;
@@ -57,6 +56,9 @@ public class GltUserTicketRelease implements Serializable {
@Schema(description = "状态") @Schema(description = "状态")
private Integer status; private Integer status;
@Schema(description = "备注")
private String remark;
@Schema(description = "是否删除, 0否, 1是") @Schema(description = "是否删除, 0否, 1是")
@TableLogic @TableLogic
private Integer deleted; private Integer deleted;

View File

@@ -37,6 +37,13 @@ public interface GltUserTicketReleaseMapper extends BaseMapper<GltUserTicketRele
*/ */
List<GltUserTicketRelease> selectListRel(@Param("param") GltUserTicketReleaseParam param); List<GltUserTicketRelease> selectListRel(@Param("param") GltUserTicketReleaseParam param);
/**
* 查询当月待释放水票数据
* @param limitNum 查询数量
* @return List<User>
*/
List<GltUserTicketRelease> getThisMonthReleaseList(@Param("limitNum") Integer limitNum);
/** /**
* 查询待释放且到期的记录(加行锁,防止多实例重复处理) * 查询待释放且到期的记录(加行锁,防止多实例重复处理)
* *

View File

@@ -11,7 +11,7 @@
d.name as receiverName, d.phone as receiverPhone, d.name as receiverName, d.phone as receiverPhone,
d.province as receiverProvince, d.city as receiverCity, d.region as receiverRegion, d.province as receiverProvince, d.city as receiverCity, d.region as receiverRegion,
d.address as receiverAddress, d.full_address as receiverFullAddress, d.lat as receiverLat, d.lng as receiverLng, d.address as receiverAddress, d.full_address as receiverFullAddress, d.lat as receiverLat, d.lng as receiverLng,
COALESCE(o.order_no, f.order_no) as orderNo, o.order_status as orderStatus COALESCE(o.order_no, a.order_no) as orderNo, o.order_status as orderStatus
FROM glt_ticket_order a FROM glt_ticket_order a
LEFT JOIN shop_store b ON a.store_id = b.id LEFT JOIN shop_store b ON a.store_id = b.id
LEFT JOIN shop_store_warehouse w ON a.warehouse_id = w.id LEFT JOIN shop_store_warehouse w ON a.warehouse_id = w.id
@@ -20,7 +20,6 @@
LEFT JOIN shop_user_address d ON a.address_id = d.id LEFT JOIN shop_user_address d ON a.address_id = d.id
LEFT JOIN glt_user_ticket f ON a.user_ticket_id = f.id LEFT JOIN glt_user_ticket f ON a.user_ticket_id = f.id
LEFT JOIN shop_order o ON f.order_id = o.order_id AND f.tenant_id = o.tenant_id AND o.deleted = 0 LEFT JOIN shop_order o ON f.order_id = o.order_id AND f.tenant_id = o.tenant_id AND o.deleted = 0
<where> <where>
<if test="param.id != null"> <if test="param.id != null">
AND a.id = #{param.id} AND a.id = #{param.id}
@@ -88,7 +87,7 @@
AND a.create_time &lt;= #{param.createTimeEnd} AND a.create_time &lt;= #{param.createTimeEnd}
</if> </if>
<if test="param.orderNo != null"> <if test="param.orderNo != null">
AND (a.id = #{param.orderNo} OR COALESCE(o.order_no, f.order_no) = #{param.orderNo}) AND (a.id = #{param.orderNo} OR COALESCE(o.order_no, a.order_no) = #{param.orderNo})
</if> </if>
<if test="param.phone != null"> <if test="param.phone != null">
AND u.phone = #{param.phone} AND u.phone = #{param.phone}
@@ -103,6 +102,12 @@
OR u.phone LIKE CONCAT('%', #{param.keywords}, '%') OR u.phone LIKE CONCAT('%', #{param.keywords}, '%')
) )
</if> </if>
<if test="param.waterTicketFlag != null">
AND a.water_ticket_flag = #{param.waterTicketFlag}
</if>
<if test="param.deliveryStatus != null and param.deliveryStatus == 10">
AND o.order_status in (0, 1, 5)
</if>
</where> </where>
</sql> </sql>

View File

@@ -58,5 +58,23 @@
<select id="selectListRel" resultType="com.gxwebsoft.glt.entity.GltUserTicketRelease"> <select id="selectListRel" resultType="com.gxwebsoft.glt.entity.GltUserTicketRelease">
<include refid="selectSql"></include> <include refid="selectSql"></include>
</select> </select>
<select id="getThisMonthReleaseList" resultType="com.gxwebsoft.glt.entity.GltUserTicketRelease">
SELECT
id,
user_ticket_id,
user_id,
release_qty,
tenant_id
FROM
glt_user_ticket_release
WHERE
STATUS = 0
AND deleted = 0
AND release_qty > 0
AND DATE_FORMAT(release_time, '%Y-%m') = DATE_FORMAT(NOW(), '%Y-%m')
ORDER BY
release_time ASC
LIMIT #{limitNum}
</select>
</mapper> </mapper>

View File

@@ -94,4 +94,7 @@ public class GltTicketOrderParam extends BaseParam {
@QueryField(type = QueryType.EQ) @QueryField(type = QueryType.EQ)
private Integer orderStatus; private Integer orderStatus;
@Schema(description = "水票订单标识 0-否 1-是")
private Integer waterTicketFlag;
} }

View File

@@ -1,5 +1,6 @@
package com.gxwebsoft.glt.service; package com.gxwebsoft.glt.service;
import com.gxwebsoft.glt.dto.NoticeRiderNewOrderDto;
import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketOrder;
/** /**
@@ -25,4 +26,10 @@ public interface GltSubscribeMessageService {
* @return 是否发送成功 * @return 是否发送成功
*/ */
boolean sendOrderStatusNotice(GltTicketOrder order, String riderOpenId, String statusText, Integer tenantId); boolean sendOrderStatusNotice(GltTicketOrder order, String riderOpenId, String statusText, Integer tenantId);
/**
* 推送配送师傅接单提醒
* @param noticeRiderNewOrderDto
*/
void sendRiderNewOrderNotice(NoticeRiderNewOrderDto noticeRiderNewOrderDto);
} }

View File

@@ -1,28 +1,26 @@
package com.gxwebsoft.glt.service; package com.gxwebsoft.glt.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.gxwebsoft.glt.entity.*;
import com.gxwebsoft.glt.entity.GltTicketTemplate; import com.gxwebsoft.glt.task.DealerOrderSettlement10584Task;
import com.gxwebsoft.glt.entity.GltUserTicket;
import com.gxwebsoft.glt.entity.GltUserTicketLog;
import com.gxwebsoft.glt.entity.GltUserTicketRelease;
import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.shop.entity.ShopOrderGoods; import com.gxwebsoft.shop.entity.ShopOrderGoods;
import com.gxwebsoft.shop.mapper.ShopOrderMapper;
import com.gxwebsoft.shop.service.ShopOrderGoodsService; import com.gxwebsoft.shop.service.ShopOrderGoodsService;
import com.gxwebsoft.shop.service.ShopOrderService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Resource;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.LocalTime; import java.time.LocalTime;
import java.util.ArrayList; import java.util.*;
import java.util.HashSet; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/** /**
* 套票发放(从订单生成用户套票 + 释放计划)的业务逻辑。 * 套票发放(从订单生成用户套票 + 释放计划)的业务逻辑。
@@ -37,6 +35,9 @@ import java.util.Set;
@RequiredArgsConstructor @RequiredArgsConstructor
public class GltTicketIssueService { public class GltTicketIssueService {
@Resource
private GltTicketOrderService gltTicketOrderService;
public static final int CHANGE_TYPE_ISSUE = 10; public static final int CHANGE_TYPE_ISSUE = 10;
private enum IssueOutcome { private enum IssueOutcome {
@@ -46,7 +47,7 @@ public class GltTicketIssueService {
NO_TEMPLATE NO_TEMPLATE
} }
private final ShopOrderService shopOrderService; private final ShopOrderMapper shopOrderMapper;
private final ShopOrderGoodsService shopOrderGoodsService; private final ShopOrderGoodsService shopOrderGoodsService;
private final GltTicketTemplateService gltTicketTemplateService; private final GltTicketTemplateService gltTicketTemplateService;
@@ -54,6 +55,7 @@ public class GltTicketIssueService {
private final GltUserTicketReleaseService gltUserTicketReleaseService; private final GltUserTicketReleaseService gltUserTicketReleaseService;
private final GltUserTicketLogService gltUserTicketLogService; private final GltUserTicketLogService gltUserTicketLogService;
private final TransactionTemplate transactionTemplate; private final TransactionTemplate transactionTemplate;
private final DealerOrderSettlement10584Task dealerOrderSettlement;
/** /**
* 扫描“今日订单”,执行套票发放。 * 扫描“今日订单”,执行套票发放。
@@ -84,7 +86,7 @@ public class GltTicketIssueService {
LocalDateTime todayStart = LocalDate.now().atStartOfDay(); LocalDateTime todayStart = LocalDate.now().atStartOfDay();
LocalDateTime tomorrowStart = todayStart.plusDays(1); LocalDateTime tomorrowStart = todayStart.plusDays(1);
List<ShopOrder> orders = shopOrderService.list( List<ShopOrder> orders = shopOrderMapper.selectList(
new LambdaQueryWrapper<ShopOrder>() new LambdaQueryWrapper<ShopOrder>()
.eq(ShopOrder::getTenantId, tenantId) .eq(ShopOrder::getTenantId, tenantId)
.in(ShopOrder::getFormId, uniqueGoodsIds) .in(ShopOrder::getFormId, uniqueGoodsIds)
@@ -128,6 +130,75 @@ public class GltTicketIssueService {
tenantId, uniqueGoodsIds, orders.size(), success, skipped, failed); tenantId, uniqueGoodsIds, orders.size(), success, skipped, failed);
} }
/**
* 商品订单支付成功后调后需处理业务
* @param orderNo 订单号
* @param tenantId 租户ID
*/
@Async
public void paySuccessTask(String orderNo, Integer tenantId){
//1.发送水票
suerTicketRelease(orderNo, tenantId);
//2.执行分销员分销、统计门店/服务商分销业务
dealerOrderSettlement.orderSettlement(orderNo);
//3.执行平台分红业务
dealerOrderSettlement.partnerProfit(orderNo, tenantId);
//4.普通商品【非水票订单】如果是需要自配送的,则会同步生成派单信息
gltTicketOrderService.dispatchOrder(orderNo, tenantId);
}
/**
* 订单支付成功,直接发送水票【后期优化订单类型,为水票的订单才需要执行此业务】
* @param orderNo 订单号
* @param tenantId 租户ID
*/
@Transactional
public void suerTicketRelease(String orderNo, Integer tenantId){
//1.订单为空跳过执行
ShopOrder shopOrder = shopOrderMapper.selectOne(new LambdaQueryWrapper<ShopOrder>()
.eq(ShopOrder::getOrderNo, orderNo)
.eq(ShopOrder::getTenantId, tenantId));
if(shopOrder == null){
return;
}
//2.只有水票订单才需要发送水票
if(!(shopOrder.getWaterTicketFlag() != null && shopOrder.getWaterTicketFlag() == 1)){
return;
}
//3.跳过已完成发放套票订单
if(shopOrder.getOrderStatus() == 1){
return;
}
//4.订单商品为空跳过执行
List<ShopOrderGoods> goodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(shopOrder.getOrderId());
if (CollectionUtils.isEmpty(goodsList)) {
return;
}
//5.执行水票发放业务
AtomicBoolean release = new AtomicBoolean(false);
goodsList.forEach(orderGood ->{
IssueOutcome outcome = transactionTemplate.execute(status -> doIssueOne(tenantId, shopOrder, orderGood));
if(Arrays.asList(IssueOutcome.ISSUED, IssueOutcome.ALREADY_ISSUED).contains(outcome)){
release.set(true);
}
});
//6.更新商品订单为已完成、已收到赠品状态
if (release.get()) {
shopOrder.setHasTakeGift(true);
shopOrder.setUpdateTime(LocalDateTime.now());
shopOrderMapper.updateById(shopOrder);
}
}
private int issueForOrder(Integer tenantId, Set<Integer> goodsIds, ShopOrder order) { private int issueForOrder(Integer tenantId, Set<Integer> goodsIds, ShopOrder order) {
List<ShopOrderGoods> goodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId()); List<ShopOrderGoods> goodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId());
if (goodsList == null || goodsList.isEmpty()) { if (goodsList == null || goodsList.isEmpty()) {
@@ -155,15 +226,10 @@ public class GltTicketIssueService {
if (shouldCompleteOrder) { if (shouldCompleteOrder) {
LocalDateTime now = LocalDateTime.now(); LocalDateTime now = LocalDateTime.now();
// 任务执行完后将订单置为“已完成”,避免后续扫描重复处理(幂等虽可挡住,但会产生大量无意义查询)。 // 任务执行完后将订单置为“已完成”,避免后续扫描重复处理(幂等虽可挡住,但会产生大量无意义查询)。
shopOrderService.update( order.setOrderStatus(1);
new LambdaUpdateWrapper<ShopOrder>() order.setHasTakeGift(true);
.eq(ShopOrder::getOrderId, order.getOrderId()) order.setUpdateTime(LocalDateTime.now());
.eq(ShopOrder::getTenantId, tenantId) shopOrderMapper.updateById(order);
.eq(ShopOrder::getOrderStatus, 0)
.set(ShopOrder::getOrderStatus, 1)
.set(ShopOrder::getHasTakeGift, true)
.set(ShopOrder::getUpdateTime, now)
);
} }
return issuedCount; return issuedCount;
@@ -184,7 +250,7 @@ public class GltTicketIssueService {
// - 这里先对商城订单行加行锁,保证同一订单在同一时刻只会被一个事务处理。 // - 这里先对商城订单行加行锁,保证同一订单在同一时刻只会被一个事务处理。
// (注意:需数据库支持 SELECT ... FOR UPDATE且 shop_order.order_id 为主键/有索引) // (注意:需数据库支持 SELECT ... FOR UPDATE且 shop_order.order_id 为主键/有索引)
if (order.getOrderId() != null) { if (order.getOrderId() != null) {
shopOrderService.getOne( shopOrderMapper.selectOne(
new LambdaQueryWrapper<ShopOrder>() new LambdaQueryWrapper<ShopOrder>()
.eq(ShopOrder::getOrderId, order.getOrderId()) .eq(ShopOrder::getOrderId, order.getOrderId())
.eq(ShopOrder::getTenantId, tenantId) .eq(ShopOrder::getTenantId, tenantId)
@@ -304,12 +370,14 @@ public class GltTicketIssueService {
// 若启用了 releasePeriods 且首期释放时机为“支付成功当刻”,则将首期释放量直接计入可用, // 若启用了 releasePeriods 且首期释放时机为“支付成功当刻”,则将首期释放量直接计入可用,
// 避免用户刚购买后短时间内无可用水票;后续期数仍由自动释放任务按 release_time 释放。 // 避免用户刚购买后短时间内无可用水票;后续期数仍由自动释放任务按 release_time 释放。
if (useReleasePeriods && !releases.isEmpty() && !Objects.equals(template.getFirstReleaseMode(), 1)) { // if (useReleasePeriods && !releases.isEmpty() && !Objects.equals(template.getFirstReleaseMode(), 1)) {
if (!releases.isEmpty() && !Objects.equals(template.getFirstReleaseMode(), 1)) {
GltUserTicketRelease first = releases.get(0); GltUserTicketRelease first = releases.get(0);
Integer firstQtyObj = first.getReleaseQty(); Integer firstQtyObj = first.getReleaseQty();
LocalDateTime firstTime = first.getReleaseTime(); LocalDateTime firstTime = first.getReleaseTime();
int firstQty = firstQtyObj != null ? firstQtyObj : 0; int firstQty = firstQtyObj != null ? firstQtyObj : 0;
if (firstQty > 0 && (firstTime == null || !firstTime.isAfter(now))) { // if (firstQty > 0 && (firstTime == null || !firstTime.isAfter(now))) {
if (firstQty > 0) {
first.setStatus(1); first.setStatus(1);
first.setUpdateTime(now); first.setUpdateTime(now);
@@ -376,10 +444,13 @@ public class GltTicketIssueService {
// 首期释放时间 // 首期释放时间
LocalDateTime firstReleaseTime; LocalDateTime firstReleaseTime;
LocalDateTime referenceTime;
if (Objects.equals(template.getFirstReleaseMode(), 1)) { if (Objects.equals(template.getFirstReleaseMode(), 1)) {
firstReleaseTime = nextMonthSameDay(baseTime); firstReleaseTime = nextMonthSameDay(baseTime);
referenceTime = firstReleaseTime.withDayOfMonth(1).toLocalDate().atStartOfDay();
} else { } else {
firstReleaseTime = baseTime; firstReleaseTime = baseTime;
referenceTime = firstReleaseTime.withDayOfMonth(1).toLocalDate().atStartOfDay();
} }
// 每期释放数量计算 // 每期释放数量计算
@@ -393,7 +464,11 @@ public class GltTicketIssueService {
if (qty <= 0) { if (qty <= 0) {
continue; continue;
} }
list.add(buildRelease(userTicket, i, qty, firstReleaseTime.plusMonths(i), now)); if(i == 0){
list.add(buildRelease(userTicket, i, qty, firstReleaseTime, now));
}else {
list.add(buildRelease(userTicket, i, qty, referenceTime.plusMonths(i), now));
}
} }
return list; return list;
} }
@@ -410,7 +485,11 @@ public class GltTicketIssueService {
break; break;
} }
remaining -= qty; remaining -= qty;
list.add(buildRelease(userTicket, i, qty, firstReleaseTime.plusMonths(i), now)); if(i == 0){
list.add(buildRelease(userTicket, i, qty, firstReleaseTime, now));
}else {
list.add(buildRelease(userTicket, i, qty, referenceTime.plusMonths(i), now));
}
} }
return list; return list;
@@ -422,7 +501,7 @@ public class GltTicketIssueService {
LocalDateTime releaseTime, LocalDateTime releaseTime,
LocalDateTime now) { LocalDateTime now) {
GltUserTicketRelease r = new GltUserTicketRelease(); GltUserTicketRelease r = new GltUserTicketRelease();
r.setUserTicketId(userTicket.getId() != null ? userTicket.getId().longValue() : null); r.setUserTicketId(userTicket.getId() != null ? userTicket.getId() : null);
r.setUserId(userTicket.getUserId()); r.setUserId(userTicket.getUserId());
r.setPeriodNo(periodNo); r.setPeriodNo(periodNo);
r.setReleaseQty(releaseQty); r.setReleaseQty(releaseQty);

View File

@@ -2,6 +2,7 @@ package com.gxwebsoft.glt.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.glt.dto.GltTransferOrderDto;
import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.param.GltTicketOrderParam; import com.gxwebsoft.glt.param.GltTicketOrderParam;
@@ -16,10 +17,10 @@ import java.time.LocalDateTime;
*/ */
public interface GltTicketOrderService extends IService<GltTicketOrder> { public interface GltTicketOrderService extends IService<GltTicketOrder> {
int DELIVERY_STATUS_WAITING = 10; int DELIVERY_STATUS_WAITING = 10; //待配送
int DELIVERY_STATUS_DELIVERING = 20; int DELIVERY_STATUS_DELIVERING = 20; //配送中
int DELIVERY_STATUS_WAIT_CONFIRM = 30; int DELIVERY_STATUS_WAIT_CONFIRM = 30; //等待收货
int DELIVERY_STATUS_FINISHED = 40; int DELIVERY_STATUS_FINISHED = 40; //收货完成
int RECEIVE_CONFIRM_TYPE_MANUAL = 10; int RECEIVE_CONFIRM_TYPE_MANUAL = 10;
int RECEIVE_CONFIRM_TYPE_PHOTO = 20; int RECEIVE_CONFIRM_TYPE_PHOTO = 20;
@@ -64,6 +65,13 @@ public interface GltTicketOrderService extends IService<GltTicketOrder> {
*/ */
void accept(Integer id, Integer riderId, Integer tenantId); void accept(Integer id, Integer riderId, Integer tenantId);
/**
* 配送员转单
* @param orderDto
* @return
*/
Boolean transferOrder(GltTransferOrderDto orderDto);
/** /**
* 指派/接单成功后,同步关联商城订单发货状态为“已发货”(deliveryStatus=20)。 * 指派/接单成功后,同步关联商城订单发货状态为“已发货”(deliveryStatus=20)。
* *
@@ -76,7 +84,7 @@ public interface GltTicketOrderService extends IService<GltTicketOrder> {
* *
* <p>用于后台直接改 deliveryStatus=40 等不经过 confirmReceive/autoConfirmTimeout 的兜底同步。</p> * <p>用于后台直接改 deliveryStatus=40 等不经过 confirmReceive/autoConfirmTimeout 的兜底同步。</p>
*/ */
void markShopOrderCompletedAfterTicketFinished(Integer ticketOrderId, Integer tenantId); void markShopOrderCompletedAfterTicketFinished(Integer id);
/** /**
* 配送员开始配送10 -> 20并写 sendStartTime。 * 配送员开始配送10 -> 20并写 sendStartTime。
@@ -106,4 +114,10 @@ public interface GltTicketOrderService extends IService<GltTicketOrder> {
*/ */
int autoConfirmTimeout(Integer tenantId, LocalDateTime now, int timeoutHours, int batchSize); int autoConfirmTimeout(Integer tenantId, LocalDateTime now, int timeoutHours, int batchSize);
/**
* 派送订单调度
* @return
*/
Boolean dispatchOrder(String orderNo, Integer tenantId);
} }

View File

@@ -133,7 +133,7 @@ public class GltTicketRevokeService {
LambdaUpdateWrapper<GltUserTicketRelease> uw = new LambdaUpdateWrapper<GltUserTicketRelease>() LambdaUpdateWrapper<GltUserTicketRelease> uw = new LambdaUpdateWrapper<GltUserTicketRelease>()
.eq(GltUserTicketRelease::getTenantId, tenantId) .eq(GltUserTicketRelease::getTenantId, tenantId)
.eq(GltUserTicketRelease::getDeleted, 0) .eq(GltUserTicketRelease::getDeleted, 0)
.eq(GltUserTicketRelease::getUserTicketId, userTicketId.longValue()) .eq(GltUserTicketRelease::getUserTicketId, userTicketId)
// status 为空时也视为“未完成” // status 为空时也视为“未完成”
.and(w -> w.ne(GltUserTicketRelease::getStatus, RELEASE_STATUS_DONE) .and(w -> w.ne(GltUserTicketRelease::getStatus, RELEASE_STATUS_DONE)
.or().isNull(GltUserTicketRelease::getStatus)) .or().isNull(GltUserTicketRelease::getStatus))

View File

@@ -17,10 +17,8 @@ public interface GltUserTicketAutoReleaseService {
int releaseDue(LocalDateTime now, int batchSize); int releaseDue(LocalDateTime now, int batchSize);
/** /**
* 释放到期的冻结水票(使用系统当前时间) * 释放到期的冻结水票【当次执行1000条】
*/ */
default int releaseDue(int batchSize) { void releaseTask();
return releaseDue(LocalDateTime.now(), batchSize);
}
} }

View File

@@ -1,14 +1,12 @@
package com.gxwebsoft.glt.service.impl; package com.gxwebsoft.glt.service.impl;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.config.WxMaConfig;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil; import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.gxwebsoft.common.core.exception.BusinessException; import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.utils.RedisUtil; import com.gxwebsoft.common.core.utils.DateTimeUtil;
import com.gxwebsoft.glt.dto.NoticeRiderNewOrderDto;
import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.service.GltSubscribeMessageService; import com.gxwebsoft.glt.service.GltSubscribeMessageService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -19,7 +17,8 @@ import javax.annotation.Resource;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static com.gxwebsoft.common.core.constants.RedisConstants.*; import static com.gxwebsoft.common.core.constants.RedisConstants.ACCESS_TOKEN_KEY;
import static com.gxwebsoft.common.core.constants.RedisConstants.MP_WX_KEY;
/** /**
* 微信订阅消息服务实现 * 微信订阅消息服务实现
@@ -43,7 +42,34 @@ public class GltSubscribeMessageServiceImpl implements GltSubscribeMessageServic
* 模板名称:订单配送通知 * 模板名称:订单配送通知
* 关键词:订单编号、订单内容、配送地址、订单金额 * 关键词:订单编号、订单内容、配送地址、订单金额
*/ */
private static final String SUBSCRIBE_TEMPLATE_ID = "YOUR_TEMPLATE_ID"; // TODO: 替换为实际模板ID private static final String ORDER_DELIVERY_ID = "vSMSqGVy3aG1RuzQUZlk282p5hCvuMBcHvix1AFhN90";
public void sendRiderNewOrderNotice(NoticeRiderNewOrderDto entity){
//1.获取微信accessToken
String accessToken = getAccessToken(entity.getTenantId());
if(accessToken == null){
log.error("配送发单消息发生失败获取accessToken失败");
return;
}
//2.品名字段最大能发送20个长度字符大于15的长度需做处理
String goodsName = entity.getGoodsName();
int keepLength = 15;
if (goodsName.length() > keepLength) {
entity.setGoodsName(goodsName.substring(0, keepLength) + "...");
}
//3.组装入参
Map<String, Object> data = new HashMap<>();
data.put("character_string1", Map.of("value", String.valueOf(entity.getOrderNo())));
data.put("thing22", Map.of("value", String.valueOf(entity.getGoodsName())));
data.put("number20", Map.of("value", String.valueOf(entity.getProductCount())));
data.put("time24", Map.of("value", DateTimeUtil.formatDateTime(entity.getCreateTime(), "yyyy-MM-dd HH:mm:ss")));
//推送订阅消息
sendSubscribeMessage(accessToken, entity.getOpenId(), data);
}
/** /**
* 发送新订单通知给配送员 * 发送新订单通知给配送员
@@ -65,7 +91,7 @@ public class GltSubscribeMessageServiceImpl implements GltSubscribeMessageServic
// 构建消息内容 // 构建消息内容
Map<String, Object> data = new HashMap<>(); Map<String, Object> data = new HashMap<>();
data.put("phrase1", Map.of("value", "待配送")); // 订单状态 data.put("phrase1", Map.of("value", "待配送")); // 订单状态
data.put("character_string2", Map.of("value", String.valueOf(order.getId()))); // 订单编号 data.put("character_string2", Map.of("value", String.valueOf(order.getOrderNo()))); // 订单编号
data.put("thing3", Map.of("value", truncateStr(order.getAddress(), 20))); // 配送地址 data.put("thing3", Map.of("value", truncateStr(order.getAddress(), 20))); // 配送地址
data.put("number4", Map.of("value", String.valueOf(order.getTotalNum()))); // 商品数量 data.put("number4", Map.of("value", String.valueOf(order.getTotalNum()))); // 商品数量
data.put("time5", Map.of("value", formatTime(order.getSendTime()))); // 期望送达时间 data.put("time5", Map.of("value", formatTime(order.getSendTime()))); // 期望送达时间
@@ -196,8 +222,8 @@ public class GltSubscribeMessageServiceImpl implements GltSubscribeMessageServic
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("touser", openId); // 用户 openid params.put("touser", openId); // 用户 openid
params.put("template_id", SUBSCRIBE_TEMPLATE_ID); // 模板ID params.put("template_id", ORDER_DELIVERY_ID); // 模板ID
params.put("page", "pages/rider/orders/index"); // 点击后跳转的页面 // params.put("page", "pages/rider/orders/index"); // 点击后跳转的页面
params.put("data", data); params.put("data", data);
String response = HttpUtil.createPost(url) String response = HttpUtil.createPost(url)
@@ -208,14 +234,14 @@ public class GltSubscribeMessageServiceImpl implements GltSubscribeMessageServic
.body(); .body();
JSONObject result = JSON.parseObject(response); JSONObject result = JSON.parseObject(response);
int errcode = result.getIntValue("errcode"); int errCode = result.getIntValue("errcode");
if (errcode == 0) { if (errCode == 0) {
log.info("订阅消息发送成功 - openId={}", openId); log.info("订阅消息发送成功 - openId={}", openId);
return true; return true;
} else { } else {
log.warn("订阅消息发送失败 - openId={}, errcode={}, errmsg={}", log.warn("订阅消息发送失败 - openId={}, errcode={}, errmsg={}",
openId, errcode, result.getString("errmsg")); openId, errCode, result.getString("errmsg"));
return false; return false;
} }
} }

View File

@@ -1,44 +1,60 @@
package com.gxwebsoft.glt.service.impl; package com.gxwebsoft.glt.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gxwebsoft.common.core.enums.ShopDealerCapitalUpdateEnum;
import com.gxwebsoft.common.core.enums.ShopDealerTypeEnum;
import com.gxwebsoft.common.core.exception.BusinessException; import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.common.core.exception.enums.GlobalErrorCodeConstants;
import com.gxwebsoft.common.core.utils.LoginUserUtil;
import com.gxwebsoft.common.core.web.PageParam; import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.mapper.UserMapper; import com.gxwebsoft.common.system.mapper.UserMapper;
import com.gxwebsoft.common.system.redis.OrderNoUtils;
import com.gxwebsoft.glt.dto.GltTransferOrderDto;
import com.gxwebsoft.glt.dto.NoticeRiderNewOrderDto;
import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketOrder;
import com.gxwebsoft.glt.entity.GltUserTicket; import com.gxwebsoft.glt.entity.GltUserTicket;
import com.gxwebsoft.glt.entity.GltUserTicketLog; import com.gxwebsoft.glt.entity.GltUserTicketLog;
import com.gxwebsoft.glt.mapper.GltTicketOrderMapper; import com.gxwebsoft.glt.mapper.GltTicketOrderMapper;
import com.gxwebsoft.glt.mapper.GltUserTicketMapper; import com.gxwebsoft.glt.mapper.GltUserTicketMapper;
import com.gxwebsoft.glt.param.GltTicketOrderParam; import com.gxwebsoft.glt.param.GltTicketOrderParam;
import com.gxwebsoft.glt.service.GltSubscribeMessageService;
import com.gxwebsoft.glt.service.GltTicketOrderService; import com.gxwebsoft.glt.service.GltTicketOrderService;
import com.gxwebsoft.glt.service.GltUserTicketLogService; import com.gxwebsoft.glt.service.GltUserTicketLogService;
import com.gxwebsoft.glt.service.GltUserTicketService; import com.gxwebsoft.glt.service.GltUserTicketService;
import com.gxwebsoft.shop.entity.ShopDealerCapital; import com.gxwebsoft.shop.dto.ShopDealerUserReduceDto;
import com.gxwebsoft.shop.entity.ShopDealerUser; import com.gxwebsoft.shop.entity.*;
import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.mapper.ShopGoodsMapper;
import com.gxwebsoft.shop.entity.ShopOrderGoods; import com.gxwebsoft.shop.mapper.ShopStoreRiderMapper;
import com.gxwebsoft.shop.mapper.ShopUserAddressMapper;
import com.gxwebsoft.shop.service.ShopDealerCapitalService; import com.gxwebsoft.shop.service.ShopDealerCapitalService;
import com.gxwebsoft.shop.service.ShopDealerUserService; import com.gxwebsoft.shop.service.ShopDealerUserService;
import com.gxwebsoft.shop.service.ShopOrderGoodsService; import com.gxwebsoft.shop.service.ShopOrderGoodsService;
import com.gxwebsoft.shop.service.ShopOrderService; import com.gxwebsoft.shop.service.ShopOrderService;
import com.gxwebsoft.shop.vo.ShopOrderGoodsInfoVO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.StringUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/** /**
* 送水订单Service实现 * 送水订单Service实现
@@ -83,11 +99,54 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
@Resource @Resource
private ShopOrderGoodsService shopOrderGoodsService; private ShopOrderGoodsService shopOrderGoodsService;
@Resource
private ShopUserAddressMapper shopUserAddressMapper;
@Resource
private OrderNoUtils orderNoUtils;
@Resource
private ShopGoodsMapper shopGoodsMapper;
@Resource
private ShopStoreRiderMapper shopStoreRiderMapper;
@Resource
private GltSubscribeMessageService gltSubscribeMessageService;
// 轮询指针(高并发安全)
private final AtomicInteger index = new AtomicInteger(0);
@Override @Override
public PageResult<GltTicketOrder> pageRel(GltTicketOrderParam param) { public PageResult<GltTicketOrder> pageRel(GltTicketOrderParam param) {
PageParam<GltTicketOrder, GltTicketOrderParam> page = new PageParam<>(param); PageParam<GltTicketOrder, GltTicketOrderParam> page = new PageParam<>(param);
page.setDefaultOrder("sort_number asc, create_time desc"); page.setDefaultOrder("create_time desc");
List<GltTicketOrder> list = baseMapper.selectPageRel(page, param); List<GltTicketOrder> list = baseMapper.selectPageRel(page, param);
if(CollectionUtils.isNotEmpty(list)){
List<Integer> addressIdList = list.stream().map(GltTicketOrder::getAddressId).distinct().collect(Collectors.toList());
List<String> orderNoList = list.stream().filter(gltTicketOrder -> StrUtil.isNotBlank(gltTicketOrder.getOrderNo())).map(GltTicketOrder::getOrderNo).distinct().collect(Collectors.toList());
List<ShopOrderGoodsInfoVO> orderGoodsInfoVOList = new ArrayList<>();
if(CollectionUtils.isNotEmpty(orderNoList)){
orderGoodsInfoVOList = shopOrderService.getOrderGoodsInfoByOrderNos(orderNoList);
}
List<ShopUserAddress> userAddressList = shopUserAddressMapper.selectBatchIds(addressIdList);
List<ShopOrderGoodsInfoVO> finalOrderGoodsInfoVOList = orderGoodsInfoVOList;
list.forEach(ticketOrder ->{
ShopUserAddress shopUserAddress = userAddressList.stream().filter(address -> ticketOrder.getAddressId().equals(address.getId())).findFirst().orElse(null);
if(shopUserAddress != null){
ticketOrder.setFullAddress(shopUserAddress.getFullAddress());
}
if(StrUtil.isNotBlank(ticketOrder.getOrderNo())){
ShopOrderGoodsInfoVO shopOrderGoodsInfoVO = finalOrderGoodsInfoVOList.stream().filter(orderGoodsInfoVO -> ticketOrder.getOrderNo().equals(orderGoodsInfoVO.getOrderNo())).findFirst().orElse(null);
if(shopOrderGoodsInfoVO != null){
ticketOrder.setGoodsName(shopOrderGoodsInfoVO.getGoodsName());
ticketOrder.setOrderStatus(shopOrderGoodsInfoVO.getOrderStatus());
}
}
});
}
return new PageResult<>(list, page.getTotal()); return new PageResult<>(list, page.getTotal());
} }
@@ -116,6 +175,10 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
if (userId == null) { if (userId == null) {
throw new BusinessException("请先登录"); throw new BusinessException("请先登录");
} }
String no = orderNoUtils.generate("S");
gltTicketOrder.setNo(no);
Integer userTicketId = gltTicketOrder.getUserTicketId(); Integer userTicketId = gltTicketOrder.getUserTicketId();
if (userTicketId == null) { if (userTicketId == null) {
throw new BusinessException("userTicketId不能为空"); throw new BusinessException("userTicketId不能为空");
@@ -151,6 +214,7 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
} }
// 4) 插入 glt_ticket_orderstoreId/addressId/totalNum/buyerRemarks… // 4) 插入 glt_ticket_orderstoreId/addressId/totalNum/buyerRemarks…
gltTicketOrder.setOrderNo(userTicket.getOrderNo());
gltTicketOrder.setUserId(userId); gltTicketOrder.setUserId(userId);
// 订单基础字段由后端兜底,避免前端误传/恶意传参 // 订单基础字段由后端兜底,避免前端误传/恶意传参
gltTicketOrder.setStatus(0); gltTicketOrder.setStatus(0);
@@ -168,10 +232,13 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
gltTicketOrder.setCreateTime(now); gltTicketOrder.setCreateTime(now);
} }
// “立刻送水”下单场景不再需要前端选择配送时间;若未传则默认当前时间,便于排序与派单。 // “立刻送水”下单场景不再需要前端选择配送时间;若未传则默认当前时间,便于排序与派单。
if (!StringUtils.hasText(gltTicketOrder.getSendTime())) { if(gltTicketOrder.getSendEndTime() == null){
gltTicketOrder.setSendTime(now.format(SEND_TIME_FMT)); gltTicketOrder.setSendTime(now.format(SEND_TIME_FMT));
} }
gltTicketOrder.setUpdateTime(now); gltTicketOrder.setUpdateTime(now);
//每个骑手平等获取派单
gltTicketOrder.setRiderId(getRiderUserId());
if (!this.save(gltTicketOrder)) { if (!this.save(gltTicketOrder)) {
throw new BusinessException("创建订单失败"); throw new BusinessException("创建订单失败");
} }
@@ -207,6 +274,29 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
throw new BusinessException("写入核销记录失败"); throw new BusinessException("写入核销记录失败");
} }
//发送配送师傅派单配送消息
if(gltTicketOrder.getRiderId() != null){
User user = userMapper.getById(gltTicketOrder.getRiderId());
if(user != null){
NoticeRiderNewOrderDto noticeDto = new NoticeRiderNewOrderDto();
noticeDto.setOrderNo(gltTicketOrder.getOrderNo());
noticeDto.setGoodsName("商品信息见订单详情");
noticeDto.setProductCount(gltTicketOrder.getTotalNum());
noticeDto.setCreateTime(gltTicketOrder.getCreateTime());
noticeDto.setTenantId(tenantId);
noticeDto.setOpenId(user.getOpenid());
ShopOrder shopOrder = shopOrderService.getByOrderNo(gltTicketOrder.getOrderNo(), tenantId);
if(shopOrder != null){
Integer formId = shopOrder.getFormId();
ShopGoods shopGoods = shopGoodsMapper.selectById(formId);
if(shopGoods != null){
noticeDto.setGoodsName(shopGoods.getName());
}
}
gltSubscribeMessageService.sendRiderNewOrderNotice(noticeDto);
}
}
return gltTicketOrder; return gltTicketOrder;
} }
@@ -274,7 +364,7 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
.update(); .update();
if (ok) { if (ok) {
// 接单成功后同步商城订单发货状态10未发货 -> 20已发货 // 接单成功后同步商城订单发货状态10未发货 -> 20已发货
updateShopOrderDeliveryStatusAfterAccept(id, tenantId, riderId, now); updateShopOrderDeliveryStatusAfterAcceptV2(id, tenantId, riderId, now);
return; return;
} }
@@ -294,13 +384,34 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
} }
@Override @Override
public void markShopOrderShippedAfterRiderAssigned(Integer ticketOrderId, Integer tenantId, Integer riderId) { public Boolean transferOrder(GltTransferOrderDto orderDto) {
updateShopOrderDeliveryStatusAfterAccept(ticketOrderId, tenantId, riderId, LocalDateTime.now()); User loginUser = LoginUserUtil.getLoginUser();
if(loginUser == null){
throw new BusinessException(GlobalErrorCodeConstants.UNAUTHORIZED.getMsg());
}
GltTicketOrder gltTicketOrder = baseMapper.selectById(orderDto.getId());
if(gltTicketOrder != null){
if(!gltTicketOrder.getRiderId().equals(loginUser.getUserId())){
throw new BusinessException("该订单归属非本人,转单操作失败!");
}
gltTicketOrder.setRiderId(orderDto.getUserId());
gltTicketOrder.setUpdateTime(LocalDateTime.now());
return baseMapper.updateById(gltTicketOrder) > 0;
}else {
throw new BusinessException(GlobalErrorCodeConstants.NOT_FOUND.getMsg());
}
} }
@Override @Override
public void markShopOrderCompletedAfterTicketFinished(Integer ticketOrderId, Integer tenantId) { public void markShopOrderShippedAfterRiderAssigned(Integer ticketOrderId, Integer tenantId, Integer riderId) {
updateShopOrderOrderStatusAfterTicketFinished(ticketOrderId, tenantId, LocalDateTime.now()); updateShopOrderDeliveryStatusAfterAcceptV2(ticketOrderId, tenantId, riderId, LocalDateTime.now());
}
@Override
public void markShopOrderCompletedAfterTicketFinished(Integer id) {
updateShopOrderOrderStatusAfterTicketFinishedV2(id);
} }
private void updateShopOrderDeliveryStatusAfterAccept(Integer ticketOrderId, Integer tenantId, Integer riderId, LocalDateTime now) { private void updateShopOrderDeliveryStatusAfterAccept(Integer ticketOrderId, Integer tenantId, Integer riderId, LocalDateTime now) {
@@ -370,22 +481,6 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
shopOrderNo = order.getOrderNo(); shopOrderNo = order.getOrderNo();
} }
} }
LambdaUpdateWrapper<GltUserTicket> backfill = new LambdaUpdateWrapper<GltUserTicket>()
.eq(GltUserTicket::getTenantId, tenantId)
.eq(GltUserTicket::getDeleted, 0)
.eq(GltUserTicket::getId, userTicket.getId());
backfill.set(GltUserTicket::getOrderId, shopOrderId);
if (!StringUtils.hasText(userTicket.getOrderNo()) && StringUtils.hasText(shopOrderNo)) {
backfill.set(GltUserTicket::getOrderNo, shopOrderNo);
}
backfill.set(GltUserTicket::getUpdateTime, now);
try {
gltUserTicketService.update(backfill);
} catch (Exception e) {
log.debug("回填水票关联商城订单信息失败(不影响主流程) - tenantId={}, userTicketId={}, orderId={}, orderNo={}",
tenantId, userTicket.getId(), shopOrderId, shopOrderNo, e);
}
} }
LambdaUpdateWrapper<ShopOrder> uw = new LambdaUpdateWrapper<ShopOrder>() LambdaUpdateWrapper<ShopOrder> uw = new LambdaUpdateWrapper<ShopOrder>()
@@ -433,6 +528,20 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
} }
} }
private void updateShopOrderDeliveryStatusAfterAcceptV2(Integer ticketOrderId, Integer tenantId, Integer riderId, LocalDateTime now) {
GltTicketOrder gltTicketOrder = baseMapper.selectById(ticketOrderId);
if(gltTicketOrder != null && StrUtil.isNotBlank(gltTicketOrder.getOrderNo())){
String orderNo = gltTicketOrder.getOrderNo();
ShopOrder shopOrder = shopOrderService.getByOrderNo(orderNo, tenantId);
if(shopOrder != null && shopOrder.getOrderStatus() == 0){
shopOrder.setDeliveryStatus(20);
shopOrder.setUpdateTime(now);
shopOrderService.updateById(shopOrder);
}
}
}
@Override @Override
public void start(Integer id, Integer riderId, Integer tenantId) { public void start(Integer id, Integer riderId, Integer tenantId) {
if (id == null) { if (id == null) {
@@ -656,7 +765,80 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
return confirmed; return confirmed;
} }
private void updateShopOrderOrderStatusAfterTicketFinished(Integer ticketOrderId, Integer tenantId, LocalDateTime now) { @Override
public Boolean dispatchOrder(String orderNo, Integer tenantId) {
ShopOrder shopOrder = shopOrderService.getByOrderNo(orderNo, tenantId);
if(shopOrder != null){
LocalDateTime now = LocalDateTime.now();
//只有:1-及时自配送、3-预约自配送 方式会生成调度单
if(Arrays.asList(1, 3).contains(shopOrder.getOrderType())){
GltTicketOrder dispatchOrder = BeanUtil.toBean(shopOrder, GltTicketOrder.class);
String no = orderNoUtils.generate("S");
dispatchOrder.setNo(no);
dispatchOrder.setRiderId(getRiderUserId());
dispatchOrder.setSendTime(now.format(SEND_TIME_FMT));
Integer deliveryMethod = shopOrder.getDeliveryMethod();
if(deliveryMethod != null && deliveryMethod == 1){
dispatchOrder.setDeliveryMethod("stairs");
}else {
dispatchOrder.setDeliveryMethod("elevator");
}
dispatchOrder.setComments("系统自动派单");
dispatchOrder.setCreateTime(now);
dispatchOrder.setUpdateTime(now);
baseMapper.insert(dispatchOrder);
//推送配送师傅接单提醒
if(dispatchOrder.getRiderId() != null){
User user = userMapper.getById(dispatchOrder.getRiderId());
if(user != null){
NoticeRiderNewOrderDto noticeDto = new NoticeRiderNewOrderDto();
noticeDto.setOrderNo(dispatchOrder.getOrderNo());
noticeDto.setGoodsName("商品信息见订单详情");
noticeDto.setProductCount(dispatchOrder.getTotalNum());
noticeDto.setCreateTime(dispatchOrder.getCreateTime());
noticeDto.setTenantId(tenantId);
noticeDto.setOpenId(user.getOpenid());
if(shopOrder != null){
Integer formId = shopOrder.getFormId();
ShopGoods shopGoods = shopGoodsMapper.selectById(formId);
if(shopGoods != null){
noticeDto.setGoodsName(shopGoods.getName());
}
}
gltSubscribeMessageService.sendRiderNewOrderNotice(noticeDto);
}
}
}
}
return Boolean.TRUE;
}
/**
* 每个骑手平等获取派单
* @return
*/
private Integer getRiderUserId(){
List<ShopStoreRider> shopStoreRiders = shopStoreRiderMapper.selectList(new LambdaQueryWrapper<ShopStoreRider>().select(ShopStoreRider::getUserId).in(ShopStoreRider::getWorkStatus, Arrays.asList(1, 2)));
if(CollectionUtils.isNotEmpty(shopStoreRiders)){
List<Integer> riderIdList = shopStoreRiders.stream().map(ShopStoreRider::getUserId).distinct().collect(Collectors.toList());
int i = index.getAndIncrement() % riderIdList.size();
return riderIdList.get(i);
}
return null;
}
/**
* 更新送水订单为已完成状态
* @param ticketOrderId
* @param tenantId
* @param now
*/
@Transactional
public void updateShopOrderOrderStatusAfterTicketFinished(Integer ticketOrderId, Integer tenantId, LocalDateTime now) {
if (ticketOrderId == null || tenantId == null) { if (ticketOrderId == null || tenantId == null) {
return; return;
} }
@@ -666,7 +848,8 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
// 找到关联水票的商城订单glt_user_ticket.orderId / orderNo // 找到关联水票的商城订单glt_user_ticket.orderId / orderNo
GltTicketOrder ticketOrder = this.lambdaQuery() GltTicketOrder ticketOrder = this.lambdaQuery()
.select(GltTicketOrder::getId, GltTicketOrder::getUserTicketId) .select(GltTicketOrder::getId, GltTicketOrder::getUserTicketId, GltTicketOrder::getTotalNum, GltTicketOrder::getRiderId,
GltTicketOrder::getUserId, GltTicketOrder::getNo)
.eq(GltTicketOrder::getId, ticketOrderId) .eq(GltTicketOrder::getId, ticketOrderId)
.eq(GltTicketOrder::getTenantId, tenantId) .eq(GltTicketOrder::getTenantId, tenantId)
.eq(GltTicketOrder::getDeleted, 0) .eq(GltTicketOrder::getDeleted, 0)
@@ -742,6 +925,80 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
} }
} }
ShopOrder order = shopOrderService.getByOrderNo(userTicket.getOrderNo(), userTicket.getTenantId());
//生成配送师傅可提现账户分佣金额数据【配送奖励(按商品设置)、配送提成(每桶0.1)】
int qty = ticketOrder.getTotalNum() == null ? 0 : ticketOrder.getTotalNum();
if (qty > 0) { //配送提成(每桶0.1)
BigDecimal money = RIDER_UNIT_COMMISSION
.multiply(BigDecimal.valueOf(qty))
.setScale(RIDER_COMMISSION_SCALE, RoundingMode.HALF_UP);
if (money.signum() > 0) {
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.WITHDRAW_ACCOUNT);
reduceDto.setUserId(ticketOrder.getRiderId());
reduceDto.setOrderUserId(ticketOrder.getUserId());
if(Arrays.asList(1, 3).contains(order.getOrderType())){
reduceDto.setOrderNo(order.getOrderNo());
}else {
reduceDto.setOrderNo(ticketOrder.getNo());
}
reduceDto.setPrice(money);
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DELIVERY_INCOME);
shopDealerUserService.reduceBalance(reduceDto);
}
}
//配送奖励(按商品设置)
Integer goodsId = userTicket.getGoodsId();
ShopGoods shopGood = shopGoodsMapper.selectById(goodsId);
if(shopGood != null && order != null){
Integer commissionType = shopGood.getCommissionType();
BigDecimal money = BigDecimal.ZERO;
if(commissionType == 10){ //按金额
money = shopGood.getDeliveryMoney();
}else { //按比率
money = order.getPayPrice().multiply(shopGood.getDeliveryMoney()).divide(BigDecimal.valueOf(100), 3, RoundingMode.HALF_UP);
}
if(money.compareTo(BigDecimal.ZERO) > 0){
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.WITHDRAW_ACCOUNT);
reduceDto.setUserId(ticketOrder.getRiderId());
reduceDto.setOrderUserId(ticketOrder.getUserId());
if(Arrays.asList(1, 3).contains(order.getOrderType())){
reduceDto.setOrderNo(order.getOrderNo());
}else {
reduceDto.setOrderNo(ticketOrder.getNo());
}
reduceDto.setPrice(money);
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DELIVERY_REWARD);
shopDealerUserService.reduceBalance(reduceDto);
}
}
//配送费结算
if(Arrays.asList(1, 3).contains(order.getOrderType()) && order.getDeliveryFee().compareTo(BigDecimal.ZERO) > 0){
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.WITHDRAW_ACCOUNT);
reduceDto.setUserId(ticketOrder.getRiderId());
reduceDto.setOrderUserId(ticketOrder.getUserId());
reduceDto.setOrderNo(order.getOrderNo());
reduceDto.setPrice(order.getDeliveryFee());
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DELIVERY_FLOOR_FEE);
shopDealerUserService.reduceBalance(reduceDto);
}
//查询未完成订单,完成资金解冻
if(order != null && order.getOrderStatus() == 0){
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.DEFROST);
reduceDto.setOrderUserId(order.getUserId());
reduceDto.setOrderNo(order.getOrderNo());
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.FREEZE_MONEY_THAW);
//按订单号资金解冻
shopDealerUserService.reduceBalance(reduceDto);
}
LambdaUpdateWrapper<ShopOrder> uw = new LambdaUpdateWrapper<ShopOrder>() LambdaUpdateWrapper<ShopOrder> uw = new LambdaUpdateWrapper<ShopOrder>()
.eq(ShopOrder::getTenantId, tenantId) .eq(ShopOrder::getTenantId, tenantId)
.eq(ShopOrder::getDeleted, 0) .eq(ShopOrder::getDeleted, 0)
@@ -753,7 +1010,6 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
} else { } else {
uw.eq(ShopOrder::getOrderNo, shopOrderNo); uw.eq(ShopOrder::getOrderNo, shopOrderNo);
} }
boolean updated = shopOrderService.update(uw); boolean updated = shopOrderService.update(uw);
if (updated) { if (updated) {
return; return;
@@ -775,6 +1031,104 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
} }
} }
/**
* 更新送水订单为已完成状态
* @param id 送水订单ID
*/
@Transactional
public void updateShopOrderOrderStatusAfterTicketFinishedV2(Integer id) {
LocalDateTime now = LocalDateTime.now();
if(id == null){
return;
}
//1.找到关联水票的商城订单
GltTicketOrder ticketOrder = baseMapper.selectById(id);
if (ticketOrder == null) {
return;
}
ShopOrder order = shopOrderService.getByOrderNo(ticketOrder.getOrderNo(), ticketOrder.getTenantId());
//2.配送提成(每桶0.1)
int qty = ticketOrder.getTotalNum() == null ? 0 : ticketOrder.getTotalNum();
if (qty > 0) {
BigDecimal money = RIDER_UNIT_COMMISSION
.multiply(BigDecimal.valueOf(qty))
.setScale(RIDER_COMMISSION_SCALE, RoundingMode.HALF_UP);
if (money.signum() > 0) {
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.WITHDRAW_ACCOUNT);
reduceDto.setUserId(ticketOrder.getRiderId());
reduceDto.setOrderUserId(ticketOrder.getUserId());
if(Arrays.asList(1, 3).contains(order.getOrderType())){
reduceDto.setOrderNo(order.getOrderNo());
}else {
reduceDto.setOrderNo(ticketOrder.getNo());
}
reduceDto.setPrice(money);
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DELIVERY_INCOME);
shopDealerUserService.reduceBalance(reduceDto);
}
}
//3.配送奖励(按商品设置)
Integer goodsId = order.getFormId();
ShopGoods shopGood = shopGoodsMapper.selectById(goodsId);
if(shopGood != null && order != null){
Integer commissionType = shopGood.getCommissionType();
BigDecimal money = BigDecimal.ZERO;
if(commissionType == 10){ //按金额
money = shopGood.getDeliveryMoney();
}else { //按比率
money = order.getPayPrice().multiply(shopGood.getDeliveryMoney()).divide(BigDecimal.valueOf(100), 3, RoundingMode.HALF_UP);
}
if(money.compareTo(BigDecimal.ZERO) > 0){
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.WITHDRAW_ACCOUNT);
reduceDto.setUserId(ticketOrder.getRiderId());
reduceDto.setOrderUserId(ticketOrder.getUserId());
if(Arrays.asList(1, 3).contains(order.getOrderType())){
reduceDto.setOrderNo(order.getOrderNo());
}else {
reduceDto.setOrderNo(ticketOrder.getNo());
}
reduceDto.setPrice(money);
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DELIVERY_REWARD);
shopDealerUserService.reduceBalance(reduceDto);
}
}
//4.配送费结算
if(Arrays.asList(1, 3).contains(order.getOrderType()) && order.getDeliveryFee().compareTo(BigDecimal.ZERO) > 0){
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.WITHDRAW_ACCOUNT);
reduceDto.setUserId(ticketOrder.getRiderId());
reduceDto.setOrderUserId(ticketOrder.getUserId());
reduceDto.setOrderNo(order.getOrderNo());
reduceDto.setPrice(order.getDeliveryFee());
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DELIVERY_FLOOR_FEE);
shopDealerUserService.reduceBalance(reduceDto);
}
//5.查询未完成订单,完成资金解冻
if(order != null && order.getOrderStatus() == 0){
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.DEFROST);
reduceDto.setOrderUserId(order.getUserId());
reduceDto.setOrderNo(order.getOrderNo());
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.FREEZE_MONEY_THAW);
//按订单号资金解冻
shopDealerUserService.reduceBalance(reduceDto);
}
//5.调整订单为已完成、配送完成状态
order.setOrderStatus(1);
order.setDeliveryStatus(40);
order.setUpdateTime(now);
shopOrderService.updateById(order);
}
private void settleRiderCommissionIfEligible(Integer ticketOrderId, Integer tenantId, boolean requirePhoto) { private void settleRiderCommissionIfEligible(Integer ticketOrderId, Integer tenantId, boolean requirePhoto) {
if (ticketOrderId == null || tenantId == null) { if (ticketOrderId == null || tenantId == null) {
return; return;

View File

@@ -1,5 +1,6 @@
package com.gxwebsoft.glt.service.impl; package com.gxwebsoft.glt.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.glt.entity.GltUserTicket; import com.gxwebsoft.glt.entity.GltUserTicket;
import com.gxwebsoft.glt.entity.GltUserTicketLog; import com.gxwebsoft.glt.entity.GltUserTicketLog;
import com.gxwebsoft.glt.entity.GltUserTicketRelease; import com.gxwebsoft.glt.entity.GltUserTicketRelease;
@@ -7,13 +8,20 @@ import com.gxwebsoft.glt.mapper.GltUserTicketLogMapper;
import com.gxwebsoft.glt.mapper.GltUserTicketMapper; import com.gxwebsoft.glt.mapper.GltUserTicketMapper;
import com.gxwebsoft.glt.mapper.GltUserTicketReleaseMapper; import com.gxwebsoft.glt.mapper.GltUserTicketReleaseMapper;
import com.gxwebsoft.glt.service.GltUserTicketAutoReleaseService; import com.gxwebsoft.glt.service.GltUserTicketAutoReleaseService;
import lombok.RequiredArgsConstructor; import com.gxwebsoft.glt.service.GltUserTicketLogService;
import com.gxwebsoft.glt.service.GltUserTicketReleaseService;
import com.gxwebsoft.glt.service.GltUserTicketService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
/** /**
* 冻结水票自动释放实现: * 冻结水票自动释放实现:
@@ -23,7 +31,7 @@ import java.util.List;
*/ */
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @AllArgsConstructor
public class GltUserTicketAutoReleaseServiceImpl implements GltUserTicketAutoReleaseService { public class GltUserTicketAutoReleaseServiceImpl implements GltUserTicketAutoReleaseService {
/** /**
@@ -44,6 +52,13 @@ public class GltUserTicketAutoReleaseServiceImpl implements GltUserTicketAutoRel
private final GltUserTicketMapper userTicketMapper; private final GltUserTicketMapper userTicketMapper;
private final GltUserTicketLogMapper userTicketLogMapper; private final GltUserTicketLogMapper userTicketLogMapper;
private GltUserTicketReleaseService gltUserTicketReleaseService;
private GltUserTicketService gltUserTicketService;
private GltUserTicketLogService gltUserTicketLogService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public int releaseDue(LocalDateTime now, int batchSize) { public int releaseDue(LocalDateTime now, int batchSize) {
@@ -71,12 +86,7 @@ public class GltUserTicketAutoReleaseServiceImpl implements GltUserTicketAutoRel
continue; continue;
} }
long userTicketIdLong = rel.getUserTicketId(); Integer userTicketId = rel.getUserTicketId();
if (userTicketIdLong > Integer.MAX_VALUE || userTicketIdLong < 1) {
markFailed(rel.getId(), now, "userTicketId超范围");
continue;
}
Integer userTicketId = (int) userTicketIdLong;
// 先释放冻结数量(条件更新,确保 frozen_qty >= qty // 先释放冻结数量(条件更新,确保 frozen_qty >= qty
int updated = userTicketMapper.releaseFrozenQty( int updated = userTicketMapper.releaseFrozenQty(
@@ -129,4 +139,96 @@ public class GltUserTicketAutoReleaseServiceImpl implements GltUserTicketAutoRel
releaseMapper.updateStatus(releaseId, RELEASE_STATUS_FAILED, now); releaseMapper.updateStatus(releaseId, RELEASE_STATUS_FAILED, now);
log.warn("冻结水票释放标记失败 - releaseId={}, reason={}", releaseId, reason); log.warn("冻结水票释放标记失败 - releaseId={}, reason={}", releaseId, reason);
} }
@Transactional
public void releaseTask() {
LocalDateTime now = LocalDateTime.now();
log.info("***执行水票释放任务***-执行时间:{}", now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
long start = System.currentTimeMillis();
List<GltUserTicketRelease> releaseList = releaseMapper.getThisMonthReleaseList(1000);
if(CollectionUtils.isEmpty(releaseList)){
log.info("***本轮任务无待释放水票数据***");
return;
}
//查询用户水票信息
List<Integer> userTickIdList = releaseList.stream().map(GltUserTicketRelease::getUserTicketId).distinct().collect(Collectors.toList());
LambdaQueryWrapper<GltUserTicket> userTicketLambdaQueryWrapper = new LambdaQueryWrapper<GltUserTicket>().select(GltUserTicket::getId, GltUserTicket::getAvailableQty,
GltUserTicket::getFrozenQty, GltUserTicket::getReleasedQty).in(GltUserTicket::getId, userTickIdList);
List<GltUserTicket> userTicketList = userTicketMapper.selectList(userTicketLambdaQueryWrapper);
//创建修改用户水票集合、水票释放计划记录集合
List<GltUserTicket> updateUserTicketList = new ArrayList<>();
List<GltUserTicketLog> userTicketLogList = new ArrayList<>();
//遍历水票释放数据执行释放任务
releaseList.forEach(release ->{
//1.缺少水票ID、用户ID、租户ID记录错误记录
if(release.getUserTicketId() == null || release.getUserId() == null || release.getTenantId() == null){
release.setRemark("缺少userTicketId/userId/tenantId");
release.setStatus(2);
release.setUpdateTime(now);
}
GltUserTicket userTicket = userTicketList.stream().filter(gltUserTicket -> release.getUserTicketId().equals(gltUserTicket.getId())).findFirst().orElse(null);
if(userTicket != null){
Integer releaseQty = release.getReleaseQty();
if(userTicket.getFrozenQty() > releaseQty){
//更改用户水票可用数量、冻结数量、已释放数量
userTicket.setAvailableQty(userTicket.getAvailableQty() + releaseQty);
userTicket.setFrozenQty(userTicket.getFrozenQty() - releaseQty);
userTicket.setReleasedQty(userTicket.getReleasedQty() + releaseQty);
userTicket.setUpdateTime(now);
updateUserTicketList.add(userTicket);
//记录水票释放计划为成功释放状态
release.setStatus(1);
release.setRemark("success");
release.setUpdateTime(now);
//生成水票释放记录
GltUserTicketLog ticketLog = new GltUserTicketLog();
ticketLog.setUserTicketId(release.getUserTicketId());
ticketLog.setChangeType(CHANGE_TYPE_RELEASE);
ticketLog.setChangeAvailable(releaseQty);
ticketLog.setChangeFrozen(-releaseQty);
ticketLog.setChangeUsed(0);
ticketLog.setAvailableAfter(userTicket.getAvailableQty());
ticketLog.setFrozenAfter(userTicket.getFrozenQty());
ticketLog.setUsedAfter(userTicket.getUsedQty());
ticketLog.setOrderId(Integer.valueOf(String.valueOf(release.getId())));
ticketLog.setUserId(release.getUserId());
ticketLog.setComments("冻结水票到期释放");
ticketLog.setTenantId(release.getTenantId());
ticketLog.setCreateTime(now);
ticketLog.setUpdateTime(now);
userTicketLogList.add(ticketLog);
}else {
release.setRemark("释放数量大于冻结数量,释放:" + releaseQty + ",冻结:" + userTicket.getFrozenQty());
release.setStatus(2);
release.setUpdateTime(LocalDateTime.now());
}
}else {
release.setRemark("查询不到水票数据");
release.setStatus(2);
release.setUpdateTime(LocalDateTime.now());
}
});
if(CollectionUtils.isNotEmpty(releaseList)){
gltUserTicketReleaseService.updateBatchById(releaseList);
}
if(CollectionUtils.isNotEmpty(updateUserTicketList)){
gltUserTicketService.updateBatchById(updateUserTicketList);
}
if(CollectionUtils.isNotEmpty(userTicketLogList)){
gltUserTicketLogService.saveBatch(userTicketLogList);
}
long end = System.currentTimeMillis();
long costMs = end - start;
log.info("***执行水票释放任务完成*** 执行耗时:{} ms", costMs);
}
} }

View File

@@ -116,7 +116,7 @@ public class DealerCommissionUnfreeze10584Task {
private final AtomicBoolean running = new AtomicBoolean(false); private final AtomicBoolean running = new AtomicBoolean(false);
@Scheduled(cron = "${dealer.commission.unfreeze10584.cron:0/50 * * * * ?}") // @Scheduled(cron = "${dealer.commission.unfreeze10584.cron:0/50 * * * * ?}")
@IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤") @IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤")
public void run() { public void run() {
if (!running.compareAndSet(false, true)) { if (!running.compareAndSet(false, true)) {

View File

@@ -1,41 +1,43 @@
package com.gxwebsoft.glt.task; package com.gxwebsoft.glt.task;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gxwebsoft.common.core.annotation.IgnoreTenant; import com.gxwebsoft.common.core.annotation.IgnoreTenant;
import com.gxwebsoft.glt.entity.GltTicketTemplate; import com.gxwebsoft.common.core.enums.ShopDealerCapitalUpdateEnum;
import com.gxwebsoft.glt.service.GltTicketTemplateService; import com.gxwebsoft.common.core.enums.ShopDealerTypeEnum;
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;
import com.gxwebsoft.shop.entity.ShopOrderGoods;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.common.system.mapper.UserMapper; import com.gxwebsoft.common.system.mapper.UserMapper;
import com.gxwebsoft.shop.service.ShopDealerCapitalService; import com.gxwebsoft.common.system.redis.OrderNoUtils;
import com.gxwebsoft.shop.service.ShopDealerOrderService; import com.gxwebsoft.glt.entity.GltTicketTemplate;
import com.gxwebsoft.shop.service.ShopDealerRefereeService; import com.gxwebsoft.glt.service.GltTicketTemplateService;
import com.gxwebsoft.shop.service.ShopDealerSettingService; import com.gxwebsoft.shop.dto.ShopDealerSettlementDto;
import com.gxwebsoft.shop.service.ShopDealerUserService; import com.gxwebsoft.shop.dto.ShopDealerSettlementItemDto;
import com.gxwebsoft.shop.service.ShopGoodsService; import com.gxwebsoft.shop.dto.ShopDealerUserReduceDto;
import com.gxwebsoft.shop.service.ShopOrderService; import com.gxwebsoft.shop.entity.*;
import com.gxwebsoft.shop.service.ShopOrderGoodsService; import com.gxwebsoft.shop.mapper.ShopDealerRefereeMapper;
import com.gxwebsoft.shop.mapper.ShopOrderMapper;
import com.gxwebsoft.shop.service.*;
import com.gxwebsoft.shop.util.UpstreamUserFinder; import com.gxwebsoft.shop.util.UpstreamUserFinder;
import com.alibaba.fastjson.JSONObject; import com.gxwebsoft.shop.vo.ShopDealerRefereeVO;
import com.gxwebsoft.shop.vo.ShopGoodsProfitVO;
import com.gxwebsoft.shop.vo.ShopOrderGoodsVO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode; import java.math.RoundingMode;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/** /**
* 租户10584分销订单结算任务 * 租户10584分销订单结算任务
@@ -50,7 +52,6 @@ public class DealerOrderSettlement10584Task {
private static final BigDecimal RATE_0_10 = new BigDecimal("0.10"); private static final BigDecimal RATE_0_10 = new BigDecimal("0.10");
private static final BigDecimal RATE_0_05 = new BigDecimal("0.05"); private static final BigDecimal RATE_0_05 = new BigDecimal("0.05");
private static final BigDecimal RATE_0_03 = new BigDecimal("0.03");
private static final BigDecimal RATE_0_02 = new BigDecimal("0.02"); private static final BigDecimal RATE_0_02 = new BigDecimal("0.02");
private static final BigDecimal RATE_0_01 = new BigDecimal("0.01"); private static final BigDecimal RATE_0_01 = new BigDecimal("0.01");
private static final BigDecimal TOTAL_DEALER_DIVIDEND_RATE = RATE_0_01; private static final BigDecimal TOTAL_DEALER_DIVIDEND_RATE = RATE_0_01;
@@ -92,14 +93,29 @@ public class DealerOrderSettlement10584Task {
@Resource @Resource
private GltTicketTemplateService gltTicketTemplateService; private GltTicketTemplateService gltTicketTemplateService;
@Resource
private ShopOrderMapper shopOrderMapper;
@Resource
private ShopDealerRefereeMapper shopDealerRefereeMapper;
@Resource
private ShopGoodsProfitService shopGoodsProfitService;
@Resource
private OrderNoUtils orderNoUtils;
/** /**
* 每10秒执行一次。 * 每10秒执行一次。
*/ */
@Scheduled(cron = "0/10 * * * * ?") // @Scheduled(cron = "0/10 * * * * ?")
@IgnoreTenant("该定时任务仅处理租户10584但需要显式按tenantId过滤避免定时任务线程无租户上下文导致查询异常") @IgnoreTenant("该定时任务仅处理租户10584但需要显式按tenantId过滤避免定时任务线程无租户上下文导致查询异常")
public void settleTenant10584Orders() { public void settleTenant10584Orders() {
try { try {
//获取水票模板对应的商品信息列表
Set<Integer> waterFormIds = loadWaterFormIds(); Set<Integer> waterFormIds = loadWaterFormIds();
//查询商品列表存在已支付未核销订单数据
List<ShopOrder> orders = findUnsettledPaidOrders(waterFormIds); List<ShopOrder> orders = findUnsettledPaidOrders(waterFormIds);
if (orders.isEmpty()) { if (orders.isEmpty()) {
return; return;
@@ -108,7 +124,11 @@ public class DealerOrderSettlement10584Task {
// Per-run caches to reduce DB chatter across orders. // Per-run caches to reduce DB chatter across orders.
Map<Integer, Integer> level1ParentCache = new HashMap<>(); Map<Integer, Integer> level1ParentCache = new HashMap<>();
Map<Integer, Boolean> shopRoleCache = new HashMap<>(); Map<Integer, Boolean> shopRoleCache = new HashMap<>();
//获取系统设置分销等级
DealerBasicSetting dealerBasicSetting = findDealerBasicSetting(); DealerBasicSetting dealerBasicSetting = findDealerBasicSetting();
//获取分销员type=2第一个分销人作为平台总分红人
ShopDealerUser totalDealerUser = findTotalDealerUser(); ShopDealerUser totalDealerUser = findTotalDealerUser();
if (totalDealerUser == null || totalDealerUser.getUserId() == null) { if (totalDealerUser == null || totalDealerUser.getUserId() == null) {
log.warn("未找到分红账号,订单仍可结算但不会发放分红 - tenantId={}", TENANT_ID); log.warn("未找到分红账号,订单仍可结算但不会发放分红 - tenantId={}", TENANT_ID);
@@ -124,6 +144,7 @@ public class DealerOrderSettlement10584Task {
try { try {
transactionTemplate.executeWithoutResult(status -> { transactionTemplate.executeWithoutResult(status -> {
// 先“认领”订单:并发/多实例下避免重复结算update=0 表示被其他线程/实例处理) // 先“认领”订单:并发/多实例下避免重复结算update=0 表示被其他线程/实例处理)
//更新商品订单为已结算状态
if (!claimOrderToSettle(order.getOrderId(), waterFormIds)) { if (!claimOrderToSettle(order.getOrderId(), waterFormIds)) {
return; return;
} }
@@ -138,6 +159,150 @@ public class DealerOrderSettlement10584Task {
} }
} }
/**
* 每10分钟执行一次。
*/
@Scheduled(cron = "0 0/10 * * * ?")
@IgnoreTenant("该定时任务仅处理租户10584但需要显式按tenantId过滤避免定时任务线程无租户上下文导致查询异常")
public void settleTenant10584OrdersV2() {
try {
//获取水票模板对应的商品信息列表
Set<Integer> waterFormIds = loadWaterFormIds();
//查询商品列表存在已支付未核销订单数据【isSettled = 0 payStatus= 1 orderStatus 不在列表2, 3, 4, 5, 6, 7
List<ShopOrder> orders = findUnsettledPaidOrders(waterFormIds);
if (orders.isEmpty()) {
return;
}
// Per-run caches to reduce DB chatter across orders.
Map<Integer, Integer> level1ParentCache = new HashMap<>();
Map<Integer, Boolean> shopRoleCache = new HashMap<>();
//获取系统设置分销等级
DealerBasicSetting dealerBasicSetting = findDealerBasicSetting();
//获取分销员type=2第一个分销人作为平台总分红人
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,
orders.size(),
orders.stream().limit(10).map(ShopOrder::getOrderNo).toList());
for (ShopOrder order : orders) {
try {
transactionTemplate.executeWithoutResult(status -> {
// 先“认领”订单:并发/多实例下避免重复结算update=0 表示被其他线程/实例处理)
//更新商品订单为已结算状态
if (!claimOrderToSettle(order.getOrderId(), waterFormIds)) {
return;
}
settleOneOrderV2(order, level1ParentCache, shopRoleCache, totalDealerUser, dealerBasicSetting.level);
});
} catch (Exception e) {
log.error("订单结算失败,将回滚本订单并在下次任务重试 - orderId={}, orderNo={}", order.getOrderId(), order.getOrderNo(), e);
}
}
} catch (Exception e) {
log.error("租户{}分销订单结算任务执行失败", TENANT_ID, e);
}
}
/**
* 订单分销金、分润金结算
*/
@Transactional
public void orderSettlement(String orderNo){
LambdaQueryWrapper<ShopOrder> orderLambdaQueryWrapper = new LambdaQueryWrapper<ShopOrder>().eq(ShopOrder::getOrderNo, orderNo).eq(ShopOrder::getIsSettled, 0).eq(ShopOrder::getPayStatus, 1);
ShopOrder order = shopOrderService.getOne(orderLambdaQueryWrapper);
if(order != null){
//获取系统设置分销等级
DealerBasicSetting dealerBasicSetting = findDealerBasicSetting();
//获取分销员type=2第一个分销人作为平台总分红人
ShopDealerUser totalDealerUser = findTotalDealerUser();
Map<Integer, Integer> level1ParentCache = new HashMap<>();
Map<Integer, Boolean> shopRoleCache = new HashMap<>();
transactionTemplate.executeWithoutResult(status -> {
// 先“认领”订单:并发/多实例下避免重复结算update=0 表示被其他线程/实例处理)
//更新商品订单为已结算状态
if (!claimOrderToSettleV2(order.getOrderId())) {
return;
}
settleOneOrderV2(order, level1ParentCache, shopRoleCache, totalDealerUser, dealerBasicSetting.level);
});
}
}
/**
* 股东/合伙人分红
* @param orderNo 订单号
* @return
*/
@Transactional
public Boolean partnerProfit(String orderNo, Integer tenantId){
//1.查询订单信息
ShopOrder shopOrder = shopOrderService.getByOrderNo(orderNo, tenantId);
if(shopOrder != null){
//2.查询订单号订单所有已开启分销的商品分润信息
List<ShopOrderGoodsVO> orderGoodsVOList = shopOrderMapper.getOrderGoodsInfo(orderNo);
if(CollectionUtils.isNotEmpty(orderGoodsVOList)){
//3.计算商品实付比例
BigDecimal rate = shopOrder.getPayPrice().divide(shopOrder.getTotalPrice(), 2, RoundingMode.HALF_UP);
//4.查询商品分红设定比例数据
List<Integer> goodsIdList = orderGoodsVOList.stream().map(ShopOrderGoodsVO::getGoodsId).distinct().collect(Collectors.toList());
List<ShopGoodsProfitVO> goodsProfitVOList = shopGoodsProfitService.getGoodsProfit(goodsIdList, 1);
if(CollectionUtils.isNotEmpty(goodsProfitVOList)){
List<ShopDealerSettlementItemDto> itemList = new ArrayList<>();
//5.按照商品分组分润信息
Map<Integer, List<ShopGoodsProfitVO>> goodsProfitMap = goodsProfitVOList.stream().collect(Collectors.groupingBy(ShopGoodsProfitVO::getGoodsId));
//6.遍历商品获取分红子项数据
orderGoodsVOList.forEach(orderGoodsVO ->{
List<ShopGoodsProfitVO> profitVOS = goodsProfitMap.get(orderGoodsVO.getGoodsId());
if(CollectionUtils.isNotEmpty(profitVOS)){
BigDecimal itemPrice = orderGoodsVO.getPrice().multiply(BigDecimal.valueOf(orderGoodsVO.getTotalNum()));
BigDecimal itemProfitPrice = itemPrice.multiply(rate).setScale(3, RoundingMode.HALF_UP);
profitVOS.forEach(profitVO ->{
ShopDealerSettlementItemDto itemDto = new ShopDealerSettlementItemDto();
String no = orderNoUtils.generate("C");
BigDecimal money = profitVO.getProfit().divide(BigDecimal.valueOf(100)).multiply(itemProfitPrice).setScale(3, RoundingMode.HALF_UP);
itemDto.setNo(no);
itemDto.setUserId(profitVO.getUserId());
itemDto.setMoney(money);
itemList.add(itemDto);
});
}
});
//7.存在分红子项数据,则批量结算
if(CollectionUtils.isNotEmpty(itemList)){
ShopDealerSettlementDto settlementDto = new ShopDealerSettlementDto();
settlementDto.setOrderNo(orderNo);
settlementDto.setToUserId(shopOrder.getUserId());
settlementDto.setTenantId(tenantId);
settlementDto.setItemList(itemList);
shopDealerUserService.orderProfit(settlementDto);
}
}
}
}
return Boolean.TRUE;
}
private List<ShopOrder> findUnsettledPaidOrders(Set<Integer> waterFormIds) { private List<ShopOrder> findUnsettledPaidOrders(Set<Integer> waterFormIds) {
// 租户10584约定 // 租户10584约定
// - 普通订单以发货为准deliveryStatus=20才结算 // - 普通订单以发货为准deliveryStatus=20才结算
@@ -148,7 +313,7 @@ public class DealerOrderSettlement10584Task {
.eq(ShopOrder::getPayStatus, true) .eq(ShopOrder::getPayStatus, true)
.eq(ShopOrder::getIsSettled, 0) .eq(ShopOrder::getIsSettled, 0)
// 退款/取消订单不结算,避免“退款后仍发放分红/分润/佣金” // 退款/取消订单不结算,避免“退款后仍发放分红/分润/佣金”
.and(w -> w.notIn(ShopOrder::getOrderStatus, 2, 4, 5, 6, 7).or().isNull(ShopOrder::getOrderStatus)); .and(w -> w.notIn(ShopOrder::getOrderStatus, 2, 3, 4, 5, 6, 7).or().isNull(ShopOrder::getOrderStatus));
if (waterFormIds != null && !waterFormIds.isEmpty()) { if (waterFormIds != null && !waterFormIds.isEmpty()) {
qw.and(w -> w.eq(ShopOrder::getDeliveryStatus, 20).or().in(ShopOrder::getFormId, waterFormIds)); qw.and(w -> w.eq(ShopOrder::getDeliveryStatus, 20).or().in(ShopOrder::getFormId, waterFormIds));
@@ -178,6 +343,17 @@ public class DealerOrderSettlement10584Task {
return shopOrderService.update(uw); return shopOrderService.update(uw);
} }
private boolean claimOrderToSettleV2(Integer orderId) {
LambdaUpdateWrapper<ShopOrder> uw = new LambdaUpdateWrapper<ShopOrder>()
.eq(ShopOrder::getOrderId, orderId)
.eq(ShopOrder::getTenantId, TENANT_ID)
.eq(ShopOrder::getIsSettled, 0)
// 二次防御:退款/取消订单不允许被“认领结算”
.and(w -> w.notIn(ShopOrder::getOrderStatus, 2, 3, 4, 5, 6, 7).or().isNull(ShopOrder::getOrderStatus));
uw.set(ShopOrder::getIsSettled, 1);
return shopOrderService.update(uw);
}
private Set<Integer> loadWaterFormIds() { private Set<Integer> loadWaterFormIds() {
try { try {
return gltTicketTemplateService.list( return gltTicketTemplateService.list(
@@ -252,6 +428,45 @@ public class DealerOrderSettlement10584Task {
log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), baseAmount); log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), baseAmount);
} }
private void settleOneOrderV2(ShopOrder order, Map<Integer, Integer> level1ParentCache, Map<Integer, Boolean> shopRoleCache,
ShopDealerUser totalDealerUser, int dealerLevel) {
if (order.getUserId() == null || order.getOrderNo() == null) {
throw new IllegalStateException("订单关键信息缺失,无法结算 - orderId=" + order.getOrderId());
}
BigDecimal totalPrice = order.getTotalPrice();
BigDecimal payPrice = order.getPayPrice();
BigDecimal rate = payPrice.divide(totalPrice, 2, RoundingMode.HALF_UP);
if(payPrice.compareTo(BigDecimal.ZERO) <= 0){
log.info("订单号:{}实付金额为0无需执行分销逻辑" + order.getOrderNo());
return;
}
//查询订单号订单所有已开启分销的商品分润信息
List<ShopOrderGoodsVO> orderGoodsVOList = shopOrderMapper.getOrderGoodsInfo(order.getOrderNo());
if(CollectionUtils.isNotEmpty(orderGoodsVOList)){
// 1) 直推/间推(直接增加冻结账户余额)
DealerRefereeCommissionV2 dealerRefereeCommission = settleDealerRefereeCommissionV2(order, rate, orderGoodsVOList, dealerLevel);
// 2) 门店分润上级:从下单用户开始逐级向上找,命中 ShopDealerUser.type=1 的最近两级(直推门店/间推门店)【只统计数据,不对分销账户进行处理,
// 已日结形式统计分销记录表shop_dealer_order 做对应一级二级管理津贴结算】
ShopRoleCommission shopRoleCommission = settleShopRoleRefereeCommissionV2(order, rate, orderGoodsVOList, level1ParentCache, shopRoleCache);
// // 3) 分红:固定比率,每个订单都分
// int goodsQty = orderGoodsVOList.stream().mapToInt(ShopOrderGoodsVO::getTotalNum).sum();
// TotalDealerCommission totalDealerCommission = settleTotalDealerCommissionV2(order, goodsQty, totalDealerUser);
// 3) 写入分销订单记录(用于排查/统计;详细分佣以 ShopDealerCapital 为准)
createDealerOrderRecordV2(order, dealerRefereeCommission, shopRoleCommission);
log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), payPrice);
}else {
log.error("订单号:{},未找到下单分销商品数据!", order.getOrderNo());
return;
}
}
private DealerRefereeCommission settleDealerRefereeCommission( private DealerRefereeCommission settleDealerRefereeCommission(
ShopOrder order, ShopOrder order,
BigDecimal baseAmount, BigDecimal baseAmount,
@@ -329,6 +544,95 @@ public class DealerOrderSettlement10584Task {
return new DealerRefereeCommission(directDealerId, directMoney, simpleDealerId, simpleMoney, thirdDealerId, thirdMoney); return new DealerRefereeCommission(directDealerId, directMoney, simpleDealerId, simpleMoney, thirdDealerId, thirdMoney);
} }
/**
* 获取分销员分销霍金数据
* @param order
* @param orderGoodsVOList
* @param dealerLevel
* @return
*/
private DealerRefereeCommissionV2 settleDealerRefereeCommissionV2(ShopOrder order, BigDecimal rate, List<ShopOrderGoodsVO> orderGoodsVOList, int dealerLevel) {
Integer directDealerId = null;
Integer simpleDealerId = null;
AtomicReference<BigDecimal> directMoney = new AtomicReference<>(BigDecimal.ZERO);
AtomicReference<BigDecimal> simpleMoney = new AtomicReference<>(BigDecimal.ZERO);
ShopDealerRefereeVO dealerRefereeVO = shopDealerRefereeMapper.getDealerIdByUserId(order.getUserId());
if(dealerRefereeVO == null){
return null;
}
if (dealerLevel == 1) {
Integer directUserId = dealerRefereeVO.getDirectUserId();
Integer directUserType = dealerRefereeVO.getDirectUserType();
if(directUserId != null && directUserType != null && directUserType == 0){
directDealerId = dealerRefereeVO.getDirectUserId();
}
}else {
Integer directUserId = dealerRefereeVO.getDirectUserId();
Integer directUserType = dealerRefereeVO.getDirectUserType();
Integer simpleUserId = dealerRefereeVO.getSimpleUserId();
Integer simpleUserType = dealerRefereeVO.getSimpleUserType();
if(directUserId != null && directUserType != null && directUserType == 0){
directDealerId = directUserId;
}
if(simpleUserId != null && simpleUserType != null && simpleUserType == 0){
simpleDealerId = simpleUserId;
}
}
if(directDealerId != null || simpleDealerId != null){
Integer finalDirectDealerId = directDealerId;
Integer finalSimpleDealerId = simpleDealerId;
orderGoodsVOList.forEach(orderGoodsVO -> {
//获取商品分润比例/金额
BigDecimal firstMoney = orderGoodsVO.getFirstMoney();
BigDecimal secondMoney = orderGoodsVO.getSecondMoney();
//按实付比例计算单项应参与分润金额
BigDecimal itemRatePrice = orderGoodsVO.getPrice().multiply(BigDecimal.valueOf(orderGoodsVO.getTotalNum())).multiply(rate);
//一级分销员存在(type = 0)且单项实付金额大于0及商品设置了一级分销比例/金额
if(finalDirectDealerId != null && itemRatePrice.compareTo(BigDecimal.ZERO) > 0 && firstMoney.compareTo(BigDecimal.ZERO) > 0){
BigDecimal one = calcMoneyByCommissionType(itemRatePrice, firstMoney, orderGoodsVO.getTotalNum(), 2, orderGoodsVO.getCommissionType());
directMoney.accumulateAndGet(one, BigDecimal::add);
}
//一级分销员存在(type = 0)且单项实付金额大于0及商品设置了一级分销比例/金额
if(finalSimpleDealerId != null && itemRatePrice.compareTo(BigDecimal.ZERO) > 0 && secondMoney.compareTo(BigDecimal.ZERO) > 0 ){
BigDecimal two = calcMoneyByCommissionType(itemRatePrice, secondMoney, orderGoodsVO.getTotalNum(), 2, orderGoodsVO.getCommissionType());
simpleMoney.accumulateAndGet(two, BigDecimal::add);
}
});
//一级分销员账户增加冻结金额
if (directDealerId != null && directMoney.get().compareTo(BigDecimal.ZERO) > 0) {
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.FREEZE_ACCOUNT);
reduceDto.setUserId(directDealerId);
reduceDto.setOrderUserId(order.getUserId());
reduceDto.setOrderNo(order.getOrderNo());
reduceDto.setPrice(directMoney.get());
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DISTRIBUTION_INCOME);
shopDealerUserService.reduceBalance(reduceDto);
}
//二级分销员账户增加冻结金额
if (simpleDealerId != null && simpleMoney.get().compareTo(BigDecimal.ZERO) > 0) {
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.FREEZE_ACCOUNT);
reduceDto.setUserId(simpleDealerId);
reduceDto.setOrderUserId(order.getUserId());
reduceDto.setOrderNo(order.getOrderNo());
reduceDto.setPrice(simpleMoney.get());
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DISTRIBUTION_INCOME);
shopDealerUserService.reduceBalance(reduceDto);
}
return new DealerRefereeCommissionV2(directDealerId, directMoney.get(), simpleDealerId, simpleMoney.get());
}
return null;
}
private Integer getDealerRefereeId(Integer userId) { private Integer getDealerRefereeId(Integer userId) {
return getDealerRefereeId(userId, 1); return getDealerRefereeId(userId, 1);
} }
@@ -412,6 +716,54 @@ public class DealerOrderSettlement10584Task {
return new ShopRoleCommission(shopRoleReferees.get(0), storeDirectMoney, shopRoleReferees.get(1), storeSimpleMoney); return new ShopRoleCommission(shopRoleReferees.get(0), storeDirectMoney, shopRoleReferees.get(1), storeSimpleMoney);
} }
private ShopRoleCommission settleShopRoleRefereeCommissionV2(ShopOrder order, BigDecimal rate, List<ShopOrderGoodsVO> orderGoodsVOList, Map<Integer, Integer> level1ParentCache, Map<Integer, Boolean> shopRoleCache) {
List<Integer> shopRoleReferees = findFirstTwoShopRoleReferees(order.getUserId(), level1ParentCache, shopRoleCache);
log.info("门店分润命中结果(type=1门店角色取前两级) - orderNo={}, buyerUserId={}, shopRoleReferees={}",
order.getOrderNo(), order.getUserId(), shopRoleReferees);
if (shopRoleReferees.isEmpty()) {
return ShopRoleCommission.empty();
}
if(CollectionUtils.isNotEmpty(shopRoleReferees)){
Integer storeDirectUserId;
Integer storeSimpleUserId = null;
AtomicReference<BigDecimal> storeDirectMoney = new AtomicReference<>(BigDecimal.ZERO);
AtomicReference<BigDecimal> storeSimpleMoney = new AtomicReference<>(BigDecimal.ZERO);
if(shopRoleReferees.size() == 1){
storeDirectUserId = shopRoleReferees.get(0);
}else {
storeDirectUserId = shopRoleReferees.get(0);
storeSimpleUserId = shopRoleReferees.get(1);
}
Integer finalStoreDirectUserId = storeDirectUserId;
Integer finalStoreSimpleUserId = storeSimpleUserId;
orderGoodsVOList.forEach(orderGoodsVO ->{
//获取商品对应服务商管理费分润比例/金额
BigDecimal firstMoney = orderGoodsVO.getFirstDividend();
BigDecimal secondMoney = orderGoodsVO.getSecondDividend();
//按实付比例计算单项应参与分润金额
BigDecimal itemRatePrice = orderGoodsVO.getPrice().multiply(BigDecimal.valueOf(orderGoodsVO.getTotalNum())).multiply(rate);
if(finalStoreDirectUserId != null && itemRatePrice.compareTo(BigDecimal.ZERO) > 0){
BigDecimal one = calcMoneyByCommissionType(itemRatePrice, firstMoney, orderGoodsVO.getTotalNum(), 2, orderGoodsVO.getCommissionType());
storeDirectMoney.accumulateAndGet(one, BigDecimal::add);
}
if(finalStoreSimpleUserId != null && itemRatePrice.compareTo(BigDecimal.ZERO) > 0){
BigDecimal two = calcMoneyByCommissionType(itemRatePrice, secondMoney, orderGoodsVO.getTotalNum(), 2, orderGoodsVO.getCommissionType());
storeSimpleMoney.accumulateAndGet(two, BigDecimal::add);
}
});
return new ShopRoleCommission(storeDirectUserId, storeDirectMoney.get(), storeSimpleUserId, storeSimpleMoney.get());
}else {
return null;
}
}
private TotalDealerCommission settleTotalDealerCommission( private TotalDealerCommission settleTotalDealerCommission(
ShopOrder order, ShopOrder order,
BigDecimal baseAmount, BigDecimal baseAmount,
@@ -438,6 +790,32 @@ public class DealerOrderSettlement10584Task {
return new TotalDealerCommission(totalDealerUser.getUserId(), money); return new TotalDealerCommission(totalDealerUser.getUserId(), money);
} }
private TotalDealerCommission settleTotalDealerCommissionV2(ShopOrder order, int goodsQty, ShopDealerUser totalDealerUser) {
if (totalDealerUser == null || totalDealerUser.getUserId() == null) {
return TotalDealerCommission.empty();
}
BigDecimal rate = safePositive(totalDealerUser.getRate());
if (rate.signum() <= 0) {
rate = TOTAL_DEALER_DIVIDEND_RATE;
}
BigDecimal money = calcMoneyByCommissionType(order.getPayPrice(), rate, goodsQty, DIVIDEND_SCALE, 20);
//一级分销员账户增加冻结金额
if (money.compareTo(BigDecimal.ZERO) > 0) {
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
reduceDto.setTypeEnum(ShopDealerTypeEnum.FREEZE_ACCOUNT);
reduceDto.setUserId(totalDealerUser.getUserId());
reduceDto.setOrderUserId(order.getUserId());
reduceDto.setOrderNo(order.getOrderNo());
reduceDto.setPrice(money);
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DIVIDEND_INCOME);
shopDealerUserService.reduceBalance(reduceDto);
return new TotalDealerCommission(totalDealerUser.getUserId(), money);
}
return TotalDealerCommission.empty();
}
private ShopDealerUser findTotalDealerUser() { private ShopDealerUser findTotalDealerUser() {
return shopDealerUserService.getOne( return shopDealerUserService.getOne(
new LambdaQueryWrapper<ShopDealerUser>() new LambdaQueryWrapper<ShopDealerUser>()
@@ -756,6 +1134,92 @@ public class DealerOrderSettlement10584Task {
order.getOrderNo(), dealerOrder.getFirstUserId(), dealerOrder.getSecondUserId(), dealerOrder.getFirstDividendUser(), dealerOrder.getSecondDividendUser()); order.getOrderNo(), dealerOrder.getFirstUserId(), dealerOrder.getSecondUserId(), dealerOrder.getFirstDividendUser(), dealerOrder.getSecondDividendUser());
} }
/**
* 记录订单分销业务
* @param order 商品订单
* @param dealerRefereeCommission 一级、二级分销员分销数据
* @param shopRoleCommission 门店/服务商一级、二级管理津贴数据
*/
private void createDealerOrderRecordV2(ShopOrder order, DealerRefereeCommissionV2 dealerRefereeCommission, ShopRoleCommission shopRoleCommission) {
// 幂等:同一订单只写一条(依赖 order_no + tenant_id 作为业务唯一)
ShopDealerOrder existed = shopDealerOrderService.getOne(
new LambdaQueryWrapper<ShopDealerOrder>()
.eq(ShopDealerOrder::getTenantId, TENANT_ID)
.eq(ShopDealerOrder::getOrderNo, order.getOrderNo())
.last("limit 1")
);
if (existed != null) {
// 允许“补发”门店分润时回填分润字段,避免订单已结算但分润字段一直为空,影响排查/对账。
LambdaUpdateWrapper<ShopDealerOrder> uw = new LambdaUpdateWrapper<ShopDealerOrder>()
.eq(ShopDealerOrder::getTenantId, TENANT_ID)
.eq(ShopDealerOrder::getOrderNo, order.getOrderNo());
boolean needUpdate = false;
if (shopRoleCommission != null && shopRoleCommission.storeDirectUserId != null) {
Integer existedUser = existed.getFirstDividendUser();
boolean needSetUser = existedUser == null;
boolean needSetMoney = existed.getFirstDividend() == null || existed.getFirstDividend().signum() == 0;
if (needSetUser) {
uw.set(ShopDealerOrder::getFirstDividendUser, shopRoleCommission.storeDirectUserId);
needUpdate = true;
}
boolean sameUser = existedUser == null || Objects.equals(existedUser, shopRoleCommission.storeDirectUserId);
if (sameUser && needSetMoney && shopRoleCommission.storeDirectMoney != null && shopRoleCommission.storeDirectMoney.signum() > 0) {
uw.set(ShopDealerOrder::getFirstDividend, shopRoleCommission.storeDirectMoney);
needUpdate = true;
}
}
if (shopRoleCommission != null && shopRoleCommission.storeSimpleUserId != null) {
Integer existedUser = existed.getSecondDividendUser();
boolean needSetUser = existedUser == null;
boolean needSetMoney = existed.getSecondDividend() == null || existed.getSecondDividend().signum() == 0;
if (needSetUser) {
uw.set(ShopDealerOrder::getSecondDividendUser, shopRoleCommission.storeSimpleUserId);
needUpdate = true;
}
boolean sameUser = existedUser == null || Objects.equals(existedUser, shopRoleCommission.storeSimpleUserId);
if (sameUser && needSetMoney && shopRoleCommission.storeSimpleMoney != null && shopRoleCommission.storeSimpleMoney.signum() > 0) {
uw.set(ShopDealerOrder::getSecondDividend, shopRoleCommission.storeSimpleMoney);
needUpdate = true;
}
}
if (needUpdate) {
shopDealerOrderService.update(uw);
log.info("ShopDealerOrder已存在回填门店分润字段 - orderNo={}, firstDividendUser={}, secondDividendUser={}",
order.getOrderNo(), shopRoleCommission.storeDirectUserId, shopRoleCommission.storeSimpleUserId);
} else {
log.info("ShopDealerOrder已存在跳过写入 - orderNo={}", order.getOrderNo());
}
return;
}else {
ShopDealerOrder dealerOrder = new ShopDealerOrder();
dealerOrder.setUserId(order.getUserId()); // 买家用户ID
dealerOrder.setOrderNo(order.getOrderNo());
dealerOrder.setOrderPrice(order.getTotalPrice());
dealerOrder.setPayPrice(order.getPayPrice());
//一级、二级分销员分销佣金统计
dealerOrder.setFirstUserId(dealerRefereeCommission != null ? dealerRefereeCommission.directDealerId : null);
dealerOrder.setFirstMoney(dealerRefereeCommission != null ? dealerRefereeCommission.directMoney : BigDecimal.ZERO);
dealerOrder.setSecondUserId(dealerRefereeCommission != null ? dealerRefereeCommission.simpleDealerId : null);
dealerOrder.setSecondMoney(dealerRefereeCommission != null ? dealerRefereeCommission.simpleMoney : BigDecimal.ZERO);
//门店(角色shop)两级分润单独落字段(详细以 ShopDealerCapital 为准)
dealerOrder.setFirstDividendUser(shopRoleCommission != null ? shopRoleCommission.storeDirectUserId : null);
dealerOrder.setFirstDividend(shopRoleCommission != null ? shopRoleCommission.storeDirectMoney : BigDecimal.ZERO);
dealerOrder.setSecondDividendUser(shopRoleCommission != null ? shopRoleCommission.storeSimpleUserId : null);
dealerOrder.setSecondDividend(shopRoleCommission != null ? shopRoleCommission.storeSimpleMoney : BigDecimal.ZERO);
dealerOrder.setIsSettled(1);
dealerOrder.setSettleTime(LocalDateTime.now());
dealerOrder.setMonth(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM")));
dealerOrder.setTenantId(TENANT_ID);
dealerOrder.setComments(buildCommissionTraceCommentV2(dealerRefereeCommission, shopRoleCommission));
shopDealerOrderService.save(dealerOrder);
}
}
private String buildCommissionTraceComment( private String buildCommissionTraceComment(
DealerRefereeCommission dealerRefereeCommission, DealerRefereeCommission dealerRefereeCommission,
ShopRoleCommission shopRoleCommission, ShopRoleCommission shopRoleCommission,
@@ -770,6 +1234,26 @@ public class DealerOrderSettlement10584Task {
+ ",totalDealer=" + totalDealerCommission.userId + ":" + totalDealerCommission.money; + ",totalDealer=" + totalDealerCommission.userId + ":" + totalDealerCommission.money;
} }
private String buildCommissionTraceCommentV2(
DealerRefereeCommissionV2 dealerRefereeCommission,
ShopRoleCommission shopRoleCommission
) {
// 轻量“过程”留痕,方便排查;详细分佣以 ShopDealerCapital 为准。
Integer direct = dealerRefereeCommission != null ? dealerRefereeCommission.directDealerId : null;
BigDecimal directMoney = dealerRefereeCommission != null ? dealerRefereeCommission.directMoney : BigDecimal.ZERO;
Integer simpleDealerId = dealerRefereeCommission != null ? dealerRefereeCommission.simpleDealerId : null;
BigDecimal simpleMoney = dealerRefereeCommission != null ? dealerRefereeCommission.simpleMoney : BigDecimal.ZERO;
Integer storeDirectUserId = shopRoleCommission != null ? shopRoleCommission.storeDirectUserId : null;
BigDecimal storeDirectMoney = shopRoleCommission != null ? shopRoleCommission.storeDirectMoney : BigDecimal.ZERO;
Integer storeSimpleUserId = shopRoleCommission != null ? shopRoleCommission.storeSimpleUserId : null;
BigDecimal storeSimpleMoney = shopRoleCommission != null ? shopRoleCommission.storeSimpleMoney : BigDecimal.ZERO;
return "direct=" + direct + ":" + directMoney
+ ",simple=" + simpleDealerId + ":" + simpleMoney
+ ",dividend1=" + storeDirectUserId + ":" + storeDirectMoney
+ ",dividend2=" + storeSimpleUserId + ":" + storeSimpleMoney;
}
private BigDecimal getOrderBaseAmount(ShopOrder order) { private BigDecimal getOrderBaseAmount(ShopOrder order) {
if (order == null) { if (order == null) {
return null; return null;
@@ -962,6 +1446,25 @@ public class DealerOrderSettlement10584Task {
} }
} }
private static class DealerRefereeCommissionV2 {
private final Integer directDealerId;
private final BigDecimal directMoney;
private final Integer simpleDealerId;
private final BigDecimal simpleMoney;
private DealerRefereeCommissionV2(
Integer directDealerId,
BigDecimal directMoney,
Integer simpleDealerId,
BigDecimal simpleMoney
) {
this.directDealerId = directDealerId;
this.directMoney = directMoney != null ? directMoney : BigDecimal.ZERO;
this.simpleDealerId = simpleDealerId;
this.simpleMoney = simpleMoney != null ? simpleMoney : BigDecimal.ZERO;
}
}
private static class ShopRoleCommission { private static class ShopRoleCommission {
private final Integer storeDirectUserId; private final Integer storeDirectUserId;
private final BigDecimal storeDirectMoney; private final BigDecimal storeDirectMoney;

View File

@@ -33,7 +33,7 @@ public class GltTicketIssue10584Task {
private final AtomicBoolean running = new AtomicBoolean(false); private final AtomicBoolean running = new AtomicBoolean(false);
@Scheduled(cron = "${glt.ticket.issue10584.cron:0/15 * * * * ?}") // @Scheduled(cron = "${glt.ticket.issue10584.cron:0/15 * * * * ?}")
@IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤") @IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤")
public void run() { public void run() {
if (!running.compareAndSet(false, true)) { if (!running.compareAndSet(false, true)) {

View File

@@ -34,7 +34,7 @@ public class GltTicketOrderAutoConfirm10584Task {
private final AtomicBoolean running = new AtomicBoolean(false); private final AtomicBoolean running = new AtomicBoolean(false);
@Scheduled(cron = "${glt.ticket-order.auto-confirm10584.cron:0/33 * * * * ?}") // @Scheduled(cron = "${glt.ticket-order.auto-confirm10584.cron:0/33 * * * * ?}")
@IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤") @IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤")
public void run() { public void run() {
if (!running.compareAndSet(false, true)) { if (!running.compareAndSet(false, true)) {

View File

@@ -35,7 +35,7 @@ public class GltTicketOrderAutoDispatch10584Task {
@Value("${glt.ticket.dispatch10584.batchSize:50}") @Value("${glt.ticket.dispatch10584.batchSize:50}")
private int batchSize; private int batchSize;
@Scheduled(cron = "${glt.ticket.dispatch10584.cron:0/20 * * * * ?}") // @Scheduled(cron = "${glt.ticket.dispatch10584.cron:0/20 * * * * ?}")
@IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤") @IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤")
public void run() { public void run() {
if (!running.compareAndSet(false, true)) { if (!running.compareAndSet(false, true)) {

View File

@@ -4,18 +4,19 @@ import com.gxwebsoft.common.core.annotation.IgnoreTenant;
import com.gxwebsoft.glt.service.GltUserTicketAutoReleaseService; import com.gxwebsoft.glt.service.GltUserTicketAutoReleaseService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* 冻结水票自动释放任务: * 冻结水票自动释放任务:每月1日凌晨1-3点每2分钟执行一次任务
* - 扫描 glt_user_ticket_release 中到期且待释放status=0的记录 * - 扫描 glt_user_ticket_release 中本月到期且待释放status=0的记录
* - 释放成功:frozen -> available并将 release.status 置为 1 * - 释放成功:
* 1.修改水票释放任务为已释放状态 glt_user_ticket_release
* 2.修改个人水票中:可用数量、冻结数量、已释放数量 glt_user_ticket
* 3.同步生产水票释放记录数据 glt_user_ticket_log
*/ */
@Slf4j @Slf4j
@Component @Component
@@ -25,25 +26,17 @@ public class GltUserTicketAutoReleaseTask {
private final GltUserTicketAutoReleaseService autoReleaseService; private final GltUserTicketAutoReleaseService autoReleaseService;
@Value("${glt.ticket.auto-release.batch-size:200}")
private int batchSize;
private final AtomicBoolean running = new AtomicBoolean(false); private final AtomicBoolean running = new AtomicBoolean(false);
@Scheduled(cron = "${glt.ticket.auto-release.cron:0 */10 * * * ?}") @Scheduled(cron = "${glt.ticket.auto-release.cron:0 */2 1-3 1 * ?}")
@IgnoreTenant("定时任务无登录态,需忽略租户隔离;释放记录自带 tenantId更新时会校验 tenantId") @IgnoreTenant("定时任务无登录态,需忽略租户隔离;释放记录自带 tenantId更新时会校验 tenantId")
public void run() { public void run() {
if (!running.compareAndSet(false, true)) { if (!running.compareAndSet(false, true)) {
log.warn("冻结水票自动释放任务仍在执行中,本轮跳过"); log.warn("冻结水票自动释放任务仍在执行中,本轮跳过");
return; return;
} }
try { try {
LocalDateTime now = LocalDateTime.now(); autoReleaseService.releaseTask();
int released = autoReleaseService.releaseDue(now, Math.max(batchSize, 1));
if (released > 0) {
log.info("冻结水票自动释放完成 - released={}, now={}", released, now);
}
} finally { } finally {
running.set(false); running.set(false);
} }

View File

@@ -230,7 +230,7 @@ public class PaymentConstants {
*/ */
public static class Environment { public static class Environment {
/** 开发环境 */ /** 开发环境 */
public static final String DEV = "dev"; public static final String DEV = "local";
/** 测试环境 */ /** 测试环境 */
public static final String TEST = "test"; public static final String TEST = "test";
/** 生产环境 */ /** 生产环境 */

View File

@@ -148,7 +148,7 @@ public class WxPayConfigService {
log.info("从数据库获取支付配置成功租户ID: {},将缓存配置", tenantId); log.info("从数据库获取支付配置成功租户ID: {},将缓存配置", tenantId);
// 开发环境下如果apiclientKey为空设置默认值 // 开发环境下如果apiclientKey为空设置默认值
if ("dev".equals(activeProfile) && if ("local".equals(activeProfile) &&
(payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty())) { (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty())) {
log.warn("开发环境数据库配置中apiclientKey为空使用默认值租户ID: {}", tenantId); log.warn("开发环境数据库配置中apiclientKey为空使用默认值租户ID: {}", tenantId);
payment.setApiclientKey("apiclient_key.pem"); payment.setApiclientKey("apiclient_key.pem");
@@ -167,7 +167,7 @@ public class WxPayConfigService {
} }
// 数据库也没有配置 // 数据库也没有配置
if (!"dev".equals(activeProfile)) { if (!"local".equals(activeProfile)) {
throw PaymentException.systemError("微信支付配置未找到租户ID: " + tenantId + ",请检查数据库配置", null); throw PaymentException.systemError("微信支付配置未找到租户ID: " + tenantId + ",请检查数据库配置", null);
} }
@@ -180,7 +180,7 @@ public class WxPayConfigService {
* 获取证书文件路径 * 获取证书文件路径
*/ */
private String getCertificatePath(Integer tenantId, Payment payment) throws PaymentException { private String getCertificatePath(Integer tenantId, Payment payment) throws PaymentException {
if ("dev".equals(activeProfile)) { if ("local".equals(activeProfile)) {
return getDevCertificatePath(tenantId); return getDevCertificatePath(tenantId);
} else { } else {
return getProdCertificatePath(payment); return getProdCertificatePath(payment);
@@ -237,7 +237,7 @@ public class WxPayConfigService {
*/ */
private Config createWxPayConfig(Payment payment, String certificatePath) throws PaymentException { private Config createWxPayConfig(Payment payment, String certificatePath) throws PaymentException {
try { try {
if ("dev".equals(activeProfile) && payment == null) { if ("local".equals(activeProfile) && payment == null) {
// 开发环境测试配置 // 开发环境测试配置
return createDevTestConfig(certificatePath); return createDevTestConfig(certificatePath);
} else if (payment != null) { } else if (payment != null) {
@@ -343,7 +343,7 @@ public class WxPayConfigService {
// 开发环境下如果apiclientKey为空给一个警告但不抛异常 // 开发环境下如果apiclientKey为空给一个警告但不抛异常
// 生产环境必须有apiclientKey // 生产环境必须有apiclientKey
if (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) { if (payment.getApiclientKey() == null || payment.getApiclientKey().trim().isEmpty()) {
if ("dev".equals(activeProfile)) { if ("local".equals(activeProfile)) {
log.warn("开发环境:证书文件名(apiclientKey)未配置,将使用默认值"); log.warn("开发环境:证书文件名(apiclientKey)未配置,将使用默认值");
} else { } else {
throw PaymentException.systemError("证书文件名(apiclientKey)未配置", null); throw PaymentException.systemError("证书文件名(apiclientKey)未配置", null);

View File

@@ -78,7 +78,7 @@ public class WxPayConstants {
public static final int AMOUNT_MULTIPLIER = 100; public static final int AMOUNT_MULTIPLIER = 100;
/** 开发环境标识 */ /** 开发环境标识 */
public static final String PROFILE_DEV = "dev"; public static final String PROFILE_DEV = "local";
/** 生产环境标识 */ /** 生产环境标识 */
public static final String PROFILE_PROD = "prod"; public static final String PROFILE_PROD = "prod";
} }

View File

@@ -0,0 +1,127 @@
package com.gxwebsoft.shop.controller;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.shop.service.ShopActiveImageService;
import com.gxwebsoft.shop.entity.ShopActiveImage;
import com.gxwebsoft.shop.param.ShopActiveImageParam;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog;
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.time.LocalDateTime;
import java.util.List;
/**
* 推广码底图控制器
*
* @author xm
* @since 2026-04-27 18:02:18
*/
@Tag(name = "推广码底图管理")
@RestController
@RequestMapping("/api/shop/shop-active-image")
public class ShopActiveImageController extends BaseController {
@Resource
private ShopActiveImageService shopActiveImageService;
// @PreAuthorize("hasAuthority('shop:shopActiveImage:list')")
@Operation(summary = "分页查询推广码底图")
@GetMapping("/page")
public ApiResult<PageResult<ShopActiveImage>> page(ShopActiveImageParam param) {
// 使用关联查询
return success(shopActiveImageService.pageRel(param));
}
// @PreAuthorize("hasAuthority('shop:shopActiveImage:list')")
@Operation(summary = "查询全部推广码底图")
@GetMapping()
public ApiResult<List<ShopActiveImage>> list(ShopActiveImageParam param) {
// 使用关联查询
return success(shopActiveImageService.listRel(param));
}
// @PreAuthorize("hasAuthority('shop:shopActiveImage:list')")
@Operation(summary = "根据id查询推广码底图")
@GetMapping("/{id}")
public ApiResult<ShopActiveImage> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(shopActiveImageService.getByIdRel(id));
}
// @PreAuthorize("hasAuthority('shop:shopActiveImage:save')")
@OperationLog
@Operation(summary = "添加推广码底图")
@PostMapping()
public ApiResult<?> save(@RequestBody ShopActiveImage shopActiveImage) {
shopActiveImage.setCreator(String.valueOf(getLoginUserId()));
shopActiveImage.setCreateTime(LocalDateTime.now());
if (shopActiveImageService.save(shopActiveImage)) {
return success("添加成功");
}
return fail("添加失败");
}
// @PreAuthorize("hasAuthority('shop:shopActiveImage:update')")
@OperationLog
@Operation(summary = "修改推广码底图")
@PutMapping()
public ApiResult<?> update(@RequestBody ShopActiveImage shopActiveImage) {
shopActiveImage.setUpdater(String.valueOf(getLoginUserId()));
shopActiveImage.setUpdateTime(LocalDateTime.now());
if (shopActiveImageService.updateById(shopActiveImage)) {
return success("修改成功");
}
return fail("修改失败");
}
// @PreAuthorize("hasAuthority('shop:shopActiveImage:remove')")
@OperationLog
@Operation(summary = "删除推广码底图")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (shopActiveImageService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
@PreAuthorize("hasAuthority('shop:shopActiveImage:save')")
@OperationLog
@Operation(summary = "批量添加推广码底图")
@PostMapping("/batch")
public ApiResult<?> saveBatch(@RequestBody List<ShopActiveImage> list) {
if (shopActiveImageService.saveBatch(list)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('shop:shopActiveImage:update')")
@OperationLog
@Operation(summary = "批量修改推广码底图")
@PutMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody BatchParam<ShopActiveImage> batchParam) {
if (batchParam.update(shopActiveImageService, "id")) {
return success("修改成功");
}
return fail("修改失败");
}
// @PreAuthorize("hasAuthority('shop:shopActiveImage:remove')")
@OperationLog
@Operation(summary = "批量删除推广码底图")
@DeleteMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
if (shopActiveImageService.removeByIds(ids)) {
return success("删除成功");
}
return fail("删除失败");
}
}

View File

@@ -1,17 +1,19 @@
package com.gxwebsoft.shop.controller; package com.gxwebsoft.shop.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.BaseController;
import com.gxwebsoft.shop.service.ShopDealerCapitalService; import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.dto.ShopDealerCapitalWaterDto;
import com.gxwebsoft.shop.entity.ShopDealerCapital; import com.gxwebsoft.shop.entity.ShopDealerCapital;
import com.gxwebsoft.shop.param.ShopDealerCapitalParam; import com.gxwebsoft.shop.param.ShopDealerCapitalParam;
import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.shop.service.ShopDealerCapitalService;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.shop.vo.ShopDealerCapitalWaterVO;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.system.entity.User;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -34,11 +36,19 @@ public class ShopDealerCapitalController extends BaseController {
@PreAuthorize("hasAuthority('shop:shopDealerCapital:list')") @PreAuthorize("hasAuthority('shop:shopDealerCapital:list')")
@Operation(summary = "分页查询分销商资金明细表") @Operation(summary = "分页查询分销商资金明细表")
@GetMapping("/page") @GetMapping("/page")
public ApiResult<PageResult<ShopDealerCapital>> page(ShopDealerCapitalParam param) { public ApiResult<PageResult<ShopDealerCapital>> page(@ParameterObject ShopDealerCapitalParam param) {
// 使用关联查询 // 使用关联查询
return success(shopDealerCapitalService.pageRel(param)); return success(shopDealerCapitalService.pageRel(param));
} }
@PreAuthorize("hasAuthority('shop:shopDealerCapital:list')")
@Operation(summary = "分页查询分销商个人流水")
@GetMapping("/myCapitalWater")
public ApiResult<PageResult<ShopDealerCapitalWaterVO>> myCapitalWater(ShopDealerCapitalWaterDto waterDto) {
// 使用关联查询
return success(shopDealerCapitalService.myCapitalWater(waterDto));
}
@PreAuthorize("hasAuthority('shop:shopDealerCapital:list')") @PreAuthorize("hasAuthority('shop:shopDealerCapital:list')")
@Operation(summary = "查询全部分销商资金明细表") @Operation(summary = "查询全部分销商资金明细表")
@GetMapping() @GetMapping()

View File

@@ -3,19 +3,18 @@ package com.gxwebsoft.shop.controller;
import cn.afterturn.easypoi.excel.ExcelImportUtil; import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.gxwebsoft.common.core.annotation.OperationLog;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.shop.service.ShopDealerOrderService;
import com.gxwebsoft.shop.entity.ShopDealerOrder;
import com.gxwebsoft.shop.param.ShopDealerOrderParam;
import com.gxwebsoft.shop.param.ShopDealerOrderImportParam;
import com.gxwebsoft.common.core.utils.JSONUtil; import com.gxwebsoft.common.core.utils.JSONUtil;
import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.BatchParam; import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.entity.ShopDealerOrder;
import com.gxwebsoft.shop.param.ShopDealerOrderImportParam;
import com.gxwebsoft.shop.param.ShopDealerOrderParam;
import com.gxwebsoft.shop.service.ShopDealerOrderService;
import com.gxwebsoft.shop.task.OrderSettlementTask;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
@@ -24,6 +23,7 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -40,6 +40,9 @@ public class ShopDealerOrderController extends BaseController {
@Resource @Resource
private ShopDealerOrderService shopDealerOrderService; private ShopDealerOrderService shopDealerOrderService;
@Resource
private OrderSettlementTask orderSettlementTask;
@PreAuthorize("hasAuthority('shop:shopDealerOrder:list')") @PreAuthorize("hasAuthority('shop:shopDealerOrder:list')")
@Operation(summary = "分页查询分销商订单记录表") @Operation(summary = "分页查询分销商订单记录表")
@GetMapping("/page") @GetMapping("/page")
@@ -64,6 +67,13 @@ public class ShopDealerOrderController extends BaseController {
return success(shopDealerOrderService.getByIdRel(id)); return success(shopDealerOrderService.getByIdRel(id));
} }
@PreAuthorize("hasAuthority('shop:shopDealerOrder:list')")
@Operation(summary = "查询个人今日收益")
@GetMapping("/todayRevenue")
public ApiResult<BigDecimal> todayRevenue() {
return success(shopDealerOrderService.todayRevenue());
}
@PreAuthorize("hasAuthority('shop:shopDealerOrder:save')") @PreAuthorize("hasAuthority('shop:shopDealerOrder:save')")
@OperationLog @OperationLog
@Operation(summary = "添加分销商订单记录表") @Operation(summary = "添加分销商订单记录表")
@@ -173,7 +183,7 @@ public class ShopDealerOrderController extends BaseController {
@PreAuthorize("hasAuthority('shop:shopDealerOrder:update')") @PreAuthorize("hasAuthority('shop:shopDealerOrder:update')")
@OperationLog @OperationLog
@Operation(summary = "手动触发单条订单佣金解冻") @Operation(summary = "手动触发单条订单佣金解冻")
@PostMapping("/unfreeze") // @PostMapping("/unfreeze")
public ApiResult<String> manualUnfreeze(@RequestBody Map<String, Object> body) { public ApiResult<String> manualUnfreeze(@RequestBody Map<String, Object> body) {
String orderNo = (String) body.get("orderNo"); String orderNo = (String) body.get("orderNo");
if (orderNo == null || orderNo.isBlank()) { if (orderNo == null || orderNo.isBlank()) {
@@ -187,4 +197,11 @@ public class ShopDealerOrderController extends BaseController {
return fail(e.getMessage(),null); return fail(e.getMessage(),null);
} }
} }
@Operation(summary = "店、服务商结算任务每天一点每10分钟执行一次结算任务")
@PutMapping("/teamSettlement")
public ApiResult<?> teamSettlement() {
orderSettlementTask.teamSettlement();
return success("success");
}
} }

View File

@@ -1,19 +1,19 @@
package com.gxwebsoft.shop.controller; package com.gxwebsoft.shop.controller;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.Constants; import com.gxwebsoft.common.core.Constants;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.exception.BusinessException; import com.gxwebsoft.common.core.exception.BusinessException;
import com.gxwebsoft.shop.service.ShopDealerRefereeService; 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.common.system.entity.User;
import com.gxwebsoft.shop.entity.ShopDealerReferee; import com.gxwebsoft.shop.entity.ShopDealerReferee;
import com.gxwebsoft.shop.param.ShopDealerRefereeParam; import com.gxwebsoft.shop.param.ShopDealerRefereeParam;
import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.shop.service.ShopDealerRefereeService;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.system.entity.User;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@@ -41,6 +41,13 @@ public class ShopDealerRefereeController extends BaseController {
return success(shopDealerRefereeService.pageRel(param)); return success(shopDealerRefereeService.pageRel(param));
} }
@PreAuthorize("hasAuthority('shop:shopDealerReferee:list')")
@Operation(summary = "分页查询分销商推荐关系表")
@GetMapping("/appPage")
public ApiResult<PageResult<ShopDealerReferee>> appPage(@ParameterObject ShopDealerRefereeParam param) {
return success(shopDealerRefereeService.appPage(param));
}
@PreAuthorize("hasAuthority('shop:shopDealerReferee:list')") @PreAuthorize("hasAuthority('shop:shopDealerReferee:list')")
@Operation(summary = "查询全部分销商推荐关系表") @Operation(summary = "查询全部分销商推荐关系表")
@GetMapping() @GetMapping()

View File

@@ -4,18 +4,19 @@ import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.common.core.utils.JSONUtil;
import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.shop.service.ShopDealerUserService;
import com.gxwebsoft.shop.entity.ShopDealerUser;
import com.gxwebsoft.shop.param.ShopDealerUserParam;
import com.gxwebsoft.shop.param.ShopDealerUserImportParam;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog; import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.core.utils.JSONUtil;
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.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.dto.ShopDealerRefundDto;
import com.gxwebsoft.shop.dto.ShopDealerUserReduceDto;
import com.gxwebsoft.shop.entity.ShopDealerUser;
import com.gxwebsoft.shop.param.ShopDealerUserImportParam;
import com.gxwebsoft.shop.param.ShopDealerUserParam;
import com.gxwebsoft.shop.service.ShopDealerUserService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
@@ -78,6 +79,13 @@ public class ShopDealerUserController extends BaseController {
return fail("添加失败"); return fail("添加失败");
} }
@PreAuthorize("hasAuthority('shop:shopDealerUser:update')")
@Operation(summary = "开启/关闭分销商用户核销权限")
@PutMapping("/verifyEnable")
public ApiResult<Boolean> verifyEnable(@RequestParam("id") Integer id) {
return success(shopDealerUserService.verifyEnable(id));
}
@PreAuthorize("hasAuthority('shop:shopDealerUser:update')") @PreAuthorize("hasAuthority('shop:shopDealerUser:update')")
@Operation(summary = "修改分销商用户记录表") @Operation(summary = "修改分销商用户记录表")
@PutMapping() @PutMapping()
@@ -178,4 +186,18 @@ public class ShopDealerUserController extends BaseController {
return fail("导入失败", null); return fail("导入失败", null);
} }
@Operation(summary = "分销结算")
@PostMapping("/dealerCapital")
@Deprecated
public ApiResult<?> dealerCapital(@RequestBody ShopDealerUserReduceDto reduceDto) {
return success(shopDealerUserService.reduceBalance(reduceDto));
}
@Operation(summary = "分销退单")
@PostMapping("/refundOrder")
@Deprecated
public ApiResult<?> refundOrder(@RequestBody ShopDealerRefundDto refundDto) {
return success(shopDealerUserService.refundOrder(refundDto));
}
} }

View File

@@ -2,6 +2,7 @@ package com.gxwebsoft.shop.controller;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.gxwebsoft.common.core.web.BaseController; import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.system.redis.OrderNoUtils;
import com.gxwebsoft.shop.entity.ShopDealerUser; import com.gxwebsoft.shop.entity.ShopDealerUser;
import com.gxwebsoft.shop.service.ShopDealerUserService; import com.gxwebsoft.shop.service.ShopDealerUserService;
import com.gxwebsoft.shop.service.ShopDealerWithdrawService; import com.gxwebsoft.shop.service.ShopDealerWithdrawService;
@@ -43,6 +44,8 @@ public class ShopDealerWithdrawController extends BaseController {
private ShopDealerUserService shopDealerUserService; private ShopDealerUserService shopDealerUserService;
@Resource @Resource
private WxTransferService wxTransferService; private WxTransferService wxTransferService;
@Resource
private OrderNoUtils orderNoUtils;
@PreAuthorize("hasAuthority('shop:shopDealerWithdraw:list')") @PreAuthorize("hasAuthority('shop:shopDealerWithdraw:list')")
@Operation(summary = "分页查询分销商提现明细表") @Operation(summary = "分页查询分销商提现明细表")
@@ -89,6 +92,8 @@ public class ShopDealerWithdrawController extends BaseController {
return fail("tenantId为空无法发起提现"); return fail("tenantId为空无法发起提现");
} }
String orderNo = orderNoUtils.generate("WD");
shopDealerWithdraw.setOrderNo(orderNo);
shopDealerWithdraw.setTenantId(tenantId); shopDealerWithdraw.setTenantId(tenantId);
shopDealerWithdraw.setUserId(loginUser.getUserId()); shopDealerWithdraw.setUserId(loginUser.getUserId());
@@ -251,7 +256,8 @@ public class ShopDealerWithdrawController extends BaseController {
} }
// 使用提现记录ID构造单号保持幂等微信要求 5-32 且仅字母/数字 // 使用提现记录ID构造单号保持幂等微信要求 5-32 且仅字母/数字
String outBillNo = String.format("WD%03d", db.getId()); String outBillNo = db.getOrderNo();
String remark = "分销商提现"; String remark = "分销商提现";
String userName = db.getRealName(); String userName = db.getRealName();

View File

@@ -0,0 +1,156 @@
package com.gxwebsoft.shop.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.common.system.entity.User;
import com.gxwebsoft.shop.entity.ShopFlashSaleActivity;
import com.gxwebsoft.shop.param.ShopFlashSaleActivityParam;
import com.gxwebsoft.shop.service.ShopFlashSaleActivityService;
import com.gxwebsoft.shop.vo.ShopFlashSaleActivityVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
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 xm
* @since 2026-04-22 17:18:18
*/
@Tag(name = "秒杀活动管理")
@RestController
@RequestMapping("/api/shop/shop-flash-sale-activity")
public class ShopFlashSaleActivityController extends BaseController {
@Resource
private ShopFlashSaleActivityService shopFlashSaleActivityService;
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:list')")
@Operation(summary = "后台分页查询秒杀活动")
@GetMapping("/page")
public ApiResult<PageResult<ShopFlashSaleActivityVO>> page(ShopFlashSaleActivityParam param) {
// 使用关联查询
return success(shopFlashSaleActivityService.pageRel(param));
}
@Operation(summary = "个人获取秒杀活动数据")
@GetMapping("/getMyActive")
public ApiResult<List<ShopFlashSaleActivityVO>> getMyActive(@RequestParam("tenantId") Integer tenantId, Integer popFlag) {
// 使用关联查询
return success(shopFlashSaleActivityService.getMyActive(tenantId, popFlag));
}
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:list')")
@Operation(summary = "查询全部秒杀活动")
@GetMapping()
public ApiResult<List<ShopFlashSaleActivity>> list(ShopFlashSaleActivityParam param) {
// 使用关联查询
return success(shopFlashSaleActivityService.listRel(param));
}
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:list')")
@Operation(summary = "根据id查询秒杀活动")
@GetMapping("/{id}")
public ApiResult<ShopFlashSaleActivityVO> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(shopFlashSaleActivityService.getInfoById(id));
}
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:save')")
@OperationLog
@Operation(summary = "添加秒杀活动")
@PostMapping()
public ApiResult<?> save(@RequestBody ShopFlashSaleActivity shopFlashSaleActivity) {
// 记录当前登录用户id
User loginUser = getLoginUser();
if (loginUser != null) {
shopFlashSaleActivity.setCreator(loginUser.getUserId().toString());
}
if (shopFlashSaleActivityService.save(shopFlashSaleActivity)) {
return success("添加成功");
}
return fail("添加失败");
}
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:update')")
@OperationLog
@Operation(summary = "修改秒杀活动")
@PutMapping()
public ApiResult<?> update(@RequestBody ShopFlashSaleActivity shopFlashSaleActivity) {
shopFlashSaleActivity.setUpdater(String.valueOf(getLoginUserId()));
if (shopFlashSaleActivityService.updateById(shopFlashSaleActivity)) {
return success("修改成功");
}
return fail("修改失败");
}
@OperationLog
@Operation(summary = "开启/关闭秒杀活动状态")
@PutMapping("/updateStatus")
public ApiResult<?> updateStatus(@RequestParam("id") Integer id) {
return success(shopFlashSaleActivityService.updateStatus(id));
}
@Operation(summary = "修改秒杀活动排序")
@PutMapping("/updateSortNumber")
@Parameters({
@Parameter(name = "id", description = "活动ID", required = true, example = "1"),
@Parameter(name = "sortNumber", description = "排序", required = true, example = "2")
})
public ApiResult<?> updateSortNumber(@RequestParam("id") Integer id, @RequestParam("sortNumber") Integer sortNumber) {
return success(shopFlashSaleActivityService.updateSortNumber(id, sortNumber));
}
// @PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:remove')")
@OperationLog
@Operation(summary = "删除秒杀活动")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (shopFlashSaleActivityService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
@PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:save')")
@OperationLog
@Operation(summary = "批量添加秒杀活动")
@PostMapping("/batch")
public ApiResult<?> saveBatch(@RequestBody List<ShopFlashSaleActivity> list) {
if (shopFlashSaleActivityService.saveBatch(list)) {
return success("添加成功");
}
return fail("添加失败");
}
@PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:update')")
@OperationLog
@Operation(summary = "批量修改秒杀活动")
@PutMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody BatchParam<ShopFlashSaleActivity> batchParam) {
if (batchParam.update(shopFlashSaleActivityService, "id")) {
return success("修改成功");
}
return fail("修改失败");
}
@PreAuthorize("hasAuthority('shop:shopFlashSaleActivity:remove')")
@OperationLog
@Operation(summary = "批量删除秒杀活动")
@DeleteMapping("/batch")
public ApiResult<?> removeBatch(@RequestBody List<Integer> ids) {
if (shopFlashSaleActivityService.removeByIds(ids)) {
return success("删除成功");
}
return fail("删除失败");
}
}

View File

@@ -6,7 +6,6 @@ import com.gxwebsoft.shop.entity.ShopGoodsCategory;
import com.gxwebsoft.shop.param.ShopGoodsCategoryParam; import com.gxwebsoft.shop.param.ShopGoodsCategoryParam;
import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.core.web.PageParam;
import com.gxwebsoft.common.core.web.BatchParam; import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.annotation.OperationLog; import com.gxwebsoft.common.core.annotation.OperationLog;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.common.system.entity.User;

View File

@@ -0,0 +1,51 @@
package com.gxwebsoft.shop.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.shop.dto.ShopGoodsProfitUpdateDto;
import com.gxwebsoft.shop.service.ShopGoodsProfitService;
import com.gxwebsoft.shop.vo.ShopGoodsProfitVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.ibatis.annotations.Param;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 商品分润设定控制器
*
* @author xm
* @since 2026-05-20 14:33:00
*/
@Tag(name = "商品分润设定管理")
@RestController
@RequestMapping("/api/shop/shop-goods-profit")
public class ShopGoodsProfitController extends BaseController {
@Resource
private ShopGoodsProfitService shopGoodsProfitService;
// @PreAuthorize("hasAuthority('shop:shopGoodsProfit:list')")
@Operation(summary = "通过商品、类型查询分润信息")
@GetMapping("/getByGoodsId")
@Parameters({
@Parameter(name = "goodsId", description = "商品ID", required = true, example = "10086"),
@Parameter(name = "type", description = "类型 1-分红 2-其他", required = true, example = "1")
})
public ApiResult<List<ShopGoodsProfitVO>> getByGoodsId(@RequestParam("goodsId") Integer goodsId, @Param("type") Integer type) {
return success(shopGoodsProfitService.getByGoodsId(goodsId, type));
}
// @PreAuthorize("hasAuthority('shop:shopGoodsProfit:update')")
@OperationLog
@Operation(summary = "根据商品ID修改商品分润设定")
@PutMapping("/updateByGoodsId")
public ApiResult<Boolean> update(@RequestBody ShopGoodsProfitUpdateDto updateDto) {
return success(shopGoodsProfitService.updateByGoodsId(updateDto));
}
}

View File

@@ -5,42 +5,45 @@ import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.config.CertificateProperties; import com.gxwebsoft.common.core.config.CertificateProperties;
import com.gxwebsoft.common.core.utils.RedisUtil; import com.gxwebsoft.common.core.config.ConfigProperties;
import com.gxwebsoft.common.core.utils.CertificateLoader; import com.gxwebsoft.common.core.utils.CertificateLoader;
import com.gxwebsoft.common.core.utils.RedisUtil;
import com.gxwebsoft.common.core.utils.WechatCertAutoConfig; import com.gxwebsoft.common.core.utils.WechatCertAutoConfig;
import com.gxwebsoft.common.core.utils.WechatPayConfigValidator; import com.gxwebsoft.common.core.utils.WechatPayConfigValidator;
import com.gxwebsoft.common.core.web.ApiResult;
import com.gxwebsoft.common.core.web.BaseController; import com.gxwebsoft.common.core.web.BaseController;
import com.gxwebsoft.common.core.web.BatchParam;
import com.gxwebsoft.common.core.web.PageResult;
import com.gxwebsoft.common.system.entity.Payment; import com.gxwebsoft.common.system.entity.Payment;
import com.gxwebsoft.shop.entity.ShopOrderDelivery; import com.gxwebsoft.common.system.entity.User;
import com.gxwebsoft.shop.entity.ShopUserAddress; import com.gxwebsoft.common.system.redis.OrderNoUtils;
import com.gxwebsoft.shop.service.*; import com.gxwebsoft.glt.service.GltTicketIssueService;
import com.gxwebsoft.glt.service.GltTicketRevokeService; import com.gxwebsoft.glt.service.GltTicketRevokeService;
import com.gxwebsoft.shop.service.impl.KuaiDi100Impl; import com.gxwebsoft.glt.task.DealerOrderSettlement10584Task;
import com.gxwebsoft.shop.task.OrderAutoCancelTask;
import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.shop.param.ShopOrderParam;
import com.gxwebsoft.shop.dto.OrderCreateRequest;
import com.gxwebsoft.shop.dto.OrderPrepayRequest;
import com.gxwebsoft.shop.dto.UpdatePaymentStatusRequest;
import com.gxwebsoft.payment.service.PaymentService;
import com.gxwebsoft.payment.dto.PaymentResponse; import com.gxwebsoft.payment.dto.PaymentResponse;
import com.gxwebsoft.payment.enums.PaymentType; import com.gxwebsoft.payment.enums.PaymentType;
import com.gxwebsoft.common.core.web.ApiResult; import com.gxwebsoft.payment.service.PaymentService;
import com.gxwebsoft.common.core.web.PageResult; import com.gxwebsoft.shop.dto.*;
import com.gxwebsoft.common.core.web.BatchParam; import com.gxwebsoft.shop.entity.ShopOrder;
import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.shop.entity.ShopOrderDelivery;
import com.gxwebsoft.shop.entity.ShopUserAddress;
import com.gxwebsoft.shop.param.ShopOrderParam;
import com.gxwebsoft.shop.service.*;
import com.gxwebsoft.shop.service.impl.KuaiDi100Impl;
import com.gxwebsoft.shop.task.OrderAutoCancelTask;
import com.gxwebsoft.shop.vo.ShopOrderMyVerifyVO;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig; import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser; import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam; import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.payments.model.Transaction; import com.wechat.pay.java.service.payments.model.Transaction;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springdoc.api.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
@@ -110,6 +113,12 @@ public class ShopOrderController extends BaseController {
private GltTicketRevokeService gltTicketRevokeService; private GltTicketRevokeService gltTicketRevokeService;
@Resource @Resource
private ShopDealerCommissionRollbackService shopDealerCommissionRollbackService; private ShopDealerCommissionRollbackService shopDealerCommissionRollbackService;
@Resource
private GltTicketIssueService gltTicketIssueService;
@Resource
private OrderNoUtils orderNoUtils;
@Resource
private DealerOrderSettlement10584Task dealerOrderSettlement;
@Operation(summary = "分页查询订单") @Operation(summary = "分页查询订单")
@GetMapping("/page") @GetMapping("/page")
@@ -133,14 +142,20 @@ public class ShopOrderController extends BaseController {
return success(shopOrderService.getByIdRel(id)); return success(shopOrderService.getByIdRel(id));
} }
@Operation(summary = "添加订单") // @PreAuthorize("hasAuthority('shop:shopOrder:list')")
@Operation(summary = "我已核销订单")
@GetMapping("/myVerifyOrder")
public ApiResult<ShopOrderMyVerifyVO> myVerifyOrder(@ParameterObject ShopOrderMyVerifyDto myVerifyDto) {
return success(shopOrderService.myVerifyOrder(myVerifyDto));
}
@Operation(summary = "添加订单【单商品添加】")
@PostMapping() @PostMapping()
public ApiResult<?> save(@RequestBody OrderCreateRequest request) { public ApiResult<?> save(@RequestBody OrderCreateRequest request) {
User loginUser = getLoginUser(); User loginUser = getLoginUser();
if (loginUser == null) { if (loginUser == null) {
return fail("用户未登录"); return fail("用户未登录");
} }
try { try {
Map<String, String> wxOrderInfo = orderBusinessService.createOrder(request, loginUser); Map<String, String> wxOrderInfo = orderBusinessService.createOrder(request, loginUser);
return success("下单成功", wxOrderInfo); return success("下单成功", wxOrderInfo);
@@ -494,12 +509,12 @@ public class ShopOrderController extends BaseController {
if (!Boolean.TRUE.equals(current.getPayStatus())) { if (!Boolean.TRUE.equals(current.getPayStatus())) {
return fail("订单未支付,无法退款"); return fail("订单未支付,无法退款");
} }
if (StrUtil.isNotBlank(current.getRefundOrder())) { if (StrUtil.isNotBlank(current.getRefundOrder()) || current.getOrderStatus() == 6) {
logger.warn("订单已经退款过,订单号: {}, 退款单号: {}", current.getOrderNo(), current.getRefundOrder()); logger.warn("订单已经退款过,订单号: {}, 退款单号: {}", current.getOrderNo(), current.getRefundOrder() != null ? current.getRefundOrder() : "");
return fail("订单已退款,请勿重复操作"); return fail("订单已退款,请勿重复操作");
} }
String refundNo = "RF" + IdUtil.getSnowflakeNextId(); String refundNo = orderNoUtils.generate("RF");
BigDecimal refundAmount = req.getRefundMoney(); BigDecimal refundAmount = req.getRefundMoney();
if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) { if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) {
@@ -573,7 +588,7 @@ public class ShopOrderController extends BaseController {
rollbackOrder.setOrderNo(current.getOrderNo()); rollbackOrder.setOrderNo(current.getOrderNo());
rollbackOrder.setPayPrice(current.getPayPrice()); rollbackOrder.setPayPrice(current.getPayPrice());
rollbackOrder.setTotalPrice(current.getTotalPrice()); rollbackOrder.setTotalPrice(current.getTotalPrice());
boolean rollbackOk = shopDealerCommissionRollbackService.rollbackOnOrderRefund(rollbackOrder, refundAmount); boolean rollbackOk = shopDealerCommissionRollbackService.rollbackOnOrderRefundV2(rollbackOrder, refundAmount);
if (!rollbackOk) { if (!rollbackOk) {
logger.error("退款成功但回退分红/分润/佣金失败 - tenantId={}, orderId={}, orderNo={}", logger.error("退款成功但回退分红/分润/佣金失败 - tenantId={}, orderId={}, orderNo={}",
tenantId, current.getOrderId(), current.getOrderNo()); tenantId, current.getOrderId(), current.getOrderNo());
@@ -764,7 +779,7 @@ public class ShopOrderController extends BaseController {
@Schema(description = "异步通知11") @Schema(description = "异步通知11")
@PostMapping("/notify/{tenantId}") @PostMapping("/notify/{tenantId}")
public String wxNotify(@RequestHeader Map<String, String> header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) { public String wxNotify(@RequestHeader Map<String, String> header, @RequestBody String body, @PathVariable("tenantId") Integer tenantId) {
logger.info("异步通知*************** = " + tenantId); logger.info("异步通知*************** = " + body + ",租户:" +tenantId);
// 获取支付配置信息用于解密 // 获取支付配置信息用于解密
String key = "Payment:1:".concat(tenantId.toString()); String key = "Payment:1:".concat(tenantId.toString());
@@ -802,7 +817,7 @@ public class ShopOrderController extends BaseController {
if (config == null) { if (config == null) {
try { try {
NotificationConfig newConfig; NotificationConfig newConfig;
if (active.equals("dev")) { if (active.equals("local")) {
// 开发环境 - 构建包含租户号的私钥路径 // 开发环境 - 构建包含租户号的私钥路径
String tenantCertPath = "dev/wechat/" + tenantId; String tenantCertPath = "dev/wechat/" + tenantId;
String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile(); String privateKeyPath = tenantCertPath + "/" + certConfig.getWechatPay().getDev().getPrivateKeyFile();
@@ -900,7 +915,7 @@ public class ShopOrderController extends BaseController {
logger.info("开始解析微信支付异步通知..."); logger.info("开始解析微信支付异步通知...");
Transaction transaction = parser.parse(requestParam, Transaction.class); Transaction transaction = parser.parse(requestParam, Transaction.class);
logger.info("✅ 异步通知解析成功 - 交易状态: {}, 商户订单号: {}", logger.info("✅ 异步通知解析成功 - 交易状态: {}, 商户订单号: {}",
transaction.getTradeStateDesc(), transaction.getOutTradeNo()); transaction.getTradeState(), transaction.getOutTradeNo());
// 使用枚举值判断支付状态,避免依赖状态描述字符串 // 使用枚举值判断支付状态,避免依赖状态描述字符串
if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) { if (Transaction.TradeStateEnum.SUCCESS.equals(transaction.getTradeState())) {
@@ -935,6 +950,10 @@ public class ShopOrderController extends BaseController {
System.out.println("实际付款金额 = " + order.getPayPrice()); System.out.println("实际付款金额 = " + order.getPayPrice());
// 更新订单状态并处理支付成功后的业务逻辑(包括累加商品销量) // 更新订单状态并处理支付成功后的业务逻辑(包括累加商品销量)
shopOrderService.updateByOutTradeNo(order); shopOrderService.updateByOutTradeNo(order);
//支付成功执行异步任务
gltTicketIssueService.paySuccessTask(order.getOrderNo(), tenantId);
return "SUCCESS"; return "SUCCESS";
} }
} }
@@ -955,6 +974,40 @@ public class ShopOrderController extends BaseController {
return "fail"; return "fail";
} }
@Operation(summary = "核销订单", description = "核销员扫码核销用户订单")
@PutMapping("/verifyOrder")
public ApiResult<Boolean> verifyOrder(@RequestBody VerifyShopOrderDto verifyDto){
return success(shopOrderService.verifyOrder(verifyDto));
}
@Operation(summary = "支付成功任务", description = "用户支付成功后执行任务")
@PutMapping("/paySuccessTask")
public ApiResult<Boolean> paySuccessTask(@RequestBody PaySuccessTaskDto taskDto){
gltTicketIssueService.paySuccessTask(taskDto.getOrderNo(), taskDto.getTenantId());
return success(Boolean.TRUE);
}
@Operation(summary = "支付成功发送水票", description = "支付成功发送水票")
@PutMapping("/suerTicketRelease")
public ApiResult<Boolean> suerTicketRelease(@RequestBody PaySuccessTaskDto taskDto){
gltTicketIssueService.suerTicketRelease(taskDto.getOrderNo(), taskDto.getTenantId());
return success(Boolean.TRUE);
}
@Operation(summary = "支付成功结算", description = "支付成功结算")
@PutMapping("/orderSettlement")
public ApiResult<Boolean> orderSettlement(@RequestBody PaySuccessTaskDto taskDto){
dealerOrderSettlement.orderSettlement(taskDto.getOrderNo());
return success(Boolean.TRUE);
}
@Operation(summary = "分红结算", description = "分红结算")
@PutMapping("/partnerProfit")
public ApiResult<Boolean> partnerProfit(@RequestBody PaySuccessTaskDto taskDto){
dealerOrderSettlement.partnerProfit(taskDto.getOrderNo(), taskDto.getTenantId());
return success(Boolean.TRUE);
}
@Operation(summary = "更新订单支付状态", description = "用户支付成功后主动同步订单状态") @Operation(summary = "更新订单支付状态", description = "用户支付成功后主动同步订单状态")
@PutMapping("/payment-status") @PutMapping("/payment-status")
public ApiResult<?> updateOrderPaymentStatus(@RequestBody UpdatePaymentStatusRequest request) { public ApiResult<?> updateOrderPaymentStatus(@RequestBody UpdatePaymentStatusRequest request) {

View File

@@ -0,0 +1,88 @@
package com.gxwebsoft.shop.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.PageResult;
import com.gxwebsoft.shop.entity.ShopSurchargeConfig;
import com.gxwebsoft.shop.param.ShopSurchargeConfigParam;
import com.gxwebsoft.shop.service.ShopSurchargeConfigService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
/**
* 步梯费用设置控制器
*
* @author xm
* @since 2026-04-28 16:30:00
*/
@Tag(name = "步梯费用设置管理")
@RestController
@RequestMapping("/api/shop/shop-surcharge-config")
public class ShopSurchargeConfigController extends BaseController {
@Resource
private ShopSurchargeConfigService shopSurchargeConfigService;
// @PreAuthorize("hasAuthority('shop:shopSurchargeConfig:list')")
@Operation(summary = "分页查询步梯费用设置")
@GetMapping("/page")
public ApiResult<PageResult<ShopSurchargeConfig>> page(ShopSurchargeConfigParam param) {
// 使用关联查询
return success(shopSurchargeConfigService.pageRel(param));
}
// @PreAuthorize("hasAuthority('shop:shopSurchargeConfig:list')")
@Operation(summary = "根据id查询步梯费用设置")
@GetMapping("/{id}")
public ApiResult<ShopSurchargeConfig> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(shopSurchargeConfigService.getByIdRel(id));
}
// @PreAuthorize("hasAuthority('shop:shopSurchargeConfig:list')")
@Operation(summary = "根据类型查询步梯费用设置")
@GetMapping("/getInfoByType")
public ApiResult<ShopSurchargeConfig> getInfoByType(@RequestParam Integer type) {
// 使用关联查询
return success(shopSurchargeConfigService.getInfoByType(type));
}
// @PreAuthorize("hasAuthority('shop:shopSurchargeConfig:save')")
@OperationLog
@Operation(summary = "添加步梯费用设置")
@PostMapping()
public ApiResult<Integer> save(@RequestBody ShopSurchargeConfig shopSurchargeConfig) {
return success(shopSurchargeConfigService.saveInfo(shopSurchargeConfig));
}
// @PreAuthorize("hasAuthority('shop:shopSurchargeConfig:update')")
@OperationLog
@Operation(summary = "修改步梯费用设置")
@PutMapping()
public ApiResult<Boolean> update(@RequestBody ShopSurchargeConfig shopSurchargeConfig) {
return success(shopSurchargeConfigService.updateInfo(shopSurchargeConfig));
}
// @PreAuthorize("hasAuthority('shop:shopSurchargeConfig:update')")
@OperationLog
@Operation(summary = "修改步梯费用设置")
@PutMapping("/updateStatus")
public ApiResult<Boolean> updateStatus(@RequestParam("id") Integer id) {
return success(shopSurchargeConfigService.updateStatus(id));
}
// @PreAuthorize("hasAuthority('shop:shopSurchargeConfig:remove')")
@OperationLog
@Operation(summary = "删除步梯费用设置")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (shopSurchargeConfigService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
}

View File

@@ -31,7 +31,7 @@
@Resource @Resource
private ShopUserAddressService shopUserAddressService; private ShopUserAddressService shopUserAddressService;
@PreAuthorize("hasAuthority('shop:shopUserAddress:list')") // @PreAuthorize("hasAuthority('shop:shopUserAddress:list')")
@Operation(summary = "分页查询收货地址") @Operation(summary = "分页查询收货地址")
@GetMapping("/page") @GetMapping("/page")
public ApiResult<PageResult<ShopUserAddress>> page(ShopUserAddressParam param) { public ApiResult<PageResult<ShopUserAddress>> page(ShopUserAddressParam param) {
@@ -39,7 +39,7 @@
return success(shopUserAddressService.pageRel(param)); return success(shopUserAddressService.pageRel(param));
} }
@PreAuthorize("hasAuthority('shop:shopUserAddress:list')") // @PreAuthorize("hasAuthority('shop:shopUserAddress:list')")
@Operation(summary = "查询全部收货地址") @Operation(summary = "查询全部收货地址")
@GetMapping() @GetMapping()
public ApiResult<List<ShopUserAddress>> list(ShopUserAddressParam param) { public ApiResult<List<ShopUserAddress>> list(ShopUserAddressParam param) {
@@ -48,7 +48,7 @@
return success(shopUserAddressService.listRel(param)); return success(shopUserAddressService.listRel(param));
} }
@PreAuthorize("hasAuthority('shop:shopUserAddress:list')") // @PreAuthorize("hasAuthority('shop:shopUserAddress:list')")
@Operation(summary = "根据id查询收货地址") @Operation(summary = "根据id查询收货地址")
@GetMapping("/{id}") @GetMapping("/{id}")
public ApiResult<ShopUserAddress> get(@PathVariable("id") Integer id) { public ApiResult<ShopUserAddress> get(@PathVariable("id") Integer id) {
@@ -56,7 +56,7 @@
return success(shopUserAddressService.getByIdRel(id)); return success(shopUserAddressService.getByIdRel(id));
} }
@PreAuthorize("hasAuthority('shop:shopUserAddress:save')") // @PreAuthorize("hasAuthority('shop:shopUserAddress:save')")
@OperationLog @OperationLog
@Operation(summary = "添加收货地址") @Operation(summary = "添加收货地址")
@PostMapping() @PostMapping()
@@ -75,18 +75,15 @@
return fail("添加失败"); return fail("添加失败");
} }
@PreAuthorize("hasAuthority('shop:shopUserAddress:update')") // @PreAuthorize("hasAuthority('shop:shopUserAddress:update')")
@OperationLog @OperationLog
@Operation(summary = "修改收货地址") @Operation(summary = "修改收货地址")
@PutMapping() @PutMapping()
public ApiResult<?> update(@RequestBody ShopUserAddress shopUserAddress) { public ApiResult<Boolean> update(@RequestBody ShopUserAddress shopUserAddress) {
if (shopUserAddressService.updateById(shopUserAddress)) { return success(shopUserAddressService.updateInfo(shopUserAddress));
return success("修改成功");
}
return fail("修改失败");
} }
@PreAuthorize("hasAuthority('shop:shopUserAddress:remove')") // @PreAuthorize("hasAuthority('shop:shopUserAddress:remove')")
@OperationLog @OperationLog
@Operation(summary = "删除收货地址") @Operation(summary = "删除收货地址")
@DeleteMapping("/{id}") @DeleteMapping("/{id}")

View File

@@ -0,0 +1,103 @@
package com.gxwebsoft.shop.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.PageResult;
import com.gxwebsoft.shop.entity.ShopVerifyUser;
import com.gxwebsoft.shop.param.ShopVerifyUserParam;
import com.gxwebsoft.shop.service.ShopVerifyUserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 订单核销人管理控制器
*
* @author xm
* @since 2026-05-25 17:13:01
*/
@Tag(name = "订单核销人管理管理")
@RestController
@RequestMapping("/api/shop/shop-verify-user")
public class ShopVerifyUserController extends BaseController {
@Resource
private ShopVerifyUserService shopVerifyUserService;
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:list')")
@Operation(summary = "分页查询订单核销人管理")
@GetMapping("/page")
public ApiResult<PageResult<ShopVerifyUser>> page(ShopVerifyUserParam param) {
// 使用关联查询
return success(shopVerifyUserService.pageRel(param));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:list')")
@Operation(summary = "查询全部订单核销人管理")
@GetMapping()
public ApiResult<List<ShopVerifyUser>> list(ShopVerifyUserParam param) {
// 使用关联查询
return success(shopVerifyUserService.listRel(param));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:list')")
@Operation(summary = "根据id查询订单核销人管理")
@GetMapping("/{id}")
public ApiResult<ShopVerifyUser> get(@PathVariable("id") Integer id) {
// 使用关联查询
return success(shopVerifyUserService.getByIdRel(id));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:list')")
@Operation(summary = "根据用户ID查询订单核销人管理")
@GetMapping("/getByUserId")
public ApiResult<ShopVerifyUser> getByUserId(@RequestParam("userId") Integer userId) {
return success(shopVerifyUserService.getInfo(userId));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:save')")
@OperationLog
@Operation(summary = "添加订单核销人管理")
@PostMapping()
public ApiResult<Boolean> save(@RequestBody ShopVerifyUser shopVerifyUser) {
return success(shopVerifyUserService.saveInfo(shopVerifyUser));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:update')")
@Operation(summary = "修改订单核销人管理")
@PutMapping()
public ApiResult<?> update(@RequestBody ShopVerifyUser shopVerifyUser) {
if (shopVerifyUserService.updateById(shopVerifyUser)) {
return success("修改成功");
}
return fail("修改失败");
}
@Operation(summary = "修改订单核销人开启状态")
@PutMapping("/updateStatus")
public ApiResult<Boolean> updateStatus(@RequestParam("id") Integer id) {
return success(shopVerifyUserService.updateStatus(id));
}
@Operation(summary = "修改订单核销人核销权限")
@PutMapping("/updateVerifyFlag")
public ApiResult<Boolean> updateVerifyFlag(@RequestParam("id") Integer id) {
return success(shopVerifyUserService.updateVerifyFlag(id));
}
// @PreAuthorize("hasAuthority('shop:shopVerifyUser:remove')")
@OperationLog
@Operation(summary = "删除订单核销人管理")
@DeleteMapping("/{id}")
public ApiResult<?> remove(@PathVariable("id") Integer id) {
if (shopVerifyUserService.removeById(id)) {
return success("删除成功");
}
return fail("删除失败");
}
}

View File

@@ -6,6 +6,7 @@ import lombok.Data;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.*; import javax.validation.constraints.*;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List; import java.util.List;
/** /**
@@ -27,6 +28,9 @@ public class OrderCreateRequest {
@Max(value = 2, message = "订单类型值无效") @Max(value = 2, message = "订单类型值无效")
private Integer type; private Integer type;
@Schema(description = "订单类型 1-及时自配送 2-自提 3-预约自配送 4-发快递 5-配送【系统自动识别电子围栏内转及时配送,电子围栏外发快递】")
private Integer orderType;
@Size(max = 60, message = "备注长度不能超过60个字符") @Size(max = 60, message = "备注长度不能超过60个字符")
@Schema(description = "订单标题") @Schema(description = "订单标题")
private String title; private String title;
@@ -88,6 +92,12 @@ public class OrderCreateRequest {
@Schema(description = "发货店铺") @Schema(description = "发货店铺")
private String expressMerchantName; private String expressMerchantName;
@Schema(description = "配送方式 0-电梯 1-步梯")
private Integer deliveryMethod;
@Schema(description = "楼层")
private Integer deliveryFloor;
@Schema(description = "订单总额") @Schema(description = "订单总额")
@NotNull(message = "订单总额不能为空") @NotNull(message = "订单总额不能为空")
@DecimalMin(value = "0.01", message = "订单总额必须大于0") @DecimalMin(value = "0.01", message = "订单总额必须大于0")
@@ -147,6 +157,12 @@ public class OrderCreateRequest {
@NotNull(message = "租户ID不能为空") @NotNull(message = "租户ID不能为空")
private Integer tenantId; private Integer tenantId;
@Schema(description = "秒杀活动ID")
private Integer activityId;
@Schema(description = "配送时间")
private LocalDateTime sendTime;
@Schema(description = "订单商品列表") @Schema(description = "订单商品列表")
@Valid @Valid
@NotEmpty(message = "订单商品列表不能为空") @NotEmpty(message = "订单商品列表不能为空")
@@ -158,14 +174,17 @@ public class OrderCreateRequest {
@Data @Data
@Schema(name = "OrderGoodsItem", description = "订单商品项") @Schema(name = "OrderGoodsItem", description = "订单商品项")
public static class OrderGoodsItem { public static class OrderGoodsItem {
@Schema(description = "商品ID", required = true) @Schema(description = "秒杀活动ID")
private Integer activityId;
@Schema(description = "商品ID")
@NotNull(message = "商品ID不能为空") @NotNull(message = "商品ID不能为空")
private Integer goodsId; private Integer goodsId;
@Schema(description = "商品SKU ID") @Schema(description = "商品SKU ID")
private Integer skuId; private Integer skuId;
@Schema(description = "商品数量", required = true) @Schema(description = "商品数量")
@NotNull(message = "商品数量不能为空") @NotNull(message = "商品数量不能为空")
@Min(value = 1, message = "商品数量必须大于0") @Min(value = 1, message = "商品数量必须大于0")
private Integer quantity; private Integer quantity;

View File

@@ -0,0 +1,25 @@
package com.gxwebsoft.shop.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 支付成功执行请求类
*
* @author xm
* @since 2026-05-04
*/
@Data
@Schema(name = "PaySuccessTaskDto", description = "支付成功执行请求类")
public class PaySuccessTaskDto {
@Schema(description = "订单号")
@NotBlank(message = "订单号不能为空")
private String orderNo;
@Schema(description = "租户ID", example = "10584")
private Integer tenantId;
}

View File

@@ -0,0 +1,28 @@
package com.gxwebsoft.shop.dto;
import com.gxwebsoft.common.core.web.BaseParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
/**
* 查询个人流水
*
*/
@Data
@Schema(name = "ShopDealerCapitalWaterDto", description = "查询个人流水")
public class ShopDealerCapitalWaterDto extends BaseParam {
@Schema(description = "用户ID")
@NotEmpty(message = "用户ID不能为空")
private Integer userId;
@Schema(description = "起始时间", example = "2026-05-01")
private String dateStart;
@Schema(description = "结束时间", example = "2026-05-31")
private String dateEnd;
}

View File

@@ -0,0 +1,28 @@
package com.gxwebsoft.shop.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* 分销订单退款
* @author xm
* @since 2026-05-13
*/
@Data
@Schema(name = "ShopDealerUserReduceDto", description = "分销订单退款")
public class ShopDealerRefundDto {
@Schema(description = "订单号")
@NotNull(message = "变订单号不可为空!")
private String orderNo;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "退款金额")
private BigDecimal refundAmount;
}

View File

@@ -0,0 +1,37 @@
package com.gxwebsoft.shop.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* 分销订单结算
* @author xm
* @since 2026-05-13
*/
@Data
@Schema(name = "ShopDealerSettlementDto", description = "分销订单结算")
public class ShopDealerSettlementDto {
@Schema(description = "变动类型 1-操作冻结账户余额 2-操作提现账户余额【直接结算】 3-解冻 4-退款")
private Integer type;
@Schema(description = "资金流动类型 (10分销收入 11团队管理津贴收入 12分红收入 13现场推广收入 20提现支出 30转账支出 40转账收入 50佣金解冻 60配送奖励 70佣金退回【退单】)")
private Integer flowType;
@Schema(description = "订单号")
private String orderNo;
@Schema(description = "描述")
private String comments;
@Schema(description = "分销来源")
private Integer toUserId;
@Schema(description = "商城ID")
private Integer tenantId;
@Schema(description = "明细列表")
private List<ShopDealerSettlementItemDto> itemList;
}

View File

@@ -0,0 +1,26 @@
package com.gxwebsoft.shop.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 分销订单退款
* @author xm
* @since 2026-05-13
*/
@Data
@Schema(name = "ShopDealerSettlementItemDto", description = "分销订单退款")
public class ShopDealerSettlementItemDto {
@Schema(description = "订单号")
private String no;
@Schema(description = "分销商用户ID")
private Integer userId;
@Schema(description = "变更金额")
private BigDecimal money;
}

View File

@@ -0,0 +1,42 @@
package com.gxwebsoft.shop.dto;
import com.gxwebsoft.common.core.enums.ShopDealerCapitalUpdateEnum;
import com.gxwebsoft.common.core.enums.ShopDealerTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
/**
* 更新分销用户资金
* @author xm
* @since 2026-05-06
*/
@Data
@Schema(name = "ShopDealerUserReduceDto", description = "更新分销用户资金请求")
public class ShopDealerUserReduceDto {
@Schema(description = "变动类型 1-操作冻结账户余额 2-操作提现账户余额【直接结算】 3-解冻")
@NotNull(message = "变更类型不可为空!")
private ShopDealerTypeEnum typeEnum;
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "订单主体用户ID")
private Integer orderUserId;
@Schema(description = "订单号")
@NotEmpty(message = "订单号不能为空!")
private String orderNo;
@Schema(description = "变更金额")
private BigDecimal price;
@Schema(description = "业务类型")
@NotEmpty(message = "业务类型不能为空!")
private ShopDealerCapitalUpdateEnum updateEnum;
}

View File

@@ -0,0 +1,29 @@
package com.gxwebsoft.shop.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* 商品分润设定更新
*
* @author xm
* @since 2026-05-20 14:33:00
*/
@Data
public class ShopGoodsProfitUpdateDto {
@Schema(description = "商品ID")
@NotEmpty(message = "商品ID不能为空")
private Integer goodsId;
@Schema(description = "分润类型 1-股东分红 2-其他")
@NotEmpty(message = "分润类型不能为空!")
private Integer type;
@Schema(description = "变更明细")
private List<ShopGoodsProfitUpdateItemDto> itemList;
}

View File

@@ -0,0 +1,26 @@
package com.gxwebsoft.shop.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
/**
* 商品分润设定更新
*
* @author xm
* @since 2026-05-20 14:33:00
*/
@Data
public class ShopGoodsProfitUpdateItemDto {
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "分佣比例 百分比")
private BigDecimal profit;
@Schema(description = "开启状态 0-未开启 1-开启")
private Integer status;
}

View File

@@ -0,0 +1,27 @@
package com.gxwebsoft.shop.dto;
import com.gxwebsoft.common.core.web.BaseParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
* 查询个人核销记录
*
*/
@Data
@Schema(name = "ShopOrderMyVerifyDto", description = "查询个人核销记录")
public class ShopOrderMyVerifyDto extends BaseParam {
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "订单号")
private String orderNo;
@Schema(description = "开始时间【核销时间】", example = "2026-05-20")
private String dateStart;
@Schema(description = "结束时间【核销时间】", example = "2026-05-25")
private String dateEnd;
}

View File

@@ -26,7 +26,7 @@ public class UserOrderStats implements Serializable {
@Schema(description = "待核销statusFilter=2") @Schema(description = "待核销statusFilter=2")
private Long waitVerify; private Long waitVerify;
@Schema(description = "待收货statusFilter=3") @Schema(description = "待收货/使用statusFilter=3")
private Long waitReceive; private Long waitReceive;
@Schema(description = "待评价statusFilter=4") @Schema(description = "待评价statusFilter=4")

View File

@@ -0,0 +1,25 @@
package com.gxwebsoft.shop.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* 更新订单支付状态请求DTO
*
* @author xm
* @since 2026-05-04
*/
@Data
@Schema(name = "VerifyShopOrderDto", description = "更新订单支付状态请求")
public class VerifyShopOrderDto {
@Schema(description = "核销码")
@NotBlank(message = "核销码不能为空")
private String verifyCode;
@Schema(description = "核销码类型 1-普通核销【无推广佣金】 2-推广结算【有订单佣金】", example = "2")
private Integer verifyType;
}

View File

@@ -0,0 +1,81 @@
package com.gxwebsoft.shop.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.time.LocalDateTime;
import java.io.Serializable;
import java.util.List;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.NotNull;
/**
* 推广码底图
*
* @author xm
* @since 2026-04-27 18:02:17
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopActiveImage对象", description = "推广码底图")
@TableName("shop_active_image")
public class ShopActiveImage implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "名称")
private String name;
@Schema(description = "类型 0-推广底图 1-其他")
private Integer type;
@Schema(description = "图片地址,多个以‘,’隔开")
private String imgUrl;
@Schema(description = "分享底图")
private String shareImg;
@Schema(description = "图片地址集合")
@TableField(exist = false)
private List<String> imgUrlList;
@Schema(description = "启用状态 0-启用 1-禁用")
private Integer status;
@Schema(description = "排序")
private Integer sortNumber;
@Schema(description = "跳转商品ID")
private Integer goodsId;
@Schema(description = "跳转商品名称")
@TableField(exist = false)
private String goodsName;
@Schema(description = "租户ID")
@NotNull(message = "租户ID不能为空")
private Integer tenantId;
@Schema(description = "创建人")
private String creator;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新人")
private String updater;
@Schema(description = "修改时间")
private LocalDateTime updateTime;
@Schema(description = "是否删除 0-未删 1-已删")
@TableLogic
private Integer deleted;
}

View File

@@ -1,10 +1,11 @@
package com.gxwebsoft.shop.entity; package com.gxwebsoft.shop.entity;
import java.math.BigDecimal; import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable; import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@@ -20,6 +21,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopDealerCapital对象", description = "分销商资金明细表") @Schema(name = "ShopDealerCapital对象", description = "分销商资金明细表")
@TableName("shop_dealer_capital")
public class ShopDealerCapital implements Serializable { public class ShopDealerCapital implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -27,26 +29,41 @@ public class ShopDealerCapital implements Serializable {
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Integer id; private Integer id;
@Schema(description = "订单编号")
private String no;
@Schema(description = "分销商用户ID") @Schema(description = "分销商用户ID")
private Integer userId; private Integer userId;
@Schema(description = "变动类型 1-操作冻结账户余额 2-操作提现账户余额【直接结算】 3-解冻 4-退款")
private Integer type;
@Schema(description = "分销商昵称") @Schema(description = "分销商昵称")
@TableField(exist = false) @TableField(exist = false)
private String nickName; private String nickName;
@Schema(description = "订单编号") @Schema(description = "关联订单编号")
private String orderNo; private String orderNo;
@Schema(description = "订单状态") @Schema(description = "订单状态")
@TableField(exist = false) @TableField(exist = false)
private Integer orderStatus; private Integer orderStatus;
@Schema(description = "资金流动类型 (10佣金收入 20提现支出 30转账支出 40转账收入 50佣金解冻 60配送奖励)") @Schema(description = "资金流动类型 (10分销收入 11团队管理津贴收入 12分红收入 13现场推广收入 14现场推广分佣 20提现支出 30转账支出 40转账收入 50佣金解冻 60配送奖励 61配送提成 62配送步梯费 70佣金退回【退单】)")
private Integer flowType; private Integer flowType;
@Schema(description = "金额") @Schema(description = "变更金额")
private BigDecimal money; private BigDecimal money;
@Schema(description = "变更后金额")
private BigDecimal moneyAfter;
@Schema(description = "变更冻结金额")
private BigDecimal freezeMoney;
@Schema(description = "变更冻结后金额")
private BigDecimal freezeMoneyAfter;
@Schema(description = "描述") @Schema(description = "描述")
private String comments; private String comments;
@@ -60,9 +77,15 @@ public class ShopDealerCapital implements Serializable {
@Schema(description = "结算月份") @Schema(description = "结算月份")
private String month; private String month;
@Schema(description = "结算标识 0-未结算 1-已结算")
private Integer paymentFlag;
@Schema(description = "商城ID") @Schema(description = "商城ID")
private Integer tenantId; private Integer tenantId;
@Schema(description = "创建人")
private Integer creator;
@Schema(description = "创建时间") @Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime; private LocalDateTime createTime;
@@ -71,4 +94,8 @@ public class ShopDealerCapital implements Serializable {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime; private LocalDateTime updateTime;
@Schema(description = "是否删除 0-未删 1-已删")
@TableLogic
private Integer deleted;
} }

View File

@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable; import java.io.Serializable;
@@ -23,6 +25,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopDealerOrder对象", description = "分销商订单记录表") @Schema(name = "ShopDealerOrder对象", description = "分销商订单记录表")
@TableName("shop_dealer_order")
public class ShopDealerOrder implements Serializable { public class ShopDealerOrder implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -66,6 +69,9 @@ public class ShopDealerOrder implements Serializable {
@TableField(exist = false) @TableField(exist = false)
private String firstNickname; private String firstNickname;
@Schema(description = "分销佣金(一级)")
private BigDecimal firstMoney;
@Schema(description = "分销商用户id(二级)") @Schema(description = "分销商用户id(二级)")
private Integer secondUserId; private Integer secondUserId;
@@ -73,42 +79,57 @@ public class ShopDealerOrder implements Serializable {
@TableField(exist = false) @TableField(exist = false)
private String secondNickname; private String secondNickname;
@Schema(description = "分销商用户id(三级)")
private Integer thirdUserId;
@Schema(description = "分销商用户昵称(三级)")
@TableField(exist = false)
private String thirdNickname;
@Schema(description = "分销佣金(一级)")
private BigDecimal firstMoney;
@Schema(description = "分销佣金(二级)") @Schema(description = "分销佣金(二级)")
private BigDecimal secondMoney; private BigDecimal secondMoney;
@Schema(description = "分销佣金(三级)") @Schema(description = "分销商用户id(弃用)")
private Integer thirdUserId;
@Schema(description = "分销商用户昵称(弃用)")
@TableField(exist = false)
private String thirdNickname;
@Schema(description = "分销佣金(弃用)")
private BigDecimal thirdMoney; private BigDecimal thirdMoney;
@Schema(description = "门店(一级)") @Schema(description = "一级服务商/门店")
private Integer firstDividendUser; private Integer firstDividendUser;
@Schema(description = "门店名称(一级)") @Schema(description = "一级服务商/门店名称")
@TableField(exist = false) @TableField(exist = false)
private String firstDividendUserName; private String firstDividendUserName;
@Schema(description = "分红(一级)") @Schema(description = "一级服务商/门店管理津贴")
private BigDecimal firstDividend; private BigDecimal firstDividend;
@Schema(description = "门店(二级)") @Schema(description = "一级服务商/门店结算标识 0-否 1-是")
private Integer firstDividendFlag;
@Schema(description = "一级服务商/门店结算单号")
private String firstDividendNo;
@Schema(description = "一级服务商/门店结算时间")
private LocalDateTime firstDividendTime;
@Schema(description = "二级服务商/门店")
private Integer secondDividendUser; private Integer secondDividendUser;
@Schema(description = "门店名称(二级)") @Schema(description = "二级服务商/门店名称")
@TableField(exist = false) @TableField(exist = false)
private String secondDividendUserName; private String secondDividendUserName;
@Schema(description = "分红(二级)") @Schema(description = "二级服务商/门店管理津贴")
private BigDecimal secondDividend; private BigDecimal secondDividend;
@Schema(description = "二级服务商/门店结算标识 0-否 1-是")
private Integer secondDividendFlag;
@Schema(description = "二级服务商/门店结算单号")
private String secondDividendNo;
@Schema(description = "二级服务商/门店结算时间")
private LocalDateTime secondDividendTime;
@Schema(description = "佣金比例") @Schema(description = "佣金比例")
private BigDecimal rate; private BigDecimal rate;

View File

@@ -3,6 +3,8 @@ package com.gxwebsoft.shop.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable; import java.io.Serializable;
@@ -87,4 +89,16 @@ public class ShopDealerReferee implements Serializable {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime; private LocalDateTime updateTime;
@Schema(description = "团队成员")
@TableField(exist = false)
private Integer teamNum;
@Schema(description = "订单数")
@TableField(exist = false)
private Integer orderNum;
@Schema(description = "订单金额")
@TableField(exist = false)
private BigDecimal orderAmount;
} }

View File

@@ -1,10 +1,11 @@
package com.gxwebsoft.shop.entity; package com.gxwebsoft.shop.entity;
import java.math.BigDecimal; import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable; import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@@ -20,6 +21,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopDealerUser对象", description = "分销商用户记录表") @Schema(name = "ShopDealerUser对象", description = "分销商用户记录表")
@TableName("shop_dealer_user")
public class ShopDealerUser implements Serializable { public class ShopDealerUser implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -102,6 +104,9 @@ public class ShopDealerUser implements Serializable {
@Schema(description = "排序号") @Schema(description = "排序号")
private Integer sortNumber; private Integer sortNumber;
@Schema(description = "核销权限是否开启 0-未开启 1-已开启")
private Boolean verifyFlag;
@Schema(description = "是否删除") @Schema(description = "是否删除")
private Integer isDelete; private Integer isDelete;
@@ -112,6 +117,9 @@ public class ShopDealerUser implements Serializable {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "更新人")
private Integer updater;
@Schema(description = "修改时间") @Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime; private LocalDateTime updateTime;
@@ -119,4 +127,8 @@ public class ShopDealerUser implements Serializable {
@Schema(description = "分销商等级0-普通用户 1-超级管理员 2-合伙人(总店) 3-合伙人(分店)") @Schema(description = "分销商等级0-普通用户 1-超级管理员 2-合伙人(总店) 3-合伙人(分店)")
private Integer dealerLevel; private Integer dealerLevel;
@Schema(description = "删除 0-未删 1-已删")
@TableLogic
private Integer deleted;
} }

View File

@@ -27,6 +27,9 @@ public class ShopDealerWithdraw implements Serializable {
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
private Integer id; private Integer id;
@Schema(description = "订单号")
private String orderNo;
@Schema(description = "分销商用户ID") @Schema(description = "分销商用户ID")
private Integer userId; private Integer userId;

View File

@@ -0,0 +1,104 @@
package com.gxwebsoft.shop.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.io.Serializable;
import com.gxwebsoft.common.core.constants.BaseConstants;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 秒杀活动
*
* @author xm
* @since 2026-04-22 17:18:17
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopFlashSaleActivity对象", description = "秒杀活动")
@TableName("shop_flash_sale_activity")
public class ShopFlashSaleActivity implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "秒杀活动编号")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "秒杀活动名称")
private String name;
@Schema(description = "秒杀活动商品")
private Integer goodsId;
@Schema(description = "商品skuId")
private Integer skuId;
@Schema(description = "商品数量")
private Integer num;
@Schema(description = "秒杀活动商品价格")
private BigDecimal price;
@Schema(description = "活动状态 0-开启 1-关闭")
private Integer status;
@Schema(
description = "活动开始时间",
type = "string",
pattern = BaseConstants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND,
example = "2026-04-01 12:00:00"
)
private LocalDateTime startTime;
@Schema(
description = "活动结束时间",
type = "string",
pattern = BaseConstants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND,
example = "2027-01-01 12:00:00"
)
private LocalDateTime endTime;
@Schema(description = "活动限购数量")
private Integer saleLimit;
@Schema(description = "库存")
private Integer stock;
@Schema(description = "展示类型0普通用户1新用户 2老用户")
private Integer displayType;
@Schema(description = "备注")
private String remark;
@Schema(description = "排序")
private Integer sortNumber;
@Schema(description = "是否弹窗 0-否 1-是")
private Integer popFlag;
@Schema(description = "租户id")
private Integer tenantId;
@Schema(description = "创建者")
private String creator;
@Schema(description = "创建时间", pattern = BaseConstants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime createTime;
@Schema(description = "更新者")
private String updater;
@Schema(description = "更新时间")
@DateTimeFormat(pattern = BaseConstants.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime updateTime;
@Schema(description = "是否删除")
@TableLogic
private Integer deleted;
}

View File

@@ -1,13 +1,16 @@
package com.gxwebsoft.shop.entity; package com.gxwebsoft.shop.entity;
import java.math.BigDecimal; import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
@@ -21,6 +24,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopGoods对象", description = "商品") @Schema(name = "ShopGoods对象", description = "商品")
@TableName("shop_goods")
public class ShopGoods implements Serializable { public class ShopGoods implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -104,6 +108,15 @@ public class ShopGoods implements Serializable {
@Schema(description = "配送奖金") @Schema(description = "配送奖金")
private BigDecimal deliveryMoney; private BigDecimal deliveryMoney;
@Schema(description = "推广核验佣金比率")
private BigDecimal verifyRate;
@Schema(description = "推广核验上级/指定人")
private Integer verifyParentUserId;
@Schema(description = "推广核验上级佣金比率/指定分佣")
private BigDecimal verifyParentRate;
@Schema(description = "库存计算方式(10下单减库存 20付款减库存)") @Schema(description = "库存计算方式(10下单减库存 20付款减库存)")
@JsonAlias({"cdeductStockType"}) @JsonAlias({"cdeductStockType"})
private Integer deductStockType; private Integer deductStockType;
@@ -168,15 +181,47 @@ public class ShopGoods implements Serializable {
@Schema(description = "用户ID") @Schema(description = "用户ID")
private Integer userId; private Integer userId;
@Schema(description = "配送方式:1-自配送 2-自提 4-发快递 5-水票 多属性用','隔开")
private String deliveryType;
@Schema(description = "配送方式:1-自配送 2-自提 4-发快递 5-水票 多属性用','隔开")
@TableField(exist = false)
private List<Integer> deliveryTypeList;
@Schema(description = "水票标识 0-否 1-是")
private Integer waterTicketFlag;
@Schema(description = "水票ID")
private Integer waterTickerId;
@Schema(description = "0-按每桶楼层计算 1-固定金额")
private Integer deliveryFeeType;
@Schema(description = "配送楼层步梯费(元)")
private BigDecimal deliveryFee;
@Schema(description = "分享图")
private String shareImg;
@Schema(description = "租户id") @Schema(description = "租户id")
private Integer tenantId; private Integer tenantId;
@Schema(description = "创建人")
private Integer creator;
@Schema(description = "创建时间") @Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "修改人")
private Integer updater;
@Schema(description = "修改时间") @Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime; private LocalDateTime updateTime;
@Schema(description = "是否删除 0-未删 1-已删")
@TableLogic
private Integer deleted;
} }

View File

@@ -2,15 +2,16 @@ package com.gxwebsoft.shop.entity;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.baomidou.mybatisplus.annotation.TableLogic; import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable; import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema; import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.time.LocalDateTime;
/** /**
* 商品分类 * 商品分类
* *
@@ -20,6 +21,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopGoodsCategory对象", description = "商品分类") @Schema(name = "ShopGoodsCategory对象", description = "商品分类")
@TableName("shop_goods_category")
public class ShopGoodsCategory implements Serializable { public class ShopGoodsCategory implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@@ -0,0 +1,65 @@
package com.gxwebsoft.shop.entity;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 商品分润设定
*
* @author xm
* @since 2026-05-20 14:33:00
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopGoodsProfit对象", description = "商品分润设定")
@TableName("shop_goods_profit")
public class ShopGoodsProfit implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "类型 1-股东分红 2-其他")
private Integer type;
@Schema(description = "商品ID")
private Integer goodsId;
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "分佣比例 百分比")
private BigDecimal profit;
@Schema(description = "开启状态 0-未开启 1-开启")
private Integer status;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "创建人")
private Integer creator;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新人")
private Integer updater;
@Schema(description = "更新人")
private LocalDateTime updateTime;
@Schema(description = "删除 0-未删 1-已删")
@TableLogic
private Integer deleted;
}

View File

@@ -1,12 +1,12 @@
package com.gxwebsoft.shop.entity; package com.gxwebsoft.shop.entity;
import java.math.BigDecimal; import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.*;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
@@ -25,6 +25,7 @@ import javax.validation.constraints.*;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopOrder对象", description = "订单") @Schema(name = "ShopOrder对象", description = "订单")
@TableName("shop_order")
public class ShopOrder implements Serializable { public class ShopOrder implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -32,6 +33,9 @@ public class ShopOrder implements Serializable {
@TableId(value = "order_id", type = IdType.AUTO) @TableId(value = "order_id", type = IdType.AUTO)
private Integer orderId; private Integer orderId;
@Schema(description = "订单类型 1-及时自配送 2-自提 3-预约自配送 4-发快递 5-水票 6-(配送:自配送/快递)")
private Integer orderType;
@Schema(description = "订单编号") @Schema(description = "订单编号")
private String orderNo; private String orderNo;
@@ -186,7 +190,7 @@ public class ShopOrder implements Serializable {
@Schema(description = "0未使用1已完成2已取消3取消中4退款申请中5退款被拒绝6退款成功7客户端申请退款") @Schema(description = "0未使用1已完成2已取消3取消中4退款申请中5退款被拒绝6退款成功7客户端申请退款")
private Integer orderStatus; private Integer orderStatus;
@Schema(description = "发货状态(10未发货 20已发货 30部分发货)") @Schema(description = "发货状态(10未发货 20已发货 30部分发货 40已送达)")
private Integer deliveryStatus; private Integer deliveryStatus;
@Schema(description = "发货备注") @Schema(description = "发货备注")
@@ -306,6 +310,62 @@ public class ShopOrder implements Serializable {
@NotNull(message = "租户ID不能为空") @NotNull(message = "租户ID不能为空")
private Integer tenantId; private Integer tenantId;
@Schema(description = "秒杀活动ID")
private Integer activityId;
@Schema(description = "秒杀活动ID")
@TableField(exist = false)
private String activityName;
@Schema(description = "水票订单标识 0-否 1-是")
private Integer waterTicketFlag;
@Schema(description = "核销码")
private String verifyCode;
@Schema(description = "核销状态 0-未核销 1-已核销")
private Integer verifyStatus;
@Schema(description = "推广佣金结算核销过期时间")
private LocalDateTime verifyExpTime;
@Schema(description = "核销时间")
private LocalDateTime verifyTime;
@Schema(description = "核销人")
private Integer verifyUser;
@Schema(description = "核销人")
@TableField(exist = false)
private String verifyUserName;
@Schema(description = "推广核销佣金")
private BigDecimal verifyMoney;
@Schema(description = "推广核验上级/指定人")
private Integer verifyParentUser;
@Schema(description = "推广核验上级/指定人佣金")
private BigDecimal verifyParentMoney;
@Schema(description = "门店、服务商结算标识 0-未结算 1-已结算")
private Integer teamSettlementFlag;
@Schema(description = "分红结算标识 0-未结算 1-已结算")
private Integer dividendSettlementFlag;
@Schema(description = "配送方式 0-电梯 1-步梯")
private Integer deliveryMethod;
@Schema(description = "楼层")
private Integer deliveryFloor;
@Schema(description = "配送费(步梯配送特有)")
private BigDecimal deliveryFee;
@Schema(description = "配送时间")
private LocalDateTime sendTime;
@Schema(description = "修改时间") @Schema(description = "修改时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateTime; private LocalDateTime updateTime;
@@ -350,4 +410,8 @@ public class ShopOrder implements Serializable {
@TableField(exist = false) @TableField(exist = false)
private ShopOrderDelivery shopOrderDelivery; private ShopOrderDelivery shopOrderDelivery;
@Schema(description = "详细地址")
@TableField(exist = false)
private String fullAddress;
} }

View File

@@ -54,6 +54,14 @@ public class ShopOrderGoods implements Serializable {
@Schema(description = "商品名称") @Schema(description = "商品名称")
private String goodsName; private String goodsName;
@Schema(description = "商品名称")
@TableField(exist = false)
private String activeNam;
@Schema(description = "核销码")
@TableField(exist = false)
private String verifyCode;
@Schema(description = "商品规格") @Schema(description = "商品规格")
private String spec; private String spec;

View File

@@ -0,0 +1,69 @@
package com.gxwebsoft.shop.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableLogic;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 步梯费用设置
*
* @author xm
* @since 2026-04-28 16:30:00
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopSurchargeConfig对象", description = "步梯费用设置")
@TableName("shop_surcharge_config")
public class ShopSurchargeConfig implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "名称")
private String name;
@Schema(description = "商品ID")
private Integer goodsId;
@Schema(description = "价格(元)")
private BigDecimal price;
@Schema(description = "类型 0-步梯费 1-其他")
private Integer type;
@Schema(description = "状态 0-开启 1-关闭")
private Integer status;
@Schema(description = "排序")
private Integer sortNumber;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "创建人")
private String creator;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "修改人")
private String updater;
@Schema(description = "修改时间")
private LocalDateTime updateTime;
@Schema(description = "是否删除 0-未删 1-已删")
@TableLogic
private Boolean deleted;
}

View File

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
@@ -20,6 +22,7 @@ import lombok.EqualsAndHashCode;
@Data @Data
@EqualsAndHashCode(callSuper = false) @EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopUserAddress对象", description = "收货地址") @Schema(name = "ShopUserAddress对象", description = "收货地址")
@TableName("shop_user_address")
public class ShopUserAddress implements Serializable { public class ShopUserAddress implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -48,7 +51,7 @@ public class ShopUserAddress implements Serializable {
@Schema(description = "收货地址") @Schema(description = "收货地址")
private String address; private String address;
@Schema(description = "收货地址") @Schema(description = "详细地址")
private String fullAddress; private String fullAddress;
private String lat; private String lat;

View File

@@ -0,0 +1,61 @@
package com.gxwebsoft.shop.entity;
import com.baomidou.mybatisplus.annotation.*;
import java.time.LocalDateTime;
import java.io.Serializable;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 订单核销人管理
*
* @author xm
* @since 2026-05-25 17:13:00
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Schema(name = "ShopVerifyUser对象", description = "订单核销人管理")
@TableName("shop_verify_user")
public class ShopVerifyUser implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键ID")
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
@Schema(description = "用户ID")
private Integer userId;
@Schema(description = "用户名称")
@TableField(exist = false)
private String userName;
@Schema(description = "核销权限是否开启 0-未开启 1-已开启")
private Integer verifyFlag;
@Schema(description = "是否开启 0-未开始 1-已开启")
private Integer status;
@Schema(description = "排序号")
private Integer sortNumber;
@Schema(description = "创建人")
private Integer creator;
@Schema(description = "创建时间")
private LocalDateTime createTime;
@Schema(description = "更新人")
private Integer updater;
@Schema(description = "更新时间")
private LocalDateTime updateTime;
@Schema(description = "是否删除 0-未删 1-已删")
@TableLogic
private Integer deleted;
}

View File

@@ -0,0 +1,37 @@
package com.gxwebsoft.shop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.shop.entity.ShopActiveImage;
import com.gxwebsoft.shop.param.ShopActiveImageParam;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 推广码底图Mapper
*
* @author xm
* @since 2026-04-27 18:02:17
*/
public interface ShopActiveImageMapper extends BaseMapper<ShopActiveImage> {
/**
* 分页查询
*
* @param page 分页对象
* @param param 查询参数
* @return List<ShopActiveImage>
*/
List<ShopActiveImage> selectPageRel(@Param("page") IPage<ShopActiveImage> page,
@Param("param") ShopActiveImageParam param);
/**
* 查询全部
*
* @param param 查询参数
* @return List<User>
*/
List<ShopActiveImage> selectListRel(@Param("param") ShopActiveImageParam param);
}

View File

@@ -2,8 +2,11 @@ package com.gxwebsoft.shop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gxwebsoft.shop.dto.ShopDealerCapitalWaterDto;
import com.gxwebsoft.shop.entity.ShopDealerCapital; import com.gxwebsoft.shop.entity.ShopDealerCapital;
import com.gxwebsoft.shop.param.ShopDealerCapitalParam; import com.gxwebsoft.shop.param.ShopDealerCapitalParam;
import com.gxwebsoft.shop.vo.ShopDealerCapitalWaterVO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@@ -34,4 +37,12 @@ public interface ShopDealerCapitalMapper extends BaseMapper<ShopDealerCapital> {
*/ */
List<ShopDealerCapital> selectListRel(@Param("param") ShopDealerCapitalParam param); List<ShopDealerCapital> selectListRel(@Param("param") ShopDealerCapitalParam param);
/**
* 查询个人资金流水
* @param page
* @param entity
* @return
*/
IPage<ShopDealerCapitalWaterVO> getPageInfo(@Param("page") Page page, @Param("entity") ShopDealerCapitalWaterDto entity);
} }

View File

@@ -4,6 +4,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.shop.entity.ShopDealerOrder; import com.gxwebsoft.shop.entity.ShopDealerOrder;
import com.gxwebsoft.shop.param.ShopDealerOrderParam; import com.gxwebsoft.shop.param.ShopDealerOrderParam;
import com.gxwebsoft.shop.vo.ShopDealerOrderTaskVO;
import com.gxwebsoft.shop.vo.ShopDealerOrderTodayRevenueVO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@@ -34,4 +36,18 @@ public interface ShopDealerOrderMapper extends BaseMapper<ShopDealerOrder> {
*/ */
List<ShopDealerOrder> selectListRel(@Param("param") ShopDealerOrderParam param); List<ShopDealerOrder> selectListRel(@Param("param") ShopDealerOrderParam param);
/**
* 获取订单门店/分销商待结算数据
* @param tenantId 租户ID
* @return
*/
List<ShopDealerOrderTaskVO> getDealerOrderList(@Param("tenantId") Integer tenantId);
/**
* 获取用户当日分佣数据
* @param userId
* @return
*/
List<ShopDealerOrderTodayRevenueVO> getTodayRevenue(@Param("userId") Integer userId);
} }

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.shop.entity.ShopDealerReferee; import com.gxwebsoft.shop.entity.ShopDealerReferee;
import com.gxwebsoft.shop.param.ShopDealerRefereeParam; import com.gxwebsoft.shop.param.ShopDealerRefereeParam;
import com.gxwebsoft.shop.vo.ShopDealerRefereeVO;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@@ -34,4 +35,11 @@ public interface ShopDealerRefereeMapper extends BaseMapper<ShopDealerReferee> {
*/ */
List<ShopDealerReferee> selectListRel(@Param("param") ShopDealerRefereeParam param); List<ShopDealerReferee> selectListRel(@Param("param") ShopDealerRefereeParam param);
/**
* 通过用户ID查询上一级分销人信息【type = 0】
* @param userId 用户ID
* @return
*/
ShopDealerRefereeVO getDealerIdByUserId(@Param("userId") Integer userId);
} }

View File

@@ -0,0 +1,38 @@
package com.gxwebsoft.shop.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.gxwebsoft.shop.entity.ShopFlashSaleActivity;
import com.gxwebsoft.shop.param.ShopFlashSaleActivityParam;
import com.gxwebsoft.shop.vo.ShopFlashSaleActivityVO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 秒杀活动Mapper
*
* @author xm
* @since 2026-04-22 17:18:17
*/
public interface ShopFlashSaleActivityMapper extends BaseMapper<ShopFlashSaleActivity> {
/**
* 分页查询
*
* @param page 分页对象
* @param param 查询参数
* @return List<ShopFlashSaleActivity>
*/
List<ShopFlashSaleActivityVO> selectPageRel(@Param("page") IPage<ShopFlashSaleActivity> page,
@Param("param") ShopFlashSaleActivityParam param);
/**
* 查询全部
*
* @param param 查询参数
* @return List<User>
*/
List<ShopFlashSaleActivity> selectListRel(@Param("param") ShopFlashSaleActivityParam param);
}

Some files were not shown because too many files have changed in this diff Show More