fix:打包问题

This commit is contained in:
dzc committed 2026-10-08 14:26:58 +08:00
1 parent 3a416e2686
commit 42ac8786ee
5 files changed
+80 -39

No files matched your search

@@ -37,25 +37,29 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
/**
* 憌笔�霈W�摨枏����瘚贝�嚗𡁏㦤�冽𤣰�?BELOW 霈W�雿輻鍂 {@code canteen_spu} �笔�摨枏��亙藁嚗? * 瘥𤩺𠯫�𡏭停霈W��㕑恥�閧掩�贝楝�勗�瘙𩤃�RESERVE 韏?ONLINE嚗��隞𣇉掩�贝粥 OFFLINE嚗剹�? * <p>
* �湔𦻖靚�鍂鈭𥪜� {@code fastenerInventory} �滩蝸嚗𡁜����頧賜� getSelf() ��閬?Spring 銝𠹺����
* 蝥臬�瘚讠㴓憓��瘜閙�靘𨥈�撘�虜����勗�撅� i18n 憭���刻圾�琜�甇文��芣鱏閮��躰秤���? */
* 食堂订单库存分流测试:机器收银 BELOW 订单使用 {@code canteen_spu} 原子库存接口,
* 每日菜谱订单按订单类型路由分池(RESERVE 走 ONLINE,其他类型走 OFFLINE)。
* <p>
* 直接调用五参 {@code fastenerInventory} 重载:四参重载经 getSelf() 需要 Spring 上下文,
* 纯单测环境无法提供;异常文案由全局 i18n 处理器解析,此处只断言错误码。
*/
class HardOrderServiceImplInventoryTest {
/** 霈W�韐剔�頧行��∴��𣂷��滚𦛚蝡臬𤐄�𣇉�����交��䔶��訫���翰�扼�?*/
/** 订单购物车服务,提供服务端固化的商品来源和下单商品快照。 */
private final HardCarService hardCarService = mock(HardCarService.class);
/** 憌笔��箇��𨅯�餈𦦵��滚𦛚嚗諹�韐�䰻霂X�憡��摮睃僎�扯�撟������?*/
/** 食堂基础菜品远程服务,负责查询权威库存并执行幂等扣减。 */
private final RemoteCanteenSpuService remoteCanteenSpuService = mock(RemoteCanteenSpuService.class);
/** 瘥𤩺𠯫�𡏭停餈𦦵��滚𦛚嚗諹�韐���交�擗鞉挾�亥砭����拐��?*/
/** 每日菜谱远程服务,负责按日期餐段查询分池剩余。 */
private final RemoteDailyMenuService remoteDailyMenuService = mock(RemoteDailyMenuService.class);
/** 鋡急�霈W��滚𦛚嚗䔶��扯��笔�摨枏��寞�嚗��隞碶�韏碶�����祉�瘚贝��?*/
/** 被测订单服务,仅执行真实库存方法,其他依赖不参与本组测试。 */
private final HardOrderServiceImpl service = mock(HardOrderServiceImpl.class, CALLS_REAL_METHODS);
/**
* 瘜典�摨枏���𣈲靘肽�嚗�僎撱箇�鈭见𦛚�峕郊銝𠹺����頝冽��∪�皛朞‘�輻蒈霈啜�? */
* 注入库存分支依赖,并建立事务同步上下文供跨服务回滚补偿登记。
*/
@BeforeEach
void setUp() {
ReflectionTestUtils.setField(service, "hardCarService", hardCarService);
@@ -65,7 +69,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 皜��蝥輻�蝏穃�����∪�甇亙膥嚗屸��滚蔣�滚�蝥輻��扯����蝏剜�霂𨰻�? */
* 清理线程绑定的事务同步器,避免影响同线程执行的后续测试。
*/
@AfterEach
void tearDown() {
if (TransactionSynchronizationManager.isSynchronizationActive()) {
@@ -74,7 +79,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹��箏膥�園𣂎韐凋僭�圈�頞�����摨枏��嗅銁餈𦦵�����齿�蝖株��𧼮����摮䀝�頞喋�? */
* 验证机器收银购买数量超过权威库存时在远程扣减前明确返回商品库存不足。
*/
@Test
void cashierOrderRejectsInsufficientCanteenSpuStock() {
prepareCart(2);
@@ -89,7 +95,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹��箏膥�園𣂎摨枏���雲�嗆�霈W��圈�����箇� SPU �?APPLY 韐笔��譌�? */
* 验证机器收银库存充足时按订单数量生成基础 SPU 的 APPLY 负增量。
*/
@Test
void cashierOrderDeductsCanteenSpuStock() {
prepareCart(2);
@@ -109,7 +116,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹��𡁜����撱箏����摮㗛�璉��芾粉���摨枏�嚗��摮睃�頞單𧒄銝齿��齿緍�譌�? */
* 验证聚合码创建前的库存预检只读权威库存,库存充足时不提前扣减。
*/
@Test
void aggregatePreflightChecksStockWithoutDeduction() {
prepareCart(2);
@@ -123,7 +131,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹��𡁜����撱箏�撠望�蝏嘥歇�亦�摨枏�銝滩雲嚗屸��滨誧蝏剖�蝷箏虾隞䀹狡鈭𣬚輕���? */
* 验证聚合码创建前就拒绝已知的库存不足,避免继续展示可付款二维码。
*/
@Test
void aggregatePreflightRejectsInsufficientStock() {
prepareCart(2);
@@ -138,7 +147,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹��箏膥�園𣂎��甈曆蝙�典睸�𤾸�撟���瑟�憭滚�韐剜㺭�𧶏��滚��噼�銝滢��滚�憓𧼮�摨枏��? */
* 验证机器收银退款使用售后单幂等号恢复原购数量,重复回调不会反复增加库存。
*/
@Test
void cashierRefundRestoresCanteenSpuStockIdempotently() {
prepareCart(2);
@@ -158,7 +168,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹�鈭箏極��甈暸���𧼮恣�豢𧒄�臭蝙�函𡠺蝡衤��∪噡�齿鰵���摨枏�嚗屸��滚𦶢銝剝�甈⊿��甈暹�憭滚�摮条�撟���嗆���? */
* 验证人工退款退回审核时可使用独立业务号重新扣减库存,避免命中首次退款恢复库存的幂等状态。
*/
@Test
void refundReviewRollbackUsesIndependentInventoryBizId() {
prepareCart(2);
@@ -177,7 +188,9 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹�霈曉�韐凋僭�曇楝嚗?hard/hard-api/ad/create-order �?BELOW+CANTEEN_SPU 韐剔�頧佗�撖孵��亥�靚勗銁����? * ����亥�靚?OFFLINE 瘙𩤃�霂瑟�撣?stockChannel=OFFLINE��𠯫�罸�畾萄�蝥蹂��拐�敹怎�嚗䔶��齿緍 canteen_spu.stock�? */
* 验证设备购买链路(/hard/hard-api/ad/create-order 的 BELOW+CANTEEN_SPU 购物车)对当日菜谱在册商品
* 扣每日菜谱 OFFLINE 池:请求带 stockChannel=OFFLINE、日期餐段和线下剩余快照,不再扣 canteen_spu.stock。
*/
@Test
void deviceCreateOrderDeductsDailyMenuOfflinePoolWhenOnMenu() {
prepareCart(1);
@@ -205,7 +218,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹�霈曉�韐凋僭銝滚銁敶𤘪𠯫�𡏭停�����𧒄隞齿緍�箇� canteen_spu.stock嚗朞窈瘙���箏蒂����𡁻��? */
* 验证设备购买不在当日菜谱的商品时仍扣基础 canteen_spu.stock:请求不携带分池通道。
*/
@Test
void deviceCreateOrderDeductsBasicSpuStockWhenNotOnMenu() {
prepareCart(1);
@@ -227,7 +241,9 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹�瘛瑕�韐剔�頧行�������嚗𡁜銁�����緍瘥𤩺𠯫�𡏭停 OFFLINE 瘙𩤃�銝滚銁�����緍�箇� canteen_spu.stock嚗? * 銝斗活撟��靚�鍂�梁鍂�䔶�銝𡁜𦛚�瘀�憌笔�蝡舐𠶖��睸�㗇��㯄�蝳鳴�銝滢�鈭垍㮾�賭葉嚗剹�? */
* 验证混合购物车按商品分流:在册商品扣每日菜谱 OFFLINE 池,不在册商品扣基础 canteen_spu.stock,
* 两次幂等调用共用同一业务号(食堂端状态键按渠道隔离,不会互相命中)。
*/
@Test
void deviceCreateOrderSplitsMixedCartBetweenPools() {
prepareTwoProductCart(1, 2);
@@ -258,8 +274,9 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹�蝥蹂�憸��瘥𤩺𠯫�𡏭停霈W���甈暹�憭?ONLINE 瘙𩤃�銝见�����?online_sold嚗屸��甈曉�憿餉��䔶�瘙𩤃�
* 敹怎��𣇉瑪銝𠰴�雿坔僎�箏蒂�交�擗鞉挾�? */
* 验证线上预定每日菜谱订单退款恢复 ONLINE 池:下单扣的是 online_sold,退款必须还同一池,
* 快照取线上剩余并携带日期餐段。
*/
@Test
void reserveRefundRestoresDailyMenuOnlineStock() {
prepareDailyMenuCart(2);
@@ -285,7 +302,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹��箏膥�園𣂎蝑匧�隞𣇉掩�讠�瘥𤩺𠯫�𡏭停霈W���甈曆��W� OFFLINE 瘙𩤃�敹怎��𣇉瑪銝见�雿踺�? */
* 验证机器收银等其他类型的每日菜谱订单退款仍恢复 OFFLINE 池,快照取线下剩余。
*/
@Test
void cashierDailyMenuRefundRestoresOfflineStock() {
prepareDailyMenuCart(2);
@@ -307,7 +325,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* 撉諹�蝥蹂�憸���滚恣�齿緍�厩瑪銝𠰴�雿蹱嵗撉䕘�蝥蹂�銝滩雲�單�蝏嘅��喃蝙蝥蹂��拐���雲�? */
* 验证线上预定重审重扣按线上剩余校验:线上不足即拒绝,即使线下剩余充足。
*/
@Test
void reserveReoccupyRejectsInsufficientOnlineStock() {
prepareDailyMenuCart(2);
@@ -323,7 +342,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* ����箏膥�園𣂎韐剔�頧行䔉皞𣂼�����圈��? *
* 准备机器收银购物车来源和商品数量。
*
* @param productCount 本次购买份数
*/
private void prepareCart(int productCount) {
@@ -341,7 +361,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* ���瘥𤩺𠯫�𡏭停韐剔�頧行䔉皞琜�cartScene 銝𤾸���䔉皞鞉�霈唬��滚𦛚蝡臭�摮㗛�餉�銝��湛������㺭�譌�? *
* 准备每日菜谱购物车来源(cartScene 与商品来源标记与服务端保存逻辑一致)和商品数量。
*
* @param productCount 本次购买份数
*/
private void prepareDailyMenuCart(int productCount) {
@@ -362,8 +383,11 @@ class HardOrderServiceImplInventoryTest {
}
/**
* ��������揚�抵膠嚗𡁶洵銝�銝芸���虾�箇緵�典��亥�靚梧�蝚砌�銝芯��刻�靚梧��其�瘛瑕����撉諹��? *
* @param firstCount 蝚砌�銝芸���遢�? * @param secondCount 蝚砌�銝芸���遢�? */
* 准备双商品购物车:第一个商品可出现在当日菜谱,第二个不在菜谱,用于混合分流验证。
*
* @param firstCount 第一个商品份数
* @param secondCount 第二个商品份数
*/
private void prepareTwoProductCart(int firstCount, int secondCount) {
HardParentCarEntity parentCar = HardParentCarEntity.builder()
.id(200L)
@@ -384,8 +408,11 @@ class HardOrderServiceImplInventoryTest {
}
/**
* ���䭾�摰𡁶瑪銝?蝥蹂��拐�����亥�靚梯��? *
* @param onlineRemain 蝥蹂�瘙惩�雿? * @param offlineRemain 蝥蹂�瘙惩�雿? * @return �其�����⊿����靚梯�
* 构造指定线上/线下剩余的每日菜谱行。
*
* @param onlineRemain 线上池剩余
* @param offlineRemain 线下池剩余
* @return 用于分池校验的菜谱行
*/
private DailyMenuAppVO dailyMenuRow(int onlineRemain, int offlineRemain) {
DailyMenuAppVO row = new DailyMenuAppVO();
@@ -397,8 +424,10 @@ class HardOrderServiceImplInventoryTest {
}
/**
* ���䭾�摰𡁏�憡��摮条�敶枏�����箇��𨅯��? *
* @param stock �滚𦛚蝡臬��滚虾�桀�摮? * @return �其�摨枏��⊿���抅蝖��𨅯�
* 构造指定权威库存的当前商户基础菜品。
*
* @param stock 服务端当前可售库存
* @return 用于库存校验的基础菜品
*/
private CanteenSpuEntity productWithStock(int stock) {
CanteenSpuEntity product = new CanteenSpuEntity();
@@ -411,7 +440,8 @@ class HardOrderServiceImplInventoryTest {
}
/**
* ���䭾㦤�冽𤣰�嗆�鈭斤�憌笔�蝥蹂�霈W��? *
* 构造机器收银提交的食堂线下订单。
*
* @return 关联固定父购物车和商户的 BELOW 订单
*/
private HardOrderEntity cashierOrder() {
@@ -425,8 +455,10 @@ class HardOrderServiceImplInventoryTest {
}
/**
* ���惩蒂�交�擗鞉挾��挽憭�揚銋啗恥�𤏪�createOrder 隡𡁜��?apptUseDate=隞𠰴予��ourType=霂瑟�擗鞉挾嚗? * �?/hard/hard-api/ad/create-order 韐凋僭瘥𤩺𠯫�𡏭停�嗥��笔�敶X���? *
* @return �唾� CANTEEN_SPU 韐剔�頧艾��𤐄摰𡁏𠯫�罸�畾萄�����?BELOW 霈W�
* 构造带日期餐段的设备购买订单:createOrder 会写入 apptUseDate=今天、hourType=请求餐段,
* 是 /hard/hard-api/ad/create-order 购买每日菜谱时的真实形态。
*
* @return 关联 CANTEEN_SPU 购物车、固定日期餐段和商户的 BELOW 订单
*/
private HardOrderEntity deviceDailyMenuOrder() {
return HardOrderEntity.builder()
@@ -441,8 +473,9 @@ class HardOrderServiceImplInventoryTest {
}
/**
* ���删瑪銝𢠃�摰𡁏�鈭斤�瘥𤩺𠯫�𡏭停霈W��? *
* @return �唾�瘥𤩺𠯫�𡏭停韐剔�頧艾��𤐄摰𡁏𠯫�罸�畾萄�����?RESERVE 霈W�
* 构造线上预定提交的每日菜谱订单。
*
* @return 关联每日菜谱购物车、固定日期餐段和商户的 RESERVE 订单
*/
private HardOrderEntity reserveDailyMenuOrder() {
return HardOrderEntity.builder()
@@ -7,6 +7,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
@@ -66,7 +67,8 @@ public class ShangyouCallbackQueueWorker implements ApplicationRunner {
try {
// BRPOP 多 key:先高优(订单状态)再普通;阻塞期间新到的高优也会被优先弹出
// ListOperations 没有多 key 阻塞弹出,走底层连接命令 bRPop(秒, keys...),返回 [key, value]
String taskId = redisTemplate.execute(connection -> {
// lambda 参数必须显式声明 RedisConnection,否则 execute 在 RedisCallback/SessionCallback 两个重载间产生歧义
String taskId = redisTemplate.execute((RedisConnection connection) -> {
List<byte[]> popped = connection.listCommands().bRPop(5,
ShangyouHotelApi.REDIS_CALLBACK_QUEUE_HIGH.getBytes(StandardCharsets.UTF_8),
ShangyouHotelApi.REDIS_CALLBACK_QUEUE.getBytes(StandardCharsets.UTF_8));
@@ -7,6 +7,7 @@ import com.bsd.pjcloud.admin.api.vo.SysUserFaceVo;
import com.bsd.pjcloud.admin.mapper.SysUserFaceMapper;
import com.bsd.pjcloud.admin.service.SysDeptService;
import com.bsd.pjcloud.admin.service.SysRoleService;
import com.bsd.pjcloud.admin.service.SysUserIdentityService;
import com.bsd.pjcloud.admin.service.SysUserRelationService;
import com.bsd.pjcloud.admin.service.SysUserService;
import com.bsd.pjcloud.admin.utils.flow.FlowUtil;
@@ -49,6 +50,7 @@ class SysUserFaceTerminalDeleteServiceImplTest {
sysDeptService,
mock(SysRoleService.class),
mock(SysUserRelationService.class),
mock(SysUserIdentityService.class),
mock(StringRedisTemplate.class),
mock(Redisson.class),
mock(ApplicationEventPublisher.class),
@@ -9,6 +9,7 @@ import com.bsd.pjcloud.admin.api.vo.SysUserFaceVo;
import com.bsd.pjcloud.admin.mapper.SysUserFaceMapper;
import com.bsd.pjcloud.admin.service.SysDeptService;
import com.bsd.pjcloud.admin.service.SysRoleService;
import com.bsd.pjcloud.admin.service.SysUserIdentityService;
import com.bsd.pjcloud.admin.service.SysUserRelationService;
import com.bsd.pjcloud.admin.service.SysUserService;
import com.bsd.pjcloud.admin.utils.flow.FlowUtil;
@@ -59,6 +60,7 @@ class SysUserFaceTerminalQualityReportServiceImplTest {
sysDeptService,
mock(SysRoleService.class),
mock(SysUserRelationService.class),
mock(SysUserIdentityService.class),
mock(StringRedisTemplate.class),
mock(Redisson.class),
mock(ApplicationEventPublisher.class),
@@ -142,7 +142,8 @@ class SysUserRelationServiceImplTest {
SysUser thirdGuardian = createUser(thirdGuardianUserId, "监护人三");
thirdGuardian.setPhone("13800000001");
when(relationTypeService.list(any())).thenReturn(List.of(createGuardianRelationType()));
when(relationTypeService.list(org.mockito.ArgumentMatchers.<Wrapper<SysUserRelationTypeEntity>>any()))
.thenReturn(List.of(createGuardianRelationType()));
doReturn(List.of(firstRelation, secondRelation, duplicatePhoneRelation))
.when(service).list(org.mockito.ArgumentMatchers.<Wrapper<SysUserRelationEntity>>any());
when(sysUserService.listByIds(any())).thenReturn(List.of(firstGuardian, secondGuardian, thirdGuardian));
@@ -161,7 +162,8 @@ class SysUserRelationServiceImplTest {
SysUserStudentService studentService = mock(SysUserStudentService.class);
SysUserRelationServiceImpl service = spy(new SysUserRelationServiceImpl(
mock(SysUserService.class), relationTypeService, studentService));
when(relationTypeService.list(any())).thenReturn(List.of(createGuardianRelationType()));
when(relationTypeService.list(org.mockito.ArgumentMatchers.<Wrapper<SysUserRelationTypeEntity>>any()))
.thenReturn(List.of(createGuardianRelationType()));
doReturn(List.of()).when(service)
.list(org.mockito.ArgumentMatchers.<Wrapper<SysUserRelationEntity>>any());
@@ -203,7 +205,7 @@ class SysUserRelationServiceImplTest {
assertEquals(99L, relationId);
verify(relationMapper).restoreDeletedRelation(any());
verify(relationMapper, never()).insert(any());
verify(relationMapper, never()).insert(any(SysUserRelationEntity.class));
verify(service).syncStudentGuardianPhones(List.of(SECOND_WARD_USER_ID));
}