zhuyifan

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

package com.infoloop.tianting.model.bo;
import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum;
import lombok.Data;
@Data
public class OrderDetailBO {
private int id;
public int skuId;
private String skuName;
private Integer price;
private int count;
private String adjustSkuRemark;
private ServeStatusEnum serveStatus;
}
......@@ -520,6 +520,7 @@ public class OrderDbDTO {
private Integer count;
private String adjustSkuRemark;
private String serveStatus;
private Integer price;
}
......
......@@ -103,6 +103,8 @@ public class SettlementDTO {
private String remark;
private String avoidRemark;
private String onlinePay;
private String operationType;
private String transactionId;
}
@Data
......
......@@ -22,6 +22,8 @@ import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderBy
import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByIdsRpcRequest;
import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByOrderIdsRpcRequest;
import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrdersByCustomerIdRpcRequest;
import com.infoloop.tianting.clientcustomerorderservice.GetOrderOperationRecordsByOrderIdsRequest;
import com.infoloop.tianting.clientcustomerorderservice.GetOrderOperationRecordsByOrderIdsResponse;
import com.infoloop.tianting.clientcustomerorderservice.MealDetail;
import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum;
import com.infoloop.tianting.clientcustomerorderservice.OrderOperationRecordCreation;
......@@ -396,7 +398,7 @@ public class OrderServiceRpcClient {
.updateSource(d.getUpdateSource().getNumber())
.updatedAt(DateUtil.formatDate(d.getUpdatedAt()))
.updatedBy(d.getUpdatedBy())
.build()).collect(Collectors.toList());
.build()).toList();
// 替换菜品的操作记录
List<SingleOperationDto> operations = new ArrayList<>();
for (OrderDetailDto originalDetail : originalOrderDetails) {
......@@ -422,6 +424,7 @@ public class OrderServiceRpcClient {
.count(newDetail.get().getCount())
.adjustSkuRemark(newDetail.get().getAdjustSkuRemark())
.serveStatus(newDetail.get().getServeStatus().name())
.price(newDetail.get().getPrice())
.build();
newDetailStr = JsonUtil.writeAsJson(List.of(newOrderDetailOperation));
}
......@@ -432,6 +435,7 @@ public class OrderServiceRpcClient {
.count(originalDetail.getCount())
.adjustSkuRemark(originalDetail.getAdjustSkuRemark())
.serveStatus(originalDetail.getServeStatus().name())
.price(originalDetail.getPrice())
.build();
originalDetailStr = JsonUtil.writeAsJson(List.of(originalOrderDetailOperation));
final var operation = SingleOperationDto.builder()
......@@ -480,7 +484,6 @@ public class OrderServiceRpcClient {
.setCreationSource(batchOperationDto.getCreationSource())
.build();
return orderServiceRpcBlockingStub.batchCreateOrderOperationRecords(request);
}
public QueryClientCustomerOrdersByPaginationRpcResponse queryClientCustomerOrdersByPagination(QueryOrderByPaginationDto queryOrderDto) {
......@@ -498,6 +501,14 @@ public class OrderServiceRpcClient {
return orderServiceRpcBlockingStub.queryClientCustomerOrdersByPagination(request);
}
public GetOrderOperationRecordsByOrderIdsResponse getOrderOperationRecordsByOrderIds(int enterpriseId, List<Integer> orderIds) {
final var request = GetOrderOperationRecordsByOrderIdsRequest.newBuilder()
.setEnterpriseId(enterpriseId)
.addAllOrderIds(orderIds)
.build();
return orderServiceRpcBlockingStub.getOrderOperationRecordsByOrderIds(request);
}
public QueryClientCustomerOrdersByConditionRpcResponse queryClientCustomerOrdersByCondition(OrderDbDTO.QueryOrderDto queryOrderDto) {
final var request = QueryClientCustomerOrdersByConditionRpcRequest.newBuilder()
.setShouldFilterStatus(true)
......
......@@ -2,8 +2,11 @@ package com.infoloop.tianting.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.infoloop.tianting.SingleDishSkuByIdsRpcResponse;
import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum;
import com.infoloop.tianting.clientcustomerorderservice.OrderOperationRecord;
import com.infoloop.tianting.clientcustomerorderservice.OrderOperationType;
import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum;
import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum;
import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum;
......@@ -17,6 +20,7 @@ import com.infoloop.tianting.exception.ClientEndExceptions.BusinessException;
import com.infoloop.tianting.exception.ErrorCodeEnum;
import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse;
import com.infoloop.tianting.menuservice.SingleMenuRpcResponse;
import com.infoloop.tianting.model.bo.OrderDetailBO;
import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto;
import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderDto;
import com.infoloop.tianting.model.dto.SettlementDTO;
......@@ -39,8 +43,10 @@ import com.infoloop.tianting.service.client.OrderServiceRpcClient;
import com.infoloop.tianting.service.client.SkuServiceRpcClient;
import com.infoloop.tianting.setmealscheduleservice.SingleMealRpcResponse;
import com.infoloop.tianting.utils.DateUtil;
import com.infoloop.tianting.utils.JsonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
......@@ -71,7 +77,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j
@Service
......@@ -295,6 +303,408 @@ public class SettlementServiceImpl implements SettlementService {
return dateList;
}
/**
* 按订单维度生成Excel
*/
private static ByteArrayOutputStream writeToExcelByOrder(SettlementDTO.SettlementDataByOrderDto settlementDataDto)
throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("客人结算");
// 创建表头样式(黑色边框)
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 创建数据行样式(浅灰色边框)
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
int rowNum = 0;
// 创建表头
Row titleRow = sheet.createRow(rowNum++);
int columnNum = 0;
Cell cell0 = titleRow.createCell(columnNum++);
cell0.setCellValue("用餐时间");
cell0.setCellStyle(headerStyle);
Cell cell1 = titleRow.createCell(columnNum++);
cell1.setCellValue("订单号");
cell1.setCellStyle(headerStyle);
Cell cell2 = titleRow.createCell(columnNum++);
cell2.setCellValue("餐别");
cell2.setCellStyle(headerStyle);
Cell cell3 = titleRow.createCell(columnNum++);
cell3.setCellValue("房间号");
cell3.setCellStyle(headerStyle);
Cell cell4 = titleRow.createCell(columnNum++);
cell4.setCellValue("客户姓名");
cell4.setCellStyle(headerStyle);
Cell cell5 = titleRow.createCell(columnNum++);
cell5.setCellValue("客户腕带号");
cell5.setCellStyle(headerStyle);
Cell cell6 = titleRow.createCell(columnNum++);
cell6.setCellValue("忌口信息");
cell6.setCellStyle(headerStyle);
Cell cell7 = titleRow.createCell(columnNum++);
cell7.setCellValue("医嘱信息");
cell7.setCellStyle(headerStyle);
Cell cell8 = titleRow.createCell(columnNum++);
cell8.setCellValue("餐单名称");
cell8.setCellStyle(headerStyle);
Cell cell9 = titleRow.createCell(columnNum++);
cell9.setCellValue("菜品名称");
cell9.setCellStyle(headerStyle);
Cell cell10 = titleRow.createCell(columnNum++);
cell10.setCellValue("菜品份数");
cell10.setCellStyle(headerStyle);
Cell cell11 = titleRow.createCell(columnNum++);
cell11.setCellValue("菜品单价");
cell11.setCellStyle(headerStyle);
Cell cell12 = titleRow.createCell(columnNum++);
cell12.setCellValue("菜品金额");
cell12.setCellStyle(headerStyle);
Cell cell13 = titleRow.createCell(columnNum++);
cell13.setCellValue("菜品状态");
cell13.setCellStyle(headerStyle);
Cell cell14 = titleRow.createCell(columnNum++);
cell14.setCellValue("交易码");
cell14.setCellStyle(headerStyle);
Cell cell15 = titleRow.createCell(columnNum++);
cell15.setCellValue("备注");
cell15.setCellStyle(headerStyle);
Cell cell16 = titleRow.createCell(columnNum++);
cell16.setCellValue("支付方式");
cell16.setCellStyle(headerStyle);
// 填充数据
final var classifyOrders = settlementDataDto.getClassifyOrders();
if (classifyOrders != null) {
for (SettlementDTO.SettlementOrderDetail orderDetail : classifyOrders) {
Row dataRow = sheet.createRow(rowNum++);
columnNum = 0;
Cell dataCell0 = dataRow.createCell(columnNum++);
dataCell0.setCellValue(orderDetail.getMealTime() != null ? orderDetail.getMealTime() : "");
dataCell0.setCellStyle(dataStyle);
Cell dataCell1 = dataRow.createCell(columnNum++);
dataCell1.setCellValue(orderDetail.getCode() != null ? orderDetail.getCode() : "");
dataCell1.setCellStyle(dataStyle);
Cell dataCell2 = dataRow.createCell(columnNum++);
dataCell2.setCellValue(orderDetail.getMealName() != null ? orderDetail.getMealName() : "");
dataCell2.setCellStyle(dataStyle);
Cell dataCell3 = dataRow.createCell(columnNum++);
dataCell3.setCellValue(orderDetail.getRoomNo() != null ? orderDetail.getRoomNo() : "");
dataCell3.setCellStyle(dataStyle);
Cell dataCell4 = dataRow.createCell(columnNum++);
dataCell4.setCellValue(orderDetail.getCustomerName() != null ? orderDetail.getCustomerName() : "");
dataCell4.setCellStyle(dataStyle);
Cell dataCell5 = dataRow.createCell(columnNum++);
dataCell5.setCellValue(orderDetail.getHISCustomerNo() != null ? orderDetail.getHISCustomerNo() : "");
dataCell5.setCellStyle(dataStyle);
// 忌口列表转字符串
String avoidsStr = orderDetail.getAvoids() != null ? String.join(", ", orderDetail.getAvoids()) : "";
Cell dataCell6 = dataRow.createCell(columnNum++);
dataCell6.setCellValue(avoidsStr);
dataCell6.setCellStyle(dataStyle);
// 医嘱列表转字符串
String doctorsStr = orderDetail.getDoctors() != null ? String.join(", ", orderDetail.getDoctors()) : "";
Cell dataCell7 = dataRow.createCell(columnNum++);
dataCell7.setCellValue(doctorsStr);
dataCell7.setCellStyle(dataStyle);
Cell dataCell8 = dataRow.createCell(columnNum++);
dataCell8.setCellValue(orderDetail.getMenuName() != null ? orderDetail.getMenuName() : "");
dataCell8.setCellStyle(dataStyle);
Cell dataCell9 = dataRow.createCell(columnNum++);
dataCell9.setCellValue(orderDetail.getSkuName() != null ? orderDetail.getSkuName() : "");
dataCell9.setCellStyle(dataStyle);
Cell dataCell10 = dataRow.createCell(columnNum++);
dataCell10.setCellValue(orderDetail.getCount() != null ? orderDetail.getCount() : 0);
dataCell10.setCellStyle(dataStyle);
// 价格
Cell dataCell11 = dataRow.createCell(columnNum++);
if (orderDetail.getPrice() != null) {
dataCell11.setCellValue(orderDetail.getPrice().doubleValue());
} else {
dataCell11.setCellValue(0.0);
}
dataCell11.setCellStyle(dataStyle);
// 总价
Cell dataCell12 = dataRow.createCell(columnNum++);
if (orderDetail.getTotalPrice() != null) {
dataCell12.setCellValue(orderDetail.getTotalPrice().doubleValue());
} else {
dataCell12.setCellValue(0.0);
}
dataCell12.setCellStyle(dataStyle);
// 状态
Cell dataCell13 = dataRow.createCell(columnNum++);
dataCell13.setCellValue(orderDetail.getOperationType());
dataCell13.setCellStyle(dataStyle);
Cell dataCell14 = dataRow.createCell(columnNum++);
dataCell14.setCellValue(orderDetail.getTransactionId() != null ? orderDetail.getTransactionId() : "");
dataCell14.setCellStyle(dataStyle);
// 合并备注和忌口备注,用分号分割,备注在前
String remark = orderDetail.getRemark() != null ? orderDetail.getRemark() : "";
String avoidRemark = orderDetail.getAvoidRemark() != null ? orderDetail.getAvoidRemark() : "";
String combinedRemark = "";
if (!remark.isEmpty() && !avoidRemark.isEmpty()) {
combinedRemark = remark + ";" + avoidRemark;
} else if (!remark.isEmpty()) {
combinedRemark = remark;
} else if (!avoidRemark.isEmpty()) {
combinedRemark = avoidRemark;
}
Cell dataCell15 = dataRow.createCell(columnNum++);
dataCell15.setCellValue(combinedRemark);
dataCell15.setCellStyle(dataStyle);
Cell dataCell16 = dataRow.createCell(columnNum++);
dataCell16.setCellValue(orderDetail.getOnlinePay() != null ? orderDetail.getOnlinePay() : "");
dataCell16.setCellStyle(dataStyle);
}
}
// 自动调整列宽
for (int i = 0; i < 17; i++) {
sheet.autoSizeColumn(i);
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
return outputStream;
}
/**
* 生成分餐表Excel
*/
private static ByteArrayOutputStream writeToExcelBySeparateMeal(SeparateMealDataDto separateMealDataDto)
throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("分餐表");
// 创建标题样式(合并单元格标题)
CellStyle titleStyle = workbook.createCellStyle();
titleStyle.setAlignment(HorizontalAlignment.CENTER);
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
titleStyle.setBorderTop(BorderStyle.THIN);
titleStyle.setBorderBottom(BorderStyle.THIN);
titleStyle.setBorderLeft(BorderStyle.THIN);
titleStyle.setBorderRight(BorderStyle.THIN);
titleStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
Font titleFont = workbook.createFont();
titleFont.setBold(true);
titleFont.setFontHeightInPoints((short) 16);
titleStyle.setFont(titleFont);
// 创建表头样式(黑色边框)
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 创建数据行样式(浅灰色边框)
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
int rowNum = 0;
// 第一行:创建合并单元格标题
Row mainTitleRow = sheet.createRow(rowNum++);
Cell mainTitleCell = mainTitleRow.createCell(0);
mainTitleCell.setCellValue("住院客户分餐表");
mainTitleCell.setCellStyle(titleStyle);
// 合并第一行的8列
CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 8);
sheet.addMergedRegion(titleRegion);
// 为合并区域设置边框
RegionUtil.setBorderTop(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderBottom(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderLeft(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderRight(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setTopBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setBottomBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setLeftBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setRightBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
// 第二行:创建表头
Row titleRow = sheet.createRow(rowNum++);
int columnNum = 0;
Cell cell0 = titleRow.createCell(columnNum++);
cell0.setCellValue("餐别");
cell0.setCellStyle(headerStyle);
Cell cell1 = titleRow.createCell(columnNum++);
cell1.setCellValue("房间号");
cell1.setCellStyle(headerStyle);
Cell cell2 = titleRow.createCell(columnNum++);
cell2.setCellValue("客户姓名");
cell2.setCellStyle(headerStyle);
Cell cell3 = titleRow.createCell(columnNum++);
cell3.setCellValue("医嘱信息");
cell3.setCellStyle(headerStyle);
Cell cell4 = titleRow.createCell(columnNum++);
cell4.setCellValue("餐单名称");
cell4.setCellStyle(headerStyle);
Cell cell5 = titleRow.createCell(columnNum++);
cell5.setCellValue("菜品名称");
cell5.setCellStyle(headerStyle);
Cell cell6 = titleRow.createCell(columnNum++);
cell6.setCellValue("菜品数量");
cell6.setCellStyle(headerStyle);
Cell cell7 = titleRow.createCell(columnNum++);
cell7.setCellValue("忌口信息");
cell7.setCellStyle(headerStyle);
Cell cell8 = titleRow.createCell(columnNum++);
cell8.setCellValue("备注");
cell8.setCellStyle(headerStyle);
// 填充数据
final var mealDetails = separateMealDataDto.getMealDetails();
if (mealDetails != null) {
for (SeparateMealDetail mealDetail : mealDetails) {
Row dataRow = sheet.createRow(rowNum++);
columnNum = 0;
Cell dataCell0 = dataRow.createCell(columnNum++);
dataCell0.setCellValue(mealDetail.getMealName() != null ? mealDetail.getMealName() : "");
dataCell0.setCellStyle(dataStyle);
Cell dataCell1 = dataRow.createCell(columnNum++);
dataCell1.setCellValue(mealDetail.getRoomNo() != null ? mealDetail.getRoomNo() : "");
dataCell1.setCellStyle(dataStyle);
Cell dataCell2 = dataRow.createCell(columnNum++);
dataCell2.setCellValue(mealDetail.getCustomerName() != null ? mealDetail.getCustomerName() : "");
dataCell2.setCellStyle(dataStyle);
Cell dataCell3 = dataRow.createCell(columnNum++);
dataCell3.setCellValue(mealDetail.getDoctors() != null ? mealDetail.getDoctors() : "");
dataCell3.setCellStyle(dataStyle);
Cell dataCell4 = dataRow.createCell(columnNum++);
dataCell4.setCellValue(mealDetail.getMenuName() != null ? mealDetail.getMenuName() : "");
dataCell4.setCellStyle(dataStyle);
Cell dataCell5 = dataRow.createCell(columnNum++);
dataCell5.setCellValue(mealDetail.getSkuName() != null ? mealDetail.getSkuName() : "");
dataCell5.setCellStyle(dataStyle);
Cell dataCell6 = dataRow.createCell(columnNum++);
dataCell6.setCellValue(mealDetail.getCount() != null ? mealDetail.getCount() : 0);
dataCell6.setCellStyle(dataStyle);
Cell dataCell7 = dataRow.createCell(columnNum++);
dataCell7.setCellValue(mealDetail.getAvoids() != null ? mealDetail.getAvoids() : "");
dataCell7.setCellStyle(dataStyle);
Cell dataCell8 = dataRow.createCell(columnNum++);
dataCell8.setCellValue(mealDetail.getRemark() != null ? mealDetail.getRemark() : "");
dataCell8.setCellStyle(dataStyle);
}
}
// 自动调整列宽
for (int i = 0; i < 9; i++) {
sheet.autoSizeColumn(i);
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
return outputStream;
}
/**
* 创建空的分餐表Excel(无数据)
*/
private static ByteArrayOutputStream createEmptyExcelBySeparateMeal() {
try {
SeparateMealDataDto emptyData = SeparateMealDataDto.builder()
.mealDetails(new ArrayList<>())
.build();
return writeToExcelBySeparateMeal(emptyData);
} catch (IOException e) {
log.error("创建空分餐表Excel失败", e);
throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
}
}
@Override
public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) {
if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_SKU)) {
......@@ -369,13 +779,11 @@ public class SettlementServiceImpl implements SettlementService {
.collect(Collectors.toList());
if (orderIds.isEmpty()) {
log.warn("筛选后无有效订单,enterpriseId: {}", enterpriseId);
return createEmptyExcelByOrder();
}
// 构建订单映射
final var orderMap = orderList.stream()
.filter(o -> o.getId() != 0)
final var orderMap = orderList.stream().filter(o -> o.getId() != 0)
.collect(Collectors.toMap(SingleClientCustomerOrderRpcResponse::getId, o -> o, (o1, o2) -> o1));
// 查询订单详情
......@@ -384,86 +792,60 @@ public class SettlementServiceImpl implements SettlementService {
log.warn("未查询到订单详情数据,orderIds: {}", orderIds);
return createEmptyExcelByOrder();
}
// 订单详情按订单ID分组
final var orderDetailGroupByOrderId = orderDetailList.stream()
.filter(Objects::nonNull)
.filter(d -> !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT))
.collect(Collectors.groupingBy(SingleClientCustomerOrderDetailRpcResponse::getOrderId));
// 获取SKU数据
List<Integer> skuIds = orderDetailList.stream()
.filter(Objects::nonNull)
.filter(d -> !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT))
.map(SingleClientCustomerOrderDetailRpcResponse::getSkuId)
final var orderDetailGroupByOrderId = orderDetailList.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(SingleClientCustomerOrderDetailRpcResponse::getOrderId));
final var orderOperationRecordsByOrderIds = orderServiceRpcClient.getOrderOperationRecordsByOrderIds(LoginContextHolder.getEnterpriseId(), orderIds).getResponsesList();
// 订单操作记录按订单ID分组
final var orderOperationRecordByOrderId = orderOperationRecordsByOrderIds.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(OrderOperationRecord::getOrderId));
List<Integer> skuIds = Stream.concat(
orderOperationRecordsByOrderIds.stream()
.filter(e -> StringUtils.isNoneBlank(e.getOriginalOrderDetailJson()))
.flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {}).stream())
.map(OrderDetailBO::getSkuId),
orderDetailList.stream()
.filter(Objects::nonNull)
.map(SingleClientCustomerOrderDetailRpcResponse::getSkuId)
)
.distinct()
.collect(Collectors.toList());
final var skuResponse = skuServiceRpcClient.getDishSkusByIds(skuIds);
final List<SingleDishSkuByIdsRpcResponse> skus = skuResponse != null ? skuResponse.getResponseList() : new ArrayList<>();
final var skuMap = skus.stream()
.filter(Objects::nonNull)
.filter(s -> s.getId() != 0)
.collect(Collectors.toMap(SingleDishSkuByIdsRpcResponse::getId, s -> s, (s1, s2) -> s1));
final List<SingleDishSkuByIdsRpcResponse> skus = skuResponse.getResponseList();
final var skuMap = skus.stream().collect(Collectors.toMap(SingleDishSkuByIdsRpcResponse::getId, s -> s, (s1, s2) -> s1));
// 获取餐别数据
final var mealResponse = mealServiceRpcClient.getAllMeals(enterpriseId);
final List<SingleMealRpcResponse> meals = mealResponse != null ? mealResponse.getResponsesList() : new ArrayList<>();
final var mealMap = meals.stream()
.filter(Objects::nonNull)
.filter(m -> m.getId() != 0)
.collect(Collectors.toMap(SingleMealRpcResponse::getId, m -> m, (m1, m2) -> m1));
final var mealMap = meals.stream().collect(Collectors.toMap(SingleMealRpcResponse::getId, m -> m, (m1, m2) -> m1));
// 获取菜单数据
List<Integer> menuIds = orderList.stream()
.filter(Objects::nonNull)
.map(SingleClientCustomerOrderRpcResponse::getMenuId)
.filter(id -> id != 0)
.distinct()
.collect(Collectors.toList());
List<Integer> menuIds = orderList.stream().map(SingleClientCustomerOrderRpcResponse::getMenuId).distinct().collect(Collectors.toList());
final var menuResponse = menuServiceRpcClient.getMenusByIds(enterpriseId, menuIds);
final List<SingleMenuRpcResponse> menuList = menuResponse != null ? menuResponse.getResponsesList() : new ArrayList<>();
final var menuMap = menuList.stream()
.filter(Objects::nonNull)
.filter(m -> m.getId() != 0)
.collect(Collectors.toMap(SingleMenuRpcResponse::getId, m -> m, (m1, m2) -> m1));
final var menuMap = menuList.stream().collect(Collectors.toMap(SingleMenuRpcResponse::getId, m -> m, (m1, m2) -> m1));
// 获取菜单详情数据
final var menuDetailResponse = menuServiceRpcClient.queryMenuDetailsByMenuIds(enterpriseId, menuIds);
final List<SingleMenuDetailRpcResponse> menuDetailList = menuDetailResponse != null ? menuDetailResponse.getResponsesList() : new ArrayList<>();
final var menuDetailMap = menuDetailList.stream()
.filter(Objects::nonNull)
.filter(m -> m.getId() != 0)
.collect(Collectors.toMap(SingleMenuDetailRpcResponse::getId, m -> m, (m1, m2) -> m1));
final List<SingleMenuDetailRpcResponse> menuDetailList = menuDetailResponse.getResponsesList();
final var menuDetailMap = menuDetailList.stream().collect(Collectors.toMap(SingleMenuDetailRpcResponse::getId, m -> m, (m1, m2) -> m1));
// 获取客户数据
List<Integer> customerIds = orderList.stream()
.filter(Objects::nonNull)
.map(SingleClientCustomerOrderRpcResponse::getCustomerId)
.filter(id -> id != 0)
.distinct()
.collect(Collectors.toList());
final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds);
final List<SingleClientCustomerRpcResponse> customers = customerResponse != null ? customerResponse.getResponsesList() : new ArrayList<>();
final var customerMap = customers.stream()
.filter(Objects::nonNull)
.filter(c -> c.getId() != 0)
.collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1));
List<Integer> customerIds = orderList.stream().map(SingleClientCustomerOrderRpcResponse::getCustomerId).distinct().collect(Collectors.toList());
final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds);
final List<SingleClientCustomerRpcResponse> customers = customerResponse.getResponsesList();
final var customerMap = customers.stream().collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1));
// 构建结算订单明细
final var classifyOrders = new ArrayList<SettlementDTO.SettlementOrderDetail>();
for (Integer orderId : orderIds) {
final var orderDetails = orderDetailGroupByOrderId.getOrDefault(orderId, Collections.emptyList());
final var order = orderMap.get(orderId);
// 订单为空则跳过
if (order == null) {
log.warn("订单不存在,orderId: {}", orderId);
continue;
}
// 获取菜单信息
final var menu = menuMap.get(order.getMenuId());
final String menuName = menu != null ? menu.getName() : "";
......@@ -473,52 +855,63 @@ public class SettlementServiceImpl implements SettlementService {
final String customerName = customer != null ? customer.getName() : "";
final String hisCustomerNo = customer != null ? customer.getHISCustomerNo() : "";
// 处理每个订单详情
for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) {
if (orderDetail == null) {
continue;
}
final var orderOperationRecords = orderOperationRecordByOrderId.get(orderId);
// 安全获取餐别名称
String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap);
Map<Integer, OrderDetailBO> addOriginalDetailMap = orderOperationRecords.stream()
.filter(e -> e.getType() == OrderOperationType.ADD_DISHES)
.flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {
}).stream())
.collect(Collectors.toMap(OrderDetailBO::getId, Function.identity(), (a, b) -> a));
// 安全获取SKU名称
String skuName = getSkuNameSafely(orderDetail, skuMap);
Map<Integer, OrderDetailBO> replaceOriginalDetailMap = orderOperationRecords.stream()
.filter(e -> e.getType() == OrderOperationType.REPLACE_DISHES)
.flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {
}).stream())
.collect(Collectors.toMap(OrderDetailBO::getId, Function.identity(), (a, b) -> a));
// 安全获取房间号
String roomNo = getRoomNoSafely(order);
for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) {
// 1. 先处理加餐
if (addOriginalDetailMap.containsKey(orderDetail.getId())
&& addOriginalDetailMap.get(orderDetail.getId()).getCount() != orderDetail.getCount()) {
SettlementDTO.SettlementOrderDetail addRecord = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "加餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(addRecord);
}
// 安全获取忌口和医嘱
List<String> avoids = getAvoidsSafely(order);
List<String> doctors = getDoctorsSafely(order);
// 2. 再处理换菜
if (replaceOriginalDetailMap.containsKey(orderDetail.getId())
&& !Objects.equals(replaceOriginalDetailMap.get(orderDetail.getId()).getSkuId(), orderDetail.getSkuId())) {
final var orderDetailBO = replaceOriginalDetailMap.get(orderDetail.getId());
SettlementDTO.SettlementOrderDetail beforeChange = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetailBO.getSkuId(), orderDetailBO.getCount(), orderDetailBO.getPrice(), "换菜前", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(beforeChange);
SettlementDTO.SettlementOrderDetail afterChange = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "换菜后", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(afterChange);
}
// 安全获取在线支付描述
String onlinePayDesc = getOnlinePayDescSafely(order);
// 3. 判断已退款
if (orderDetail.getServeStatus() == ServeStatusEnum.SERVE_REJECT) {
SettlementDTO.SettlementOrderDetail refundRecord = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "已退款", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(refundRecord);
}
// 构建订单详情
order.getOrderCode();
order.getRemark();
order.getAvoidRemark();
SettlementDTO.SettlementOrderDetail settlementOrderDetail = SettlementDTO.SettlementOrderDetail.builder()
.mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "")
.code(order.getOrderCode())
.mealName(mealName)
.roomNo(roomNo)
.customerName(customerName)
.HISCustomerNo(hisCustomerNo)
.avoids(avoids)
.doctors(doctors)
.menuName(menuName)
.skuName(skuName)
.count(orderDetail.getCount() != 0 ? orderDetail.getCount() : 0)
.price(calculatePrice(orderDetail.getPrice()))
.totalPrice(calculateTotalPrice(orderDetail.getPrice(), orderDetail.getCount()))
.remark(order.getRemark())
.avoidRemark(order.getAvoidRemark())
.onlinePay(onlinePayDesc)
.build();
classifyOrders.add(settlementOrderDetail);
// 4. 如果既不是加餐,也不是换菜,也不是退款,才记录“订餐”
boolean isNormal = !(addOriginalDetailMap.containsKey(orderDetail.getId())
&& addOriginalDetailMap.get(orderDetail.getId()).getCount() != orderDetail.getCount())
&& !(replaceOriginalDetailMap.containsKey(orderDetail.getId())
&& !Objects.equals(replaceOriginalDetailMap.get(orderDetail.getId()).getSkuId(), orderDetail.getSkuId()))
&& orderDetail.getServeStatus() != ServeStatusEnum.SERVE_REJECT;
if (isNormal) {
SettlementDTO.SettlementOrderDetail normalRecord = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "订餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(normalRecord);
}
}
}
// 构建结算数据
......@@ -535,17 +928,57 @@ public class SettlementServiceImpl implements SettlementService {
}
}
private SettlementDTO.SettlementOrderDetail buildSettlementOrderDetail(SingleClientCustomerOrderRpcResponse order,
int menuDetailId,
int skuId,
int count,
Integer price,
String operationType,
String menuName,
String customerName,
String hisCustomerNo,
Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
Map<Integer, SingleMealRpcResponse> mealMap,
Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
String mealName = getMealNameSafely(menuDetailId, menuDetailMap, mealMap);
String skuName = getSkuNameSafely(skuId, skuMap);
String roomNo = getRoomNoSafely(order);
List<String> avoids = getAvoidsSafely(order);
List<String> doctors = getDoctorsSafely(order);
String onlinePayDesc = getOnlinePayDescSafely(order);
return SettlementDTO.SettlementOrderDetail.builder()
.mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "")
.code(order.getOrderCode())
.mealName(mealName)
.roomNo(roomNo)
.customerName(customerName)
.HISCustomerNo(hisCustomerNo)
.avoids(avoids)
.doctors(doctors)
.menuName(menuName)
.skuName(skuName)
.count(count)
.price(calculatePrice(price))
.totalPrice(calculateTotalPrice(price, count))
.remark(order.getRemark())
.avoidRemark(order.getAvoidRemark())
.onlinePay(onlinePayDesc)
.operationType(operationType)
.transactionId(order.getTransactionId())
.build();
}
/**
* 安全获取餐别名称
*/
private String getMealNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail,
Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
Map<Integer, SingleMealRpcResponse> mealMap) {
if (orderDetail == null || orderDetail.getMenuDetailId() == 0) {
private String getMealNameSafely(int menuDetailId,
Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
Map<Integer, SingleMealRpcResponse> mealMap) {
if (menuDetailId == 0) {
return "";
}
final var menuDetail = menuDetailMap.get(orderDetail.getMenuDetailId());
final var menuDetail = menuDetailMap.get(menuDetailId);
if (menuDetail == null || menuDetail.getMealId() == 0) {
return "";
}
......@@ -557,13 +990,12 @@ public class SettlementServiceImpl implements SettlementService {
/**
* 安全获取SKU名称
*/
private String getSkuNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail,
Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
if (orderDetail == null || orderDetail.getSkuId() == 0) {
private String getSkuNameSafely(int skuId,
Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
if (skuId == 0) {
return "";
}
final var sku = skuMap.get(orderDetail.getSkuId());
final var sku = skuMap.get(skuId);
return sku != null ? sku.getName() : "";
}
......@@ -598,268 +1030,65 @@ public class SettlementServiceImpl implements SettlementService {
* 安全获取医嘱列表
*/
private List<String> getDoctorsSafely(SingleClientCustomerOrderRpcResponse order) {
if (order == null) {
return Collections.emptyList();
}
return order.getCustomerNoticeJson().getDoctorsList();
}
/**
* 安全获取在线支付描述
*/
private String getOnlinePayDescSafely(SingleClientCustomerOrderRpcResponse order) {
if (order == null) {
return "";
}
try {
String desc = BaseProtoDescEnum.getDescByProtoEnum(order.getOnlinePay(), OnlinePayDescEnum.class);
return desc != null ? desc : "";
} catch (Exception e) {
log.warn("获取在线支付描述失败,orderId: {}", order.getId(), e);
return "";
}
}
/**
* 计算单价
*/
private BigDecimal calculatePrice(Integer price) {
if (price == null) {
return BigDecimal.ZERO;
}
return new BigDecimal(price).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
/**
* 计算总价
*/
private BigDecimal calculateTotalPrice(Integer price, Integer count) {
if (price == null || count == null) {
return BigDecimal.ZERO;
}
return new BigDecimal(price)
.multiply(new BigDecimal(count))
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
/**
* 创建空的订单Excel
*/
private ByteArrayOutputStream createEmptyExcelByOrder() {
try {
final var emptyData = SettlementDTO.SettlementDataByOrderDto.builder()
.classifyOrders(Collections.emptyList())
.build();
return writeToExcelByOrder(emptyData);
} catch (IOException e) {
log.error("创建空Excel失败", e);
throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
}
}
/**
* 按订单维度生成Excel
*/
private static ByteArrayOutputStream writeToExcelByOrder(SettlementDTO.SettlementDataByOrderDto settlementDataDto)
throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("客人结算");
// 创建表头样式(黑色边框)
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 创建数据行样式(浅灰色边框)
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
int rowNum = 0;
// 创建表头
Row titleRow = sheet.createRow(rowNum++);
int columnNum = 0;
Cell cell0 = titleRow.createCell(columnNum++);
cell0.setCellValue("用餐时间");
cell0.setCellStyle(headerStyle);
Cell cell1 = titleRow.createCell(columnNum++);
cell1.setCellValue("订单号");
cell1.setCellStyle(headerStyle);
Cell cell2 = titleRow.createCell(columnNum++);
cell2.setCellValue("餐别");
cell2.setCellStyle(headerStyle);
Cell cell3 = titleRow.createCell(columnNum++);
cell3.setCellValue("房间号");
cell3.setCellStyle(headerStyle);
Cell cell4 = titleRow.createCell(columnNum++);
cell4.setCellValue("客户姓名");
cell4.setCellStyle(headerStyle);
Cell cell5 = titleRow.createCell(columnNum++);
cell5.setCellValue("客户腕带号");
cell5.setCellStyle(headerStyle);
Cell cell6 = titleRow.createCell(columnNum++);
cell6.setCellValue("忌口信息");
cell6.setCellStyle(headerStyle);
Cell cell7 = titleRow.createCell(columnNum++);
cell7.setCellValue("医嘱信息");
cell7.setCellStyle(headerStyle);
Cell cell8 = titleRow.createCell(columnNum++);
cell8.setCellValue("餐单名称");
cell8.setCellStyle(headerStyle);
Cell cell9 = titleRow.createCell(columnNum++);
cell9.setCellValue("菜品名称");
cell9.setCellStyle(headerStyle);
Cell cell10 = titleRow.createCell(columnNum++);
cell10.setCellValue("菜品份数");
cell10.setCellStyle(headerStyle);
Cell cell11 = titleRow.createCell(columnNum++);
cell11.setCellValue("菜品单价");
cell11.setCellStyle(headerStyle);
Cell cell12 = titleRow.createCell(columnNum++);
cell12.setCellValue("菜品金额");
cell12.setCellStyle(headerStyle);
Cell cell13 = titleRow.createCell(columnNum++);
cell13.setCellValue("备注");
cell13.setCellStyle(headerStyle);
Cell cell14 = titleRow.createCell(columnNum++);
cell14.setCellValue("支付方式");
cell14.setCellStyle(headerStyle);
// 填充数据
final var classifyOrders = settlementDataDto.getClassifyOrders();
if (classifyOrders != null) {
for (SettlementDTO.SettlementOrderDetail orderDetail : classifyOrders) {
Row dataRow = sheet.createRow(rowNum++);
columnNum = 0;
Cell dataCell0 = dataRow.createCell(columnNum++);
dataCell0.setCellValue(orderDetail.getMealTime() != null ? orderDetail.getMealTime() : "");
dataCell0.setCellStyle(dataStyle);
Cell dataCell1 = dataRow.createCell(columnNum++);
dataCell1.setCellValue(orderDetail.getCode() != null ? orderDetail.getCode() : "");
dataCell1.setCellStyle(dataStyle);
Cell dataCell2 = dataRow.createCell(columnNum++);
dataCell2.setCellValue(orderDetail.getMealName() != null ? orderDetail.getMealName() : "");
dataCell2.setCellStyle(dataStyle);
Cell dataCell3 = dataRow.createCell(columnNum++);
dataCell3.setCellValue(orderDetail.getRoomNo() != null ? orderDetail.getRoomNo() : "");
dataCell3.setCellStyle(dataStyle);
Cell dataCell4 = dataRow.createCell(columnNum++);
dataCell4.setCellValue(orderDetail.getCustomerName() != null ? orderDetail.getCustomerName() : "");
dataCell4.setCellStyle(dataStyle);
Cell dataCell5 = dataRow.createCell(columnNum++);
dataCell5.setCellValue(orderDetail.getHISCustomerNo() != null ? orderDetail.getHISCustomerNo() : "");
dataCell5.setCellStyle(dataStyle);
// 忌口列表转字符串
String avoidsStr = orderDetail.getAvoids() != null ? String.join(", ", orderDetail.getAvoids()) : "";
Cell dataCell6 = dataRow.createCell(columnNum++);
dataCell6.setCellValue(avoidsStr);
dataCell6.setCellStyle(dataStyle);
// 医嘱列表转字符串
String doctorsStr = orderDetail.getDoctors() != null ? String.join(", ", orderDetail.getDoctors()) : "";
Cell dataCell7 = dataRow.createCell(columnNum++);
dataCell7.setCellValue(doctorsStr);
dataCell7.setCellStyle(dataStyle);
Cell dataCell8 = dataRow.createCell(columnNum++);
dataCell8.setCellValue(orderDetail.getMenuName() != null ? orderDetail.getMenuName() : "");
dataCell8.setCellStyle(dataStyle);
Cell dataCell9 = dataRow.createCell(columnNum++);
dataCell9.setCellValue(orderDetail.getSkuName() != null ? orderDetail.getSkuName() : "");
dataCell9.setCellStyle(dataStyle);
Cell dataCell10 = dataRow.createCell(columnNum++);
dataCell10.setCellValue(orderDetail.getCount() != null ? orderDetail.getCount() : 0);
dataCell10.setCellStyle(dataStyle);
// 价格
Cell dataCell11 = dataRow.createCell(columnNum++);
if (orderDetail.getPrice() != null) {
dataCell11.setCellValue(orderDetail.getPrice().doubleValue());
} else {
dataCell11.setCellValue(0.0);
}
dataCell11.setCellStyle(dataStyle);
// 总价
Cell dataCell12 = dataRow.createCell(columnNum++);
if (orderDetail.getTotalPrice() != null) {
dataCell12.setCellValue(orderDetail.getTotalPrice().doubleValue());
} else {
dataCell12.setCellValue(0.0);
}
dataCell12.setCellStyle(dataStyle);
if (order == null) {
return Collections.emptyList();
}
// 合并备注和忌口备注,用分号分割,备注在前
String remark = orderDetail.getRemark() != null ? orderDetail.getRemark() : "";
String avoidRemark = orderDetail.getAvoidRemark() != null ? orderDetail.getAvoidRemark() : "";
String combinedRemark = "";
if (!remark.isEmpty() && !avoidRemark.isEmpty()) {
combinedRemark = remark + ";" + avoidRemark;
} else if (!remark.isEmpty()) {
combinedRemark = remark;
} else if (!avoidRemark.isEmpty()) {
combinedRemark = avoidRemark;
}
Cell dataCell13 = dataRow.createCell(columnNum++);
dataCell13.setCellValue(combinedRemark);
dataCell13.setCellStyle(dataStyle);
return order.getCustomerNoticeJson().getDoctorsList();
}
Cell dataCell14 = dataRow.createCell(columnNum++);
dataCell14.setCellValue(orderDetail.getOnlinePay() != null ? orderDetail.getOnlinePay() : "");
dataCell14.setCellStyle(dataStyle);
}
/**
* 安全获取在线支付描述
*/
private String getOnlinePayDescSafely(SingleClientCustomerOrderRpcResponse order) {
if (order == null) {
return "";
}
// 自动调整列宽
for (int i = 0; i < 15; i++) {
sheet.autoSizeColumn(i);
try {
String desc = BaseProtoDescEnum.getDescByProtoEnum(order.getOnlinePay(), OnlinePayDescEnum.class);
return desc != null ? desc : "";
} catch (Exception e) {
log.warn("获取在线支付描述失败,orderId: {}", order.getId(), e);
return "";
}
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
/**
* 计算单价
*/
private BigDecimal calculatePrice(Integer price) {
if (price == null) {
return BigDecimal.ZERO;
}
return new BigDecimal(price).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
return outputStream;
/**
* 计算总价
*/
private BigDecimal calculateTotalPrice(Integer price, Integer count) {
if (price == null || count == null) {
return BigDecimal.ZERO;
}
return new BigDecimal(price)
.multiply(new BigDecimal(count))
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
/**
* 创建空的订单Excel
*/
private ByteArrayOutputStream createEmptyExcelByOrder() {
try {
final var emptyData = SettlementDTO.SettlementDataByOrderDto.builder()
.classifyOrders(Collections.emptyList())
.build();
return writeToExcelByOrder(emptyData);
} catch (IOException e) {
log.error("创建空Excel失败", e);
throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
}
}
public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) {
......@@ -1249,10 +1478,10 @@ public class SettlementServiceImpl implements SettlementService {
}
// 安全获取餐别名称
String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap);
String mealName = getMealNameSafely(orderDetail.getMenuDetailId(), menuDetailMap, mealMap);
// 安全获取SKU名称
String skuName = getSkuNameSafely(orderDetail, skuMap);
String skuName = getSkuNameSafely(orderDetail.getSkuId(), skuMap);
// 安全获取忌口信息(列表转字符串)
List<String> avoidsList = getAvoidsSafely(order);
......@@ -1304,186 +1533,4 @@ public class SettlementServiceImpl implements SettlementService {
}
}
/**
* 生成分餐表Excel
*/
private static ByteArrayOutputStream writeToExcelBySeparateMeal(SeparateMealDataDto separateMealDataDto)
throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("分餐表");
// 创建标题样式(合并单元格标题)
CellStyle titleStyle = workbook.createCellStyle();
titleStyle.setAlignment(HorizontalAlignment.CENTER);
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
titleStyle.setBorderTop(BorderStyle.THIN);
titleStyle.setBorderBottom(BorderStyle.THIN);
titleStyle.setBorderLeft(BorderStyle.THIN);
titleStyle.setBorderRight(BorderStyle.THIN);
titleStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
Font titleFont = workbook.createFont();
titleFont.setBold(true);
titleFont.setFontHeightInPoints((short) 16);
titleStyle.setFont(titleFont);
// 创建表头样式(黑色边框)
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 创建数据行样式(浅灰色边框)
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
int rowNum = 0;
// 第一行:创建合并单元格标题
Row mainTitleRow = sheet.createRow(rowNum++);
Cell mainTitleCell = mainTitleRow.createCell(0);
mainTitleCell.setCellValue("住院客户分餐表");
mainTitleCell.setCellStyle(titleStyle);
// 合并第一行的8列
CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 8);
sheet.addMergedRegion(titleRegion);
// 为合并区域设置边框
RegionUtil.setBorderTop(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderBottom(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderLeft(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderRight(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setTopBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setBottomBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setLeftBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setRightBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
// 第二行:创建表头
Row titleRow = sheet.createRow(rowNum++);
int columnNum = 0;
Cell cell0 = titleRow.createCell(columnNum++);
cell0.setCellValue("餐别");
cell0.setCellStyle(headerStyle);
Cell cell1 = titleRow.createCell(columnNum++);
cell1.setCellValue("房间号");
cell1.setCellStyle(headerStyle);
Cell cell2 = titleRow.createCell(columnNum++);
cell2.setCellValue("客户姓名");
cell2.setCellStyle(headerStyle);
Cell cell3 = titleRow.createCell(columnNum++);
cell3.setCellValue("医嘱信息");
cell3.setCellStyle(headerStyle);
Cell cell4 = titleRow.createCell(columnNum++);
cell4.setCellValue("餐单名称");
cell4.setCellStyle(headerStyle);
Cell cell5 = titleRow.createCell(columnNum++);
cell5.setCellValue("菜品名称");
cell5.setCellStyle(headerStyle);
Cell cell6 = titleRow.createCell(columnNum++);
cell6.setCellValue("菜品数量");
cell6.setCellStyle(headerStyle);
Cell cell7 = titleRow.createCell(columnNum++);
cell7.setCellValue("忌口信息");
cell7.setCellStyle(headerStyle);
Cell cell8 = titleRow.createCell(columnNum++);
cell8.setCellValue("备注");
cell8.setCellStyle(headerStyle);
// 填充数据
final var mealDetails = separateMealDataDto.getMealDetails();
if (mealDetails != null) {
for (SeparateMealDetail mealDetail : mealDetails) {
Row dataRow = sheet.createRow(rowNum++);
columnNum = 0;
Cell dataCell0 = dataRow.createCell(columnNum++);
dataCell0.setCellValue(mealDetail.getMealName() != null ? mealDetail.getMealName() : "");
dataCell0.setCellStyle(dataStyle);
Cell dataCell1 = dataRow.createCell(columnNum++);
dataCell1.setCellValue(mealDetail.getRoomNo() != null ? mealDetail.getRoomNo() : "");
dataCell1.setCellStyle(dataStyle);
Cell dataCell2 = dataRow.createCell(columnNum++);
dataCell2.setCellValue(mealDetail.getCustomerName() != null ? mealDetail.getCustomerName() : "");
dataCell2.setCellStyle(dataStyle);
Cell dataCell3 = dataRow.createCell(columnNum++);
dataCell3.setCellValue(mealDetail.getDoctors() != null ? mealDetail.getDoctors() : "");
dataCell3.setCellStyle(dataStyle);
Cell dataCell4 = dataRow.createCell(columnNum++);
dataCell4.setCellValue(mealDetail.getMenuName() != null ? mealDetail.getMenuName() : "");
dataCell4.setCellStyle(dataStyle);
Cell dataCell5 = dataRow.createCell(columnNum++);
dataCell5.setCellValue(mealDetail.getSkuName() != null ? mealDetail.getSkuName() : "");
dataCell5.setCellStyle(dataStyle);
Cell dataCell6 = dataRow.createCell(columnNum++);
dataCell6.setCellValue(mealDetail.getCount() != null ? mealDetail.getCount() : 0);
dataCell6.setCellStyle(dataStyle);
Cell dataCell7 = dataRow.createCell(columnNum++);
dataCell7.setCellValue(mealDetail.getAvoids() != null ? mealDetail.getAvoids() : "");
dataCell7.setCellStyle(dataStyle);
Cell dataCell8 = dataRow.createCell(columnNum++);
dataCell8.setCellValue(mealDetail.getRemark() != null ? mealDetail.getRemark() : "");
dataCell8.setCellStyle(dataStyle);
}
}
// 自动调整列宽
for (int i = 0; i < 9; i++) {
sheet.autoSizeColumn(i);
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
return outputStream;
}
/**
* 创建空的分餐表Excel(无数据)
*/
private static ByteArrayOutputStream createEmptyExcelBySeparateMeal() {
try {
SeparateMealDataDto emptyData = SeparateMealDataDto.builder()
.mealDetails(new ArrayList<>())
.build();
return writeToExcelBySeparateMeal(emptyData);
} catch (IOException e) {
log.error("创建空分餐表Excel失败", e);
throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
}
}
}
......
......@@ -2,6 +2,7 @@ package com.infoloop.tianting.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
......@@ -41,6 +42,14 @@ public class JsonUtil {
}
}
public static <T> T readJsonAs(final String json, final TypeReference<T> typeRef) {
try {
return OBJECT_MAPPER.readValue(json, typeRef);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static <T> T convertValue(final Object object, final Class<T> clazz) {
return OBJECT_MAPPER.convertValue(object, clazz);
}
......
......@@ -32,6 +32,7 @@ service ClientCustomerOrderServiceRpc {
// 操作记录
rpc GetOrderOperationRecordsByOrderId (GetOrderOperationRecordsByOrderIdRequest) returns (GetOrderOperationRecordsByOrderIdResponse) {}
rpc GetOrderOperationRecordsByOrderIds (GetOrderOperationRecordsByOrderIdsRequest) returns (GetOrderOperationRecordsByOrderIdsResponse) {}
rpc BatchCreateOrderOperationRecords (BatchCreateOrderOperationRecordsRequest) returns (BatchCreateOrderOperationRecordsResponse) {}
......@@ -624,6 +625,15 @@ message GetOrderOperationRecordsByOrderIdResponse {
repeated OrderOperationRecord responses = 1;
}
message GetOrderOperationRecordsByOrderIdsRequest {
int32 enterpriseId = 1;
repeated int32 orderIds = 2;
}
message GetOrderOperationRecordsByOrderIdsResponse {
repeated OrderOperationRecord responses = 1;
}
message OrderOperationRecordCreation {
int32 orderId = 1;
OrderOperationType type = 2;
......