zhuyifan

菜品售卖量接口

Showing 21 changed files with 519 additions and 23 deletions
package com.infoloop.tianting.controller;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.infoloop.tianting.annotation.RepeatSubmit;
import com.infoloop.tianting.model.dto.OrderDbDTO;
import com.infoloop.tianting.model.dto.OrderDbDTO.BatchUpdateOrderDetailResponse;
import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto;
......@@ -67,6 +68,7 @@ public class OrderController {
@ApiOperation(value = "创建订单")
@PostMapping("/orders")
@ResponseStatus(HttpStatus.OK)
@RepeatSubmit(prefix = "createOrder")
public CreateOrderResponse createOrder(@Valid @RequestBody CreateOrderDto createOrderDto) {
return orderService.createOrder(createOrderDto);
}
......@@ -74,12 +76,11 @@ public class OrderController {
@ApiOperation(value = "院区端创建订单")
@PostMapping("/operator/orders")
@ResponseStatus(HttpStatus.OK)
public CreateOrderResponse createOrderByOperator(
@Valid @RequestBody OrderDbDTO.OperatorCreateOrderDto createOrderDto) {
@RepeatSubmit(prefix = "createOrder")
public CreateOrderResponse createOrderByOperator(@Valid @RequestBody OrderDbDTO.OperatorCreateOrderDto createOrderDto) {
return orderService.orderCreation(createOrderDto);
}
// @SaIgnore
@ApiOperation(value = "修改订单")
@PatchMapping("/orders/modification")
@ResponseStatus(HttpStatus.OK)
......@@ -87,12 +88,10 @@ public class OrderController {
return orderService.updateOrder(updateOrderDto);
}
// @SaIgnore
@ApiOperation(value = "批量修改订单详情")
@PatchMapping("/order_details/modification")
@ResponseStatus(HttpStatus.OK)
public BatchUpdateOrderDetailResponse batchUpdateOrderDetails(
@Valid @RequestBody OrderDbDTO.OrderDetailBatchUpdateDto updateDto) {
public BatchUpdateOrderDetailResponse batchUpdateOrderDetails(@Valid @RequestBody OrderDbDTO.OrderDetailBatchUpdateDto updateDto) {
return orderService.batchUpdateOrderDetails(updateDto);
}
......
......@@ -8,7 +8,6 @@ import com.infoloop.tianting.model.dto.SkuSellQuantityDTO;
import com.infoloop.tianting.model.vo.SkuSellQuantityStatisticsVO;
import com.infoloop.tianting.model.vo.SkuSellQuantityVO;
import com.infoloop.tianting.service.SkuService;
import com.infoloop.tianting.utils.PageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
......@@ -25,7 +24,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.Collections;
import java.util.List;
@Api(tags = "sku")
......@@ -41,7 +39,7 @@ public class SkuController {
@ApiOperation(value = "根据sku ids获取")
@PostMapping("/skus")
@ResponseStatus(HttpStatus.OK)
public List<SkuDto> getOrderByCustomerId(@Valid @RequestBody SkuIdsDto skuIdsDto) {
public List<SkuDto> getSkusByIds(@Valid @RequestBody SkuIdsDto skuIdsDto) {
return skuService.getSkusByIds(skuIdsDto.getIds());
}
......@@ -49,29 +47,28 @@ public class SkuController {
@GetMapping("/stall/{stallId}/skusellquantities/statistics")
@ResponseStatus(HttpStatus.OK)
public SkuSellQuantityStatisticsVO querySkuSellQuantityStatistics(@PathVariable("stallId") int stallId) {
return SkuSellQuantityStatisticsVO.builder().build();
return skuService.querySkuSellQuantityStatistics(stallId);
}
@ApiOperation(value = "分页查询菜品售卖量")
@PostMapping("/skusellquantities/query")
@ResponseStatus(HttpStatus.OK)
public PageResult<SkuSellQuantityVO> querySkuSellQuantity(@Valid @RequestBody SkuSellQuantityDTO.QuerySkuSellQuantityDTO querySkuSellQuantityDTO) {
SkuSellQuantityVO skuSellQuantityVO = SkuSellQuantityVO.builder().build();
return PageUtil.buildEmpty(skuSellQuantityVO);
return skuService.querySkuSellQuantity(querySkuSellQuantityDTO);
}
@ApiOperation(value = "批量设置菜品售卖量")
@PutMapping("/stall/{stallId}/skusellquantities/batchset")
@ResponseStatus(HttpStatus.CREATED)
public void batchSetSkuSellQuantity(@PathVariable("stallId") int stallId,
@Valid @RequestBody SkuSellQuantityDTO.BatchSetSkuSellQuantityDTO batchSetSkuSellQuantityDTO) {
public boolean batchSetSkuSellQuantity(@PathVariable("stallId") int stallId,
@Valid @RequestBody SkuSellQuantityDTO.BatchSetSkuSellQuantityDTO batchSetSkuSellQuantityDTO) {
return skuService.batchSetSkuSellQuantity(stallId, batchSetSkuSellQuantityDTO);
}
@ApiOperation(value = "根据菜品ids批量查询菜品售卖量")
@PostMapping("/skusellquantities/querybyskuids")
@ResponseStatus(HttpStatus.OK)
public List<SkuSellQuantityVO> querySkuSellQuantityBySkuIds(@Valid @RequestBody SkuSellQuantityDTO.QuerySkuSellQuantityBySkuIdsDTO querySkuSellQuantityBySkuIdsDTO) {
return Collections.emptyList();
return skuService.querySkuSellQuantityBySkuIds(querySkuSellQuantityBySkuIdsDTO);
}
}
......
......@@ -29,6 +29,10 @@ public enum ErrorCodeEnum implements BaseEnum {
ORDER_COUNT_LIMIT(406000005, "已超过该餐单预定次数"),
QUERY_CLIENT_CUSTOMER_ERROR(406000006, "获取当日在住客户失败"),
SKUS_SOLD_OUT_TODAY(406000007, "下单菜品今日售罄"),
ORDER_CANCEL(406000008, "订单已自动取消")
;
private final int code;
......
package com.infoloop.tianting.logic.delay;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RedissonClient;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Slf4j
public class DelayTaskQueueExecutor<T> {
private final RedissonClient redissonClient;
private final RBlockingQueue<T> blockingDeque;
private final Processor<T> processor;
private final ExecutorService executorService;
private volatile boolean running = true;
public interface Processor<T> {
void process(T task) throws InterruptedException;
}
public DelayTaskQueueExecutor(String threadName, RedissonClient redissonClient, RBlockingQueue<T> blockingDeque, Processor<T> processor) {
this.redissonClient = redissonClient;
this.blockingDeque = blockingDeque;
this.processor = processor;
this.executorService = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setName(threadName);
return t;
});
this.executorService.submit(this::looper);
}
public void looper() {
while (running) {
try {
if (redissonClient.isShutdown()) {
shutdown();
return;
}
T task = blockingDeque.take();
processor.process(task);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
} catch (Exception e) {
log.error("Task processing error in thread: {}", Thread.currentThread().getName(), e);
}
}
}
public void shutdown() {
running = false;
executorService.shutdown();
try {
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
log.warn("Executor did not terminate in the specified time.");
executorService.shutdownNow();
}
} catch (InterruptedException e) {
log.error("Shutdown interrupted", e);
executorService.shutdownNow();
Thread.currentThread().interrupt();
}
}
}
package com.infoloop.tianting.logic.delay;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
@Slf4j
@Service
@RequiredArgsConstructor
public class DelayedQueue<T> {
private final RedissonClient redissonClient;
private final Map<String, RDelayedQueue<T>> delayedQueues = new ConcurrentHashMap<>();
/**
* 初始化队列,传入队列名称和处理逻辑
*/
public void initQueue(String queueName, Consumer<T> processMessage) {
RBlockingQueue<T> blockingQueue = redissonClient.getBlockingQueue(queueName);
RDelayedQueue<T> delayedQueue = redissonClient.getDelayedQueue(blockingQueue);
delayedQueues.put(queueName, delayedQueue);
DelayTaskQueueExecutor.Processor<T> processor = task -> {
try {
processMessage.accept(task);
} catch (Exception e) {
log.error("Error processing task: {}", task, e);
}
};
new DelayTaskQueueExecutor<>(queueName + " DELAY TASK", redissonClient, blockingQueue, processor);
log.info("Initialized delay queue for {}", queueName);
}
public void addToQueue(String queueName, T message, long delay, TimeUnit timeUnit) {
RDelayedQueue<T> queue = getDelayedQueue(queueName);
queue.offer(message, delay, timeUnit);
log.info("Added to queue: {}, msg: {}, delay: {} {}", queueName, message, delay, timeUnit);
}
public void addToQueue(String queueName, List<T> messages, long delay, TimeUnit timeUnit) {
RDelayedQueue<T> queue = getDelayedQueue(queueName);
messages.forEach(message -> {
queue.offer(message, delay, timeUnit);
log.info("Added to queue: {}, msg: {}, delay: {} {}", queueName, message, delay, timeUnit);
});
}
private RDelayedQueue<T> getDelayedQueue(String queueName) {
RDelayedQueue<T> queue = delayedQueues.get(queueName);
if (queue == null) {
throw new IllegalArgumentException("Queue not initialized: " + queueName);
}
return queue;
}
}
package com.infoloop.tianting.logic.delay;
import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum;
import com.infoloop.tianting.logic.delay.param.AutoCancelParam;
import com.infoloop.tianting.model.bo.AddSkusSellQuantityBO;
import com.infoloop.tianting.service.client.OrderServiceRpcClient;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.stream.Collectors;
@Slf4j
@Component
@RequiredArgsConstructor
public class OrderAutoCancelDelayTask {
private final DelayedQueue<AutoCancelParam> delayedQueue;
private final OrderServiceRpcClient orderServiceRpcClient;
public static final String AUTO_CANCEL_ORDER_DELAY_QUEUE = "AUTO_CANCEL_ORDER_QUEUE";
@PostConstruct
public void init() {
delayedQueue.initQueue(AUTO_CANCEL_ORDER_DELAY_QUEUE, this::execute);
}
private void execute(AutoCancelParam param) {
try {
final var orderById = orderServiceRpcClient.getOrderById(param.getOrderId());
if (orderById == null) {
log.error("Order not found, orderId: {}", param.getOrderId());
return;
}
if (orderById.getPayStatus() == PayStatusEnum.PAY_CANCELED) {
log.info("Order {} already canceled, skipping.", param.getOrderId());
return;
}
if (orderById.getPayStatus() == PayStatusEnum.IN_PROGRESS || orderById.getPayStatus() == PayStatusEnum.SUCCEED) {
log.info("Order {} already successful, skipping.", param.getOrderId());
return;
}
final var isUpdated = orderServiceRpcClient.updateClientCustomerOrderCancel(orderById.getEnterpriseId(), orderById.getId());
if (isUpdated) {
final var orderDetails = orderServiceRpcClient.getOrderDetailsByOrderId(orderById.getId());
final var isSuccess = orderServiceRpcClient.addSkusSellQuantities(orderById.getEnterpriseId(), orderById.getStallId(), orderDetails.stream().map(e -> AddSkusSellQuantityBO.builder()
.skuId(e.getSkuId())
.quantity(-e.getCount())
.build()).collect(Collectors.toList()));
log.info("Order {} addSkusSellQuantities result: {}", param.getOrderId(), isSuccess);
}
} catch (Exception e) {
log.error("OrderAutoCancelDelayTask execute error", e);
}
}
}
package com.infoloop.tianting.logic.delay.param;
import lombok.Data;
@Data
public class AutoCancelParam {
private int orderId;
}
package com.infoloop.tianting.model.bo;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class AddSkusSellQuantityBO {
private int skuId;
private int quantity;
}
package com.infoloop.tianting.model.bo;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class SkuSellQuantityBO {
private Integer id;
private int skuId;
private int maxSellQuantity;
}
......@@ -41,6 +41,9 @@ public class SkuSellQuantityDTO {
@ApiModelProperty("菜品售卖状态")
@NotNull
private SkuSellQuantityStatus status;
@ApiModelProperty("关键字")
private String keyword;
}
@Data
......
......@@ -11,7 +11,7 @@ import lombok.Data;
public class SkuSellQuantityStatisticsVO {
@ApiModelProperty("全部")
private Long total;
private int total;
@ApiModelProperty("售罄")
private Long soldOut;
......
......@@ -6,6 +6,7 @@ import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsResponseDto;
import com.infoloop.tianting.model.dto.MenuDbDTO.MenuDetailDto;
import com.infoloop.tianting.model.dto.MenuDbDTO.MenuDto;
import com.infoloop.tianting.model.dto.MenuDbDTO.MenuRefDto;
import java.util.List;
public interface MenuService {
......@@ -21,4 +22,6 @@ public interface MenuService {
List<MenuRefDto> getClientCustomerMenuRefsByCustomerId(Integer enterpriseId, Integer customerId);
BatchCreateMenuRefsResponseDto batchCreateMenuRefs(BatchCreateMenuRefsDto batchCreateMenuRefsDto);
List<Integer> queryMenuSkuIdsByStallId(int enterpriseId, int stallId);
}
......
package com.infoloop.tianting.service;
import com.infoloop.tianting.model.common.OrderPageResult;
import com.infoloop.tianting.model.common.PageResult;
import com.infoloop.tianting.model.dto.OrderDbDTO.BatchUpdateOrderDetailResponse;
import com.infoloop.tianting.model.dto.OrderDbDTO.getMenuOrderCountDto;
import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto;
import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderResponse;
import com.infoloop.tianting.model.dto.OrderDbDTO.OperatorCreateOrderDto;
......@@ -15,6 +13,8 @@ import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto;
import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByPaginationDto;
import com.infoloop.tianting.model.dto.OrderDbDTO.UpdateOrderDto;
import com.infoloop.tianting.model.dto.OrderDbDTO.UpdateOrderResponse;
import com.infoloop.tianting.model.dto.OrderDbDTO.getMenuOrderCountDto;
import java.util.List;
public interface OrderService {
......
package com.infoloop.tianting.service;
import com.infoloop.tianting.model.common.PageResult;
import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDto;
import com.infoloop.tianting.model.dto.SkuSellQuantityDTO;
import com.infoloop.tianting.model.vo.SkuSellQuantityStatisticsVO;
import com.infoloop.tianting.model.vo.SkuSellQuantityVO;
import javax.validation.Valid;
import java.util.List;
public interface SkuService {
List<SkuDto> getSkusByIds(List<Integer> ids);
SkuSellQuantityStatisticsVO querySkuSellQuantityStatistics(int stallId);
PageResult<SkuSellQuantityVO> querySkuSellQuantity(SkuSellQuantityDTO.QuerySkuSellQuantityDTO querySkuSellQuantityDTO);
boolean batchSetSkuSellQuantity(int stallId, SkuSellQuantityDTO.BatchSetSkuSellQuantityDTO batchSetSkuSellQuantityDTO);
List<SkuSellQuantityVO> querySkuSellQuantityBySkuIds(SkuSellQuantityDTO.@Valid QuerySkuSellQuantityBySkuIdsDTO querySkuSellQuantityBySkuIdsDTO);
}
......
......@@ -8,8 +8,11 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderModification;
import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum;
import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum;
import com.infoloop.tianting.config.BusinessConfig;
import com.infoloop.tianting.exception.ClientEndExceptions;
import com.infoloop.tianting.exception.ErrorCodeEnum;
import com.infoloop.tianting.model.dto.PayDTO.PayInformRequestDto;
import com.infoloop.tianting.model.dto.PayDTO.PayResponseDto;
import com.infoloop.tianting.model.dto.PayDTO.ThirdPartyPayInformRequestDto;
......@@ -49,6 +52,11 @@ public class PayServiceClient {
private String clientId;
public PayResponseDto payInform(PayInformRequestDto payRequestDto) {
final var orderById = orderServiceRpcClient.getOrderById(Integer.valueOf(payRequestDto.getOrderId()));
if (orderById == null || orderById.getPayStatus() == PayStatusEnum.PAY_CANCELED || orderById.getStatus() == OrderStatusEnum.ORDER_CANCELED) {
log.info("Order {} not found or canceled, skipping.", payRequestDto.getOrderId());
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_CANCEL);
}
String url = businessConfig.getPayUrl();
String requestDate = DateUtil.formatDate(LocalDateTime.now(), DateUtil.YMDHMS);
ThirdPartyPayInformRequestDto jsonData = buildRequestData(payRequestDto, requestDate);
......
......@@ -2,6 +2,7 @@ package com.infoloop.tianting.service.client;
import com.infoloop.tianting.GeDishSkuByIdsRpcResponse;
import com.infoloop.tianting.GetSkusByIdsRpcRequest;
import com.infoloop.tianting.SingleSkuResponse;
import com.infoloop.tianting.SkuServiceProtoRpcGrpc;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
......@@ -21,4 +22,12 @@ public class SkuServiceRpcClient {
.build();
return skuServiceProtoRpcBlockingStub.getDishSkusByIds(request);
}
public List<SingleSkuResponse> getSkusByIds(List<Integer> ids) {
final var request = GetSkusByIdsRpcRequest.newBuilder()
.addAllIds(ids)
.setIncludeDeleted(false)
.build();
return skuServiceProtoRpcBlockingStub.getSkusByIds(request).getResponseList();
}
}
......
package com.infoloop.tianting.service.impl;
import com.infoloop.tianting.context.LoginContextHolder;
import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse;
import com.infoloop.tianting.menuservice.SingleMenuRpcResponse;
import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsDto;
import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsResponseDto;
import com.infoloop.tianting.model.dto.MenuDbDTO.DishRuleJson;
......@@ -197,4 +200,10 @@ public class MenuServiceImpl implements MenuService {
.build();
}
@Override
public List<Integer> queryMenuSkuIdsByStallId(int enterpriseId, int stallId) {
final var menuIds = menuServiceRpcClient.queryPublishedMenusByStallId(LoginContextHolder.getEnterpriseId(), stallId).getResponsesList().stream().map(SingleMenuRpcResponse::getId).collect(Collectors.toList());
return menuServiceRpcClient.queryMenuDetailsByMenuIds(LoginContextHolder.getEnterpriseId(), menuIds).getResponsesList().stream().map(SingleMenuDetailRpcResponse::getSkuId).distinct().collect(Collectors.toList());
}
}
......
......@@ -118,10 +118,7 @@ public class OrderServiceImpl implements OrderService {
createOrderDto.setCreationSource(OrderSourceEnum.STALL.getNumber());
createOrderDto.setEnterpriseId(operatorLoginInfo.getEnterpriseId());
// createOrderDto.setStallId();
var onlinePay = false;
if (menu.getOrderRuleJson().getModeOfPayment() == ModeOfPaymentEnum.ONLINE) {
onlinePay = true;
}
var onlinePay = menu.getOrderRuleJson().getModeOfPayment() == ModeOfPaymentEnum.ONLINE;
createOrderDto.setOnlinePay(onlinePay);
OrderTypeEnum orderType;
if (menu.getOrderRuleJson().getCloseTimeType() == CloseTimeTypeEnum.RESERVATION) {
......
package com.infoloop.tianting.service.impl;
import com.infoloop.tianting.SingleSkuResponse;
import com.infoloop.tianting.clientcustomerorderservice.SingleSkuSellQuantityRpcResponse;
import com.infoloop.tianting.context.LoginContextHolder;
import com.infoloop.tianting.enums.SkuSellQuantityStatus;
import com.infoloop.tianting.model.bo.SkuSellQuantityBO;
import com.infoloop.tianting.model.common.PageResult;
import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDetailSingleResponseDto;
import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDto;
import com.infoloop.tianting.model.dto.SkuDbDTO.SkuSpecialDetailSingleResponseDto;
import com.infoloop.tianting.model.dto.SkuSellQuantityDTO;
import com.infoloop.tianting.model.vo.SkuSellQuantityStatisticsVO;
import com.infoloop.tianting.model.vo.SkuSellQuantityVO;
import com.infoloop.tianting.service.MenuService;
import com.infoloop.tianting.service.SkuService;
import com.infoloop.tianting.service.client.OrderServiceRpcClient;
import com.infoloop.tianting.service.client.SkuServiceRpcClient;
import com.infoloop.tianting.utils.DateUtil;
import com.infoloop.tianting.utils.PageUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class SkuServiceImpl implements SkuService {
private final MenuService menuService;
private final SkuServiceRpcClient skuServiceRpcClient;
private final OrderServiceRpcClient orderServiceRpcClient;
@Override
public List<SkuDto> getSkusByIds(List<Integer> ids) {
final var response = skuServiceRpcClient.getDishSkusByIds(ids);
......@@ -56,4 +75,133 @@ public class SkuServiceImpl implements SkuService {
.build()
).collect(Collectors.toList());
}
@Override
public SkuSellQuantityStatisticsVO querySkuSellQuantityStatistics(int stallId) {
final var skuIds = menuService.queryMenuSkuIdsByStallId(LoginContextHolder.getEnterpriseId(), stallId);
final var responses = orderServiceRpcClient.querySkuSellQuantitiesByStall(LoginContextHolder.getEnterpriseId(), stallId);
final var skuSellQuantitiesMap = responses.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity()));
final var soldOut = skuIds.stream()
.filter(e -> skuSellQuantitiesMap.get(e) == null || skuSellQuantitiesMap.get(e).getMaxSellQuantity() == skuSellQuantitiesMap.get(e).getTodaySellQuantity())
.count();
final int total = skuIds.size();
return SkuSellQuantityStatisticsVO.builder()
.total(total)
.soldOut(soldOut)
.onSale(total - soldOut)
.build();
}
@Override
public PageResult<SkuSellQuantityVO> querySkuSellQuantity(SkuSellQuantityDTO.QuerySkuSellQuantityDTO querySkuSellQuantityDTO) {
final var stallId = querySkuSellQuantityDTO.getStallId();
final var enterpriseId = LoginContextHolder.getEnterpriseId();
final var skuIds = menuService.queryMenuSkuIdsByStallId(enterpriseId, stallId);
var responses = orderServiceRpcClient.querySkuSellQuantitiesByStall(enterpriseId, stallId);
final var skuSellQuantityMap = responses.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity()));
responses = skuIds.stream()
.map(skuId -> {
var response = skuSellQuantityMap.get(skuId);
if (response == null) {
response = SingleSkuSellQuantityRpcResponse.newBuilder()
.setSkuId(skuId)
.setMaxSellQuantity(0)
.setTodaySellQuantity(0)
.build();
}
return response;
})
.collect(Collectors.toList());
if (querySkuSellQuantityDTO.getStatus() != SkuSellQuantityStatus.ALL) {
responses = responses.stream()
.filter(e -> {
switch (querySkuSellQuantityDTO.getStatus()) {
case SOLD_OUT:
return e.getMaxSellQuantity() == e.getTodaySellQuantity();
case ON_SALE:
return e.getMaxSellQuantity() != e.getTodaySellQuantity();
default:
return true;
}
})
.collect(Collectors.toList());
}
final var skuList = skuServiceRpcClient.getSkusByIds(responses.stream().map(SingleSkuSellQuantityRpcResponse::getSkuId).collect(Collectors.toList()));
final var skuMap = skuList.stream().collect(Collectors.toMap(SingleSkuResponse::getId, Function.identity()));
final var keyword = querySkuSellQuantityDTO.getKeyword();
if (keyword != null && !keyword.isEmpty()) {
responses = responses.stream()
.filter(e -> {
var sku = skuMap.get(e.getSkuId());
return sku != null && (sku.getCode().contains(keyword) || sku.getName().contains(keyword));
})
.collect(Collectors.toList());
}
final var skuSellQuantityVOS = responses.stream()
.map(e -> {
var sku = skuMap.get(e.getSkuId());
return SkuSellQuantityVO.builder()
.skuId(e.getSkuId())
.skuName(sku != null ? sku.getName() : "")
.skuCode(sku != null ? sku.getCode() : "")
.maxSellQuantity(e.getMaxSellQuantity())
.todaySellQuantity(e.getTodaySellQuantity())
.soldOut(e.getMaxSellQuantity() == e.getTodaySellQuantity())
.build();
})
.sorted(Comparator.comparing(SkuSellQuantityVO::getSkuCode))
.collect(Collectors.toList());
return PageUtil.subListPage(skuSellQuantityVOS, querySkuSellQuantityDTO.getPageNo(), querySkuSellQuantityDTO.getPageSize());
}
@Override
public boolean batchSetSkuSellQuantity(int stallId, SkuSellQuantityDTO.BatchSetSkuSellQuantityDTO batchSetSkuSellQuantityDTO) {
final var responses = orderServiceRpcClient.querySkuSellQuantitiesByStallAndSkuIds(LoginContextHolder.getEnterpriseId(), stallId, batchSetSkuSellQuantityDTO.getSkuIds());
final var skuMap = responses.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity()));
final var skuSellQuantityBOs = batchSetSkuSellQuantityDTO.getSkuIds().stream().map(skuId -> SkuSellQuantityBO.builder()
.id(skuMap.get(skuId) == null ? null : skuMap.get(skuId).getId())
.skuId(skuId)
.maxSellQuantity(batchSetSkuSellQuantityDTO.getMaxSellQuantity())
.build()
).collect(Collectors.toList());
return orderServiceRpcClient.batchSaveSkuSellQuantities(LoginContextHolder.getEnterpriseId(), stallId, skuSellQuantityBOs);
}
@Override
public List<SkuSellQuantityVO> querySkuSellQuantityBySkuIds(SkuSellQuantityDTO.QuerySkuSellQuantityBySkuIdsDTO querySkuSellQuantityBySkuIdsDTO) {
final var stallId = querySkuSellQuantityBySkuIdsDTO.getStallId();
final var enterpriseId = LoginContextHolder.getEnterpriseId();
final var skuIds = menuService.queryMenuSkuIdsByStallId(enterpriseId, stallId);
var responses = orderServiceRpcClient.querySkuSellQuantitiesByStall(enterpriseId, stallId);
final var skuSellQuantityMap = responses.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity()));
responses = skuIds.stream()
.map(skuId -> {
var response = skuSellQuantityMap.get(skuId);
if (response == null) {
response = SingleSkuSellQuantityRpcResponse.newBuilder()
.setSkuId(skuId)
.setMaxSellQuantity(0)
.setTodaySellQuantity(0)
.build();
}
return response;
})
.collect(Collectors.toList());
final var skuList = skuServiceRpcClient.getSkusByIds(responses.stream().map(SingleSkuSellQuantityRpcResponse::getSkuId).collect(Collectors.toList()));
final var skuMap = skuList.stream().collect(Collectors.toMap(SingleSkuResponse::getId, Function.identity()));
return responses.stream()
.map(e -> {
var sku = skuMap.get(e.getSkuId());
return SkuSellQuantityVO.builder()
.skuId(e.getSkuId())
.skuName(sku != null ? sku.getName() : "")
.skuCode(sku != null ? sku.getCode() : "")
.maxSellQuantity(e.getMaxSellQuantity())
.todaySellQuantity(e.getTodaySellQuantity())
.soldOut(e.getMaxSellQuantity() == e.getTodaySellQuantity())
.build();
})
.sorted(Comparator.comparing(SkuSellQuantityVO::getSkuCode))
.collect(Collectors.toList());
}
}
......
......@@ -33,6 +33,14 @@ service ClientCustomerOrderServiceRpc {
// 操作记录
rpc GetOrderOperationRecordsByOrderId (GetOrderOperationRecordsByOrderIdRequest) returns (GetOrderOperationRecordsByOrderIdResponse) {}
rpc BatchCreateOrderOperationRecords (BatchCreateOrderOperationRecordsRequest) returns (BatchCreateOrderOperationRecordsResponse) {}
// sku菜品库存
rpc QuerySkuSellQuantitiesByStall(QuerySkuSellQuantitiesByStallRpcRequest) returns (QuerySkuSellQuantitiesByStallRpcResponse) {}
rpc QuerySkuSellQuantitiesByStallAndSkuIds(QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest) returns (QuerySkuSellQuantitiesByStallAndSkuIdsRpcResponse) {}
rpc BatchSaveSkuSellQuantities(BatchSaveSkuSellQuantitiesRpcRequest) returns (BatchSaveSkuSellQuantitiesRpcResponse) {}
rpc AddSkusSellQuantities(AddSkusSellQuantitiesRpcRequest) returns (AddSkusSellQuantitiesRpcResponse) {}
}
enum OrderStatusEnum {
......@@ -608,3 +616,71 @@ message BatchCreateOrderOperationRecordsResponse {
bool isCreated = 1;
repeated int32 ids = 2;
}
message SingleSkuSellQuantityRpcResponse {
int32 id = 1;
int32 enterpriseId = 2;
int32 stallId = 3;
int32 skuId = 4;
int32 maxSellQuantity = 5;
int32 todaySellQuantity = 6;
int32 createdBy = 7;
int64 createdAt = 8;
int32 creationSource = 9;
int32 updatedBy = 10;
int64 updatedAt = 11;
int32 updateSource = 12;
bool isDeleted = 13;
}
message QuerySkuSellQuantitiesByStallRpcRequest {
int32 enterpriseId = 1;
int32 stallId = 2;
}
message QuerySkuSellQuantitiesByStallRpcResponse {
repeated SingleSkuSellQuantityRpcResponse responses = 1;
}
message QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest {
int32 enterpriseId = 1;
int32 stallId = 2;
repeated int32 skuIds = 3;
}
message QuerySkuSellQuantitiesByStallAndSkuIdsRpcResponse {
repeated SingleSkuSellQuantityRpcResponse responses = 1;
}
message BatchSaveSkuSellQuantitiesRpcRequest {
repeated SkuSellQuantityModification skuSellQuantityModifications = 1;
int32 enterpriseId = 2;
int32 updatedBy = 3;
int32 updateSource = 4;
}
message SkuSellQuantityModification {
int32 id = 1;
int32 stallId = 2;
int32 skuId = 3;
int32 maxSellQuantity = 4;
}
message BatchSaveSkuSellQuantitiesRpcResponse {
bool isSaved = 1;
}
message AddSkusSellQuantitiesRpcRequest {
int32 enterpriseId = 1;
int32 stallId = 2;
repeated SkuSellQuantity skuSellQuantities = 3;
}
message SkuSellQuantity {
int32 skuId = 1;
int32 quantity = 2;
}
message AddSkusSellQuantitiesRpcResponse {
bool isAdded = 1;
}
......