酒店
This commit is contained in:
1 parent
e3e2726f91
commit
b4e83d5604
4 files changed
+247
-13
No files matched your search
+15
@@ -108,4 +108,19 @@ public class SmHotelOrderEntity extends Model<SmHotelOrderEntity> {
|
||||
@TableLogic
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String delFlag;
|
||||
|
||||
/** 列表展示:酒店名称(非表字段) */
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "酒店名称")
|
||||
private String hotelName;
|
||||
|
||||
/** 列表展示:下单来源 APP/ADMIN/DOWNSTREAM(非表字段,由 channelNo 推断) */
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "下单来源")
|
||||
private String orderSource;
|
||||
|
||||
/** 列表展示:酒店数据来源 local/shangyou(非表字段) */
|
||||
@TableField(exist = false)
|
||||
@Schema(description = "酒店数据来源")
|
||||
private String hotelDataSource;
|
||||
}
|
||||
+91
-12
@@ -10,6 +10,7 @@ import com.bsd.pjcloud.common.api.encrypt.annotation.crypto.ApiCryptoAes;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.security.service.PjcloudUser;
|
||||
import com.bsd.pjcloud.common.security.util.SecurityUtils;
|
||||
import com.bsd.pjcloud.supermarket.constant.SmHotelDataSource;
|
||||
import com.bsd.pjcloud.supermarket.entity.SmHotelDailyEntity;
|
||||
import com.bsd.pjcloud.supermarket.entity.SmHotelEntity;
|
||||
import com.bsd.pjcloud.supermarket.entity.SmHotelOrderEntity;
|
||||
@@ -62,6 +63,7 @@ public class SmHotelAppController {
|
||||
@GetMapping("/filter-meta")
|
||||
public R<Map<String, Object>> filterMeta() {
|
||||
var online = Wrappers.<SmHotelEntity>lambdaQuery()
|
||||
.eq(SmHotelEntity::getSheetName, SmHotelDataSource.LOCAL)
|
||||
.and(w -> w.isNull(SmHotelEntity::getUpstreamStatus)
|
||||
.or()
|
||||
.ne(SmHotelEntity::getUpstreamStatus, "OFFLINE"))
|
||||
@@ -129,6 +131,8 @@ public class SmHotelAppController {
|
||||
List<Integer> starList = parseIntCsv(starLevels);
|
||||
List<String> facilityList = parseStrCsv(facilityTags);
|
||||
var wrapper = Wrappers.<SmHotelEntity>lambdaQuery()
|
||||
// 移动端 TOC 仅展示本地酒店,不展示上游同步酒店
|
||||
.eq(SmHotelEntity::getSheetName, SmHotelDataSource.LOCAL)
|
||||
.and(w -> w.isNull(SmHotelEntity::getUpstreamStatus)
|
||||
.or()
|
||||
.ne(SmHotelEntity::getUpstreamStatus, "OFFLINE"))
|
||||
@@ -187,7 +191,11 @@ public class SmHotelAppController {
|
||||
if (r.getCode() != 0 || r.getData() == null || r.getData().getHotel() == null) {
|
||||
return r;
|
||||
}
|
||||
if ("OFFLINE".equalsIgnoreCase(r.getData().getHotel().getUpstreamStatus())) {
|
||||
SmHotelEntity hotel = r.getData().getHotel();
|
||||
if (!SmHotelDataSource.isLocal(hotel.getSheetName())) {
|
||||
return R.failed("仅支持预订本地酒店");
|
||||
}
|
||||
if ("OFFLINE".equalsIgnoreCase(hotel.getUpstreamStatus())) {
|
||||
return R.failed("酒店已下架");
|
||||
}
|
||||
return r;
|
||||
@@ -202,6 +210,9 @@ public class SmHotelAppController {
|
||||
if (hotel == null) {
|
||||
return R.failed("酒店不存在");
|
||||
}
|
||||
if (!SmHotelDataSource.isLocal(hotel.getSheetName())) {
|
||||
return R.failed("仅支持预订本地酒店");
|
||||
}
|
||||
if ("OFFLINE".equalsIgnoreCase(hotel.getUpstreamStatus())) {
|
||||
return R.failed("酒店已下架");
|
||||
}
|
||||
@@ -212,13 +223,26 @@ public class SmHotelAppController {
|
||||
@PostMapping("/order/create")
|
||||
public R<JSONObject> createOrder(@RequestBody Map<String, Object> body) {
|
||||
PjcloudUser user = SecurityUtils.getUser();
|
||||
if (user == null) {
|
||||
if (user == null || user.getId() == null) {
|
||||
return R.failed("请先登录");
|
||||
}
|
||||
Map<String, Object> req = body == null ? new HashMap<>() : new HashMap<>(body);
|
||||
if (StrUtil.isBlank(str(req.get("channelNo")))) {
|
||||
req.put("channelNo", "APP" + user.getId() + System.currentTimeMillis());
|
||||
Long hotelId = null;
|
||||
Object hotelIdObj = req.get("hotelId");
|
||||
if (hotelIdObj != null && StrUtil.isNotBlank(String.valueOf(hotelIdObj))) {
|
||||
hotelId = Long.valueOf(String.valueOf(hotelIdObj));
|
||||
}
|
||||
if (hotelId != null) {
|
||||
SmHotelEntity hotel = hotelService.getById(hotelId);
|
||||
if (hotel == null) {
|
||||
return R.failed("酒店不存在");
|
||||
}
|
||||
if (!SmHotelDataSource.isLocal(hotel.getSheetName())) {
|
||||
return R.failed("仅支持预订本地酒店");
|
||||
}
|
||||
}
|
||||
// 渠道单号绑定用户 ID:APP{userId}{ts},列表/详情/取消均按此前缀认主(与用户名无关)
|
||||
req.put("channelNo", "APP" + user.getId() + System.currentTimeMillis());
|
||||
if (StrUtil.isBlank(str(req.get("contactName")))) {
|
||||
req.put("contactName", StrUtil.blankToDefault(user.getName(), user.getUsername()));
|
||||
}
|
||||
@@ -236,22 +260,38 @@ public class SmHotelAppController {
|
||||
if (user == null) {
|
||||
return R.failed("请先登录");
|
||||
}
|
||||
SmHotelOrderEntity query = new SmHotelOrderEntity();
|
||||
query.setOrderStatus(StrUtil.trimToNull(orderStatus));
|
||||
query.setCreateBy(user.getUsername());
|
||||
Page<SmHotelOrderEntity> raw = orderService.pageOrders(page, query);
|
||||
Page<SmHotelOrderEntity> raw = orderService.pageMyAppOrders(page, user, StrUtil.trimToNull(orderStatus));
|
||||
List<Long> hotelIds = raw.getRecords().stream()
|
||||
.map(SmHotelOrderEntity::getHotelId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.toList();
|
||||
Map<Long, String> hotelNameMap = new HashMap<>();
|
||||
Map<Long, String> hotelCoverMap = new HashMap<>();
|
||||
if (!hotelIds.isEmpty()) {
|
||||
List<SmHotelEntity> hotels = hotelService.listByIds(hotelIds);
|
||||
for (SmHotelEntity h : hotels) {
|
||||
hotelNameMap.put(h.getId(), h.getHotelName());
|
||||
hotelCoverMap.put(h.getId(), h.getCoverImage());
|
||||
}
|
||||
}
|
||||
// 补齐房型名
|
||||
Map<String, String> productNameMap = new HashMap<>();
|
||||
for (SmHotelOrderEntity o : raw.getRecords()) {
|
||||
if (o.getHotelId() == null || StrUtil.isBlank(o.getProductCode())) {
|
||||
continue;
|
||||
}
|
||||
String key = o.getHotelId() + "#" + o.getProductCode();
|
||||
if (productNameMap.containsKey(key)) {
|
||||
continue;
|
||||
}
|
||||
SmHotelProductEntity p = Db.lambdaQuery(SmHotelProductEntity.class)
|
||||
.eq(SmHotelProductEntity::getHotelId, o.getHotelId())
|
||||
.eq(SmHotelProductEntity::getProductCode, o.getProductCode())
|
||||
.last("limit 1")
|
||||
.one();
|
||||
productNameMap.put(key, p == null ? null : p.getProductName());
|
||||
}
|
||||
Page<Map<String, Object>> out = new Page<>(raw.getCurrent(), raw.getSize(), raw.getTotal());
|
||||
out.setRecords(raw.getRecords().stream().map(o -> {
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
@@ -261,7 +301,9 @@ public class SmHotelAppController {
|
||||
row.put("hotelId", o.getHotelId());
|
||||
row.put("hotelCode", o.getHotelCode());
|
||||
row.put("hotelName", hotelNameMap.get(o.getHotelId()));
|
||||
row.put("coverImage", hotelCoverMap.get(o.getHotelId()));
|
||||
row.put("productCode", o.getProductCode());
|
||||
row.put("productName", productNameMap.get(o.getHotelId() + "#" + o.getProductCode()));
|
||||
row.put("roomTypeCode", o.getRoomTypeCode());
|
||||
row.put("checkInDate", o.getCheckInDate());
|
||||
row.put("checkOutDate", o.getCheckOutDate());
|
||||
@@ -279,7 +321,7 @@ public class SmHotelAppController {
|
||||
|
||||
@Operation(summary = "我的订单详情")
|
||||
@GetMapping("/order/{id}")
|
||||
public R<SmHotelOrderEntity> orderDetail(@PathVariable Long id) {
|
||||
public R<Map<String, Object>> orderDetail(@PathVariable Long id) {
|
||||
PjcloudUser user = SecurityUtils.getUser();
|
||||
if (user == null) {
|
||||
return R.failed("请先登录");
|
||||
@@ -288,10 +330,47 @@ public class SmHotelAppController {
|
||||
if (order == null) {
|
||||
return R.failed("订单不存在");
|
||||
}
|
||||
if (!user.getUsername().equals(order.getCreateBy())) {
|
||||
if (!orderService.isOwnedByAppUser(order, user)) {
|
||||
return R.failed("无权查看该订单");
|
||||
}
|
||||
return R.ok(order);
|
||||
Map<String, Object> row = new LinkedHashMap<>();
|
||||
row.put("id", order.getId());
|
||||
row.put("channelNo", order.getChannelNo());
|
||||
row.put("platformNo", order.getPlatformNo());
|
||||
row.put("hotelId", order.getHotelId());
|
||||
row.put("hotelCode", order.getHotelCode());
|
||||
row.put("productCode", order.getProductCode());
|
||||
row.put("roomTypeCode", order.getRoomTypeCode());
|
||||
row.put("checkInDate", order.getCheckInDate());
|
||||
row.put("checkOutDate", order.getCheckOutDate());
|
||||
row.put("count", order.getCount());
|
||||
row.put("sellAmount", order.getSellAmount());
|
||||
row.put("orderStatus", order.getOrderStatus());
|
||||
row.put("bookStatus", order.getBookStatus());
|
||||
row.put("contactName", order.getContactName());
|
||||
row.put("contactPhone", order.getContactPhone());
|
||||
row.put("createTime", order.getCreateTime());
|
||||
row.put("failMsg", order.getFailMsg());
|
||||
if (order.getHotelId() != null) {
|
||||
SmHotelEntity hotel = hotelService.getById(order.getHotelId());
|
||||
if (hotel != null) {
|
||||
row.put("hotelName", hotel.getHotelName());
|
||||
row.put("coverImage", hotel.getCoverImage());
|
||||
row.put("address", hotel.getAddress());
|
||||
row.put("phone", hotel.getPhone());
|
||||
}
|
||||
if (StrUtil.isNotBlank(order.getProductCode())) {
|
||||
SmHotelProductEntity p = Db.lambdaQuery(SmHotelProductEntity.class)
|
||||
.eq(SmHotelProductEntity::getHotelId, order.getHotelId())
|
||||
.eq(SmHotelProductEntity::getProductCode, order.getProductCode())
|
||||
.last("limit 1")
|
||||
.one();
|
||||
if (p != null) {
|
||||
row.put("productName", p.getProductName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return R.ok(row);
|
||||
}
|
||||
|
||||
@Operation(summary = "取消我的订单")
|
||||
@@ -305,7 +384,7 @@ public class SmHotelAppController {
|
||||
if (order == null) {
|
||||
return R.failed("订单不存在");
|
||||
}
|
||||
if (!user.getUsername().equals(order.getCreateBy())) {
|
||||
if (!orderService.isOwnedByAppUser(order, user)) {
|
||||
return R.failed("无权取消该订单");
|
||||
}
|
||||
String reason = body == null ? "用户取消" : String.valueOf(body.getOrDefault("reason", "用户取消"));
|
||||
|
||||
+7
@@ -2,6 +2,7 @@ package com.bsd.pjcloud.supermarket.service;
|
||||
|
||||
import cn.hutool.json.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.bsd.pjcloud.common.security.service.PjcloudUser;
|
||||
import com.bsd.pjcloud.supermarket.entity.SmHotelOrderEntity;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
|
||||
@@ -11,6 +12,12 @@ public interface SmHotelOrderService {
|
||||
|
||||
Page<SmHotelOrderEntity> pageOrders(Page<SmHotelOrderEntity> page, SmHotelOrderEntity query);
|
||||
|
||||
/** App「我的订单」:按用户 ID 绑定(channelNo 前缀 APP{userId}) */
|
||||
Page<SmHotelOrderEntity> pageMyAppOrders(Page<SmHotelOrderEntity> page, PjcloudUser user, String orderStatus);
|
||||
|
||||
/** App 订单归属:仅认 APP{userId},不依赖用户名(改名不影响) */
|
||||
boolean isOwnedByAppUser(SmHotelOrderEntity order, PjcloudUser user);
|
||||
|
||||
SmHotelOrderEntity getDetail(Long id);
|
||||
|
||||
/** 下游回传下单 → 可定校验 → 上游创建 → 必要时挂补偿 */
|
||||
|
||||
+134
-1
@@ -19,6 +19,7 @@ import com.bsd.pjcloud.supermarket.service.SmHotelPriceConfigService;
|
||||
import com.bsd.pjcloud.common.core.util.R;
|
||||
import com.bsd.pjcloud.common.data.tenant.TenantBroker;
|
||||
import com.bsd.pjcloud.common.data.tenant.TenantContextHolder;
|
||||
import com.bsd.pjcloud.common.security.service.PjcloudUser;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -28,8 +29,11 @@ import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 中转订单:可定校验 → 上游下单 → 不确定/3028/P 状态补偿(文档 3/5/10 分钟)。
|
||||
@@ -67,7 +71,7 @@ public class SmHotelOrderServiceImpl extends ServiceImpl<SmHotelOrderMapper, SmH
|
||||
|
||||
@Override
|
||||
public Page<SmHotelOrderEntity> pageOrders(Page<SmHotelOrderEntity> page, SmHotelOrderEntity query) {
|
||||
return baseMapper.selectPage(page, Wrappers.<SmHotelOrderEntity>lambdaQuery()
|
||||
Page<SmHotelOrderEntity> result = baseMapper.selectPage(page, Wrappers.<SmHotelOrderEntity>lambdaQuery()
|
||||
.like(StrUtil.isNotBlank(query.getChannelNo()), SmHotelOrderEntity::getChannelNo, query.getChannelNo())
|
||||
.like(StrUtil.isNotBlank(query.getPlatformNo()), SmHotelOrderEntity::getPlatformNo,
|
||||
query.getPlatformNo())
|
||||
@@ -77,8 +81,99 @@ public class SmHotelOrderServiceImpl extends ServiceImpl<SmHotelOrderMapper, SmH
|
||||
.eq(StrUtil.isNotBlank(query.getCompensateStatus()), SmHotelOrderEntity::getCompensateStatus,
|
||||
query.getCompensateStatus())
|
||||
.eq(StrUtil.isNotBlank(query.getHotelCode()), SmHotelOrderEntity::getHotelCode, query.getHotelCode())
|
||||
.like(StrUtil.isNotBlank(query.getContactName()), SmHotelOrderEntity::getContactName,
|
||||
query.getContactName())
|
||||
.like(StrUtil.isNotBlank(query.getContactPhone()), SmHotelOrderEntity::getContactPhone,
|
||||
query.getContactPhone())
|
||||
.eq(StrUtil.isNotBlank(query.getCreateBy()), SmHotelOrderEntity::getCreateBy, query.getCreateBy())
|
||||
.orderByDesc(SmHotelOrderEntity::getCreateTime));
|
||||
// 后台列表补齐酒店名与来源,便于识别 App 下单
|
||||
fillOrderListDisplay(result.getRecords());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<SmHotelOrderEntity> pageMyAppOrders(Page<SmHotelOrderEntity> page, PjcloudUser user,
|
||||
String orderStatus) {
|
||||
if (user == null || user.getId() == null) {
|
||||
return page;
|
||||
}
|
||||
// 归属绑定用户 ID:channelNo = APP{userId}{ts};不按 createBy/用户名/手机号(改名、撞号都不串单)
|
||||
String appChannelPrefix = "APP" + user.getId();
|
||||
Page<SmHotelOrderEntity> result = baseMapper.selectPage(page, Wrappers.<SmHotelOrderEntity>lambdaQuery()
|
||||
.eq(StrUtil.isNotBlank(orderStatus), SmHotelOrderEntity::getOrderStatus, orderStatus)
|
||||
.likeRight(SmHotelOrderEntity::getChannelNo, appChannelPrefix)
|
||||
.orderByDesc(SmHotelOrderEntity::getCreateTime));
|
||||
fillOrderListDisplay(result.getRecords());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOwnedByAppUser(SmHotelOrderEntity order, PjcloudUser user) {
|
||||
if (order == null || user == null || user.getId() == null) {
|
||||
return false;
|
||||
}
|
||||
return StrUtil.startWith(order.getChannelNo(), "APP" + user.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页列表展示字段:酒店名称、数据来源(本地/上游)、channelNo 推断下单来源。
|
||||
*/
|
||||
private void fillOrderListDisplay(List<SmHotelOrderEntity> records) {
|
||||
if (records == null || records.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<Long> hotelIds = records.stream()
|
||||
.map(SmHotelOrderEntity::getHotelId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<Long, SmHotelEntity> hotelById = new HashMap<>();
|
||||
if (!hotelIds.isEmpty()) {
|
||||
for (SmHotelEntity h : hotelMapper.selectByIds(hotelIds)) {
|
||||
hotelById.put(h.getId(), h);
|
||||
}
|
||||
}
|
||||
// hotelId 缺失时按 hotelCode 补名(历史试下单/上游单)
|
||||
List<String> codes = records.stream()
|
||||
.filter(o -> o.getHotelId() == null || !hotelById.containsKey(o.getHotelId()))
|
||||
.map(SmHotelOrderEntity::getHotelCode)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
Map<String, SmHotelEntity> hotelByCode = new HashMap<>();
|
||||
if (!codes.isEmpty()) {
|
||||
List<SmHotelEntity> byCode = hotelMapper.selectList(Wrappers.<SmHotelEntity>lambdaQuery()
|
||||
.in(SmHotelEntity::getHotelCode, codes));
|
||||
for (SmHotelEntity h : byCode) {
|
||||
if (StrUtil.isNotBlank(h.getHotelCode())) {
|
||||
hotelByCode.putIfAbsent(h.getHotelCode(), h);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (SmHotelOrderEntity o : records) {
|
||||
SmHotelEntity hotel = o.getHotelId() != null ? hotelById.get(o.getHotelId()) : null;
|
||||
if (hotel == null && StrUtil.isNotBlank(o.getHotelCode())) {
|
||||
hotel = hotelByCode.get(o.getHotelCode());
|
||||
}
|
||||
if (hotel != null) {
|
||||
o.setHotelName(hotel.getHotelName());
|
||||
o.setHotelDataSource(SmHotelDataSource.isLocal(hotel.getSheetName()) ? "local" : "shangyou");
|
||||
}
|
||||
String channelNo = o.getChannelNo();
|
||||
if (StrUtil.startWithIgnoreCase(channelNo, "APP")) {
|
||||
o.setOrderSource("APP");
|
||||
}
|
||||
else if (StrUtil.startWithIgnoreCase(channelNo, "ADMIN")) {
|
||||
o.setOrderSource("ADMIN");
|
||||
}
|
||||
else if (StrUtil.startWithIgnoreCase(o.getPlatformNo(), "LOCAL")) {
|
||||
o.setOrderSource("LOCAL");
|
||||
}
|
||||
else {
|
||||
o.setOrderSource(StrUtil.isBlank(channelNo) ? "-" : "DOWNSTREAM");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -316,6 +411,14 @@ public class SmHotelOrderServiceImpl extends ServiceImpl<SmHotelOrderMapper, SmH
|
||||
order.setInventoryStatus(SmHotelInventoryStatus.NONE);
|
||||
order.setCompensateRound(0);
|
||||
order.setReqJson(JSONUtil.toJsonStr(body));
|
||||
// 本地酒店:先校验日历库存,避免 insert 后因缺库存整单回滚,App 假成功/后台无单
|
||||
if (localHotel) {
|
||||
String precheck = precheckLocalInventory(product.getId(), checkIn, checkOut, count);
|
||||
if (precheck != null) {
|
||||
return R.failed(precheck);
|
||||
}
|
||||
}
|
||||
|
||||
baseMapper.insert(order);
|
||||
|
||||
if (localHotel) {
|
||||
@@ -354,6 +457,36 @@ public class SmHotelOrderServiceImpl extends ServiceImpl<SmHotelOrderMapper, SmH
|
||||
return R.ok(out, "下单已提交");
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地下单前只读校验日历库存(不占用 sold)。
|
||||
*
|
||||
* @return null=可下;非空=失败原因
|
||||
*/
|
||||
private String precheckLocalInventory(Long productId, LocalDate checkIn, LocalDate checkOut, int rooms) {
|
||||
if (productId == null || checkIn == null || checkOut == null || !checkIn.isBefore(checkOut)) {
|
||||
return "入住/离店日期无效";
|
||||
}
|
||||
int need = rooms < 1 ? 1 : rooms;
|
||||
for (LocalDate d = checkIn; d.isBefore(checkOut); d = d.plusDays(1)) {
|
||||
SmHotelDailyEntity row = dailyMapper.selectOne(Wrappers.<SmHotelDailyEntity>lambdaQuery()
|
||||
.eq(SmHotelDailyEntity::getProductId, productId)
|
||||
.eq(SmHotelDailyEntity::getStayDate, d)
|
||||
.last("limit 1"));
|
||||
if (row == null) {
|
||||
return "本地库存不足:缺少日期 " + d + " 的日历,请先在后台维护本地房价房量";
|
||||
}
|
||||
if (!Integer.valueOf(1).equals(row.getDailyStatus())) {
|
||||
return "本地库存不足:日期 " + d + " 已关房";
|
||||
}
|
||||
int stock = row.getStock() == null ? 0 : row.getStock();
|
||||
int sold = row.getSold() == null ? 0 : row.getSold();
|
||||
if (stock - sold < need) {
|
||||
return "本地库存不足:日期 " + d + " 可售 " + Math.max(0, stock - sold) + ",需要 " + need;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 本地酒店下单:按入住夜 CAS 增加 sold,成功则本地确认,不调上游。
|
||||
*/
|
||||
|
||||
Reference in new issue
Block a user