wangyingyang

fix

...@@ -48,7 +48,16 @@ public class SettlementDTO { ...@@ -48,7 +48,16 @@ public class SettlementDTO {
48 48
49 @Data 49 @Data
50 @Builder 50 @Builder
51 - @ApiModel(description = "SettlementRequestDto") 51 + @ApiModel(description = "SettlementMenuMealDto")
52 + public static class SettlementMenuMealDto {
53 + private String skuName;
54 + private Integer price;
55 + private Integer count;
56 + }
57 +
58 + @Data
59 + @Builder
60 + @ApiModel(description = "SettlementDataDto")
52 public static class SettlementDataDto { 61 public static class SettlementDataDto {
53 private String client; 62 private String client;
54 private String startTime; 63 private String startTime;
...@@ -56,6 +65,16 @@ public class SettlementDTO { ...@@ -56,6 +65,16 @@ public class SettlementDTO {
56 private Map<String, Map<String, List<SettlementMenuSkuDto>>> classifyOrders; 65 private Map<String, Map<String, List<SettlementMenuSkuDto>>> classifyOrders;
57 } 66 }
58 67
68 + @Data
69 + @Builder
70 + @ApiModel(description = "SettlementDataByMealDto")
71 + public static class SettlementDataByMealDto {
72 + private String client;
73 + private LocalDateTime startTime;
74 + private LocalDateTime endTime;
75 + private Map<String, Map<String, Map<String, List<SettlementMenuMealDto>>>> classifyOrders;
76 + }
77 +
59 } 78 }
60 79
61 80
......
...@@ -4,21 +4,33 @@ import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum; ...@@ -4,21 +4,33 @@ import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum;
4 import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse; 4 import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderDetailRpcResponse;
5 import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse; 5 import com.infoloop.tianting.clientcustomerorderservice.SingleClientCustomerOrderRpcResponse;
6 import com.infoloop.tianting.context.LoginContextHolder; 6 import com.infoloop.tianting.context.LoginContextHolder;
7 +import com.infoloop.tianting.enums.SettlementDimensionEnum;
7 import com.infoloop.tianting.exception.ClientEndExceptions.BusinessException; 8 import com.infoloop.tianting.exception.ClientEndExceptions.BusinessException;
8 import com.infoloop.tianting.exception.ErrorCodeEnum; 9 import com.infoloop.tianting.exception.ErrorCodeEnum;
9 import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse; 10 import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse;
11 +import com.infoloop.tianting.menuservice.SingleMenuRpcResponse;
10 import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto; 12 import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto;
13 +import com.infoloop.tianting.model.dto.SettlementDTO;
14 +import com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataByMealDto;
11 import com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataDto; 15 import com.infoloop.tianting.model.dto.SettlementDTO.SettlementDataDto;
16 +import com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuMealDto;
12 import com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuSkuDto; 17 import com.infoloop.tianting.model.dto.SettlementDTO.SettlementMenuSkuDto;
13 import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto; 18 import com.infoloop.tianting.model.dto.SettlementDTO.SettlementRequestDto;
14 import com.infoloop.tianting.service.SettlementService; 19 import com.infoloop.tianting.service.SettlementService;
15 import com.infoloop.tianting.service.client.InventoryServiceRpcClient; 20 import com.infoloop.tianting.service.client.InventoryServiceRpcClient;
21 +import com.infoloop.tianting.service.client.MealServiceRpcClient;
16 import com.infoloop.tianting.service.client.MenuServiceRpcClient; 22 import com.infoloop.tianting.service.client.MenuServiceRpcClient;
17 import com.infoloop.tianting.service.client.OrderServiceRpcClient; 23 import com.infoloop.tianting.service.client.OrderServiceRpcClient;
18 import com.infoloop.tianting.service.client.SkuServiceRpcClient; 24 import com.infoloop.tianting.service.client.SkuServiceRpcClient;
25 +import com.infoloop.tianting.setmealscheduleservice.SingleMealRpcResponse;
19 import com.infoloop.tianting.utils.DateUtil; 26 import com.infoloop.tianting.utils.DateUtil;
27 +import java.time.LocalDate;
28 +import java.time.LocalDateTime;
29 +import java.time.temporal.ChronoUnit;
30 +import java.util.Comparator;
20 import lombok.RequiredArgsConstructor; 31 import lombok.RequiredArgsConstructor;
21 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
33 +import org.apache.poi.hpsf.Date;
22 import org.apache.poi.ss.usermodel.Cell; 34 import org.apache.poi.ss.usermodel.Cell;
23 import org.apache.poi.ss.usermodel.Row; 35 import org.apache.poi.ss.usermodel.Row;
24 import org.apache.poi.ss.usermodel.Sheet; 36 import org.apache.poi.ss.usermodel.Sheet;
...@@ -45,9 +57,19 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -45,9 +57,19 @@ public class SettlementServiceImpl implements SettlementService {
45 private final MenuServiceRpcClient menuServiceRpcClient; 57 private final MenuServiceRpcClient menuServiceRpcClient;
46 private final SkuServiceRpcClient skuServiceRpcClient; 58 private final SkuServiceRpcClient skuServiceRpcClient;
47 private final InventoryServiceRpcClient inventoryServiceRpcClient; 59 private final InventoryServiceRpcClient inventoryServiceRpcClient;
60 + private final MealServiceRpcClient mealServiceRpcClient;
48 61
49 @Override 62 @Override
50 public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) { 63 public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) {
64 + if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_SKU)) {
65 + return generateOrderSettlementExcelBySku(settlementRequest);
66 + } else {
67 + return generateOrderSettlementExcelByMeal(settlementRequest);
68 + }
69 + }
70 +
71 + public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) {
72 +
51 final var startDate = settlementRequest.getTimeStart().toLocalDate().atStartOfDay(); 73 final var startDate = settlementRequest.getTimeStart().toLocalDate().atStartOfDay();
52 final var endDate = settlementRequest.getTimeEnd().toLocalDate().plusDays(1).atStartOfDay(); 74 final var endDate = settlementRequest.getTimeEnd().toLocalDate().plusDays(1).atStartOfDay();
53 final var operatorLoginInfo = LoginContextHolder.getLoginInfo(); 75 final var operatorLoginInfo = LoginContextHolder.getLoginInfo();
...@@ -185,7 +207,7 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -185,7 +207,7 @@ public class SettlementServiceImpl implements SettlementService {
185 .endTime(DateUtil.formatDate(settlementRequest.getTimeEnd(), DateUtil.YYYY_MM_DD)) 207 .endTime(DateUtil.formatDate(settlementRequest.getTimeEnd(), DateUtil.YYYY_MM_DD))
186 .build(); 208 .build();
187 try { 209 try {
188 - final var bytes = writeToExcel(settlementDataDto); 210 + final var bytes = writeToExcelBySku(settlementDataDto);
189 return bytes; 211 return bytes;
190 } catch (IOException e) { 212 } catch (IOException e) {
191 throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR); 213 throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
...@@ -193,7 +215,7 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -193,7 +215,7 @@ public class SettlementServiceImpl implements SettlementService {
193 215
194 } 216 }
195 217
196 - public static ByteArrayOutputStream writeToExcel(SettlementDataDto settlementDataDto) 218 + public static ByteArrayOutputStream writeToExcelBySku(SettlementDataDto settlementDataDto)
197 throws IOException { 219 throws IOException {
198 Workbook workbook = new XSSFWorkbook(); 220 Workbook workbook = new XSSFWorkbook();
199 Sheet sheet = workbook.createSheet("订单数据"); 221 Sheet sheet = workbook.createSheet("订单数据");
...@@ -295,4 +317,225 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -295,4 +317,225 @@ public class SettlementServiceImpl implements SettlementService {
295 return outputStream; 317 return outputStream;
296 } 318 }
297 319
320 + public ByteArrayOutputStream generateOrderSettlementExcelByMeal(SettlementRequestDto settlementRequest) {
321 +
322 + final var startDate = settlementRequest.getTimeStart().toLocalDate().atStartOfDay();
323 + final var endDate = settlementRequest.getTimeEnd().toLocalDate().plusDays(1).atStartOfDay();
324 + final var operatorLoginInfo = LoginContextHolder.getLoginInfo();
325 + final var queryOrderDto = QueryOrderByConditionDto.builder()
326 + .enterpriseId(LoginContextHolder.hasLogin() ? operatorLoginInfo.getEnterpriseId() : settlementRequest.getEnterpriseId())
327 + .shouldFilterCreatedAtTimeStart(true)
328 + .createdAtTimeStart(startDate)
329 + .shouldFilterCreatedAtTimeEnd(true)
330 + .createdAtTimeEnd(endDate)
331 + .shouldFilterStallIds(!settlementRequest.getStallIds().isEmpty())
332 + .stallIds(settlementRequest.getStallIds())
333 + .build();
334 + final var orderList = orderServiceRpcClient.getOrdersByCondition(queryOrderDto);
335 + List<Integer> orderIds = orderList.stream()
336 + .filter(o -> !o.getStatus().equals(OrderStatusEnum.ORDER_CANCELED))
337 + .map(SingleClientCustomerOrderRpcResponse::getId).distinct()
338 + .collect(Collectors.toList());
339 + final var orderDetailList = orderServiceRpcClient.getOrderDetailsByOrderIds(orderIds);
340 + List<Integer> skuIds = orderDetailList.stream()
341 + .map(SingleClientCustomerOrderDetailRpcResponse::getSkuId)
342 + .distinct()
343 + .collect(Collectors.toList());
344 + final var skus = skuServiceRpcClient.getDishSkusByIds(skuIds).getResponseList();
345 +
346 + List<Integer> menuIds = orderList.stream().map(
347 + SingleClientCustomerOrderRpcResponse::getMenuId).distinct()
348 + .collect(Collectors.toList());
349 + final var menuList = menuServiceRpcClient
350 + .getMenusByIds(operatorLoginInfo.getEnterpriseId(), menuIds)
351 + .getResponsesList();
352 + final var menuDetailList = menuServiceRpcClient.queryMenuDetailsByMenuIds(
353 + operatorLoginInfo.getEnterpriseId(), menuIds).getResponsesList();
354 + //获取到所有的餐别
355 + final var allMeals = mealServiceRpcClient.getAllMeals(operatorLoginInfo.getEnterpriseId()).getResponsesList();
356 +
357 + Map<String, Map<String, Map<String, List<SettlementMenuMealDto>>>> classifyOrders = new HashMap<>();
358 + for(SingleMenuRpcResponse menu: menuList) {
359 + final var menuName = menu.getName();
360 + if (!classifyOrders.containsKey(menuName)) {
361 + classifyOrders.put(menuName, new HashMap<>());
362 + }
363 + final var menusMap = classifyOrders.get(menuName);
364 + //这个餐单下所有已点的orders
365 + final var curMenuOrders = orderList.stream()
366 + .filter(o -> o.getMenuId() == menu.getId())
367 + .collect(Collectors.toList());
368 + final var curMenuOrderIds = curMenuOrders.stream()
369 + .map(SingleClientCustomerOrderRpcResponse::getId)
370 + .collect(Collectors.toList());
371 + //这个餐单下所有已点的order details
372 + final var curMenuOrderDetails = orderDetailList.stream()
373 + .filter(od -> curMenuOrderIds.contains(od.getOrderId()))
374 + .collect(Collectors.toList());
375 + //这个餐单下所有已点的餐别
376 + final var curMenuMealIds = curMenuOrderDetails.stream()
377 + .map(SingleClientCustomerOrderDetailRpcResponse::getMealId)
378 + .distinct()
379 + .collect(Collectors.toList());
380 + final var curMenuMeals = allMeals.stream()
381 + .filter(m -> curMenuMealIds.contains(m.getId()))
382 + .collect(Collectors.toList());
383 + // 汇总每个餐别的情况
384 + for(SingleMealRpcResponse meal: curMenuMeals) {
385 + final var mealName = meal.getName();
386 + if (!menusMap.containsKey(mealName)) {
387 + menusMap.put(menuName, new HashMap<>());
388 + }
389 + final var mealsMap = menusMap.get(mealName);
390 + //当前餐别已点的order details
391 + final var curMealOrderDetails = curMenuOrderDetails.stream()
392 + .filter(od -> od.getMealId() == meal.getId())
393 + .collect(Collectors.toList());
394 + //找出所有需要的日期
395 + final var dates = curMealOrderDetails.stream()
396 + .sorted(Comparator.comparingLong(SingleClientCustomerOrderDetailRpcResponse::getCreatedAt))
397 + .map(o -> DateUtil.formatDateOfUtc(o.getCreatedAt(), DateUtil.YYYY_MM_DD_UTC))
398 + .distinct()
399 + .collect(Collectors.toList());
400 + for(String date: dates) {
401 +
402 + if (!mealsMap.containsKey(date)) {
403 + mealsMap.put(date, new ArrayList<>());
404 + }
405 + final var curMealDateSkuList = mealsMap.get(date);
406 + //找出当天所有的order details
407 + final var curMealDateOrderDetails = curMealOrderDetails.stream()
408 + .filter(o -> DateUtil.formatDateOfUtc(o.getCreatedAt(), DateUtil.YYYY_MM_DD_UTC).equals(date))
409 + .collect(Collectors.toList());
410 + for(SingleClientCustomerOrderDetailRpcResponse detail: curMealDateOrderDetails) {
411 + final var settlementOrderDetail = SettlementMenuMealDto.builder()
412 + .skuName(detail.getShowName())
413 + .count(detail.getCount())
414 + .price(detail.getPrice())
415 + .build();
416 + curMealDateSkuList.add(settlementOrderDetail);
417 + }
418 + }
419 + }
420 +
421 + }
422 + final var client = inventoryServiceRpcClient.getClientById(operatorLoginInfo.getEnterpriseId(),
423 + settlementRequest.getClientId()).getClient();
424 + final var settlementDataByMealDto = SettlementDataByMealDto.builder()
425 + .classifyOrders(classifyOrders)
426 + .client(client.getName())
427 + .startTime(settlementRequest.getTimeStart())
428 + .endTime(settlementRequest.getTimeEnd())
429 + .build();
430 + try {
431 + final var bytes = writeToExcelByMeal(settlementDataByMealDto);
432 + return bytes;
433 + } catch (IOException e) {
434 + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
435 + }
436 +
437 + }
438 +
439 + public static ByteArrayOutputStream writeToExcelByMeal(SettlementDataByMealDto settlementDataDto)
440 + throws IOException {
441 + Workbook workbook = new XSSFWorkbook();
442 + Sheet sheet = workbook.createSheet("订单数据");
443 +
444 + final var classifyOrders = settlementDataDto.getClassifyOrders();
445 +
446 + int rowNum = 0;
447 + Row sheetTitleRow = sheet.createRow(rowNum++);
448 + Cell sheetTitleCell = sheetTitleRow.createCell(0);
449 + sheetTitleCell.setCellValue(settlementDataDto.getClient());
450 + Row dateRangeRow = sheet.createRow(rowNum++);
451 + Cell dateRangeCell = dateRangeRow.createCell(0);
452 + final var dateRange = settlementDataDto.getStartTime() + "至" + settlementDataDto.getEndTime();
453 + dateRangeCell.setCellValue(dateRange);
454 + Row titleRow = sheet.createRow(rowNum++);
455 + int columnNum = 0;
456 + Cell menuTitleCell = titleRow.createCell(columnNum++);
457 + menuTitleCell.setCellValue("餐单名称");
458 + Cell mealTitleCell = titleRow.createCell(columnNum++);
459 + mealTitleCell.setCellValue("餐别");
460 +
461 + final var dates = getDatesBetween(settlementDataDto.getStartTime(),
462 + settlementDataDto.getEndTime());
463 + for (String date: dates) {
464 + Cell dateTitleCell = titleRow.createCell(columnNum++);
465 + dateTitleCell.setCellValue(date);
466 + }
467 + Cell priceTitleCell = titleRow.createCell(columnNum);
468 + priceTitleCell.setCellValue("总金额");
469 + for (Map.Entry<String, Map<String, Map<String, List<SettlementMenuMealDto>>>> outerEntry : classifyOrders.entrySet()) {
470 + String menuNme = outerEntry.getKey();
471 + Map<String, Map<String, List<SettlementMenuMealDto>>> innerMap = outerEntry.getValue();
472 + int curMenuTotalRow = innerMap.size();
473 + // 写入menu列并合并单元格
474 + int startRowForMenu = rowNum;
475 + for (int i = 0; i < curMenuTotalRow; i++) {
476 + Row dateRow = sheet.createRow(rowNum++);
477 + Cell menuCell = dateRow.createCell(0);
478 + menuCell.setCellValue(menuNme);
479 + }
480 + int endRowForDate = rowNum - 1;
481 + if (endRowForDate > startRowForMenu) {
482 + CellRangeAddress dateRegion = new CellRangeAddress(startRowForMenu, endRowForDate, 0, 0);
483 + sheet.addMergedRegion(dateRegion);
484 + }
485 +
486 + rowNum = startRowForMenu;
487 + for (Map.Entry<String, Map<String, List<SettlementMenuMealDto>>> innerEntry : innerMap.entrySet()) {
488 + String mealName = innerEntry.getKey();
489 + Map<String, List<SettlementMenuMealDto>> skuMap = innerEntry.getValue();
490 +
491 + // 写入meal列并合并单元格
492 + Row mealRow = sheet.getRow(rowNum++);
493 + Cell mealCell = mealRow.createCell(1);
494 + mealCell.setCellValue(mealName);
495 +
496 + columnNum = 2;
497 + Integer totalPrice = 0;
498 + for (String date: dates) {
499 + final var toWriteDateSkuList = skuMap.get(date);
500 + Integer price = 0;
501 + if(!toWriteDateSkuList.isEmpty()) {
502 + for (SettlementMenuMealDto settlementMenuMealDto: toWriteDateSkuList) {
503 + price += settlementMenuMealDto.getPrice() * settlementMenuMealDto.getCount();
504 + totalPrice += price;
505 + }
506 + }
507 + Cell priceCell = mealRow.createCell(columnNum++);
508 + priceCell.setCellValue((double)price/100);
509 + }
510 + Cell totalPriceCell = mealRow.createCell(columnNum);
511 + totalPriceCell.setCellValue((double)totalPrice/100);
512 + }
513 + }
514 +
515 + // 自动调整列宽
516 + for (int i = 0; i < 7; i++) {
517 + sheet.autoSizeColumn(i);
518 + }
519 +
520 + // 将工作簿内容写入字节数组输出流
521 + ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
522 + workbook.write(outputStream);
523 + workbook.close();
524 +
525 + return outputStream;
526 + }
527 +
528 + public static List<String> getDatesBetween(LocalDateTime startTime, LocalDateTime endTime) {
529 + List<String> dateList = new ArrayList<>();
530 + LocalDate startDate = startTime.toLocalDate();
531 + LocalDate endDate = endTime.toLocalDate();
532 +
533 + long daysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1;
534 + for (int i = 0; i < daysBetween; i++) {
535 + LocalDate currentDate = startDate.plusDays(i);
536 + dateList.add(DateUtil.formatDate(currentDate, DateUtil.YYYY_MM_DD));
537 + }
538 + return dateList;
539 + }
540 +
298 } 541 }
......