feat:预计使用时间

This commit is contained in:
dzc committed 2026-07-29 15:01:16 +08:00
1 parent d96206828e
commit 41fa28775b
15 files changed
+69 -28

No files matched your search

@@ -28,6 +28,7 @@ public class HardCarDto extends HardCarEntity implements BaseIsIncludeTreeInterf
private List<Long> mchIds;
/** 预计使用日期范围。 */
private LocalDateTime[] apptUseDateTimeList;
/**
@@ -45,6 +45,7 @@ public class HardOrderDto extends HardOrderEntity implements BaseIsIncludeTreeIn
private LocalDateTime[] refundTimeList;
/** 预计使用日期范围。 */
private LocalDateTime[] apptUseDateTimeList;
/** 预约用餐日期下限,用于查询今天及之后的未核销预约。 */
@@ -136,9 +136,9 @@ public class HardOrderEntity extends Model<HardOrderEntity> {
private Long apptRuleId;
/**
* 预约使用时间(天)
* 预计使用日期,食堂预约订单取预约目标日期,其他订单取下单当天,精确到天
*/
@Schema(description = "预约使用时间(天)")
@Schema(description = "预计使用日期,食堂预约订单取预约目标日期,其他订单取下单当天,精确到天")
private LocalDate apptUseDate;
/**
@@ -2,6 +2,7 @@ package com.bsd.pjcloud.hard.controller.order;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.bsd.pjcloud.common.api.encrypt.annotation.crypto.ApiCryptoAes;
import com.bsd.pjcloud.common.core.constant.enums.MerchantTypeEnum;
import com.bsd.pjcloud.common.core.util.R;
import com.bsd.pjcloud.common.data.datascope.DataScope;
@@ -46,6 +47,7 @@ public class HardCanteenApptTotalController {
/* ************************************* start app start ************************************* */
@Operation(summary = "App食堂菜品预约统计", description = "App食堂菜品预约统计")
@ApiCryptoAes
@PostMapping("/app/proudct-reserv-total")
public R<Page<HardCanteenProductTotalVo>> appProductReservTotal(@ParameterObject Page page, @RequestBody HardOrderDto dto) {
// 查询商户
@@ -78,7 +78,6 @@ import java.time.LocalDate;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -155,7 +154,7 @@ public class HardOrderController {
@GetMapping("/app/user-appt-list")
public R<List<HardOrderVo>> userApptList(@RequestParam(required = false) List<Long> dinerUserIds) {
HardOrderDto dto = new HardOrderDto();
LocalDate today = LocalDate.now(ZoneId.of("Asia/Shanghai"));
LocalDate today = LocalDate.now();
PjcloudUser user = SecurityUtils.getUser();
dto.setUserIds(ObjectUtil.isEmpty(dinerUserIds)
@@ -163,6 +162,7 @@ public class HardOrderController {
: hardwareOrderService.validateReserveDinerUserIds(user.getId(), dinerUserIds));
dto.setIsFindCarList(true);
dto.setIsFindApptList(true);
dto.setApptIdOrApptRuleIdNotNull(true);
dto.setApptUseDateStart(today.atStartOfDay());
dto.setOrderType(HardOrderTypeEnum.RESERVE.getType());
dto.setOrderStatusCodes(List.of(HardOrderStatusEnum.PAY.getType()));
@@ -33,7 +33,6 @@ 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;
@@ -47,8 +46,6 @@ import java.util.TreeMap;
@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;
@@ -67,7 +64,8 @@ public class ReservationMenuQueryServiceImpl implements ReservationMenuQueryServ
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.setApptIdOrApptRuleIdNotNull(true);
query.setApptUseDateStart(LocalDate.now().atStartOfDay());
query.setIsFindCarList(true);
query.setIsFindApptList(true);
@@ -85,13 +83,14 @@ public class ReservationMenuQueryServiceImpl implements ReservationMenuQueryServ
public Boolean cancel(ReservationMenuCancelDto dto, Long hardId) {
HardOrderEntity order = hardOrderService.getById(dto.getOrderId());
if (order == null) throw new RuntimeException("预约订单不存在");
if (!Objects.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType()) || !Objects.equals(order.getOrderStatus(), HardOrderStatusEnum.PAY.getType())) {
boolean isAppointmentOrder = order.getApptId() != null || order.getApptRuleId() != null;
if (!isAppointmentOrder || !Objects.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType()) || !Objects.equals(order.getOrderStatus(), HardOrderStatusEnum.PAY.getType())) {
throw new RuntimeException("该预约订单当前不可核销");
}
if (!isCancelableRefundStatus(order.getRefundStatus())) {
throw new RuntimeException("该预约订单正在退款或已退款,不能核销");
}
if (order.getApptUseDate() == null || order.getApptUseDate().isBefore(LocalDate.now(BUSINESS_ZONE))) {
if (order.getApptUseDate() == null || order.getApptUseDate().isBefore(LocalDate.now())) {
throw new RuntimeException("该预约订单已失效");
}
@@ -53,6 +53,7 @@ public class VerificationRecordServiceImpl implements VerificationRecordService
HardOrderDto query = new HardOrderDto();
query.setHardId(hard.getId());
query.setOrderType(HardOrderTypeEnum.RESERVE.getType());
query.setApptIdOrApptRuleIdNotNull(true);
query.setOrderStatusCodes(List.of(HardOrderStatusEnum.CANCEL.getType()));
// 活动核销历史上复用了预约订单类型,支付方式范围需明确排除 ACT_CANCEL。
query.setExcludeOrderPayTypeCodes(List.of(HardPayTypeEnum.ACT_CANCEL.getType()));
@@ -39,6 +39,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDate;
import java.time.LocalDateTime;
@@ -102,6 +103,7 @@ public class HardThirdSelfZyServiceImpl implements HardThirdSelfZyService {
.extraPrice(0)
.payPrice(totalPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.walletId(wallet.getId())
.build();
@@ -200,7 +200,8 @@ public class HardAfterSaleServiceImpl extends ServiceImpl<HardAfterSaleMapper, H
}
boolean isCanteenReserveOrder = ObjectUtil.equals(order.getMerchantType(), MerchantTypeEnum.CANTEEN.getType())
&& ObjectUtil.equals(order.getSysType(), HardTypeEnum.CANTEEN.getType())
&& ObjectUtil.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType());
&& ObjectUtil.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType())
&& (order.getApptId() != null || order.getApptRuleId() != null);
if (isCanteenReserveOrder) {
hardOrderService.validateAppMerchantReserveAccess(order.getId(), viewerUserId);
}
@@ -140,6 +140,7 @@ public class HardOnlineCanteenStatsServiceImpl implements HardOnlineCanteenStats
HardOrderDto dto = new HardOrderDto();
dto.setOrderTypeCodes(List.of(HardOrderTypeEnum.RESERVE.getType()));
dto.setMchTypeCodes(List.of(MerchantTypeEnum.CANTEEN.getType()));
dto.setApptIdOrApptRuleIdNotNull(true);
dto.setOrderStatusCodes(HardOrderStatusEnum.getPaySuccessCodes());
dto.setRefundStatusCodes(List.of(HardRefundStatusEnum.NONE.getStatus(), HardRefundStatusEnum.APPLY.getStatus(), HardRefundStatusEnum.REJECT.getStatus()));
dto.setPayTimeList(query.getPayTimeList());
@@ -138,7 +138,6 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@@ -224,12 +223,15 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
if (distinctUserIds.isEmpty()) {
return List.of();
}
LocalDate today = LocalDate.now(ZoneId.of("Asia/Shanghai"));
LocalDate today = LocalDate.now();
Map<Long, Long> countMap = baseMapper.selectList(new LambdaQueryWrapper<HardOrderEntity>()
.select(HardOrderEntity::getUserId)
.in(HardOrderEntity::getUserId, distinctUserIds)
.eq(HardOrderEntity::getOrderType, HardOrderTypeEnum.RESERVE.getType())
.eq(HardOrderEntity::getOrderStatus, HardOrderStatusEnum.PAY.getType())
.and(wrapper -> wrapper.isNotNull(HardOrderEntity::getApptId)
.or()
.isNotNull(HardOrderEntity::getApptRuleId))
.ge(HardOrderEntity::getApptUseDate, today))
.stream()
.collect(Collectors.groupingBy(HardOrderEntity::getUserId, LinkedHashMap::new, Collectors.counting()));
@@ -564,7 +566,8 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
private boolean isCanteenReserveOrder(HardOrderEntity order) {
return Objects.equals(order.getMerchantType(), MerchantTypeEnum.CANTEEN.getType())
&& Objects.equals(order.getSysType(), HardTypeEnum.CANTEEN.getType())
&& Objects.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType());
&& Objects.equals(order.getOrderType(), HardOrderTypeEnum.RESERVE.getType())
&& (order.getApptId() != null || order.getApptRuleId() != null);
}
@@ -663,6 +666,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(extraPrice)
.payPrice(totalPrice + extraPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.build();
if (ObjectUtil.isNotEmpty(sysUser)) {
@@ -754,6 +758,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(extraPrice)
.payPrice(0)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.build();
orderObj.setUserId(-1L);
@@ -861,13 +866,6 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
if (ObjectUtil.isEmpty(parentCar)) {
throw new RuntimeException("购物车不存在");
}
HardApptReservationService.ReservationValidation reservation = null;
if (ObjectUtil.equals(dto.getOrderType(), HardOrderTypeEnum.RESERVE)
&& ObjectUtil.equals(dto.getHardType(), HardTypeEnum.CANTEEN)) {
reservation = hardApptReservationService.validateReservation(
parentCar.getMerchantId(), dto.getApptId(), dto.getApptRuleId(),
dto.getHourType(), dto.getApptDate(), dto.getApptTimeType());
}
Long reserveCount = isHaveCanteenReserve(dto.getUserId());
if (reserveCount > 3) {
throw new RuntimeException("您有" + reserveCount + "笔未核销的预约订单,请先核销");
@@ -917,14 +915,9 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(totalPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.build();
if (reservation != null) {
order.setHourType(reservation.hourType());
order.setApptId(reservation.appt() == null ? null : reservation.appt().getId());
order.setApptRuleId(reservation.apptRuleId());
order.setApptUseDate(reservation.apptDate());
}
if (isPay) {
order.setWalletId(wallet.getId());
}
@@ -1123,6 +1116,9 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.eq(HardOrderEntity::getSysType, HardTypeEnum.CANTEEN.getType())
.eq(HardOrderEntity::getOrderType, HardOrderTypeEnum.RESERVE.getType())
.eq(HardOrderEntity::getOrderStatus, HardOrderStatusEnum.PAY.getType())
.and(wrapper -> wrapper.isNotNull(HardOrderEntity::getApptId)
.or()
.isNotNull(HardOrderEntity::getApptRuleId))
.eq(HardOrderEntity::getApptUseDate, reservation.apptDate())
.eq(HardOrderEntity::getHourType, reservation.hourType()));
if (existingCount > 0) {
@@ -1293,12 +1289,12 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.payPrice(singlePrice)
.walletId(wallet.getId())
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(reservation.apptDate())
.productDesc(subject)
.build();
order.setHourType(reservation.hourType());
order.setApptId(reservation.appt() == null ? null : reservation.appt().getId());
order.setApptRuleId(reservation.apptRuleId());
order.setApptUseDate(reservation.apptDate());
return order;
}
@@ -1470,6 +1466,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(totalPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.deliveryPrice(deliveryPrice)
.productDesc(subject)
.build();
@@ -1670,6 +1667,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(totalPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.walletId(wallet.getId())
.build();
@@ -1745,6 +1743,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(totalPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.walletId(wallet.getId())
.build();
@@ -1829,6 +1828,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(totalPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.addressName(userMapAddress.getFullAddress())
.build();
@@ -1919,6 +1919,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(totalPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.build();
orderObj.setWalletId(wallet.getId());
@@ -2001,6 +2002,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(dto.getPrice())
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.build();
if (ObjectUtil.isNotEmpty(wallet)) {
@@ -2106,6 +2108,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(totalPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.walletId(wallet.getId())
.build();
@@ -2178,6 +2181,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(0)
.payPrice(0)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc("智能柜商品*?")
.build();
baseMapper.insert(orderObj);
@@ -2496,6 +2500,7 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.extraPrice(extraPrice)
.payPrice(totalPrice + extraPrice)
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(orderDesc)
.build();
baseMapper.insert(orderObj);
@@ -2963,6 +2968,9 @@ public class HardOrderServiceImpl extends ServiceImpl<HardOrderMapper, HardOrder
.eq(HardOrderEntity::getSysType, HardTypeEnum.CANTEEN.getType())
.eq(HardOrderEntity::getOrderType, HardOrderTypeEnum.RESERVE.getType())
.eq(HardOrderEntity::getOrderStatus, HardOrderStatusEnum.PAY.getType())
.and(wrapper -> wrapper.isNotNull(HardOrderEntity::getApptId)
.or()
.isNotNull(HardOrderEntity::getApptRuleId))
);
}
@@ -33,6 +33,8 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -197,6 +199,9 @@ public class HardOrderSyncServiceImpl implements HardOrderSyncService {
res.setIsOfflineOrder(YesNoEnum.YES.getCode());
res.setProductDesc(order.getProductDesc());
res.setHourType(order.getHourType());
LocalDateTime orderTime = Optional.ofNullable(order.getCreateTime()).orElse(order.getPayTime());
// 离线订单优先保留设备原始下单日期,旧终端未传时才使用同步当天。
res.setApptUseDate(orderTime == null ? LocalDate.now() : orderTime.toLocalDate());
return res;
}
@@ -47,6 +47,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@@ -150,6 +151,7 @@ public class HardThirdPayServiceImpl implements HardThirdPayService {
.extraPrice(dto.getPrice() - orderTotalPrice)
.payPrice(dto.getPrice())
.isOfflineOrder(YesNoEnum.NO.getCode())
.apptUseDate(LocalDate.now())
.productDesc(subject)
.walletId(wallet.getId())
.build();
@@ -219,6 +219,7 @@
a.merchant_type = '1'
and a.sys_type = '2'
and a.order_type = '2'
and (a.appt_id is not null or a.appt_rule_id is not null)
and (
p.user_id = #{dto.appViewerUserId}
<if test="dto.appWardUserIds != null and dto.appWardUserIds.size() != 0">
@@ -77,6 +77,7 @@ class ReservationMenuQueryServiceImplTest {
assertEquals(200L, query.getMerchantId());
assertEquals(HardOrderTypeEnum.RESERVE.getType(), query.getOrderType());
assertEquals(List.of(HardOrderStatusEnum.PAY.getType()), query.getOrderStatusCodes());
assertTrue(query.getApptIdOrApptRuleIdNotNull());
assertTrue(query.getIsFindCarList());
assertTrue(query.getIsFindApptList());
assertEquals("林*", result.getMaskedName());
@@ -185,6 +186,20 @@ class ReservationMenuQueryServiceImplTest {
verify(hardOrderService).getById(1L);
}
@Test
void cancelRejectsOrderTypeReserveWithoutAppointmentRelation() {
HardOrderEntity order = HardOrderEntity.builder()
.id(1L)
.orderType(HardOrderTypeEnum.RESERVE.getType())
.orderStatus(HardOrderStatusEnum.PAY.getType())
.apptUseDate(LocalDate.now().plusDays(1))
.build();
when(hardOrderService.getById(1L)).thenReturn(order);
assertThrows(RuntimeException.class, () -> service.cancel(cancel(1L)));
verify(hardOrderService).getById(1L);
}
@Test
void cancelUsesOnlyOrderIdAndDelegatesExistingCancellationFlow() {
HardOrderEntity order = HardOrderEntity.builder()
@@ -194,6 +209,7 @@ class ReservationMenuQueryServiceImplTest {
.orderType(HardOrderTypeEnum.RESERVE.getType())
.orderStatus(HardOrderStatusEnum.PAY.getType())
.refundStatus(HardRefundStatusEnum.NONE.getStatus())
.apptId(10L)
.apptUseDate(LocalDate.now().plusDays(1))
.build();
when(hardOrderService.getById(1L)).thenReturn(order);
@@ -215,6 +231,7 @@ class ReservationMenuQueryServiceImplTest {
.orderType(HardOrderTypeEnum.RESERVE.getType())
.orderStatus(HardOrderStatusEnum.PAY.getType())
.refundStatus(HardRefundStatusEnum.APPLY.getStatus())
.apptId(10L)
.apptUseDate(LocalDate.now())
.build();
when(hardOrderService.getById(1L)).thenReturn(order);