Showing
30 changed files
with
874 additions
and
67 deletions
| ... | @@ -44,6 +44,11 @@ public @interface RepeatSubmit { | ... | @@ -44,6 +44,11 @@ public @interface RepeatSubmit { |
| 44 | String message() default "不允许重复提交,请稍后再试"; | 44 | String message() default "不允许重复提交,请稍后再试"; |
| 45 | 45 | ||
| 46 | /** | 46 | /** |
| 47 | + * 是否根据登录用户ID加锁 | ||
| 48 | + */ | ||
| 49 | + boolean isLockByLoginUser() default true; | ||
| 50 | + | ||
| 51 | + /** | ||
| 47 | * 方法执行完自动释放锁 | 52 | * 方法执行完自动释放锁 |
| 48 | */ | 53 | */ |
| 49 | boolean methodAutoUnlock() default true; | 54 | boolean methodAutoUnlock() default true; | ... | ... |
| ... | @@ -110,7 +110,11 @@ public class RepeatSubmitAspect { | ... | @@ -110,7 +110,11 @@ public class RepeatSubmitAspect { |
| 110 | } | 110 | } |
| 111 | } | 111 | } |
| 112 | } | 112 | } |
| 113 | + if (requestLock.isLockByLoginUser()) { | ||
| 113 | final var operatorId = LoginContextHolder.hasLogin() ? LoginContextHolder.getId() : null; | 114 | final var operatorId = LoginContextHolder.hasLogin() ? LoginContextHolder.getId() : null; |
| 114 | return requestLock.prefix() + (operatorId != null ? CommonConstants.COLON + operatorId : "") + (sb.length() > 0 ? CommonConstants.UNDERLINE + sb : ""); | 115 | return requestLock.prefix() + (operatorId != null ? CommonConstants.COLON + operatorId : "") + (sb.length() > 0 ? CommonConstants.UNDERLINE + sb : ""); |
| 116 | + } else { | ||
| 117 | + return requestLock.prefix() + (sb.length() > 0 ? CommonConstants.UNDERLINE + sb : ""); | ||
| 118 | + } | ||
| 115 | } | 119 | } |
| 116 | } | 120 | } | ... | ... |
| ... | @@ -9,7 +9,7 @@ import io.lettuce.core.resource.ClientResources; | ... | @@ -9,7 +9,7 @@ import io.lettuce.core.resource.ClientResources; |
| 9 | import io.lettuce.core.tracing.BraveTracing; | 9 | import io.lettuce.core.tracing.BraveTracing; |
| 10 | import org.redisson.Redisson; | 10 | import org.redisson.Redisson; |
| 11 | import org.redisson.api.RedissonClient; | 11 | import org.redisson.api.RedissonClient; |
| 12 | -import org.redisson.client.codec.StringCodec; | 12 | +import org.redisson.codec.JsonJacksonCodec; |
| 13 | import org.redisson.config.Config; | 13 | import org.redisson.config.Config; |
| 14 | import org.springframework.beans.factory.annotation.Autowired; | 14 | import org.springframework.beans.factory.annotation.Autowired; |
| 15 | import org.springframework.beans.factory.annotation.Qualifier; | 15 | import org.springframework.beans.factory.annotation.Qualifier; |
| ... | @@ -68,7 +68,7 @@ public class RedisConfig { | ... | @@ -68,7 +68,7 @@ public class RedisConfig { |
| 68 | @Value(REDIS_PORT) final String port, | 68 | @Value(REDIS_PORT) final String port, |
| 69 | @Value(REDIS_DATABASE) final int dbToken) { | 69 | @Value(REDIS_DATABASE) final int dbToken) { |
| 70 | final var config = new Config(); | 70 | final var config = new Config(); |
| 71 | - config.setCodec(StringCodec.INSTANCE); | 71 | + config.setCodec(new JsonJacksonCodec()); |
| 72 | 72 | ||
| 73 | config.useSingleServer() | 73 | config.useSingleServer() |
| 74 | .setAddress("redis://" + url + ":" + port) | 74 | .setAddress("redis://" + url + ":" + port) | ... | ... |
| ... | @@ -15,8 +15,15 @@ import org.springframework.http.converter.StringHttpMessageConverter; | ... | @@ -15,8 +15,15 @@ import org.springframework.http.converter.StringHttpMessageConverter; |
| 15 | import org.springframework.web.client.DefaultResponseErrorHandler; | 15 | import org.springframework.web.client.DefaultResponseErrorHandler; |
| 16 | import org.springframework.web.client.RestTemplate; | 16 | import org.springframework.web.client.RestTemplate; |
| 17 | 17 | ||
| 18 | +import javax.net.ssl.SSLContext; | ||
| 19 | +import javax.net.ssl.TrustManager; | ||
| 20 | +import javax.net.ssl.X509TrustManager; | ||
| 18 | import java.io.IOException; | 21 | import java.io.IOException; |
| 19 | import java.nio.charset.StandardCharsets; | 22 | import java.nio.charset.StandardCharsets; |
| 23 | +import java.security.KeyManagementException; | ||
| 24 | +import java.security.NoSuchAlgorithmException; | ||
| 25 | +import java.security.SecureRandom; | ||
| 26 | +import java.security.cert.X509Certificate; | ||
| 20 | import java.util.ArrayList; | 27 | import java.util.ArrayList; |
| 21 | import java.util.concurrent.TimeUnit; | 28 | import java.util.concurrent.TimeUnit; |
| 22 | 29 | ||
| ... | @@ -40,8 +47,26 @@ public class RestTemplateConfig { | ... | @@ -40,8 +47,26 @@ public class RestTemplateConfig { |
| 40 | private Integer keepAliveDuration; | 47 | private Integer keepAliveDuration; |
| 41 | 48 | ||
| 42 | @Bean | 49 | @Bean |
| 43 | - public OkHttpClient okHttpClient() { | 50 | + public OkHttpClient okHttpClient() throws NoSuchAlgorithmException, KeyManagementException { |
| 51 | + TrustManager[] trustAllCertificates = new TrustManager[]{ | ||
| 52 | + new X509TrustManager() { | ||
| 53 | + @Override | ||
| 54 | + public void checkClientTrusted(X509Certificate[] chain, String authType) {} | ||
| 55 | + | ||
| 56 | + @Override | ||
| 57 | + public void checkServerTrusted(X509Certificate[] chain, String authType) {} | ||
| 58 | + | ||
| 59 | + @Override | ||
| 60 | + public X509Certificate[] getAcceptedIssuers() { | ||
| 61 | + return new X509Certificate[0]; | ||
| 62 | + } | ||
| 63 | + } | ||
| 64 | + }; | ||
| 65 | + SSLContext sslContext = SSLContext.getInstance("TLS"); | ||
| 66 | + sslContext.init(null, trustAllCertificates, new SecureRandom()); | ||
| 44 | return new OkHttpClient.Builder() | 67 | return new OkHttpClient.Builder() |
| 68 | + .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCertificates[0]) | ||
| 69 | + .hostnameVerifier((hostname, session) -> true) | ||
| 45 | .connectTimeout(connectTimeout, TimeUnit.SECONDS) | 70 | .connectTimeout(connectTimeout, TimeUnit.SECONDS) |
| 46 | .readTimeout(readTimeout, TimeUnit.SECONDS) | 71 | .readTimeout(readTimeout, TimeUnit.SECONDS) |
| 47 | .writeTimeout(writeTimeout, TimeUnit.SECONDS) | 72 | .writeTimeout(writeTimeout, TimeUnit.SECONDS) | ... | ... |
| 1 | package com.infoloop.tianting.controller; | 1 | package com.infoloop.tianting.controller; |
| 2 | 2 | ||
| 3 | import com.github.xiaoymin.knife4j.annotations.ApiSupport; | 3 | import com.github.xiaoymin.knife4j.annotations.ApiSupport; |
| 4 | +import com.infoloop.tianting.annotation.RepeatSubmit; | ||
| 4 | import com.infoloop.tianting.model.dto.OrderDbDTO; | 5 | import com.infoloop.tianting.model.dto.OrderDbDTO; |
| 5 | import com.infoloop.tianting.model.dto.OrderDbDTO.BatchUpdateOrderDetailResponse; | 6 | import com.infoloop.tianting.model.dto.OrderDbDTO.BatchUpdateOrderDetailResponse; |
| 6 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto; | 7 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto; |
| ... | @@ -67,6 +68,7 @@ public class OrderController { | ... | @@ -67,6 +68,7 @@ public class OrderController { |
| 67 | @ApiOperation(value = "创建订单") | 68 | @ApiOperation(value = "创建订单") |
| 68 | @PostMapping("/orders") | 69 | @PostMapping("/orders") |
| 69 | @ResponseStatus(HttpStatus.OK) | 70 | @ResponseStatus(HttpStatus.OK) |
| 71 | + @RepeatSubmit(prefix = "createOrder", isLockByLoginUser = false) | ||
| 70 | public CreateOrderResponse createOrder(@Valid @RequestBody CreateOrderDto createOrderDto) { | 72 | public CreateOrderResponse createOrder(@Valid @RequestBody CreateOrderDto createOrderDto) { |
| 71 | return orderService.createOrder(createOrderDto); | 73 | return orderService.createOrder(createOrderDto); |
| 72 | } | 74 | } |
| ... | @@ -74,12 +76,11 @@ public class OrderController { | ... | @@ -74,12 +76,11 @@ public class OrderController { |
| 74 | @ApiOperation(value = "院区端创建订单") | 76 | @ApiOperation(value = "院区端创建订单") |
| 75 | @PostMapping("/operator/orders") | 77 | @PostMapping("/operator/orders") |
| 76 | @ResponseStatus(HttpStatus.OK) | 78 | @ResponseStatus(HttpStatus.OK) |
| 77 | - public CreateOrderResponse createOrderByOperator( | 79 | + @RepeatSubmit(prefix = "createOrder", isLockByLoginUser = false) |
| 78 | - @Valid @RequestBody OrderDbDTO.OperatorCreateOrderDto createOrderDto) { | 80 | + public CreateOrderResponse createOrderByOperator(@Valid @RequestBody OrderDbDTO.OperatorCreateOrderDto createOrderDto) { |
| 79 | return orderService.orderCreation(createOrderDto); | 81 | return orderService.orderCreation(createOrderDto); |
| 80 | } | 82 | } |
| 81 | 83 | ||
| 82 | - // @SaIgnore | ||
| 83 | @ApiOperation(value = "修改订单") | 84 | @ApiOperation(value = "修改订单") |
| 84 | @PatchMapping("/orders/modification") | 85 | @PatchMapping("/orders/modification") |
| 85 | @ResponseStatus(HttpStatus.OK) | 86 | @ResponseStatus(HttpStatus.OK) |
| ... | @@ -87,20 +88,17 @@ public class OrderController { | ... | @@ -87,20 +88,17 @@ public class OrderController { |
| 87 | return orderService.updateOrder(updateOrderDto); | 88 | return orderService.updateOrder(updateOrderDto); |
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | - // @SaIgnore | ||
| 91 | @ApiOperation(value = "批量修改订单详情") | 91 | @ApiOperation(value = "批量修改订单详情") |
| 92 | @PatchMapping("/order_details/modification") | 92 | @PatchMapping("/order_details/modification") |
| 93 | @ResponseStatus(HttpStatus.OK) | 93 | @ResponseStatus(HttpStatus.OK) |
| 94 | - public BatchUpdateOrderDetailResponse batchUpdateOrderDetails( | 94 | + public BatchUpdateOrderDetailResponse batchUpdateOrderDetails(@Valid @RequestBody OrderDbDTO.OrderDetailBatchUpdateDto updateDto) { |
| 95 | - @Valid @RequestBody OrderDbDTO.OrderDetailBatchUpdateDto updateDto) { | ||
| 96 | return orderService.batchUpdateOrderDetails(updateDto); | 95 | return orderService.batchUpdateOrderDetails(updateDto); |
| 97 | } | 96 | } |
| 98 | 97 | ||
| 99 | @ApiOperation(value = "获取已预定该餐单的次数") | 98 | @ApiOperation(value = "获取已预定该餐单的次数") |
| 100 | @PostMapping("/order/check") | 99 | @PostMapping("/order/check") |
| 101 | @ResponseStatus(HttpStatus.OK) | 100 | @ResponseStatus(HttpStatus.OK) |
| 102 | - public Integer checkOrder( | 101 | + public Integer checkOrder(@Valid @RequestBody OrderDbDTO.getMenuOrderCountDto checkIfOrderedDto) { |
| 103 | - @Valid @RequestBody OrderDbDTO.getMenuOrderCountDto checkIfOrderedDto) { | ||
| 104 | return orderService.getMenuOrderCount(checkIfOrderedDto); | 102 | return orderService.getMenuOrderCount(checkIfOrderedDto); |
| 105 | } | 103 | } |
| 106 | 104 | ... | ... |
| 1 | package com.infoloop.tianting.controller; | 1 | package com.infoloop.tianting.controller; |
| 2 | 2 | ||
| 3 | import com.github.xiaoymin.knife4j.annotations.ApiSupport; | 3 | import com.github.xiaoymin.knife4j.annotations.ApiSupport; |
| 4 | +import com.infoloop.tianting.model.common.PageResult; | ||
| 4 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDto; | 5 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDto; |
| 5 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuIdsDto; | 6 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuIdsDto; |
| 7 | +import com.infoloop.tianting.model.dto.SkuSellQuantityDTO; | ||
| 8 | +import com.infoloop.tianting.model.vo.SkuSellQuantityStatisticsVO; | ||
| 9 | +import com.infoloop.tianting.model.vo.SkuSellQuantityVO; | ||
| 6 | import com.infoloop.tianting.service.SkuService; | 10 | import com.infoloop.tianting.service.SkuService; |
| 7 | import io.swagger.annotations.Api; | 11 | import io.swagger.annotations.Api; |
| 8 | import io.swagger.annotations.ApiOperation; | 12 | import io.swagger.annotations.ApiOperation; |
| ... | @@ -11,7 +15,10 @@ import lombok.extern.slf4j.Slf4j; | ... | @@ -11,7 +15,10 @@ import lombok.extern.slf4j.Slf4j; |
| 11 | import org.springframework.beans.factory.annotation.Autowired; | 15 | import org.springframework.beans.factory.annotation.Autowired; |
| 12 | import org.springframework.http.HttpStatus; | 16 | import org.springframework.http.HttpStatus; |
| 13 | import org.springframework.validation.annotation.Validated; | 17 | import org.springframework.validation.annotation.Validated; |
| 18 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 19 | +import org.springframework.web.bind.annotation.PathVariable; | ||
| 14 | import org.springframework.web.bind.annotation.PostMapping; | 20 | import org.springframework.web.bind.annotation.PostMapping; |
| 21 | +import org.springframework.web.bind.annotation.PutMapping; | ||
| 15 | import org.springframework.web.bind.annotation.RequestBody; | 22 | import org.springframework.web.bind.annotation.RequestBody; |
| 16 | import org.springframework.web.bind.annotation.ResponseStatus; | 23 | import org.springframework.web.bind.annotation.ResponseStatus; |
| 17 | import org.springframework.web.bind.annotation.RestController; | 24 | import org.springframework.web.bind.annotation.RestController; |
| ... | @@ -32,7 +39,36 @@ public class SkuController { | ... | @@ -32,7 +39,36 @@ public class SkuController { |
| 32 | @ApiOperation(value = "根据sku ids获取") | 39 | @ApiOperation(value = "根据sku ids获取") |
| 33 | @PostMapping("/skus") | 40 | @PostMapping("/skus") |
| 34 | @ResponseStatus(HttpStatus.OK) | 41 | @ResponseStatus(HttpStatus.OK) |
| 35 | - public List<SkuDto> getOrderByCustomerId(@Valid @RequestBody SkuIdsDto skuIdsDto) { | 42 | + public List<SkuDto> getSkusByIds(@Valid @RequestBody SkuIdsDto skuIdsDto) { |
| 36 | return skuService.getSkusByIds(skuIdsDto.getIds()); | 43 | return skuService.getSkusByIds(skuIdsDto.getIds()); |
| 37 | } | 44 | } |
| 45 | + | ||
| 46 | + @ApiOperation(value = "获取菜品售卖量统计") | ||
| 47 | + @GetMapping("/stall/{stallId}/skusellquantities/statistics") | ||
| 48 | + @ResponseStatus(HttpStatus.OK) | ||
| 49 | + public SkuSellQuantityStatisticsVO querySkuSellQuantityStatistics(@PathVariable("stallId") int stallId) { | ||
| 50 | + return skuService.querySkuSellQuantityStatistics(stallId); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @ApiOperation(value = "分页查询菜品售卖量") | ||
| 54 | + @PostMapping("/skusellquantities/query") | ||
| 55 | + @ResponseStatus(HttpStatus.OK) | ||
| 56 | + public PageResult<SkuSellQuantityVO> querySkuSellQuantity(@Valid @RequestBody SkuSellQuantityDTO.QuerySkuSellQuantityDTO querySkuSellQuantityDTO) { | ||
| 57 | + return skuService.querySkuSellQuantity(querySkuSellQuantityDTO); | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + @ApiOperation(value = "批量设置菜品售卖量") | ||
| 61 | + @PutMapping("/stall/{stallId}/skusellquantities/batchset") | ||
| 62 | + @ResponseStatus(HttpStatus.CREATED) | ||
| 63 | + public boolean batchSetSkuSellQuantity(@PathVariable("stallId") int stallId, | ||
| 64 | + @Valid @RequestBody SkuSellQuantityDTO.BatchSetSkuSellQuantityDTO batchSetSkuSellQuantityDTO) { | ||
| 65 | + return skuService.batchSetSkuSellQuantity(stallId, batchSetSkuSellQuantityDTO); | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + @ApiOperation(value = "根据菜品ids批量查询菜品售卖量") | ||
| 69 | + @PostMapping("/skusellquantities/querybyskuids") | ||
| 70 | + @ResponseStatus(HttpStatus.OK) | ||
| 71 | + public List<SkuSellQuantityVO> querySkuSellQuantityBySkuIds(@Valid @RequestBody SkuSellQuantityDTO.QuerySkuSellQuantityBySkuIdsDTO querySkuSellQuantityBySkuIdsDTO) { | ||
| 72 | + return skuService.querySkuSellQuantityBySkuIds(querySkuSellQuantityBySkuIdsDTO); | ||
| 73 | + } | ||
| 38 | } | 74 | } | ... | ... |
| ... | @@ -29,6 +29,12 @@ public enum ErrorCodeEnum implements BaseEnum { | ... | @@ -29,6 +29,12 @@ public enum ErrorCodeEnum implements BaseEnum { |
| 29 | ORDER_COUNT_LIMIT(406000005, "已超过该餐单预定次数"), | 29 | ORDER_COUNT_LIMIT(406000005, "已超过该餐单预定次数"), |
| 30 | 30 | ||
| 31 | QUERY_CLIENT_CUSTOMER_ERROR(406000006, "获取当日在住客户失败"), | 31 | QUERY_CLIENT_CUSTOMER_ERROR(406000006, "获取当日在住客户失败"), |
| 32 | + | ||
| 33 | + SKUS_SOLD_OUT_TODAY(406000007, "下单菜品\n{0}\n今日已售罄"), | ||
| 34 | + | ||
| 35 | + SKUS_STOCK_NO_ENOUGH_TODAY(406000007, "下单菜品\n{0}\n库存不足"), | ||
| 36 | + | ||
| 37 | + ORDER_CANCEL(406000008, "订单已自动取消") | ||
| 32 | ; | 38 | ; |
| 33 | private final int code; | 39 | private final int code; |
| 34 | 40 | ... | ... |
| 1 | +package com.infoloop.tianting.logic.delay; | ||
| 2 | + | ||
| 3 | +import lombok.extern.slf4j.Slf4j; | ||
| 4 | +import org.redisson.api.RBlockingQueue; | ||
| 5 | +import org.redisson.api.RedissonClient; | ||
| 6 | + | ||
| 7 | +import java.util.concurrent.ExecutorService; | ||
| 8 | +import java.util.concurrent.Executors; | ||
| 9 | +import java.util.concurrent.TimeUnit; | ||
| 10 | + | ||
| 11 | +@Slf4j | ||
| 12 | +public class DelayTaskQueueExecutor<T> { | ||
| 13 | + | ||
| 14 | + private final RedissonClient redissonClient; | ||
| 15 | + private final RBlockingQueue<T> blockingDeque; | ||
| 16 | + private final Processor<T> processor; | ||
| 17 | + private final ExecutorService executorService; | ||
| 18 | + private volatile boolean running = true; | ||
| 19 | + | ||
| 20 | + public interface Processor<T> { | ||
| 21 | + void process(T task) throws InterruptedException; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + public DelayTaskQueueExecutor(String threadName, RedissonClient redissonClient, RBlockingQueue<T> blockingDeque, Processor<T> processor) { | ||
| 25 | + this.redissonClient = redissonClient; | ||
| 26 | + this.blockingDeque = blockingDeque; | ||
| 27 | + this.processor = processor; | ||
| 28 | + this.executorService = Executors.newSingleThreadExecutor(r -> { | ||
| 29 | + Thread t = new Thread(r); | ||
| 30 | + t.setName(threadName); | ||
| 31 | + return t; | ||
| 32 | + }); | ||
| 33 | + this.executorService.submit(this::looper); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public void looper() { | ||
| 37 | + while (running) { | ||
| 38 | + try { | ||
| 39 | + if (redissonClient.isShutdown()) { | ||
| 40 | + shutdown(); | ||
| 41 | + return; | ||
| 42 | + } | ||
| 43 | + T task = blockingDeque.take(); | ||
| 44 | + processor.process(task); | ||
| 45 | + } catch (InterruptedException e) { | ||
| 46 | + Thread.currentThread().interrupt(); | ||
| 47 | + break; | ||
| 48 | + } catch (Exception e) { | ||
| 49 | + log.error("Task processing error in thread: {}", Thread.currentThread().getName(), e); | ||
| 50 | + } | ||
| 51 | + } | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + public void shutdown() { | ||
| 55 | + running = false; | ||
| 56 | + executorService.shutdown(); | ||
| 57 | + try { | ||
| 58 | + if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) { | ||
| 59 | + log.warn("Executor did not terminate in the specified time."); | ||
| 60 | + executorService.shutdownNow(); | ||
| 61 | + } | ||
| 62 | + } catch (InterruptedException e) { | ||
| 63 | + log.error("Shutdown interrupted", e); | ||
| 64 | + executorService.shutdownNow(); | ||
| 65 | + Thread.currentThread().interrupt(); | ||
| 66 | + } | ||
| 67 | + } | ||
| 68 | +} |
| 1 | +package com.infoloop.tianting.logic.delay; | ||
| 2 | + | ||
| 3 | +import lombok.RequiredArgsConstructor; | ||
| 4 | +import lombok.extern.slf4j.Slf4j; | ||
| 5 | +import org.redisson.api.RBlockingQueue; | ||
| 6 | +import org.redisson.api.RDelayedQueue; | ||
| 7 | +import org.redisson.api.RedissonClient; | ||
| 8 | +import org.springframework.stereotype.Service; | ||
| 9 | + | ||
| 10 | +import java.util.List; | ||
| 11 | +import java.util.Map; | ||
| 12 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 13 | +import java.util.concurrent.TimeUnit; | ||
| 14 | +import java.util.function.Consumer; | ||
| 15 | + | ||
| 16 | +@Slf4j | ||
| 17 | +@Service | ||
| 18 | +@RequiredArgsConstructor | ||
| 19 | +public class DelayedQueue<T> { | ||
| 20 | + | ||
| 21 | + private final RedissonClient redissonClient; | ||
| 22 | + | ||
| 23 | + private final Map<String, RDelayedQueue<T>> delayedQueues = new ConcurrentHashMap<>(); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 初始化队列,传入队列名称和处理逻辑 | ||
| 27 | + */ | ||
| 28 | + public void initQueue(String queueName, Consumer<T> processMessage) { | ||
| 29 | + RBlockingQueue<T> blockingQueue = redissonClient.getBlockingQueue(queueName); | ||
| 30 | + RDelayedQueue<T> delayedQueue = redissonClient.getDelayedQueue(blockingQueue); | ||
| 31 | + delayedQueues.put(queueName, delayedQueue); | ||
| 32 | + DelayTaskQueueExecutor.Processor<T> processor = task -> { | ||
| 33 | + try { | ||
| 34 | + processMessage.accept(task); | ||
| 35 | + } catch (Exception e) { | ||
| 36 | + log.error("Error processing task: {}", task, e); | ||
| 37 | + } | ||
| 38 | + }; | ||
| 39 | + new DelayTaskQueueExecutor<>(queueName + " DELAY TASK", redissonClient, blockingQueue, processor); | ||
| 40 | + log.info("Initialized delay queue for {}", queueName); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public void addToQueue(String queueName, T message, long delay, TimeUnit timeUnit) { | ||
| 44 | + RDelayedQueue<T> queue = getDelayedQueue(queueName); | ||
| 45 | + queue.offer(message, delay, timeUnit); | ||
| 46 | + log.info("Added to queue: {}, msg: {}, delay: {} {}", queueName, message, delay, timeUnit); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public void addToQueue(String queueName, List<T> messages, long delay, TimeUnit timeUnit) { | ||
| 50 | + RDelayedQueue<T> queue = getDelayedQueue(queueName); | ||
| 51 | + messages.forEach(message -> { | ||
| 52 | + queue.offer(message, delay, timeUnit); | ||
| 53 | + log.info("Added to queue: {}, msg: {}, delay: {} {}", queueName, message, delay, timeUnit); | ||
| 54 | + }); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + private RDelayedQueue<T> getDelayedQueue(String queueName) { | ||
| 58 | + RDelayedQueue<T> queue = delayedQueues.get(queueName); | ||
| 59 | + if (queue == null) { | ||
| 60 | + throw new IllegalArgumentException("Queue not initialized: " + queueName); | ||
| 61 | + } | ||
| 62 | + return queue; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | +} |
| 1 | +package com.infoloop.tianting.logic.delay; | ||
| 2 | + | ||
| 3 | +import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; | ||
| 4 | +import com.infoloop.tianting.logic.delay.param.AutoCancelParam; | ||
| 5 | +import com.infoloop.tianting.model.bo.AddSkusSellQuantityBO; | ||
| 6 | +import com.infoloop.tianting.service.client.OrderServiceRpcClient; | ||
| 7 | +import lombok.RequiredArgsConstructor; | ||
| 8 | +import lombok.extern.slf4j.Slf4j; | ||
| 9 | +import org.springframework.stereotype.Component; | ||
| 10 | + | ||
| 11 | +import javax.annotation.PostConstruct; | ||
| 12 | +import java.util.stream.Collectors; | ||
| 13 | + | ||
| 14 | +@Slf4j | ||
| 15 | +@Component | ||
| 16 | +@RequiredArgsConstructor | ||
| 17 | +public class OrderAutoCancelDelayTask { | ||
| 18 | + | ||
| 19 | + private final DelayedQueue<AutoCancelParam> delayedQueue; | ||
| 20 | + | ||
| 21 | + private final OrderServiceRpcClient orderServiceRpcClient; | ||
| 22 | + | ||
| 23 | + public static final String AUTO_CANCEL_ORDER_DELAY_QUEUE = "AUTO_CANCEL_ORDER_QUEUE"; | ||
| 24 | + | ||
| 25 | + @PostConstruct | ||
| 26 | + public void init() { | ||
| 27 | + delayedQueue.initQueue(AUTO_CANCEL_ORDER_DELAY_QUEUE, this::execute); | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + private void execute(AutoCancelParam param) { | ||
| 31 | + try { | ||
| 32 | + final var orderById = orderServiceRpcClient.getOrderById(param.getOrderId()); | ||
| 33 | + if (orderById == null) { | ||
| 34 | + log.error("Order not found, orderId: {}", param.getOrderId()); | ||
| 35 | + return; | ||
| 36 | + } | ||
| 37 | + if (orderById.getPayStatus() == PayStatusEnum.PAY_CANCELED) { | ||
| 38 | + log.info("Order {} already canceled, skipping.", param.getOrderId()); | ||
| 39 | + return; | ||
| 40 | + } | ||
| 41 | + if (orderById.getPayStatus() != PayStatusEnum.TO_PAY) { | ||
| 42 | + log.info("Order {} not to pay, skipping.", param.getOrderId()); | ||
| 43 | + return; | ||
| 44 | + } | ||
| 45 | + final var isUpdated = orderServiceRpcClient.updateClientCustomerOrderCancel(orderById.getEnterpriseId(), orderById.getId()); | ||
| 46 | + if (isUpdated) { | ||
| 47 | + final var orderDetails = orderServiceRpcClient.getOrderDetailsByOrderId(orderById.getId()); | ||
| 48 | + final var isSuccess = orderServiceRpcClient.addSkusSellQuantities(orderById.getEnterpriseId(), orderById.getStallId(), orderDetails.stream().map(e -> AddSkusSellQuantityBO.builder() | ||
| 49 | + .skuId(e.getSkuId()) | ||
| 50 | + .quantity(-e.getCount()) | ||
| 51 | + .build()).collect(Collectors.toList())); | ||
| 52 | + log.info("Order {} addSkusSellQuantities result: {}", param.getOrderId(), isSuccess); | ||
| 53 | + } | ||
| 54 | + } catch (Exception e) { | ||
| 55 | + log.error("OrderAutoCancelDelayTask execute error", e); | ||
| 56 | + } | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | +} |
| ... | @@ -3,19 +3,16 @@ package com.infoloop.tianting.model.common; | ... | @@ -3,19 +3,16 @@ package com.infoloop.tianting.model.common; |
| 3 | import io.swagger.annotations.ApiModel; | 3 | import io.swagger.annotations.ApiModel; |
| 4 | import io.swagger.annotations.ApiModelProperty; | 4 | import io.swagger.annotations.ApiModelProperty; |
| 5 | import lombok.Data; | 5 | import lombok.Data; |
| 6 | -import lombok.Singular; | ||
| 7 | 6 | ||
| 7 | +import javax.validation.constraints.NotEmpty; | ||
| 8 | import java.util.List; | 8 | import java.util.List; |
| 9 | 9 | ||
| 10 | @Data | 10 | @Data |
| 11 | @ApiModel(description = "公共参数") | 11 | @ApiModel(description = "公共参数") |
| 12 | -public class Param { | 12 | +public class IdsParam { |
| 13 | 13 | ||
| 14 | @ApiModelProperty(value = "ids") | 14 | @ApiModelProperty(value = "ids") |
| 15 | - @Singular("id") | 15 | + @NotEmpty(message = "ids不能为空") |
| 16 | private List<Integer> ids; | 16 | private List<Integer> ids; |
| 17 | 17 | ||
| 18 | - @ApiModelProperty(value = "keyword") | ||
| 19 | - private String keyword; | ||
| 20 | - | ||
| 21 | } | 18 | } | ... | ... |
| 1 | package com.infoloop.tianting.model.dto; | 1 | package com.infoloop.tianting.model.dto; |
| 2 | 2 | ||
| 3 | +import com.infoloop.tianting.annotation.RequestKeyParam; | ||
| 3 | import com.infoloop.tianting.clientcustomerorderservice.CloseTimeType; | 4 | import com.infoloop.tianting.clientcustomerorderservice.CloseTimeType; |
| 4 | import com.infoloop.tianting.clientcustomerorderservice.OrderSourceEnum; | 5 | import com.infoloop.tianting.clientcustomerorderservice.OrderSourceEnum; |
| 5 | import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; | 6 | import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; |
| ... | @@ -200,6 +201,8 @@ public class OrderDbDTO { | ... | @@ -200,6 +201,8 @@ public class OrderDbDTO { |
| 200 | @Builder | 201 | @Builder |
| 201 | @ApiModel(description = "创建订单视图") | 202 | @ApiModel(description = "创建订单视图") |
| 202 | public static class OperatorCreateOrderDto { | 203 | public static class OperatorCreateOrderDto { |
| 204 | + | ||
| 205 | + @RequestKeyParam | ||
| 203 | @ApiModelProperty(value = "档口 ID") | 206 | @ApiModelProperty(value = "档口 ID") |
| 204 | private Integer stallId; | 207 | private Integer stallId; |
| 205 | 208 | ||
| ... | @@ -234,6 +237,7 @@ public class OrderDbDTO { | ... | @@ -234,6 +237,7 @@ public class OrderDbDTO { |
| 234 | @ApiModelProperty(value = "院区 ID") | 237 | @ApiModelProperty(value = "院区 ID") |
| 235 | private Integer clientId; | 238 | private Integer clientId; |
| 236 | 239 | ||
| 240 | + @RequestKeyParam | ||
| 237 | @ApiModelProperty(value = "档口 ID") | 241 | @ApiModelProperty(value = "档口 ID") |
| 238 | private Integer stallId; | 242 | private Integer stallId; |
| 239 | 243 | ||
| ... | @@ -534,6 +538,7 @@ public class OrderDbDTO { | ... | @@ -534,6 +538,7 @@ public class OrderDbDTO { |
| 534 | @ToString | 538 | @ToString |
| 535 | @ApiModel(description = "订单详情信息,即菜品细节") | 539 | @ApiModel(description = "订单详情信息,即菜品细节") |
| 536 | public static class OperatorCreateOrderDetailDto { | 540 | public static class OperatorCreateOrderDetailDto { |
| 541 | + | ||
| 537 | @ApiModelProperty(value = "餐单详情 id,即菜品") | 542 | @ApiModelProperty(value = "餐单详情 id,即菜品") |
| 538 | private Integer menuDetailId; | 543 | private Integer menuDetailId; |
| 539 | 544 | ... | ... |
| 1 | +package com.infoloop.tianting.model.dto; | ||
| 2 | + | ||
| 3 | +import com.infoloop.tianting.enums.SkuSellQuantityStatus; | ||
| 4 | +import com.infoloop.tianting.model.common.PageInfo; | ||
| 5 | +import io.swagger.annotations.ApiModel; | ||
| 6 | +import io.swagger.annotations.ApiModelProperty; | ||
| 7 | +import lombok.Data; | ||
| 8 | +import lombok.EqualsAndHashCode; | ||
| 9 | + | ||
| 10 | +import javax.validation.constraints.NotEmpty; | ||
| 11 | +import javax.validation.constraints.NotNull; | ||
| 12 | +import java.util.List; | ||
| 13 | + | ||
| 14 | +@Data | ||
| 15 | +@ApiModel(description = "SkuSellQuantityDTO") | ||
| 16 | +public class SkuSellQuantityDTO { | ||
| 17 | + | ||
| 18 | + @Data | ||
| 19 | + @ApiModel(description = "批量设置菜品售卖量") | ||
| 20 | + public static class BatchSetSkuSellQuantityDTO { | ||
| 21 | + | ||
| 22 | + @ApiModelProperty("菜品 Ids") | ||
| 23 | + @NotEmpty | ||
| 24 | + private List<Integer> skuIds; | ||
| 25 | + | ||
| 26 | + @ApiModelProperty("最大售卖数量") | ||
| 27 | + @NotNull | ||
| 28 | + private Integer maxSellQuantity; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + | ||
| 32 | + @EqualsAndHashCode(callSuper = true) | ||
| 33 | + @Data | ||
| 34 | + @ApiModel(description = "分页查询菜品售卖量") | ||
| 35 | + public static class QuerySkuSellQuantityDTO extends PageInfo { | ||
| 36 | + | ||
| 37 | + @ApiModelProperty("档口Id") | ||
| 38 | + @NotNull | ||
| 39 | + private Integer stallId; | ||
| 40 | + | ||
| 41 | + @ApiModelProperty("菜品售卖状态") | ||
| 42 | + @NotNull | ||
| 43 | + private SkuSellQuantityStatus status; | ||
| 44 | + | ||
| 45 | + @ApiModelProperty("关键字") | ||
| 46 | + private String keyword; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @Data | ||
| 50 | + @ApiModel(description = "根据菜品 Ids 查询菜品售卖量") | ||
| 51 | + public static class QuerySkuSellQuantityBySkuIdsDTO { | ||
| 52 | + | ||
| 53 | + @ApiModelProperty("档口Id") | ||
| 54 | + @NotNull | ||
| 55 | + private Integer stallId; | ||
| 56 | + | ||
| 57 | + @ApiModelProperty("菜品售卖状态") | ||
| 58 | + @NotEmpty | ||
| 59 | + private List<Integer> skuIds; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | +} |
| 1 | +package com.infoloop.tianting.model.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Builder; | ||
| 6 | +import lombok.Data; | ||
| 7 | + | ||
| 8 | +@Data | ||
| 9 | +@ApiModel | ||
| 10 | +@Builder | ||
| 11 | +public class SkuSellQuantityStatisticsVO { | ||
| 12 | + | ||
| 13 | + @ApiModelProperty("全部") | ||
| 14 | + private int total; | ||
| 15 | + | ||
| 16 | + @ApiModelProperty("售罄") | ||
| 17 | + private Long soldOut; | ||
| 18 | + | ||
| 19 | + @ApiModelProperty("在售") | ||
| 20 | + private Long onSale; | ||
| 21 | +} |
| 1 | +package com.infoloop.tianting.model.vo; | ||
| 2 | + | ||
| 3 | +import io.swagger.annotations.ApiModel; | ||
| 4 | +import io.swagger.annotations.ApiModelProperty; | ||
| 5 | +import lombok.Builder; | ||
| 6 | +import lombok.Data; | ||
| 7 | + | ||
| 8 | + | ||
| 9 | +@Data | ||
| 10 | +@ApiModel | ||
| 11 | +@Builder | ||
| 12 | +public class SkuSellQuantityVO { | ||
| 13 | + | ||
| 14 | + @ApiModelProperty("菜品Id") | ||
| 15 | + private Integer skuId; | ||
| 16 | + | ||
| 17 | + @ApiModelProperty("菜品名称") | ||
| 18 | + private String skuName; | ||
| 19 | + | ||
| 20 | + @ApiModelProperty("菜品编号") | ||
| 21 | + private String skuCode; | ||
| 22 | + | ||
| 23 | + @ApiModelProperty("最大售卖数量") | ||
| 24 | + private int maxSellQuantity; | ||
| 25 | + | ||
| 26 | + @ApiModelProperty("今日售卖数量") | ||
| 27 | + private int todaySellQuantity; | ||
| 28 | + | ||
| 29 | + @ApiModelProperty("是否售罄") | ||
| 30 | + private Boolean soldOut; | ||
| 31 | + | ||
| 32 | +} |
| ... | @@ -6,6 +6,7 @@ import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsResponseDto; | ... | @@ -6,6 +6,7 @@ import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsResponseDto; |
| 6 | import com.infoloop.tianting.model.dto.MenuDbDTO.MenuDetailDto; | 6 | import com.infoloop.tianting.model.dto.MenuDbDTO.MenuDetailDto; |
| 7 | import com.infoloop.tianting.model.dto.MenuDbDTO.MenuDto; | 7 | import com.infoloop.tianting.model.dto.MenuDbDTO.MenuDto; |
| 8 | import com.infoloop.tianting.model.dto.MenuDbDTO.MenuRefDto; | 8 | import com.infoloop.tianting.model.dto.MenuDbDTO.MenuRefDto; |
| 9 | + | ||
| 9 | import java.util.List; | 10 | import java.util.List; |
| 10 | 11 | ||
| 11 | public interface MenuService { | 12 | public interface MenuService { |
| ... | @@ -21,4 +22,6 @@ public interface MenuService { | ... | @@ -21,4 +22,6 @@ public interface MenuService { |
| 21 | List<MenuRefDto> getClientCustomerMenuRefsByCustomerId(Integer enterpriseId, Integer customerId); | 22 | List<MenuRefDto> getClientCustomerMenuRefsByCustomerId(Integer enterpriseId, Integer customerId); |
| 22 | 23 | ||
| 23 | BatchCreateMenuRefsResponseDto batchCreateMenuRefs(BatchCreateMenuRefsDto batchCreateMenuRefsDto); | 24 | BatchCreateMenuRefsResponseDto batchCreateMenuRefs(BatchCreateMenuRefsDto batchCreateMenuRefsDto); |
| 25 | + | ||
| 26 | + List<Integer> queryMenuSkuIdsByStallId(int enterpriseId, int stallId); | ||
| 24 | } | 27 | } | ... | ... |
| 1 | package com.infoloop.tianting.service; | 1 | package com.infoloop.tianting.service; |
| 2 | 2 | ||
| 3 | import com.infoloop.tianting.model.common.OrderPageResult; | 3 | import com.infoloop.tianting.model.common.OrderPageResult; |
| 4 | -import com.infoloop.tianting.model.common.PageResult; | ||
| 5 | import com.infoloop.tianting.model.dto.OrderDbDTO.BatchUpdateOrderDetailResponse; | 4 | import com.infoloop.tianting.model.dto.OrderDbDTO.BatchUpdateOrderDetailResponse; |
| 6 | -import com.infoloop.tianting.model.dto.OrderDbDTO.getMenuOrderCountDto; | ||
| 7 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto; | 5 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto; |
| 8 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderResponse; | 6 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderResponse; |
| 9 | import com.infoloop.tianting.model.dto.OrderDbDTO.OperatorCreateOrderDto; | 7 | import com.infoloop.tianting.model.dto.OrderDbDTO.OperatorCreateOrderDto; |
| ... | @@ -15,6 +13,8 @@ import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto; | ... | @@ -15,6 +13,8 @@ import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto; |
| 15 | import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByPaginationDto; | 13 | import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByPaginationDto; |
| 16 | import com.infoloop.tianting.model.dto.OrderDbDTO.UpdateOrderDto; | 14 | import com.infoloop.tianting.model.dto.OrderDbDTO.UpdateOrderDto; |
| 17 | import com.infoloop.tianting.model.dto.OrderDbDTO.UpdateOrderResponse; | 15 | import com.infoloop.tianting.model.dto.OrderDbDTO.UpdateOrderResponse; |
| 16 | +import com.infoloop.tianting.model.dto.OrderDbDTO.getMenuOrderCountDto; | ||
| 17 | + | ||
| 18 | import java.util.List; | 18 | import java.util.List; |
| 19 | 19 | ||
| 20 | public interface OrderService { | 20 | public interface OrderService { | ... | ... |
| 1 | package com.infoloop.tianting.service; | 1 | package com.infoloop.tianting.service; |
| 2 | 2 | ||
| 3 | +import com.infoloop.tianting.model.common.PageResult; | ||
| 3 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDto; | 4 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDto; |
| 5 | +import com.infoloop.tianting.model.dto.SkuSellQuantityDTO; | ||
| 6 | +import com.infoloop.tianting.model.vo.SkuSellQuantityStatisticsVO; | ||
| 7 | +import com.infoloop.tianting.model.vo.SkuSellQuantityVO; | ||
| 8 | + | ||
| 9 | +import javax.validation.Valid; | ||
| 4 | import java.util.List; | 10 | import java.util.List; |
| 5 | 11 | ||
| 6 | public interface SkuService { | 12 | public interface SkuService { |
| 7 | 13 | ||
| 8 | List<SkuDto> getSkusByIds(List<Integer> ids); | 14 | List<SkuDto> getSkusByIds(List<Integer> ids); |
| 9 | 15 | ||
| 16 | + SkuSellQuantityStatisticsVO querySkuSellQuantityStatistics(int stallId); | ||
| 17 | + | ||
| 18 | + PageResult<SkuSellQuantityVO> querySkuSellQuantity(SkuSellQuantityDTO.QuerySkuSellQuantityDTO querySkuSellQuantityDTO); | ||
| 19 | + | ||
| 20 | + boolean batchSetSkuSellQuantity(int stallId, SkuSellQuantityDTO.BatchSetSkuSellQuantityDTO batchSetSkuSellQuantityDTO); | ||
| 21 | + | ||
| 22 | + List<SkuSellQuantityVO> querySkuSellQuantityBySkuIds(SkuSellQuantityDTO.@Valid QuerySkuSellQuantityBySkuIdsDTO querySkuSellQuantityBySkuIdsDTO); | ||
| 10 | } | 23 | } | ... | ... |
| 1 | package com.infoloop.tianting.service.client; | 1 | package com.infoloop.tianting.service.client; |
| 2 | 2 | ||
| 3 | import com.infoloop.tianting.SingleResponse; | 3 | import com.infoloop.tianting.SingleResponse; |
| 4 | +import com.infoloop.tianting.SingleSkuResponse; | ||
| 4 | import com.infoloop.tianting.SingleSpecialResponse; | 5 | import com.infoloop.tianting.SingleSpecialResponse; |
| 6 | +import com.infoloop.tianting.clientcustomerorderservice.AddSkusSellQuantitiesRpcRequest; | ||
| 5 | import com.infoloop.tianting.clientcustomerorderservice.BatchCreateOrderOperationRecordsRequest; | 7 | import com.infoloop.tianting.clientcustomerorderservice.BatchCreateOrderOperationRecordsRequest; |
| 6 | import com.infoloop.tianting.clientcustomerorderservice.BatchCreateOrderOperationRecordsResponse; | 8 | import com.infoloop.tianting.clientcustomerorderservice.BatchCreateOrderOperationRecordsResponse; |
| 9 | +import com.infoloop.tianting.clientcustomerorderservice.BatchSaveSkuSellQuantitiesRpcRequest; | ||
| 7 | import com.infoloop.tianting.clientcustomerorderservice.BatchUpdateClientCustomerOrderDetailsRpcRequest; | 10 | import com.infoloop.tianting.clientcustomerorderservice.BatchUpdateClientCustomerOrderDetailsRpcRequest; |
| 8 | import com.infoloop.tianting.clientcustomerorderservice.BatchUpdateClientCustomerOrderDetailsRpcResponse; | 11 | import com.infoloop.tianting.clientcustomerorderservice.BatchUpdateClientCustomerOrderDetailsRpcResponse; |
| 9 | import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderCreation; | 12 | import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderCreation; |
| ... | @@ -13,7 +16,6 @@ import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderModif | ... | @@ -13,7 +16,6 @@ import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderModif |
| 13 | import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderServiceRpcGrpc; | 16 | import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderServiceRpcGrpc; |
| 14 | import com.infoloop.tianting.clientcustomerorderservice.CloseTimeType; | 17 | import com.infoloop.tianting.clientcustomerorderservice.CloseTimeType; |
| 15 | import com.infoloop.tianting.clientcustomerorderservice.CreateClientCustomerOrderRpcRequest; | 18 | import com.infoloop.tianting.clientcustomerorderservice.CreateClientCustomerOrderRpcRequest; |
| 16 | -import com.infoloop.tianting.clientcustomerorderservice.CreateClientCustomerOrderRpcResponse; | ||
| 17 | import com.infoloop.tianting.clientcustomerorderservice.CustomerNotice; | 19 | import com.infoloop.tianting.clientcustomerorderservice.CustomerNotice; |
| 18 | import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderByIdRpcRequest; | 20 | import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderByIdRpcRequest; |
| 19 | import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByIdsRpcRequest; | 21 | import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByIdsRpcRequest; |
| ... | @@ -28,13 +30,26 @@ import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; | ... | @@ -28,13 +30,26 @@ import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; |
| 28 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByConditionRpcRequest; | 30 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByConditionRpcRequest; |
| 29 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcRequest; | 31 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcRequest; |
| 30 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcResponse; | 32 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcResponse; |
| 33 | +import com.infoloop.tianting.clientcustomerorderservice.QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest; | ||
| 34 | +import com.infoloop.tianting.clientcustomerorderservice.QuerySkuSellQuantitiesByStallRpcRequest; | ||
| 31 | import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum; | 35 | import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum; |
| 32 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse; | 36 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse; |
| 33 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse; | 37 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse; |
| 38 | +import com.infoloop.tianting.clientcustomerorderservice.SingleSkuSellQuantityRpcResponse; | ||
| 39 | +import com.infoloop.tianting.clientcustomerorderservice.SkuSellQuantity; | ||
| 40 | +import com.infoloop.tianting.clientcustomerorderservice.SkuSellQuantityModification; | ||
| 34 | import com.infoloop.tianting.clientcustomerorderservice.UpdateClientCustomerOrderRpcRequest; | 41 | import com.infoloop.tianting.clientcustomerorderservice.UpdateClientCustomerOrderRpcRequest; |
| 35 | import com.infoloop.tianting.clientcustomerorderservice.UpdateClientCustomerOrderRpcResponse; | 42 | import com.infoloop.tianting.clientcustomerorderservice.UpdateClientCustomerOrderRpcResponse; |
| 36 | import com.infoloop.tianting.context.LoginContextHolder; | 43 | import com.infoloop.tianting.context.LoginContextHolder; |
| 37 | import com.infoloop.tianting.enums.OrderTypeEnum; | 44 | import com.infoloop.tianting.enums.OrderTypeEnum; |
| 45 | +import com.infoloop.tianting.exception.ClientEndExceptions; | ||
| 46 | +import com.infoloop.tianting.exception.ErrorCodeEnum; | ||
| 47 | +import com.infoloop.tianting.logic.delay.DelayedQueue; | ||
| 48 | +import com.infoloop.tianting.logic.delay.OrderAutoCancelDelayTask; | ||
| 49 | +import com.infoloop.tianting.logic.delay.param.AutoCancelParam; | ||
| 50 | +import com.infoloop.tianting.menuservice.CloseTimeTypeEnum; | ||
| 51 | +import com.infoloop.tianting.model.bo.AddSkusSellQuantityBO; | ||
| 52 | +import com.infoloop.tianting.model.bo.SkuSellQuantityBO; | ||
| 38 | import com.infoloop.tianting.model.dto.OperationDTO.BatchOperationDto; | 53 | import com.infoloop.tianting.model.dto.OperationDTO.BatchOperationDto; |
| 39 | import com.infoloop.tianting.model.dto.OperationDTO.SingleOperationDto; | 54 | import com.infoloop.tianting.model.dto.OperationDTO.SingleOperationDto; |
| 40 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDetailDto; | 55 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDetailDto; |
| ... | @@ -59,7 +74,10 @@ import javax.annotation.Nullable; | ... | @@ -59,7 +74,10 @@ import javax.annotation.Nullable; |
| 59 | import java.time.LocalDate; | 74 | import java.time.LocalDate; |
| 60 | import java.time.ZoneOffset; | 75 | import java.time.ZoneOffset; |
| 61 | import java.util.ArrayList; | 76 | import java.util.ArrayList; |
| 77 | +import java.util.HashMap; | ||
| 62 | import java.util.List; | 78 | import java.util.List; |
| 79 | +import java.util.concurrent.TimeUnit; | ||
| 80 | +import java.util.function.Function; | ||
| 63 | import java.util.stream.Collectors; | 81 | import java.util.stream.Collectors; |
| 64 | 82 | ||
| 65 | @Slf4j | 83 | @Slf4j |
| ... | @@ -72,6 +90,7 @@ public class OrderServiceRpcClient { | ... | @@ -72,6 +90,7 @@ public class OrderServiceRpcClient { |
| 72 | private final SkuServiceRpcClient skuServiceRpcClient; | 90 | private final SkuServiceRpcClient skuServiceRpcClient; |
| 73 | private final OperatorServiceRpcClient operatorServiceRpcClient; | 91 | private final OperatorServiceRpcClient operatorServiceRpcClient; |
| 74 | private final RedissonClient redissonClient; | 92 | private final RedissonClient redissonClient; |
| 93 | + private final DelayedQueue<AutoCancelParam> delayedQueue; | ||
| 75 | 94 | ||
| 76 | @Nullable | 95 | @Nullable |
| 77 | public SingleClientCustomerOrderRpcResponse getOrderById(Integer orderId) { | 96 | public SingleClientCustomerOrderRpcResponse getOrderById(Integer orderId) { |
| ... | @@ -149,6 +168,23 @@ public class OrderServiceRpcClient { | ... | @@ -149,6 +168,23 @@ public class OrderServiceRpcClient { |
| 149 | return orderServiceRpcBlockingStub.updateClientCustomerOrder(request); | 168 | return orderServiceRpcBlockingStub.updateClientCustomerOrder(request); |
| 150 | } | 169 | } |
| 151 | 170 | ||
| 171 | + public boolean updateClientCustomerOrderCancel(int enterpriseId, int id) { | ||
| 172 | + final var modification = ClientCustomerOrderModification.newBuilder() | ||
| 173 | + .setId(id) | ||
| 174 | + .setShouldUpdateStatus(true) | ||
| 175 | + .setStatus(OrderStatusEnum.ORDER_CANCELED) | ||
| 176 | + .setShouldUpdatePayStatus(true) | ||
| 177 | + .setPayStatus(PayStatusEnum.PAY_CANCELED) | ||
| 178 | + .build(); | ||
| 179 | + final var request = UpdateClientCustomerOrderRpcRequest.newBuilder() | ||
| 180 | + .setEnterpriseId(enterpriseId) | ||
| 181 | + .setUpdatedBy(0) | ||
| 182 | + .setUpdateSource(OrderSourceEnum.STALL) | ||
| 183 | + .setModification(modification) | ||
| 184 | + .build(); | ||
| 185 | + return orderServiceRpcBlockingStub.updateClientCustomerOrder(request).getIsUpdated(); | ||
| 186 | + } | ||
| 187 | + | ||
| 152 | public UpdateClientCustomerOrderRpcResponse updateClientCustomerOrderPaymentResult(SingleClientCustomerOrderRpcResponse order, ClientCustomerOrderModification modification) { | 188 | public UpdateClientCustomerOrderRpcResponse updateClientCustomerOrderPaymentResult(SingleClientCustomerOrderRpcResponse order, ClientCustomerOrderModification modification) { |
| 153 | final var request = UpdateClientCustomerOrderRpcRequest.newBuilder() | 189 | final var request = UpdateClientCustomerOrderRpcRequest.newBuilder() |
| 154 | .setEnterpriseId(order.getEnterpriseId()) | 190 | .setEnterpriseId(order.getEnterpriseId()) |
| ... | @@ -160,16 +196,15 @@ public class OrderServiceRpcClient { | ... | @@ -160,16 +196,15 @@ public class OrderServiceRpcClient { |
| 160 | } | 196 | } |
| 161 | 197 | ||
| 162 | 198 | ||
| 163 | - public BatchUpdateClientCustomerOrderDetailsRpcResponse batchUpdateClientCustomerOrderDetails( | 199 | + public BatchUpdateClientCustomerOrderDetailsRpcResponse batchUpdateClientCustomerOrderDetails(OrderDetailBatchUpdateDto orderDetailBatchUpdateDto) { |
| 164 | - OrderDetailBatchUpdateDto orderDetailBatchUpdateDto) { | ||
| 165 | final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); | 200 | final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); |
| 166 | final var operator = operatorServiceRpcClient.getCOperatorById(operatorLoginInfo.getId()); | 201 | final var operator = operatorServiceRpcClient.getCOperatorById(operatorLoginInfo.getId()); |
| 167 | - List<Integer> idsOfNeedUpdateMenuDetails = new ArrayList<>(); | 202 | + final var idsOfNeedUpdateMenuDetails = new ArrayList<Integer>(); |
| 168 | - List<Integer> idsOfAddCount = new ArrayList<>(); | 203 | + final var idsOfAddCount = new ArrayList<Integer>(); |
| 169 | - List<OrderDetailDto> orgionalOrderDetails = new ArrayList<>(); | 204 | + List<OrderDetailDto> originalOrderDetails = new ArrayList<>(); |
| 170 | List<OrderDetailDto> newOrderDetails; | 205 | List<OrderDetailDto> newOrderDetails; |
| 171 | final var modifications = orderDetailBatchUpdateDto.getDetails().stream().map(d -> { | 206 | final var modifications = orderDetailBatchUpdateDto.getDetails().stream().map(d -> { |
| 172 | - MealDetail mealDetail = MealDetail.newBuilder().build(); | 207 | + var mealDetail = MealDetail.newBuilder().build(); |
| 173 | Integer menuDetailId = 0; | 208 | Integer menuDetailId = 0; |
| 174 | int mealId = 0; | 209 | int mealId = 0; |
| 175 | int categoryId = 0; | 210 | int categoryId = 0; |
| ... | @@ -178,8 +213,7 @@ public class OrderServiceRpcClient { | ... | @@ -178,8 +213,7 @@ public class OrderServiceRpcClient { |
| 178 | if (d.getShouldUpdateMenuDetailId()) { | 213 | if (d.getShouldUpdateMenuDetailId()) { |
| 179 | idsOfNeedUpdateMenuDetails.add(d.getId()); | 214 | idsOfNeedUpdateMenuDetails.add(d.getId()); |
| 180 | menuDetailId = d.getMenuDetailId(); | 215 | menuDetailId = d.getMenuDetailId(); |
| 181 | - final var menuDetail = menuServiceRpcClient.getMenuDetailById( | 216 | + final var menuDetail = menuServiceRpcClient.getMenuDetailById(operatorLoginInfo.getEnterpriseId(), menuDetailId).getResponse(); |
| 182 | - operatorLoginInfo.getEnterpriseId(), menuDetailId).getResponse(); | ||
| 183 | mealId = menuDetail.getMealId(); | 217 | mealId = menuDetail.getMealId(); |
| 184 | categoryId = menuDetail.getCategoryId(); | 218 | categoryId = menuDetail.getCategoryId(); |
| 185 | skuId = menuDetail.getSkuId(); | 219 | skuId = menuDetail.getSkuId(); |
| ... | @@ -190,8 +224,7 @@ public class OrderServiceRpcClient { | ... | @@ -190,8 +224,7 @@ public class OrderServiceRpcClient { |
| 190 | final var skuAvoids = rpcSkus.get(0).getAvoidsList().stream().map(SingleResponse::getName).collect(Collectors.toList()); | 224 | final var skuAvoids = rpcSkus.get(0).getAvoidsList().stream().map(SingleResponse::getName).collect(Collectors.toList()); |
| 191 | final var tastes = rpcSkus.get(0).getTastesList().stream().map(SingleResponse::getName).collect(Collectors.toList()); | 225 | final var tastes = rpcSkus.get(0).getTastesList().stream().map(SingleResponse::getName).collect(Collectors.toList()); |
| 192 | final var efficacies = rpcSkus.get(0).getEfficaciesList().stream().map(SingleResponse::getName).collect(Collectors.toList()); | 226 | final var efficacies = rpcSkus.get(0).getEfficaciesList().stream().map(SingleResponse::getName).collect(Collectors.toList()); |
| 193 | - final var allergies = rpcSkus.get(0).getAllergiesList().stream().map( | 227 | + final var allergies = rpcSkus.get(0).getAllergiesList().stream().map(SingleSpecialResponse::getName).collect(Collectors.toList()); |
| 194 | - SingleSpecialResponse::getName).collect(Collectors.toList()); | ||
| 195 | final var skuDoctors = rpcSkus.get(0).getDoctorsList().stream().map(SingleSpecialResponse::getName).collect(Collectors.toList()); | 228 | final var skuDoctors = rpcSkus.get(0).getDoctorsList().stream().map(SingleSpecialResponse::getName).collect(Collectors.toList()); |
| 196 | mealDetail = MealDetail.newBuilder() | 229 | mealDetail = MealDetail.newBuilder() |
| 197 | .setBasicMaterials(rpcSkus.get(0).getBasicMaterials()) | 230 | .setBasicMaterials(rpcSkus.get(0).getBasicMaterials()) |
| ... | @@ -249,8 +282,7 @@ public class OrderServiceRpcClient { | ... | @@ -249,8 +282,7 @@ public class OrderServiceRpcClient { |
| 249 | totalIds.addAll(idsOfAddCount); | 282 | totalIds.addAll(idsOfAddCount); |
| 250 | if (!idsOfNeedUpdateMenuDetails.isEmpty() || !idsOfAddCount.isEmpty()) { | 283 | if (!idsOfNeedUpdateMenuDetails.isEmpty() || !idsOfAddCount.isEmpty()) { |
| 251 | final var orgionalResponseList = getClientCustomerOrderDetailsByIds(totalIds); | 284 | final var orgionalResponseList = getClientCustomerOrderDetailsByIds(totalIds); |
| 252 | - orgionalOrderDetails = orgionalResponseList.stream().map(d -> | 285 | + originalOrderDetails = orgionalResponseList.stream().map(d -> OrderDetailDto.builder() |
| 253 | - OrderDetailDto.builder() | ||
| 254 | .id(d.getId()) | 286 | .id(d.getId()) |
| 255 | .count(d.getCount()) | 287 | .count(d.getCount()) |
| 256 | .categoryId(d.getCategoryId()) | 288 | .categoryId(d.getCategoryId()) |
| ... | @@ -287,7 +319,6 @@ public class OrderServiceRpcClient { | ... | @@ -287,7 +319,6 @@ public class OrderServiceRpcClient { |
| 287 | final var res = orderServiceRpcBlockingStub.batchUpdateClientCustomerOrderDetails(request); | 319 | final var res = orderServiceRpcBlockingStub.batchUpdateClientCustomerOrderDetails(request); |
| 288 | if (res.getIsUpdated()) { | 320 | if (res.getIsUpdated()) { |
| 289 | if (!idsOfNeedUpdateMenuDetails.isEmpty() || !idsOfAddCount.isEmpty()) { | 321 | if (!idsOfNeedUpdateMenuDetails.isEmpty() || !idsOfAddCount.isEmpty()) { |
| 290 | - | ||
| 291 | final var newResponseList = getClientCustomerOrderDetailsByIds(totalIds); | 322 | final var newResponseList = getClientCustomerOrderDetailsByIds(totalIds); |
| 292 | newOrderDetails = newResponseList.stream().map(d -> | 323 | newOrderDetails = newResponseList.stream().map(d -> |
| 293 | OrderDetailDto.builder() | 324 | OrderDetailDto.builder() |
| ... | @@ -323,19 +354,18 @@ public class OrderServiceRpcClient { | ... | @@ -323,19 +354,18 @@ public class OrderServiceRpcClient { |
| 323 | .updatedAt(DateUtil.formatDate(d.getUpdatedAt())) | 354 | .updatedAt(DateUtil.formatDate(d.getUpdatedAt())) |
| 324 | .updatedBy(d.getUpdatedBy()) | 355 | .updatedBy(d.getUpdatedBy()) |
| 325 | .build()).collect(Collectors.toList()); | 356 | .build()).collect(Collectors.toList()); |
| 326 | - | ||
| 327 | // 替换菜品的操作记录 | 357 | // 替换菜品的操作记录 |
| 328 | List<SingleOperationDto> operations = new ArrayList<>(); | 358 | List<SingleOperationDto> operations = new ArrayList<>(); |
| 329 | - for (OrderDetailDto orgionalDetail : orgionalOrderDetails) { | 359 | + for (OrderDetailDto originalDetail : originalOrderDetails) { |
| 330 | OrderOperationType orderOperationType = OrderOperationType.UNKNOWN_OPERATION_TYPE; | 360 | OrderOperationType orderOperationType = OrderOperationType.UNKNOWN_OPERATION_TYPE; |
| 331 | - if (idsOfNeedUpdateMenuDetails.contains(orgionalDetail.getId())) { | 361 | + if (idsOfNeedUpdateMenuDetails.contains(originalDetail.getId())) { |
| 332 | orderOperationType = OrderOperationType.REPLACE_DISHES; | 362 | orderOperationType = OrderOperationType.REPLACE_DISHES; |
| 333 | - } else if (idsOfAddCount.contains(orgionalDetail.getId())) { | 363 | + } else if (idsOfAddCount.contains(originalDetail.getId())) { |
| 334 | orderOperationType = OrderOperationType.ADD_DISHES; | 364 | orderOperationType = OrderOperationType.ADD_DISHES; |
| 335 | } | 365 | } |
| 336 | - String orgionalDetailStr = ""; | 366 | + String originalDetailStr; |
| 337 | String newDetailStr = ""; | 367 | String newDetailStr = ""; |
| 338 | - final var newDetail = newOrderDetails.stream().filter(n -> n.getId().equals(orgionalDetail.getId())).findFirst(); | 368 | + final var newDetail = newOrderDetails.stream().filter(n -> n.getId().equals(originalDetail.getId())).findFirst(); |
| 339 | if (newDetail.isPresent()) { | 369 | if (newDetail.isPresent()) { |
| 340 | final var newOrderDetailOperation = OrderDetailOperationDto.builder() | 370 | final var newOrderDetailOperation = OrderDetailOperationDto.builder() |
| 341 | .id(newDetail.get().getId()) | 371 | .id(newDetail.get().getId()) |
| ... | @@ -347,23 +377,23 @@ public class OrderServiceRpcClient { | ... | @@ -347,23 +377,23 @@ public class OrderServiceRpcClient { |
| 347 | .build(); | 377 | .build(); |
| 348 | newDetailStr = JsonUtil.writeAsJson(List.of(newOrderDetailOperation)); | 378 | newDetailStr = JsonUtil.writeAsJson(List.of(newOrderDetailOperation)); |
| 349 | } | 379 | } |
| 350 | - final var orgionalOrderDetailOperation = OrderDetailOperationDto.builder() | 380 | + final var originalOrderDetailOperation = OrderDetailOperationDto.builder() |
| 351 | - .id(orgionalDetail.getId()) | 381 | + .id(originalDetail.getId()) |
| 352 | - .skuId(orgionalDetail.getSkuId()) | 382 | + .skuId(originalDetail.getSkuId()) |
| 353 | - .skuName(orgionalDetail.getShowName()) | 383 | + .skuName(originalDetail.getShowName()) |
| 354 | - .count(orgionalDetail.getCount()) | 384 | + .count(originalDetail.getCount()) |
| 355 | - .adjustSkuRemark(orgionalDetail.getAdjustSkuRemark()) | 385 | + .adjustSkuRemark(originalDetail.getAdjustSkuRemark()) |
| 356 | - .serveStatus(orgionalDetail.getServeStatus().name()) | 386 | + .serveStatus(originalDetail.getServeStatus().name()) |
| 357 | .build(); | 387 | .build(); |
| 358 | - orgionalDetailStr = JsonUtil.writeAsJson(List.of(orgionalOrderDetailOperation)); | 388 | + originalDetailStr = JsonUtil.writeAsJson(List.of(originalOrderDetailOperation)); |
| 359 | final var operation = SingleOperationDto.builder() | 389 | final var operation = SingleOperationDto.builder() |
| 360 | - .orderId(orgionalDetail.getOrderId()) | 390 | + .orderId(originalDetail.getOrderId()) |
| 361 | .shouldCreateAdjustOrderDetailJson(true) | 391 | .shouldCreateAdjustOrderDetailJson(true) |
| 362 | .shouldCreateOriginalOrderDetailJson(true) | 392 | .shouldCreateOriginalOrderDetailJson(true) |
| 363 | .shouldCreateAdjustOrderJson(false) | 393 | .shouldCreateAdjustOrderJson(false) |
| 364 | .shouldCreateOriginalOrderJson(false) | 394 | .shouldCreateOriginalOrderJson(false) |
| 365 | .adjustOrderDetailJson(newDetailStr) | 395 | .adjustOrderDetailJson(newDetailStr) |
| 366 | - .originalOrderDetailJson(orgionalDetailStr) | 396 | + .originalOrderDetailJson(originalDetailStr) |
| 367 | .type(orderOperationType) | 397 | .type(orderOperationType) |
| 368 | .build(); | 398 | .build(); |
| 369 | operations.add(operation); | 399 | operations.add(operation); |
| ... | @@ -381,9 +411,7 @@ public class OrderServiceRpcClient { | ... | @@ -381,9 +411,7 @@ public class OrderServiceRpcClient { |
| 381 | return res; | 411 | return res; |
| 382 | } | 412 | } |
| 383 | 413 | ||
| 384 | - public BatchCreateOrderOperationRecordsResponse batchCreateOrderOperationRecords( | 414 | + public BatchCreateOrderOperationRecordsResponse batchCreateOrderOperationRecords(BatchOperationDto batchOperationDto) { |
| 385 | - BatchOperationDto batchOperationDto) { | ||
| 386 | - | ||
| 387 | final var request = BatchCreateOrderOperationRecordsRequest.newBuilder() | 415 | final var request = BatchCreateOrderOperationRecordsRequest.newBuilder() |
| 388 | .addAllCreations(batchOperationDto.getCreations().stream().map(c -> | 416 | .addAllCreations(batchOperationDto.getCreations().stream().map(c -> |
| 389 | OrderOperationRecordCreation.newBuilder() | 417 | OrderOperationRecordCreation.newBuilder() |
| ... | @@ -407,8 +435,7 @@ public class OrderServiceRpcClient { | ... | @@ -407,8 +435,7 @@ public class OrderServiceRpcClient { |
| 407 | 435 | ||
| 408 | } | 436 | } |
| 409 | 437 | ||
| 410 | - public QueryClientCustomerOrdersByPaginationRpcResponse queryClientCustomerOrdersByPagination( | 438 | + public QueryClientCustomerOrdersByPaginationRpcResponse queryClientCustomerOrdersByPagination(QueryOrderByPaginationDto queryOrderDto) { |
| 411 | - QueryOrderByPaginationDto queryOrderDto) { | ||
| 412 | final var request = QueryClientCustomerOrdersByPaginationRpcRequest.newBuilder() | 439 | final var request = QueryClientCustomerOrdersByPaginationRpcRequest.newBuilder() |
| 413 | .setKeyword(queryOrderDto.getKeyword() == null ? "" : queryOrderDto.getKeyword()) | 440 | .setKeyword(queryOrderDto.getKeyword() == null ? "" : queryOrderDto.getKeyword()) |
| 414 | .setPageNo(queryOrderDto.getPn()) | 441 | .setPageNo(queryOrderDto.getPn()) |
| ... | @@ -536,14 +563,95 @@ public class OrderServiceRpcClient { | ... | @@ -536,14 +563,95 @@ public class OrderServiceRpcClient { |
| 536 | .setShouldCreateOrderDetails(true) | 563 | .setShouldCreateOrderDetails(true) |
| 537 | .addAllOrderDetails(orderDetails) | 564 | .addAllOrderDetails(orderDetails) |
| 538 | .build(); | 565 | .build(); |
| 539 | - CreateClientCustomerOrderRpcResponse orderResponse = orderServiceRpcBlockingStub | 566 | + final var menuById = menuServiceRpcClient.getMenuById(createOrderDto.getEnterpriseId(), createOrderDto.getMenuId()); |
| 567 | + if (menuById.getResponse().getOrderRuleJson().getCloseTimeType() == CloseTimeTypeEnum.IMMEDIATELY) { | ||
| 568 | + final var skuIds = createOrderDto.getOrderDetailDtos().stream().map(CreateOrderDetailDto::getSkuId).collect(Collectors.toList()); | ||
| 569 | + final var skuSellQuantities = this.querySkuSellQuantitiesByStallAndSkuIds(createOrderDto.getEnterpriseId(), createOrderDto.getStallId(), skuIds); | ||
| 570 | + final var skuSellQuantityMap = skuSellQuantities.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity())); | ||
| 571 | + final var skuMap = skuServiceRpcClient.getSkusByIds(skuIds).stream().collect(Collectors.toMap(SingleSkuResponse::getId, Function.identity())); | ||
| 572 | + final var soldOutSkus = new ArrayList<String>(); | ||
| 573 | + final var skuStockMap = new HashMap<String, Integer>(); | ||
| 574 | + for (var orderDetail : createOrderDto.getOrderDetailDtos()) { | ||
| 575 | + final var skuSellQuantityRpcResponse = skuSellQuantityMap.get(orderDetail.getSkuId()); | ||
| 576 | + if (skuSellQuantityRpcResponse == null) { | ||
| 577 | + log.error("skuSellQuantityRpcResponse is null; stallId:{}, skuId:{}", createOrderDto.getStallId(), orderDetail.getSkuId()); | ||
| 578 | + soldOutSkus.add(skuMap.get(orderDetail.getSkuId()).getName()); | ||
| 579 | + continue; | ||
| 580 | + } | ||
| 581 | + if ((skuSellQuantityRpcResponse.getTodaySellQuantity() + orderDetail.getCount()) > skuSellQuantityRpcResponse.getMaxSellQuantity()) { | ||
| 582 | + log.error("skuSellQuantityRpcResponse stock no enough; stallId:{}, skuId:{}, count:{}", createOrderDto.getStallId(), orderDetail.getSkuId(), orderDetail.getCount()); | ||
| 583 | + skuStockMap.put(skuMap.get(orderDetail.getSkuId()).getName(), skuSellQuantityRpcResponse.getMaxSellQuantity() - skuSellQuantityRpcResponse.getTodaySellQuantity()); | ||
| 584 | + continue; | ||
| 585 | + } | ||
| 586 | + } | ||
| 587 | + if (!soldOutSkus.isEmpty()) { | ||
| 588 | + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.SKUS_SOLD_OUT_TODAY, String.join(",", soldOutSkus)); | ||
| 589 | + } | ||
| 590 | + if (!skuStockMap.isEmpty()) { | ||
| 591 | + final var noEnoughSkus = String.join(", ", skuStockMap.keySet()); | ||
| 592 | + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.SKUS_STOCK_NO_ENOUGH_TODAY, noEnoughSkus); | ||
| 593 | + } | ||
| 594 | + } | ||
| 595 | + final var orderResponse = orderServiceRpcBlockingStub | ||
| 540 | .createClientCustomerOrder(CreateClientCustomerOrderRpcRequest.newBuilder() | 596 | .createClientCustomerOrder(CreateClientCustomerOrderRpcRequest.newBuilder() |
| 541 | .setCreation(creation) | 597 | .setCreation(creation) |
| 542 | .setCreationSource(OrderSourceEnum.forNumber(createOrderDto.getCreationSource())) | 598 | .setCreationSource(OrderSourceEnum.forNumber(createOrderDto.getCreationSource())) |
| 543 | .setEnterpriseId(createOrderDto.getEnterpriseId()) | 599 | .setEnterpriseId(createOrderDto.getEnterpriseId()) |
| 544 | .setCreatedBy(createOrderDto.getCreatedBy()) | 600 | .setCreatedBy(createOrderDto.getCreatedBy()) |
| 545 | .build()); | 601 | .build()); |
| 602 | + if (orderResponse.getIsCreated() && menuById.getResponse().getOrderRuleJson().getCloseTimeType() == CloseTimeTypeEnum.IMMEDIATELY) { | ||
| 603 | + final var isSuccess = this.addSkusSellQuantities(createOrderDto.getEnterpriseId(), createOrderDto.getStallId(), | ||
| 604 | + orderDetails.stream().map(e -> AddSkusSellQuantityBO.builder() | ||
| 605 | + .skuId(e.getSkuId()) | ||
| 606 | + .quantity(e.getCount()) | ||
| 607 | + .build()).collect(Collectors.toList())); | ||
| 608 | + if (isSuccess) { | ||
| 609 | + final var autoCancelParam = new AutoCancelParam(); | ||
| 610 | + autoCancelParam.setOrderId(orderResponse.getId()); | ||
| 611 | + delayedQueue.addToQueue(OrderAutoCancelDelayTask.AUTO_CANCEL_ORDER_DELAY_QUEUE, autoCancelParam, 10, TimeUnit.MINUTES); | ||
| 612 | + } | ||
| 613 | + } | ||
| 546 | return CreateOrderResponse.builder().id(orderResponse.getId()).isCreated(true).build(); | 614 | return CreateOrderResponse.builder().id(orderResponse.getId()).isCreated(true).build(); |
| 547 | } | 615 | } |
| 548 | 616 | ||
| 617 | + | ||
| 618 | + public List<SingleSkuSellQuantityRpcResponse> querySkuSellQuantitiesByStall(int enterpriseId, int stallId) { | ||
| 619 | + return orderServiceRpcBlockingStub.querySkuSellQuantitiesByStall(QuerySkuSellQuantitiesByStallRpcRequest.newBuilder() | ||
| 620 | + .setEnterpriseId(enterpriseId) | ||
| 621 | + .setStallId(stallId) | ||
| 622 | + .build()).getResponsesList(); | ||
| 623 | + } | ||
| 624 | + | ||
| 625 | + public List<SingleSkuSellQuantityRpcResponse> querySkuSellQuantitiesByStallAndSkuIds(int enterpriseId, int stallId, List<Integer> skuIds) { | ||
| 626 | + return orderServiceRpcBlockingStub.querySkuSellQuantitiesByStallAndSkuIds(QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest.newBuilder() | ||
| 627 | + .setEnterpriseId(enterpriseId) | ||
| 628 | + .setStallId(stallId) | ||
| 629 | + .addAllSkuIds(skuIds) | ||
| 630 | + .build()).getResponsesList(); | ||
| 631 | + } | ||
| 632 | + | ||
| 633 | + public boolean batchSaveSkuSellQuantities(int enterpriseId, int stallId, List<SkuSellQuantityBO> skuSellQuantityBOs) { | ||
| 634 | + return orderServiceRpcBlockingStub.batchSaveSkuSellQuantities(BatchSaveSkuSellQuantitiesRpcRequest.newBuilder() | ||
| 635 | + .setEnterpriseId(enterpriseId) | ||
| 636 | + .setUpdatedBy(stallId) | ||
| 637 | + .addAllSkuSellQuantityModifications(skuSellQuantityBOs.stream().map(e -> SkuSellQuantityModification.newBuilder() | ||
| 638 | + .setId(e.getId() == null ? 0 : e.getId()) | ||
| 639 | + .setStallId(stallId) | ||
| 640 | + .setSkuId(e.getSkuId()) | ||
| 641 | + .setMaxSellQuantity(e.getMaxSellQuantity()) | ||
| 642 | + .build()).collect(Collectors.toList())) | ||
| 643 | + .build()).getIsSaved(); | ||
| 644 | + } | ||
| 645 | + | ||
| 646 | + public boolean addSkusSellQuantities(int enterpriseId, int stallId, List<AddSkusSellQuantityBO> skuSellQuantityBOs) { | ||
| 647 | + return orderServiceRpcBlockingStub.addSkusSellQuantities(AddSkusSellQuantitiesRpcRequest.newBuilder() | ||
| 648 | + .setEnterpriseId(enterpriseId) | ||
| 649 | + .setStallId(stallId) | ||
| 650 | + .addAllSkuSellQuantities(skuSellQuantityBOs.stream().map(e -> SkuSellQuantity.newBuilder() | ||
| 651 | + .setSkuId(e.getSkuId()) | ||
| 652 | + .setQuantity(e.getQuantity()) | ||
| 653 | + .build()).collect(Collectors.toList())) | ||
| 654 | + .build()).getIsAdded(); | ||
| 655 | + } | ||
| 656 | + | ||
| 549 | } | 657 | } | ... | ... |
| ... | @@ -8,8 +8,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; | ... | @@ -8,8 +8,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; |
| 8 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; | 8 | import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
| 9 | import com.fasterxml.jackson.dataformat.xml.XmlMapper; | 9 | import com.fasterxml.jackson.dataformat.xml.XmlMapper; |
| 10 | import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderModification; | 10 | import com.infoloop.tianting.clientcustomerorderservice.ClientCustomerOrderModification; |
| 11 | +import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; | ||
| 11 | import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; | 12 | import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; |
| 12 | import com.infoloop.tianting.config.BusinessConfig; | 13 | import com.infoloop.tianting.config.BusinessConfig; |
| 14 | +import com.infoloop.tianting.exception.ClientEndExceptions; | ||
| 15 | +import com.infoloop.tianting.exception.ErrorCodeEnum; | ||
| 13 | import com.infoloop.tianting.model.dto.PayDTO.PayInformRequestDto; | 16 | import com.infoloop.tianting.model.dto.PayDTO.PayInformRequestDto; |
| 14 | import com.infoloop.tianting.model.dto.PayDTO.PayResponseDto; | 17 | import com.infoloop.tianting.model.dto.PayDTO.PayResponseDto; |
| 15 | import com.infoloop.tianting.model.dto.PayDTO.ThirdPartyPayInformRequestDto; | 18 | import com.infoloop.tianting.model.dto.PayDTO.ThirdPartyPayInformRequestDto; |
| ... | @@ -49,6 +52,11 @@ public class PayServiceClient { | ... | @@ -49,6 +52,11 @@ public class PayServiceClient { |
| 49 | private String clientId; | 52 | private String clientId; |
| 50 | 53 | ||
| 51 | public PayResponseDto payInform(PayInformRequestDto payRequestDto) { | 54 | public PayResponseDto payInform(PayInformRequestDto payRequestDto) { |
| 55 | + final var orderById = orderServiceRpcClient.getOrderById(Integer.valueOf(payRequestDto.getOrderId())); | ||
| 56 | + if (orderById == null || orderById.getPayStatus() == PayStatusEnum.PAY_CANCELED || orderById.getStatus() == OrderStatusEnum.ORDER_CANCELED) { | ||
| 57 | + log.info("Order {} not found or canceled, skipping.", payRequestDto.getOrderId()); | ||
| 58 | + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_CANCEL); | ||
| 59 | + } | ||
| 52 | String url = businessConfig.getPayUrl(); | 60 | String url = businessConfig.getPayUrl(); |
| 53 | String requestDate = DateUtil.formatDate(LocalDateTime.now(), DateUtil.YMDHMS); | 61 | String requestDate = DateUtil.formatDate(LocalDateTime.now(), DateUtil.YMDHMS); |
| 54 | ThirdPartyPayInformRequestDto jsonData = buildRequestData(payRequestDto, requestDate); | 62 | ThirdPartyPayInformRequestDto jsonData = buildRequestData(payRequestDto, requestDate); | ... | ... |
| ... | @@ -2,6 +2,7 @@ package com.infoloop.tianting.service.client; | ... | @@ -2,6 +2,7 @@ package com.infoloop.tianting.service.client; |
| 2 | 2 | ||
| 3 | import com.infoloop.tianting.GeDishSkuByIdsRpcResponse; | 3 | import com.infoloop.tianting.GeDishSkuByIdsRpcResponse; |
| 4 | import com.infoloop.tianting.GetSkusByIdsRpcRequest; | 4 | import com.infoloop.tianting.GetSkusByIdsRpcRequest; |
| 5 | +import com.infoloop.tianting.SingleSkuResponse; | ||
| 5 | import com.infoloop.tianting.SkuServiceProtoRpcGrpc; | 6 | import com.infoloop.tianting.SkuServiceProtoRpcGrpc; |
| 6 | import lombok.RequiredArgsConstructor; | 7 | import lombok.RequiredArgsConstructor; |
| 7 | import org.springframework.beans.factory.annotation.Autowired; | 8 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | @@ -21,4 +22,12 @@ public class SkuServiceRpcClient { | ... | @@ -21,4 +22,12 @@ public class SkuServiceRpcClient { |
| 21 | .build(); | 22 | .build(); |
| 22 | return skuServiceProtoRpcBlockingStub.getDishSkusByIds(request); | 23 | return skuServiceProtoRpcBlockingStub.getDishSkusByIds(request); |
| 23 | } | 24 | } |
| 25 | + | ||
| 26 | + public List<SingleSkuResponse> getSkusByIds(List<Integer> ids) { | ||
| 27 | + final var request = GetSkusByIdsRpcRequest.newBuilder() | ||
| 28 | + .addAllIds(ids) | ||
| 29 | + .setIncludeDeleted(false) | ||
| 30 | + .build(); | ||
| 31 | + return skuServiceProtoRpcBlockingStub.getSkusByIds(request).getResponseList(); | ||
| 32 | + } | ||
| 24 | } | 33 | } | ... | ... |
| 1 | package com.infoloop.tianting.service.impl; | 1 | package com.infoloop.tianting.service.impl; |
| 2 | 2 | ||
| 3 | +import com.infoloop.tianting.context.LoginContextHolder; | ||
| 4 | +import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse; | ||
| 5 | +import com.infoloop.tianting.menuservice.SingleMenuRpcResponse; | ||
| 3 | import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsDto; | 6 | import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsDto; |
| 4 | import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsResponseDto; | 7 | import com.infoloop.tianting.model.dto.MenuDbDTO.BatchCreateMenuRefsResponseDto; |
| 5 | import com.infoloop.tianting.model.dto.MenuDbDTO.DishRuleJson; | 8 | import com.infoloop.tianting.model.dto.MenuDbDTO.DishRuleJson; |
| ... | @@ -197,4 +200,10 @@ public class MenuServiceImpl implements MenuService { | ... | @@ -197,4 +200,10 @@ public class MenuServiceImpl implements MenuService { |
| 197 | .build(); | 200 | .build(); |
| 198 | } | 201 | } |
| 199 | 202 | ||
| 203 | + @Override | ||
| 204 | + public List<Integer> queryMenuSkuIdsByStallId(int enterpriseId, int stallId) { | ||
| 205 | + final var menuIds = menuServiceRpcClient.queryPublishedMenusByStallId(LoginContextHolder.getEnterpriseId(), stallId).getResponsesList().stream().map(SingleMenuRpcResponse::getId).collect(Collectors.toList()); | ||
| 206 | + return menuServiceRpcClient.queryMenuDetailsByMenuIds(LoginContextHolder.getEnterpriseId(), menuIds).getResponsesList().stream().map(SingleMenuDetailRpcResponse::getSkuId).distinct().collect(Collectors.toList()); | ||
| 207 | + } | ||
| 208 | + | ||
| 200 | } | 209 | } | ... | ... |
| ... | @@ -56,7 +56,6 @@ import lombok.extern.slf4j.Slf4j; | ... | @@ -56,7 +56,6 @@ import lombok.extern.slf4j.Slf4j; |
| 56 | import org.springframework.beans.factory.annotation.Autowired; | 56 | import org.springframework.beans.factory.annotation.Autowired; |
| 57 | import org.springframework.stereotype.Service; | 57 | import org.springframework.stereotype.Service; |
| 58 | 58 | ||
| 59 | -import java.time.LocalDate; | ||
| 60 | import java.util.ArrayList; | 59 | import java.util.ArrayList; |
| 61 | import java.util.List; | 60 | import java.util.List; |
| 62 | import java.util.stream.Collectors; | 61 | import java.util.stream.Collectors; |
| ... | @@ -112,16 +111,12 @@ public class OrderServiceImpl implements OrderService { | ... | @@ -112,16 +111,12 @@ public class OrderServiceImpl implements OrderService { |
| 112 | if (placeOrderCount != 0 && menuOrderCount >= placeOrderCount) { | 111 | if (placeOrderCount != 0 && menuOrderCount >= placeOrderCount) { |
| 113 | throw ClientEndExceptions.OperationForbidden.build(ErrorCodeEnum.ORDER_COUNT_LIMIT.name()); | 112 | throw ClientEndExceptions.OperationForbidden.build(ErrorCodeEnum.ORDER_COUNT_LIMIT.name()); |
| 114 | } | 113 | } |
| 115 | - createOrderDto.setCloseTimeType( | 114 | + createOrderDto.setCloseTimeType(CloseTimeType.forNumber(menu.getOrderRuleJson().getCloseTimeType().getNumber())); |
| 116 | - CloseTimeType.forNumber(menu.getOrderRuleJson().getCloseTimeType().getNumber())); | ||
| 117 | createOrderDto.setRoomNo(record.getRoomNo()); | 115 | createOrderDto.setRoomNo(record.getRoomNo()); |
| 118 | createOrderDto.setCreationSource(OrderSourceEnum.STALL.getNumber()); | 116 | createOrderDto.setCreationSource(OrderSourceEnum.STALL.getNumber()); |
| 119 | createOrderDto.setEnterpriseId(operatorLoginInfo.getEnterpriseId()); | 117 | createOrderDto.setEnterpriseId(operatorLoginInfo.getEnterpriseId()); |
| 120 | // createOrderDto.setStallId(); | 118 | // createOrderDto.setStallId(); |
| 121 | - var onlinePay = false; | 119 | + var onlinePay = menu.getOrderRuleJson().getModeOfPayment() == ModeOfPaymentEnum.ONLINE; |
| 122 | - if (menu.getOrderRuleJson().getModeOfPayment() == ModeOfPaymentEnum.ONLINE) { | ||
| 123 | - onlinePay = true; | ||
| 124 | - } | ||
| 125 | createOrderDto.setOnlinePay(onlinePay); | 120 | createOrderDto.setOnlinePay(onlinePay); |
| 126 | OrderTypeEnum orderType; | 121 | OrderTypeEnum orderType; |
| 127 | if (menu.getOrderRuleJson().getCloseTimeType() == CloseTimeTypeEnum.RESERVATION) { | 122 | if (menu.getOrderRuleJson().getCloseTimeType() == CloseTimeTypeEnum.RESERVATION) { |
| ... | @@ -231,8 +226,7 @@ public class OrderServiceImpl implements OrderService { | ... | @@ -231,8 +226,7 @@ public class OrderServiceImpl implements OrderService { |
| 231 | } | 226 | } |
| 232 | 227 | ||
| 233 | @Override | 228 | @Override |
| 234 | - public BatchUpdateOrderDetailResponse batchUpdateOrderDetails( | 229 | + public BatchUpdateOrderDetailResponse batchUpdateOrderDetails(OrderDetailBatchUpdateDto batchUpdateDto) { |
| 235 | - OrderDetailBatchUpdateDto batchUpdateDto) { | ||
| 236 | final var response = orderServiceRpcClient.batchUpdateClientCustomerOrderDetails(batchUpdateDto); | 230 | final var response = orderServiceRpcClient.batchUpdateClientCustomerOrderDetails(batchUpdateDto); |
| 237 | return BatchUpdateOrderDetailResponse.builder() | 231 | return BatchUpdateOrderDetailResponse.builder() |
| 238 | .isUpdated(response.getIsUpdated()) | 232 | .isUpdated(response.getIsUpdated()) |
| ... | @@ -243,7 +237,7 @@ public class OrderServiceImpl implements OrderService { | ... | @@ -243,7 +237,7 @@ public class OrderServiceImpl implements OrderService { |
| 243 | public Integer getMenuOrderCount(getMenuOrderCountDto checkIfOrdered) { | 237 | public Integer getMenuOrderCount(getMenuOrderCountDto checkIfOrdered) { |
| 244 | final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); | 238 | final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); |
| 245 | final var mealTimeStart = checkIfOrdered.getMealTime().toLocalDate().atStartOfDay(); | 239 | final var mealTimeStart = checkIfOrdered.getMealTime().toLocalDate().atStartOfDay(); |
| 246 | - LocalDate tomorrow = checkIfOrdered.getMealTime().toLocalDate().plusDays(1); | 240 | + final var tomorrow = checkIfOrdered.getMealTime().toLocalDate().plusDays(1); |
| 247 | final var mealTimeEnd = tomorrow.atStartOfDay(); | 241 | final var mealTimeEnd = tomorrow.atStartOfDay(); |
| 248 | final var queryOrderDto = QueryOrderByConditionDto.builder() | 242 | final var queryOrderDto = QueryOrderByConditionDto.builder() |
| 249 | .enterpriseId(operatorLoginInfo.getEnterpriseId()) | 243 | .enterpriseId(operatorLoginInfo.getEnterpriseId()) | ... | ... |
| 1 | package com.infoloop.tianting.service.impl; | 1 | package com.infoloop.tianting.service.impl; |
| 2 | 2 | ||
| 3 | +import com.infoloop.tianting.SingleSkuResponse; | ||
| 4 | +import com.infoloop.tianting.clientcustomerorderservice.SingleSkuSellQuantityRpcResponse; | ||
| 5 | +import com.infoloop.tianting.context.LoginContextHolder; | ||
| 6 | +import com.infoloop.tianting.enums.SkuSellQuantityStatus; | ||
| 7 | +import com.infoloop.tianting.model.bo.SkuSellQuantityBO; | ||
| 8 | +import com.infoloop.tianting.model.common.PageResult; | ||
| 3 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDetailSingleResponseDto; | 9 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDetailSingleResponseDto; |
| 4 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDto; | 10 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuDto; |
| 5 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuSpecialDetailSingleResponseDto; | 11 | import com.infoloop.tianting.model.dto.SkuDbDTO.SkuSpecialDetailSingleResponseDto; |
| 12 | +import com.infoloop.tianting.model.dto.SkuSellQuantityDTO; | ||
| 13 | +import com.infoloop.tianting.model.vo.SkuSellQuantityStatisticsVO; | ||
| 14 | +import com.infoloop.tianting.model.vo.SkuSellQuantityVO; | ||
| 15 | +import com.infoloop.tianting.service.MenuService; | ||
| 6 | import com.infoloop.tianting.service.SkuService; | 16 | import com.infoloop.tianting.service.SkuService; |
| 17 | +import com.infoloop.tianting.service.client.OrderServiceRpcClient; | ||
| 7 | import com.infoloop.tianting.service.client.SkuServiceRpcClient; | 18 | import com.infoloop.tianting.service.client.SkuServiceRpcClient; |
| 8 | import com.infoloop.tianting.utils.DateUtil; | 19 | import com.infoloop.tianting.utils.DateUtil; |
| 20 | +import com.infoloop.tianting.utils.PageUtil; | ||
| 9 | import lombok.RequiredArgsConstructor; | 21 | import lombok.RequiredArgsConstructor; |
| 10 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
| 11 | import org.springframework.beans.factory.annotation.Autowired; | 23 | import org.springframework.beans.factory.annotation.Autowired; |
| 12 | import org.springframework.stereotype.Service; | 24 | import org.springframework.stereotype.Service; |
| 13 | 25 | ||
| 26 | +import java.util.Comparator; | ||
| 14 | import java.util.List; | 27 | import java.util.List; |
| 28 | +import java.util.function.Function; | ||
| 15 | import java.util.stream.Collectors; | 29 | import java.util.stream.Collectors; |
| 16 | 30 | ||
| 17 | @Slf4j | 31 | @Slf4j |
| 18 | @Service | 32 | @Service |
| 19 | @RequiredArgsConstructor(onConstructor = @__(@Autowired)) | 33 | @RequiredArgsConstructor(onConstructor = @__(@Autowired)) |
| 20 | public class SkuServiceImpl implements SkuService { | 34 | public class SkuServiceImpl implements SkuService { |
| 35 | + | ||
| 36 | + private final MenuService menuService; | ||
| 37 | + | ||
| 21 | private final SkuServiceRpcClient skuServiceRpcClient; | 38 | private final SkuServiceRpcClient skuServiceRpcClient; |
| 22 | 39 | ||
| 40 | + private final OrderServiceRpcClient orderServiceRpcClient; | ||
| 41 | + | ||
| 23 | @Override | 42 | @Override |
| 24 | public List<SkuDto> getSkusByIds(List<Integer> ids) { | 43 | public List<SkuDto> getSkusByIds(List<Integer> ids) { |
| 25 | final var response = skuServiceRpcClient.getDishSkusByIds(ids); | 44 | final var response = skuServiceRpcClient.getDishSkusByIds(ids); |
| ... | @@ -56,4 +75,133 @@ public class SkuServiceImpl implements SkuService { | ... | @@ -56,4 +75,133 @@ public class SkuServiceImpl implements SkuService { |
| 56 | .build() | 75 | .build() |
| 57 | ).collect(Collectors.toList()); | 76 | ).collect(Collectors.toList()); |
| 58 | } | 77 | } |
| 78 | + | ||
| 79 | + @Override | ||
| 80 | + public SkuSellQuantityStatisticsVO querySkuSellQuantityStatistics(int stallId) { | ||
| 81 | + final var skuIds = menuService.queryMenuSkuIdsByStallId(LoginContextHolder.getEnterpriseId(), stallId); | ||
| 82 | + final var responses = orderServiceRpcClient.querySkuSellQuantitiesByStall(LoginContextHolder.getEnterpriseId(), stallId); | ||
| 83 | + final var skuSellQuantitiesMap = responses.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity())); | ||
| 84 | + final var soldOut = skuIds.stream() | ||
| 85 | + .filter(e -> skuSellQuantitiesMap.get(e) == null || skuSellQuantitiesMap.get(e).getMaxSellQuantity() == skuSellQuantitiesMap.get(e).getTodaySellQuantity()) | ||
| 86 | + .count(); | ||
| 87 | + final int total = skuIds.size(); | ||
| 88 | + return SkuSellQuantityStatisticsVO.builder() | ||
| 89 | + .total(total) | ||
| 90 | + .soldOut(soldOut) | ||
| 91 | + .onSale(total - soldOut) | ||
| 92 | + .build(); | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + @Override | ||
| 96 | + public PageResult<SkuSellQuantityVO> querySkuSellQuantity(SkuSellQuantityDTO.QuerySkuSellQuantityDTO querySkuSellQuantityDTO) { | ||
| 97 | + final var stallId = querySkuSellQuantityDTO.getStallId(); | ||
| 98 | + final var enterpriseId = LoginContextHolder.getEnterpriseId(); | ||
| 99 | + final var skuIds = menuService.queryMenuSkuIdsByStallId(enterpriseId, stallId); | ||
| 100 | + var responses = orderServiceRpcClient.querySkuSellQuantitiesByStall(enterpriseId, stallId); | ||
| 101 | + final var skuSellQuantityMap = responses.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity())); | ||
| 102 | + responses = skuIds.stream() | ||
| 103 | + .map(skuId -> { | ||
| 104 | + var response = skuSellQuantityMap.get(skuId); | ||
| 105 | + if (response == null) { | ||
| 106 | + response = SingleSkuSellQuantityRpcResponse.newBuilder() | ||
| 107 | + .setSkuId(skuId) | ||
| 108 | + .setMaxSellQuantity(0) | ||
| 109 | + .setTodaySellQuantity(0) | ||
| 110 | + .build(); | ||
| 111 | + } | ||
| 112 | + return response; | ||
| 113 | + }) | ||
| 114 | + .collect(Collectors.toList()); | ||
| 115 | + if (querySkuSellQuantityDTO.getStatus() != SkuSellQuantityStatus.ALL) { | ||
| 116 | + responses = responses.stream() | ||
| 117 | + .filter(e -> { | ||
| 118 | + switch (querySkuSellQuantityDTO.getStatus()) { | ||
| 119 | + case SOLD_OUT: | ||
| 120 | + return e.getMaxSellQuantity() == e.getTodaySellQuantity(); | ||
| 121 | + case ON_SALE: | ||
| 122 | + return e.getMaxSellQuantity() != e.getTodaySellQuantity(); | ||
| 123 | + default: | ||
| 124 | + return true; | ||
| 125 | + } | ||
| 126 | + }) | ||
| 127 | + .collect(Collectors.toList()); | ||
| 128 | + } | ||
| 129 | + final var skuList = skuServiceRpcClient.getSkusByIds(responses.stream().map(SingleSkuSellQuantityRpcResponse::getSkuId).collect(Collectors.toList())); | ||
| 130 | + final var skuMap = skuList.stream().collect(Collectors.toMap(SingleSkuResponse::getId, Function.identity())); | ||
| 131 | + final var keyword = querySkuSellQuantityDTO.getKeyword(); | ||
| 132 | + if (keyword != null && !keyword.isEmpty()) { | ||
| 133 | + responses = responses.stream() | ||
| 134 | + .filter(e -> { | ||
| 135 | + var sku = skuMap.get(e.getSkuId()); | ||
| 136 | + return sku != null && (sku.getCode().contains(keyword) || sku.getName().contains(keyword)); | ||
| 137 | + }) | ||
| 138 | + .collect(Collectors.toList()); | ||
| 139 | + } | ||
| 140 | + final var skuSellQuantityVOS = responses.stream() | ||
| 141 | + .map(e -> { | ||
| 142 | + var sku = skuMap.get(e.getSkuId()); | ||
| 143 | + return SkuSellQuantityVO.builder() | ||
| 144 | + .skuId(e.getSkuId()) | ||
| 145 | + .skuName(sku != null ? sku.getName() : "") | ||
| 146 | + .skuCode(sku != null ? sku.getCode() : "") | ||
| 147 | + .maxSellQuantity(e.getMaxSellQuantity()) | ||
| 148 | + .todaySellQuantity(e.getTodaySellQuantity()) | ||
| 149 | + .soldOut(e.getMaxSellQuantity() == e.getTodaySellQuantity()) | ||
| 150 | + .build(); | ||
| 151 | + }) | ||
| 152 | + .sorted(Comparator.comparing(SkuSellQuantityVO::getSkuCode)) | ||
| 153 | + .collect(Collectors.toList()); | ||
| 154 | + return PageUtil.subListPage(skuSellQuantityVOS, querySkuSellQuantityDTO.getPageNo(), querySkuSellQuantityDTO.getPageSize()); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + @Override | ||
| 158 | + public boolean batchSetSkuSellQuantity(int stallId, SkuSellQuantityDTO.BatchSetSkuSellQuantityDTO batchSetSkuSellQuantityDTO) { | ||
| 159 | + final var responses = orderServiceRpcClient.querySkuSellQuantitiesByStallAndSkuIds(LoginContextHolder.getEnterpriseId(), stallId, batchSetSkuSellQuantityDTO.getSkuIds()); | ||
| 160 | + final var skuMap = responses.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity())); | ||
| 161 | + final var skuSellQuantityBOs = batchSetSkuSellQuantityDTO.getSkuIds().stream().map(skuId -> SkuSellQuantityBO.builder() | ||
| 162 | + .id(skuMap.get(skuId) == null ? null : skuMap.get(skuId).getId()) | ||
| 163 | + .skuId(skuId) | ||
| 164 | + .maxSellQuantity(batchSetSkuSellQuantityDTO.getMaxSellQuantity()) | ||
| 165 | + .build() | ||
| 166 | + ).collect(Collectors.toList()); | ||
| 167 | + return orderServiceRpcClient.batchSaveSkuSellQuantities(LoginContextHolder.getEnterpriseId(), stallId, skuSellQuantityBOs); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + @Override | ||
| 171 | + public List<SkuSellQuantityVO> querySkuSellQuantityBySkuIds(SkuSellQuantityDTO.QuerySkuSellQuantityBySkuIdsDTO querySkuSellQuantityBySkuIdsDTO) { | ||
| 172 | + final var stallId = querySkuSellQuantityBySkuIdsDTO.getStallId(); | ||
| 173 | + final var enterpriseId = LoginContextHolder.getEnterpriseId(); | ||
| 174 | + final var skuIds = menuService.queryMenuSkuIdsByStallId(enterpriseId, stallId); | ||
| 175 | + var responses = orderServiceRpcClient.querySkuSellQuantitiesByStall(enterpriseId, stallId); | ||
| 176 | + final var skuSellQuantityMap = responses.stream().collect(Collectors.toMap(SingleSkuSellQuantityRpcResponse::getSkuId, Function.identity())); | ||
| 177 | + responses = skuIds.stream() | ||
| 178 | + .map(skuId -> { | ||
| 179 | + var response = skuSellQuantityMap.get(skuId); | ||
| 180 | + if (response == null) { | ||
| 181 | + response = SingleSkuSellQuantityRpcResponse.newBuilder() | ||
| 182 | + .setSkuId(skuId) | ||
| 183 | + .setMaxSellQuantity(0) | ||
| 184 | + .setTodaySellQuantity(0) | ||
| 185 | + .build(); | ||
| 186 | + } | ||
| 187 | + return response; | ||
| 188 | + }) | ||
| 189 | + .collect(Collectors.toList()); | ||
| 190 | + final var skuList = skuServiceRpcClient.getSkusByIds(responses.stream().map(SingleSkuSellQuantityRpcResponse::getSkuId).collect(Collectors.toList())); | ||
| 191 | + final var skuMap = skuList.stream().collect(Collectors.toMap(SingleSkuResponse::getId, Function.identity())); | ||
| 192 | + return responses.stream() | ||
| 193 | + .map(e -> { | ||
| 194 | + var sku = skuMap.get(e.getSkuId()); | ||
| 195 | + return SkuSellQuantityVO.builder() | ||
| 196 | + .skuId(e.getSkuId()) | ||
| 197 | + .skuName(sku != null ? sku.getName() : "") | ||
| 198 | + .skuCode(sku != null ? sku.getCode() : "") | ||
| 199 | + .maxSellQuantity(e.getMaxSellQuantity()) | ||
| 200 | + .todaySellQuantity(e.getTodaySellQuantity()) | ||
| 201 | + .soldOut(e.getMaxSellQuantity() == e.getTodaySellQuantity()) | ||
| 202 | + .build(); | ||
| 203 | + }) | ||
| 204 | + .sorted(Comparator.comparing(SkuSellQuantityVO::getSkuCode)) | ||
| 205 | + .collect(Collectors.toList()); | ||
| 206 | + } | ||
| 59 | } | 207 | } | ... | ... |
| ... | @@ -2,13 +2,23 @@ package com.infoloop.tianting.utils; | ... | @@ -2,13 +2,23 @@ package com.infoloop.tianting.utils; |
| 2 | 2 | ||
| 3 | import com.infoloop.tianting.model.common.OrderPageResult; | 3 | import com.infoloop.tianting.model.common.OrderPageResult; |
| 4 | import com.infoloop.tianting.model.common.PageResult; | 4 | import com.infoloop.tianting.model.common.PageResult; |
| 5 | - | ||
| 6 | import com.infoloop.tianting.model.dto.OrderDbDTO.OrderCountByStatusDto; | 5 | import com.infoloop.tianting.model.dto.OrderDbDTO.OrderCountByStatusDto; |
| 6 | + | ||
| 7 | import java.util.LinkedList; | 7 | import java.util.LinkedList; |
| 8 | import java.util.List; | 8 | import java.util.List; |
| 9 | 9 | ||
| 10 | public class PageUtil { | 10 | public class PageUtil { |
| 11 | 11 | ||
| 12 | + public static <T> PageResult<T> buildEmpty(T t) { | ||
| 13 | + PageResult<T> pageRet = new PageResult<>(); | ||
| 14 | + pageRet.setTotalCount(0); | ||
| 15 | + pageRet.setDataList(List.of(t)); | ||
| 16 | + pageRet.setPageNo(0); | ||
| 17 | + pageRet.setPageSize(0); | ||
| 18 | + pageRet.setTotalPage(0); | ||
| 19 | + return pageRet; | ||
| 20 | + } | ||
| 21 | + | ||
| 12 | /** | 22 | /** |
| 13 | * 自定义分页 | 23 | * 自定义分页 |
| 14 | */ | 24 | */ | ... | ... |
| ... | @@ -33,6 +33,14 @@ service ClientCustomerOrderServiceRpc { | ... | @@ -33,6 +33,14 @@ service ClientCustomerOrderServiceRpc { |
| 33 | // 操作记录 | 33 | // 操作记录 |
| 34 | rpc GetOrderOperationRecordsByOrderId (GetOrderOperationRecordsByOrderIdRequest) returns (GetOrderOperationRecordsByOrderIdResponse) {} | 34 | rpc GetOrderOperationRecordsByOrderId (GetOrderOperationRecordsByOrderIdRequest) returns (GetOrderOperationRecordsByOrderIdResponse) {} |
| 35 | rpc BatchCreateOrderOperationRecords (BatchCreateOrderOperationRecordsRequest) returns (BatchCreateOrderOperationRecordsResponse) {} | 35 | rpc BatchCreateOrderOperationRecords (BatchCreateOrderOperationRecordsRequest) returns (BatchCreateOrderOperationRecordsResponse) {} |
| 36 | + | ||
| 37 | + | ||
| 38 | + // sku菜品库存 | ||
| 39 | + rpc QuerySkuSellQuantitiesByStall(QuerySkuSellQuantitiesByStallRpcRequest) returns (QuerySkuSellQuantitiesByStallRpcResponse) {} | ||
| 40 | + rpc QuerySkuSellQuantitiesByStallAndSkuIds(QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest) returns (QuerySkuSellQuantitiesByStallAndSkuIdsRpcResponse) {} | ||
| 41 | + rpc BatchSaveSkuSellQuantities(BatchSaveSkuSellQuantitiesRpcRequest) returns (BatchSaveSkuSellQuantitiesRpcResponse) {} | ||
| 42 | + rpc AddSkusSellQuantities(AddSkusSellQuantitiesRpcRequest) returns (AddSkusSellQuantitiesRpcResponse) {} | ||
| 43 | + | ||
| 36 | } | 44 | } |
| 37 | 45 | ||
| 38 | enum OrderStatusEnum { | 46 | enum OrderStatusEnum { |
| ... | @@ -608,3 +616,71 @@ message BatchCreateOrderOperationRecordsResponse { | ... | @@ -608,3 +616,71 @@ message BatchCreateOrderOperationRecordsResponse { |
| 608 | bool isCreated = 1; | 616 | bool isCreated = 1; |
| 609 | repeated int32 ids = 2; | 617 | repeated int32 ids = 2; |
| 610 | } | 618 | } |
| 619 | + | ||
| 620 | +message SingleSkuSellQuantityRpcResponse { | ||
| 621 | + int32 id = 1; | ||
| 622 | + int32 enterpriseId = 2; | ||
| 623 | + int32 stallId = 3; | ||
| 624 | + int32 skuId = 4; | ||
| 625 | + int32 maxSellQuantity = 5; | ||
| 626 | + int32 todaySellQuantity = 6; | ||
| 627 | + int32 createdBy = 7; | ||
| 628 | + int64 createdAt = 8; | ||
| 629 | + int32 creationSource = 9; | ||
| 630 | + int32 updatedBy = 10; | ||
| 631 | + int64 updatedAt = 11; | ||
| 632 | + int32 updateSource = 12; | ||
| 633 | + bool isDeleted = 13; | ||
| 634 | +} | ||
| 635 | + | ||
| 636 | +message QuerySkuSellQuantitiesByStallRpcRequest { | ||
| 637 | + int32 enterpriseId = 1; | ||
| 638 | + int32 stallId = 2; | ||
| 639 | +} | ||
| 640 | + | ||
| 641 | +message QuerySkuSellQuantitiesByStallRpcResponse { | ||
| 642 | + repeated SingleSkuSellQuantityRpcResponse responses = 1; | ||
| 643 | +} | ||
| 644 | + | ||
| 645 | +message QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest { | ||
| 646 | + int32 enterpriseId = 1; | ||
| 647 | + int32 stallId = 2; | ||
| 648 | + repeated int32 skuIds = 3; | ||
| 649 | +} | ||
| 650 | + | ||
| 651 | +message QuerySkuSellQuantitiesByStallAndSkuIdsRpcResponse { | ||
| 652 | + repeated SingleSkuSellQuantityRpcResponse responses = 1; | ||
| 653 | +} | ||
| 654 | + | ||
| 655 | +message BatchSaveSkuSellQuantitiesRpcRequest { | ||
| 656 | + repeated SkuSellQuantityModification skuSellQuantityModifications = 1; | ||
| 657 | + int32 enterpriseId = 2; | ||
| 658 | + int32 updatedBy = 3; | ||
| 659 | + int32 updateSource = 4; | ||
| 660 | +} | ||
| 661 | + | ||
| 662 | +message SkuSellQuantityModification { | ||
| 663 | + int32 id = 1; | ||
| 664 | + int32 stallId = 2; | ||
| 665 | + int32 skuId = 3; | ||
| 666 | + int32 maxSellQuantity = 4; | ||
| 667 | +} | ||
| 668 | + | ||
| 669 | +message BatchSaveSkuSellQuantitiesRpcResponse { | ||
| 670 | + bool isSaved = 1; | ||
| 671 | +} | ||
| 672 | + | ||
| 673 | +message AddSkusSellQuantitiesRpcRequest { | ||
| 674 | + int32 enterpriseId = 1; | ||
| 675 | + int32 stallId = 2; | ||
| 676 | + repeated SkuSellQuantity skuSellQuantities = 3; | ||
| 677 | +} | ||
| 678 | + | ||
| 679 | +message SkuSellQuantity { | ||
| 680 | + int32 skuId = 1; | ||
| 681 | + int32 quantity = 2; | ||
| 682 | +} | ||
| 683 | + | ||
| 684 | +message AddSkusSellQuantitiesRpcResponse { | ||
| 685 | + bool isAdded = 1; | ||
| 686 | +} | ... | ... |
-
Please register or login to post a comment