From a20d1dd4659d23e17e381db2552017462f96b601 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E5=BF=A0=E6=9E=97?= <170083662@qq.com> Date: Sat, 7 Feb 2026 00:25:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(tickets):=20=E5=AE=9E=E7=8E=B0=E5=86=BB?= =?UTF-8?q?=E7=BB=93=E6=B0=B4=E7=A5=A8=E8=87=AA=E5=8A=A8=E9=87=8A=E6=94=BE?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 GltUserTicketMapper 中新增 releaseFrozenQty 方法用于释放冻结水票 - 新增 GltUserTicketReleaseMapper 处理释放记录的查询和状态更新 - 添加 H2 数据库依赖支持单元测试 - 创建 GltUserTicketAutoReleaseService 接口及其实现类 - 实现自动释放服务的核心逻辑包括加锁查询、数量更新和流水记录 - 新建定时任务 GltUserTicketAutoReleaseTask 定期执行释放操作 - 添加完整的单元测试覆盖正常释放、未到期和冻结不足等场景 - 创建测试专用数据库表结构文件 --- pom.xml | 5 + .../glt/mapper/GltUserTicketMapper.java | 26 +++ .../mapper/GltUserTicketReleaseMapper.java | 36 +++ .../GltUserTicketAutoReleaseService.java | 26 +++ .../GltUserTicketAutoReleaseServiceImpl.java | 132 +++++++++++ .../task/GltUserTicketAutoReleaseTask.java | 51 +++++ .../glt/AutoReleaseTestApplication.java | 22 ++ .../GltUserTicketAutoReleaseServiceTest.java | 209 ++++++++++++++++++ src/test/resources/schema-auto-release-h2.sql | 62 ++++++ 9 files changed, 569 insertions(+) create mode 100644 src/main/java/com/gxwebsoft/glt/service/GltUserTicketAutoReleaseService.java create mode 100644 src/main/java/com/gxwebsoft/glt/service/impl/GltUserTicketAutoReleaseServiceImpl.java create mode 100644 src/main/java/com/gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java create mode 100644 src/test/java/com/gxwebsoft/glt/AutoReleaseTestApplication.java create mode 100644 src/test/java/com/gxwebsoft/glt/service/GltUserTicketAutoReleaseServiceTest.java create mode 100644 src/test/resources/schema-auto-release-h2.sql diff --git a/pom.xml b/pom.xml index 3cd2de5..320011d 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,11 @@ spring-boot-starter-test test + + com.h2database + h2 + test + diff --git a/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketMapper.java b/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketMapper.java index b1eb700..d46a767 100644 --- a/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketMapper.java +++ b/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketMapper.java @@ -5,8 +5,10 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.gxwebsoft.glt.entity.GltUserTicket; import com.gxwebsoft.glt.param.GltUserTicketParam; import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; import org.apache.ibatis.annotations.Param; +import java.time.LocalDateTime; import java.util.List; /** @@ -63,4 +65,28 @@ public interface GltUserTicketMapper extends BaseMapper { @Param("userId") Integer userId, @Param("tenantId") Integer tenantId); + /** + * 释放冻结水票(冻结 -> 可用;并累加已释放数量) + *

+ * 返回值为受影响行数:1 表示释放成功;0 表示记录不存在/状态不符/冻结不足。 + */ + @Update(""" + UPDATE glt_user_ticket + SET available_qty = COALESCE(available_qty, 0) + #{qty}, + frozen_qty = COALESCE(frozen_qty, 0) - #{qty}, + released_qty = COALESCE(released_qty, 0) + #{qty}, + update_time = #{now} + WHERE id = #{id} + AND user_id = #{userId} + AND tenant_id = #{tenantId} + AND status = 0 + AND deleted = 0 + AND COALESCE(frozen_qty, 0) >= #{qty} + """) + int releaseFrozenQty(@Param("id") Integer id, + @Param("userId") Integer userId, + @Param("tenantId") Integer tenantId, + @Param("qty") Integer qty, + @Param("now") LocalDateTime now); + } diff --git a/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketReleaseMapper.java b/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketReleaseMapper.java index aef1462..baf5639 100644 --- a/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketReleaseMapper.java +++ b/src/main/java/com/gxwebsoft/glt/mapper/GltUserTicketReleaseMapper.java @@ -4,8 +4,11 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.gxwebsoft.glt.entity.GltUserTicketRelease; import com.gxwebsoft.glt.param.GltUserTicketReleaseParam; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; import org.apache.ibatis.annotations.Param; +import java.time.LocalDateTime; import java.util.List; /** @@ -34,4 +37,37 @@ public interface GltUserTicketReleaseMapper extends BaseMapper selectListRel(@Param("param") GltUserTicketReleaseParam param); + /** + * 查询待释放且到期的记录(加行锁,防止多实例重复处理) + * + * status: 0=待释放, 1=已释放, 2=释放失败(数据异常) + */ + @Select(""" + SELECT * + FROM glt_user_ticket_release + WHERE status = 0 + AND deleted = 0 + AND release_time <= #{now} + ORDER BY release_time ASC, id ASC + LIMIT #{limit} + FOR UPDATE + """) + List selectDueForUpdate(@Param("now") LocalDateTime now, + @Param("limit") int limit); + + /** + * 更新释放记录状态 + */ + @Update(""" + UPDATE glt_user_ticket_release + SET status = #{status}, + update_time = #{now} + WHERE id = #{id} + AND deleted = 0 + AND status = 0 + """) + int updateStatus(@Param("id") Long id, + @Param("status") Integer status, + @Param("now") LocalDateTime now); + } diff --git a/src/main/java/com/gxwebsoft/glt/service/GltUserTicketAutoReleaseService.java b/src/main/java/com/gxwebsoft/glt/service/GltUserTicketAutoReleaseService.java new file mode 100644 index 0000000..83a7fb3 --- /dev/null +++ b/src/main/java/com/gxwebsoft/glt/service/GltUserTicketAutoReleaseService.java @@ -0,0 +1,26 @@ +package com.gxwebsoft.glt.service; + +import java.time.LocalDateTime; + +/** + * 冻结水票自动释放(到达 release_time 后执行:frozen -> available)。 + */ +public interface GltUserTicketAutoReleaseService { + + /** + * 释放到期的冻结水票 + * + * @param now 当前时间(用于测试/可控时钟) + * @param batchSize 单次处理上限 + * @return 成功释放的条数 + */ + int releaseDue(LocalDateTime now, int batchSize); + + /** + * 释放到期的冻结水票(使用系统当前时间) + */ + default int releaseDue(int batchSize) { + return releaseDue(LocalDateTime.now(), batchSize); + } +} + diff --git a/src/main/java/com/gxwebsoft/glt/service/impl/GltUserTicketAutoReleaseServiceImpl.java b/src/main/java/com/gxwebsoft/glt/service/impl/GltUserTicketAutoReleaseServiceImpl.java new file mode 100644 index 0000000..fb576e4 --- /dev/null +++ b/src/main/java/com/gxwebsoft/glt/service/impl/GltUserTicketAutoReleaseServiceImpl.java @@ -0,0 +1,132 @@ +package com.gxwebsoft.glt.service.impl; + +import com.gxwebsoft.glt.entity.GltUserTicket; +import com.gxwebsoft.glt.entity.GltUserTicketLog; +import com.gxwebsoft.glt.entity.GltUserTicketRelease; +import com.gxwebsoft.glt.mapper.GltUserTicketLogMapper; +import com.gxwebsoft.glt.mapper.GltUserTicketMapper; +import com.gxwebsoft.glt.mapper.GltUserTicketReleaseMapper; +import com.gxwebsoft.glt.service.GltUserTicketAutoReleaseService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 冻结水票自动释放实现: + * - 读取到期且待释放的 release 记录(FOR UPDATE 加锁,防止重复处理) + * - 释放成功:更新 user_ticket 数量 & 将 release.status 置为 1,并写入流水 + * - 释放失败:将 release.status 置为 2(数据异常/冻结不足等) + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class GltUserTicketAutoReleaseServiceImpl implements GltUserTicketAutoReleaseService { + + /** + * 变更类型:冻结释放 + *

+ * 现有发放类型为 10(见 GltTicketIssueService.CHANGE_TYPE_ISSUE),这里取 11。 + */ + private static final int CHANGE_TYPE_RELEASE = 11; + + /** release.status:待释放 */ + private static final int RELEASE_STATUS_PENDING = 0; + /** release.status:已释放 */ + private static final int RELEASE_STATUS_DONE = 1; + /** release.status:释放失败(数据异常/冻结不足等,需人工处理) */ + private static final int RELEASE_STATUS_FAILED = 2; + + private final GltUserTicketReleaseMapper releaseMapper; + private final GltUserTicketMapper userTicketMapper; + private final GltUserTicketLogMapper userTicketLogMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public int releaseDue(LocalDateTime now, int batchSize) { + int limit = Math.max(batchSize, 1); + List dueList = releaseMapper.selectDueForUpdate(now, limit); + if (dueList == null || dueList.isEmpty()) { + return 0; + } + + int success = 0; + for (GltUserTicketRelease rel : dueList) { + if (rel.getId() == null || rel.getStatus() == null || rel.getStatus() != RELEASE_STATUS_PENDING) { + continue; + } + + Integer qtyObj = rel.getReleaseQty(); + if (qtyObj == null || qtyObj <= 0) { + markFailed(rel.getId(), now, "releaseQty无效"); + continue; + } + int qty = qtyObj; + + if (rel.getUserTicketId() == null || rel.getUserId() == null || rel.getTenantId() == null) { + markFailed(rel.getId(), now, "缺少userTicketId/userId/tenantId"); + continue; + } + + long userTicketIdLong = rel.getUserTicketId(); + if (userTicketIdLong > Integer.MAX_VALUE || userTicketIdLong < 1) { + markFailed(rel.getId(), now, "userTicketId超范围"); + continue; + } + Integer userTicketId = (int) userTicketIdLong; + + // 先释放冻结数量(条件更新,确保 frozen_qty >= qty) + int updated = userTicketMapper.releaseFrozenQty( + userTicketId, + rel.getUserId(), + rel.getTenantId(), + qty, + now + ); + if (updated <= 0) { + markFailed(rel.getId(), now, "冻结不足/水票不存在/状态不符"); + continue; + } + + // 写入流水(可用 +qty,冻结 -qty) + GltUserTicket ticket = userTicketMapper.selectById(userTicketId); + GltUserTicketLog logRow = new GltUserTicketLog(); + logRow.setUserTicketId(userTicketId); + logRow.setChangeType(CHANGE_TYPE_RELEASE); + logRow.setChangeAvailable(qty); + logRow.setChangeFrozen(-qty); + logRow.setChangeUsed(0); + if (ticket != null) { + logRow.setAvailableAfter(ticket.getAvailableQty()); + logRow.setFrozenAfter(ticket.getFrozenQty()); + logRow.setUsedAfter(ticket.getUsedQty()); + } + logRow.setOrderId(null); + logRow.setOrderNo(null); + logRow.setUserId(rel.getUserId()); + logRow.setSortNumber(0); + logRow.setComments("冻结水票到期释放"); + logRow.setStatus(0); + logRow.setDeleted(0); + logRow.setTenantId(rel.getTenantId()); + logRow.setCreateTime(now); + logRow.setUpdateTime(now); + userTicketLogMapper.insert(logRow); + + // 标记释放记录已完成(放在最后:若流水失败则回滚) + releaseMapper.updateStatus(rel.getId(), RELEASE_STATUS_DONE, now); + + success++; + } + + return success; + } + + private void markFailed(Long releaseId, LocalDateTime now, String reason) { + releaseMapper.updateStatus(releaseId, RELEASE_STATUS_FAILED, now); + log.warn("冻结水票释放标记失败 - releaseId={}, reason={}", releaseId, reason); + } +} diff --git a/src/main/java/com/gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java b/src/main/java/com/gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java new file mode 100644 index 0000000..4450929 --- /dev/null +++ b/src/main/java/com/gxwebsoft/glt/task/GltUserTicketAutoReleaseTask.java @@ -0,0 +1,51 @@ +package com.gxwebsoft.glt.task; + +import com.gxwebsoft.common.core.annotation.IgnoreTenant; +import com.gxwebsoft.glt.service.GltUserTicketAutoReleaseService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * 冻结水票自动释放任务: + * - 扫描 glt_user_ticket_release 中到期且待释放(status=0)的记录 + * - 释放成功:frozen -> available,并将 release.status 置为 1 + */ +@Slf4j +@Component +@RequiredArgsConstructor +@ConditionalOnProperty(prefix = "glt.ticket.auto-release", name = "enabled", havingValue = "true", matchIfMissing = true) +public class GltUserTicketAutoReleaseTask { + + private final GltUserTicketAutoReleaseService autoReleaseService; + + @Value("${glt.ticket.auto-release.batch-size:200}") + private int batchSize; + + private final AtomicBoolean running = new AtomicBoolean(false); + + @Scheduled(cron = "${glt.ticket.auto-release.cron:0 */1 * * * ?}") + @IgnoreTenant("定时任务无登录态,需忽略租户隔离;释放记录自带 tenantId,更新时会校验 tenantId") + public void run() { + if (!running.compareAndSet(false, true)) { + log.warn("冻结水票自动释放任务仍在执行中,本轮跳过"); + return; + } + + try { + LocalDateTime now = LocalDateTime.now(); + int released = autoReleaseService.releaseDue(now, Math.max(batchSize, 1)); + if (released > 0) { + log.info("冻结水票自动释放完成 - released={}, now={}", released, now); + } + } finally { + running.set(false); + } + } +} diff --git a/src/test/java/com/gxwebsoft/glt/AutoReleaseTestApplication.java b/src/test/java/com/gxwebsoft/glt/AutoReleaseTestApplication.java new file mode 100644 index 0000000..dced12c --- /dev/null +++ b/src/test/java/com/gxwebsoft/glt/AutoReleaseTestApplication.java @@ -0,0 +1,22 @@ +package com.gxwebsoft.glt; + +import com.gxwebsoft.glt.mapper.GltUserTicketLogMapper; +import com.gxwebsoft.glt.mapper.GltUserTicketMapper; +import com.gxwebsoft.glt.mapper.GltUserTicketReleaseMapper; +import com.gxwebsoft.glt.service.impl.GltUserTicketAutoReleaseServiceImpl; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.context.annotation.Import; + +@SpringBootConfiguration +@EnableAutoConfiguration +@MapperScan(basePackageClasses = { + GltUserTicketMapper.class, + GltUserTicketReleaseMapper.class, + GltUserTicketLogMapper.class +}) +@Import(GltUserTicketAutoReleaseServiceImpl.class) +public class AutoReleaseTestApplication { +} + diff --git a/src/test/java/com/gxwebsoft/glt/service/GltUserTicketAutoReleaseServiceTest.java b/src/test/java/com/gxwebsoft/glt/service/GltUserTicketAutoReleaseServiceTest.java new file mode 100644 index 0000000..dda1579 --- /dev/null +++ b/src/test/java/com/gxwebsoft/glt/service/GltUserTicketAutoReleaseServiceTest.java @@ -0,0 +1,209 @@ +package com.gxwebsoft.glt.service; + +import com.gxwebsoft.glt.AutoReleaseTestApplication; +import com.gxwebsoft.glt.entity.GltUserTicket; +import com.gxwebsoft.glt.entity.GltUserTicketLog; +import com.gxwebsoft.glt.entity.GltUserTicketRelease; +import com.gxwebsoft.glt.mapper.GltUserTicketLogMapper; +import com.gxwebsoft.glt.mapper.GltUserTicketMapper; +import com.gxwebsoft.glt.mapper.GltUserTicketReleaseMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.jdbc.core.JdbcTemplate; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +@SpringBootTest( + classes = AutoReleaseTestApplication.class, + properties = { + "spring.datasource.url=jdbc:h2:mem:auto_release;MODE=MySQL;DB_CLOSE_DELAY=-1;DATABASE_TO_LOWER=TRUE", + "spring.datasource.driver-class-name=org.h2.Driver", + "spring.datasource.username=sa", + "spring.datasource.password=", + "spring.sql.init.mode=always", + "spring.sql.init.schema-locations=classpath:schema-auto-release-h2.sql", + "mybatis-plus.configuration.map-underscore-to-camel-case=true", + "mybatis-plus.global-config.db-config.logic-delete-value=1", + "mybatis-plus.global-config.db-config.logic-not-delete-value=0" + } +) +class GltUserTicketAutoReleaseServiceTest { + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private GltUserTicketMapper userTicketMapper; + + @Autowired + private GltUserTicketReleaseMapper releaseMapper; + + @Autowired + private GltUserTicketLogMapper logMapper; + + @Autowired + private GltUserTicketAutoReleaseService autoReleaseService; + + @BeforeEach + void clean() { + jdbcTemplate.execute("DELETE FROM glt_user_ticket_log"); + jdbcTemplate.execute("DELETE FROM glt_user_ticket_release"); + jdbcTemplate.execute("DELETE FROM glt_user_ticket"); + } + + @Test + void releaseDue_success_updatesTicketReleaseAndWritesLog() { + LocalDateTime now = LocalDateTime.of(2026, 2, 6, 12, 0, 0); + + GltUserTicket ticket = new GltUserTicket(); + ticket.setTemplateId(1); + ticket.setGoodsId(1); + ticket.setOrderId(1); + ticket.setOrderNo("T-001"); + ticket.setOrderGoodsId(1); + ticket.setTotalQty(10); + ticket.setAvailableQty(0); + ticket.setFrozenQty(10); + ticket.setUsedQty(0); + ticket.setReleasedQty(0); + ticket.setUserId(100); + ticket.setSortNumber(0); + ticket.setComments("test"); + ticket.setStatus(0); + ticket.setDeleted(0); + ticket.setTenantId(10584); + ticket.setCreateTime(now); + ticket.setUpdateTime(now); + assertEquals(1, userTicketMapper.insert(ticket)); + assertNotNull(ticket.getId()); + + GltUserTicketRelease rel = new GltUserTicketRelease(); + rel.setUserTicketId(ticket.getId().longValue()); + rel.setUserId(100); + rel.setPeriodNo(1); + rel.setReleaseQty(3); + rel.setReleaseTime(now.minusSeconds(1)); + rel.setStatus(0); + rel.setDeleted(0); + rel.setTenantId(10584); + rel.setCreateTime(now); + rel.setUpdateTime(now); + assertEquals(1, releaseMapper.insert(rel)); + assertNotNull(rel.getId()); + + int releasedCount = autoReleaseService.releaseDue(now, 100); + assertEquals(1, releasedCount); + + GltUserTicket after = userTicketMapper.selectById(ticket.getId()); + assertNotNull(after); + assertEquals(3, after.getAvailableQty()); + assertEquals(7, after.getFrozenQty()); + assertEquals(3, after.getReleasedQty()); + + GltUserTicketRelease relAfter = releaseMapper.selectById(rel.getId()); + assertNotNull(relAfter); + assertEquals(1, relAfter.getStatus()); + + List logs = logMapper.selectList(null); + assertEquals(1, logs.size()); + assertEquals(ticket.getId(), logs.get(0).getUserTicketId()); + assertEquals(3, logs.get(0).getChangeAvailable()); + assertEquals(-3, logs.get(0).getChangeFrozen()); + } + + @Test + void releaseDue_notDue_noop() { + LocalDateTime now = LocalDateTime.of(2026, 2, 6, 12, 0, 0); + + GltUserTicket ticket = new GltUserTicket(); + ticket.setTotalQty(10); + ticket.setAvailableQty(0); + ticket.setFrozenQty(10); + ticket.setUsedQty(0); + ticket.setReleasedQty(0); + ticket.setUserId(100); + ticket.setStatus(0); + ticket.setDeleted(0); + ticket.setTenantId(10584); + ticket.setCreateTime(now); + ticket.setUpdateTime(now); + userTicketMapper.insert(ticket); + + GltUserTicketRelease rel = new GltUserTicketRelease(); + rel.setUserTicketId(ticket.getId().longValue()); + rel.setUserId(100); + rel.setPeriodNo(1); + rel.setReleaseQty(3); + rel.setReleaseTime(now.plusDays(1)); + rel.setStatus(0); + rel.setDeleted(0); + rel.setTenantId(10584); + rel.setCreateTime(now); + rel.setUpdateTime(now); + releaseMapper.insert(rel); + + int releasedCount = autoReleaseService.releaseDue(now, 100); + assertEquals(0, releasedCount); + + GltUserTicket after = userTicketMapper.selectById(ticket.getId()); + assertNotNull(after); + assertEquals(0, after.getAvailableQty()); + assertEquals(10, after.getFrozenQty()); + + GltUserTicketRelease relAfter = releaseMapper.selectById(rel.getId()); + assertNotNull(relAfter); + assertEquals(0, relAfter.getStatus()); + assertEquals(0, logMapper.selectCount(null)); + } + + @Test + void releaseDue_frozenInsufficient_marksFailed() { + LocalDateTime now = LocalDateTime.of(2026, 2, 6, 12, 0, 0); + + GltUserTicket ticket = new GltUserTicket(); + ticket.setTotalQty(2); + ticket.setAvailableQty(0); + ticket.setFrozenQty(2); + ticket.setUsedQty(0); + ticket.setReleasedQty(0); + ticket.setUserId(100); + ticket.setStatus(0); + ticket.setDeleted(0); + ticket.setTenantId(10584); + ticket.setCreateTime(now); + ticket.setUpdateTime(now); + userTicketMapper.insert(ticket); + + GltUserTicketRelease rel = new GltUserTicketRelease(); + rel.setUserTicketId(ticket.getId().longValue()); + rel.setUserId(100); + rel.setPeriodNo(1); + rel.setReleaseQty(3); + rel.setReleaseTime(now.minusSeconds(1)); + rel.setStatus(0); + rel.setDeleted(0); + rel.setTenantId(10584); + rel.setCreateTime(now); + rel.setUpdateTime(now); + releaseMapper.insert(rel); + + int releasedCount = autoReleaseService.releaseDue(now, 100); + assertEquals(0, releasedCount); + + GltUserTicket after = userTicketMapper.selectById(ticket.getId()); + assertNotNull(after); + assertEquals(0, after.getAvailableQty()); + assertEquals(2, after.getFrozenQty()); + + GltUserTicketRelease relAfter = releaseMapper.selectById(rel.getId()); + assertNotNull(relAfter); + assertEquals(2, relAfter.getStatus()); + assertEquals(0, logMapper.selectCount(null)); + } +} + diff --git a/src/test/resources/schema-auto-release-h2.sql b/src/test/resources/schema-auto-release-h2.sql new file mode 100644 index 0000000..70748f8 --- /dev/null +++ b/src/test/resources/schema-auto-release-h2.sql @@ -0,0 +1,62 @@ +DROP TABLE IF EXISTS glt_user_ticket_log; +DROP TABLE IF EXISTS glt_user_ticket_release; +DROP TABLE IF EXISTS glt_user_ticket; + +CREATE TABLE glt_user_ticket ( + id INT AUTO_INCREMENT PRIMARY KEY, + template_id INT, + goods_id INT, + order_id INT, + order_no VARCHAR(64), + order_goods_id INT, + total_qty INT, + available_qty INT, + frozen_qty INT, + used_qty INT, + released_qty INT, + user_id INT, + sort_number INT, + comments VARCHAR(255), + status INT, + deleted INT DEFAULT 0, + tenant_id INT, + create_time TIMESTAMP, + update_time TIMESTAMP +); + +CREATE TABLE glt_user_ticket_release ( + id BIGINT AUTO_INCREMENT PRIMARY KEY, + user_ticket_id BIGINT, + user_id INT, + period_no INT, + release_qty INT, + release_time TIMESTAMP, + status INT, + deleted INT DEFAULT 0, + tenant_id INT, + create_time TIMESTAMP, + update_time TIMESTAMP +); + +CREATE TABLE glt_user_ticket_log ( + id INT AUTO_INCREMENT PRIMARY KEY, + user_ticket_id INT, + change_type INT, + change_available INT, + change_frozen INT, + change_used INT, + available_after INT, + frozen_after INT, + used_after INT, + order_id INT, + order_no VARCHAR(64), + user_id INT, + sort_number INT, + comments VARCHAR(255), + status INT, + deleted INT DEFAULT 0, + tenant_id INT, + create_time TIMESTAMP, + update_time TIMESTAMP +); +