feat(settlement): 新增按订单维度结算及分餐表导出功能、新增忌口备注字段并支持更新
- 在 ClientCustomerOrderService.proto 中新增忌口备注字段 avoidRemark - 在 KdsDTO 中增加 mealTime 字段用于指定查询日期- 修改 KdsServiceImpl 中获取订单逻辑,使用 mealTime 替代当前日期 - 在 OrderDbDTO 中添加 avoidRemark 字段以存储忌口信息 - 更新 OrderServiceImpl 映射逻辑,包含 avoidRemark 字段 - 在 OrderServiceRpcClient 中实现 avoidRemark 的更新逻辑
Showing
14 changed files
with
1137 additions
and
43 deletions
| ... | @@ -48,8 +48,8 @@ public class KdsController { | ... | @@ -48,8 +48,8 @@ public class KdsController { |
| 48 | @ApiOperation(value = "kds获取餐别详情") | 48 | @ApiOperation(value = "kds获取餐别详情") |
| 49 | @PostMapping("/kds/mealDetails") | 49 | @PostMapping("/kds/mealDetails") |
| 50 | @ResponseStatus(HttpStatus.OK) | 50 | @ResponseStatus(HttpStatus.OK) |
| 51 | - public List<KdsMealDetailDto> getMealDetail() { | 51 | + public List<KdsMealDetailDto> getMealDetail(@Valid @RequestBody KdsDTO.KdsMealDetailQueryDto queryDto) { |
| 52 | - return kdsService.getMealDetail(); | 52 | + return kdsService.getMealDetail(queryDto); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | } | 55 | } | ... | ... |
| ... | @@ -8,6 +8,7 @@ import lombok.Getter; | ... | @@ -8,6 +8,7 @@ import lombok.Getter; |
| 8 | public enum SettlementDimensionEnum { | 8 | public enum SettlementDimensionEnum { |
| 9 | BY_SKU(1, "菜品"), | 9 | BY_SKU(1, "菜品"), |
| 10 | BY_MEAL(2, "餐别"), | 10 | BY_MEAL(2, "餐别"), |
| 11 | + BY_ORDER(3, "订单") | ||
| 11 | ; | 12 | ; |
| 12 | 13 | ||
| 13 | /** | 14 | /** | ... | ... |
| ... | @@ -30,6 +30,7 @@ public class KdsDTO { | ... | @@ -30,6 +30,7 @@ public class KdsDTO { |
| 30 | private Integer price; | 30 | private Integer price; |
| 31 | private String roomNo; | 31 | private String roomNo; |
| 32 | private String remark; | 32 | private String remark; |
| 33 | + private String avoidRemark; | ||
| 33 | private CustomerNotice customerNotice; | 34 | private CustomerNotice customerNotice; |
| 34 | private String adjustSkuRemark; | 35 | private String adjustSkuRemark; |
| 35 | private String mealTime; | 36 | private String mealTime; |
| ... | @@ -38,6 +39,8 @@ public class KdsDTO { | ... | @@ -38,6 +39,8 @@ public class KdsDTO { |
| 38 | private ClientDto client; | 39 | private ClientDto client; |
| 39 | private ClientDto stall; | 40 | private ClientDto stall; |
| 40 | private CustomerDetailDto customer; | 41 | private CustomerDetailDto customer; |
| 42 | + private Integer menuId; | ||
| 43 | + private String menuName; | ||
| 41 | } | 44 | } |
| 42 | 45 | ||
| 43 | @Data | 46 | @Data |
| ... | @@ -77,6 +80,7 @@ public class KdsDTO { | ... | @@ -77,6 +80,7 @@ public class KdsDTO { |
| 77 | private String tableCode; | 80 | private String tableCode; |
| 78 | private Integer totalCount; | 81 | private Integer totalCount; |
| 79 | private String remark; | 82 | private String remark; |
| 83 | + private String avoidRemark; | ||
| 80 | private String mealTime; | 84 | private String mealTime; |
| 81 | private CustomerNotice customerNotice; | 85 | private CustomerNotice customerNotice; |
| 82 | private Integer totalPrice; | 86 | private Integer totalPrice; |
| ... | @@ -87,6 +91,8 @@ public class KdsDTO { | ... | @@ -87,6 +91,8 @@ public class KdsDTO { |
| 87 | private ClientDto client; | 91 | private ClientDto client; |
| 88 | private CustomerDetailDto customer; | 92 | private CustomerDetailDto customer; |
| 89 | private List<KdsOrderLocationDetailDto> orderDetailList; | 93 | private List<KdsOrderLocationDetailDto> orderDetailList; |
| 94 | + private Integer menuId; | ||
| 95 | + private String menuName; | ||
| 90 | } | 96 | } |
| 91 | 97 | ||
| 92 | @Data | 98 | @Data |
| ... | @@ -97,6 +103,7 @@ public class KdsDTO { | ... | @@ -97,6 +103,7 @@ public class KdsDTO { |
| 97 | public static class KdsOrderSkuQueryDto { | 103 | public static class KdsOrderSkuQueryDto { |
| 98 | private ServeStatusEnum serveStatus; | 104 | private ServeStatusEnum serveStatus; |
| 99 | private Integer mealId; | 105 | private Integer mealId; |
| 106 | + private String mealTime; | ||
| 100 | } | 107 | } |
| 101 | 108 | ||
| 102 | @Data | 109 | @Data |
| ... | @@ -107,12 +114,22 @@ public class KdsDTO { | ... | @@ -107,12 +114,22 @@ public class KdsDTO { |
| 107 | public static class KdsOrderLocationQueryDto { | 114 | public static class KdsOrderLocationQueryDto { |
| 108 | private OrderStatusEnum orderStatus; | 115 | private OrderStatusEnum orderStatus; |
| 109 | private Integer mealId; | 116 | private Integer mealId; |
| 117 | + private String mealTime; | ||
| 110 | } | 118 | } |
| 111 | 119 | ||
| 112 | @Data | 120 | @Data |
| 113 | @Builder | 121 | @Builder |
| 114 | @AllArgsConstructor | 122 | @AllArgsConstructor |
| 115 | @NoArgsConstructor | 123 | @NoArgsConstructor |
| 124 | + @ApiModel(description = "KdsMealDetailQueryDto") | ||
| 125 | + public static class KdsMealDetailQueryDto { | ||
| 126 | + private String mealTime; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + @Data | ||
| 130 | + @Builder | ||
| 131 | + @AllArgsConstructor | ||
| 132 | + @NoArgsConstructor | ||
| 116 | @ApiModel(description = "KdsMealDetailDto") | 133 | @ApiModel(description = "KdsMealDetailDto") |
| 117 | public static class KdsMealDetailDto { | 134 | public static class KdsMealDetailDto { |
| 118 | private Integer mealId; | 135 | private Integer mealId; | ... | ... |
| ... | @@ -64,6 +64,16 @@ public class OrderDbDTO { | ... | @@ -64,6 +64,16 @@ public class OrderDbDTO { |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | @Data | 66 | @Data |
| 67 | + @ApiModel(description = "查询订单Dto") | ||
| 68 | + public static class QueryOrderDto { | ||
| 69 | + private Integer enterpriseId; | ||
| 70 | + private Integer clientId; | ||
| 71 | + private OrderStatusEnum status; | ||
| 72 | + private String keyword; | ||
| 73 | + private List<Integer> stallIds; | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + @Data | ||
| 67 | @ApiModel(description = "查询已撤销订单Dto") | 77 | @ApiModel(description = "查询已撤销订单Dto") |
| 68 | public static class QueryRefundOrderByPaginationDto { | 78 | public static class QueryRefundOrderByPaginationDto { |
| 69 | private Integer enterpriseId; | 79 | private Integer enterpriseId; |
| ... | @@ -155,6 +165,7 @@ public class OrderDbDTO { | ... | @@ -155,6 +165,7 @@ public class OrderDbDTO { |
| 155 | private String tableCode; | 165 | private String tableCode; |
| 156 | private Integer updatedBy; | 166 | private Integer updatedBy; |
| 157 | private OrderSourceEnum updatedSource; | 167 | private OrderSourceEnum updatedSource; |
| 168 | + private String avoidRemark; | ||
| 158 | } | 169 | } |
| 159 | 170 | ||
| 160 | 171 | ||
| ... | @@ -440,6 +451,9 @@ public class OrderDbDTO { | ... | @@ -440,6 +451,9 @@ public class OrderDbDTO { |
| 440 | @ApiModelProperty(value = "备注") | 451 | @ApiModelProperty(value = "备注") |
| 441 | private String remark; | 452 | private String remark; |
| 442 | 453 | ||
| 454 | + @ApiModelProperty(value = "忌口备注") | ||
| 455 | + private String avoidRemark; | ||
| 456 | + | ||
| 443 | @ApiModelProperty(value = "下单客户当时的忌口、医嘱") | 457 | @ApiModelProperty(value = "下单客户当时的忌口、医嘱") |
| 444 | private CustomerNotice customerNoticeJson; | 458 | private CustomerNotice customerNoticeJson; |
| 445 | 459 | ... | ... |
| ... | @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModel; | ... | @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModel; |
| 5 | import lombok.Builder; | 5 | import lombok.Builder; |
| 6 | import lombok.Data; | 6 | import lombok.Data; |
| 7 | 7 | ||
| 8 | +import java.math.BigDecimal; | ||
| 8 | import java.time.LocalDateTime; | 9 | import java.time.LocalDateTime; |
| 9 | import java.util.ArrayList; | 10 | import java.util.ArrayList; |
| 10 | import java.util.List; | 11 | import java.util.List; |
| ... | @@ -75,7 +76,55 @@ public class SettlementDTO { | ... | @@ -75,7 +76,55 @@ public class SettlementDTO { |
| 75 | private Map<String, Map<String, Map<String, List<SettlementMenuMealDto>>>> classifyOrders; | 76 | private Map<String, Map<String, Map<String, List<SettlementMenuMealDto>>>> classifyOrders; |
| 76 | } | 77 | } |
| 77 | 78 | ||
| 78 | -} | 79 | + @Data |
| 80 | + @Builder | ||
| 81 | + @ApiModel(description = "SettlementDataByOrderDto") | ||
| 82 | + public static class SettlementDataByOrderDto { | ||
| 83 | + private List<SettlementOrderDetail> classifyOrders; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + @Data | ||
| 87 | + @Builder | ||
| 88 | + @ApiModel(description = "SettlementOrderDetail") | ||
| 89 | + public static class SettlementOrderDetail { | ||
| 90 | + private String mealTime; | ||
| 91 | + private String code; | ||
| 92 | + private String mealName; | ||
| 93 | + private String roomNo; | ||
| 94 | + private String customerName; | ||
| 95 | + private String HISCustomerNo; | ||
| 96 | + private List<String> avoids; | ||
| 97 | + private List<String> doctors; | ||
| 98 | + private String menuName; | ||
| 99 | + private String skuName; | ||
| 100 | + private Integer count; | ||
| 101 | + private BigDecimal price; | ||
| 102 | + private BigDecimal totalPrice; | ||
| 103 | + private String remark; | ||
| 104 | + private String avoidRemark; | ||
| 105 | + private String onlinePay; | ||
| 106 | + } | ||
| 79 | 107 | ||
| 108 | + @Data | ||
| 109 | + @Builder | ||
| 110 | + @ApiModel(description = "SeparateMealDetail") | ||
| 111 | + public static class SeparateMealDetail { | ||
| 112 | + private Integer orderId; | ||
| 113 | + private String mealName; | ||
| 114 | + private String roomNo; | ||
| 115 | + private String customerName; | ||
| 116 | + private String menuName; | ||
| 117 | + private String skuName; | ||
| 118 | + private Integer count; | ||
| 119 | + private String avoids; | ||
| 120 | + private String remark; | ||
| 121 | + } | ||
| 80 | 122 | ||
| 81 | - | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 123 | + @Data | ||
| 124 | + @Builder | ||
| 125 | + @ApiModel(description = "SeparateMealDataDto") | ||
| 126 | + public static class SeparateMealDataDto { | ||
| 127 | + private List<SeparateMealDetail> mealDetails; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | +} | ... | ... |
| 1 | +package com.infoloop.tianting.model.enums.desc; | ||
| 2 | + | ||
| 3 | +import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum; | ||
| 4 | + | ||
| 5 | +public enum OnlinePayDescEnum implements BaseProtoDescEnum<OnlinePayEnum> { | ||
| 6 | + | ||
| 7 | + UNKNOWN(OnlinePayEnum.UNKNOWN, "未知"), | ||
| 8 | + ONLINE(OnlinePayEnum.ONLINE, "在线"), | ||
| 9 | + OFFLINE(OnlinePayEnum.OFFLINE, "线下"), | ||
| 10 | + LEAVE_HOSPITAL(OnlinePayEnum.LEAVE_HOSPITAL, "出院"), | ||
| 11 | + EMPLOYEE_CARD(OnlinePayEnum.EMPLOYEE_CARD, "员工卡"), | ||
| 12 | + PAPER_VERIFICATION(OnlinePayEnum.PAPER_VERIFICATION, "纸质核销"), | ||
| 13 | + CASH(OnlinePayEnum.CASH, "现金"), | ||
| 14 | + MEAL_CARD(OnlinePayEnum.MEAL_CARD, "餐卡"), | ||
| 15 | + BAND_CARD(OnlinePayEnum.BAND_CARD, "银行卡"), | ||
| 16 | + ALIPAY(OnlinePayEnum.ALIPAY, "支付宝"), | ||
| 17 | + WECHATPAY(OnlinePayEnum.WECHATPAY, "微信支付"); | ||
| 18 | + | ||
| 19 | + private final OnlinePayEnum protoEnum; | ||
| 20 | + private final String desc; | ||
| 21 | + | ||
| 22 | + OnlinePayDescEnum(OnlinePayEnum protoEnum, String desc) { | ||
| 23 | + this.protoEnum = protoEnum; | ||
| 24 | + this.desc = desc; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + @Override | ||
| 28 | + public OnlinePayEnum getProtoEnum() { | ||
| 29 | + return protoEnum; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public String getDesc() { | ||
| 34 | + return desc; | ||
| 35 | + } | ||
| 36 | +} |
| 1 | package com.infoloop.tianting.service; | 1 | package com.infoloop.tianting.service; |
| 2 | 2 | ||
| 3 | +import com.infoloop.tianting.model.dto.KdsDTO; | ||
| 3 | import com.infoloop.tianting.model.dto.KdsDTO.KdsMealDetailDto; | 4 | import com.infoloop.tianting.model.dto.KdsDTO.KdsMealDetailDto; |
| 4 | import com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDto; | 5 | import com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDto; |
| 5 | import com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationQueryDto; | 6 | import com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationQueryDto; |
| ... | @@ -14,5 +15,5 @@ public interface KdsService { | ... | @@ -14,5 +15,5 @@ public interface KdsService { |
| 14 | 15 | ||
| 15 | List<KdsOrderLocationDto> getOrderDetailByLocation(KdsOrderLocationQueryDto queryDto); | 16 | List<KdsOrderLocationDto> getOrderDetailByLocation(KdsOrderLocationQueryDto queryDto); |
| 16 | 17 | ||
| 17 | - List<KdsMealDetailDto> getMealDetail(); | 18 | + List<KdsMealDetailDto> getMealDetail(KdsDTO.KdsMealDetailQueryDto queryDto); |
| 18 | } | 19 | } | ... | ... |
| 1 | package com.infoloop.tianting.service; | 1 | package com.infoloop.tianting.service; |
| 2 | 2 | ||
| 3 | +import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderDto; | ||
| 3 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto; | 4 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto; |
| 4 | 5 | ||
| 5 | import java.io.ByteArrayOutputStream; | 6 | import java.io.ByteArrayOutputStream; |
| 6 | 7 | ||
| 7 | public interface SettlementService { | 8 | public interface SettlementService { |
| 8 | ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest); | 9 | ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest); |
| 10 | + ByteArrayOutputStream exportSeparateMealsExcel(QueryOrderDto queryOrderDto); | ||
| 9 | } | 11 | } | ... | ... |
| ... | @@ -31,6 +31,7 @@ import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; | ... | @@ -31,6 +31,7 @@ import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; |
| 31 | import com.infoloop.tianting.clientcustomerorderservice.OrderTypeEnum; | 31 | import com.infoloop.tianting.clientcustomerorderservice.OrderTypeEnum; |
| 32 | import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; | 32 | import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; |
| 33 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByConditionRpcRequest; | 33 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByConditionRpcRequest; |
| 34 | +import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByConditionRpcResponse; | ||
| 34 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcRequest; | 35 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcRequest; |
| 35 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcResponse; | 36 | import com.infoloop.tianting.clientcustomerorderservice.QueryClientCustomerOrdersByPaginationRpcResponse; |
| 36 | import com.infoloop.tianting.clientcustomerorderservice.QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest; | 37 | import com.infoloop.tianting.clientcustomerorderservice.QuerySkuSellQuantitiesByStallAndSkuIdsRpcRequest; |
| ... | @@ -57,6 +58,7 @@ import com.infoloop.tianting.model.bo.AddSkusSellQuantityBO; | ... | @@ -57,6 +58,7 @@ import com.infoloop.tianting.model.bo.AddSkusSellQuantityBO; |
| 57 | import com.infoloop.tianting.model.bo.SkuSellQuantityBO; | 58 | import com.infoloop.tianting.model.bo.SkuSellQuantityBO; |
| 58 | import com.infoloop.tianting.model.dto.OperationDTO.BatchOperationDto; | 59 | import com.infoloop.tianting.model.dto.OperationDTO.BatchOperationDto; |
| 59 | import com.infoloop.tianting.model.dto.OperationDTO.SingleOperationDto; | 60 | import com.infoloop.tianting.model.dto.OperationDTO.SingleOperationDto; |
| 61 | +import com.infoloop.tianting.model.dto.OrderDbDTO; | ||
| 60 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDetailDto; | 62 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDetailDto; |
| 61 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto; | 63 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderDto; |
| 62 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderResponse; | 64 | import com.infoloop.tianting.model.dto.OrderDbDTO.CreateOrderResponse; |
| ... | @@ -180,6 +182,8 @@ public class OrderServiceRpcClient { | ... | @@ -180,6 +182,8 @@ public class OrderServiceRpcClient { |
| 180 | .setTableCode(tableCode) | 182 | .setTableCode(tableCode) |
| 181 | .setShouldUpdateRoomNo(updateOrderDto.isShouldUpdateRoomNo()) | 183 | .setShouldUpdateRoomNo(updateOrderDto.isShouldUpdateRoomNo()) |
| 182 | .setRoomNo(roomNo) | 184 | .setRoomNo(roomNo) |
| 185 | + .setShouldUpdateAvoidRemark(updateOrderDto.getAvoidRemark() != null) | ||
| 186 | + .setAvoidRemark(updateOrderDto.getAvoidRemark() == null ? "" : updateOrderDto.getAvoidRemark()) | ||
| 183 | .build(); | 187 | .build(); |
| 184 | final var request = UpdateClientCustomerOrderRpcRequest.newBuilder() | 188 | final var request = UpdateClientCustomerOrderRpcRequest.newBuilder() |
| 185 | .setEnterpriseId(updateOrderDto.getEnterpriseId()) | 189 | .setEnterpriseId(updateOrderDto.getEnterpriseId()) |
| ... | @@ -188,7 +192,7 @@ public class OrderServiceRpcClient { | ... | @@ -188,7 +192,7 @@ public class OrderServiceRpcClient { |
| 188 | .setModification(modification) | 192 | .setModification(modification) |
| 189 | .build(); | 193 | .build(); |
| 190 | final UpdateClientCustomerOrderRpcResponse updateClientCustomerOrderRpcResponse = orderServiceRpcBlockingStub.updateClientCustomerOrder(request); | 194 | final UpdateClientCustomerOrderRpcResponse updateClientCustomerOrderRpcResponse = orderServiceRpcBlockingStub.updateClientCustomerOrder(request); |
| 191 | - if (updateClientCustomerOrderRpcResponse.getIsUpdated() && updateOrderDto.getStatus() == OrderStatusEnum.ORDER_CANCELED) { | 195 | + if (updateClientCustomerOrderRpcResponse.getIsUpdated() && updateOrderDto.getStatus() != null && updateOrderDto.getStatus() == OrderStatusEnum.ORDER_CANCELED) { |
| 192 | final var orderById = getOrderById(updateOrderDto.getId()); | 196 | final var orderById = getOrderById(updateOrderDto.getId()); |
| 193 | if (orderById != null && orderById.getCloseTimeType() == CloseTimeType.IMMEDIATELY) { | 197 | if (orderById != null && orderById.getCloseTimeType() == CloseTimeType.IMMEDIATELY) { |
| 194 | final var orderDetails = getOrderDetailsByOrderId(orderById.getId()); | 198 | final var orderDetails = getOrderDetailsByOrderId(orderById.getId()); |
| ... | @@ -484,6 +488,17 @@ public class OrderServiceRpcClient { | ... | @@ -484,6 +488,17 @@ public class OrderServiceRpcClient { |
| 484 | return orderServiceRpcBlockingStub.queryClientCustomerOrdersByPagination(request); | 488 | return orderServiceRpcBlockingStub.queryClientCustomerOrdersByPagination(request); |
| 485 | } | 489 | } |
| 486 | 490 | ||
| 491 | + public QueryClientCustomerOrdersByConditionRpcResponse queryClientCustomerOrdersByCondition(OrderDbDTO.QueryOrderDto queryOrderDto) { | ||
| 492 | + final var request = QueryClientCustomerOrdersByConditionRpcRequest.newBuilder() | ||
| 493 | + .setShouldFilterStatus(true) | ||
| 494 | + .setStatus(queryOrderDto.getStatus()) | ||
| 495 | + .setEnterpriseId(queryOrderDto.getEnterpriseId()) | ||
| 496 | + .setShouldFilterClientIds(true).addClientIds(queryOrderDto.getClientId()) | ||
| 497 | + .setShouldFilterStallIds(true).addAllStallIds(queryOrderDto.getStallIds()) | ||
| 498 | + .build(); | ||
| 499 | + return orderServiceRpcBlockingStub.queryClientCustomerOrdersByCondition(request); | ||
| 500 | + } | ||
| 501 | + | ||
| 487 | public QueryClientCustomerOrdersByPaginationRpcResponse queryRefundClientCustomerOrdersByPagination( | 502 | public QueryClientCustomerOrdersByPaginationRpcResponse queryRefundClientCustomerOrdersByPagination( |
| 488 | QueryRefundOrderByPaginationDto queryOrderDto) { | 503 | QueryRefundOrderByPaginationDto queryOrderDto) { |
| 489 | final var request = QueryClientCustomerOrdersByPaginationRpcRequest.newBuilder() | 504 | final var request = QueryClientCustomerOrdersByPaginationRpcRequest.newBuilder() | ... | ... |
| ... | @@ -6,7 +6,9 @@ import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum; | ... | @@ -6,7 +6,9 @@ import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum; |
| 6 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse; | 6 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse; |
| 7 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse; | 7 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse; |
| 8 | import com.infoloop.tianting.context.LoginContextHolder; | 8 | import com.infoloop.tianting.context.LoginContextHolder; |
| 9 | +import com.infoloop.tianting.menuservice.SingleMenuRpcResponse; | ||
| 9 | import com.infoloop.tianting.model.dto.ClientInventoryDbDTO.ClientDto; | 10 | import com.infoloop.tianting.model.dto.ClientInventoryDbDTO.ClientDto; |
| 11 | +import com.infoloop.tianting.model.dto.KdsDTO; | ||
| 10 | import com.infoloop.tianting.model.dto.KdsDTO.KdsMealDetailDto; | 12 | import com.infoloop.tianting.model.dto.KdsDTO.KdsMealDetailDto; |
| 11 | import com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDetailDto; | 13 | import com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDetailDto; |
| 12 | import com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDto; | 14 | import com.infoloop.tianting.model.dto.KdsDTO.KdsOrderLocationDto; |
| ... | @@ -22,6 +24,7 @@ import com.infoloop.tianting.service.client.ClientCustomerServiceRpcClient; | ... | @@ -22,6 +24,7 @@ import com.infoloop.tianting.service.client.ClientCustomerServiceRpcClient; |
| 22 | import com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient; | 24 | import com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient; |
| 23 | import com.infoloop.tianting.service.client.EnterpriseResourceServiceRpcClient; | 25 | import com.infoloop.tianting.service.client.EnterpriseResourceServiceRpcClient; |
| 24 | import com.infoloop.tianting.service.client.MealServiceRpcClient; | 26 | import com.infoloop.tianting.service.client.MealServiceRpcClient; |
| 27 | +import com.infoloop.tianting.service.client.MenuServiceRpcClient; | ||
| 25 | import com.infoloop.tianting.service.client.OrderServiceRpcClient; | 28 | import com.infoloop.tianting.service.client.OrderServiceRpcClient; |
| 26 | import com.infoloop.tianting.service.client.SkuServiceRpcClient; | 29 | import com.infoloop.tianting.service.client.SkuServiceRpcClient; |
| 27 | import com.infoloop.tianting.service.client.WOperatorServiceRpcClient; | 30 | import com.infoloop.tianting.service.client.WOperatorServiceRpcClient; |
| ... | @@ -33,8 +36,10 @@ import org.springframework.stereotype.Service; | ... | @@ -33,8 +36,10 @@ import org.springframework.stereotype.Service; |
| 33 | 36 | ||
| 34 | import java.time.LocalDate; | 37 | import java.time.LocalDate; |
| 35 | import java.time.LocalDateTime; | 38 | import java.time.LocalDateTime; |
| 39 | +import java.time.LocalTime; | ||
| 36 | import java.util.ArrayList; | 40 | import java.util.ArrayList; |
| 37 | import java.util.List; | 41 | import java.util.List; |
| 42 | +import java.util.function.Function; | ||
| 38 | import java.util.stream.Collectors; | 43 | import java.util.stream.Collectors; |
| 39 | 44 | ||
| 40 | @Slf4j | 45 | @Slf4j |
| ... | @@ -49,14 +54,14 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -49,14 +54,14 @@ public class KdsServiceImpl implements KdsService { |
| 49 | private final SkuServiceRpcClient skuServiceRpcClient; | 54 | private final SkuServiceRpcClient skuServiceRpcClient; |
| 50 | private final ClientInventoryServiceRpcClient clientInventoryServiceRpcClient; | 55 | private final ClientInventoryServiceRpcClient clientInventoryServiceRpcClient; |
| 51 | private final ClientCustomerServiceRpcClient clientCustomerServiceRpcClient; | 56 | private final ClientCustomerServiceRpcClient clientCustomerServiceRpcClient; |
| 57 | + private final MenuServiceRpcClient menuServiceRpcClient; | ||
| 52 | 58 | ||
| 53 | @Override | 59 | @Override |
| 54 | public List<KdsOrderSkuDto> getOrderDetailBySku(KdsOrderSkuQueryDto queryDto) { | 60 | public List<KdsOrderSkuDto> getOrderDetailBySku(KdsOrderSkuQueryDto queryDto) { |
| 55 | // 获取当日所有的订单 和 订单明细 | 61 | // 获取当日所有的订单 和 订单明细 |
| 56 | - LocalDate today = LocalDate.now(); | 62 | + LocalDate today = LocalDate.parse(queryDto.getMealTime(), DateUtil.YYYY_MM_DD); |
| 57 | LocalDateTime todayZero = today.atStartOfDay(); | 63 | LocalDateTime todayZero = today.atStartOfDay(); |
| 58 | - LocalDate tomorrow = today.plusDays(1); | 64 | + LocalDateTime todayEnd = today.atTime(LocalTime.MAX); |
| 59 | - LocalDateTime tomorrowZero = tomorrow.atStartOfDay(); | ||
| 60 | final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); | 65 | final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); |
| 61 | boolean shouldFilterStallIds = false; | 66 | boolean shouldFilterStallIds = false; |
| 62 | List<Integer> stallIds = new ArrayList<>(); | 67 | List<Integer> stallIds = new ArrayList<>(); |
| ... | @@ -73,7 +78,7 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -73,7 +78,7 @@ public class KdsServiceImpl implements KdsService { |
| 73 | .shouldFilterMealTimeStart(true) | 78 | .shouldFilterMealTimeStart(true) |
| 74 | .mealTimeStart(todayZero) | 79 | .mealTimeStart(todayZero) |
| 75 | .shouldFilterMealTimeEnd(true) | 80 | .shouldFilterMealTimeEnd(true) |
| 76 | - .mealTimeEnd(tomorrowZero) | 81 | + .mealTimeEnd(todayEnd) |
| 77 | .shouldFilterPayStatus(true) | 82 | .shouldFilterPayStatus(true) |
| 78 | .payStatus(PayStatusEnum.SUCCEED) | 83 | .payStatus(PayStatusEnum.SUCCEED) |
| 79 | .build(); | 84 | .build(); |
| ... | @@ -118,6 +123,9 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -118,6 +123,9 @@ public class KdsServiceImpl implements KdsService { |
| 118 | .collect(Collectors.toList()); | 123 | .collect(Collectors.toList()); |
| 119 | final var skus = skuServiceRpcClient.getDishSkusByIds(skuIds).getResponseList(); | 124 | final var skus = skuServiceRpcClient.getDishSkusByIds(skuIds).getResponseList(); |
| 120 | 125 | ||
| 126 | + final var menuIds = orderList.stream().map(SingleClientCustomerOrderRpcResponse::getMenuId).distinct().toList(); | ||
| 127 | + final var menuMap = menuServiceRpcClient.getMenusByIds(operator.getEnterpriseId(), menuIds).getResponsesList().stream().collect(Collectors.toMap(SingleMenuRpcResponse::getId, Function.identity())); | ||
| 128 | + | ||
| 121 | List<KdsOrderSkuDto> kdsOrderSkuList = new ArrayList<>(); | 129 | List<KdsOrderSkuDto> kdsOrderSkuList = new ArrayList<>(); |
| 122 | for (Integer menuDetailId : menuDetailIds) { | 130 | for (Integer menuDetailId : menuDetailIds) { |
| 123 | // 找出该menuDetailId 的所有orderDetail | 131 | // 找出该menuDetailId 的所有orderDetail |
| ... | @@ -168,8 +176,11 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -168,8 +176,11 @@ public class KdsServiceImpl implements KdsService { |
| 168 | .count(detail.getCount()) | 176 | .count(detail.getCount()) |
| 169 | .orderDetailId(detail.getId()) | 177 | .orderDetailId(detail.getId()) |
| 170 | .remark(order.get().getRemark()) | 178 | .remark(order.get().getRemark()) |
| 179 | + .avoidRemark(order.get().getAvoidRemark()) | ||
| 171 | .orderId(order.get().getId()) | 180 | .orderId(order.get().getId()) |
| 172 | .roomNo(order.get().getSyncRoomNo().isEmpty() ? order.get().getRoomNo() : order.get().getSyncRoomNo()) | 181 | .roomNo(order.get().getSyncRoomNo().isEmpty() ? order.get().getRoomNo() : order.get().getSyncRoomNo()) |
| 182 | + .menuId(order.get().getMenuId()) | ||
| 183 | + .menuName(menuMap.get(order.get().getMenuId()) == null ? "" : menuMap.get(order.get().getMenuId()).getName()) | ||
| 173 | .tableCode(order.get().getTableCode()) | 184 | .tableCode(order.get().getTableCode()) |
| 174 | .customerNotice(CustomerNotice.builder() | 185 | .customerNotice(CustomerNotice.builder() |
| 175 | .doctors(order.get().getCustomerNoticeJson().getDoctorsList()) | 186 | .doctors(order.get().getCustomerNoticeJson().getDoctorsList()) |
| ... | @@ -208,9 +219,9 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -208,9 +219,9 @@ public class KdsServiceImpl implements KdsService { |
| 208 | } | 219 | } |
| 209 | 220 | ||
| 210 | @Override | 221 | @Override |
| 211 | - public List<KdsMealDetailDto> getMealDetail() { | 222 | + public List<KdsMealDetailDto> getMealDetail(KdsDTO.KdsMealDetailQueryDto queryDto) { |
| 212 | // 获取当日用餐的所有的订单 和 订单明细 | 223 | // 获取当日用餐的所有的订单 和 订单明细 |
| 213 | - LocalDate today = LocalDate.now(); | 224 | + LocalDate today = LocalDate.parse(queryDto.getMealTime(), DateUtil.YYYY_MM_DD); |
| 214 | LocalDateTime todayZero = today.atStartOfDay(); | 225 | LocalDateTime todayZero = today.atStartOfDay(); |
| 215 | LocalDate tomorrow = today.plusDays(1); | 226 | LocalDate tomorrow = today.plusDays(1); |
| 216 | LocalDateTime tomorrowZero = tomorrow.atStartOfDay().minusMinutes(1); | 227 | LocalDateTime tomorrowZero = tomorrow.atStartOfDay().minusMinutes(1); |
| ... | @@ -235,6 +246,8 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -235,6 +246,8 @@ public class KdsServiceImpl implements KdsService { |
| 235 | .mealTimeStart(todayZero) | 246 | .mealTimeStart(todayZero) |
| 236 | .shouldFilterMealTimeEnd(true) | 247 | .shouldFilterMealTimeEnd(true) |
| 237 | .mealTimeEnd(tomorrowZero) | 248 | .mealTimeEnd(tomorrowZero) |
| 249 | + .shouldFilterPayStatus(true) | ||
| 250 | + .payStatus(PayStatusEnum.SUCCEED) | ||
| 238 | .build(); | 251 | .build(); |
| 239 | 252 | ||
| 240 | final var orderList = orderServiceRpcClient.getOrdersByCondition(queryOrderDto); | 253 | final var orderList = orderServiceRpcClient.getOrdersByCondition(queryOrderDto); |
| ... | @@ -281,10 +294,9 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -281,10 +294,9 @@ public class KdsServiceImpl implements KdsService { |
| 281 | @Override | 294 | @Override |
| 282 | public List<KdsOrderLocationDto> getOrderDetailByLocation(KdsOrderLocationQueryDto queryDto) { | 295 | public List<KdsOrderLocationDto> getOrderDetailByLocation(KdsOrderLocationQueryDto queryDto) { |
| 283 | // 获取当日用餐的所有的订单 和 订单明细 | 296 | // 获取当日用餐的所有的订单 和 订单明细 |
| 284 | - LocalDate today = LocalDate.now(); | 297 | + LocalDate today = LocalDate.parse(queryDto.getMealTime(), DateUtil.YYYY_MM_DD); |
| 285 | LocalDateTime todayZero = today.atStartOfDay(); | 298 | LocalDateTime todayZero = today.atStartOfDay(); |
| 286 | - LocalDate tomorrow = today.plusDays(1); | 299 | + LocalDateTime todayEnd = today.atTime(LocalTime.MAX); |
| 287 | - LocalDateTime tomorrowZero = tomorrow.atStartOfDay().minusMinutes(1); | ||
| 288 | 300 | ||
| 289 | final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); | 301 | final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); |
| 290 | 302 | ||
| ... | @@ -305,7 +317,7 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -305,7 +317,7 @@ public class KdsServiceImpl implements KdsService { |
| 305 | .shouldFilterMealTimeStart(true) | 317 | .shouldFilterMealTimeStart(true) |
| 306 | .mealTimeStart(todayZero) | 318 | .mealTimeStart(todayZero) |
| 307 | .shouldFilterMealTimeEnd(true) | 319 | .shouldFilterMealTimeEnd(true) |
| 308 | - .mealTimeEnd(tomorrowZero) | 320 | + .mealTimeEnd(todayEnd) |
| 309 | .shouldFilterStatus(true) | 321 | .shouldFilterStatus(true) |
| 310 | .status(queryDto.getOrderStatus()) | 322 | .status(queryDto.getOrderStatus()) |
| 311 | .shouldFilterPayStatus(true) | 323 | .shouldFilterPayStatus(true) |
| ... | @@ -339,6 +351,12 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -339,6 +351,12 @@ public class KdsServiceImpl implements KdsService { |
| 339 | final var filteredOrderDetailList = orderDetailList.stream() | 351 | final var filteredOrderDetailList = orderDetailList.stream() |
| 340 | .filter(od -> od.getMealId() == queryDto.getMealId() && od.getServeStatus() != ServeStatusEnum.SERVE_REJECT) | 352 | .filter(od -> od.getMealId() == queryDto.getMealId() && od.getServeStatus() != ServeStatusEnum.SERVE_REJECT) |
| 341 | .collect(Collectors.toList()); | 353 | .collect(Collectors.toList()); |
| 354 | + | ||
| 355 | + | ||
| 356 | + final var menuIds = orderList.stream().map(SingleClientCustomerOrderRpcResponse::getMenuId).distinct().toList(); | ||
| 357 | + final var menuMap = menuServiceRpcClient.getMenusByIds(operator.getEnterpriseId(), menuIds).getResponsesList().stream().collect(Collectors.toMap(SingleMenuRpcResponse::getId, Function.identity())); | ||
| 358 | + | ||
| 359 | + | ||
| 342 | List<KdsOrderLocationDto> kdsOrderLocationList = new ArrayList<>(); | 360 | List<KdsOrderLocationDto> kdsOrderLocationList = new ArrayList<>(); |
| 343 | 361 | ||
| 344 | for (SingleClientCustomerOrderRpcResponse order : orderList) { | 362 | for (SingleClientCustomerOrderRpcResponse order : orderList) { |
| ... | @@ -395,9 +413,12 @@ public class KdsServiceImpl implements KdsService { | ... | @@ -395,9 +413,12 @@ public class KdsServiceImpl implements KdsService { |
| 395 | final var kdsOrder = KdsOrderLocationDto.builder() | 413 | final var kdsOrder = KdsOrderLocationDto.builder() |
| 396 | .totalCount(order.getTotalNum()) | 414 | .totalCount(order.getTotalNum()) |
| 397 | .remark(order.getRemark()) | 415 | .remark(order.getRemark()) |
| 416 | + .avoidRemark(order.getAvoidRemark()) | ||
| 398 | .orderId(order.getId()) | 417 | .orderId(order.getId()) |
| 399 | .roomNo(order.getSyncRoomNo().isEmpty() ? order.getRoomNo() : order.getSyncRoomNo()) | 418 | .roomNo(order.getSyncRoomNo().isEmpty() ? order.getRoomNo() : order.getSyncRoomNo()) |
| 400 | .tableCode(order.getTableCode()) | 419 | .tableCode(order.getTableCode()) |
| 420 | + .menuId(order.getMenuId()) | ||
| 421 | + .menuName(menuMap.get(order.getMenuId()) == null ? "" : menuMap.get(order.getMenuId()).getName()) | ||
| 401 | .customerNotice(CustomerNotice.builder() | 422 | .customerNotice(CustomerNotice.builder() |
| 402 | .doctors(order.getCustomerNoticeJson().getDoctorsList()) | 423 | .doctors(order.getCustomerNoticeJson().getDoctorsList()) |
| 403 | .avoids(order.getCustomerNoticeJson().getAvoidsList()) | 424 | .avoids(order.getCustomerNoticeJson().getAvoidsList()) | ... | ... |
| ... | @@ -487,6 +487,7 @@ public class OrderServiceImpl implements OrderService { | ... | @@ -487,6 +487,7 @@ public class OrderServiceImpl implements OrderService { |
| 487 | .mealTime(DateUtil.formatDate(r.getMealTime())) | 487 | .mealTime(DateUtil.formatDate(r.getMealTime())) |
| 488 | .orderType(r.getOrderTypeValue()) | 488 | .orderType(r.getOrderTypeValue()) |
| 489 | .remark(r.getRemark()) | 489 | .remark(r.getRemark()) |
| 490 | + .avoidRemark(r.getAvoidRemark()) | ||
| 490 | .isDeleted(r.getIsDeleted()) | 491 | .isDeleted(r.getIsDeleted()) |
| 491 | .isRead(r.getIsRead()) | 492 | .isRead(r.getIsRead()) |
| 492 | .creationSource(r.getCreationSource().getNumber()) | 493 | .creationSource(r.getCreationSource().getNumber()) | ... | ... |
| 1 | package com.infoloop.tianting.service.impl; | 1 | package com.infoloop.tianting.service.impl; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.date.LocalDateTimeUtil; | ||
| 4 | +import com.infoloop.tianting.SingleDishSkuByIdsRpcResponse; | ||
| 5 | +import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum; | ||
| 3 | import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; | 6 | import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; |
| 7 | +import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; | ||
| 4 | import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum; | 8 | import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum; |
| 5 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse; | 9 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse; |
| 6 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse; | 10 | import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse; |
| 11 | +import com.infoloop.tianting.clientcustomerservice.SingleClientCustomerRpcResponse; | ||
| 7 | import com.infoloop.tianting.clientinventoryservice.SingleClientRpcResponse; | 12 | import com.infoloop.tianting.clientinventoryservice.SingleClientRpcResponse; |
| 8 | import com.infoloop.tianting.context.LoginContextHolder; | 13 | import com.infoloop.tianting.context.LoginContextHolder; |
| 9 | import com.infoloop.tianting.enums.SettlementDimensionEnum; | 14 | import com.infoloop.tianting.enums.SettlementDimensionEnum; |
| ... | @@ -12,35 +17,53 @@ import com.infoloop.tianting.exception.ErrorCodeEnum; | ... | @@ -12,35 +17,53 @@ import com.infoloop.tianting.exception.ErrorCodeEnum; |
| 12 | import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse; | 17 | import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse; |
| 13 | import com.infoloop.tianting.menuservice.SingleMenuRpcResponse; | 18 | import com.infoloop.tianting.menuservice.SingleMenuRpcResponse; |
| 14 | import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto; | 19 | import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto; |
| 20 | +import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderDto; | ||
| 21 | +import com.infoloop.tianting.model.dto.SettlementDTO; | ||
| 22 | +import com.infoloop.tianting.model.dto.SettlementDTO.SeparateMealDataDto; | ||
| 23 | +import com.infoloop.tianting.model.dto.SettlementDTO.SeparateMealDetail; | ||
| 15 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataByMealDto; | 24 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataByMealDto; |
| 16 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataDto; | 25 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataDto; |
| 17 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuMealDto; | 26 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuMealDto; |
| 18 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuSkuDto; | 27 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuSkuDto; |
| 19 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto; | 28 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto; |
| 29 | +import com.infoloop.tianting.model.enums.desc.BaseProtoDescEnum; | ||
| 30 | +import com.infoloop.tianting.model.enums.desc.OnlinePayDescEnum; | ||
| 20 | import com.infoloop.tianting.service.SettlementService; | 31 | import com.infoloop.tianting.service.SettlementService; |
| 32 | +import com.infoloop.tianting.service.client.ClientCustomerServiceRpcClient; | ||
| 21 | import com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient; | 33 | import com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient; |
| 22 | import com.infoloop.tianting.service.client.MealServiceRpcClient; | 34 | import com.infoloop.tianting.service.client.MealServiceRpcClient; |
| 23 | import com.infoloop.tianting.service.client.MenuServiceRpcClient; | 35 | import com.infoloop.tianting.service.client.MenuServiceRpcClient; |
| 24 | import com.infoloop.tianting.service.client.OrderServiceRpcClient; | 36 | import com.infoloop.tianting.service.client.OrderServiceRpcClient; |
| 25 | import com.infoloop.tianting.service.client.SkuServiceRpcClient; | 37 | import com.infoloop.tianting.service.client.SkuServiceRpcClient; |
| 38 | +import com.infoloop.tianting.setmealscheduleservice.SingleMealRpcResponse; | ||
| 26 | import com.infoloop.tianting.utils.DateUtil; | 39 | import com.infoloop.tianting.utils.DateUtil; |
| 27 | import lombok.RequiredArgsConstructor; | 40 | import lombok.RequiredArgsConstructor; |
| 28 | import lombok.extern.slf4j.Slf4j; | 41 | import lombok.extern.slf4j.Slf4j; |
| 42 | +import org.apache.poi.ss.usermodel.BorderStyle; | ||
| 29 | import org.apache.poi.ss.usermodel.Cell; | 43 | import org.apache.poi.ss.usermodel.Cell; |
| 44 | +import org.apache.poi.ss.usermodel.CellStyle; | ||
| 45 | +import org.apache.poi.ss.usermodel.Font; | ||
| 46 | +import org.apache.poi.ss.usermodel.HorizontalAlignment; | ||
| 47 | +import org.apache.poi.ss.usermodel.IndexedColors; | ||
| 30 | import org.apache.poi.ss.usermodel.Row; | 48 | import org.apache.poi.ss.usermodel.Row; |
| 31 | import org.apache.poi.ss.usermodel.Sheet; | 49 | import org.apache.poi.ss.usermodel.Sheet; |
| 50 | +import org.apache.poi.ss.usermodel.VerticalAlignment; | ||
| 32 | import org.apache.poi.ss.usermodel.Workbook; | 51 | import org.apache.poi.ss.usermodel.Workbook; |
| 33 | import org.apache.poi.ss.util.CellRangeAddress; | 52 | import org.apache.poi.ss.util.CellRangeAddress; |
| 53 | +import org.apache.poi.ss.util.RegionUtil; | ||
| 34 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; | 54 | import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| 35 | import org.springframework.beans.factory.annotation.Autowired; | 55 | import org.springframework.beans.factory.annotation.Autowired; |
| 36 | import org.springframework.stereotype.Service; | 56 | import org.springframework.stereotype.Service; |
| 37 | 57 | ||
| 38 | import java.io.ByteArrayOutputStream; | 58 | import java.io.ByteArrayOutputStream; |
| 39 | import java.io.IOException; | 59 | import java.io.IOException; |
| 60 | +import java.math.BigDecimal; | ||
| 61 | +import java.math.RoundingMode; | ||
| 40 | import java.time.LocalDate; | 62 | import java.time.LocalDate; |
| 41 | import java.time.LocalDateTime; | 63 | import java.time.LocalDateTime; |
| 42 | import java.time.temporal.ChronoUnit; | 64 | import java.time.temporal.ChronoUnit; |
| 43 | import java.util.ArrayList; | 65 | import java.util.ArrayList; |
| 66 | +import java.util.Collections; | ||
| 44 | import java.util.Comparator; | 67 | import java.util.Comparator; |
| 45 | import java.util.HashMap; | 68 | import java.util.HashMap; |
| 46 | import java.util.List; | 69 | import java.util.List; |
| ... | @@ -57,6 +80,7 @@ public class SettlementServiceImpl implements SettlementService { | ... | @@ -57,6 +80,7 @@ public class SettlementServiceImpl implements SettlementService { |
| 57 | private final SkuServiceRpcClient skuServiceRpcClient; | 80 | private final SkuServiceRpcClient skuServiceRpcClient; |
| 58 | private final ClientInventoryServiceRpcClient clientInventoryServiceRpcClient; | 81 | private final ClientInventoryServiceRpcClient clientInventoryServiceRpcClient; |
| 59 | private final MealServiceRpcClient mealServiceRpcClient; | 82 | private final MealServiceRpcClient mealServiceRpcClient; |
| 83 | + private final ClientCustomerServiceRpcClient clientCustomerServiceRpcClient; | ||
| 60 | 84 | ||
| 61 | public static ByteArrayOutputStream writeToExcelBySku(SettlementDataDto settlementDataDto) | 85 | public static ByteArrayOutputStream writeToExcelBySku(SettlementDataDto settlementDataDto) |
| 62 | throws IOException { | 86 | throws IOException { |
| ... | @@ -272,9 +296,557 @@ public class SettlementServiceImpl implements SettlementService { | ... | @@ -272,9 +296,557 @@ public class SettlementServiceImpl implements SettlementService { |
| 272 | public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) { | 296 | public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) { |
| 273 | if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_SKU)) { | 297 | if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_SKU)) { |
| 274 | return generateOrderSettlementExcelBySku(settlementRequest); | 298 | return generateOrderSettlementExcelBySku(settlementRequest); |
| 275 | - } else { | 299 | + } else if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_MEAL)) { |
| 276 | return generateOrderSettlementExcelByMeal(settlementRequest); | 300 | return generateOrderSettlementExcelByMeal(settlementRequest); |
| 301 | + } else if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_ORDER)) { | ||
| 302 | + return generateOrderSettlementExcelByOrder(settlementRequest); | ||
| 277 | } | 303 | } |
| 304 | + return null; | ||
| 305 | + } | ||
| 306 | + | ||
| 307 | + private ByteArrayOutputStream generateOrderSettlementExcelByOrder(SettlementRequestDto settlementRequest) { | ||
| 308 | + // 参数校验 | ||
| 309 | + if (settlementRequest == null || settlementRequest.getTimeStart() == null || settlementRequest.getTimeEnd() == null) { | ||
| 310 | + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR); | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + // 计算日期范围 | ||
| 314 | + final var startDate = settlementRequest.getTimeStart().plusHours(8).toLocalDate().atStartOfDay(); | ||
| 315 | + final var endDate = settlementRequest.getTimeEnd().plusHours(8).toLocalDate().plusDays(1).atStartOfDay(); | ||
| 316 | + | ||
| 317 | + // 获取企业ID | ||
| 318 | + final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); | ||
| 319 | + final int enterpriseId = LoginContextHolder.hasLogin() ? operatorLoginInfo.getEnterpriseId() : settlementRequest.getEnterpriseId(); | ||
| 320 | + | ||
| 321 | + // 构建查询条件 | ||
| 322 | + final var queryOrderDto = QueryOrderByConditionDto.builder() | ||
| 323 | + .enterpriseId(enterpriseId) | ||
| 324 | + .shouldFilterCreatedAtTimeStart(true) | ||
| 325 | + .createdAtTimeStart(startDate) | ||
| 326 | + .shouldFilterCreatedAtTimeEnd(true) | ||
| 327 | + .createdAtTimeEnd(endDate) | ||
| 328 | + .shouldFilterStallIds(settlementRequest.getStallIds() != null && !settlementRequest.getStallIds().isEmpty()) | ||
| 329 | + .stallIds(settlementRequest.getStallIds() != null ? settlementRequest.getStallIds() : Collections.emptyList()) | ||
| 330 | + .build(); | ||
| 331 | + | ||
| 332 | + // 查询订单列表 | ||
| 333 | + final var orderList = orderServiceRpcClient.getOrdersByCondition(queryOrderDto); | ||
| 334 | + if (orderList == null || orderList.isEmpty()) { | ||
| 335 | + log.warn("未查询到订单数据,enterpriseId: {}, startDate: {}, endDate: {}", enterpriseId, startDate, endDate); | ||
| 336 | + return createEmptyExcelByOrder(); | ||
| 337 | + } | ||
| 338 | + | ||
| 339 | + // 筛选有效订单ID | ||
| 340 | + List<Integer> orderIds = orderList.stream() | ||
| 341 | + .filter(Objects::nonNull) | ||
| 342 | + .filter(o -> { | ||
| 343 | + // 在线支付订单需要支付成功 | ||
| 344 | + if (o.getOnlinePay() != null && o.getOnlinePay() == OnlinePayEnum.ONLINE) { | ||
| 345 | + return o.getPayStatus() != null && o.getPayStatus() == PayStatusEnum.SUCCEED; | ||
| 346 | + } else { | ||
| 347 | + // 非在线支付订单需要未取消 | ||
| 348 | + return o.getStatus() != null && o.getStatus() != OrderStatusEnum.ORDER_CANCELED; | ||
| 349 | + } | ||
| 350 | + }) | ||
| 351 | + .map(SingleClientCustomerOrderRpcResponse::getId) | ||
| 352 | + .filter(Objects::nonNull) | ||
| 353 | + .distinct() | ||
| 354 | + .collect(Collectors.toList()); | ||
| 355 | + | ||
| 356 | + if (orderIds.isEmpty()) { | ||
| 357 | + log.warn("筛选后无有效订单,enterpriseId: {}", enterpriseId); | ||
| 358 | + return createEmptyExcelByOrder(); | ||
| 359 | + } | ||
| 360 | + | ||
| 361 | + // 构建订单映射 | ||
| 362 | + final var orderMap = orderList.stream() | ||
| 363 | + .filter(Objects::nonNull) | ||
| 364 | + .filter(o -> o.getId() != 0) | ||
| 365 | + .collect(Collectors.toMap(SingleClientCustomerOrderRpcResponse::getId, o -> o, (o1, o2) -> o1)); | ||
| 366 | + | ||
| 367 | + // 查询订单详情 | ||
| 368 | + final var orderDetailList = orderServiceRpcClient.getOrderDetailsByOrderIds(orderIds); | ||
| 369 | + if (orderDetailList == null || orderDetailList.isEmpty()) { | ||
| 370 | + log.warn("未查询到订单详情数据,orderIds: {}", orderIds); | ||
| 371 | + return createEmptyExcelByOrder(); | ||
| 372 | + } | ||
| 373 | + | ||
| 374 | + // 订单详情按订单ID分组 | ||
| 375 | + final var orderDetailGroupByOrderId = orderDetailList.stream() | ||
| 376 | + .filter(Objects::nonNull) | ||
| 377 | + .filter(d -> d.getServeStatus() != null && !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT)) | ||
| 378 | + .collect(Collectors.groupingBy(SingleClientCustomerOrderDetailRpcResponse::getOrderId)); | ||
| 379 | + | ||
| 380 | + // 获取SKU数据 | ||
| 381 | + List<Integer> skuIds = orderDetailList.stream() | ||
| 382 | + .filter(Objects::nonNull) | ||
| 383 | + .filter(d -> d.getServeStatus() != null && !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT)) | ||
| 384 | + .map(SingleClientCustomerOrderDetailRpcResponse::getSkuId) | ||
| 385 | + .filter(Objects::nonNull) | ||
| 386 | + .distinct() | ||
| 387 | + .collect(Collectors.toList()); | ||
| 388 | + | ||
| 389 | + final var skuResponse = skuServiceRpcClient.getDishSkusByIds(skuIds); | ||
| 390 | + final List<SingleDishSkuByIdsRpcResponse> skus = skuResponse != null ? skuResponse.getResponseList() : new ArrayList<>(); | ||
| 391 | + final var skuMap = skus.stream() | ||
| 392 | + .filter(Objects::nonNull) | ||
| 393 | + .filter(s -> s.getId() != 0) | ||
| 394 | + .collect(Collectors.toMap(SingleDishSkuByIdsRpcResponse::getId, s -> s, (s1, s2) -> s1)); | ||
| 395 | + | ||
| 396 | + // 获取餐别数据 | ||
| 397 | + final var mealResponse = mealServiceRpcClient.getAllMeals(enterpriseId); | ||
| 398 | + final List<SingleMealRpcResponse> meals = mealResponse != null ? mealResponse.getResponsesList() : new ArrayList<>(); | ||
| 399 | + final var mealMap = meals.stream() | ||
| 400 | + .filter(Objects::nonNull) | ||
| 401 | + .filter(m -> m.getId() != 0) | ||
| 402 | + .collect(Collectors.toMap(SingleMealRpcResponse::getId, m -> m, (m1, m2) -> m1)); | ||
| 403 | + | ||
| 404 | + // 获取菜单数据 | ||
| 405 | + List<Integer> menuIds = orderList.stream() | ||
| 406 | + .filter(Objects::nonNull) | ||
| 407 | + .map(SingleClientCustomerOrderRpcResponse::getMenuId) | ||
| 408 | + .filter(id -> id != 0) | ||
| 409 | + .distinct() | ||
| 410 | + .collect(Collectors.toList()); | ||
| 411 | + | ||
| 412 | + final var menuResponse = menuServiceRpcClient.getMenusByIds(enterpriseId, menuIds); | ||
| 413 | + final List<SingleMenuRpcResponse> menuList = menuResponse != null ? menuResponse.getResponsesList() : new ArrayList<>(); | ||
| 414 | + final var menuMap = menuList.stream() | ||
| 415 | + .filter(Objects::nonNull) | ||
| 416 | + .filter(m -> m.getId() != 0) | ||
| 417 | + .collect(Collectors.toMap(SingleMenuRpcResponse::getId, m -> m, (m1, m2) -> m1)); | ||
| 418 | + | ||
| 419 | + // 获取菜单详情数据 | ||
| 420 | + final var menuDetailResponse = menuServiceRpcClient.queryMenuDetailsByMenuIds(enterpriseId, menuIds); | ||
| 421 | + final List<SingleMenuDetailRpcResponse> menuDetailList = menuDetailResponse != null ? menuDetailResponse.getResponsesList() : new ArrayList<>(); | ||
| 422 | + final var menuDetailMap = menuDetailList.stream() | ||
| 423 | + .filter(Objects::nonNull) | ||
| 424 | + .filter(m -> m.getId() != 0) | ||
| 425 | + .collect(Collectors.toMap(SingleMenuDetailRpcResponse::getId, m -> m, (m1, m2) -> m1)); | ||
| 426 | + | ||
| 427 | + // 获取客户数据 | ||
| 428 | + List<Integer> customerIds = orderList.stream() | ||
| 429 | + .filter(Objects::nonNull) | ||
| 430 | + .map(SingleClientCustomerOrderRpcResponse::getCustomerId) | ||
| 431 | + .filter(id -> id != 0) | ||
| 432 | + .distinct() | ||
| 433 | + .collect(Collectors.toList()); | ||
| 434 | + | ||
| 435 | + final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds); | ||
| 436 | + final List<SingleClientCustomerRpcResponse> customers = customerResponse != null ? customerResponse.getResponsesList() : new ArrayList<>(); | ||
| 437 | + final var customerMap = customers.stream() | ||
| 438 | + .filter(Objects::nonNull) | ||
| 439 | + .filter(c -> c.getId() != 0) | ||
| 440 | + .collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1)); | ||
| 441 | + | ||
| 442 | + // 构建结算订单明细 | ||
| 443 | + final var classifyOrders = new ArrayList<SettlementDTO.SettlementOrderDetail>(); | ||
| 444 | + for (Integer orderId : orderIds) { | ||
| 445 | + final var orderDetails = orderDetailGroupByOrderId.getOrDefault(orderId, Collections.emptyList()); | ||
| 446 | + final var order = orderMap.get(orderId); | ||
| 447 | + | ||
| 448 | + // 订单为空则跳过 | ||
| 449 | + if (order == null) { | ||
| 450 | + log.warn("订单不存在,orderId: {}", orderId); | ||
| 451 | + continue; | ||
| 452 | + } | ||
| 453 | + | ||
| 454 | + // 获取菜单信息 | ||
| 455 | + final var menu = menuMap.get(order.getMenuId()); | ||
| 456 | + final String menuName = menu != null ? menu.getName() : ""; | ||
| 457 | + | ||
| 458 | + // 获取客户信息 | ||
| 459 | + final var customer = customerMap.get(order.getCustomerId()); | ||
| 460 | + final String customerName = customer != null ? customer.getName() : ""; | ||
| 461 | + final String hisCustomerNo = customer != null ? customer.getHISCustomerNo() : ""; | ||
| 462 | + | ||
| 463 | + // 处理每个订单详情 | ||
| 464 | + for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) { | ||
| 465 | + if (orderDetail == null) { | ||
| 466 | + continue; | ||
| 467 | + } | ||
| 468 | + | ||
| 469 | + // 安全获取餐别名称 | ||
| 470 | + String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap); | ||
| 471 | + | ||
| 472 | + // 安全获取SKU名称 | ||
| 473 | + String skuName = getSkuNameSafely(orderDetail, skuMap); | ||
| 474 | + | ||
| 475 | + // 安全获取房间号 | ||
| 476 | + String roomNo = getRoomNoSafely(order); | ||
| 477 | + | ||
| 478 | + // 安全获取忌口和医嘱 | ||
| 479 | + List<String> avoids = getAvoidsSafely(order); | ||
| 480 | + List<String> doctors = getDoctorsSafely(order); | ||
| 481 | + | ||
| 482 | + // 安全获取在线支付描述 | ||
| 483 | + String onlinePayDesc = getOnlinePayDescSafely(order); | ||
| 484 | + | ||
| 485 | + // 构建订单详情 | ||
| 486 | + SettlementDTO.SettlementOrderDetail settlementOrderDetail = SettlementDTO.SettlementOrderDetail.builder() | ||
| 487 | + .mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "") | ||
| 488 | + .code(order.getOrderCode() != null ? order.getOrderCode() : "") | ||
| 489 | + .mealName(mealName) | ||
| 490 | + .roomNo(roomNo) | ||
| 491 | + .customerName(customerName) | ||
| 492 | + .HISCustomerNo(hisCustomerNo) | ||
| 493 | + .avoids(avoids) | ||
| 494 | + .doctors(doctors) | ||
| 495 | + .menuName(menuName) | ||
| 496 | + .skuName(skuName) | ||
| 497 | + .count(orderDetail.getCount() != 0 ? orderDetail.getCount() : 0) | ||
| 498 | + .price(calculatePrice(orderDetail.getPrice())) | ||
| 499 | + .totalPrice(calculateTotalPrice(orderDetail.getPrice(), orderDetail.getCount())) | ||
| 500 | + .remark(order.getRemark() != null ? order.getRemark() : "") | ||
| 501 | + .avoidRemark(order.getAvoidRemark() != null ? order.getAvoidRemark() : "") | ||
| 502 | + .onlinePay(onlinePayDesc) | ||
| 503 | + .build(); | ||
| 504 | + classifyOrders.add(settlementOrderDetail); | ||
| 505 | + } | ||
| 506 | + } | ||
| 507 | + | ||
| 508 | + // 构建结算数据 | ||
| 509 | + final var settlementDataByOrderDto = SettlementDTO.SettlementDataByOrderDto.builder() | ||
| 510 | + .classifyOrders(classifyOrders) | ||
| 511 | + .build(); | ||
| 512 | + | ||
| 513 | + // 生成Excel | ||
| 514 | + try { | ||
| 515 | + return writeToExcelByOrder(settlementDataByOrderDto); | ||
| 516 | + } catch (IOException e) { | ||
| 517 | + log.error("生成按订单结算Excel失败", e); | ||
| 518 | + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR); | ||
| 519 | + } | ||
| 520 | + } | ||
| 521 | + | ||
| 522 | + /** | ||
| 523 | + * 安全获取餐别名称 | ||
| 524 | + */ | ||
| 525 | + private String getMealNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail, | ||
| 526 | + Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap, | ||
| 527 | + Map<Integer, SingleMealRpcResponse> mealMap) { | ||
| 528 | + if (orderDetail == null || orderDetail.getMenuDetailId() == 0) { | ||
| 529 | + return ""; | ||
| 530 | + } | ||
| 531 | + | ||
| 532 | + final var menuDetail = menuDetailMap.get(orderDetail.getMenuDetailId()); | ||
| 533 | + if (menuDetail == null || menuDetail.getMealId() == 0) { | ||
| 534 | + return ""; | ||
| 535 | + } | ||
| 536 | + | ||
| 537 | + final var meal = mealMap.get(menuDetail.getMealId()); | ||
| 538 | + return meal != null && meal.getName() != null ? meal.getName() : ""; | ||
| 539 | + } | ||
| 540 | + | ||
| 541 | + /** | ||
| 542 | + * 安全获取SKU名称 | ||
| 543 | + */ | ||
| 544 | + private String getSkuNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail, | ||
| 545 | + Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) { | ||
| 546 | + if (orderDetail == null || orderDetail.getSkuId() == 0) { | ||
| 547 | + return ""; | ||
| 548 | + } | ||
| 549 | + | ||
| 550 | + final var sku = skuMap.get(orderDetail.getSkuId()); | ||
| 551 | + return sku != null && sku.getName() != null ? sku.getName() : ""; | ||
| 552 | + } | ||
| 553 | + | ||
| 554 | + /** | ||
| 555 | + * 安全获取房间号 | ||
| 556 | + */ | ||
| 557 | + private String getRoomNoSafely(SingleClientCustomerOrderRpcResponse order) { | ||
| 558 | + if (order == null) { | ||
| 559 | + return ""; | ||
| 560 | + } | ||
| 561 | + | ||
| 562 | + String syncRoomNo = order.getSyncRoomNo(); | ||
| 563 | + if (syncRoomNo != null && !syncRoomNo.isEmpty()) { | ||
| 564 | + return syncRoomNo; | ||
| 565 | + } | ||
| 566 | + | ||
| 567 | + String roomNo = order.getRoomNo(); | ||
| 568 | + return roomNo != null ? roomNo : ""; | ||
| 569 | + } | ||
| 570 | + | ||
| 571 | + /** | ||
| 572 | + * 安全获取忌口列表 | ||
| 573 | + */ | ||
| 574 | + private List<String> getAvoidsSafely(SingleClientCustomerOrderRpcResponse order) { | ||
| 575 | + if (order == null || order.getCustomerNoticeJson() == null) { | ||
| 576 | + return Collections.emptyList(); | ||
| 577 | + } | ||
| 578 | + | ||
| 579 | + List<String> avoids = order.getCustomerNoticeJson().getAvoidsList(); | ||
| 580 | + return avoids != null ? avoids : Collections.emptyList(); | ||
| 581 | + } | ||
| 582 | + | ||
| 583 | + /** | ||
| 584 | + * 安全获取医嘱列表 | ||
| 585 | + */ | ||
| 586 | + private List<String> getDoctorsSafely(SingleClientCustomerOrderRpcResponse order) { | ||
| 587 | + if (order == null || order.getCustomerNoticeJson() == null) { | ||
| 588 | + return Collections.emptyList(); | ||
| 589 | + } | ||
| 590 | + | ||
| 591 | + List<String> doctors = order.getCustomerNoticeJson().getDoctorsList(); | ||
| 592 | + return doctors != null ? doctors : Collections.emptyList(); | ||
| 593 | + } | ||
| 594 | + | ||
| 595 | + /** | ||
| 596 | + * 安全获取在线支付描述 | ||
| 597 | + */ | ||
| 598 | + private String getOnlinePayDescSafely(SingleClientCustomerOrderRpcResponse order) { | ||
| 599 | + if (order == null || order.getOnlinePay() == null) { | ||
| 600 | + return ""; | ||
| 601 | + } | ||
| 602 | + | ||
| 603 | + try { | ||
| 604 | + String desc = BaseProtoDescEnum.getDescByProtoEnum(order.getOnlinePay(), OnlinePayDescEnum.class); | ||
| 605 | + return desc != null ? desc : ""; | ||
| 606 | + } catch (Exception e) { | ||
| 607 | + log.warn("获取在线支付描述失败,orderId: {}", order.getId(), e); | ||
| 608 | + return ""; | ||
| 609 | + } | ||
| 610 | + } | ||
| 611 | + | ||
| 612 | + /** | ||
| 613 | + * 计算单价 | ||
| 614 | + */ | ||
| 615 | + private BigDecimal calculatePrice(Integer price) { | ||
| 616 | + if (price == null) { | ||
| 617 | + return BigDecimal.ZERO; | ||
| 618 | + } | ||
| 619 | + return new BigDecimal(price).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP); | ||
| 620 | + } | ||
| 621 | + | ||
| 622 | + /** | ||
| 623 | + * 计算总价 | ||
| 624 | + */ | ||
| 625 | + private BigDecimal calculateTotalPrice(Integer price, Integer count) { | ||
| 626 | + if (price == null || count == null) { | ||
| 627 | + return BigDecimal.ZERO; | ||
| 628 | + } | ||
| 629 | + return new BigDecimal(price) | ||
| 630 | + .multiply(new BigDecimal(count)) | ||
| 631 | + .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP); | ||
| 632 | + } | ||
| 633 | + | ||
| 634 | + /** | ||
| 635 | + * 创建空的订单Excel | ||
| 636 | + */ | ||
| 637 | + private ByteArrayOutputStream createEmptyExcelByOrder() { | ||
| 638 | + try { | ||
| 639 | + final var emptyData = SettlementDTO.SettlementDataByOrderDto.builder() | ||
| 640 | + .classifyOrders(Collections.emptyList()) | ||
| 641 | + .build(); | ||
| 642 | + return writeToExcelByOrder(emptyData); | ||
| 643 | + } catch (IOException e) { | ||
| 644 | + log.error("创建空Excel失败", e); | ||
| 645 | + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR); | ||
| 646 | + } | ||
| 647 | + } | ||
| 648 | + | ||
| 649 | + /** | ||
| 650 | + * 按订单维度生成Excel | ||
| 651 | + */ | ||
| 652 | + private static ByteArrayOutputStream writeToExcelByOrder(SettlementDTO.SettlementDataByOrderDto settlementDataDto) | ||
| 653 | + throws IOException { | ||
| 654 | + Workbook workbook = new XSSFWorkbook(); | ||
| 655 | + Sheet sheet = workbook.createSheet("客人结算"); | ||
| 656 | + | ||
| 657 | + // 创建表头样式(黑色边框) | ||
| 658 | + CellStyle headerStyle = workbook.createCellStyle(); | ||
| 659 | + headerStyle.setBorderTop(BorderStyle.THIN); | ||
| 660 | + headerStyle.setBorderBottom(BorderStyle.THIN); | ||
| 661 | + headerStyle.setBorderLeft(BorderStyle.THIN); | ||
| 662 | + headerStyle.setBorderRight(BorderStyle.THIN); | ||
| 663 | + headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 664 | + headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 665 | + headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 666 | + headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 667 | + | ||
| 668 | + // 创建数据行样式(浅灰色边框) | ||
| 669 | + CellStyle dataStyle = workbook.createCellStyle(); | ||
| 670 | + dataStyle.setBorderTop(BorderStyle.THIN); | ||
| 671 | + dataStyle.setBorderBottom(BorderStyle.THIN); | ||
| 672 | + dataStyle.setBorderLeft(BorderStyle.THIN); | ||
| 673 | + dataStyle.setBorderRight(BorderStyle.THIN); | ||
| 674 | + dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 675 | + dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 676 | + dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 677 | + dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 678 | + | ||
| 679 | + int rowNum = 0; | ||
| 680 | + | ||
| 681 | + // 创建表头 | ||
| 682 | + Row titleRow = sheet.createRow(rowNum++); | ||
| 683 | + int columnNum = 0; | ||
| 684 | + | ||
| 685 | + Cell cell0 = titleRow.createCell(columnNum++); | ||
| 686 | + cell0.setCellValue("用餐时间"); | ||
| 687 | + cell0.setCellStyle(headerStyle); | ||
| 688 | + | ||
| 689 | + Cell cell1 = titleRow.createCell(columnNum++); | ||
| 690 | + cell1.setCellValue("订单号"); | ||
| 691 | + cell1.setCellStyle(headerStyle); | ||
| 692 | + | ||
| 693 | + Cell cell2 = titleRow.createCell(columnNum++); | ||
| 694 | + cell2.setCellValue("餐别"); | ||
| 695 | + cell2.setCellStyle(headerStyle); | ||
| 696 | + | ||
| 697 | + Cell cell3 = titleRow.createCell(columnNum++); | ||
| 698 | + cell3.setCellValue("房间号"); | ||
| 699 | + cell3.setCellStyle(headerStyle); | ||
| 700 | + | ||
| 701 | + Cell cell4 = titleRow.createCell(columnNum++); | ||
| 702 | + cell4.setCellValue("客户姓名"); | ||
| 703 | + cell4.setCellStyle(headerStyle); | ||
| 704 | + | ||
| 705 | + Cell cell5 = titleRow.createCell(columnNum++); | ||
| 706 | + cell5.setCellValue("客户腕带号"); | ||
| 707 | + cell5.setCellStyle(headerStyle); | ||
| 708 | + | ||
| 709 | + Cell cell6 = titleRow.createCell(columnNum++); | ||
| 710 | + cell6.setCellValue("忌口信息"); | ||
| 711 | + cell6.setCellStyle(headerStyle); | ||
| 712 | + | ||
| 713 | + Cell cell7 = titleRow.createCell(columnNum++); | ||
| 714 | + cell7.setCellValue("医嘱信息"); | ||
| 715 | + cell7.setCellStyle(headerStyle); | ||
| 716 | + | ||
| 717 | + Cell cell8 = titleRow.createCell(columnNum++); | ||
| 718 | + cell8.setCellValue("餐单名称"); | ||
| 719 | + cell8.setCellStyle(headerStyle); | ||
| 720 | + | ||
| 721 | + Cell cell9 = titleRow.createCell(columnNum++); | ||
| 722 | + cell9.setCellValue("菜品名称"); | ||
| 723 | + cell9.setCellStyle(headerStyle); | ||
| 724 | + | ||
| 725 | + Cell cell10 = titleRow.createCell(columnNum++); | ||
| 726 | + cell10.setCellValue("菜品份数"); | ||
| 727 | + cell10.setCellStyle(headerStyle); | ||
| 728 | + | ||
| 729 | + Cell cell11 = titleRow.createCell(columnNum++); | ||
| 730 | + cell11.setCellValue("菜品单价"); | ||
| 731 | + cell11.setCellStyle(headerStyle); | ||
| 732 | + | ||
| 733 | + Cell cell12 = titleRow.createCell(columnNum++); | ||
| 734 | + cell12.setCellValue("菜品金额"); | ||
| 735 | + cell12.setCellStyle(headerStyle); | ||
| 736 | + | ||
| 737 | + Cell cell13 = titleRow.createCell(columnNum++); | ||
| 738 | + cell13.setCellValue("备注"); | ||
| 739 | + cell13.setCellStyle(headerStyle); | ||
| 740 | + | ||
| 741 | + Cell cell14 = titleRow.createCell(columnNum++); | ||
| 742 | + cell14.setCellValue("支付方式"); | ||
| 743 | + cell14.setCellStyle(headerStyle); | ||
| 744 | + | ||
| 745 | + // 填充数据 | ||
| 746 | + final var classifyOrders = settlementDataDto.getClassifyOrders(); | ||
| 747 | + if (classifyOrders != null) { | ||
| 748 | + for (SettlementDTO.SettlementOrderDetail orderDetail : classifyOrders) { | ||
| 749 | + Row dataRow = sheet.createRow(rowNum++); | ||
| 750 | + columnNum = 0; | ||
| 751 | + | ||
| 752 | + Cell dataCell0 = dataRow.createCell(columnNum++); | ||
| 753 | + dataCell0.setCellValue(orderDetail.getMealTime() != null ? orderDetail.getMealTime() : ""); | ||
| 754 | + dataCell0.setCellStyle(dataStyle); | ||
| 755 | + | ||
| 756 | + Cell dataCell1 = dataRow.createCell(columnNum++); | ||
| 757 | + dataCell1.setCellValue(orderDetail.getCode() != null ? orderDetail.getCode() : ""); | ||
| 758 | + dataCell1.setCellStyle(dataStyle); | ||
| 759 | + | ||
| 760 | + Cell dataCell2 = dataRow.createCell(columnNum++); | ||
| 761 | + dataCell2.setCellValue(orderDetail.getMealName() != null ? orderDetail.getMealName() : ""); | ||
| 762 | + dataCell2.setCellStyle(dataStyle); | ||
| 763 | + | ||
| 764 | + Cell dataCell3 = dataRow.createCell(columnNum++); | ||
| 765 | + dataCell3.setCellValue(orderDetail.getRoomNo() != null ? orderDetail.getRoomNo() : ""); | ||
| 766 | + dataCell3.setCellStyle(dataStyle); | ||
| 767 | + | ||
| 768 | + Cell dataCell4 = dataRow.createCell(columnNum++); | ||
| 769 | + dataCell4.setCellValue(orderDetail.getCustomerName() != null ? orderDetail.getCustomerName() : ""); | ||
| 770 | + dataCell4.setCellStyle(dataStyle); | ||
| 771 | + | ||
| 772 | + Cell dataCell5 = dataRow.createCell(columnNum++); | ||
| 773 | + dataCell5.setCellValue(orderDetail.getHISCustomerNo() != null ? orderDetail.getHISCustomerNo() : ""); | ||
| 774 | + dataCell5.setCellStyle(dataStyle); | ||
| 775 | + | ||
| 776 | + // 忌口列表转字符串 | ||
| 777 | + String avoidsStr = orderDetail.getAvoids() != null ? String.join(", ", orderDetail.getAvoids()) : ""; | ||
| 778 | + Cell dataCell6 = dataRow.createCell(columnNum++); | ||
| 779 | + dataCell6.setCellValue(avoidsStr); | ||
| 780 | + dataCell6.setCellStyle(dataStyle); | ||
| 781 | + | ||
| 782 | + // 医嘱列表转字符串 | ||
| 783 | + String doctorsStr = orderDetail.getDoctors() != null ? String.join(", ", orderDetail.getDoctors()) : ""; | ||
| 784 | + Cell dataCell7 = dataRow.createCell(columnNum++); | ||
| 785 | + dataCell7.setCellValue(doctorsStr); | ||
| 786 | + dataCell7.setCellStyle(dataStyle); | ||
| 787 | + | ||
| 788 | + Cell dataCell8 = dataRow.createCell(columnNum++); | ||
| 789 | + dataCell8.setCellValue(orderDetail.getMenuName() != null ? orderDetail.getMenuName() : ""); | ||
| 790 | + dataCell8.setCellStyle(dataStyle); | ||
| 791 | + | ||
| 792 | + Cell dataCell9 = dataRow.createCell(columnNum++); | ||
| 793 | + dataCell9.setCellValue(orderDetail.getSkuName() != null ? orderDetail.getSkuName() : ""); | ||
| 794 | + dataCell9.setCellStyle(dataStyle); | ||
| 795 | + | ||
| 796 | + Cell dataCell10 = dataRow.createCell(columnNum++); | ||
| 797 | + dataCell10.setCellValue(orderDetail.getCount() != null ? orderDetail.getCount() : 0); | ||
| 798 | + dataCell10.setCellStyle(dataStyle); | ||
| 799 | + | ||
| 800 | + // 价格 | ||
| 801 | + Cell dataCell11 = dataRow.createCell(columnNum++); | ||
| 802 | + if (orderDetail.getPrice() != null) { | ||
| 803 | + dataCell11.setCellValue(orderDetail.getPrice().doubleValue()); | ||
| 804 | + } else { | ||
| 805 | + dataCell11.setCellValue(0.0); | ||
| 806 | + } | ||
| 807 | + dataCell11.setCellStyle(dataStyle); | ||
| 808 | + | ||
| 809 | + // 总价 | ||
| 810 | + Cell dataCell12 = dataRow.createCell(columnNum++); | ||
| 811 | + if (orderDetail.getTotalPrice() != null) { | ||
| 812 | + dataCell12.setCellValue(orderDetail.getTotalPrice().doubleValue()); | ||
| 813 | + } else { | ||
| 814 | + dataCell12.setCellValue(0.0); | ||
| 815 | + } | ||
| 816 | + dataCell12.setCellStyle(dataStyle); | ||
| 817 | + | ||
| 818 | + // 合并备注和忌口备注,用分号分割,备注在前 | ||
| 819 | + String remark = orderDetail.getRemark() != null ? orderDetail.getRemark() : ""; | ||
| 820 | + String avoidRemark = orderDetail.getAvoidRemark() != null ? orderDetail.getAvoidRemark() : ""; | ||
| 821 | + String combinedRemark = ""; | ||
| 822 | + if (!remark.isEmpty() && !avoidRemark.isEmpty()) { | ||
| 823 | + combinedRemark = remark + ";" + avoidRemark; | ||
| 824 | + } else if (!remark.isEmpty()) { | ||
| 825 | + combinedRemark = remark; | ||
| 826 | + } else if (!avoidRemark.isEmpty()) { | ||
| 827 | + combinedRemark = avoidRemark; | ||
| 828 | + } | ||
| 829 | + Cell dataCell13 = dataRow.createCell(columnNum++); | ||
| 830 | + dataCell13.setCellValue(combinedRemark); | ||
| 831 | + dataCell13.setCellStyle(dataStyle); | ||
| 832 | + | ||
| 833 | + Cell dataCell14 = dataRow.createCell(columnNum++); | ||
| 834 | + dataCell14.setCellValue(orderDetail.getOnlinePay() != null ? orderDetail.getOnlinePay() : ""); | ||
| 835 | + dataCell14.setCellStyle(dataStyle); | ||
| 836 | + } | ||
| 837 | + } | ||
| 838 | + | ||
| 839 | + // 自动调整列宽 | ||
| 840 | + for (int i = 0; i < 15; i++) { | ||
| 841 | + sheet.autoSizeColumn(i); | ||
| 842 | + } | ||
| 843 | + | ||
| 844 | + // 将工作簿内容写入字节数组输出流 | ||
| 845 | + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | ||
| 846 | + workbook.write(outputStream); | ||
| 847 | + workbook.close(); | ||
| 848 | + | ||
| 849 | + return outputStream; | ||
| 278 | } | 850 | } |
| 279 | 851 | ||
| 280 | public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) { | 852 | public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) { |
| ... | @@ -541,4 +1113,334 @@ public class SettlementServiceImpl implements SettlementService { | ... | @@ -541,4 +1113,334 @@ public class SettlementServiceImpl implements SettlementService { |
| 541 | 1113 | ||
| 542 | } | 1114 | } |
| 543 | 1115 | ||
| 1116 | + @Override | ||
| 1117 | + public ByteArrayOutputStream exportSeparateMealsExcel(QueryOrderDto queryOrderDto) { | ||
| 1118 | + // 参数校验 | ||
| 1119 | + if (queryOrderDto == null) { | ||
| 1120 | + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR); | ||
| 1121 | + } | ||
| 1122 | + | ||
| 1123 | + final int enterpriseId = queryOrderDto.getEnterpriseId(); | ||
| 1124 | + | ||
| 1125 | + // 查询订单列表 | ||
| 1126 | + final var queryClientCustomerOrdersByConditionRpcResponse = orderServiceRpcClient.queryClientCustomerOrdersByCondition(queryOrderDto); | ||
| 1127 | + final var orderList = queryClientCustomerOrdersByConditionRpcResponse.getResponsesList(); | ||
| 1128 | + if (orderList.isEmpty()) { | ||
| 1129 | + log.warn("未查询到订单数据,enterpriseId: {}", enterpriseId); | ||
| 1130 | + return null; | ||
| 1131 | + } | ||
| 1132 | + | ||
| 1133 | + // 获取订单IDs | ||
| 1134 | + List<Integer> orderIds = orderList.stream() | ||
| 1135 | + .map(SingleClientCustomerOrderRpcResponse::getId) | ||
| 1136 | + .collect(Collectors.toList()); | ||
| 1137 | + | ||
| 1138 | + // 构建订单映射 | ||
| 1139 | + final var orderMap = orderList.stream() | ||
| 1140 | + .filter(Objects::nonNull) | ||
| 1141 | + .filter(o -> o.getId() != 0) | ||
| 1142 | + .collect(Collectors.toMap(SingleClientCustomerOrderRpcResponse::getId, o -> o, (o1, o2) -> o1)); | ||
| 1143 | + | ||
| 1144 | + // 查询订单详情 | ||
| 1145 | + final var orderDetailList = orderServiceRpcClient.getOrderDetailsByOrderIds(orderIds); | ||
| 1146 | + if (orderDetailList == null || orderDetailList.isEmpty()) { | ||
| 1147 | + log.warn("未查询到订单详情数据,orderIds: {}", orderIds); | ||
| 1148 | + return null; | ||
| 1149 | + } | ||
| 1150 | + | ||
| 1151 | + // 订单详情按订单ID分组 | ||
| 1152 | + final var orderDetailGroupByOrderId = orderDetailList.stream() | ||
| 1153 | + .filter(Objects::nonNull) | ||
| 1154 | + .filter(d -> !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT)) | ||
| 1155 | + .collect(Collectors.groupingBy(SingleClientCustomerOrderDetailRpcResponse::getOrderId)); | ||
| 1156 | + | ||
| 1157 | + // 获取SKU数据 | ||
| 1158 | + List<Integer> skuIds = orderDetailList.stream() | ||
| 1159 | + .filter(Objects::nonNull) | ||
| 1160 | + .filter(d -> !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT)) | ||
| 1161 | + .map(SingleClientCustomerOrderDetailRpcResponse::getSkuId) | ||
| 1162 | + .distinct() | ||
| 1163 | + .collect(Collectors.toList()); | ||
| 1164 | + | ||
| 1165 | + final var skuResponse = skuServiceRpcClient.getDishSkusByIds(skuIds); | ||
| 1166 | + final List<SingleDishSkuByIdsRpcResponse> skus = skuResponse != null ? skuResponse.getResponseList() : new ArrayList<>(); | ||
| 1167 | + final var skuMap = skus.stream() | ||
| 1168 | + .collect(Collectors.toMap(SingleDishSkuByIdsRpcResponse::getId, s -> s, (s1, s2) -> s1)); | ||
| 1169 | + | ||
| 1170 | + // 获取餐别数据 | ||
| 1171 | + final var mealResponse = mealServiceRpcClient.getAllMeals(enterpriseId); | ||
| 1172 | + final List<SingleMealRpcResponse> meals = mealResponse != null ? mealResponse.getResponsesList() : new ArrayList<>(); | ||
| 1173 | + final var mealMap = meals.stream() | ||
| 1174 | + .filter(Objects::nonNull) | ||
| 1175 | + .filter(m -> m.getId() != 0) | ||
| 1176 | + .collect(Collectors.toMap(SingleMealRpcResponse::getId, m -> m, (m1, m2) -> m1)); | ||
| 1177 | + | ||
| 1178 | + // 获取菜单数据 | ||
| 1179 | + List<Integer> menuIds = orderList.stream() | ||
| 1180 | + .map(SingleClientCustomerOrderRpcResponse::getMenuId) | ||
| 1181 | + .distinct() | ||
| 1182 | + .collect(Collectors.toList()); | ||
| 1183 | + | ||
| 1184 | + final var menuResponse = menuServiceRpcClient.getMenusByIds(enterpriseId, menuIds); | ||
| 1185 | + final List<SingleMenuRpcResponse> menuList = menuResponse != null ? menuResponse.getResponsesList() : new ArrayList<>(); | ||
| 1186 | + final var menuMap = menuList.stream() | ||
| 1187 | + .collect(Collectors.toMap(SingleMenuRpcResponse::getId, m -> m, (m1, m2) -> m1)); | ||
| 1188 | + | ||
| 1189 | + // 获取菜单详情数据 | ||
| 1190 | + final var menuDetailResponse = menuServiceRpcClient.queryMenuDetailsByMenuIds(enterpriseId, menuIds); | ||
| 1191 | + final List<SingleMenuDetailRpcResponse> menuDetailList = menuDetailResponse != null ? menuDetailResponse.getResponsesList() : new ArrayList<>(); | ||
| 1192 | + final var menuDetailMap = menuDetailList.stream() | ||
| 1193 | + .collect(Collectors.toMap(SingleMenuDetailRpcResponse::getId, m -> m, (m1, m2) -> m1)); | ||
| 1194 | + | ||
| 1195 | + // 获取客户数据 | ||
| 1196 | + List<Integer> customerIds = orderList.stream() | ||
| 1197 | + .map(SingleClientCustomerOrderRpcResponse::getCustomerId) | ||
| 1198 | + .filter(id -> id != 0) | ||
| 1199 | + .distinct() | ||
| 1200 | + .collect(Collectors.toList()); | ||
| 1201 | + | ||
| 1202 | + final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds); | ||
| 1203 | + final List<SingleClientCustomerRpcResponse> customers = customerResponse != null ? customerResponse.getResponsesList() : new ArrayList<>(); | ||
| 1204 | + final var customerMap = customers.stream() | ||
| 1205 | + .collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1)); | ||
| 1206 | + | ||
| 1207 | + // 构建分餐表明细 | ||
| 1208 | + final var mealDetails = new ArrayList<SeparateMealDetail>(); | ||
| 1209 | + for (Integer orderId : orderIds) { | ||
| 1210 | + final var orderDetails = orderDetailGroupByOrderId.getOrDefault(orderId, Collections.emptyList()); | ||
| 1211 | + final var order = orderMap.get(orderId); | ||
| 1212 | + | ||
| 1213 | + // 订单为空则跳过 | ||
| 1214 | + if (order == null) { | ||
| 1215 | + log.warn("订单不存在,orderId: {}", orderId); | ||
| 1216 | + continue; | ||
| 1217 | + } | ||
| 1218 | + | ||
| 1219 | + // 获取菜单信息 | ||
| 1220 | + final var menu = menuMap.get(order.getMenuId()); | ||
| 1221 | + final String menuName = menu != null ? menu.getName() : ""; | ||
| 1222 | + | ||
| 1223 | + // 获取客户信息 | ||
| 1224 | + final var customer = customerMap.get(order.getCustomerId()); | ||
| 1225 | + final String customerName = customer != null ? customer.getName() : ""; | ||
| 1226 | + | ||
| 1227 | + // 安全获取房间号 | ||
| 1228 | + String roomNo = getRoomNoSafely(order); | ||
| 1229 | + | ||
| 1230 | + // 处理每个订单详情 | ||
| 1231 | + for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) { | ||
| 1232 | + if (orderDetail == null) { | ||
| 1233 | + continue; | ||
| 1234 | + } | ||
| 1235 | + | ||
| 1236 | + // 安全获取餐别名称 | ||
| 1237 | + String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap); | ||
| 1238 | + | ||
| 1239 | + // 安全获取SKU名称 | ||
| 1240 | + String skuName = getSkuNameSafely(orderDetail, skuMap); | ||
| 1241 | + | ||
| 1242 | + // 安全获取忌口信息(列表转字符串) | ||
| 1243 | + List<String> avoidsList = getAvoidsSafely(order); | ||
| 1244 | + String avoidsStr = String.join(", ", avoidsList); | ||
| 1245 | + | ||
| 1246 | + String remark = order.getRemark(); | ||
| 1247 | + String avoidRemark = order.getAvoidRemark(); | ||
| 1248 | + String combinedRemark = ""; | ||
| 1249 | + if (!remark.isEmpty() && !avoidRemark.isEmpty()) { | ||
| 1250 | + combinedRemark = remark + ";" + avoidRemark; | ||
| 1251 | + } else if (!remark.isEmpty()) { | ||
| 1252 | + combinedRemark = remark; | ||
| 1253 | + } else if (!avoidRemark.isEmpty()) { | ||
| 1254 | + combinedRemark = avoidRemark; | ||
| 1255 | + } | ||
| 1256 | + | ||
| 1257 | + // 构建分餐表明细 | ||
| 1258 | + SeparateMealDetail mealDetail = SeparateMealDetail.builder() | ||
| 1259 | + .orderId(orderId) | ||
| 1260 | + .mealName(mealName) | ||
| 1261 | + .roomNo(roomNo) | ||
| 1262 | + .customerName(customerName) | ||
| 1263 | + .menuName(menuName) | ||
| 1264 | + .skuName(skuName) | ||
| 1265 | + .count(orderDetail.getCount() != 0 ? orderDetail.getCount() : 0) | ||
| 1266 | + .avoids(avoidsStr) | ||
| 1267 | + .remark(combinedRemark) | ||
| 1268 | + .build(); | ||
| 1269 | + mealDetails.add(mealDetail); | ||
| 1270 | + } | ||
| 1271 | + } | ||
| 1272 | + | ||
| 1273 | + // 构建分餐表数据 | ||
| 1274 | + final var separateMealDataDto = SeparateMealDataDto.builder() | ||
| 1275 | + .mealDetails(mealDetails) | ||
| 1276 | + .build(); | ||
| 1277 | + | ||
| 1278 | + // 生成Excel | ||
| 1279 | + try { | ||
| 1280 | + return writeToExcelBySeparateMeal(separateMealDataDto); | ||
| 1281 | + } catch (IOException e) { | ||
| 1282 | + log.error("生成分餐表Excel失败", e); | ||
| 1283 | + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR); | ||
| 1284 | + } | ||
| 1285 | + } | ||
| 1286 | + | ||
| 1287 | + /** | ||
| 1288 | + * 生成分餐表Excel | ||
| 1289 | + */ | ||
| 1290 | + private static ByteArrayOutputStream writeToExcelBySeparateMeal(SeparateMealDataDto separateMealDataDto) | ||
| 1291 | + throws IOException { | ||
| 1292 | + Workbook workbook = new XSSFWorkbook(); | ||
| 1293 | + Sheet sheet = workbook.createSheet("分餐表"); | ||
| 1294 | + | ||
| 1295 | + // 创建标题样式(合并单元格标题) | ||
| 1296 | + CellStyle titleStyle = workbook.createCellStyle(); | ||
| 1297 | + titleStyle.setAlignment(HorizontalAlignment.CENTER); | ||
| 1298 | + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); | ||
| 1299 | + titleStyle.setBorderTop(BorderStyle.THIN); | ||
| 1300 | + titleStyle.setBorderBottom(BorderStyle.THIN); | ||
| 1301 | + titleStyle.setBorderLeft(BorderStyle.THIN); | ||
| 1302 | + titleStyle.setBorderRight(BorderStyle.THIN); | ||
| 1303 | + titleStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 1304 | + titleStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 1305 | + titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 1306 | + titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 1307 | + Font titleFont = workbook.createFont(); | ||
| 1308 | + titleFont.setBold(true); | ||
| 1309 | + titleFont.setFontHeightInPoints((short) 16); | ||
| 1310 | + titleStyle.setFont(titleFont); | ||
| 1311 | + | ||
| 1312 | + // 创建表头样式(黑色边框) | ||
| 1313 | + CellStyle headerStyle = workbook.createCellStyle(); | ||
| 1314 | + headerStyle.setBorderTop(BorderStyle.THIN); | ||
| 1315 | + headerStyle.setBorderBottom(BorderStyle.THIN); | ||
| 1316 | + headerStyle.setBorderLeft(BorderStyle.THIN); | ||
| 1317 | + headerStyle.setBorderRight(BorderStyle.THIN); | ||
| 1318 | + headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 1319 | + headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 1320 | + headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 1321 | + headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex()); | ||
| 1322 | + | ||
| 1323 | + // 创建数据行样式(浅灰色边框) | ||
| 1324 | + CellStyle dataStyle = workbook.createCellStyle(); | ||
| 1325 | + dataStyle.setBorderTop(BorderStyle.THIN); | ||
| 1326 | + dataStyle.setBorderBottom(BorderStyle.THIN); | ||
| 1327 | + dataStyle.setBorderLeft(BorderStyle.THIN); | ||
| 1328 | + dataStyle.setBorderRight(BorderStyle.THIN); | ||
| 1329 | + dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 1330 | + dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 1331 | + dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 1332 | + dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); | ||
| 1333 | + | ||
| 1334 | + int rowNum = 0; | ||
| 1335 | + | ||
| 1336 | + // 第一行:创建合并单元格标题 | ||
| 1337 | + Row mainTitleRow = sheet.createRow(rowNum++); | ||
| 1338 | + Cell mainTitleCell = mainTitleRow.createCell(0); | ||
| 1339 | + mainTitleCell.setCellValue("住院客户分餐表"); | ||
| 1340 | + mainTitleCell.setCellStyle(titleStyle); | ||
| 1341 | + | ||
| 1342 | + // 合并第一行的8列 | ||
| 1343 | + CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 7); | ||
| 1344 | + sheet.addMergedRegion(titleRegion); | ||
| 1345 | + | ||
| 1346 | + // 为合并区域设置边框 | ||
| 1347 | + RegionUtil.setBorderTop(BorderStyle.THIN, titleRegion, sheet); | ||
| 1348 | + RegionUtil.setBorderBottom(BorderStyle.THIN, titleRegion, sheet); | ||
| 1349 | + RegionUtil.setBorderLeft(BorderStyle.THIN, titleRegion, sheet); | ||
| 1350 | + RegionUtil.setBorderRight(BorderStyle.THIN, titleRegion, sheet); | ||
| 1351 | + RegionUtil.setTopBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet); | ||
| 1352 | + RegionUtil.setBottomBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet); | ||
| 1353 | + RegionUtil.setLeftBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet); | ||
| 1354 | + RegionUtil.setRightBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet); | ||
| 1355 | + | ||
| 1356 | + // 第二行:创建表头 | ||
| 1357 | + Row titleRow = sheet.createRow(rowNum++); | ||
| 1358 | + int columnNum = 0; | ||
| 1359 | + | ||
| 1360 | + Cell cell0 = titleRow.createCell(columnNum++); | ||
| 1361 | + cell0.setCellValue("餐别"); | ||
| 1362 | + cell0.setCellStyle(headerStyle); | ||
| 1363 | + | ||
| 1364 | + Cell cell1 = titleRow.createCell(columnNum++); | ||
| 1365 | + cell1.setCellValue("房间号"); | ||
| 1366 | + cell1.setCellStyle(headerStyle); | ||
| 1367 | + | ||
| 1368 | + Cell cell2 = titleRow.createCell(columnNum++); | ||
| 1369 | + cell2.setCellValue("客户姓名"); | ||
| 1370 | + cell2.setCellStyle(headerStyle); | ||
| 1371 | + | ||
| 1372 | + Cell cell3 = titleRow.createCell(columnNum++); | ||
| 1373 | + cell3.setCellValue("餐单名称"); | ||
| 1374 | + cell3.setCellStyle(headerStyle); | ||
| 1375 | + | ||
| 1376 | + Cell cell4 = titleRow.createCell(columnNum++); | ||
| 1377 | + cell4.setCellValue("菜品名称"); | ||
| 1378 | + cell4.setCellStyle(headerStyle); | ||
| 1379 | + | ||
| 1380 | + Cell cell5 = titleRow.createCell(columnNum++); | ||
| 1381 | + cell5.setCellValue("菜品数量"); | ||
| 1382 | + cell5.setCellStyle(headerStyle); | ||
| 1383 | + | ||
| 1384 | + Cell cell6 = titleRow.createCell(columnNum++); | ||
| 1385 | + cell6.setCellValue("忌口信息"); | ||
| 1386 | + cell6.setCellStyle(headerStyle); | ||
| 1387 | + | ||
| 1388 | + Cell cell7 = titleRow.createCell(columnNum++); | ||
| 1389 | + cell7.setCellValue("备注"); | ||
| 1390 | + cell7.setCellStyle(headerStyle); | ||
| 1391 | + | ||
| 1392 | + // 填充数据 | ||
| 1393 | + final var mealDetails = separateMealDataDto.getMealDetails(); | ||
| 1394 | + if (mealDetails != null) { | ||
| 1395 | + for (SeparateMealDetail mealDetail : mealDetails) { | ||
| 1396 | + Row dataRow = sheet.createRow(rowNum++); | ||
| 1397 | + columnNum = 0; | ||
| 1398 | + | ||
| 1399 | + Cell dataCell0 = dataRow.createCell(columnNum++); | ||
| 1400 | + dataCell0.setCellValue(mealDetail.getMealName() != null ? mealDetail.getMealName() : ""); | ||
| 1401 | + dataCell0.setCellStyle(dataStyle); | ||
| 1402 | + | ||
| 1403 | + Cell dataCell1 = dataRow.createCell(columnNum++); | ||
| 1404 | + dataCell1.setCellValue(mealDetail.getRoomNo() != null ? mealDetail.getRoomNo() : ""); | ||
| 1405 | + dataCell1.setCellStyle(dataStyle); | ||
| 1406 | + | ||
| 1407 | + Cell dataCell2 = dataRow.createCell(columnNum++); | ||
| 1408 | + dataCell2.setCellValue(mealDetail.getCustomerName() != null ? mealDetail.getCustomerName() : ""); | ||
| 1409 | + dataCell2.setCellStyle(dataStyle); | ||
| 1410 | + | ||
| 1411 | + Cell dataCell3 = dataRow.createCell(columnNum++); | ||
| 1412 | + dataCell3.setCellValue(mealDetail.getMenuName() != null ? mealDetail.getMenuName() : ""); | ||
| 1413 | + dataCell3.setCellStyle(dataStyle); | ||
| 1414 | + | ||
| 1415 | + Cell dataCell4 = dataRow.createCell(columnNum++); | ||
| 1416 | + dataCell4.setCellValue(mealDetail.getSkuName() != null ? mealDetail.getSkuName() : ""); | ||
| 1417 | + dataCell4.setCellStyle(dataStyle); | ||
| 1418 | + | ||
| 1419 | + Cell dataCell5 = dataRow.createCell(columnNum++); | ||
| 1420 | + dataCell5.setCellValue(mealDetail.getCount() != null ? mealDetail.getCount() : 0); | ||
| 1421 | + dataCell5.setCellStyle(dataStyle); | ||
| 1422 | + | ||
| 1423 | + Cell dataCell6 = dataRow.createCell(columnNum++); | ||
| 1424 | + dataCell6.setCellValue(mealDetail.getAvoids() != null ? mealDetail.getAvoids() : ""); | ||
| 1425 | + dataCell6.setCellStyle(dataStyle); | ||
| 1426 | + | ||
| 1427 | + Cell dataCell7 = dataRow.createCell(columnNum++); | ||
| 1428 | + dataCell7.setCellValue(mealDetail.getRemark() != null ? mealDetail.getRemark() : ""); | ||
| 1429 | + dataCell7.setCellStyle(dataStyle); | ||
| 1430 | + } | ||
| 1431 | + } | ||
| 1432 | + | ||
| 1433 | + // 自动调整列宽 | ||
| 1434 | + for (int i = 0; i < 8; i++) { | ||
| 1435 | + sheet.autoSizeColumn(i); | ||
| 1436 | + } | ||
| 1437 | + | ||
| 1438 | + // 将工作簿内容写入字节数组输出流 | ||
| 1439 | + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); | ||
| 1440 | + workbook.write(outputStream); | ||
| 1441 | + workbook.close(); | ||
| 1442 | + | ||
| 1443 | + return outputStream; | ||
| 1444 | + } | ||
| 1445 | + | ||
| 544 | } | 1446 | } | ... | ... |
| ... | @@ -2,6 +2,8 @@ package com.infoloop.tianting.streamController; | ... | @@ -2,6 +2,8 @@ package com.infoloop.tianting.streamController; |
| 2 | 2 | ||
| 3 | import cn.dev33.satoken.annotation.SaIgnore; | 3 | import cn.dev33.satoken.annotation.SaIgnore; |
| 4 | import com.github.xiaoymin.knife4j.annotations.ApiSupport; | 4 | import com.github.xiaoymin.knife4j.annotations.ApiSupport; |
| 5 | +import com.infoloop.tianting.enums.SettlementDimensionEnum; | ||
| 6 | +import com.infoloop.tianting.model.dto.OrderDbDTO; | ||
| 5 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto; | 7 | import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto; |
| 6 | import com.infoloop.tianting.service.SettlementService; | 8 | import com.infoloop.tianting.service.SettlementService; |
| 7 | import io.swagger.annotations.Api; | 9 | import io.swagger.annotations.Api; |
| ... | @@ -21,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController; | ... | @@ -21,6 +23,7 @@ import org.springframework.web.bind.annotation.RestController; |
| 21 | 23 | ||
| 22 | import javax.validation.Valid; | 24 | import javax.validation.Valid; |
| 23 | import java.io.ByteArrayOutputStream; | 25 | import java.io.ByteArrayOutputStream; |
| 26 | +import java.time.format.DateTimeFormatter; | ||
| 24 | 27 | ||
| 25 | @Api(tags = "结算") | 28 | @Api(tags = "结算") |
| 26 | @ApiSupport(order = 0) | 29 | @ApiSupport(order = 0) |
| ... | @@ -29,35 +32,59 @@ import java.io.ByteArrayOutputStream; | ... | @@ -29,35 +32,59 @@ import java.io.ByteArrayOutputStream; |
| 29 | @RestController | 32 | @RestController |
| 30 | @RequiredArgsConstructor(onConstructor = @__(@Autowired)) | 33 | @RequiredArgsConstructor(onConstructor = @__(@Autowired)) |
| 31 | public class SettlementController { | 34 | public class SettlementController { |
| 32 | - private final SettlementService settlementService; | 35 | + private final SettlementService settlementService; |
| 33 | - | 36 | + |
| 34 | - @SaIgnore | 37 | + @SaIgnore |
| 35 | - @ApiOperation(value = "企业端结算账单生成excel") | 38 | + @ApiOperation(value = "企业端结算账单生成excel") |
| 36 | - @PostMapping("/enterprise/settlement/generate-excel") | 39 | + @PostMapping("/enterprise/settlement/generate-excel") |
| 37 | - @ResponseStatus(HttpStatus.OK) | 40 | + @ResponseStatus(HttpStatus.OK) |
| 38 | - public ResponseEntity<byte[]> enterpriseSettlementGenerateExcel(@Valid @RequestBody SettlementRequestDto settlementRequestDto) { | 41 | + public ResponseEntity<byte[]> enterpriseSettlementGenerateExcel(@Valid @RequestBody SettlementRequestDto settlementRequestDto) { |
| 39 | - ByteArrayOutputStream outputStream = settlementService.generateOrderSettlementExcel(settlementRequestDto); | 42 | + ByteArrayOutputStream outputStream = settlementService.generateOrderSettlementExcel(settlementRequestDto); |
| 40 | - HttpHeaders headers = new HttpHeaders(); | 43 | + HttpHeaders headers = new HttpHeaders(); |
| 41 | - headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); | 44 | + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); |
| 42 | - headers.setContentDispositionFormData("attachment", "订单数据.xlsx"); | 45 | + headers.setContentDispositionFormData("attachment", "订单数据.xlsx"); |
| 43 | - return ResponseEntity.ok() | 46 | + return ResponseEntity.ok() |
| 44 | - .headers(headers) | 47 | + .headers(headers) |
| 45 | - .body(outputStream.toByteArray()); | 48 | + .body(outputStream.toByteArray()); |
| 46 | - } | 49 | + } |
| 47 | 50 | ||
| 48 | @ApiOperation(value = "结算账单生成excel") | 51 | @ApiOperation(value = "结算账单生成excel") |
| 49 | @PostMapping("/settlement/generate-excel") | 52 | @PostMapping("/settlement/generate-excel") |
| 50 | @ResponseStatus(HttpStatus.OK) | 53 | @ResponseStatus(HttpStatus.OK) |
| 51 | - public ResponseEntity<byte[]> settlementGenerateExcel( | 54 | + public ResponseEntity<byte[]> settlementGenerateExcel(@Valid @RequestBody SettlementRequestDto settlementRequestDto) { |
| 52 | - @Valid @RequestBody SettlementRequestDto settlementRequestDto) { | 55 | + ByteArrayOutputStream outputStream = settlementService.generateOrderSettlementExcel( |
| 53 | - ByteArrayOutputStream outputStream = settlementService.generateOrderSettlementExcel( | 56 | + settlementRequestDto); |
| 54 | - settlementRequestDto); | 57 | + |
| 55 | - HttpHeaders headers = new HttpHeaders(); | 58 | + String fileName; |
| 56 | - headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); | 59 | + if (settlementRequestDto.getDimension() == SettlementDimensionEnum.BY_ORDER) { |
| 57 | - headers.setContentDispositionFormData("attachment", "订单数据.xlsx"); | 60 | + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); |
| 58 | - | 61 | + String startDate = settlementRequestDto.getTimeStart().format(formatter); |
| 59 | - return ResponseEntity.ok() | 62 | + String endDate = settlementRequestDto.getTimeEnd().format(formatter); |
| 60 | - .headers(headers) | 63 | + fileName = String.format("结算报表_%s_%s.xlsx", startDate, endDate); |
| 61 | - .body(outputStream.toByteArray()); | 64 | + } else { |
| 65 | + fileName = "订单数据.xlsx"; | ||
| 66 | + } | ||
| 67 | + | ||
| 68 | + HttpHeaders headers = new HttpHeaders(); | ||
| 69 | + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); | ||
| 70 | + headers.setContentDispositionFormData("attachment", fileName); | ||
| 71 | + | ||
| 72 | + return ResponseEntity.ok() | ||
| 73 | + .headers(headers) | ||
| 74 | + .body(outputStream.toByteArray()); | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + @ApiOperation(value = "院区端订单导出") | ||
| 78 | + @PostMapping("/separateMeals/export") | ||
| 79 | + @ResponseStatus(HttpStatus.OK) | ||
| 80 | + public ResponseEntity<byte[]> exportSeparateMeals(@Valid @RequestBody OrderDbDTO.QueryOrderDto queryOrderDto) { | ||
| 81 | + ByteArrayOutputStream outputStream = settlementService.exportSeparateMealsExcel(queryOrderDto); | ||
| 82 | + HttpHeaders headers = new HttpHeaders(); | ||
| 83 | + headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); | ||
| 84 | + headers.setContentDispositionFormData("attachment", "分餐表.xlsx"); | ||
| 85 | + return ResponseEntity.ok() | ||
| 86 | + .headers(headers) | ||
| 87 | + .body(outputStream.toByteArray()); | ||
| 62 | } | 88 | } |
| 89 | + | ||
| 63 | } | 90 | } | ... | ... |
| ... | @@ -89,6 +89,11 @@ enum OnlinePayEnum { | ... | @@ -89,6 +89,11 @@ enum OnlinePayEnum { |
| 89 | LEAVE_HOSPITAL = 3;//出院 | 89 | LEAVE_HOSPITAL = 3;//出院 |
| 90 | EMPLOYEE_CARD = 4; //员工卡 | 90 | EMPLOYEE_CARD = 4; //员工卡 |
| 91 | PAPER_VERIFICATION = 5; //纸质核销 | 91 | PAPER_VERIFICATION = 5; //纸质核销 |
| 92 | + CASH = 6;//现金 | ||
| 93 | + MEAL_CARD = 7;//餐卡 | ||
| 94 | + BAND_CARD = 8;//银行卡 | ||
| 95 | + ALIPAY = 9;//支付宝 | ||
| 96 | + WECHATPAY = 10;//微信支付 | ||
| 92 | } | 97 | } |
| 93 | 98 | ||
| 94 | enum ServeStatusEnum { | 99 | enum ServeStatusEnum { |
| ... | @@ -141,6 +146,7 @@ message SingleClientCustomerOrderRpcResponse { | ... | @@ -141,6 +146,7 @@ message SingleClientCustomerOrderRpcResponse { |
| 141 | bool isAllocation = 35; | 146 | bool isAllocation = 35; |
| 142 | string syncRoomNo = 36; | 147 | string syncRoomNo = 36; |
| 143 | bool isCanceled = 37; | 148 | bool isCanceled = 37; |
| 149 | + string avoidRemark = 38; | ||
| 144 | } | 150 | } |
| 145 | 151 | ||
| 146 | message GetClientCustomerOrderByIdRpcRequest { | 152 | message GetClientCustomerOrderByIdRpcRequest { |
| ... | @@ -385,6 +391,8 @@ message ClientCustomerOrderModification { | ... | @@ -385,6 +391,8 @@ message ClientCustomerOrderModification { |
| 385 | string syncRoomNo = 55; | 391 | string syncRoomNo = 55; |
| 386 | bool shouldUpdateIsCanceled = 56; | 392 | bool shouldUpdateIsCanceled = 56; |
| 387 | bool isCanceled = 57; | 393 | bool isCanceled = 57; |
| 394 | + bool shouldUpdateAvoidRemark = 58; | ||
| 395 | + string avoidRemark = 59; | ||
| 388 | } | 396 | } |
| 389 | 397 | ||
| 390 | message UpdateClientCustomerOrderRpcRequest { | 398 | message UpdateClientCustomerOrderRpcRequest { | ... | ... |
-
Please register or login to post a comment