zhuyifan

feat(order): add bulk operation records query and excel generation

1 +package com.infoloop.tianting.model.bo;
2 +
3 +import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum;
4 +import lombok.Data;
5 +
6 +@Data
7 +public class OrderDetailBO {
8 +
9 + private int id;
10 +
11 + public int skuId;
12 +
13 + private String skuName;
14 +
15 + private Integer price;
16 +
17 + private int count;
18 +
19 + private String adjustSkuRemark;
20 +
21 + private ServeStatusEnum serveStatus;
22 +}
...@@ -520,6 +520,7 @@ public class OrderDbDTO { ...@@ -520,6 +520,7 @@ public class OrderDbDTO {
520 private Integer count; 520 private Integer count;
521 private String adjustSkuRemark; 521 private String adjustSkuRemark;
522 private String serveStatus; 522 private String serveStatus;
523 + private Integer price;
523 } 524 }
524 525
525 526
......
...@@ -103,6 +103,8 @@ public class SettlementDTO { ...@@ -103,6 +103,8 @@ public class SettlementDTO {
103 private String remark; 103 private String remark;
104 private String avoidRemark; 104 private String avoidRemark;
105 private String onlinePay; 105 private String onlinePay;
106 + private String operationType;
107 + private String transactionId;
106 } 108 }
107 109
108 @Data 110 @Data
......
...@@ -22,6 +22,8 @@ import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderBy ...@@ -22,6 +22,8 @@ import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderBy
22 import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByIdsRpcRequest; 22 import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByIdsRpcRequest;
23 import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByOrderIdsRpcRequest; 23 import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByOrderIdsRpcRequest;
24 import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrdersByCustomerIdRpcRequest; 24 import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrdersByCustomerIdRpcRequest;
25 +import com.infoloop.tianting.clientcustomerorderservice.GetOrderOperationRecordsByOrderIdsRequest;
26 +import com.infoloop.tianting.clientcustomerorderservice.GetOrderOperationRecordsByOrderIdsResponse;
25 import com.infoloop.tianting.clientcustomerorderservice.MealDetail; 27 import com.infoloop.tianting.clientcustomerorderservice.MealDetail;
26 import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum; 28 import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum;
27 import com.infoloop.tianting.clientcustomerorderservice.OrderOperationRecordCreation; 29 import com.infoloop.tianting.clientcustomerorderservice.OrderOperationRecordCreation;
...@@ -396,7 +398,7 @@ public class OrderServiceRpcClient { ...@@ -396,7 +398,7 @@ public class OrderServiceRpcClient {
396 .updateSource(d.getUpdateSource().getNumber()) 398 .updateSource(d.getUpdateSource().getNumber())
397 .updatedAt(DateUtil.formatDate(d.getUpdatedAt())) 399 .updatedAt(DateUtil.formatDate(d.getUpdatedAt()))
398 .updatedBy(d.getUpdatedBy()) 400 .updatedBy(d.getUpdatedBy())
399 - .build()).collect(Collectors.toList()); 401 + .build()).toList();
400 // 替换菜品的操作记录 402 // 替换菜品的操作记录
401 List<SingleOperationDto> operations = new ArrayList<>(); 403 List<SingleOperationDto> operations = new ArrayList<>();
402 for (OrderDetailDto originalDetail : originalOrderDetails) { 404 for (OrderDetailDto originalDetail : originalOrderDetails) {
...@@ -422,6 +424,7 @@ public class OrderServiceRpcClient { ...@@ -422,6 +424,7 @@ public class OrderServiceRpcClient {
422 .count(newDetail.get().getCount()) 424 .count(newDetail.get().getCount())
423 .adjustSkuRemark(newDetail.get().getAdjustSkuRemark()) 425 .adjustSkuRemark(newDetail.get().getAdjustSkuRemark())
424 .serveStatus(newDetail.get().getServeStatus().name()) 426 .serveStatus(newDetail.get().getServeStatus().name())
427 + .price(newDetail.get().getPrice())
425 .build(); 428 .build();
426 newDetailStr = JsonUtil.writeAsJson(List.of(newOrderDetailOperation)); 429 newDetailStr = JsonUtil.writeAsJson(List.of(newOrderDetailOperation));
427 } 430 }
...@@ -432,6 +435,7 @@ public class OrderServiceRpcClient { ...@@ -432,6 +435,7 @@ public class OrderServiceRpcClient {
432 .count(originalDetail.getCount()) 435 .count(originalDetail.getCount())
433 .adjustSkuRemark(originalDetail.getAdjustSkuRemark()) 436 .adjustSkuRemark(originalDetail.getAdjustSkuRemark())
434 .serveStatus(originalDetail.getServeStatus().name()) 437 .serveStatus(originalDetail.getServeStatus().name())
438 + .price(originalDetail.getPrice())
435 .build(); 439 .build();
436 originalDetailStr = JsonUtil.writeAsJson(List.of(originalOrderDetailOperation)); 440 originalDetailStr = JsonUtil.writeAsJson(List.of(originalOrderDetailOperation));
437 final var operation = SingleOperationDto.builder() 441 final var operation = SingleOperationDto.builder()
...@@ -480,7 +484,6 @@ public class OrderServiceRpcClient { ...@@ -480,7 +484,6 @@ public class OrderServiceRpcClient {
480 .setCreationSource(batchOperationDto.getCreationSource()) 484 .setCreationSource(batchOperationDto.getCreationSource())
481 .build(); 485 .build();
482 return orderServiceRpcBlockingStub.batchCreateOrderOperationRecords(request); 486 return orderServiceRpcBlockingStub.batchCreateOrderOperationRecords(request);
483 -
484 } 487 }
485 488
486 public QueryClientCustomerOrdersByPaginationRpcResponse queryClientCustomerOrdersByPagination(QueryOrderByPaginationDto queryOrderDto) { 489 public QueryClientCustomerOrdersByPaginationRpcResponse queryClientCustomerOrdersByPagination(QueryOrderByPaginationDto queryOrderDto) {
...@@ -498,6 +501,14 @@ public class OrderServiceRpcClient { ...@@ -498,6 +501,14 @@ public class OrderServiceRpcClient {
498 return orderServiceRpcBlockingStub.queryClientCustomerOrdersByPagination(request); 501 return orderServiceRpcBlockingStub.queryClientCustomerOrdersByPagination(request);
499 } 502 }
500 503
504 + public GetOrderOperationRecordsByOrderIdsResponse getOrderOperationRecordsByOrderIds(int enterpriseId, List<Integer> orderIds) {
505 + final var request = GetOrderOperationRecordsByOrderIdsRequest.newBuilder()
506 + .setEnterpriseId(enterpriseId)
507 + .addAllOrderIds(orderIds)
508 + .build();
509 + return orderServiceRpcBlockingStub.getOrderOperationRecordsByOrderIds(request);
510 + }
511 +
501 public QueryClientCustomerOrdersByConditionRpcResponse queryClientCustomerOrdersByCondition(OrderDbDTO.QueryOrderDto queryOrderDto) { 512 public QueryClientCustomerOrdersByConditionRpcResponse queryClientCustomerOrdersByCondition(OrderDbDTO.QueryOrderDto queryOrderDto) {
502 final var request = QueryClientCustomerOrdersByConditionRpcRequest.newBuilder() 513 final var request = QueryClientCustomerOrdersByConditionRpcRequest.newBuilder()
503 .setShouldFilterStatus(true) 514 .setShouldFilterStatus(true)
......
...@@ -2,8 +2,11 @@ package com.infoloop.tianting.service.impl; ...@@ -2,8 +2,11 @@ package com.infoloop.tianting.service.impl;
2 2
3 import cn.hutool.core.collection.CollectionUtil; 3 import cn.hutool.core.collection.CollectionUtil;
4 import cn.hutool.core.date.LocalDateTimeUtil; 4 import cn.hutool.core.date.LocalDateTimeUtil;
5 +import com.fasterxml.jackson.core.type.TypeReference;
5 import com.infoloop.tianting.SingleDishSkuByIdsRpcResponse; 6 import com.infoloop.tianting.SingleDishSkuByIdsRpcResponse;
6 import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum; 7 import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum;
8 +import com.infoloop.tianting.clientcustomerorderservice.OrderOperationRecord;
9 +import com.infoloop.tianting.clientcustomerorderservice.OrderOperationType;
7 import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; 10 import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum;
8 import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum; 11 import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum;
9 import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum; 12 import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum;
...@@ -17,6 +20,7 @@ import com.infoloop.tianting.exception.ClientEndExceptions.BusinessException; ...@@ -17,6 +20,7 @@ import com.infoloop.tianting.exception.ClientEndExceptions.BusinessException;
17 import com.infoloop.tianting.exception.ErrorCodeEnum; 20 import com.infoloop.tianting.exception.ErrorCodeEnum;
18 import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse; 21 import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse;
19 import com.infoloop.tianting.menuservice.SingleMenuRpcResponse; 22 import com.infoloop.tianting.menuservice.SingleMenuRpcResponse;
23 +import com.infoloop.tianting.model.bo.OrderDetailBO;
20 import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto; 24 import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto;
21 import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderDto; 25 import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderDto;
22 import com.infoloop.tianting.model.dto.SettlementDTO; 26 import com.infoloop.tianting.model.dto.SettlementDTO;
...@@ -39,8 +43,10 @@ import com.infoloop.tianting.service.client.OrderServiceRpcClient; ...@@ -39,8 +43,10 @@ import com.infoloop.tianting.service.client.OrderServiceRpcClient;
39 import com.infoloop.tianting.service.client.SkuServiceRpcClient; 43 import com.infoloop.tianting.service.client.SkuServiceRpcClient;
40 import com.infoloop.tianting.setmealscheduleservice.SingleMealRpcResponse; 44 import com.infoloop.tianting.setmealscheduleservice.SingleMealRpcResponse;
41 import com.infoloop.tianting.utils.DateUtil; 45 import com.infoloop.tianting.utils.DateUtil;
46 +import com.infoloop.tianting.utils.JsonUtil;
42 import lombok.RequiredArgsConstructor; 47 import lombok.RequiredArgsConstructor;
43 import lombok.extern.slf4j.Slf4j; 48 import lombok.extern.slf4j.Slf4j;
49 +import org.apache.commons.lang3.StringUtils;
44 import org.apache.poi.ss.usermodel.BorderStyle; 50 import org.apache.poi.ss.usermodel.BorderStyle;
45 import org.apache.poi.ss.usermodel.Cell; 51 import org.apache.poi.ss.usermodel.Cell;
46 import org.apache.poi.ss.usermodel.CellStyle; 52 import org.apache.poi.ss.usermodel.CellStyle;
...@@ -71,7 +77,9 @@ import java.util.HashMap; ...@@ -71,7 +77,9 @@ import java.util.HashMap;
71 import java.util.List; 77 import java.util.List;
72 import java.util.Map; 78 import java.util.Map;
73 import java.util.Objects; 79 import java.util.Objects;
80 +import java.util.function.Function;
74 import java.util.stream.Collectors; 81 import java.util.stream.Collectors;
82 +import java.util.stream.Stream;
75 83
76 @Slf4j 84 @Slf4j
77 @Service 85 @Service
...@@ -295,6 +303,408 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -295,6 +303,408 @@ public class SettlementServiceImpl implements SettlementService {
295 return dateList; 303 return dateList;
296 } 304 }
297 305
306 + /**
307 + * 按订单维度生成Excel
308 + */
309 + private static ByteArrayOutputStream writeToExcelByOrder(SettlementDTO.SettlementDataByOrderDto settlementDataDto)
310 + throws IOException {
311 + Workbook workbook = new XSSFWorkbook();
312 + Sheet sheet = workbook.createSheet("客人结算");
313 +
314 + // 创建表头样式(黑色边框)
315 + CellStyle headerStyle = workbook.createCellStyle();
316 + headerStyle.setBorderTop(BorderStyle.THIN);
317 + headerStyle.setBorderBottom(BorderStyle.THIN);
318 + headerStyle.setBorderLeft(BorderStyle.THIN);
319 + headerStyle.setBorderRight(BorderStyle.THIN);
320 + headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
321 + headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
322 + headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
323 + headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
324 +
325 + // 创建数据行样式(浅灰色边框)
326 + CellStyle dataStyle = workbook.createCellStyle();
327 + dataStyle.setBorderTop(BorderStyle.THIN);
328 + dataStyle.setBorderBottom(BorderStyle.THIN);
329 + dataStyle.setBorderLeft(BorderStyle.THIN);
330 + dataStyle.setBorderRight(BorderStyle.THIN);
331 + dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
332 + dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
333 + dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
334 + dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
335 +
336 + int rowNum = 0;
337 +
338 + // 创建表头
339 + Row titleRow = sheet.createRow(rowNum++);
340 + int columnNum = 0;
341 +
342 + Cell cell0 = titleRow.createCell(columnNum++);
343 + cell0.setCellValue("用餐时间");
344 + cell0.setCellStyle(headerStyle);
345 +
346 + Cell cell1 = titleRow.createCell(columnNum++);
347 + cell1.setCellValue("订单号");
348 + cell1.setCellStyle(headerStyle);
349 +
350 + Cell cell2 = titleRow.createCell(columnNum++);
351 + cell2.setCellValue("餐别");
352 + cell2.setCellStyle(headerStyle);
353 +
354 + Cell cell3 = titleRow.createCell(columnNum++);
355 + cell3.setCellValue("房间号");
356 + cell3.setCellStyle(headerStyle);
357 +
358 + Cell cell4 = titleRow.createCell(columnNum++);
359 + cell4.setCellValue("客户姓名");
360 + cell4.setCellStyle(headerStyle);
361 +
362 + Cell cell5 = titleRow.createCell(columnNum++);
363 + cell5.setCellValue("客户腕带号");
364 + cell5.setCellStyle(headerStyle);
365 +
366 + Cell cell6 = titleRow.createCell(columnNum++);
367 + cell6.setCellValue("忌口信息");
368 + cell6.setCellStyle(headerStyle);
369 +
370 + Cell cell7 = titleRow.createCell(columnNum++);
371 + cell7.setCellValue("医嘱信息");
372 + cell7.setCellStyle(headerStyle);
373 +
374 + Cell cell8 = titleRow.createCell(columnNum++);
375 + cell8.setCellValue("餐单名称");
376 + cell8.setCellStyle(headerStyle);
377 +
378 + Cell cell9 = titleRow.createCell(columnNum++);
379 + cell9.setCellValue("菜品名称");
380 + cell9.setCellStyle(headerStyle);
381 +
382 + Cell cell10 = titleRow.createCell(columnNum++);
383 + cell10.setCellValue("菜品份数");
384 + cell10.setCellStyle(headerStyle);
385 +
386 + Cell cell11 = titleRow.createCell(columnNum++);
387 + cell11.setCellValue("菜品单价");
388 + cell11.setCellStyle(headerStyle);
389 +
390 + Cell cell12 = titleRow.createCell(columnNum++);
391 + cell12.setCellValue("菜品金额");
392 + cell12.setCellStyle(headerStyle);
393 +
394 + Cell cell13 = titleRow.createCell(columnNum++);
395 + cell13.setCellValue("菜品状态");
396 + cell13.setCellStyle(headerStyle);
397 +
398 + Cell cell14 = titleRow.createCell(columnNum++);
399 + cell14.setCellValue("交易码");
400 + cell14.setCellStyle(headerStyle);
401 +
402 + Cell cell15 = titleRow.createCell(columnNum++);
403 + cell15.setCellValue("备注");
404 + cell15.setCellStyle(headerStyle);
405 +
406 + Cell cell16 = titleRow.createCell(columnNum++);
407 + cell16.setCellValue("支付方式");
408 + cell16.setCellStyle(headerStyle);
409 +
410 + // 填充数据
411 + final var classifyOrders = settlementDataDto.getClassifyOrders();
412 + if (classifyOrders != null) {
413 + for (SettlementDTO.SettlementOrderDetail orderDetail : classifyOrders) {
414 + Row dataRow = sheet.createRow(rowNum++);
415 + columnNum = 0;
416 +
417 + Cell dataCell0 = dataRow.createCell(columnNum++);
418 + dataCell0.setCellValue(orderDetail.getMealTime() != null ? orderDetail.getMealTime() : "");
419 + dataCell0.setCellStyle(dataStyle);
420 +
421 + Cell dataCell1 = dataRow.createCell(columnNum++);
422 + dataCell1.setCellValue(orderDetail.getCode() != null ? orderDetail.getCode() : "");
423 + dataCell1.setCellStyle(dataStyle);
424 +
425 + Cell dataCell2 = dataRow.createCell(columnNum++);
426 + dataCell2.setCellValue(orderDetail.getMealName() != null ? orderDetail.getMealName() : "");
427 + dataCell2.setCellStyle(dataStyle);
428 +
429 + Cell dataCell3 = dataRow.createCell(columnNum++);
430 + dataCell3.setCellValue(orderDetail.getRoomNo() != null ? orderDetail.getRoomNo() : "");
431 + dataCell3.setCellStyle(dataStyle);
432 +
433 + Cell dataCell4 = dataRow.createCell(columnNum++);
434 + dataCell4.setCellValue(orderDetail.getCustomerName() != null ? orderDetail.getCustomerName() : "");
435 + dataCell4.setCellStyle(dataStyle);
436 +
437 + Cell dataCell5 = dataRow.createCell(columnNum++);
438 + dataCell5.setCellValue(orderDetail.getHISCustomerNo() != null ? orderDetail.getHISCustomerNo() : "");
439 + dataCell5.setCellStyle(dataStyle);
440 +
441 + // 忌口列表转字符串
442 + String avoidsStr = orderDetail.getAvoids() != null ? String.join(", ", orderDetail.getAvoids()) : "";
443 + Cell dataCell6 = dataRow.createCell(columnNum++);
444 + dataCell6.setCellValue(avoidsStr);
445 + dataCell6.setCellStyle(dataStyle);
446 +
447 + // 医嘱列表转字符串
448 + String doctorsStr = orderDetail.getDoctors() != null ? String.join(", ", orderDetail.getDoctors()) : "";
449 + Cell dataCell7 = dataRow.createCell(columnNum++);
450 + dataCell7.setCellValue(doctorsStr);
451 + dataCell7.setCellStyle(dataStyle);
452 +
453 + Cell dataCell8 = dataRow.createCell(columnNum++);
454 + dataCell8.setCellValue(orderDetail.getMenuName() != null ? orderDetail.getMenuName() : "");
455 + dataCell8.setCellStyle(dataStyle);
456 +
457 + Cell dataCell9 = dataRow.createCell(columnNum++);
458 + dataCell9.setCellValue(orderDetail.getSkuName() != null ? orderDetail.getSkuName() : "");
459 + dataCell9.setCellStyle(dataStyle);
460 +
461 + Cell dataCell10 = dataRow.createCell(columnNum++);
462 + dataCell10.setCellValue(orderDetail.getCount() != null ? orderDetail.getCount() : 0);
463 + dataCell10.setCellStyle(dataStyle);
464 +
465 + // 价格
466 + Cell dataCell11 = dataRow.createCell(columnNum++);
467 + if (orderDetail.getPrice() != null) {
468 + dataCell11.setCellValue(orderDetail.getPrice().doubleValue());
469 + } else {
470 + dataCell11.setCellValue(0.0);
471 + }
472 + dataCell11.setCellStyle(dataStyle);
473 +
474 + // 总价
475 + Cell dataCell12 = dataRow.createCell(columnNum++);
476 + if (orderDetail.getTotalPrice() != null) {
477 + dataCell12.setCellValue(orderDetail.getTotalPrice().doubleValue());
478 + } else {
479 + dataCell12.setCellValue(0.0);
480 + }
481 + dataCell12.setCellStyle(dataStyle);
482 +
483 + // 状态
484 + Cell dataCell13 = dataRow.createCell(columnNum++);
485 + dataCell13.setCellValue(orderDetail.getOperationType());
486 + dataCell13.setCellStyle(dataStyle);
487 +
488 + Cell dataCell14 = dataRow.createCell(columnNum++);
489 + dataCell14.setCellValue(orderDetail.getTransactionId() != null ? orderDetail.getTransactionId() : "");
490 + dataCell14.setCellStyle(dataStyle);
491 +
492 + // 合并备注和忌口备注,用分号分割,备注在前
493 + String remark = orderDetail.getRemark() != null ? orderDetail.getRemark() : "";
494 + String avoidRemark = orderDetail.getAvoidRemark() != null ? orderDetail.getAvoidRemark() : "";
495 + String combinedRemark = "";
496 + if (!remark.isEmpty() && !avoidRemark.isEmpty()) {
497 + combinedRemark = remark + ";" + avoidRemark;
498 + } else if (!remark.isEmpty()) {
499 + combinedRemark = remark;
500 + } else if (!avoidRemark.isEmpty()) {
501 + combinedRemark = avoidRemark;
502 + }
503 + Cell dataCell15 = dataRow.createCell(columnNum++);
504 + dataCell15.setCellValue(combinedRemark);
505 + dataCell15.setCellStyle(dataStyle);
506 +
507 + Cell dataCell16 = dataRow.createCell(columnNum++);
508 + dataCell16.setCellValue(orderDetail.getOnlinePay() != null ? orderDetail.getOnlinePay() : "");
509 + dataCell16.setCellStyle(dataStyle);
510 + }
511 + }
512 +
513 + // 自动调整列宽
514 + for (int i = 0; i < 17; i++) {
515 + sheet.autoSizeColumn(i);
516 + }
517 +
518 + // 将工作簿内容写入字节数组输出流
519 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
520 + workbook.write(outputStream);
521 + workbook.close();
522 +
523 + return outputStream;
524 + }
525 +
526 + /**
527 + * 生成分餐表Excel
528 + */
529 + private static ByteArrayOutputStream writeToExcelBySeparateMeal(SeparateMealDataDto separateMealDataDto)
530 + throws IOException {
531 + Workbook workbook = new XSSFWorkbook();
532 + Sheet sheet = workbook.createSheet("分餐表");
533 +
534 + // 创建标题样式(合并单元格标题)
535 + CellStyle titleStyle = workbook.createCellStyle();
536 + titleStyle.setAlignment(HorizontalAlignment.CENTER);
537 + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
538 + titleStyle.setBorderTop(BorderStyle.THIN);
539 + titleStyle.setBorderBottom(BorderStyle.THIN);
540 + titleStyle.setBorderLeft(BorderStyle.THIN);
541 + titleStyle.setBorderRight(BorderStyle.THIN);
542 + titleStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
543 + titleStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
544 + titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
545 + titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
546 + Font titleFont = workbook.createFont();
547 + titleFont.setBold(true);
548 + titleFont.setFontHeightInPoints((short) 16);
549 + titleStyle.setFont(titleFont);
550 +
551 + // 创建表头样式(黑色边框)
552 + CellStyle headerStyle = workbook.createCellStyle();
553 + headerStyle.setBorderTop(BorderStyle.THIN);
554 + headerStyle.setBorderBottom(BorderStyle.THIN);
555 + headerStyle.setBorderLeft(BorderStyle.THIN);
556 + headerStyle.setBorderRight(BorderStyle.THIN);
557 + headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
558 + headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
559 + headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
560 + headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
561 +
562 + // 创建数据行样式(浅灰色边框)
563 + CellStyle dataStyle = workbook.createCellStyle();
564 + dataStyle.setBorderTop(BorderStyle.THIN);
565 + dataStyle.setBorderBottom(BorderStyle.THIN);
566 + dataStyle.setBorderLeft(BorderStyle.THIN);
567 + dataStyle.setBorderRight(BorderStyle.THIN);
568 + dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
569 + dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
570 + dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
571 + dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
572 +
573 + int rowNum = 0;
574 +
575 + // 第一行:创建合并单元格标题
576 + Row mainTitleRow = sheet.createRow(rowNum++);
577 + Cell mainTitleCell = mainTitleRow.createCell(0);
578 + mainTitleCell.setCellValue("住院客户分餐表");
579 + mainTitleCell.setCellStyle(titleStyle);
580 +
581 + // 合并第一行的8列
582 + CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 8);
583 + sheet.addMergedRegion(titleRegion);
584 +
585 + // 为合并区域设置边框
586 + RegionUtil.setBorderTop(BorderStyle.THIN, titleRegion, sheet);
587 + RegionUtil.setBorderBottom(BorderStyle.THIN, titleRegion, sheet);
588 + RegionUtil.setBorderLeft(BorderStyle.THIN, titleRegion, sheet);
589 + RegionUtil.setBorderRight(BorderStyle.THIN, titleRegion, sheet);
590 + RegionUtil.setTopBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
591 + RegionUtil.setBottomBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
592 + RegionUtil.setLeftBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
593 + RegionUtil.setRightBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
594 +
595 + // 第二行:创建表头
596 + Row titleRow = sheet.createRow(rowNum++);
597 + int columnNum = 0;
598 +
599 + Cell cell0 = titleRow.createCell(columnNum++);
600 + cell0.setCellValue("餐别");
601 + cell0.setCellStyle(headerStyle);
602 +
603 + Cell cell1 = titleRow.createCell(columnNum++);
604 + cell1.setCellValue("房间号");
605 + cell1.setCellStyle(headerStyle);
606 +
607 + Cell cell2 = titleRow.createCell(columnNum++);
608 + cell2.setCellValue("客户姓名");
609 + cell2.setCellStyle(headerStyle);
610 +
611 + Cell cell3 = titleRow.createCell(columnNum++);
612 + cell3.setCellValue("医嘱信息");
613 + cell3.setCellStyle(headerStyle);
614 +
615 + Cell cell4 = titleRow.createCell(columnNum++);
616 + cell4.setCellValue("餐单名称");
617 + cell4.setCellStyle(headerStyle);
618 +
619 + Cell cell5 = titleRow.createCell(columnNum++);
620 + cell5.setCellValue("菜品名称");
621 + cell5.setCellStyle(headerStyle);
622 +
623 + Cell cell6 = titleRow.createCell(columnNum++);
624 + cell6.setCellValue("菜品数量");
625 + cell6.setCellStyle(headerStyle);
626 +
627 + Cell cell7 = titleRow.createCell(columnNum++);
628 + cell7.setCellValue("忌口信息");
629 + cell7.setCellStyle(headerStyle);
630 +
631 + Cell cell8 = titleRow.createCell(columnNum++);
632 + cell8.setCellValue("备注");
633 + cell8.setCellStyle(headerStyle);
634 +
635 + // 填充数据
636 + final var mealDetails = separateMealDataDto.getMealDetails();
637 + if (mealDetails != null) {
638 + for (SeparateMealDetail mealDetail : mealDetails) {
639 + Row dataRow = sheet.createRow(rowNum++);
640 + columnNum = 0;
641 +
642 + Cell dataCell0 = dataRow.createCell(columnNum++);
643 + dataCell0.setCellValue(mealDetail.getMealName() != null ? mealDetail.getMealName() : "");
644 + dataCell0.setCellStyle(dataStyle);
645 +
646 + Cell dataCell1 = dataRow.createCell(columnNum++);
647 + dataCell1.setCellValue(mealDetail.getRoomNo() != null ? mealDetail.getRoomNo() : "");
648 + dataCell1.setCellStyle(dataStyle);
649 +
650 + Cell dataCell2 = dataRow.createCell(columnNum++);
651 + dataCell2.setCellValue(mealDetail.getCustomerName() != null ? mealDetail.getCustomerName() : "");
652 + dataCell2.setCellStyle(dataStyle);
653 +
654 + Cell dataCell3 = dataRow.createCell(columnNum++);
655 + dataCell3.setCellValue(mealDetail.getDoctors() != null ? mealDetail.getDoctors() : "");
656 + dataCell3.setCellStyle(dataStyle);
657 +
658 + Cell dataCell4 = dataRow.createCell(columnNum++);
659 + dataCell4.setCellValue(mealDetail.getMenuName() != null ? mealDetail.getMenuName() : "");
660 + dataCell4.setCellStyle(dataStyle);
661 +
662 + Cell dataCell5 = dataRow.createCell(columnNum++);
663 + dataCell5.setCellValue(mealDetail.getSkuName() != null ? mealDetail.getSkuName() : "");
664 + dataCell5.setCellStyle(dataStyle);
665 +
666 + Cell dataCell6 = dataRow.createCell(columnNum++);
667 + dataCell6.setCellValue(mealDetail.getCount() != null ? mealDetail.getCount() : 0);
668 + dataCell6.setCellStyle(dataStyle);
669 +
670 + Cell dataCell7 = dataRow.createCell(columnNum++);
671 + dataCell7.setCellValue(mealDetail.getAvoids() != null ? mealDetail.getAvoids() : "");
672 + dataCell7.setCellStyle(dataStyle);
673 +
674 + Cell dataCell8 = dataRow.createCell(columnNum++);
675 + dataCell8.setCellValue(mealDetail.getRemark() != null ? mealDetail.getRemark() : "");
676 + dataCell8.setCellStyle(dataStyle);
677 + }
678 + }
679 +
680 + // 自动调整列宽
681 + for (int i = 0; i < 9; i++) {
682 + sheet.autoSizeColumn(i);
683 + }
684 +
685 + // 将工作簿内容写入字节数组输出流
686 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
687 + workbook.write(outputStream);
688 + workbook.close();
689 +
690 + return outputStream;
691 + }
692 +
693 + /**
694 + * 创建空的分餐表Excel(无数据)
695 + */
696 + private static ByteArrayOutputStream createEmptyExcelBySeparateMeal() {
697 + try {
698 + SeparateMealDataDto emptyData = SeparateMealDataDto.builder()
699 + .mealDetails(new ArrayList<>())
700 + .build();
701 + return writeToExcelBySeparateMeal(emptyData);
702 + } catch (IOException e) {
703 + log.error("创建空分餐表Excel失败", e);
704 + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
705 + }
706 + }
707 +
298 @Override 708 @Override
299 public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) { 709 public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) {
300 if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_SKU)) { 710 if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_SKU)) {
...@@ -369,13 +779,11 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -369,13 +779,11 @@ public class SettlementServiceImpl implements SettlementService {
369 .collect(Collectors.toList()); 779 .collect(Collectors.toList());
370 780
371 if (orderIds.isEmpty()) { 781 if (orderIds.isEmpty()) {
372 - log.warn("筛选后无有效订单,enterpriseId: {}", enterpriseId);
373 return createEmptyExcelByOrder(); 782 return createEmptyExcelByOrder();
374 } 783 }
375 784
376 // 构建订单映射 785 // 构建订单映射
377 - final var orderMap = orderList.stream() 786 + final var orderMap = orderList.stream().filter(o -> o.getId() != 0)
378 - .filter(o -> o.getId() != 0)
379 .collect(Collectors.toMap(SingleClientCustomerOrderRpcResponse::getId, o -> o, (o1, o2) -> o1)); 787 .collect(Collectors.toMap(SingleClientCustomerOrderRpcResponse::getId, o -> o, (o1, o2) -> o1));
380 788
381 // 查询订单详情 789 // 查询订单详情
...@@ -384,86 +792,60 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -384,86 +792,60 @@ public class SettlementServiceImpl implements SettlementService {
384 log.warn("未查询到订单详情数据,orderIds: {}", orderIds); 792 log.warn("未查询到订单详情数据,orderIds: {}", orderIds);
385 return createEmptyExcelByOrder(); 793 return createEmptyExcelByOrder();
386 } 794 }
387 -
388 // 订单详情按订单ID分组 795 // 订单详情按订单ID分组
389 - final var orderDetailGroupByOrderId = orderDetailList.stream() 796 + final var orderDetailGroupByOrderId = orderDetailList.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(SingleClientCustomerOrderDetailRpcResponse::getOrderId));
390 - .filter(Objects::nonNull) 797 +
391 - .filter(d -> !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT)) 798 + final var orderOperationRecordsByOrderIds = orderServiceRpcClient.getOrderOperationRecordsByOrderIds(LoginContextHolder.getEnterpriseId(), orderIds).getResponsesList();
392 - .collect(Collectors.groupingBy(SingleClientCustomerOrderDetailRpcResponse::getOrderId)); 799 +
393 - 800 + // 订单操作记录按订单ID分组
394 - // 获取SKU数据 801 + final var orderOperationRecordByOrderId = orderOperationRecordsByOrderIds.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(OrderOperationRecord::getOrderId));
395 - List<Integer> skuIds = orderDetailList.stream() 802 +
396 - .filter(Objects::nonNull) 803 + List<Integer> skuIds = Stream.concat(
397 - .filter(d -> !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT)) 804 + orderOperationRecordsByOrderIds.stream()
398 - .map(SingleClientCustomerOrderDetailRpcResponse::getSkuId) 805 + .filter(e -> StringUtils.isNoneBlank(e.getOriginalOrderDetailJson()))
806 + .flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {}).stream())
807 + .map(OrderDetailBO::getSkuId),
808 + orderDetailList.stream()
809 + .filter(Objects::nonNull)
810 + .map(SingleClientCustomerOrderDetailRpcResponse::getSkuId)
811 + )
399 .distinct() 812 .distinct()
400 .collect(Collectors.toList()); 813 .collect(Collectors.toList());
401 814
402 final var skuResponse = skuServiceRpcClient.getDishSkusByIds(skuIds); 815 final var skuResponse = skuServiceRpcClient.getDishSkusByIds(skuIds);
403 - final List<SingleDishSkuByIdsRpcResponse> skus = skuResponse != null ? skuResponse.getResponseList() : new ArrayList<>(); 816 + final List<SingleDishSkuByIdsRpcResponse> skus = skuResponse.getResponseList();
404 - final var skuMap = skus.stream() 817 + final var skuMap = skus.stream().collect(Collectors.toMap(SingleDishSkuByIdsRpcResponse::getId, s -> s, (s1, s2) -> s1));
405 - .filter(Objects::nonNull)
406 - .filter(s -> s.getId() != 0)
407 - .collect(Collectors.toMap(SingleDishSkuByIdsRpcResponse::getId, s -> s, (s1, s2) -> s1));
408 818
409 // 获取餐别数据 819 // 获取餐别数据
410 final var mealResponse = mealServiceRpcClient.getAllMeals(enterpriseId); 820 final var mealResponse = mealServiceRpcClient.getAllMeals(enterpriseId);
411 final List<SingleMealRpcResponse> meals = mealResponse != null ? mealResponse.getResponsesList() : new ArrayList<>(); 821 final List<SingleMealRpcResponse> meals = mealResponse != null ? mealResponse.getResponsesList() : new ArrayList<>();
412 - final var mealMap = meals.stream() 822 + final var mealMap = meals.stream().collect(Collectors.toMap(SingleMealRpcResponse::getId, m -> m, (m1, m2) -> m1));
413 - .filter(Objects::nonNull)
414 - .filter(m -> m.getId() != 0)
415 - .collect(Collectors.toMap(SingleMealRpcResponse::getId, m -> m, (m1, m2) -> m1));
416 823
417 // 获取菜单数据 824 // 获取菜单数据
418 - List<Integer> menuIds = orderList.stream() 825 + List<Integer> menuIds = orderList.stream().map(SingleClientCustomerOrderRpcResponse::getMenuId).distinct().collect(Collectors.toList());
419 - .filter(Objects::nonNull)
420 - .map(SingleClientCustomerOrderRpcResponse::getMenuId)
421 - .filter(id -> id != 0)
422 - .distinct()
423 - .collect(Collectors.toList());
424 -
425 final var menuResponse = menuServiceRpcClient.getMenusByIds(enterpriseId, menuIds); 826 final var menuResponse = menuServiceRpcClient.getMenusByIds(enterpriseId, menuIds);
426 final List<SingleMenuRpcResponse> menuList = menuResponse != null ? menuResponse.getResponsesList() : new ArrayList<>(); 827 final List<SingleMenuRpcResponse> menuList = menuResponse != null ? menuResponse.getResponsesList() : new ArrayList<>();
427 - final var menuMap = menuList.stream() 828 + final var menuMap = menuList.stream().collect(Collectors.toMap(SingleMenuRpcResponse::getId, m -> m, (m1, m2) -> m1));
428 - .filter(Objects::nonNull)
429 - .filter(m -> m.getId() != 0)
430 - .collect(Collectors.toMap(SingleMenuRpcResponse::getId, m -> m, (m1, m2) -> m1));
431 829
432 // 获取菜单详情数据 830 // 获取菜单详情数据
433 final var menuDetailResponse = menuServiceRpcClient.queryMenuDetailsByMenuIds(enterpriseId, menuIds); 831 final var menuDetailResponse = menuServiceRpcClient.queryMenuDetailsByMenuIds(enterpriseId, menuIds);
434 - final List<SingleMenuDetailRpcResponse> menuDetailList = menuDetailResponse != null ? menuDetailResponse.getResponsesList() : new ArrayList<>(); 832 + final List<SingleMenuDetailRpcResponse> menuDetailList = menuDetailResponse.getResponsesList();
435 - final var menuDetailMap = menuDetailList.stream() 833 + final var menuDetailMap = menuDetailList.stream().collect(Collectors.toMap(SingleMenuDetailRpcResponse::getId, m -> m, (m1, m2) -> m1));
436 - .filter(Objects::nonNull)
437 - .filter(m -> m.getId() != 0)
438 - .collect(Collectors.toMap(SingleMenuDetailRpcResponse::getId, m -> m, (m1, m2) -> m1));
439 834
440 // 获取客户数据 835 // 获取客户数据
441 - List<Integer> customerIds = orderList.stream() 836 + List<Integer> customerIds = orderList.stream().map(SingleClientCustomerOrderRpcResponse::getCustomerId).distinct().collect(Collectors.toList());
442 - .filter(Objects::nonNull) 837 + final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds);
443 - .map(SingleClientCustomerOrderRpcResponse::getCustomerId) 838 + final List<SingleClientCustomerRpcResponse> customers = customerResponse.getResponsesList();
444 - .filter(id -> id != 0) 839 + final var customerMap = customers.stream().collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1));
445 - .distinct()
446 - .collect(Collectors.toList());
447 -
448 - final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds);
449 - final List<SingleClientCustomerRpcResponse> customers = customerResponse != null ? customerResponse.getResponsesList() : new ArrayList<>();
450 - final var customerMap = customers.stream()
451 - .filter(Objects::nonNull)
452 - .filter(c -> c.getId() != 0)
453 - .collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1));
454 840
455 // 构建结算订单明细 841 // 构建结算订单明细
456 final var classifyOrders = new ArrayList<SettlementDTO.SettlementOrderDetail>(); 842 final var classifyOrders = new ArrayList<SettlementDTO.SettlementOrderDetail>();
457 for (Integer orderId : orderIds) { 843 for (Integer orderId : orderIds) {
458 final var orderDetails = orderDetailGroupByOrderId.getOrDefault(orderId, Collections.emptyList()); 844 final var orderDetails = orderDetailGroupByOrderId.getOrDefault(orderId, Collections.emptyList());
459 final var order = orderMap.get(orderId); 845 final var order = orderMap.get(orderId);
460 -
461 - // 订单为空则跳过
462 if (order == null) { 846 if (order == null) {
463 - log.warn("订单不存在,orderId: {}", orderId);
464 continue; 847 continue;
465 } 848 }
466 -
467 // 获取菜单信息 849 // 获取菜单信息
468 final var menu = menuMap.get(order.getMenuId()); 850 final var menu = menuMap.get(order.getMenuId());
469 final String menuName = menu != null ? menu.getName() : ""; 851 final String menuName = menu != null ? menu.getName() : "";
...@@ -473,52 +855,63 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -473,52 +855,63 @@ public class SettlementServiceImpl implements SettlementService {
473 final String customerName = customer != null ? customer.getName() : ""; 855 final String customerName = customer != null ? customer.getName() : "";
474 final String hisCustomerNo = customer != null ? customer.getHISCustomerNo() : ""; 856 final String hisCustomerNo = customer != null ? customer.getHISCustomerNo() : "";
475 857
476 - // 处理每个订单详情 858 + final var orderOperationRecords = orderOperationRecordByOrderId.get(orderId);
477 - for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) {
478 - if (orderDetail == null) {
479 - continue;
480 - }
481 859
482 - // 安全获取餐别名称 860 + Map<Integer, OrderDetailBO> addOriginalDetailMap = orderOperationRecords.stream()
483 - String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap); 861 + .filter(e -> e.getType() == OrderOperationType.ADD_DISHES)
862 + .flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {
863 + }).stream())
864 + .collect(Collectors.toMap(OrderDetailBO::getId, Function.identity(), (a, b) -> a));
484 865
485 - // 安全获取SKU名称 866 + Map<Integer, OrderDetailBO> replaceOriginalDetailMap = orderOperationRecords.stream()
486 - String skuName = getSkuNameSafely(orderDetail, skuMap); 867 + .filter(e -> e.getType() == OrderOperationType.REPLACE_DISHES)
868 + .flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {
869 + }).stream())
870 + .collect(Collectors.toMap(OrderDetailBO::getId, Function.identity(), (a, b) -> a));
487 871
488 - // 安全获取房间号 872 + for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) {
489 - String roomNo = getRoomNoSafely(order); 873 + // 1. 先处理加餐
874 + if (addOriginalDetailMap.containsKey(orderDetail.getId())
875 + && addOriginalDetailMap.get(orderDetail.getId()).getCount() != orderDetail.getCount()) {
876 + SettlementDTO.SettlementOrderDetail addRecord = buildSettlementOrderDetail(
877 + order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "加餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
878 + classifyOrders.add(addRecord);
879 + }
490 880
491 - // 安全获取忌口和医嘱 881 + // 2. 再处理换菜
492 - List<String> avoids = getAvoidsSafely(order); 882 + if (replaceOriginalDetailMap.containsKey(orderDetail.getId())
493 - List<String> doctors = getDoctorsSafely(order); 883 + && !Objects.equals(replaceOriginalDetailMap.get(orderDetail.getId()).getSkuId(), orderDetail.getSkuId())) {
884 + final var orderDetailBO = replaceOriginalDetailMap.get(orderDetail.getId());
885 + SettlementDTO.SettlementOrderDetail beforeChange = buildSettlementOrderDetail(
886 + order, orderDetail.getMenuDetailId(), orderDetailBO.getSkuId(), orderDetailBO.getCount(), orderDetailBO.getPrice(), "换菜前", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
887 + classifyOrders.add(beforeChange);
888 +
889 + SettlementDTO.SettlementOrderDetail afterChange = buildSettlementOrderDetail(
890 + order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "换菜后", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
891 + classifyOrders.add(afterChange);
892 + }
494 893
495 - // 安全获取在线支付描述 894 + // 3. 判断已退款
496 - String onlinePayDesc = getOnlinePayDescSafely(order); 895 + if (orderDetail.getServeStatus() == ServeStatusEnum.SERVE_REJECT) {
896 + SettlementDTO.SettlementOrderDetail refundRecord = buildSettlementOrderDetail(
897 + order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "已退款", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
898 + classifyOrders.add(refundRecord);
899 + }
497 900
498 - // 构建订单详情 901 + // 4. 如果既不是加餐,也不是换菜,也不是退款,才记录“订餐”
499 - order.getOrderCode(); 902 + boolean isNormal = !(addOriginalDetailMap.containsKey(orderDetail.getId())
500 - order.getRemark(); 903 + && addOriginalDetailMap.get(orderDetail.getId()).getCount() != orderDetail.getCount())
501 - order.getAvoidRemark(); 904 + && !(replaceOriginalDetailMap.containsKey(orderDetail.getId())
502 - SettlementDTO.SettlementOrderDetail settlementOrderDetail = SettlementDTO.SettlementOrderDetail.builder() 905 + && !Objects.equals(replaceOriginalDetailMap.get(orderDetail.getId()).getSkuId(), orderDetail.getSkuId()))
503 - .mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "") 906 + && orderDetail.getServeStatus() != ServeStatusEnum.SERVE_REJECT;
504 - .code(order.getOrderCode()) 907 +
505 - .mealName(mealName) 908 + if (isNormal) {
506 - .roomNo(roomNo) 909 + SettlementDTO.SettlementOrderDetail normalRecord = buildSettlementOrderDetail(
507 - .customerName(customerName) 910 + order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "订餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
508 - .HISCustomerNo(hisCustomerNo) 911 + classifyOrders.add(normalRecord);
509 - .avoids(avoids) 912 + }
510 - .doctors(doctors)
511 - .menuName(menuName)
512 - .skuName(skuName)
513 - .count(orderDetail.getCount() != 0 ? orderDetail.getCount() : 0)
514 - .price(calculatePrice(orderDetail.getPrice()))
515 - .totalPrice(calculateTotalPrice(orderDetail.getPrice(), orderDetail.getCount()))
516 - .remark(order.getRemark())
517 - .avoidRemark(order.getAvoidRemark())
518 - .onlinePay(onlinePayDesc)
519 - .build();
520 - classifyOrders.add(settlementOrderDetail);
521 } 913 }
914 +
522 } 915 }
523 916
524 // 构建结算数据 917 // 构建结算数据
...@@ -535,17 +928,57 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -535,17 +928,57 @@ public class SettlementServiceImpl implements SettlementService {
535 } 928 }
536 } 929 }
537 930
931 + private SettlementDTO.SettlementOrderDetail buildSettlementOrderDetail(SingleClientCustomerOrderRpcResponse order,
932 + int menuDetailId,
933 + int skuId,
934 + int count,
935 + Integer price,
936 + String operationType,
937 + String menuName,
938 + String customerName,
939 + String hisCustomerNo,
940 + Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
941 + Map<Integer, SingleMealRpcResponse> mealMap,
942 + Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
943 + String mealName = getMealNameSafely(menuDetailId, menuDetailMap, mealMap);
944 + String skuName = getSkuNameSafely(skuId, skuMap);
945 + String roomNo = getRoomNoSafely(order);
946 + List<String> avoids = getAvoidsSafely(order);
947 + List<String> doctors = getDoctorsSafely(order);
948 + String onlinePayDesc = getOnlinePayDescSafely(order);
949 + return SettlementDTO.SettlementOrderDetail.builder()
950 + .mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "")
951 + .code(order.getOrderCode())
952 + .mealName(mealName)
953 + .roomNo(roomNo)
954 + .customerName(customerName)
955 + .HISCustomerNo(hisCustomerNo)
956 + .avoids(avoids)
957 + .doctors(doctors)
958 + .menuName(menuName)
959 + .skuName(skuName)
960 + .count(count)
961 + .price(calculatePrice(price))
962 + .totalPrice(calculateTotalPrice(price, count))
963 + .remark(order.getRemark())
964 + .avoidRemark(order.getAvoidRemark())
965 + .onlinePay(onlinePayDesc)
966 + .operationType(operationType)
967 + .transactionId(order.getTransactionId())
968 + .build();
969 + }
970 +
538 /** 971 /**
539 * 安全获取餐别名称 972 * 安全获取餐别名称
540 */ 973 */
541 - private String getMealNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail, 974 + private String getMealNameSafely(int menuDetailId,
542 - Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap, 975 + Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
543 - Map<Integer, SingleMealRpcResponse> mealMap) { 976 + Map<Integer, SingleMealRpcResponse> mealMap) {
544 - if (orderDetail == null || orderDetail.getMenuDetailId() == 0) { 977 + if (menuDetailId == 0) {
545 return ""; 978 return "";
546 } 979 }
547 980
548 - final var menuDetail = menuDetailMap.get(orderDetail.getMenuDetailId()); 981 + final var menuDetail = menuDetailMap.get(menuDetailId);
549 if (menuDetail == null || menuDetail.getMealId() == 0) { 982 if (menuDetail == null || menuDetail.getMealId() == 0) {
550 return ""; 983 return "";
551 } 984 }
...@@ -557,13 +990,12 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -557,13 +990,12 @@ public class SettlementServiceImpl implements SettlementService {
557 /** 990 /**
558 * 安全获取SKU名称 991 * 安全获取SKU名称
559 */ 992 */
560 - private String getSkuNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail, 993 + private String getSkuNameSafely(int skuId,
561 - Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) { 994 + Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
562 - if (orderDetail == null || orderDetail.getSkuId() == 0) { 995 + if (skuId == 0) {
563 return ""; 996 return "";
564 } 997 }
565 - 998 + final var sku = skuMap.get(skuId);
566 - final var sku = skuMap.get(orderDetail.getSkuId());
567 return sku != null ? sku.getName() : ""; 999 return sku != null ? sku.getName() : "";
568 } 1000 }
569 1001
...@@ -598,268 +1030,65 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -598,268 +1030,65 @@ public class SettlementServiceImpl implements SettlementService {
598 * 安全获取医嘱列表 1030 * 安全获取医嘱列表
599 */ 1031 */
600 private List<String> getDoctorsSafely(SingleClientCustomerOrderRpcResponse order) { 1032 private List<String> getDoctorsSafely(SingleClientCustomerOrderRpcResponse order) {
601 - if (order == null) { 1033 + if (order == null) {
602 - return Collections.emptyList(); 1034 + return Collections.emptyList();
603 - } 1035 + }
604 -
605 - return order.getCustomerNoticeJson().getDoctorsList();
606 - }
607 -
608 - /**
609 - * 安全获取在线支付描述
610 - */
611 - private String getOnlinePayDescSafely(SingleClientCustomerOrderRpcResponse order) {
612 - if (order == null) {
613 - return "";
614 - }
615 -
616 - try {
617 - String desc = BaseProtoDescEnum.getDescByProtoEnum(order.getOnlinePay(), OnlinePayDescEnum.class);
618 - return desc != null ? desc : "";
619 - } catch (Exception e) {
620 - log.warn("获取在线支付描述失败,orderId: {}", order.getId(), e);
621 - return "";
622 - }
623 - }
624 -
625 - /**
626 - * 计算单价
627 - */
628 - private BigDecimal calculatePrice(Integer price) {
629 - if (price == null) {
630 - return BigDecimal.ZERO;
631 - }
632 - return new BigDecimal(price).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
633 - }
634 -
635 - /**
636 - * 计算总价
637 - */
638 - private BigDecimal calculateTotalPrice(Integer price, Integer count) {
639 - if (price == null || count == null) {
640 - return BigDecimal.ZERO;
641 - }
642 - return new BigDecimal(price)
643 - .multiply(new BigDecimal(count))
644 - .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
645 - }
646 -
647 - /**
648 - * 创建空的订单Excel
649 - */
650 - private ByteArrayOutputStream createEmptyExcelByOrder() {
651 - try {
652 - final var emptyData = SettlementDTO.SettlementDataByOrderDto.builder()
653 - .classifyOrders(Collections.emptyList())
654 - .build();
655 - return writeToExcelByOrder(emptyData);
656 - } catch (IOException e) {
657 - log.error("创建空Excel失败", e);
658 - throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
659 - }
660 - }
661 -
662 - /**
663 - * 按订单维度生成Excel
664 - */
665 - private static ByteArrayOutputStream writeToExcelByOrder(SettlementDTO.SettlementDataByOrderDto settlementDataDto)
666 - throws IOException {
667 - Workbook workbook = new XSSFWorkbook();
668 - Sheet sheet = workbook.createSheet("客人结算");
669 -
670 - // 创建表头样式(黑色边框)
671 - CellStyle headerStyle = workbook.createCellStyle();
672 - headerStyle.setBorderTop(BorderStyle.THIN);
673 - headerStyle.setBorderBottom(BorderStyle.THIN);
674 - headerStyle.setBorderLeft(BorderStyle.THIN);
675 - headerStyle.setBorderRight(BorderStyle.THIN);
676 - headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
677 - headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
678 - headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
679 - headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
680 -
681 - // 创建数据行样式(浅灰色边框)
682 - CellStyle dataStyle = workbook.createCellStyle();
683 - dataStyle.setBorderTop(BorderStyle.THIN);
684 - dataStyle.setBorderBottom(BorderStyle.THIN);
685 - dataStyle.setBorderLeft(BorderStyle.THIN);
686 - dataStyle.setBorderRight(BorderStyle.THIN);
687 - dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
688 - dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
689 - dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
690 - dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
691 -
692 - int rowNum = 0;
693 -
694 - // 创建表头
695 - Row titleRow = sheet.createRow(rowNum++);
696 - int columnNum = 0;
697 -
698 - Cell cell0 = titleRow.createCell(columnNum++);
699 - cell0.setCellValue("用餐时间");
700 - cell0.setCellStyle(headerStyle);
701 -
702 - Cell cell1 = titleRow.createCell(columnNum++);
703 - cell1.setCellValue("订单号");
704 - cell1.setCellStyle(headerStyle);
705 -
706 - Cell cell2 = titleRow.createCell(columnNum++);
707 - cell2.setCellValue("餐别");
708 - cell2.setCellStyle(headerStyle);
709 -
710 - Cell cell3 = titleRow.createCell(columnNum++);
711 - cell3.setCellValue("房间号");
712 - cell3.setCellStyle(headerStyle);
713 -
714 - Cell cell4 = titleRow.createCell(columnNum++);
715 - cell4.setCellValue("客户姓名");
716 - cell4.setCellStyle(headerStyle);
717 -
718 - Cell cell5 = titleRow.createCell(columnNum++);
719 - cell5.setCellValue("客户腕带号");
720 - cell5.setCellStyle(headerStyle);
721 -
722 - Cell cell6 = titleRow.createCell(columnNum++);
723 - cell6.setCellValue("忌口信息");
724 - cell6.setCellStyle(headerStyle);
725 -
726 - Cell cell7 = titleRow.createCell(columnNum++);
727 - cell7.setCellValue("医嘱信息");
728 - cell7.setCellStyle(headerStyle);
729 -
730 - Cell cell8 = titleRow.createCell(columnNum++);
731 - cell8.setCellValue("餐单名称");
732 - cell8.setCellStyle(headerStyle);
733 -
734 - Cell cell9 = titleRow.createCell(columnNum++);
735 - cell9.setCellValue("菜品名称");
736 - cell9.setCellStyle(headerStyle);
737 -
738 - Cell cell10 = titleRow.createCell(columnNum++);
739 - cell10.setCellValue("菜品份数");
740 - cell10.setCellStyle(headerStyle);
741 -
742 - Cell cell11 = titleRow.createCell(columnNum++);
743 - cell11.setCellValue("菜品单价");
744 - cell11.setCellStyle(headerStyle);
745 -
746 - Cell cell12 = titleRow.createCell(columnNum++);
747 - cell12.setCellValue("菜品金额");
748 - cell12.setCellStyle(headerStyle);
749 -
750 - Cell cell13 = titleRow.createCell(columnNum++);
751 - cell13.setCellValue("备注");
752 - cell13.setCellStyle(headerStyle);
753 -
754 - Cell cell14 = titleRow.createCell(columnNum++);
755 - cell14.setCellValue("支付方式");
756 - cell14.setCellStyle(headerStyle);
757 -
758 - // 填充数据
759 - final var classifyOrders = settlementDataDto.getClassifyOrders();
760 - if (classifyOrders != null) {
761 - for (SettlementDTO.SettlementOrderDetail orderDetail : classifyOrders) {
762 - Row dataRow = sheet.createRow(rowNum++);
763 - columnNum = 0;
764 -
765 - Cell dataCell0 = dataRow.createCell(columnNum++);
766 - dataCell0.setCellValue(orderDetail.getMealTime() != null ? orderDetail.getMealTime() : "");
767 - dataCell0.setCellStyle(dataStyle);
768 -
769 - Cell dataCell1 = dataRow.createCell(columnNum++);
770 - dataCell1.setCellValue(orderDetail.getCode() != null ? orderDetail.getCode() : "");
771 - dataCell1.setCellStyle(dataStyle);
772 -
773 - Cell dataCell2 = dataRow.createCell(columnNum++);
774 - dataCell2.setCellValue(orderDetail.getMealName() != null ? orderDetail.getMealName() : "");
775 - dataCell2.setCellStyle(dataStyle);
776 -
777 - Cell dataCell3 = dataRow.createCell(columnNum++);
778 - dataCell3.setCellValue(orderDetail.getRoomNo() != null ? orderDetail.getRoomNo() : "");
779 - dataCell3.setCellStyle(dataStyle);
780 -
781 - Cell dataCell4 = dataRow.createCell(columnNum++);
782 - dataCell4.setCellValue(orderDetail.getCustomerName() != null ? orderDetail.getCustomerName() : "");
783 - dataCell4.setCellStyle(dataStyle);
784 -
785 - Cell dataCell5 = dataRow.createCell(columnNum++);
786 - dataCell5.setCellValue(orderDetail.getHISCustomerNo() != null ? orderDetail.getHISCustomerNo() : "");
787 - dataCell5.setCellStyle(dataStyle);
788 -
789 - // 忌口列表转字符串
790 - String avoidsStr = orderDetail.getAvoids() != null ? String.join(", ", orderDetail.getAvoids()) : "";
791 - Cell dataCell6 = dataRow.createCell(columnNum++);
792 - dataCell6.setCellValue(avoidsStr);
793 - dataCell6.setCellStyle(dataStyle);
794 -
795 - // 医嘱列表转字符串
796 - String doctorsStr = orderDetail.getDoctors() != null ? String.join(", ", orderDetail.getDoctors()) : "";
797 - Cell dataCell7 = dataRow.createCell(columnNum++);
798 - dataCell7.setCellValue(doctorsStr);
799 - dataCell7.setCellStyle(dataStyle);
800 -
801 - Cell dataCell8 = dataRow.createCell(columnNum++);
802 - dataCell8.setCellValue(orderDetail.getMenuName() != null ? orderDetail.getMenuName() : "");
803 - dataCell8.setCellStyle(dataStyle);
804 -
805 - Cell dataCell9 = dataRow.createCell(columnNum++);
806 - dataCell9.setCellValue(orderDetail.getSkuName() != null ? orderDetail.getSkuName() : "");
807 - dataCell9.setCellStyle(dataStyle);
808 -
809 - Cell dataCell10 = dataRow.createCell(columnNum++);
810 - dataCell10.setCellValue(orderDetail.getCount() != null ? orderDetail.getCount() : 0);
811 - dataCell10.setCellStyle(dataStyle);
812 -
813 - // 价格
814 - Cell dataCell11 = dataRow.createCell(columnNum++);
815 - if (orderDetail.getPrice() != null) {
816 - dataCell11.setCellValue(orderDetail.getPrice().doubleValue());
817 - } else {
818 - dataCell11.setCellValue(0.0);
819 - }
820 - dataCell11.setCellStyle(dataStyle);
821 -
822 - // 总价
823 - Cell dataCell12 = dataRow.createCell(columnNum++);
824 - if (orderDetail.getTotalPrice() != null) {
825 - dataCell12.setCellValue(orderDetail.getTotalPrice().doubleValue());
826 - } else {
827 - dataCell12.setCellValue(0.0);
828 - }
829 - dataCell12.setCellStyle(dataStyle);
830 1036
831 - // 合并备注和忌口备注,用分号分割,备注在前 1037 + return order.getCustomerNoticeJson().getDoctorsList();
832 - String remark = orderDetail.getRemark() != null ? orderDetail.getRemark() : ""; 1038 + }
833 - String avoidRemark = orderDetail.getAvoidRemark() != null ? orderDetail.getAvoidRemark() : "";
834 - String combinedRemark = "";
835 - if (!remark.isEmpty() && !avoidRemark.isEmpty()) {
836 - combinedRemark = remark + ";" + avoidRemark;
837 - } else if (!remark.isEmpty()) {
838 - combinedRemark = remark;
839 - } else if (!avoidRemark.isEmpty()) {
840 - combinedRemark = avoidRemark;
841 - }
842 - Cell dataCell13 = dataRow.createCell(columnNum++);
843 - dataCell13.setCellValue(combinedRemark);
844 - dataCell13.setCellStyle(dataStyle);
845 1039
846 - Cell dataCell14 = dataRow.createCell(columnNum++); 1040 + /**
847 - dataCell14.setCellValue(orderDetail.getOnlinePay() != null ? orderDetail.getOnlinePay() : ""); 1041 + * 安全获取在线支付描述
848 - dataCell14.setCellStyle(dataStyle); 1042 + */
849 - } 1043 + private String getOnlinePayDescSafely(SingleClientCustomerOrderRpcResponse order) {
1044 + if (order == null) {
1045 + return "";
850 } 1046 }
851 1047
852 - // 自动调整列宽 1048 + try {
853 - for (int i = 0; i < 15; i++) { 1049 + String desc = BaseProtoDescEnum.getDescByProtoEnum(order.getOnlinePay(), OnlinePayDescEnum.class);
854 - sheet.autoSizeColumn(i); 1050 + return desc != null ? desc : "";
1051 + } catch (Exception e) {
1052 + log.warn("获取在线支付描述失败,orderId: {}", order.getId(), e);
1053 + return "";
855 } 1054 }
1055 + }
856 1056
857 - // 将工作簿内容写入字节数组输出流 1057 + /**
858 - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 1058 + * 计算单价
859 - workbook.write(outputStream); 1059 + */
860 - workbook.close(); 1060 + private BigDecimal calculatePrice(Integer price) {
1061 + if (price == null) {
1062 + return BigDecimal.ZERO;
1063 + }
1064 + return new BigDecimal(price).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
1065 + }
861 1066
862 - return outputStream; 1067 + /**
1068 + * 计算总价
1069 + */
1070 + private BigDecimal calculateTotalPrice(Integer price, Integer count) {
1071 + if (price == null || count == null) {
1072 + return BigDecimal.ZERO;
1073 + }
1074 + return new BigDecimal(price)
1075 + .multiply(new BigDecimal(count))
1076 + .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
1077 + }
1078 +
1079 + /**
1080 + * 创建空的订单Excel
1081 + */
1082 + private ByteArrayOutputStream createEmptyExcelByOrder() {
1083 + try {
1084 + final var emptyData = SettlementDTO.SettlementDataByOrderDto.builder()
1085 + .classifyOrders(Collections.emptyList())
1086 + .build();
1087 + return writeToExcelByOrder(emptyData);
1088 + } catch (IOException e) {
1089 + log.error("创建空Excel失败", e);
1090 + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
1091 + }
863 } 1092 }
864 1093
865 public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) { 1094 public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) {
...@@ -1249,10 +1478,10 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -1249,10 +1478,10 @@ public class SettlementServiceImpl implements SettlementService {
1249 } 1478 }
1250 1479
1251 // 安全获取餐别名称 1480 // 安全获取餐别名称
1252 - String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap); 1481 + String mealName = getMealNameSafely(orderDetail.getMenuDetailId(), menuDetailMap, mealMap);
1253 1482
1254 // 安全获取SKU名称 1483 // 安全获取SKU名称
1255 - String skuName = getSkuNameSafely(orderDetail, skuMap); 1484 + String skuName = getSkuNameSafely(orderDetail.getSkuId(), skuMap);
1256 1485
1257 // 安全获取忌口信息(列表转字符串) 1486 // 安全获取忌口信息(列表转字符串)
1258 List<String> avoidsList = getAvoidsSafely(order); 1487 List<String> avoidsList = getAvoidsSafely(order);
...@@ -1304,186 +1533,4 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -1304,186 +1533,4 @@ public class SettlementServiceImpl implements SettlementService {
1304 } 1533 }
1305 } 1534 }
1306 1535
1307 - /**
1308 - * 生成分餐表Excel
1309 - */
1310 - private static ByteArrayOutputStream writeToExcelBySeparateMeal(SeparateMealDataDto separateMealDataDto)
1311 - throws IOException {
1312 - Workbook workbook = new XSSFWorkbook();
1313 - Sheet sheet = workbook.createSheet("分餐表");
1314 -
1315 - // 创建标题样式(合并单元格标题)
1316 - CellStyle titleStyle = workbook.createCellStyle();
1317 - titleStyle.setAlignment(HorizontalAlignment.CENTER);
1318 - titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
1319 - titleStyle.setBorderTop(BorderStyle.THIN);
1320 - titleStyle.setBorderBottom(BorderStyle.THIN);
1321 - titleStyle.setBorderLeft(BorderStyle.THIN);
1322 - titleStyle.setBorderRight(BorderStyle.THIN);
1323 - titleStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
1324 - titleStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
1325 - titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
1326 - titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
1327 - Font titleFont = workbook.createFont();
1328 - titleFont.setBold(true);
1329 - titleFont.setFontHeightInPoints((short) 16);
1330 - titleStyle.setFont(titleFont);
1331 -
1332 - // 创建表头样式(黑色边框)
1333 - CellStyle headerStyle = workbook.createCellStyle();
1334 - headerStyle.setBorderTop(BorderStyle.THIN);
1335 - headerStyle.setBorderBottom(BorderStyle.THIN);
1336 - headerStyle.setBorderLeft(BorderStyle.THIN);
1337 - headerStyle.setBorderRight(BorderStyle.THIN);
1338 - headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
1339 - headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
1340 - headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
1341 - headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
1342 -
1343 - // 创建数据行样式(浅灰色边框)
1344 - CellStyle dataStyle = workbook.createCellStyle();
1345 - dataStyle.setBorderTop(BorderStyle.THIN);
1346 - dataStyle.setBorderBottom(BorderStyle.THIN);
1347 - dataStyle.setBorderLeft(BorderStyle.THIN);
1348 - dataStyle.setBorderRight(BorderStyle.THIN);
1349 - dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
1350 - dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
1351 - dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
1352 - dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
1353 -
1354 - int rowNum = 0;
1355 -
1356 - // 第一行:创建合并单元格标题
1357 - Row mainTitleRow = sheet.createRow(rowNum++);
1358 - Cell mainTitleCell = mainTitleRow.createCell(0);
1359 - mainTitleCell.setCellValue("住院客户分餐表");
1360 - mainTitleCell.setCellStyle(titleStyle);
1361 -
1362 - // 合并第一行的8列
1363 - CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 8);
1364 - sheet.addMergedRegion(titleRegion);
1365 -
1366 - // 为合并区域设置边框
1367 - RegionUtil.setBorderTop(BorderStyle.THIN, titleRegion, sheet);
1368 - RegionUtil.setBorderBottom(BorderStyle.THIN, titleRegion, sheet);
1369 - RegionUtil.setBorderLeft(BorderStyle.THIN, titleRegion, sheet);
1370 - RegionUtil.setBorderRight(BorderStyle.THIN, titleRegion, sheet);
1371 - RegionUtil.setTopBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
1372 - RegionUtil.setBottomBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
1373 - RegionUtil.setLeftBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
1374 - RegionUtil.setRightBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
1375 -
1376 - // 第二行:创建表头
1377 - Row titleRow = sheet.createRow(rowNum++);
1378 - int columnNum = 0;
1379 -
1380 - Cell cell0 = titleRow.createCell(columnNum++);
1381 - cell0.setCellValue("餐别");
1382 - cell0.setCellStyle(headerStyle);
1383 -
1384 - Cell cell1 = titleRow.createCell(columnNum++);
1385 - cell1.setCellValue("房间号");
1386 - cell1.setCellStyle(headerStyle);
1387 -
1388 - Cell cell2 = titleRow.createCell(columnNum++);
1389 - cell2.setCellValue("客户姓名");
1390 - cell2.setCellStyle(headerStyle);
1391 -
1392 - Cell cell3 = titleRow.createCell(columnNum++);
1393 - cell3.setCellValue("医嘱信息");
1394 - cell3.setCellStyle(headerStyle);
1395 -
1396 - Cell cell4 = titleRow.createCell(columnNum++);
1397 - cell4.setCellValue("餐单名称");
1398 - cell4.setCellStyle(headerStyle);
1399 -
1400 - Cell cell5 = titleRow.createCell(columnNum++);
1401 - cell5.setCellValue("菜品名称");
1402 - cell5.setCellStyle(headerStyle);
1403 -
1404 - Cell cell6 = titleRow.createCell(columnNum++);
1405 - cell6.setCellValue("菜品数量");
1406 - cell6.setCellStyle(headerStyle);
1407 -
1408 - Cell cell7 = titleRow.createCell(columnNum++);
1409 - cell7.setCellValue("忌口信息");
1410 - cell7.setCellStyle(headerStyle);
1411 -
1412 - Cell cell8 = titleRow.createCell(columnNum++);
1413 - cell8.setCellValue("备注");
1414 - cell8.setCellStyle(headerStyle);
1415 -
1416 - // 填充数据
1417 - final var mealDetails = separateMealDataDto.getMealDetails();
1418 - if (mealDetails != null) {
1419 - for (SeparateMealDetail mealDetail : mealDetails) {
1420 - Row dataRow = sheet.createRow(rowNum++);
1421 - columnNum = 0;
1422 -
1423 - Cell dataCell0 = dataRow.createCell(columnNum++);
1424 - dataCell0.setCellValue(mealDetail.getMealName() != null ? mealDetail.getMealName() : "");
1425 - dataCell0.setCellStyle(dataStyle);
1426 -
1427 - Cell dataCell1 = dataRow.createCell(columnNum++);
1428 - dataCell1.setCellValue(mealDetail.getRoomNo() != null ? mealDetail.getRoomNo() : "");
1429 - dataCell1.setCellStyle(dataStyle);
1430 -
1431 - Cell dataCell2 = dataRow.createCell(columnNum++);
1432 - dataCell2.setCellValue(mealDetail.getCustomerName() != null ? mealDetail.getCustomerName() : "");
1433 - dataCell2.setCellStyle(dataStyle);
1434 -
1435 - Cell dataCell3 = dataRow.createCell(columnNum++);
1436 - dataCell3.setCellValue(mealDetail.getDoctors() != null ? mealDetail.getDoctors() : "");
1437 - dataCell3.setCellStyle(dataStyle);
1438 -
1439 - Cell dataCell4 = dataRow.createCell(columnNum++);
1440 - dataCell4.setCellValue(mealDetail.getMenuName() != null ? mealDetail.getMenuName() : "");
1441 - dataCell4.setCellStyle(dataStyle);
1442 -
1443 - Cell dataCell5 = dataRow.createCell(columnNum++);
1444 - dataCell5.setCellValue(mealDetail.getSkuName() != null ? mealDetail.getSkuName() : "");
1445 - dataCell5.setCellStyle(dataStyle);
1446 -
1447 - Cell dataCell6 = dataRow.createCell(columnNum++);
1448 - dataCell6.setCellValue(mealDetail.getCount() != null ? mealDetail.getCount() : 0);
1449 - dataCell6.setCellStyle(dataStyle);
1450 -
1451 - Cell dataCell7 = dataRow.createCell(columnNum++);
1452 - dataCell7.setCellValue(mealDetail.getAvoids() != null ? mealDetail.getAvoids() : "");
1453 - dataCell7.setCellStyle(dataStyle);
1454 -
1455 - Cell dataCell8 = dataRow.createCell(columnNum++);
1456 - dataCell8.setCellValue(mealDetail.getRemark() != null ? mealDetail.getRemark() : "");
1457 - dataCell8.setCellStyle(dataStyle);
1458 - }
1459 - }
1460 -
1461 - // 自动调整列宽
1462 - for (int i = 0; i < 9; i++) {
1463 - sheet.autoSizeColumn(i);
1464 - }
1465 -
1466 - // 将工作簿内容写入字节数组输出流
1467 - ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1468 - workbook.write(outputStream);
1469 - workbook.close();
1470 -
1471 - return outputStream;
1472 - }
1473 -
1474 - /**
1475 - * 创建空的分餐表Excel(无数据)
1476 - */
1477 - private static ByteArrayOutputStream createEmptyExcelBySeparateMeal() {
1478 - try {
1479 - SeparateMealDataDto emptyData = SeparateMealDataDto.builder()
1480 - .mealDetails(new ArrayList<>())
1481 - .build();
1482 - return writeToExcelBySeparateMeal(emptyData);
1483 - } catch (IOException e) {
1484 - log.error("创建空分餐表Excel失败", e);
1485 - throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
1486 - }
1487 - }
1488 -
1489 } 1536 }
......
...@@ -2,6 +2,7 @@ package com.infoloop.tianting.utils; ...@@ -2,6 +2,7 @@ package com.infoloop.tianting.utils;
2 2
3 import com.fasterxml.jackson.annotation.JsonInclude; 3 import com.fasterxml.jackson.annotation.JsonInclude;
4 import com.fasterxml.jackson.core.JsonProcessingException; 4 import com.fasterxml.jackson.core.JsonProcessingException;
5 +import com.fasterxml.jackson.core.type.TypeReference;
5 import com.fasterxml.jackson.databind.DeserializationFeature; 6 import com.fasterxml.jackson.databind.DeserializationFeature;
6 import com.fasterxml.jackson.databind.JsonNode; 7 import com.fasterxml.jackson.databind.JsonNode;
7 import com.fasterxml.jackson.databind.ObjectMapper; 8 import com.fasterxml.jackson.databind.ObjectMapper;
...@@ -41,6 +42,14 @@ public class JsonUtil { ...@@ -41,6 +42,14 @@ public class JsonUtil {
41 } 42 }
42 } 43 }
43 44
45 + public static <T> T readJsonAs(final String json, final TypeReference<T> typeRef) {
46 + try {
47 + return OBJECT_MAPPER.readValue(json, typeRef);
48 + } catch (IOException e) {
49 + throw new RuntimeException(e);
50 + }
51 + }
52 +
44 public static <T> T convertValue(final Object object, final Class<T> clazz) { 53 public static <T> T convertValue(final Object object, final Class<T> clazz) {
45 return OBJECT_MAPPER.convertValue(object, clazz); 54 return OBJECT_MAPPER.convertValue(object, clazz);
46 } 55 }
......
...@@ -32,6 +32,7 @@ service ClientCustomerOrderServiceRpc { ...@@ -32,6 +32,7 @@ service ClientCustomerOrderServiceRpc {
32 32
33 // 操作记录 33 // 操作记录
34 rpc GetOrderOperationRecordsByOrderId (GetOrderOperationRecordsByOrderIdRequest) returns (GetOrderOperationRecordsByOrderIdResponse) {} 34 rpc GetOrderOperationRecordsByOrderId (GetOrderOperationRecordsByOrderIdRequest) returns (GetOrderOperationRecordsByOrderIdResponse) {}
35 + rpc GetOrderOperationRecordsByOrderIds (GetOrderOperationRecordsByOrderIdsRequest) returns (GetOrderOperationRecordsByOrderIdsResponse) {}
35 rpc BatchCreateOrderOperationRecords (BatchCreateOrderOperationRecordsRequest) returns (BatchCreateOrderOperationRecordsResponse) {} 36 rpc BatchCreateOrderOperationRecords (BatchCreateOrderOperationRecordsRequest) returns (BatchCreateOrderOperationRecordsResponse) {}
36 37
37 38
...@@ -624,6 +625,15 @@ message GetOrderOperationRecordsByOrderIdResponse { ...@@ -624,6 +625,15 @@ message GetOrderOperationRecordsByOrderIdResponse {
624 repeated OrderOperationRecord responses = 1; 625 repeated OrderOperationRecord responses = 1;
625 } 626 }
626 627
628 +message GetOrderOperationRecordsByOrderIdsRequest {
629 + int32 enterpriseId = 1;
630 + repeated int32 orderIds = 2;
631 +}
632 +
633 +message GetOrderOperationRecordsByOrderIdsResponse {
634 + repeated OrderOperationRecord responses = 1;
635 +}
636 +
627 message OrderOperationRecordCreation { 637 message OrderOperationRecordCreation {
628 int32 orderId = 1; 638 int32 orderId = 1;
629 OrderOperationType type = 2; 639 OrderOperationType type = 2;
......