eat:查询菜单页面主屏+副屏

This commit is contained in:
dzc committed 2026-07-24 17:30:55 +08:00
1 parent cce873b1c6
commit d62c702c8e
8 files changed
+498 -8

No files matched your search

@@ -0,0 +1,9 @@
package com.bsd.pjcloud.hard.api.constant;
/**
* 终端预约菜单查询的身份识别方式。
*/
public enum ReservationRecognitionTypeEnum {
CARD,
FACE
}
@@ -0,0 +1,27 @@
package com.bsd.pjcloud.hard.api.dto.hard;
import com.bsd.pjcloud.hard.api.constant.ReservationRecognitionTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* 终端本人预约菜单查询参数。
*/
@Data
public class ReservationMenuQueryDto {
@NotNull(message = "设备ID不能为空")
@Schema(description = "设备ID", requiredMode = Schema.RequiredMode.REQUIRED)
private Long hardId;
@NotNull(message = "识别方式不能为空")
@Schema(description = "识别方式:CARD饭卡、FACE人脸", requiredMode = Schema.RequiredMode.REQUIRED)
private ReservationRecognitionTypeEnum recognitionType;
@Schema(description = "饭卡卡号,CARD识别时必填")
private String cardNumber;
@Schema(description = "人脸插件识别出的用户ID,FACE识别时必填")
private Long faceUserId;
}
@@ -0,0 +1,43 @@
package com.bsd.pjcloud.hard.api.vo.android;
import lombok.Data;
import java.time.LocalDate;
import java.util.List;
/**
* 终端本人预约菜单查询结果,仅包含主副屏展示所需的脱敏信息。
*/
@Data
public class ReservationMenuQueryVo {
private String maskedName;
private String deptName;
private String merchantName;
private Integer totalDayCount;
private Integer totalMealCount;
private List<Day> days;
@Data
public static class Day {
private LocalDate date;
private List<Meal> meals;
}
@Data
public static class Meal {
private String hourType;
private String mealTitle;
private List<String> items;
}
}
@@ -16,6 +16,7 @@ import com.bsd.pjcloud.hard.api.dto.order.HardCreateCarDto;
import com.bsd.pjcloud.hard.api.vo.HardInvoiceVo;
import com.bsd.pjcloud.hard.api.vo.manager.HardManagerVo;
import com.bsd.pjcloud.hard.api.vo.android.HardAdUserVo;
import com.bsd.pjcloud.hard.api.vo.android.ReservationMenuQueryVo;
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
import com.bsd.pjcloud.hard.api.vo.order.HardCreateHardQrCodeScanOrderVo;
import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo;
@@ -47,6 +48,7 @@ public class HardApiController {
private final HardOrderSyncService hardOrderSyncService;
private final HardApiService hardApiService;
private final HardOrderTotalService hardOrderTotalService;
private final ReservationMenuQueryService reservationMenuQueryService;
@PostMapping("/bind")
@Operation(summary = "绑定服务端设备")
@@ -170,6 +172,12 @@ public class HardApiController {
return R.ok(hardApiService.getUserByCard(card));
}
@PostMapping("/reservation-menu/query")
@Operation(summary = "查询终端当前识别用户的预约菜单")
public R<ReservationMenuQueryVo> queryReservationMenu(@Valid @RequestBody ReservationMenuQueryDto dto) {
return R.ok(reservationMenuQueryService.query(dto));
}
@GetMapping("/chart-latitude")
@Operation(summary = "统计每天、每周、每月、每年的交易人数和次数")
public R<HardChartLatitudeVo> chartLatitude(@RequestParam Long merchantId) {
@@ -0,0 +1,12 @@
package com.bsd.pjcloud.hard.service;
import com.bsd.pjcloud.hard.api.dto.hard.ReservationMenuQueryDto;
import com.bsd.pjcloud.hard.api.vo.android.ReservationMenuQueryVo;
/**
* 终端本人预约菜单查询服务。
*/
public interface ReservationMenuQueryService {
ReservationMenuQueryVo query(ReservationMenuQueryDto dto);
}
@@ -0,0 +1,208 @@
package com.bsd.pjcloud.hard.service.impl;
import cn.hutool.core.util.StrUtil;
import com.bsd.pjcloud.admin.api.dto.UserInfo;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.entity.SysUser;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.hard.api.constant.ReservationRecognitionTypeEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardHourTypeEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum;
import com.bsd.pjcloud.hard.api.constant.refund.HardRefundStatusEnum;
import com.bsd.pjcloud.hard.api.dto.hard.ReservationMenuQueryDto;
import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto;
import com.bsd.pjcloud.hard.api.entity.manager.HardManagerEntity;
import com.bsd.pjcloud.hard.api.vo.android.HardAdUserVo;
import com.bsd.pjcloud.hard.api.vo.android.ReservationMenuQueryVo;
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo;
import com.bsd.pjcloud.hard.service.HardApiService;
import com.bsd.pjcloud.hard.service.HardManagerService;
import com.bsd.pjcloud.hard.service.HardOrderService;
import com.bsd.pjcloud.hard.service.ReservationMenuQueryService;
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
@Service
@RequiredArgsConstructor
public class ReservationMenuQueryServiceImpl implements ReservationMenuQueryService {
private static final ZoneId BUSINESS_ZONE = ZoneId.of("Asia/Shanghai");
private final HardManagerService hardManagerService;
private final HardApiService hardApiService;
private final HardOrderService hardOrderService;
private final RemoteUserService remoteUserService;
private final RemoteDeptService remoteDeptService;
private final RemoteMchService remoteMchService;
@Override
public ReservationMenuQueryVo query(ReservationMenuQueryDto dto) {
TerminalMerchant terminalMerchant = resolveTerminalMerchant(dto.getHardId());
RecognizedUser recognizedUser = recognizeUser(dto);
HardOrderDto query = new HardOrderDto();
query.setUserId(recognizedUser.userId());
query.setMerchantId(terminalMerchant.merchant().getId());
query.setOrderType(HardOrderTypeEnum.RESERVE.getType());
query.setOrderStatusCodes(List.of(HardOrderStatusEnum.PAY.getType()));
query.setRefundStatusCodes(List.of(HardRefundStatusEnum.NONE.getStatus(), HardRefundStatusEnum.REJECT.getStatus()));
query.setApptUseDateStart(LocalDate.now(BUSINESS_ZONE).atStartOfDay());
query.setIsFindCarList(true);
query.setIsFindApptList(true);
// 身份与商户条件只在服务端生成,终端无法借此接口查询其他用户或其他食堂。
List<HardOrderVo> orders = hardOrderService.scopeList(query, null);
return aggregate(recognizedUser, terminalMerchant, orders);
}
private TerminalMerchant resolveTerminalMerchant(Long hardId) {
HardManagerEntity hard = hardManagerService.getById(hardId);
if (hard == null) {
throw new RuntimeException("设备不存在或无权访问");
}
if (hard.getMerchantId() == null) {
throw new RuntimeException("设备未绑定食堂");
}
R<MchManageVo> merchantResult = remoteMchService.getById(hard.getMerchantId());
MchManageVo merchant = requireData(merchantResult, "查询设备绑定食堂失败");
if (!Objects.equals(merchant.getTypes(), MerchantTypeEnum.CANTEEN.getType())) {
throw new RuntimeException("设备未绑定有效食堂");
}
return new TerminalMerchant(merchant);
}
private RecognizedUser recognizeUser(ReservationMenuQueryDto dto) {
if (dto.getRecognitionType() == ReservationRecognitionTypeEnum.CARD) {
if (StrUtil.isBlank(dto.getCardNumber())) {
throw new RuntimeException("饭卡卡号不能为空");
}
HardAdUserVo user = hardApiService.getUserByCard(dto.getCardNumber().trim());
if (user == null || user.getUserId() == null) {
throw new RuntimeException("未识别到有效饭卡用户");
}
return new RecognizedUser(user.getUserId(), user.getUsername(), user.getDeptId());
}
if (dto.getFaceUserId() == null) {
throw new RuntimeException("人脸用户ID不能为空");
}
UserInfo userInfo = requireData(remoteUserService.getInnerByUserId(dto.getFaceUserId()), "未识别到有效人脸用户");
SysUser user = userInfo.getSysUser();
if (user == null || user.getUserId() == null) {
throw new RuntimeException("未识别到有效人脸用户");
}
return new RecognizedUser(user.getUserId(), user.getName(), user.getDeptId());
}
private ReservationMenuQueryVo aggregate(RecognizedUser user, TerminalMerchant terminalMerchant, List<HardOrderVo> sourceOrders) {
List<HardOrderVo> orders = (sourceOrders == null ? List.<HardOrderVo>of() : sourceOrders).stream()
.filter(order -> order != null && order.getApptUseDate() != null && StrUtil.isNotBlank(resolveHourType(order)))
.sorted(Comparator.comparing(HardOrderVo::getApptUseDate)
.thenComparing(ReservationMenuQueryServiceImpl::resolveHourType)
.thenComparing(HardOrderVo::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()))
.thenComparing(HardOrderVo::getId, Comparator.nullsLast(Comparator.naturalOrder())))
.toList();
Map<LocalDate, LinkedHashMap<String, MealAccumulator>> grouped = new TreeMap<>();
for (HardOrderVo order : orders) {
String hourType = resolveHourType(order);
LinkedHashMap<String, MealAccumulator> meals = grouped.computeIfAbsent(order.getApptUseDate(), ignored -> new LinkedHashMap<>());
MealAccumulator meal = meals.computeIfAbsent(hourType, ignored -> new MealAccumulator(hourType, resolveMealTitle(order, hourType)));
if (order.getCarList() == null) continue;
for (HardCarVo car : order.getCarList()) {
if (car != null && StrUtil.isNotBlank(car.getProductName())) {
meal.items().add(car.getProductName().trim());
}
}
}
List<ReservationMenuQueryVo.Day> days = new ArrayList<>();
int totalMealCount = 0;
for (Map.Entry<LocalDate, LinkedHashMap<String, MealAccumulator>> dayEntry : grouped.entrySet()) {
ReservationMenuQueryVo.Day day = new ReservationMenuQueryVo.Day();
day.setDate(dayEntry.getKey());
List<ReservationMenuQueryVo.Meal> meals = dayEntry.getValue().values().stream().map(ReservationMenuQueryServiceImpl::toMeal).toList();
day.setMeals(meals);
totalMealCount += meals.size();
days.add(day);
}
ReservationMenuQueryVo result = new ReservationMenuQueryVo();
result.setMaskedName(maskName(user.name()));
result.setDeptName(resolveDeptName(user.deptId()));
result.setMerchantName(terminalMerchant.merchant().getName());
result.setTotalDayCount(days.size());
result.setTotalMealCount(totalMealCount);
result.setDays(days);
return result;
}
private static ReservationMenuQueryVo.Meal toMeal(MealAccumulator source) {
ReservationMenuQueryVo.Meal meal = new ReservationMenuQueryVo.Meal();
meal.setHourType(source.hourType());
meal.setMealTitle(source.mealTitle());
meal.setItems(new ArrayList<>(source.items()));
return meal;
}
private static String resolveHourType(HardOrderVo order) {
return StrUtil.blankToDefault(order.getHourType(), order.getApptHourType());
}
private static String resolveMealTitle(HardOrderVo order, String hourType) {
HardHourTypeEnum type = HardHourTypeEnum.valueOfByType(hourType);
if (type != null) return type.getDescription();
return StrUtil.blankToDefault(order.getApptTitle(), "餐段");
}
private static String maskName(String name) {
if (StrUtil.isBlank(name)) return "*";
String normalized = name.trim();
return normalized.length() == 1 ? "*" : normalized.substring(0, 1) + "*";
}
private static <T> T requireData(R<T> result, String message) {
if (result == null || !result.isOk() || result.getData() == null) {
throw new RuntimeException(message);
}
return result.getData();
}
private String resolveDeptName(Long deptId) {
if (deptId == null) return null;
R<SysDept> result = remoteDeptService.getDeptByDeptId(deptId);
if (result == null || !result.isOk() || result.getData() == null) return null;
return result.getData().getName();
}
record RecognizedUser(Long userId, String name, Long deptId) {
}
record TerminalMerchant(MchManageVo merchant) {
}
private record MealAccumulator(String hourType, String mealTitle, LinkedHashSet<String> items) {
private MealAccumulator(String hourType, String mealTitle) {
this(hourType, mealTitle, new LinkedHashSet<>());
}
}
}
@@ -402,13 +402,13 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
for (HardOrderVo order : orders) {
Long payerUserId = resolvePayerUserId(order);
boolean isDiner = Objects.equals(order.getUserId(), viewerUserId);
// 目前允许家长查看核销二维码
isDiner = true;
boolean isPayer = Objects.equals(payerUserId, viewerUserId);
order.setPayerUserId(payerUserId);
boolean isCanteenReserve = isCanteenReserveOrder(order);
order.setIsProxyOrder(isCanteenReserve && payerUserId != null
&& !Objects.equals(payerUserId, order.getUserId()));
// These flags are meaningful only for the newly supported canteen reservation flow.
// Preserve the old App behavior for supermarket, farmer, and delivery orders.
order.setIsProxyOrder(isCanteenReserve && payerUserId != null && !Objects.equals(payerUserId, order.getUserId()));
// 这些权限标记仅适用于新支持的食堂预约流程,商城、共富商城和配送订单继续保持原有 App 行为。
order.setCanRefund(isCanteenReserve ? isPayer : null);
order.setCanViewReserveCode(isCanteenReserve ? isDiner : null);
if (!isDiner) {
@@ -505,8 +505,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
return order == null ? null : order.getUserId();
}
HardParentCarEntity parentCar = hardParentCarService.getById(order.getParentCarId());
// Legacy orders may not have a parent cart. For those records wallet ownership
// remains the only reliable payer signal and must not be changed by this feature.
// 历史订单可能没有父购物车,此时钱包归属仍是唯一可靠的付款人判断依据,本功能不得改变该规则。
return parentCar == null ? order.getUserId() : parentCar.getUserId();
}
@@ -1279,8 +1278,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
log.error("|{}|多人订餐钱包补偿失败,orderId:|{}|", TAG, order.getId(), compensationException);
}
}
// Any cloned carts are in the same local transaction and are rolled back with the
// orders. The original cart is intentionally not deleted so a failed batch can be retried.
// 克隆购物车与订单处于同一本地事务中,会随订单一并回滚;原购物车刻意保留,便于整批失败后重试。
}
/**
@@ -0,0 +1,185 @@
package com.bsd.pjcloud.hard.service.impl;
import com.bsd.pjcloud.admin.api.dto.UserInfo;
import com.bsd.pjcloud.admin.api.entity.SysDept;
import com.bsd.pjcloud.admin.api.entity.SysUser;
import com.bsd.pjcloud.admin.api.feign.RemoteDeptService;
import com.bsd.pjcloud.admin.api.feign.RemoteUserService;
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.hard.api.constant.ReservationRecognitionTypeEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderStatusEnum;
import com.bsd.pjcloud.hard.api.constant.order.HardOrderTypeEnum;
import com.bsd.pjcloud.hard.api.dto.hard.ReservationMenuQueryDto;
import com.bsd.pjcloud.hard.api.dto.order.HardOrderDto;
import com.bsd.pjcloud.hard.api.entity.manager.HardManagerEntity;
import com.bsd.pjcloud.hard.api.vo.android.HardAdUserVo;
import com.bsd.pjcloud.hard.api.vo.android.ReservationMenuQueryVo;
import com.bsd.pjcloud.hard.api.vo.order.HardCarVo;
import com.bsd.pjcloud.hard.api.vo.order.HardOrderVo;
import com.bsd.pjcloud.hard.service.HardApiService;
import com.bsd.pjcloud.hard.service.HardManagerService;
import com.bsd.pjcloud.hard.service.HardOrderService;
import com.bsd.pjcloud.wallet.api.feign.RemoteMchService;
import com.bsd.pjcloud.wallet.api.vo.MchManageVo;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
class ReservationMenuQueryServiceImplTest {
private final HardManagerService hardManagerService = mock(HardManagerService.class);
private final HardApiService hardApiService = mock(HardApiService.class);
private final HardOrderService hardOrderService = mock(HardOrderService.class);
private final RemoteUserService remoteUserService = mock(RemoteUserService.class);
private final RemoteDeptService remoteDeptService = mock(RemoteDeptService.class);
private final RemoteMchService remoteMchService = mock(RemoteMchService.class);
private final ReservationMenuQueryServiceImpl service = new ReservationMenuQueryServiceImpl(
hardManagerService, hardApiService, hardOrderService, remoteUserService, remoteDeptService, remoteMchService);
@Test
void cardQueryUsesTerminalMerchantAndSelfOnlyFilters() {
stubTerminal(100L, 200L, "第一食堂");
HardAdUserVo cardUser = new HardAdUserVo();
cardUser.setUserId(300L);
cardUser.setUsername("林小明");
cardUser.setDeptId(400L);
when(hardApiService.getUserByCard("CARD-001")).thenReturn(cardUser);
stubDept(400L, "二年级3班");
when(hardOrderService.scopeList(any(), isNull())).thenReturn(List.of());
ReservationMenuQueryVo result = service.query(cardQuery(100L, " CARD-001 "));
ArgumentCaptor<HardOrderDto> queryCaptor = ArgumentCaptor.forClass(HardOrderDto.class);
verify(hardOrderService).scopeList(queryCaptor.capture(), isNull());
HardOrderDto query = queryCaptor.getValue();
assertEquals(300L, query.getUserId());
assertEquals(200L, query.getMerchantId());
assertEquals(HardOrderTypeEnum.RESERVE.getType(), query.getOrderType());
assertEquals(List.of(HardOrderStatusEnum.PAY.getType()), query.getOrderStatusCodes());
assertTrue(query.getIsFindCarList());
assertTrue(query.getIsFindApptList());
assertEquals("林*", result.getMaskedName());
assertEquals("二年级3班", result.getDeptName());
assertEquals("第一食堂", result.getMerchantName());
assertEquals(0, result.getTotalDayCount());
}
@Test
void faceQueryRequiresExistingUser() {
stubTerminal(100L, 200L, "第一食堂");
when(remoteUserService.getInnerByUserId(300L)).thenReturn(R.ok(null));
ReservationMenuQueryDto query = new ReservationMenuQueryDto();
query.setHardId(100L);
query.setRecognitionType(ReservationRecognitionTypeEnum.FACE);
query.setFaceUserId(300L);
assertThrows(RuntimeException.class, () -> service.query(query));
verifyNoMoreInteractions(hardOrderService);
}
@Test
void mealsAreMergedByDateAndSegmentWithStableItemDeduplication() {
stubTerminal(100L, 200L, "第一食堂");
stubFaceUser(300L, "王小华", 400L);
stubDept(400L, "三年级1班");
when(hardOrderService.scopeList(any(), isNull())).thenReturn(List.of(
order(2L, LocalDate.of(2026, 7, 25), "1", "早餐预约", LocalDateTime.of(2026, 7, 20, 9, 0), "牛奶", "鸡蛋"),
order(1L, LocalDate.of(2026, 7, 24), "2", "午餐预约", LocalDateTime.of(2026, 7, 20, 8, 0), "米饭", "青菜"),
order(3L, LocalDate.of(2026, 7, 24), "2", "午餐预约", LocalDateTime.of(2026, 7, 20, 10, 0), "青菜", "红烧肉")));
ReservationMenuQueryVo result = service.query(faceQuery(100L, 300L));
assertEquals(2, result.getTotalDayCount());
assertEquals(2, result.getTotalMealCount());
assertEquals(LocalDate.of(2026, 7, 24), result.getDays().get(0).getDate());
assertEquals("2", result.getDays().get(0).getMeals().get(0).getHourType());
assertEquals("午餐", result.getDays().get(0).getMeals().get(0).getMealTitle());
assertEquals(List.of("米饭", "青菜", "红烧肉"), result.getDays().get(0).getMeals().get(0).getItems());
}
@Test
void invalidTerminalBindingIsRejectedBeforeIdentityLookup() {
HardManagerEntity hard = new HardManagerEntity();
hard.setId(100L);
when(hardManagerService.getById(100L)).thenReturn(hard);
assertThrows(RuntimeException.class, () -> service.query(cardQuery(100L, "CARD-001")));
verifyNoMoreInteractions(hardApiService, hardOrderService);
}
private void stubTerminal(Long hardId, Long merchantId, String merchantName) {
HardManagerEntity hard = new HardManagerEntity();
hard.setId(hardId);
hard.setMerchantId(merchantId);
when(hardManagerService.getById(hardId)).thenReturn(hard);
MchManageVo merchant = new MchManageVo();
merchant.setId(merchantId);
merchant.setName(merchantName);
merchant.setTypes(MerchantTypeEnum.CANTEEN.getType());
when(remoteMchService.getById(merchantId)).thenReturn(R.ok(merchant));
}
private void stubFaceUser(Long userId, String name, Long deptId) {
SysUser user = new SysUser();
user.setUserId(userId);
user.setName(name);
user.setDeptId(deptId);
UserInfo userInfo = new UserInfo();
userInfo.setSysUser(user);
when(remoteUserService.getInnerByUserId(userId)).thenReturn(R.ok(userInfo));
}
private void stubDept(Long deptId, String deptName) {
SysDept dept = new SysDept();
dept.setDeptId(deptId);
dept.setName(deptName);
when(remoteDeptService.getDeptByDeptId(deptId)).thenReturn(R.ok(dept));
}
private static ReservationMenuQueryDto cardQuery(Long hardId, String cardNumber) {
ReservationMenuQueryDto query = new ReservationMenuQueryDto();
query.setHardId(hardId);
query.setRecognitionType(ReservationRecognitionTypeEnum.CARD);
query.setCardNumber(cardNumber);
return query;
}
private static ReservationMenuQueryDto faceQuery(Long hardId, Long userId) {
ReservationMenuQueryDto query = new ReservationMenuQueryDto();
query.setHardId(hardId);
query.setRecognitionType(ReservationRecognitionTypeEnum.FACE);
query.setFaceUserId(userId);
return query;
}
private static HardOrderVo order(Long id, LocalDate date, String hourType, String title, LocalDateTime createTime, String... items) {
HardOrderVo order = new HardOrderVo();
order.setId(id);
order.setApptUseDate(date);
order.setHourType(hourType);
order.setApptTitle(title);
order.setCreateTime(createTime);
order.setCarList(java.util.Arrays.stream(items).map(ReservationMenuQueryServiceImplTest::car).toList());
return order;
}
private static HardCarVo car(String productName) {
HardCarVo car = new HardCarVo();
car.setProductName(productName);
return car;
}
}