From 32db399cb52184e6af2596fa4e273e25fc2b3fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Feb 2026 00:44:08 +0800 Subject: [PATCH 01/10] =?UTF-8?q?refactor(shop):=20=E9=87=8D=E6=9E=84ShopU?= =?UTF-8?q?ser=E5=AE=9E=E4=BD=93=E7=B1=BB=E5=92=8C=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 调整ShopUser实体类字段定义,将id改为userId作为主键 - 更新用户类型枚举描述,从"个人用户/企业用户/其他"改为"普通用户/企业用户/特殊用户" - 在birthday、settlementTime、createTime和updateTime字段添加@JsonFormat注解格式化输出 - 将offline字段类型从Boolean改为Integer以支持更多状态值 - 新增isDefault字段用于标识默认账号,解决多租户相同手机号问题 - 更新ShopUserController中的get方法参数从userId改为id并添加权限验证 - 注释掉ShopUserController中设置当前登录用户id的逻辑 - 修正ShopUserMapper.xml中查询条件的字段映射 - 在ShopUserParam中同步更新字段定义和查询条件配置 - 统一更新所有文件的since注释时间戳信息 --- .../shop/controller/ShopUserController.java | 31 ++++++++++--------- .../com/gxwebsoft/shop/entity/ShopUser.java | 30 ++++++++++-------- .../gxwebsoft/shop/mapper/ShopUserMapper.java | 2 +- .../shop/mapper/xml/ShopUserMapper.xml | 6 ++-- .../gxwebsoft/shop/param/ShopUserParam.java | 21 ++++++------- .../shop/service/ShopUserService.java | 2 +- .../service/impl/ShopUserServiceImpl.java | 10 +++--- 7 files changed, 53 insertions(+), 49 deletions(-) diff --git a/src/main/java/com/gxwebsoft/shop/controller/ShopUserController.java b/src/main/java/com/gxwebsoft/shop/controller/ShopUserController.java index 10f53a5..7926f98 100644 --- a/src/main/java/com/gxwebsoft/shop/controller/ShopUserController.java +++ b/src/main/java/com/gxwebsoft/shop/controller/ShopUserController.java @@ -1,14 +1,14 @@ 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.service.ShopUserService; import com.gxwebsoft.shop.entity.ShopUser; import com.gxwebsoft.shop.param.ShopUserParam; -import com.gxwebsoft.shop.service.ShopUserService; +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 io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.security.access.prepost.PreAuthorize; @@ -21,7 +21,7 @@ import java.util.List; * 用户记录表控制器 * * @author 科技小王子 - * @since 2025-10-03 13:41:09 + * @since 2026-02-10 00:37:07 */ @Tag(name = "用户记录表管理") @RestController @@ -46,11 +46,12 @@ public class ShopUserController extends BaseController { return success(shopUserService.listRel(param)); } - @Operation(summary = "根据userId查询用户记录表") - @GetMapping("/{userId}") - public ApiResult get(@PathVariable("userId") Integer userId) { + @PreAuthorize("hasAuthority('shop:shopUser:list')") + @Operation(summary = "根据id查询用户记录表") + @GetMapping("/{id}") + public ApiResult get(@PathVariable("id") Integer id) { // 使用关联查询 - return success(shopUserService.getByIdRel(userId)); + return success(shopUserService.getByIdRel(id)); } @PreAuthorize("hasAuthority('shop:shopUser:save')") @@ -59,10 +60,10 @@ public class ShopUserController extends BaseController { @PostMapping() public ApiResult save(@RequestBody ShopUser shopUser) { // 记录当前登录用户id - User loginUser = getLoginUser(); - if (loginUser != null) { - shopUser.setUserId(loginUser.getUserId()); - } + // User loginUser = getLoginUser(); + // if (loginUser != null) { + // shopUser.setUserId(loginUser.getUserId()); + // } if (shopUserService.save(shopUser)) { return success("添加成功"); } diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopUser.java b/src/main/java/com/gxwebsoft/shop/entity/ShopUser.java index f540f64..cd90cb4 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopUser.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopUser.java @@ -1,37 +1,34 @@ package com.gxwebsoft.shop.entity; +import java.math.BigDecimal; import com.baomidou.mybatisplus.annotation.IdType; +import java.time.LocalDate; import com.baomidou.mybatisplus.annotation.TableId; +import java.time.LocalDateTime; import com.baomidou.mybatisplus.annotation.TableLogic; +import java.io.Serializable; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; - -import java.io.Serializable; -import java.math.BigDecimal; -import java.time.LocalDate; -import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonFormat; /** * 用户记录表 * * @author 科技小王子 - * @since 2025-10-03 13:41:09 + * @since 2026-02-10 00:37:07 */ @Data @EqualsAndHashCode(callSuper = false) -@Schema(description = "用户记录表") +@Schema(name = "ShopUser对象", description = "用户记录表") public class ShopUser implements Serializable { private static final long serialVersionUID = 1L; - @Schema(description = "id") - @TableId(value = "id", type = IdType.AUTO) - private Integer id; - @Schema(description = "用户id") + @TableId(value = "user_id", type = IdType.AUTO) private Integer userId; - @Schema(description = "用户类型 0个人用户 1企业用户 2其他") + @Schema(description = "用户类型 0普通用户 1企业用户 2特殊用户") private Integer type; @Schema(description = "账号") @@ -71,6 +68,7 @@ public class ShopUser implements Serializable { private String idCard; @Schema(description = "出生日期") + @JsonFormat(pattern = "yyyy-MM-dd") private LocalDate birthday; @Schema(description = "所在国家") @@ -143,7 +141,7 @@ public class ShopUser implements Serializable { private Integer age; @Schema(description = "是否线下会员") - private Boolean offline; + private Integer offline; @Schema(description = "关注数") private Integer followers; @@ -178,6 +176,9 @@ public class ShopUser implements Serializable { @Schema(description = "是否管理员") private Boolean isAdmin; + @Schema(description = "默认账号(适用于不同租户存在相同的手机号码)") + private Boolean isDefault; + @Schema(description = "是否企业管理员") private Boolean isOrganizationAdmin; @@ -209,6 +210,7 @@ public class ShopUser implements Serializable { private Integer expireTime; @Schema(description = "最后结算时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime settlementTime; @Schema(description = "资质") @@ -246,9 +248,11 @@ public class ShopUser implements Serializable { private Integer tenantId; @Schema(description = "注册时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime createTime; @Schema(description = "修改时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private LocalDateTime updateTime; } diff --git a/src/main/java/com/gxwebsoft/shop/mapper/ShopUserMapper.java b/src/main/java/com/gxwebsoft/shop/mapper/ShopUserMapper.java index e7a09c4..d6c093f 100644 --- a/src/main/java/com/gxwebsoft/shop/mapper/ShopUserMapper.java +++ b/src/main/java/com/gxwebsoft/shop/mapper/ShopUserMapper.java @@ -12,7 +12,7 @@ import java.util.List; * 用户记录表Mapper * * @author 科技小王子 - * @since 2025-10-03 13:41:09 + * @since 2026-02-10 00:37:07 */ public interface ShopUserMapper extends BaseMapper { diff --git a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserMapper.xml b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserMapper.xml index 0ccbb57..fa3f83c 100644 --- a/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserMapper.xml +++ b/src/main/java/com/gxwebsoft/shop/mapper/xml/ShopUserMapper.xml @@ -7,9 +7,6 @@ SELECT a.* FROM shop_user a - - AND a.id = #{param.id} - AND a.user_id = #{param.userId} @@ -160,6 +157,9 @@ AND a.is_admin = #{param.isAdmin} + + AND a.is_default = #{param.isDefault} + AND a.is_organization_admin = #{param.isOrganizationAdmin} diff --git a/src/main/java/com/gxwebsoft/shop/param/ShopUserParam.java b/src/main/java/com/gxwebsoft/shop/param/ShopUserParam.java index 2b3ac02..bceec72 100644 --- a/src/main/java/com/gxwebsoft/shop/param/ShopUserParam.java +++ b/src/main/java/com/gxwebsoft/shop/param/ShopUserParam.java @@ -1,37 +1,32 @@ package com.gxwebsoft.shop.param; -import com.fasterxml.jackson.annotation.JsonInclude; +import java.math.BigDecimal; import com.gxwebsoft.common.core.annotation.QueryField; import com.gxwebsoft.common.core.annotation.QueryType; import com.gxwebsoft.common.core.web.BaseParam; +import com.fasterxml.jackson.annotation.JsonInclude; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; -import java.math.BigDecimal; - /** * 用户记录表查询参数 * * @author 科技小王子 - * @since 2025-10-03 13:41:08 + * @since 2026-02-10 00:37:06 */ @Data @EqualsAndHashCode(callSuper = false) @JsonInclude(JsonInclude.Include.NON_NULL) -@Schema(description = "用户记录表查询参数") +@Schema(name = "ShopUserParam对象", description = "用户记录表查询参数") public class ShopUserParam extends BaseParam { private static final long serialVersionUID = 1L; - @Schema(description = "id") - @QueryField(type = QueryType.EQ) - private Integer id; - @Schema(description = "用户id") @QueryField(type = QueryType.EQ) private Integer userId; - @Schema(description = "用户类型 0个人用户 1企业用户 2其他") + @Schema(description = "用户类型 0普通用户 1企业用户 2特殊用户") @QueryField(type = QueryType.EQ) private Integer type; @@ -157,7 +152,7 @@ public class ShopUserParam extends BaseParam { @Schema(description = "是否线下会员") @QueryField(type = QueryType.EQ) - private Boolean offline; + private Integer offline; @Schema(description = "关注数") @QueryField(type = QueryType.EQ) @@ -199,6 +194,10 @@ public class ShopUserParam extends BaseParam { @QueryField(type = QueryType.EQ) private Boolean isAdmin; + @Schema(description = "默认账号(适用于不同租户存在相同的手机号码)") + @QueryField(type = QueryType.EQ) + private Boolean isDefault; + @Schema(description = "是否企业管理员") @QueryField(type = QueryType.EQ) private Boolean isOrganizationAdmin; diff --git a/src/main/java/com/gxwebsoft/shop/service/ShopUserService.java b/src/main/java/com/gxwebsoft/shop/service/ShopUserService.java index 52d8fba..03335b3 100644 --- a/src/main/java/com/gxwebsoft/shop/service/ShopUserService.java +++ b/src/main/java/com/gxwebsoft/shop/service/ShopUserService.java @@ -11,7 +11,7 @@ import java.util.List; * 用户记录表Service * * @author 科技小王子 - * @since 2025-10-03 13:41:09 + * @since 2026-02-10 00:37:07 */ public interface ShopUserService extends IService { diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserServiceImpl.java index 9d7cde5..f9964c9 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopUserServiceImpl.java @@ -1,12 +1,12 @@ package com.gxwebsoft.shop.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.shop.mapper.ShopUserMapper; +import com.gxwebsoft.shop.service.ShopUserService; +import com.gxwebsoft.shop.entity.ShopUser; +import com.gxwebsoft.shop.param.ShopUserParam; import com.gxwebsoft.common.core.web.PageParam; import com.gxwebsoft.common.core.web.PageResult; -import com.gxwebsoft.shop.entity.ShopUser; -import com.gxwebsoft.shop.mapper.ShopUserMapper; -import com.gxwebsoft.shop.param.ShopUserParam; -import com.gxwebsoft.shop.service.ShopUserService; import org.springframework.stereotype.Service; import java.util.List; @@ -15,7 +15,7 @@ import java.util.List; * 用户记录表Service实现 * * @author 科技小王子 - * @since 2025-10-03 13:41:09 + * @since 2026-02-10 00:37:07 */ @Service public class ShopUserServiceImpl extends ServiceImpl implements ShopUserService { From 4c8e67fe64b347e43b9ddd4c436448bb62cde1ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Feb 2026 10:46:05 +0800 Subject: [PATCH 02/10] =?UTF-8?q?feat(task):=20=E5=AE=8C=E5=96=84=E7=BB=8F?= =?UTF-8?q?=E9=94=80=E5=95=86=E4=BD=A3=E9=87=91=E8=A7=A3=E5=86=BB=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 ShopDealerOrderService 服务注入用于订单状态更新 - 添加 isUnfreeze 和 unfreezeTime 字段到 ShopDealerOrder 实体 - 实现佣金解冻完成后自动更新分销订单状态为"已解冻" - 添加解冻时间记录功能 - 通过统计 flowType 判断佣金解冻完成度避免提前更新状态 - 增加解冻状态更新失败的日志警告 --- .../DealerCommissionUnfreeze10584Task.java | 50 +++++++++++++++++++ .../shop/entity/ShopDealerOrder.java | 6 +++ 2 files changed, 56 insertions(+) diff --git a/src/main/java/com/gxwebsoft/glt/task/DealerCommissionUnfreeze10584Task.java b/src/main/java/com/gxwebsoft/glt/task/DealerCommissionUnfreeze10584Task.java index 7fc6d1f..081a25a 100644 --- a/src/main/java/com/gxwebsoft/glt/task/DealerCommissionUnfreeze10584Task.java +++ b/src/main/java/com/gxwebsoft/glt/task/DealerCommissionUnfreeze10584Task.java @@ -1,6 +1,7 @@ package com.gxwebsoft.glt.task; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.gxwebsoft.common.core.annotation.IgnoreTenant; import com.gxwebsoft.glt.entity.GltTicketOrder; import com.gxwebsoft.glt.entity.GltTicketTemplate; @@ -9,9 +10,11 @@ import com.gxwebsoft.glt.service.GltTicketOrderService; import com.gxwebsoft.glt.service.GltTicketTemplateService; import com.gxwebsoft.glt.service.GltUserTicketService; import com.gxwebsoft.shop.entity.ShopDealerCapital; +import com.gxwebsoft.shop.entity.ShopDealerOrder; import com.gxwebsoft.shop.entity.ShopDealerUser; import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.service.ShopDealerCapitalService; +import com.gxwebsoft.shop.service.ShopDealerOrderService; import com.gxwebsoft.shop.service.ShopDealerUserService; import com.gxwebsoft.shop.service.ShopOrderService; import lombok.extern.slf4j.Slf4j; @@ -65,6 +68,9 @@ public class DealerCommissionUnfreeze10584Task { @Resource private ShopDealerCapitalService shopDealerCapitalService; + @Resource + private ShopDealerOrderService shopDealerOrderService; + @Resource private ShopDealerUserService shopDealerUserService; @@ -355,12 +361,56 @@ public class DealerCommissionUnfreeze10584Task { marker.setUpdateTime(now); shopDealerCapitalService.save(marker); + // 佣金全部解冻完成后,将分销订单状态置为“已解冻”(0)。 + // 以当前任务生成的 flowType=50 marker 数量作为完成度判断,避免提前将订单置为已解冻。 + setDealerOrderUnfrozenIfCompleted(orderNo, now); + log.info("佣金解冻成功 - tenantId={}, orderNo={}, dealerUserId={}, amount={}, capitalId={}", TENANT_ID, orderNo, dealerUserId, amount, capitalId); return true; })); } + private void setDealerOrderUnfrozenIfCompleted(String orderNo, LocalDateTime now) { + if (orderNo == null || orderNo.isBlank()) { + return; + } + + long totalCommissions = shopDealerCapitalService.count( + new LambdaQueryWrapper() + .eq(ShopDealerCapital::getTenantId, TENANT_ID) + .eq(ShopDealerCapital::getFlowType, 10) + .eq(ShopDealerCapital::getOrderNo, orderNo) + ); + if (totalCommissions <= 0) { + return; + } + + long unfrozenMarkers = shopDealerCapitalService.count( + new LambdaQueryWrapper() + .eq(ShopDealerCapital::getTenantId, TENANT_ID) + .eq(ShopDealerCapital::getFlowType, 50) + .eq(ShopDealerCapital::getOrderNo, orderNo) + .like(ShopDealerCapital::getComments, "佣金解冻(capitalId=") + ); + + if (unfrozenMarkers < totalCommissions) { + return; + } + + boolean updated = shopDealerOrderService.update( + new LambdaUpdateWrapper() + .eq(ShopDealerOrder::getTenantId, TENANT_ID) + .eq(ShopDealerOrder::getOrderNo, orderNo) + .set(ShopDealerOrder::getIsUnfreeze, 1) + .set(ShopDealerOrder::getUnfreezeTime, now) + .set(ShopDealerOrder::getUpdateTime, now) + ); + if (!updated) { + log.warn("已完成佣金解冻,但更新分销订单isUnfreeze失败/无记录 - tenantId={}, orderNo={}", TENANT_ID, orderNo); + } + } + private String buildUnfreezeMarkerComment(Integer capitalId) { return "佣金解冻(capitalId=" + capitalId + ")"; } diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java b/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java index 32be34d..e3c0c74 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopDealerOrder.java @@ -120,9 +120,15 @@ public class ShopDealerOrder implements Serializable { @Schema(description = "佣金结算(0未结算 1已结算)") private Integer isSettled; + @Schema(description = "佣金冻结(1解冻中 0已解冻)") + private Integer isUnfreeze; + @Schema(description = "结算时间") private LocalDateTime settleTime; + @Schema(description = "解冻时间") + private LocalDateTime unfreezeTime; + @Schema(description = "备注") private String comments; From 011c9e458a06bdc132ea7a5aab7884649580441b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Feb 2026 11:20:46 +0800 Subject: [PATCH 03/10] =?UTF-8?q?fix(order):=20=E4=BF=AE=E5=A4=8D=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除订单状态字段的错误更新设置 - 移除发货状态字段的错误更新设置 - 保留礼品领取状态和更新时间的正确更新逻辑 --- .../java/com/gxwebsoft/glt/service/GltTicketIssueService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/gxwebsoft/glt/service/GltTicketIssueService.java b/src/main/java/com/gxwebsoft/glt/service/GltTicketIssueService.java index 004abf2..2751277 100644 --- a/src/main/java/com/gxwebsoft/glt/service/GltTicketIssueService.java +++ b/src/main/java/com/gxwebsoft/glt/service/GltTicketIssueService.java @@ -168,9 +168,6 @@ public class GltTicketIssueService { new LambdaUpdateWrapper() .eq(ShopOrder::getOrderId, order.getOrderId()) .eq(ShopOrder::getTenantId, tenantId) - .set(ShopOrder::getOrderStatus, 1) - // 同步更新发货状态为“已发货” - .set(ShopOrder::getDeliveryStatus, 20) .set(ShopOrder::getHasTakeGift, true) .set(ShopOrder::getUpdateTime, now) ); From 448185080918f246d3c9408bdcbf86e18718a423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Feb 2026 11:29:00 +0800 Subject: [PATCH 04/10] =?UTF-8?q?feat(ticket):=20=E6=8E=A5=E5=8D=95?= =?UTF-8?q?=E6=97=B6=E5=90=8C=E6=AD=A5=E5=95=86=E5=9F=8E=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=8F=91=E8=B4=A7=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在接单方法上添加事务注解确保操作原子性 - 优化时间获取逻辑避免重复调用当前时间 - 新增updateShopOrderDeliveryStatusAfterAccept方法处理发货状态同步 - 查询关联水票订单并更新对应商城订单的配送状态为20(已发货) - 添加幂等性检查避免重复更新并记录异常情况日志 - 引入ShopOrder和ShopOrderService依赖支持订单状态更新 --- .../impl/GltTicketOrderServiceImpl.java | 80 ++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java index 82f8f08..f8065c2 100644 --- a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java @@ -1,6 +1,8 @@ package com.gxwebsoft.glt.service.impl; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.gxwebsoft.common.core.exception.BusinessException; import com.gxwebsoft.common.core.web.PageParam; @@ -18,8 +20,10 @@ import com.gxwebsoft.glt.service.GltUserTicketLogService; import com.gxwebsoft.glt.service.GltUserTicketService; import com.gxwebsoft.shop.entity.ShopDealerCapital; import com.gxwebsoft.shop.entity.ShopDealerUser; +import com.gxwebsoft.shop.entity.ShopOrder; import com.gxwebsoft.shop.service.ShopDealerCapitalService; import com.gxwebsoft.shop.service.ShopDealerUserService; +import com.gxwebsoft.shop.service.ShopOrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; import org.springframework.stereotype.Service; @@ -70,6 +74,9 @@ public class GltTicketOrderServiceImpl extends ServiceImpl pageRel(GltTicketOrderParam param) { PageParam page = new PageParam<>(param); @@ -192,6 +199,7 @@ public class GltTicketOrderServiceImpl extends ServiceImpl w.isNull(GltTicketOrder::getRiderId).or().eq(GltTicketOrder::getRiderId, 0)) .update(); if (ok) { + // 接单成功后,同步商城订单发货状态:10未发货 -> 20已发货 + updateShopOrderDeliveryStatusAfterAccept(id, tenantId, now); return; } @@ -233,6 +244,73 @@ public class GltTicketOrderServiceImpl extends ServiceImpl() + .eq(GltUserTicket::getTenantId, tenantId) + .eq(GltUserTicket::getDeleted, 0) + .eq(GltUserTicket::getId, ticketOrder.getUserTicketId()) + .last("limit 1") + ); + if (userTicket == null) { + return; + } + + Integer shopOrderId = userTicket.getOrderId(); + String shopOrderNo = userTicket.getOrderNo(); + if (shopOrderId == null && !StringUtils.hasText(shopOrderNo)) { + return; + } + + LambdaUpdateWrapper uw = new LambdaUpdateWrapper() + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getDeleted, 0) + .and(w -> w.ne(ShopOrder::getDeliveryStatus, 20).or().isNull(ShopOrder::getDeliveryStatus)) + .set(ShopOrder::getDeliveryStatus, 20) + .set(ShopOrder::getUpdateTime, now); + if (shopOrderId != null) { + uw.eq(ShopOrder::getOrderId, shopOrderId); + } else { + uw.eq(ShopOrder::getOrderNo, shopOrderNo); + } + + boolean updated = shopOrderService.update(uw); + if (updated) { + return; + } + + // 幂等:若已是 20,则视为成功;否则记录日志便于排查关联关系/数据缺失 + LambdaQueryWrapper qw = new LambdaQueryWrapper() + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getDeleted, 0) + .eq(ShopOrder::getDeliveryStatus, 20); + if (shopOrderId != null) { + qw.eq(ShopOrder::getOrderId, shopOrderId); + } else { + qw.eq(ShopOrder::getOrderNo, shopOrderNo); + } + if (shopOrderService.count(qw) <= 0) { + log.warn("接单成功但同步商城订单发货状态失败 - tenantId={}, ticketOrderId={}, shopOrderId={}, shopOrderNo={}", + tenantId, ticketOrderId, shopOrderId, shopOrderNo); + } + } + @Override public void start(Integer id, Integer riderId, Integer tenantId) { if (id == null) { From ad5a5abb31f0eb4608a1deb427169b9d39cdaf56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Feb 2026 12:08:58 +0800 Subject: [PATCH 05/10] =?UTF-8?q?feat(order):=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=90=8E=E5=8F=B0=E6=8C=87=E6=B4=BE=E9=85=8D=E9=80=81=E5=91=98?= =?UTF-8?q?=E6=97=B6=E5=90=8C=E6=AD=A5=E5=95=86=E5=9F=8E=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E5=8F=91=E8=B4=A7=E7=8A=B6=E6=80=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在订单更新接口中添加配送员指派后的状态同步逻辑 - 新增 markShopOrderShippedAfterRiderAssigned 方法用于状态同步 - 实现后台指派配送员时自动将关联商城订单标记为已发货状态 - 添加相关业务方法注释说明使用场景和目的 - 确保配送员指派后订单状态的一致性同步 --- .../gxwebsoft/glt/controller/GltTicketOrderController.java | 7 +++++++ .../com/gxwebsoft/glt/service/GltTicketOrderService.java | 7 +++++++ .../glt/service/impl/GltTicketOrderServiceImpl.java | 5 +++++ 3 files changed, 19 insertions(+) diff --git a/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java b/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java index f7e49ee..07f5849 100644 --- a/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java +++ b/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java @@ -242,6 +242,13 @@ public class GltTicketOrderController extends BaseController { @PutMapping() public ApiResult update(@RequestBody GltTicketOrder gltTicketOrder) { if (gltTicketOrderService.updateById(gltTicketOrder)) { + // 后台指派配送员(直接改 riderId)时,同步商城订单为“已发货”(deliveryStatus=20) + if (gltTicketOrder != null + && gltTicketOrder.getId() != null + && gltTicketOrder.getRiderId() != null + && gltTicketOrder.getRiderId() > 0) { + gltTicketOrderService.markShopOrderShippedAfterRiderAssigned(gltTicketOrder.getId(), getTenantId()); + } return success("修改成功"); } return fail("修改失败"); diff --git a/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java b/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java index 92511a0..3fdb16b 100644 --- a/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java +++ b/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java @@ -64,6 +64,13 @@ public interface GltTicketOrderService extends IService { */ void accept(Integer id, Integer riderId, Integer tenantId); + /** + * 指派/接单成功后,同步关联商城订单发货状态为“已发货”(deliveryStatus=20)。 + * + *

用于后台指派配送员(不走接单接口)等场景的状态兜底同步。

+ */ + void markShopOrderShippedAfterRiderAssigned(Integer ticketOrderId, Integer tenantId); + /** * 配送员开始配送:10 -> 20,并写 sendStartTime。 */ diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java index f8065c2..2f13605 100644 --- a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java @@ -244,6 +244,11 @@ public class GltTicketOrderServiceImpl extends ServiceImpl Date: Tue, 10 Feb 2026 12:13:00 +0800 Subject: [PATCH 06/10] =?UTF-8?q?feat(order):=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E9=85=8D=E9=80=81=E7=8A=B6=E6=80=81=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E9=80=BB=E8=BE=91=E4=BB=A5=E6=94=AF=E6=8C=81=E9=85=8D?= =?UTF-8?q?=E9=80=81=E5=91=98ID=E4=BC=A0=E9=80=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在markShopOrderShippedAfterRiderAssigned方法中添加riderId参数 - 修改updateShopOrderDeliveryStatusAfterAccept方法以接收并处理配送员ID - 更新查询逻辑以包含配送员ID字段的选择 - 添加实际配送员ID的判断逻辑,优先使用传入的配送员ID - 修改配送状态更新条件,包含配送员ID不一致的场景 - 在更新配送状态的同时设置配送员ID - 添加配送员ID查询条件到最终验证查询中 - 更新警告日志信息以包含配送员ID相关信息 --- .../controller/GltTicketOrderController.java | 6 +++- .../glt/service/GltTicketOrderService.java | 2 +- .../impl/GltTicketOrderServiceImpl.java | 30 ++++++++++++++----- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java b/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java index 07f5849..d8dc338 100644 --- a/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java +++ b/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java @@ -247,7 +247,11 @@ public class GltTicketOrderController extends BaseController { && gltTicketOrder.getId() != null && gltTicketOrder.getRiderId() != null && gltTicketOrder.getRiderId() > 0) { - gltTicketOrderService.markShopOrderShippedAfterRiderAssigned(gltTicketOrder.getId(), getTenantId()); + gltTicketOrderService.markShopOrderShippedAfterRiderAssigned( + gltTicketOrder.getId(), + getTenantId(), + gltTicketOrder.getRiderId() + ); } return success("修改成功"); } diff --git a/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java b/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java index 3fdb16b..1252f65 100644 --- a/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java +++ b/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java @@ -69,7 +69,7 @@ public interface GltTicketOrderService extends IService { * *

用于后台指派配送员(不走接单接口)等场景的状态兜底同步。

*/ - void markShopOrderShippedAfterRiderAssigned(Integer ticketOrderId, Integer tenantId); + void markShopOrderShippedAfterRiderAssigned(Integer ticketOrderId, Integer tenantId, Integer riderId); /** * 配送员开始配送:10 -> 20,并写 sendStartTime。 diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java index 2f13605..770ca87 100644 --- a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java @@ -225,7 +225,7 @@ public class GltTicketOrderServiceImpl extends ServiceImpl 20已发货 - updateShopOrderDeliveryStatusAfterAccept(id, tenantId, now); + updateShopOrderDeliveryStatusAfterAccept(id, tenantId, riderId, now); return; } @@ -245,18 +245,18 @@ public class GltTicketOrderServiceImpl extends ServiceImpl 0) ? riderId : ticketOrder.getRiderId(); + GltUserTicket userTicket = gltUserTicketService.getOne( new LambdaQueryWrapper() .eq(GltUserTicket::getTenantId, tenantId) @@ -286,9 +288,18 @@ public class GltTicketOrderServiceImpl extends ServiceImpl uw = new LambdaUpdateWrapper() .eq(ShopOrder::getTenantId, tenantId) .eq(ShopOrder::getDeleted, 0) - .and(w -> w.ne(ShopOrder::getDeliveryStatus, 20).or().isNull(ShopOrder::getDeliveryStatus)) + // deliveryStatus 已经是 20 时也可能需要补写/更新 riderId,因此条件包含 riderId 不一致的场景 + .and(w -> { + w.ne(ShopOrder::getDeliveryStatus, 20).or().isNull(ShopOrder::getDeliveryStatus); + if (actualRiderId != null && actualRiderId > 0) { + w.or().ne(ShopOrder::getRiderId, actualRiderId).or().isNull(ShopOrder::getRiderId); + } + }) .set(ShopOrder::getDeliveryStatus, 20) .set(ShopOrder::getUpdateTime, now); + if (actualRiderId != null && actualRiderId > 0) { + uw.set(ShopOrder::getRiderId, actualRiderId); + } if (shopOrderId != null) { uw.eq(ShopOrder::getOrderId, shopOrderId); } else { @@ -305,14 +316,17 @@ public class GltTicketOrderServiceImpl extends ServiceImpl 0) { + qw.eq(ShopOrder::getRiderId, actualRiderId); + } if (shopOrderId != null) { qw.eq(ShopOrder::getOrderId, shopOrderId); } else { qw.eq(ShopOrder::getOrderNo, shopOrderNo); } if (shopOrderService.count(qw) <= 0) { - log.warn("接单成功但同步商城订单发货状态失败 - tenantId={}, ticketOrderId={}, shopOrderId={}, shopOrderNo={}", - tenantId, ticketOrderId, shopOrderId, shopOrderNo); + log.warn("接单/指派成功但同步商城订单发货状态/配送员失败 - tenantId={}, ticketOrderId={}, riderId={}, shopOrderId={}, shopOrderNo={}", + tenantId, ticketOrderId, actualRiderId, shopOrderId, shopOrderNo); } } From 0fc914f47adbde7a96493e3d2622229bdfa95a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Feb 2026 12:52:27 +0800 Subject: [PATCH 07/10] =?UTF-8?q?fix(order):=20=E8=A7=A3=E5=86=B3=E9=80=81?= =?UTF-8?q?=E6=B0=B4=E8=AE=A2=E5=8D=95=E5=AE=8C=E6=88=90=E5=90=8E=E5=90=8C?= =?UTF-8?q?=E6=AD=A5=E5=95=86=E5=9F=8E=E8=AE=A2=E5=8D=95=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=8F=8A=E5=85=B3=E8=81=94=E8=AE=B0=E5=BD=95=E6=95=B0=E5=9B=9E?= =?UTF-8?q?=E5=A1=AB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在送水订单完成、确认收货和超时自动确认收货时同步更新关联商城订单状态为已完成 - 添加updateShopOrderOrderStatusAfterTicketFinished方法处理商城订单状态同步逻辑 - 在CreditCompanyRecordCountService中优化SQL查询方式,避免相关子查询导致的性能问题 - 将批量更新的chunk大小从1000调整为500以提高稳定性 - 在导入功能中添加异常处理,确保即使回填失败也不会影响整体导入流程 - 当关联记录数回填失败时在响应消息中添加警告信息 --- .../controller/CreditCompanyController.java | 25 ++++++- .../CreditCompanyRecordCountService.java | 20 +++-- .../impl/GltTicketOrderServiceImpl.java | 74 +++++++++++++++++++ 3 files changed, 110 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gxwebsoft/credit/controller/CreditCompanyController.java b/src/main/java/com/gxwebsoft/credit/controller/CreditCompanyController.java index 828fa0e..968bdfc 100644 --- a/src/main/java/com/gxwebsoft/credit/controller/CreditCompanyController.java +++ b/src/main/java/com/gxwebsoft/credit/controller/CreditCompanyController.java @@ -149,6 +149,7 @@ public class CreditCompanyController extends BaseController { List errorMessages = new ArrayList<>(); int insertedCount = 0; Set touchedMatchNames = new HashSet<>(); + String refreshWarning = null; try { List list = null; @@ -324,13 +325,31 @@ public class CreditCompanyController extends BaseController { } } } - creditCompanyRecordCountService.refreshAll(touchedCompanyIds); + try { + creditCompanyRecordCountService.refreshAll(touchedCompanyIds); + } catch (Exception ex) { + // 导入本身已经成功写入,回填计数字段失败不应导致整个导入失败(可后续单独重试刷新)。 + String msg = ex.getMessage(); + if (msg != null && msg.length() > 300) { + msg = msg.substring(0, 300) + "..."; + } + refreshWarning = "关联记录数回填失败:" + (msg != null ? msg : ex.getClass().getSimpleName()); + ex.printStackTrace(); + } } if (errorMessages.isEmpty()) { - return success("成功入库" + insertedCount + "条数据", null); + String msg = "成功入库" + insertedCount + "条数据"; + if (refreshWarning != null) { + msg = msg + ";" + refreshWarning; + } + return success(msg, null); } else { - return success("导入完成,入库" + insertedCount + "条,失败" + errorMessages.size() + "条", errorMessages); + String msg = "导入完成,入库" + insertedCount + "条,失败" + errorMessages.size() + "条"; + if (refreshWarning != null) { + msg = msg + ";" + refreshWarning; + } + return success(msg, errorMessages); } } catch (Exception e) { diff --git a/src/main/java/com/gxwebsoft/credit/service/CreditCompanyRecordCountService.java b/src/main/java/com/gxwebsoft/credit/service/CreditCompanyRecordCountService.java index 0326a22..9cd21cc 100644 --- a/src/main/java/com/gxwebsoft/credit/service/CreditCompanyRecordCountService.java +++ b/src/main/java/com/gxwebsoft/credit/service/CreditCompanyRecordCountService.java @@ -82,16 +82,24 @@ public class CreditCompanyRecordCountService { } // 表/字段名来自固定枚举,不允许外部传入,避免 SQL 注入。 + // + // 这里不要用「UPDATE ... SET col=(SELECT COUNT... WHERE t.company_id=c.id)」的相关子查询: + // 如果关联表缺少 (company_id, deleted) 索引,会导致对每个 company_id 都进行一次全表扫描,极慢, + // 进而容易触发 JDBC/MySQL 侧的超时/断链(Communications link failure)。 + // + // 用聚合后再 JOIN 的方式:每个 chunk 只扫描一次关联表。 String sql = "" + "UPDATE credit_company c " - + "SET " + type.getCompanyColumn() + " = (" - + " SELECT COUNT(1) " - + " FROM " + type.getSourceTable() + " t " - + " WHERE t.company_id = c.id AND t.deleted = 0" - + ") " + + "LEFT JOIN (" + + " SELECT company_id, COUNT(1) AS cnt " + + " FROM " + type.getSourceTable() + " " + + " WHERE deleted = 0 AND company_id IN (:ids) " + + " GROUP BY company_id" + + ") t ON t.company_id = c.id " + + "SET c." + type.getCompanyColumn() + " = IFNULL(t.cnt, 0) " + "WHERE c.id IN (:ids)"; - final int inChunkSize = 1000; + final int inChunkSize = 500; for (int i = 0; i < ids.size(); i += inChunkSize) { List chunk = ids.subList(i, Math.min(ids.size(), i + inChunkSize)); namedJdbc.update(sql, new MapSqlParameterSource("ids", chunk)); diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java index 770ca87..7a1e639 100644 --- a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java @@ -459,6 +459,8 @@ public class GltTicketOrderServiceImpl extends ServiceImpl() + .eq(GltUserTicket::getTenantId, tenantId) + .eq(GltUserTicket::getDeleted, 0) + .eq(GltUserTicket::getId, ticketOrder.getUserTicketId()) + .last("limit 1") + ); + if (userTicket == null) { + return; + } + + Integer shopOrderId = userTicket.getOrderId(); + String shopOrderNo = userTicket.getOrderNo(); + if (shopOrderId == null && !StringUtils.hasText(shopOrderNo)) { + return; + } + + LambdaUpdateWrapper uw = new LambdaUpdateWrapper() + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getDeleted, 0) + .and(w -> w.ne(ShopOrder::getOrderStatus, 1).or().isNull(ShopOrder::getOrderStatus)) + .set(ShopOrder::getOrderStatus, 1) + .set(ShopOrder::getUpdateTime, now); + if (shopOrderId != null) { + uw.eq(ShopOrder::getOrderId, shopOrderId); + } else { + uw.eq(ShopOrder::getOrderNo, shopOrderNo); + } + + boolean updated = shopOrderService.update(uw); + if (updated) { + return; + } + + // 幂等:若已是 1,则视为成功;否则记录日志便于排查关联关系/数据缺失 + LambdaQueryWrapper qw = new LambdaQueryWrapper() + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getDeleted, 0) + .eq(ShopOrder::getOrderStatus, 1); + if (shopOrderId != null) { + qw.eq(ShopOrder::getOrderId, shopOrderId); + } else { + qw.eq(ShopOrder::getOrderNo, shopOrderNo); + } + if (shopOrderService.count(qw) <= 0) { + log.warn("送水订单完成但同步商城订单完成状态失败 - tenantId={}, ticketOrderId={}, shopOrderId={}, shopOrderNo={}", + tenantId, ticketOrderId, shopOrderId, shopOrderNo); + } + } + private void settleRiderCommissionIfEligible(Integer ticketOrderId, Integer tenantId, boolean requirePhoto) { if (ticketOrderId == null || tenantId == null) { return; From 117773046426cdf219342401df60be8c409051e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Feb 2026 13:52:13 +0800 Subject: [PATCH 08/10] =?UTF-8?q?perf(task):=20=E8=B0=83=E6=95=B4=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E6=89=A7=E8=A1=8C=E9=A2=91=E7=8E=87?= =?UTF-8?q?=E4=BB=A5=E4=BC=98=E5=8C=96=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将经销商佣金解冻任务执行频率从每分钟调整为每30秒一次 - 将经销商订单结算任务执行频率从每20秒调整为每10秒一次 - 将GLT套票发放任务执行频率从每分钟调整为每15秒一次 - 将GLT票券订单自动确认任务执行频率从每分钟调整为每33秒一次 - 将GLT用户票券自动释放任务执行频率从每分钟调整为每10分钟一次 - 在票券订单完成时同步更新商城订单状态为已完成 --- .../glt/service/impl/GltTicketOrderServiceImpl.java | 3 +++ .../glt/task/DealerCommissionUnfreeze10584Task.java | 2 +- .../gxwebsoft/glt/task/DealerOrderSettlement10584Task.java | 6 +++--- .../com/gxwebsoft/glt/task/GltTicketIssue10584Task.java | 4 ++-- .../glt/task/GltTicketOrderAutoConfirm10584Task.java | 3 +-- .../gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java index 7a1e639..322d39c 100644 --- a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java @@ -407,6 +407,8 @@ public class GltTicketOrderServiceImpl extends ServiceImpl - * 每20秒执行一次,查询“已付款且未结算”的订单,按指定规则计算佣金并先计入分销商冻结金额(freezeMoney),并将订单置为已结算。 + * 每10秒执行一次,查询“已付款且未结算”的订单,按指定规则计算佣金并先计入分销商冻结金额(freezeMoney),并将订单置为已结算。 */ @Slf4j @Component @@ -88,9 +88,9 @@ public class DealerOrderSettlement10584Task { private UserMapper userMapper; /** - * 每30秒执行一次。 + * 每10秒执行一次。 */ - @Scheduled(cron = "0/20 * * * * ?") + @Scheduled(cron = "0/10 * * * * ?") @IgnoreTenant("该定时任务仅处理租户10584,但需要显式按tenantId过滤,避免定时任务线程无租户上下文导致查询异常") public void settleTenant10584Orders() { try { diff --git a/src/main/java/com/gxwebsoft/glt/task/GltTicketIssue10584Task.java b/src/main/java/com/gxwebsoft/glt/task/GltTicketIssue10584Task.java index bb34a8d..8dd9f28 100644 --- a/src/main/java/com/gxwebsoft/glt/task/GltTicketIssue10584Task.java +++ b/src/main/java/com/gxwebsoft/glt/task/GltTicketIssue10584Task.java @@ -16,7 +16,7 @@ import java.util.concurrent.atomic.AtomicBoolean; /** * GLT 套票发放任务: - * - 每分钟扫描一次今日订单(tenantId=10584, formId in 套票模板 goodsId, payStatus=1, orderStatus=0) + * - 每30秒扫描一次今日订单(tenantId=10584, formId in 套票模板 goodsId, payStatus=1, orderStatus=0) * - 为订单生成用户套票账户 + 释放计划(幂等) * - 若模板配置了 startSendQty,则发放时自动核销对应数量(用于“第一次送水”场景) */ @@ -33,7 +33,7 @@ public class GltTicketIssue10584Task { private final AtomicBoolean running = new AtomicBoolean(false); - @Scheduled(cron = "${glt.ticket.issue10584.cron:0 */1 * * * ?}") + @Scheduled(cron = "${glt.ticket.issue10584.cron:0/15 * * * * ?}") @IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤") public void run() { if (!running.compareAndSet(false, true)) { diff --git a/src/main/java/com/gxwebsoft/glt/task/GltTicketOrderAutoConfirm10584Task.java b/src/main/java/com/gxwebsoft/glt/task/GltTicketOrderAutoConfirm10584Task.java index a6f54c4..4866fce 100644 --- a/src/main/java/com/gxwebsoft/glt/task/GltTicketOrderAutoConfirm10584Task.java +++ b/src/main/java/com/gxwebsoft/glt/task/GltTicketOrderAutoConfirm10584Task.java @@ -34,7 +34,7 @@ public class GltTicketOrderAutoConfirm10584Task { private final AtomicBoolean running = new AtomicBoolean(false); - @Scheduled(cron = "${glt.ticket-order.auto-confirm10584.cron:0 */1 * * * ?}") + @Scheduled(cron = "${glt.ticket-order.auto-confirm10584.cron:0/33 * * * * ?}") @IgnoreTenant("定时任务无登录态,需忽略租户隔离;内部使用 tenantId=10584 精确过滤") public void run() { if (!running.compareAndSet(false, true)) { @@ -53,4 +53,3 @@ public class GltTicketOrderAutoConfirm10584Task { } } } - diff --git a/src/main/java/com/gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java b/src/main/java/com/gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java index 4450929..91855db 100644 --- a/src/main/java/com/gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java +++ b/src/main/java/com/gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java @@ -30,7 +30,7 @@ public class GltUserTicketAutoReleaseTask { private final AtomicBoolean running = new AtomicBoolean(false); - @Scheduled(cron = "${glt.ticket.auto-release.cron:0 */1 * * * ?}") + @Scheduled(cron = "${glt.ticket.auto-release.cron:0 */10 * * * ?}") @IgnoreTenant("定时任务无登录态,需忽略租户隔离;释放记录自带 tenantId,更新时会校验 tenantId") public void run() { if (!running.compareAndSet(false, true)) { From e1ef21f1408db5d2b4aab1120b6da50161ff26cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Tue, 10 Feb 2026 17:05:57 +0800 Subject: [PATCH 09/10] =?UTF-8?q?feat(order):=20=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E4=BB=98=E6=AC=BE=E5=87=8F=E5=BA=93=E5=AD=98=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=B9=B6=E4=BC=98=E5=8C=96=E8=AE=A2=E5=8D=95=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在GltTicketOrder实体中新增orderNo字段用于订单编号关联 - 在订单查询SQL中关联glt_user_ticket表获取订单编号 - 新增DEDUCT_STOCK_TYPE_ORDER和DEDUCT_STOCK_TYPE_PAY常量定义库存扣除时机 - 实现下单时跳过付款减库存商品的库存扣除逻辑 - 实现订单取消时跳过付款减库存商品的库存回退逻辑 - 在ShopGoods实体中添加deductStockType字段支持库存计算方式配置 - 通过@JsonAlias注解支持前端字段别名映射 - 实现支付成功后触发付款减库存的库存扣除逻辑 - 添加deductStockAfterPaidIfNeeded方法处理支付后库存扣除 - 优化syncPaymentStatus方法确保支付状态同步时触发相关业务逻辑 - 添加重复支付状态检查避免重复执行支付成功业务逻辑 - 实现租户隔离的库存扣除操作和异常兜底机制 --- .../gxwebsoft/glt/entity/GltTicketOrder.java | 4 + .../glt/mapper/xml/GltTicketOrderMapper.xml | 4 +- .../com/gxwebsoft/shop/entity/ShopGoods.java | 2 + .../shop/service/OrderBusinessService.java | 11 ++ .../service/impl/OrderCancelServiceImpl.java | 15 ++ .../service/impl/ShopOrderServiceImpl.java | 165 ++++++++++++++---- 6 files changed, 165 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java b/src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java index dfae59e..9038bb1 100644 --- a/src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java +++ b/src/main/java/com/gxwebsoft/glt/entity/GltTicketOrder.java @@ -31,6 +31,10 @@ public class GltTicketOrder implements Serializable { @Schema(description = "用户水票ID") private Integer userTicketId; + @Schema(description = "订单编号") + @TableField(exist = false) + private String orderNo; + @Schema(description = "门店ID") private Integer storeId; diff --git a/src/main/java/com/gxwebsoft/glt/mapper/xml/GltTicketOrderMapper.xml b/src/main/java/com/gxwebsoft/glt/mapper/xml/GltTicketOrderMapper.xml index a38798e..b45594c 100644 --- a/src/main/java/com/gxwebsoft/glt/mapper/xml/GltTicketOrderMapper.xml +++ b/src/main/java/com/gxwebsoft/glt/mapper/xml/GltTicketOrderMapper.xml @@ -10,13 +10,15 @@ u.nickname, u.phone, u.avatar, d.name as receiverName, d.phone as receiverPhone, 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, + f.order_no as orderNo FROM glt_ticket_order a 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_rider c ON a.rider_id = c.user_id LEFT JOIN gxwebsoft_core.sys_user u ON a.user_id = u.user_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 diff --git a/src/main/java/com/gxwebsoft/shop/entity/ShopGoods.java b/src/main/java/com/gxwebsoft/shop/entity/ShopGoods.java index 9d3f303..7fe522f 100644 --- a/src/main/java/com/gxwebsoft/shop/entity/ShopGoods.java +++ b/src/main/java/com/gxwebsoft/shop/entity/ShopGoods.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import java.time.LocalDateTime; +import com.fasterxml.jackson.annotation.JsonAlias; import com.fasterxml.jackson.annotation.JsonFormat; import java.io.Serializable; import io.swagger.v3.oas.annotations.media.Schema; @@ -101,6 +102,7 @@ public class ShopGoods implements Serializable { private BigDecimal secondDividend; @Schema(description = "库存计算方式(10下单减库存 20付款减库存)") + @JsonAlias({"cdeductStockType"}) private Integer deductStockType; @Schema(description = "交付方式(0不启用)") diff --git a/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java b/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java index 337b32c..ed8b43c 100644 --- a/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java +++ b/src/main/java/com/gxwebsoft/shop/service/OrderBusinessService.java @@ -32,6 +32,8 @@ import java.util.Map; @Slf4j @Service public class OrderBusinessService { + private static final int DEDUCT_STOCK_TYPE_ORDER = 10; // 下单减库存 + private static final int DEDUCT_STOCK_TYPE_PAY = 20; // 付款减库存 @Resource private ShopOrderService shopOrderService; @@ -713,6 +715,15 @@ public class OrderBusinessService { */ private void deductStock(OrderCreateRequest request) { for (OrderCreateRequest.OrderGoodsItem item : request.getGoodsItems()) { + // 付款减库存的商品:创建订单时不扣库存 + ShopGoods goodsForType = shopGoodsService.getById(item.getGoodsId()); + Integer deductStockType = goodsForType != null ? goodsForType.getDeductStockType() : null; + if (deductStockType != null && deductStockType == DEDUCT_STOCK_TYPE_PAY) { + log.debug("跳过下单扣库存(付款减库存) - goodsId={}, skuId={}, qty={}", + item.getGoodsId(), item.getSkuId(), item.getQuantity()); + continue; + } + if (item.getSkuId() != null) { // 多规格商品,扣减SKU库存 ShopGoodsSku sku = shopGoodsSkuService.getById(item.getSkuId()); diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java index 46901d2..f327838 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/OrderCancelServiceImpl.java @@ -24,6 +24,7 @@ import java.util.List; @Slf4j @Service public class OrderCancelServiceImpl implements OrderCancelService { + private static final int DEDUCT_STOCK_TYPE_PAY = 20; // 付款减库存:下单不扣库存,因此未支付取消无需回退 @Autowired private ShopOrderService shopOrderService; @@ -182,6 +183,20 @@ public class OrderCancelServiceImpl implements OrderCancelService { } for (ShopOrderGoods orderGood : orderGoods) { + // 付款减库存的商品:创建订单时未扣库存,未支付取消时无需回退(避免库存被“加多”) + try { + ShopGoods goods = shopGoodsService.getById(orderGood.getGoodsId()); + if (goods != null && goods.getDeductStockType() != null && goods.getDeductStockType() == DEDUCT_STOCK_TYPE_PAY) { + log.debug("跳过未支付取消的库存回退(付款减库存) - orderId={}, goodsId={}, skuId={}, qty={}", + order.getOrderId(), orderGood.getGoodsId(), orderGood.getSkuId(), orderGood.getTotalNum()); + continue; + } + } catch (Exception e) { + // 查不到商品或查询异常时,保持原有回退逻辑,避免出现“库存无法回退”的更坏情况 + log.warn("读取商品扣库存方式失败,继续执行库存回退 - orderId={}, goodsId={}", + order.getOrderId(), orderGood.getGoodsId(), e); + } + if (orderGood.getSkuId() != null && orderGood.getSkuId() > 0) { // 多规格商品,恢复SKU库存 restoreSkuStock(orderGood); diff --git a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java index 24322b7..9f91ffb 100644 --- a/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/shop/service/impl/ShopOrderServiceImpl.java @@ -1,8 +1,10 @@ package com.gxwebsoft.shop.service.impl; import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.gxwebsoft.common.core.context.TenantContext; import com.gxwebsoft.common.core.config.ConfigProperties; import com.gxwebsoft.common.core.config.CertificateProperties; import com.gxwebsoft.common.core.utils.*; @@ -86,10 +88,13 @@ public class ShopOrderServiceImpl extends ServiceImpl 0) { markCouponAsUsed(order); @@ -816,6 +829,90 @@ public class ShopOrderServiceImpl extends ServiceImpl orderGoodsList = shopOrderGoodsService.getListByOrderIdIgnoreTenant(order.getOrderId()); + if (CollectionUtils.isEmpty(orderGoodsList)) { + return; + } + + TenantContext.runIgnoreTenant(() -> { + for (ShopOrderGoods og : orderGoodsList) { + if (og == null || og.getGoodsId() == null) { + continue; + } + int qty = og.getTotalNum() == null ? 0 : og.getTotalNum(); + if (qty <= 0) { + continue; + } + + ShopGoods goods = shopGoodsService.getById(og.getGoodsId()); + Integer deductStockType = goods != null ? goods.getDeductStockType() : null; + if (deductStockType == null || deductStockType != DEDUCT_STOCK_TYPE_PAY) { + continue; + } + + try { + if (og.getSkuId() != null && og.getSkuId() > 0) { + // 多规格:扣 SKU 库存 + boolean updated = shopGoodsSkuService.update( + new LambdaUpdateWrapper() + .eq(ShopGoodsSku::getId, og.getSkuId()) + .eq(ShopGoodsSku::getTenantId, order.getTenantId()) + .apply("IFNULL(stock,0) >= {0}", qty) + .setSql("stock = IFNULL(stock,0) - " + qty) + ); + if (!updated) { + log.warn("支付成功后扣SKU库存失败 - tenantId={}, orderId={}, skuId={}, goodsId={}, qty={}", + order.getTenantId(), order.getOrderId(), og.getSkuId(), og.getGoodsId(), qty); + // 兜底:库存不足时至少将库存置0,避免出现“明明已售出但库存仍大于0”的情况 + shopGoodsSkuService.update( + new LambdaUpdateWrapper() + .eq(ShopGoodsSku::getId, og.getSkuId()) + .eq(ShopGoodsSku::getTenantId, order.getTenantId()) + .apply("IFNULL(stock,0) < {0}", qty) + .setSql("stock = 0") + ); + } + } else { + // 单规格:扣商品库存 + boolean updated = shopGoodsService.update( + new LambdaUpdateWrapper() + .eq(ShopGoods::getGoodsId, og.getGoodsId()) + .eq(ShopGoods::getTenantId, order.getTenantId()) + .apply("IFNULL(stock,0) >= {0}", qty) + .setSql("stock = IFNULL(stock,0) - " + qty) + ); + if (!updated) { + log.warn("支付成功后扣商品库存失败 - tenantId={}, orderId={}, goodsId={}, qty={}", + order.getTenantId(), order.getOrderId(), og.getGoodsId(), qty); + // 兜底:库存不足时至少将库存置0,避免出现“明明已售出但库存仍大于0”的情况 + shopGoodsService.update( + new LambdaUpdateWrapper() + .eq(ShopGoods::getGoodsId, og.getGoodsId()) + .eq(ShopGoods::getTenantId, order.getTenantId()) + .apply("IFNULL(stock,0) < {0}", qty) + .setSql("stock = 0") + ); + } + } + } catch (Exception e) { + log.warn("支付成功后扣库存异常 - tenantId={}, orderId={}, goodsId={}, skuId={}, qty={}", + order.getTenantId(), order.getOrderId(), og.getGoodsId(), og.getSkuId(), qty, e); + } + } + }); + } + /** * 标记优惠券为已使用 */ @@ -1452,43 +1549,41 @@ public class ShopOrderServiceImpl extends ServiceImpl Date: Tue, 10 Feb 2026 17:27:45 +0800 Subject: [PATCH 10/10] =?UTF-8?q?feat(order):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E9=80=81=E6=B0=B4=E8=AE=A2=E5=8D=95=E4=B8=8E=E5=95=86=E5=9F=8E?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E5=90=8C=E6=AD=A5=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在订单更新时增加租户ID获取逻辑并传递给相关服务方法 - 新增后台直接修改订单为已完成状态时同步商城订单的功能 - 优化数据库查询,使用COALESCE函数处理订单号显示逻辑 - 新增通过订单商品ID反向查找商城订单的兼容性处理 - 增加历史数据兜底机制,自动回填缺失的订单关联信息 - 添加详细的日志记录用于调试和监控订单同步状态 --- .../controller/GltTicketOrderController.java | 10 +- .../glt/mapper/xml/GltTicketOrderMapper.xml | 3 +- .../glt/service/GltTicketOrderService.java | 7 ++ .../impl/GltTicketOrderServiceImpl.java | 108 ++++++++++++++++++ 4 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java b/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java index d8dc338..4502142 100644 --- a/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java +++ b/src/main/java/com/gxwebsoft/glt/controller/GltTicketOrderController.java @@ -242,6 +242,7 @@ public class GltTicketOrderController extends BaseController { @PutMapping() public ApiResult update(@RequestBody GltTicketOrder gltTicketOrder) { if (gltTicketOrderService.updateById(gltTicketOrder)) { + Integer tenantId = getTenantId(); // 后台指派配送员(直接改 riderId)时,同步商城订单为“已发货”(deliveryStatus=20) if (gltTicketOrder != null && gltTicketOrder.getId() != null @@ -249,10 +250,17 @@ public class GltTicketOrderController extends BaseController { && gltTicketOrder.getRiderId() > 0) { gltTicketOrderService.markShopOrderShippedAfterRiderAssigned( gltTicketOrder.getId(), - getTenantId(), + tenantId, gltTicketOrder.getRiderId() ); } + // 后台直接改“已完成”(deliveryStatus=40)时,同步商城订单为“已完成”(orderStatus=1) + if (gltTicketOrder != null + && gltTicketOrder.getId() != null + && gltTicketOrder.getDeliveryStatus() != null + && gltTicketOrder.getDeliveryStatus() == GltTicketOrderService.DELIVERY_STATUS_FINISHED) { + gltTicketOrderService.markShopOrderCompletedAfterTicketFinished(gltTicketOrder.getId(), tenantId); + } return success("修改成功"); } return fail("修改失败"); diff --git a/src/main/java/com/gxwebsoft/glt/mapper/xml/GltTicketOrderMapper.xml b/src/main/java/com/gxwebsoft/glt/mapper/xml/GltTicketOrderMapper.xml index b45594c..91312a4 100644 --- a/src/main/java/com/gxwebsoft/glt/mapper/xml/GltTicketOrderMapper.xml +++ b/src/main/java/com/gxwebsoft/glt/mapper/xml/GltTicketOrderMapper.xml @@ -11,7 +11,7 @@ d.name as receiverName, d.phone as receiverPhone, 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, - f.order_no as orderNo + COALESCE(o.order_no, f.order_no) as orderNo FROM glt_ticket_order a LEFT JOIN shop_store b ON a.store_id = b.id LEFT JOIN shop_store_warehouse w ON a.warehouse_id = w.id @@ -19,6 +19,7 @@ LEFT JOIN gxwebsoft_core.sys_user u ON a.user_id = u.user_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 shop_order o ON f.order_id = o.order_id AND f.tenant_id = o.tenant_id AND o.deleted = 0 diff --git a/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java b/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java index 1252f65..9f3fc81 100644 --- a/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java +++ b/src/main/java/com/gxwebsoft/glt/service/GltTicketOrderService.java @@ -71,6 +71,13 @@ public interface GltTicketOrderService extends IService { */ void markShopOrderShippedAfterRiderAssigned(Integer ticketOrderId, Integer tenantId, Integer riderId); + /** + * 送水订单完成后,同步关联商城订单为“已完成”(orderStatus=1)。 + * + *

用于后台直接改 deliveryStatus=40 等不经过 confirmReceive/autoConfirmTimeout 的兜底同步。

+ */ + void markShopOrderCompletedAfterTicketFinished(Integer ticketOrderId, Integer tenantId); + /** * 配送员开始配送:10 -> 20,并写 sendStartTime。 */ diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java index 322d39c..cca8400 100644 --- a/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltTicketOrderServiceImpl.java @@ -21,8 +21,10 @@ import com.gxwebsoft.glt.service.GltUserTicketService; import com.gxwebsoft.shop.entity.ShopDealerCapital; import com.gxwebsoft.shop.entity.ShopDealerUser; import com.gxwebsoft.shop.entity.ShopOrder; +import com.gxwebsoft.shop.entity.ShopOrderGoods; import com.gxwebsoft.shop.service.ShopDealerCapitalService; import com.gxwebsoft.shop.service.ShopDealerUserService; +import com.gxwebsoft.shop.service.ShopOrderGoodsService; import com.gxwebsoft.shop.service.ShopOrderService; import lombok.extern.slf4j.Slf4j; import org.springframework.util.StringUtils; @@ -77,6 +79,9 @@ public class GltTicketOrderServiceImpl extends ServiceImpl pageRel(GltTicketOrderParam param) { PageParam page = new PageParam<>(param); @@ -249,6 +254,11 @@ public class GltTicketOrderServiceImpl extends ServiceImpl() + .select(ShopOrderGoods::getOrderId) + .eq(ShopOrderGoods::getTenantId, tenantId) + .eq(ShopOrderGoods::getId, userTicket.getOrderGoodsId()) + .last("limit 1") + ); + if (og != null) { + shopOrderId = og.getOrderId(); + resolvedByOrderGoodsId = shopOrderId != null; + } + } if (shopOrderId == null && !StringUtils.hasText(shopOrderNo)) { + log.warn("同步商城订单发货状态失败:未找到关联商城订单 - tenantId={}, ticketOrderId={}, userTicketId={}, userTicket.orderId={}, userTicket.orderNo={}, userTicket.orderGoodsId={}", + tenantId, ticketOrderId, userTicket.getId(), userTicket.getOrderId(), userTicket.getOrderNo(), userTicket.getOrderGoodsId()); return; } + // 若是通过 orderGoodsId 兜底反查到 orderId,则顺便回填 glt_user_ticket.order_id/order_no,减少后续同步/查询依赖兜底分支。 + if (resolvedByOrderGoodsId && userTicket.getOrderId() == null && shopOrderId != null) { + if (!StringUtils.hasText(shopOrderNo)) { + ShopOrder order = shopOrderService.getOne( + new LambdaQueryWrapper() + .select(ShopOrder::getOrderNo) + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getDeleted, 0) + .eq(ShopOrder::getOrderId, shopOrderId) + .last("limit 1") + ); + if (order != null) { + shopOrderNo = order.getOrderNo(); + } + } + + LambdaUpdateWrapper backfill = new LambdaUpdateWrapper() + .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 uw = new LambdaUpdateWrapper() .eq(ShopOrder::getTenantId, tenantId) @@ -586,9 +645,58 @@ public class GltTicketOrderServiceImpl extends ServiceImpl() + .select(ShopOrderGoods::getOrderId) + .eq(ShopOrderGoods::getTenantId, tenantId) + .eq(ShopOrderGoods::getId, userTicket.getOrderGoodsId()) + .last("limit 1") + ); + if (og != null) { + shopOrderId = og.getOrderId(); + resolvedByOrderGoodsId = shopOrderId != null; + } + } if (shopOrderId == null && !StringUtils.hasText(shopOrderNo)) { + log.warn("送水订单完成但未找到关联商城订单,无法同步完成状态 - tenantId={}, ticketOrderId={}, userTicketId={}, userTicket.orderId={}, userTicket.orderNo={}, userTicket.orderGoodsId={}", + tenantId, ticketOrderId, userTicket.getId(), userTicket.getOrderId(), userTicket.getOrderNo(), userTicket.getOrderGoodsId()); return; } + // 若是通过 orderGoodsId 兜底反查到 orderId,则顺便回填 glt_user_ticket.order_id/order_no,减少后续同步/查询依赖兜底分支。 + if (resolvedByOrderGoodsId && userTicket.getOrderId() == null && shopOrderId != null) { + if (!StringUtils.hasText(shopOrderNo)) { + ShopOrder order = shopOrderService.getOne( + new LambdaQueryWrapper() + .select(ShopOrder::getOrderNo) + .eq(ShopOrder::getTenantId, tenantId) + .eq(ShopOrder::getDeleted, 0) + .eq(ShopOrder::getOrderId, shopOrderId) + .last("limit 1") + ); + if (order != null) { + shopOrderNo = order.getOrderNo(); + } + } + + LambdaUpdateWrapper backfill = new LambdaUpdateWrapper() + .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 uw = new LambdaUpdateWrapper() .eq(ShopOrder::getTenantId, tenantId)