zhuyifan

fix(order): optimize dish replacement logic and update payment transaction ID

...@@ -60,4 +60,5 @@ public class PayController { ...@@ -60,4 +60,5 @@ public class PayController {
60 public String cancel(@Valid @RequestBody PayDTO.PayRefundRequestDto payRefundRequestDto) { 60 public String cancel(@Valid @RequestBody PayDTO.PayRefundRequestDto payRefundRequestDto) {
61 return payServiceClient.orderPayRefund(payRefundRequestDto); 61 return payServiceClient.orderPayRefund(payRefundRequestDto);
62 } 62 }
63 +
63 } 64 }
...\ No newline at end of file ...\ No newline at end of file
......
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
...@@ -730,6 +731,10 @@ public class OrderDbDTO { ...@@ -730,6 +731,10 @@ public class OrderDbDTO {
730 @Builder.Default 731 @Builder.Default
731 private Boolean shouldUpdateServeStatus = false; 732 private Boolean shouldUpdateServeStatus = false;
732 733
734 + @ApiModelProperty(value = "价格")
735 + @Builder.Default
736 + private Integer price = null;
737 +
733 @ApiModelProperty(value = "出餐状态: 默认未出餐=1; 不出餐=2; 已出餐=3") 738 @ApiModelProperty(value = "出餐状态: 默认未出餐=1; 不出餐=2; 已出餐=3")
734 @Builder.Default 739 @Builder.Default
735 private ServeStatusEnum serveStatus = ServeStatusEnum.SERVE_NOT_START; 740 private ServeStatusEnum serveStatus = ServeStatusEnum.SERVE_NOT_START;
......
...@@ -9,6 +9,8 @@ import lombok.Builder; ...@@ -9,6 +9,8 @@ import lombok.Builder;
9 import lombok.Data; 9 import lombok.Data;
10 import lombok.NoArgsConstructor; 10 import lombok.NoArgsConstructor;
11 11
12 +import java.util.List;
13 +
12 @Data 14 @Data
13 @ApiModel(description = "支付DTO") 15 @ApiModel(description = "支付DTO")
14 public class PayDTO { 16 public class PayDTO {
...@@ -31,6 +33,7 @@ public class PayDTO { ...@@ -31,6 +33,7 @@ public class PayDTO {
31 @AllArgsConstructor 33 @AllArgsConstructor
32 public static class PayRefundRequestDto { 34 public static class PayRefundRequestDto {
33 private Integer orderId; 35 private Integer orderId;
36 + private List<Integer> orderDetailIds;
34 private String hospitalCode; 37 private String hospitalCode;
35 } 38 }
36 39
......
...@@ -18,6 +18,9 @@ public class PaymentCallbackResult { ...@@ -18,6 +18,9 @@ public class PaymentCallbackResult {
18 @JacksonXmlProperty(localName = "TransSN") 18 @JacksonXmlProperty(localName = "TransSN")
19 private String transSN; 19 private String transSN;
20 20
21 + @JacksonXmlProperty(localName = "TradeReferenceNo")
22 + private String tradeReferenceNo;
23 +
21 @JacksonXmlProperty(localName = "TransType") 24 @JacksonXmlProperty(localName = "TransType")
22 private String transType; 25 private String transType;
23 26
......
...@@ -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;
...@@ -240,8 +242,10 @@ public class OrderServiceRpcClient { ...@@ -240,8 +242,10 @@ public class OrderServiceRpcClient {
240 final var operator = operatorServiceRpcClient.getCOperatorById(operatorLoginInfo.getId()); 242 final var operator = operatorServiceRpcClient.getCOperatorById(operatorLoginInfo.getId());
241 final var idsOfNeedUpdateMenuDetails = new ArrayList<Integer>(); 243 final var idsOfNeedUpdateMenuDetails = new ArrayList<Integer>();
242 final var idsOfAddCount = new ArrayList<Integer>(); 244 final var idsOfAddCount = new ArrayList<Integer>();
245 + final var idsOfNoReject = new ArrayList<Integer>();
243 List<OrderDetailDto> originalOrderDetails = new ArrayList<>(); 246 List<OrderDetailDto> originalOrderDetails = new ArrayList<>();
244 List<OrderDetailDto> newOrderDetails; 247 List<OrderDetailDto> newOrderDetails;
248 + final var orderDetailsMap = orderDetailBatchUpdateDto.getDetails().stream().collect(Collectors.toMap(OrderDbDTO.OrderDetailUpdateDto::getId, Function.identity()));
245 final var modifications = orderDetailBatchUpdateDto.getDetails().stream().map(d -> { 249 final var modifications = orderDetailBatchUpdateDto.getDetails().stream().map(d -> {
246 var mealDetail = MealDetail.newBuilder().build(); 250 var mealDetail = MealDetail.newBuilder().build();
247 Integer menuDetailId = 0; 251 Integer menuDetailId = 0;
...@@ -280,9 +284,11 @@ public class OrderServiceRpcClient { ...@@ -280,9 +284,11 @@ public class OrderServiceRpcClient {
280 .build(); 284 .build();
281 } 285 }
282 } 286 }
283 -
284 ServeStatusEnum serveStatus = ServeStatusEnum.UNKNOWN_SERVE_STATUS; 287 ServeStatusEnum serveStatus = ServeStatusEnum.UNKNOWN_SERVE_STATUS;
285 if (d.getShouldUpdateServeStatus()) { 288 if (d.getShouldUpdateServeStatus()) {
289 + if (d.getServeStatus() == ServeStatusEnum.SERVE_REJECT) {
290 + idsOfNoReject.add(d.getId());
291 + }
286 serveStatus = d.getServeStatus(); 292 serveStatus = d.getServeStatus();
287 } 293 }
288 Integer count = 0; 294 Integer count = 0;
...@@ -319,7 +325,8 @@ public class OrderServiceRpcClient { ...@@ -319,7 +325,8 @@ public class OrderServiceRpcClient {
319 .build(); 325 .build();
320 final var totalIds = new ArrayList<>(idsOfNeedUpdateMenuDetails); 326 final var totalIds = new ArrayList<>(idsOfNeedUpdateMenuDetails);
321 totalIds.addAll(idsOfAddCount); 327 totalIds.addAll(idsOfAddCount);
322 - if (!idsOfNeedUpdateMenuDetails.isEmpty() || !idsOfAddCount.isEmpty()) { 328 + totalIds.addAll(idsOfNoReject);
329 + if (!totalIds.isEmpty()) {
323 final var orgionalResponseList = getClientCustomerOrderDetailsByIds(totalIds); 330 final var orgionalResponseList = getClientCustomerOrderDetailsByIds(totalIds);
324 originalOrderDetails = orgionalResponseList.stream().map(d -> OrderDetailDto.builder() 331 originalOrderDetails = orgionalResponseList.stream().map(d -> OrderDetailDto.builder()
325 .id(d.getId()) 332 .id(d.getId())
...@@ -357,7 +364,7 @@ public class OrderServiceRpcClient { ...@@ -357,7 +364,7 @@ public class OrderServiceRpcClient {
357 } 364 }
358 final var res = orderServiceRpcBlockingStub.batchUpdateClientCustomerOrderDetails(request); 365 final var res = orderServiceRpcBlockingStub.batchUpdateClientCustomerOrderDetails(request);
359 if (res.getIsUpdated()) { 366 if (res.getIsUpdated()) {
360 - if (!idsOfNeedUpdateMenuDetails.isEmpty() || !idsOfAddCount.isEmpty()) { 367 + if (!totalIds.isEmpty()) {
361 final var newResponseList = getClientCustomerOrderDetailsByIds(totalIds); 368 final var newResponseList = getClientCustomerOrderDetailsByIds(totalIds);
362 newOrderDetails = newResponseList.stream().map(d -> 369 newOrderDetails = newResponseList.stream().map(d ->
363 OrderDetailDto.builder() 370 OrderDetailDto.builder()
...@@ -392,15 +399,21 @@ public class OrderServiceRpcClient { ...@@ -392,15 +399,21 @@ public class OrderServiceRpcClient {
392 .updateSource(d.getUpdateSource().getNumber()) 399 .updateSource(d.getUpdateSource().getNumber())
393 .updatedAt(DateUtil.formatDate(d.getUpdatedAt())) 400 .updatedAt(DateUtil.formatDate(d.getUpdatedAt()))
394 .updatedBy(d.getUpdatedBy()) 401 .updatedBy(d.getUpdatedBy())
395 - .build()).collect(Collectors.toList()); 402 + .build()).toList();
396 // 替换菜品的操作记录 403 // 替换菜品的操作记录
397 List<SingleOperationDto> operations = new ArrayList<>(); 404 List<SingleOperationDto> operations = new ArrayList<>();
398 for (OrderDetailDto originalDetail : originalOrderDetails) { 405 for (OrderDetailDto originalDetail : originalOrderDetails) {
406 + if (!totalIds.contains(originalDetail.getId())) {
407 + continue;
408 + }
409 + final var orderDetailUpdateDto = orderDetailsMap.get(originalDetail.getId());
399 OrderOperationType orderOperationType = OrderOperationType.UNKNOWN_OPERATION_TYPE; 410 OrderOperationType orderOperationType = OrderOperationType.UNKNOWN_OPERATION_TYPE;
400 if (idsOfNeedUpdateMenuDetails.contains(originalDetail.getId())) { 411 if (idsOfNeedUpdateMenuDetails.contains(originalDetail.getId())) {
401 orderOperationType = OrderOperationType.REPLACE_DISHES; 412 orderOperationType = OrderOperationType.REPLACE_DISHES;
402 } else if (idsOfAddCount.contains(originalDetail.getId())) { 413 } else if (idsOfAddCount.contains(originalDetail.getId())) {
403 orderOperationType = OrderOperationType.ADD_DISHES; 414 orderOperationType = OrderOperationType.ADD_DISHES;
415 + } else if (idsOfNoReject.contains(originalDetail.getId())) {
416 + orderOperationType = OrderOperationType.NOT_SERVE;
404 } 417 }
405 String originalDetailStr; 418 String originalDetailStr;
406 String newDetailStr = ""; 419 String newDetailStr = "";
...@@ -413,6 +426,7 @@ public class OrderServiceRpcClient { ...@@ -413,6 +426,7 @@ public class OrderServiceRpcClient {
413 .count(newDetail.get().getCount()) 426 .count(newDetail.get().getCount())
414 .adjustSkuRemark(newDetail.get().getAdjustSkuRemark()) 427 .adjustSkuRemark(newDetail.get().getAdjustSkuRemark())
415 .serveStatus(newDetail.get().getServeStatus().name()) 428 .serveStatus(newDetail.get().getServeStatus().name())
429 + .price(orderDetailUpdateDto.getPrice() == null ? newDetail.get().getPrice() : orderDetailUpdateDto.getPrice())
416 .build(); 430 .build();
417 newDetailStr = JsonUtil.writeAsJson(List.of(newOrderDetailOperation)); 431 newDetailStr = JsonUtil.writeAsJson(List.of(newOrderDetailOperation));
418 } 432 }
...@@ -423,6 +437,7 @@ public class OrderServiceRpcClient { ...@@ -423,6 +437,7 @@ public class OrderServiceRpcClient {
423 .count(originalDetail.getCount()) 437 .count(originalDetail.getCount())
424 .adjustSkuRemark(originalDetail.getAdjustSkuRemark()) 438 .adjustSkuRemark(originalDetail.getAdjustSkuRemark())
425 .serveStatus(originalDetail.getServeStatus().name()) 439 .serveStatus(originalDetail.getServeStatus().name())
440 + .price(originalDetail.getPrice())
426 .build(); 441 .build();
427 originalDetailStr = JsonUtil.writeAsJson(List.of(originalOrderDetailOperation)); 442 originalDetailStr = JsonUtil.writeAsJson(List.of(originalOrderDetailOperation));
428 final var operation = SingleOperationDto.builder() 443 final var operation = SingleOperationDto.builder()
...@@ -471,7 +486,6 @@ public class OrderServiceRpcClient { ...@@ -471,7 +486,6 @@ public class OrderServiceRpcClient {
471 .setCreationSource(batchOperationDto.getCreationSource()) 486 .setCreationSource(batchOperationDto.getCreationSource())
472 .build(); 487 .build();
473 return orderServiceRpcBlockingStub.batchCreateOrderOperationRecords(request); 488 return orderServiceRpcBlockingStub.batchCreateOrderOperationRecords(request);
474 -
475 } 489 }
476 490
477 public QueryClientCustomerOrdersByPaginationRpcResponse queryClientCustomerOrdersByPagination(QueryOrderByPaginationDto queryOrderDto) { 491 public QueryClientCustomerOrdersByPaginationRpcResponse queryClientCustomerOrdersByPagination(QueryOrderByPaginationDto queryOrderDto) {
...@@ -489,6 +503,14 @@ public class OrderServiceRpcClient { ...@@ -489,6 +503,14 @@ public class OrderServiceRpcClient {
489 return orderServiceRpcBlockingStub.queryClientCustomerOrdersByPagination(request); 503 return orderServiceRpcBlockingStub.queryClientCustomerOrdersByPagination(request);
490 } 504 }
491 505
506 + public GetOrderOperationRecordsByOrderIdsResponse getOrderOperationRecordsByOrderIds(int enterpriseId, List<Integer> orderIds) {
507 + final var request = GetOrderOperationRecordsByOrderIdsRequest.newBuilder()
508 + .setEnterpriseId(enterpriseId)
509 + .addAllOrderIds(orderIds)
510 + .build();
511 + return orderServiceRpcBlockingStub.getOrderOperationRecordsByOrderIds(request);
512 + }
513 +
492 public QueryClientCustomerOrdersByConditionRpcResponse queryClientCustomerOrdersByCondition(OrderDbDTO.QueryOrderDto queryOrderDto) { 514 public QueryClientCustomerOrdersByConditionRpcResponse queryClientCustomerOrdersByCondition(OrderDbDTO.QueryOrderDto queryOrderDto) {
493 final var request = QueryClientCustomerOrdersByConditionRpcRequest.newBuilder() 515 final var request = QueryClientCustomerOrdersByConditionRpcRequest.newBuilder()
494 .setShouldFilterStatus(true) 516 .setShouldFilterStatus(true)
......
...@@ -38,6 +38,7 @@ import lombok.RequiredArgsConstructor; ...@@ -38,6 +38,7 @@ import lombok.RequiredArgsConstructor;
38 import lombok.extern.slf4j.Slf4j; 38 import lombok.extern.slf4j.Slf4j;
39 import org.apache.commons.codec.binary.Base64; 39 import org.apache.commons.codec.binary.Base64;
40 import org.apache.commons.codec.digest.DigestUtils; 40 import org.apache.commons.codec.digest.DigestUtils;
41 +import org.apache.commons.collections4.CollectionUtils;
41 import org.springframework.beans.factory.annotation.Autowired; 42 import org.springframework.beans.factory.annotation.Autowired;
42 import org.springframework.http.HttpEntity; 43 import org.springframework.http.HttpEntity;
43 import org.springframework.http.HttpHeaders; 44 import org.springframework.http.HttpHeaders;
...@@ -66,333 +67,338 @@ import java.util.stream.Collectors; ...@@ -66,333 +67,338 @@ import java.util.stream.Collectors;
66 @RequiredArgsConstructor(onConstructor = @__(@Autowired)) 67 @RequiredArgsConstructor(onConstructor = @__(@Autowired))
67 public class PayServiceClient { 68 public class PayServiceClient {
68 69
69 - private final RestTemplate restTemplate; 70 + private final RestTemplate restTemplate;
70 71
71 - private final BusinessConfig businessConfig; 72 + private final BusinessConfig businessConfig;
72 73
73 - private final OrderServiceRpcClient orderServiceRpcClient; 74 + private final OrderServiceRpcClient orderServiceRpcClient;
74 75
75 - private final ClientResourceTagServiceRpcClient clientResourceTagServiceRpcClient; 76 + private final ClientResourceTagServiceRpcClient clientResourceTagServiceRpcClient;
76 77
77 - private final EnterpriseResourceServiceRpcClient enterpriseResourceServiceRpcClient; 78 + private final EnterpriseResourceServiceRpcClient enterpriseResourceServiceRpcClient;
78 79
79 - private final XmlMapper xmlMapper = new XmlMapper(); 80 + private final XmlMapper xmlMapper = new XmlMapper();
80 81
81 - public PayResponseDto payInform(PayInformRequestDto payRequestDto) { 82 + public PayResponseDto payInform(PayInformRequestDto payRequestDto) {
82 - final var orderById = 83 + final var orderById =
83 - orderServiceRpcClient.getOrderById(Integer.valueOf(payRequestDto.getOrderId())); 84 + orderServiceRpcClient.getOrderById(Integer.valueOf(payRequestDto.getOrderId()));
84 - if (orderById == null 85 + if (orderById == null
85 - || orderById.getPayStatus() == PayStatusEnum.PAY_CANCELED 86 + || orderById.getPayStatus() == PayStatusEnum.PAY_CANCELED
86 - || orderById.getStatus() == OrderStatusEnum.ORDER_CANCELED) { 87 + || orderById.getStatus() == OrderStatusEnum.ORDER_CANCELED) {
87 - log.info("Order {} not found or canceled, skipping.", payRequestDto.getOrderId()); 88 + log.info("Order {} not found or canceled, skipping.", payRequestDto.getOrderId());
88 - throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_CANCEL); 89 + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_CANCEL);
89 - } 90 + }
90 - String url = MessageFormat.format(businessConfig.getPayUrl(), businessConfig.getPayClientId()); 91 + String url = MessageFormat.format(businessConfig.getPayUrl(), businessConfig.getPayClientId());
91 - String requestDate = DateUtil.formatDate(LocalDateTime.now(), DateUtil.YMDHMS); 92 + String requestDate = DateUtil.formatDate(LocalDateTime.now(), DateUtil.YMDHMS);
92 - ThirdPartyPayInformRequestDto jsonData = buildRequestData(payRequestDto, requestDate); 93 + ThirdPartyPayInformRequestDto jsonData = buildRequestData(payRequestDto, requestDate);
93 - String jsonDataString; 94 + String jsonDataString;
94 - try { 95 + try {
95 - ObjectMapper objectMapper = new ObjectMapper(); 96 + ObjectMapper objectMapper = new ObjectMapper();
96 - objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); 97 + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
97 - objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); 98 + objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
98 - objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.UpperCamelCaseStrategy()); 99 + objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.UpperCamelCaseStrategy());
99 - jsonDataString = objectMapper.writeValueAsString(jsonData); 100 + jsonDataString = objectMapper.writeValueAsString(jsonData);
100 - } catch (JsonProcessingException e) { 101 + } catch (JsonProcessingException e) {
101 - log.error("Failed to serialize request data", e); 102 + log.error("Failed to serialize request data", e);
102 - throw new IllegalArgumentException("支付信息获取失败: JSON 解析错误"); 103 + throw new IllegalArgumentException("支付信息获取失败: JSON 解析错误");
104 + }
105 + HttpEntity<String> requestEntity = new HttpEntity<>(jsonDataString, createHeaders());
106 + log.info("payInform request: {}", jsonDataString);
107 + ResponseEntity<String> responseEntity =
108 + restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
109 + return processResponse(responseEntity);
103 } 110 }
104 - HttpEntity<String> requestEntity = new HttpEntity<>(jsonDataString, createHeaders());
105 - log.info("payInform request: {}", jsonDataString);
106 - ResponseEntity<String> responseEntity =
107 - restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
108 - return processResponse(responseEntity);
109 - }
110 -
111 - private ThirdPartyPayInformRequestDto buildRequestData(
112 - PayInformRequestDto payRequestDto, String requestDate) {
113 - ThirdPartyPayInformRequestDto jsonData = new ThirdPartyPayInformRequestDto();
114 - jsonData.setClientId(businessConfig.getPayClientId());
115 - jsonData.setTradeId(payRequestDto.getOrderId());
116 - jsonData.setRequestDate(requestDate);
117 - jsonData.setRequestSource("OFWXApplet");
118 - jsonData.setPayerOpenId(LoginContextHolder.getOpenId());
119 - jsonData.setHospitalCode(payRequestDto.getHospitalCode());
120 - jsonData.setPID(LoginContextHolder.getOpenId());
121 - jsonData.setRemark("");
122 - jsonData.setTransAmount(payRequestDto.getPrice());
123 - jsonData.setTradeDesc("");
124 - jsonData.setSign(
125 - EncryptionUtil.sha1Encryption(
126 - businessConfig.getPayClientId()
127 - + payRequestDto.getOrderId()
128 - + requestDate
129 - + businessConfig.getPayClientId()));
130 - return jsonData;
131 - }
132 111
133 - private HttpHeaders createHeaders() { 112 + private ThirdPartyPayInformRequestDto buildRequestData(
134 - HttpHeaders headers = new HttpHeaders(); 113 + PayInformRequestDto payRequestDto, String requestDate) {
135 - headers.setContentType(MediaType.APPLICATION_JSON); 114 + ThirdPartyPayInformRequestDto jsonData = new ThirdPartyPayInformRequestDto();
136 - return headers; 115 + jsonData.setClientId(businessConfig.getPayClientId());
137 - } 116 + jsonData.setTradeId(payRequestDto.getOrderId());
138 - 117 + jsonData.setRequestDate(requestDate);
139 - private PayResponseDto processResponse(ResponseEntity<String> responseEntity) { 118 + jsonData.setRequestSource("OFWXApplet");
140 - if (!responseEntity.getStatusCode().is2xxSuccessful() || responseEntity.getBody() == null) { 119 + jsonData.setPayerOpenId(LoginContextHolder.getOpenId());
141 - log.error("payInform failed with response: {}", responseEntity.getBody()); 120 + jsonData.setHospitalCode(payRequestDto.getHospitalCode());
142 - throw new IllegalArgumentException("支付信息获取失败"); 121 + jsonData.setPID(LoginContextHolder.getOpenId());
143 - } 122 + jsonData.setRemark("");
144 - try { 123 + jsonData.setTransAmount(payRequestDto.getPrice());
145 - log.info("processResponse response: {}", responseEntity.getBody()); 124 + jsonData.setTradeDesc("");
146 - return xmlMapper.readValue(responseEntity.getBody(), PayResponseDto.class); 125 + jsonData.setSign(
147 - } catch (Exception e) { 126 + EncryptionUtil.sha1Encryption(
148 - log.error("Failed to parse XML response", e); 127 + businessConfig.getPayClientId()
149 - throw new RuntimeException("支付信息结果解析失败", e); 128 + + payRequestDto.getOrderId()
129 + + requestDate
130 + + businessConfig.getPayClientId()));
131 + return jsonData;
150 } 132 }
151 - }
152 133
153 - public boolean callback(PaymentCallbackDTO paymentCallbackDTO) { 134 + private HttpHeaders createHeaders() {
154 - log.info("callback request received: {}", paymentCallbackDTO); 135 + HttpHeaders headers = new HttpHeaders();
155 - try { 136 + headers.setContentType(MediaType.APPLICATION_JSON);
156 - final var paymentCallbackResult = 137 + return headers;
157 - xmlMapper.readValue(paymentCallbackDTO.getPayResult(), PaymentCallbackResult.class); 138 + }
158 - log.info("Parsed paymentCallbackResult: {}", paymentCallbackResult);
159 - final var orderId = Integer.parseInt(paymentCallbackResult.getTradeId());
160 - final var orderById = orderServiceRpcClient.getOrderById(orderId);
161 - if (orderById == null) {
162 - log.error("Order not found, orderId: {}", orderId);
163 - return false;
164 - }
165 - log.info("Order callback, orderId: {}", orderId);
166 139
167 - final var transType = paymentCallbackResult.getTransType(); 140 + private PayResponseDto processResponse(ResponseEntity<String> responseEntity) {
168 - if (transType.equals("00")) { 141 + if (!responseEntity.getStatusCode().is2xxSuccessful() || responseEntity.getBody() == null) {
169 - if (orderById.getPayStatus() != PayStatusEnum.TO_PAY 142 + log.error("payInform failed with response: {}", responseEntity.getBody());
170 - && orderById.getPayStatus() != PayStatusEnum.IN_PROGRESS) { 143 + throw new IllegalArgumentException("支付信息获取失败");
171 - log.error("Order status is not TO_PAY or IN_PROGRESS, orderId: {}", orderId);
172 - return true;
173 } 144 }
174 - long payTime;
175 try { 145 try {
176 - payTime = 146 + log.info("processResponse response: {}", responseEntity.getBody());
177 - DateUtil.parseDate(paymentCallbackResult.getTransDate(), "yyyyMMddHHmmss").getTime(); 147 + return xmlMapper.readValue(responseEntity.getBody(), PayResponseDto.class);
178 - } catch (ParseException e) { 148 + } catch (Exception e) {
179 - log.error("Failed to parse TransDate: {}", paymentCallbackResult.getTransDate(), e); 149 + log.error("Failed to parse XML response", e);
180 - throw new IllegalArgumentException("支付时间格式错误: " + paymentCallbackResult.getTransDate(), e); 150 + throw new RuntimeException("支付信息结果解析失败", e);
181 } 151 }
182 - BigDecimal realAmount; 152 + }
153 +
154 + public boolean callback(PaymentCallbackDTO paymentCallbackDTO) {
155 + log.info("callback request received: {}", paymentCallbackDTO);
183 try { 156 try {
184 - realAmount = Convert.toBigDecimal(paymentCallbackResult.getRealAmount()); 157 + final var paymentCallbackResult =
185 - if (realAmount == null) { 158 + xmlMapper.readValue(paymentCallbackDTO.getPayResult(), PaymentCallbackResult.class);
186 - throw new NumberFormatException("RealAmount is null or empty"); 159 + log.info("Parsed paymentCallbackResult: {}", paymentCallbackResult);
187 - } 160 + final var orderId = Integer.parseInt(paymentCallbackResult.getTradeId());
188 - } catch (NumberFormatException e) { 161 + final var orderById = orderServiceRpcClient.getOrderById(orderId);
189 - log.error("Invalid RealAmount value: {}", paymentCallbackResult.getRealAmount(), e); 162 + if (orderById == null) {
190 - throw new IllegalArgumentException("支付金额错误: " + paymentCallbackResult.getRealAmount(), e); 163 + log.error("Order not found, orderId: {}", orderId);
191 - } 164 + return false;
192 - final var build =
193 - ClientCustomerOrderModification.newBuilder()
194 - .setId(orderId)
195 - .setShouldUpdatePayTime(true)
196 - .setPayTime(payTime)
197 - .setShouldUpdatePayPrice(true)
198 - .setPayPrice(realAmount.multiply(new BigDecimal("100")).intValue())
199 - .setShouldUpdatePayStatus(true)
200 - .setPayStatus(PayStatusEnum.SUCCEED)
201 - .setShouldUpdateStatus(true)
202 - .setStatus(OrderStatusEnum.PREPARING)
203 - .setShouldUpdateTransactionId(true)
204 - .setTransactionId(paymentCallbackResult.getTransSN())
205 - .build();
206 - final var updateResponse =
207 - orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
208 - log.info("callback updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
209 - if (updateResponse.getIsUpdated()) {
210 - String createdAt = Instant.ofEpochMilli(orderById.getCreatedAt())
211 - .atZone(DateUtil.CHINA_ZONE)
212 - .minusHours(8)
213 - .format(DateUtil.Y_M_D_H_M_S);
214 - String payTimed = Instant.ofEpochMilli(orderById.getPayTime())
215 - .atZone(DateUtil.CHINA_ZONE)
216 - .minusHours(8)
217 - .format(DateUtil.Y_M_D_H_M_S);
218 - final var orderPaymentSuccessData =
219 - OrderPaymentSuccessData.builder()
220 - .orderId(orderById.getId())
221 - .orderCode(orderById.getOrderCode())
222 - .createTime(createdAt)
223 - .payTime(payTimed)
224 - .build();
225 - final var data =
226 - SocketMessage.<OrderPaymentSuccessData>builder()
227 - .type(MessageTypeEnum.ORDER)
228 - .noticeType(NoticeTypeEnum.ORDER_PAYMENT_SUCCESS)
229 - .subject(NoticeTypeEnum.ORDER_PAYMENT_SUCCESS.getDescription())
230 - .message("您的订单:" + orderById.getOrderCode() + " 支付成功啦,快去查看吧~")
231 - .data(orderPaymentSuccessData)
232 - .build();
233 - WebSocketServer.sendMessageToUser(
234 - UserSessionKey.builder()
235 - .userId(orderById.getOpenId())
236 - .userType(UserTypeEnum.MICRO)
237 - .build(),
238 - data);
239 - if (LocalDate.now().equals(DateUtil.toLocalDate(orderById.getMealTime()))) {
240 - final var orderCreateSuccessData =
241 - OrderCreateSuccessData.builder().orderId(orderById.getId()).build();
242 - final var createOrderData =
243 - SocketMessage.<OrderCreateSuccessData>builder()
244 - .type(MessageTypeEnum.ORDER)
245 - .noticeType(NoticeTypeEnum.ORDER_CREATED)
246 - .subject(NoticeTypeEnum.ORDER_CREATED.getDescription())
247 - .message("有新的订单下单成功啦,快去查看吧~")
248 - .data(orderCreateSuccessData)
249 - .build();
250 - final var clientOperatorIds =
251 - clientResourceTagServiceRpcClient
252 - .getOperatorIdsByStallIds(List.of(orderById.getStallId())).stream()
253 - .map(SingleResourceLabelEntityRefsResponse::getEntityId)
254 - .distinct()
255 - .collect(Collectors.toList());
256 - final var enterpriseOperatorIds =
257 - enterpriseResourceServiceRpcClient.getOperatorIdsByStallId(
258 - orderById.getEnterpriseId(), orderById.getStallId());
259 - final var userAuthData = new ArrayList<UserAuthData>();
260 - userAuthData.addAll(
261 - clientOperatorIds.stream()
262 - .map(
263 - e ->
264 - UserAuthData.builder()
265 - .operatorId(e)
266 - .userType(UserTypeEnum.CLIENT)
267 - .build())
268 - .collect(Collectors.toList()));
269 - userAuthData.addAll(
270 - enterpriseOperatorIds.stream()
271 - .map(e -> UserAuthData.builder().operatorId(e).userType(UserTypeEnum.KDS).build())
272 - .collect(Collectors.toList()));
273 - log.info("received userAuthData:{}", JsonUtil.writeAsJson(userAuthData));
274 - try {
275 - WebSocketServer.sendMessageByUserTypes(
276 - List.of(UserTypeEnum.CLIENT, UserTypeEnum.KDS), userAuthData, createOrderData);
277 - } catch (IOException e) {
278 - log.error("Failed to send message to user", e);
279 } 165 }
280 - } 166 + log.info("Order callback, orderId: {}", orderId);
167 +
168 + final var transType = paymentCallbackResult.getTransType();
169 + if (transType.equals("00")) {
170 + if (orderById.getPayStatus() != PayStatusEnum.TO_PAY
171 + && orderById.getPayStatus() != PayStatusEnum.IN_PROGRESS) {
172 + log.error("Order status is not TO_PAY or IN_PROGRESS, orderId: {}", orderId);
173 + return true;
174 + }
175 + long payTime;
176 + try {
177 + payTime =
178 + DateUtil.parseDate(paymentCallbackResult.getTransDate(), "yyyyMMddHHmmss").getTime();
179 + } catch (ParseException e) {
180 + log.error("Failed to parse TransDate: {}", paymentCallbackResult.getTransDate(), e);
181 + throw new IllegalArgumentException("支付时间格式错误: " + paymentCallbackResult.getTransDate(), e);
182 + }
183 + BigDecimal realAmount;
184 + try {
185 + realAmount = Convert.toBigDecimal(paymentCallbackResult.getRealAmount());
186 + if (realAmount == null) {
187 + throw new NumberFormatException("RealAmount is null or empty");
188 + }
189 + } catch (NumberFormatException e) {
190 + log.error("Invalid RealAmount value: {}", paymentCallbackResult.getRealAmount(), e);
191 + throw new IllegalArgumentException("支付金额错误: " + paymentCallbackResult.getRealAmount(), e);
192 + }
193 + final var build =
194 + ClientCustomerOrderModification.newBuilder()
195 + .setId(orderId)
196 + .setShouldUpdatePayTime(true)
197 + .setPayTime(payTime)
198 + .setShouldUpdatePayPrice(true)
199 + .setPayPrice(realAmount.multiply(new BigDecimal("100")).intValue())
200 + .setShouldUpdatePayStatus(true)
201 + .setPayStatus(PayStatusEnum.SUCCEED)
202 + .setShouldUpdateStatus(true)
203 + .setStatus(OrderStatusEnum.PREPARING)
204 + .setShouldUpdateTransactionId(true)
205 + .setTransactionId(paymentCallbackResult.getTradeReferenceNo())
206 + .build();
207 + final var updateResponse =
208 + orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
209 + log.info("callback updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
210 + if (updateResponse.getIsUpdated()) {
211 + String createdAt = Instant.ofEpochMilli(orderById.getCreatedAt())
212 + .atZone(DateUtil.CHINA_ZONE)
213 + .minusHours(8)
214 + .format(DateUtil.Y_M_D_H_M_S);
215 + String payTimed = Instant.ofEpochMilli(orderById.getPayTime())
216 + .atZone(DateUtil.CHINA_ZONE)
217 + .minusHours(8)
218 + .format(DateUtil.Y_M_D_H_M_S);
219 + final var orderPaymentSuccessData =
220 + OrderPaymentSuccessData.builder()
221 + .orderId(orderById.getId())
222 + .orderCode(orderById.getOrderCode())
223 + .createTime(createdAt)
224 + .payTime(payTimed)
225 + .build();
226 + final var data =
227 + SocketMessage.<OrderPaymentSuccessData>builder()
228 + .type(MessageTypeEnum.ORDER)
229 + .noticeType(NoticeTypeEnum.ORDER_PAYMENT_SUCCESS)
230 + .subject(NoticeTypeEnum.ORDER_PAYMENT_SUCCESS.getDescription())
231 + .message("您的订单:" + orderById.getOrderCode() + " 支付成功啦,快去查看吧~")
232 + .data(orderPaymentSuccessData)
233 + .build();
234 + WebSocketServer.sendMessageToUser(
235 + UserSessionKey.builder()
236 + .userId(orderById.getOpenId())
237 + .userType(UserTypeEnum.MICRO)
238 + .build(),
239 + data);
240 + if (LocalDate.now().equals(DateUtil.toLocalDate(orderById.getMealTime()))) {
241 + final var orderCreateSuccessData =
242 + OrderCreateSuccessData.builder().orderId(orderById.getId()).build();
243 + final var createOrderData =
244 + SocketMessage.<OrderCreateSuccessData>builder()
245 + .type(MessageTypeEnum.ORDER)
246 + .noticeType(NoticeTypeEnum.ORDER_CREATED)
247 + .subject(NoticeTypeEnum.ORDER_CREATED.getDescription())
248 + .message("有新的订单下单成功啦,快去查看吧~")
249 + .data(orderCreateSuccessData)
250 + .build();
251 + final var clientOperatorIds =
252 + clientResourceTagServiceRpcClient
253 + .getOperatorIdsByStallIds(List.of(orderById.getStallId())).stream()
254 + .map(SingleResourceLabelEntityRefsResponse::getEntityId)
255 + .distinct()
256 + .collect(Collectors.toList());
257 + final var enterpriseOperatorIds =
258 + enterpriseResourceServiceRpcClient.getOperatorIdsByStallId(
259 + orderById.getEnterpriseId(), orderById.getStallId());
260 + final var userAuthData = new ArrayList<UserAuthData>();
261 + userAuthData.addAll(
262 + clientOperatorIds.stream()
263 + .map(
264 + e ->
265 + UserAuthData.builder()
266 + .operatorId(e)
267 + .userType(UserTypeEnum.CLIENT)
268 + .build())
269 + .collect(Collectors.toList()));
270 + userAuthData.addAll(
271 + enterpriseOperatorIds.stream()
272 + .map(e -> UserAuthData.builder().operatorId(e).userType(UserTypeEnum.KDS).build())
273 + .collect(Collectors.toList()));
274 + log.info("received userAuthData:{}", JsonUtil.writeAsJson(userAuthData));
275 + try {
276 + WebSocketServer.sendMessageByUserTypes(
277 + List.of(UserTypeEnum.CLIENT, UserTypeEnum.KDS), userAuthData, createOrderData);
278 + } catch (IOException e) {
279 + log.error("Failed to send message to user", e);
280 + }
281 + }
282 + }
283 + return updateResponse.getIsUpdated();
284 + } else {
285 + final var build =
286 + ClientCustomerOrderModification.newBuilder()
287 + .setId(orderId)
288 + .setShouldUpdatePayStatus(true)
289 + .setPayStatus(PayStatusEnum.REFUND)
290 + .build();
291 + final var updateResponse =
292 + orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
293 + log.info("callback updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
294 + return updateResponse.getIsUpdated();
295 + }
296 + } catch (JsonProcessingException e) {
297 + log.error("Failed to parse XML response, raw XML: {}", paymentCallbackDTO.getPayResult(), e);
298 + throw new RuntimeException("支付/退款通知结果解析失败", e);
299 + } catch (Exception e) {
300 + log.error("Unexpected error in callback, request: {}", paymentCallbackDTO, e);
301 + throw new RuntimeException("支付/退款通知处理失败", e);
302 + }
303 + }
304 +
305 + public boolean waiting(Integer orderId) {
306 + final var orderById = orderServiceRpcClient.getOrderById(orderId);
307 + if (orderById == null) {
308 + log.error("waiting Order not found, orderId: {}", orderId);
309 + return false;
310 + }
311 + if (orderById.getPayStatus() != PayStatusEnum.TO_PAY) {
312 + log.info("waiting Order {} already processed, skipping.", orderId);
313 + return false;
281 } 314 }
282 - return updateResponse.getIsUpdated();
283 - } else {
284 final var build = 315 final var build =
285 - ClientCustomerOrderModification.newBuilder() 316 + ClientCustomerOrderModification.newBuilder()
286 - .setId(orderId) 317 + .setId(orderId)
287 - .setShouldUpdatePayStatus(true) 318 + .setShouldUpdatePayStatus(true)
288 - .setPayStatus(PayStatusEnum.REFUND) 319 + .setPayStatus(PayStatusEnum.IN_PROGRESS)
289 - .build(); 320 + .build();
290 final var updateResponse = 321 final var updateResponse =
291 - orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build); 322 + orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
292 - log.info("callback updateClientCustomerOrder result: {}", updateResponse.getIsUpdated()); 323 + log.info("waiting updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
293 return updateResponse.getIsUpdated(); 324 return updateResponse.getIsUpdated();
294 - }
295 - } catch (JsonProcessingException e) {
296 - log.error("Failed to parse XML response, raw XML: {}", paymentCallbackDTO.getPayResult(), e);
297 - throw new RuntimeException("支付/退款通知结果解析失败", e);
298 - } catch (Exception e) {
299 - log.error("Unexpected error in callback, request: {}", paymentCallbackDTO, e);
300 - throw new RuntimeException("支付/退款通知处理失败", e);
301 } 325 }
302 - }
303 326
304 - public boolean waiting(Integer orderId) { 327 + public String orderPayRefund(PayRefundRequestDto payRefundRequestDto) {
305 - final var orderById = orderServiceRpcClient.getOrderById(orderId); 328 + Integer orderId = payRefundRequestDto.getOrderId();
306 - if (orderById == null) { 329 + final var orderById = orderServiceRpcClient.getOrderById(orderId);
307 - log.error("waiting Order not found, orderId: {}", orderId); 330 + if (orderById == null) {
308 - return false; 331 + log.error("Order not found, orderId: {}", orderId);
309 - } 332 + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_FOUND);
310 - if (orderById.getPayStatus() != PayStatusEnum.TO_PAY) { 333 + }
311 - log.info("waiting Order {} already processed, skipping.", orderId); 334 + if (orderById.getOnlinePay() != OnlinePayEnum.ONLINE) {
312 - return false; 335 + log.info("Order {} is not online pay.", orderId);
313 - } 336 + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_ONLINE_PAY);
314 - final var build = 337 + }
315 - ClientCustomerOrderModification.newBuilder() 338 + if (orderById.getPayStatus() != PayStatusEnum.SUCCEED) {
316 - .setId(orderId) 339 + log.info("Order {} pay is not succeed.", orderId);
317 - .setShouldUpdatePayStatus(true) 340 + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_SUCCESS);
318 - .setPayStatus(PayStatusEnum.IN_PROGRESS) 341 + }
319 - .build(); 342 + LocalDate today = LocalDate.now();
320 - final var updateResponse = 343 + LocalDate tomorrow = today.plusDays(1);
321 - orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build); 344 + LocalDateTime tomorrowZero = tomorrow.atStartOfDay();
322 - log.info("waiting updateClientCustomerOrder result: {}", updateResponse.getIsUpdated()); 345 + LocalDateTime orderPayTime = DateUtil.toLocalDateTime(orderById.getPayTime()).minusHours(8);
323 - return updateResponse.getIsUpdated(); 346 + if (!orderPayTime.isBefore(tomorrowZero)) {
324 - } 347 + log.info("Order {} pay is beyond cancel time.", orderId);
325 - 348 + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
326 - public String orderPayRefund(PayRefundRequestDto payRefundRequestDto) { 349 + }
327 - Integer orderId = payRefundRequestDto.getOrderId(); 350 + BigDecimal detailPrice = BigDecimal.ZERO;
328 - final var orderById = orderServiceRpcClient.getOrderById(orderId); 351 + if (CollectionUtils.isNotEmpty(payRefundRequestDto.getOrderDetailIds())) {
329 - if (orderById == null) { 352 + final var orderDetails = orderServiceRpcClient.getClientCustomerOrderDetailsByIds(payRefundRequestDto.getOrderDetailIds());
330 - log.error("Order not found, orderId: {}", orderId); 353 + detailPrice = orderDetails.stream().filter(e -> e.getPrice() > 0).map(e -> new BigDecimal(e.getPrice()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)).reduce(BigDecimal.ZERO, BigDecimal::add);
331 - throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_FOUND); 354 + }
332 - }
333 - if (orderById.getOnlinePay() != OnlinePayEnum.ONLINE) {
334 - log.info("Order {} is not online pay.", orderId);
335 - throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_ONLINE_PAY);
336 - }
337 - if (orderById.getPayStatus() != PayStatusEnum.SUCCEED) {
338 - log.info("Order {} pay is not succeed.", orderId);
339 - throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_SUCCESS);
340 - }
341 - LocalDate today = LocalDate.now();
342 - LocalDate tomorrow = today.plusDays(1);
343 - LocalDateTime tomorrowZero = tomorrow.atStartOfDay();
344 - LocalDateTime orderPayTime = DateUtil.toLocalDateTime(orderById.getPayTime()).minusHours(8);
345 - if (!orderPayTime.isBefore(tomorrowZero)) {
346 - log.info("Order {} pay is beyond cancel time.", orderId);
347 - throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
348 - }
349 355
350 - String appId = businessConfig.getPayClientId(); 356 + String appId = businessConfig.getPayClientId();
351 357
352 - // 构建paycontent 358 + // 构建paycontent
353 - String payTime = Instant.ofEpochMilli(orderById.getPayTime()) 359 + String payTime = Instant.ofEpochMilli(orderById.getPayTime())
354 - .atZone(DateUtil.CHINA_ZONE) 360 + .atZone(DateUtil.CHINA_ZONE)
355 - .minusHours(8) 361 + .minusHours(8)
356 - .format(DateUtil.YMDHMS); 362 + .format(DateUtil.YMDHMS);
357 363
358 - BigDecimal price = 364 + BigDecimal price = detailPrice.compareTo(BigDecimal.ZERO) == 0 ?
359 - new BigDecimal(orderById.getPayPrice()) 365 + new BigDecimal(orderById.getPayPrice()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).negate()
360 - .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).negate(); 366 + : detailPrice.negate();
361 367
362 - String payContentStr = 368 + String payContentStr =
363 - orderById.getId() 369 + orderById.getId()
364 - + "^" 370 + + "^"
365 - + "01" 371 + + "01"
366 - + "^" 372 + + "^"
367 - + "^" 373 + + "^"
368 - + orderById.getOpenId() 374 + + orderById.getOpenId()
369 - + "^" 375 + + "^"
370 - + orderById.getOrderCode() 376 + + orderById.getOrderCode()
371 - + "^" 377 + + "^"
372 - + price 378 + + price
373 - + "^" 379 + + "^"
374 - + payTime 380 + + payTime
375 - + "^" 381 + + "^"
376 - + orderById.getTransactionId() 382 + + orderById.getTransactionId()
377 - + "^" 383 + + "^"
378 - + payRefundRequestDto.getHospitalCode() 384 + + payRefundRequestDto.getHospitalCode()
379 - + "^" 385 + + "^"
380 - + "^" 386 + + "^"
381 - + LoginContextHolder.getId() 387 + + LoginContextHolder.getId()
382 - + "^" 388 + + "^"
383 - + LoginContextHolder.getName(); 389 + + LoginContextHolder.getName();
384 - String payContent = 390 + String payContent =
385 - URLEncoder.encode( 391 + URLEncoder.encode(
386 - Base64.encodeBase64String(payContentStr.getBytes()), StandardCharsets.UTF_8); 392 + Base64.encodeBase64String(payContentStr.getBytes()), StandardCharsets.UTF_8);
387 393
388 - // 构建signinfo 394 + // 构建signinfo
389 - String signInfoStr = appId + orderById.getId() + payTime + businessConfig.getRefundSecurityKey(); 395 + String signInfoStr = appId + orderById.getId() + payTime + businessConfig.getRefundSecurityKey();
390 - String signInfo = DigestUtils.sha1Hex(signInfoStr.getBytes()); 396 + String signInfo = DigestUtils.sha1Hex(signInfoStr.getBytes());
391 397
392 - // 构建请求 398 + // 构建请求
393 - try { 399 + try {
394 - String url = businessConfig.getCancelPayUrl() + "?" + "appid=" + appId + "&paycontent=" + payContent + "&signinfo=" + signInfo; 400 + String url = businessConfig.getCancelPayUrl() + "?" + "appid=" + appId + "&paycontent=" + payContent + "&signinfo=" + signInfo;
395 - log.info("cancel order pay url:{}", url); 401 + log.info("cancel order pay url:{}", url);
396 // Request request = 402 // Request request =
397 // new Request.Builder().url(url).get().build(); 403 // new Request.Builder().url(url).get().build();
398 // Response payResponse = client.newCall(request).execute(); 404 // Response payResponse = client.newCall(request).execute();
...@@ -400,10 +406,10 @@ public class PayServiceClient { ...@@ -400,10 +406,10 @@ public class PayServiceClient {
400 // throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED); 406 // throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
401 // } 407 // }
402 // String htmlContent = payResponse.body().string(); 408 // String htmlContent = payResponse.body().string();
403 - return url; 409 + return url;
404 - } catch (Exception e) { 410 + } catch (Exception e) {
405 - log.error(e.getMessage()); 411 + log.error(e.getMessage());
406 - throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED); 412 + throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
413 + }
407 } 414 }
408 - }
409 } 415 }
......
...@@ -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)
443 - .map(SingleClientCustomerOrderRpcResponse::getCustomerId)
444 - .filter(id -> id != 0)
445 - .distinct()
446 - .collect(Collectors.toList());
447 -
448 final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds); 837 final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds);
449 - final List<SingleClientCustomerRpcResponse> customers = customerResponse != null ? customerResponse.getResponsesList() : new ArrayList<>(); 838 + final List<SingleClientCustomerRpcResponse> customers = customerResponse.getResponsesList();
450 - final var customerMap = customers.stream() 839 + final var customerMap = customers.stream().collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1));
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,76 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -473,52 +855,76 @@ 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.getOrDefault(orderId, Collections.emptyList());
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 + Map<Integer, OrderDetailBO> replaceAdjustDetailMap = orderOperationRecords.stream()
489 - String roomNo = getRoomNoSafely(order); 873 + .filter(e -> e.getType() == OrderOperationType.REPLACE_DISHES)
874 + .flatMap(e -> JsonUtil.readJsonAs(e.getAdjustOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {
875 + }).stream())
876 + .collect(Collectors.toMap(OrderDetailBO::getId, Function.identity(), (a, b) -> a));
490 877
491 - // 安全获取忌口和医嘱 878 + for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) {
492 - List<String> avoids = getAvoidsSafely(order); 879 + // 1. 先处理加餐
493 - List<String> doctors = getDoctorsSafely(order); 880 + if (addOriginalDetailMap.containsKey(orderDetail.getId())
881 + && addOriginalDetailMap.get(orderDetail.getId()).getCount() != orderDetail.getCount()) {
882 + final var orderDetailBO = addOriginalDetailMap.get(orderDetail.getId());
883 + SettlementDTO.SettlementOrderDetail beforeChange = buildSettlementOrderDetail(
884 + order, orderDetail.getMenuDetailId(), orderDetailBO.getSkuId(), orderDetailBO.getCount(), orderDetail.getPrice(), "订餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
885 + classifyOrders.add(beforeChange);
886 + SettlementDTO.SettlementOrderDetail afterChange = buildSettlementOrderDetail(
887 + order, orderDetail.getMenuDetailId(), orderDetailBO.getSkuId(), orderDetail.getCount() - orderDetailBO.getCount(), orderDetail.getPrice(), "加餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
888 + classifyOrders.add(afterChange);
889 + }
494 890
495 - // 安全获取在线支付描述 891 + // 2. 再处理换菜
496 - String onlinePayDesc = getOnlinePayDescSafely(order); 892 + if (replaceOriginalDetailMap.containsKey(orderDetail.getId())
893 + && !Objects.equals(replaceOriginalDetailMap.get(orderDetail.getId()).getSkuId(), orderDetail.getSkuId())) {
894 + final var orderDetailBO = replaceOriginalDetailMap.get(orderDetail.getId());
895 + final var orderDetailAdjustBO = replaceAdjustDetailMap.get(orderDetail.getId());
896 + SettlementDTO.SettlementOrderDetail beforeChange = buildSettlementOrderDetail(
897 + order, orderDetail.getMenuDetailId(), orderDetailBO.getSkuId(), orderDetailBO.getCount(), orderDetailBO.getPrice(), "换菜前", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
898 + classifyOrders.add(beforeChange);
899 + SettlementDTO.SettlementOrderDetail afterChange = buildSettlementOrderDetail(
900 + order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetailAdjustBO.getPrice(), "换菜后", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
901 + classifyOrders.add(afterChange);
902 + }
497 903
498 - // 构建订单详情 904 + // 3. 判断已退款
499 - order.getOrderCode(); 905 + if (orderDetail.getServeStatus() == ServeStatusEnum.SERVE_REJECT) {
500 - order.getRemark(); 906 + SettlementDTO.SettlementOrderDetail refundRecord1 = buildSettlementOrderDetail(
501 - order.getAvoidRemark(); 907 + order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "订餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
502 - SettlementDTO.SettlementOrderDetail settlementOrderDetail = SettlementDTO.SettlementOrderDetail.builder() 908 + classifyOrders.add(refundRecord1);
503 - .mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "") 909 + SettlementDTO.SettlementOrderDetail refundRecord2 = buildSettlementOrderDetail(
504 - .code(order.getOrderCode()) 910 + order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), -orderDetail.getCount(), orderDetail.getPrice(), "已退款", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
505 - .mealName(mealName) 911 + classifyOrders.add(refundRecord2);
506 - .roomNo(roomNo) 912 + }
507 - .customerName(customerName) 913 +
508 - .HISCustomerNo(hisCustomerNo) 914 + // 4. 如果既不是加餐,也不是换菜,也不是退款,才记录“订餐”
509 - .avoids(avoids) 915 + boolean isNormal = !(addOriginalDetailMap.containsKey(orderDetail.getId())
510 - .doctors(doctors) 916 + && addOriginalDetailMap.get(orderDetail.getId()).getCount() != orderDetail.getCount())
511 - .menuName(menuName) 917 + && !(replaceOriginalDetailMap.containsKey(orderDetail.getId())
512 - .skuName(skuName) 918 + && !Objects.equals(replaceOriginalDetailMap.get(orderDetail.getId()).getSkuId(), orderDetail.getSkuId()))
513 - .count(orderDetail.getCount() != 0 ? orderDetail.getCount() : 0) 919 + && orderDetail.getServeStatus() != ServeStatusEnum.SERVE_REJECT;
514 - .price(calculatePrice(orderDetail.getPrice())) 920 +
515 - .totalPrice(calculateTotalPrice(orderDetail.getPrice(), orderDetail.getCount())) 921 + if (isNormal) {
516 - .remark(order.getRemark()) 922 + SettlementDTO.SettlementOrderDetail normalRecord = buildSettlementOrderDetail(
517 - .avoidRemark(order.getAvoidRemark()) 923 + order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "订餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
518 - .onlinePay(onlinePayDesc) 924 + classifyOrders.add(normalRecord);
519 - .build(); 925 + }
520 - classifyOrders.add(settlementOrderDetail);
521 } 926 }
927 +
522 } 928 }
523 929
524 // 构建结算数据 930 // 构建结算数据
...@@ -535,17 +941,57 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -535,17 +941,57 @@ public class SettlementServiceImpl implements SettlementService {
535 } 941 }
536 } 942 }
537 943
944 + private SettlementDTO.SettlementOrderDetail buildSettlementOrderDetail(SingleClientCustomerOrderRpcResponse order,
945 + int menuDetailId,
946 + int skuId,
947 + int count,
948 + Integer price,
949 + String operationType,
950 + String menuName,
951 + String customerName,
952 + String hisCustomerNo,
953 + Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
954 + Map<Integer, SingleMealRpcResponse> mealMap,
955 + Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
956 + String mealName = getMealNameSafely(menuDetailId, menuDetailMap, mealMap);
957 + String skuName = getSkuNameSafely(skuId, skuMap);
958 + String roomNo = getRoomNoSafely(order);
959 + List<String> avoids = getAvoidsSafely(order);
960 + List<String> doctors = getDoctorsSafely(order);
961 + String onlinePayDesc = getOnlinePayDescSafely(order);
962 + return SettlementDTO.SettlementOrderDetail.builder()
963 + .mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "")
964 + .code(order.getOrderCode())
965 + .mealName(mealName)
966 + .roomNo(roomNo)
967 + .customerName(customerName)
968 + .HISCustomerNo(hisCustomerNo)
969 + .avoids(avoids)
970 + .doctors(doctors)
971 + .menuName(menuName)
972 + .skuName(skuName)
973 + .count(count)
974 + .price(calculatePrice(price))
975 + .totalPrice(calculateTotalPrice(price, count))
976 + .remark(order.getRemark())
977 + .avoidRemark(order.getAvoidRemark())
978 + .onlinePay(onlinePayDesc)
979 + .operationType(operationType)
980 + .transactionId(operationType.equals("已退款") ? "" : order.getTransactionId())
981 + .build();
982 + }
983 +
538 /** 984 /**
539 * 安全获取餐别名称 985 * 安全获取餐别名称
540 */ 986 */
541 - private String getMealNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail, 987 + private String getMealNameSafely(int menuDetailId,
542 - Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap, 988 + Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
543 - Map<Integer, SingleMealRpcResponse> mealMap) { 989 + Map<Integer, SingleMealRpcResponse> mealMap) {
544 - if (orderDetail == null || orderDetail.getMenuDetailId() == 0) { 990 + if (menuDetailId == 0) {
545 return ""; 991 return "";
546 } 992 }
547 993
548 - final var menuDetail = menuDetailMap.get(orderDetail.getMenuDetailId()); 994 + final var menuDetail = menuDetailMap.get(menuDetailId);
549 if (menuDetail == null || menuDetail.getMealId() == 0) { 995 if (menuDetail == null || menuDetail.getMealId() == 0) {
550 return ""; 996 return "";
551 } 997 }
...@@ -557,13 +1003,12 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -557,13 +1003,12 @@ public class SettlementServiceImpl implements SettlementService {
557 /** 1003 /**
558 * 安全获取SKU名称 1004 * 安全获取SKU名称
559 */ 1005 */
560 - private String getSkuNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail, 1006 + private String getSkuNameSafely(int skuId,
561 - Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) { 1007 + Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
562 - if (orderDetail == null || orderDetail.getSkuId() == 0) { 1008 + if (skuId == 0) {
563 return ""; 1009 return "";
564 } 1010 }
565 - 1011 + final var sku = skuMap.get(skuId);
566 - final var sku = skuMap.get(orderDetail.getSkuId());
567 return sku != null ? sku.getName() : ""; 1012 return sku != null ? sku.getName() : "";
568 } 1013 }
569 1014
...@@ -598,268 +1043,65 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -598,268 +1043,65 @@ public class SettlementServiceImpl implements SettlementService {
598 * 安全获取医嘱列表 1043 * 安全获取医嘱列表
599 */ 1044 */
600 private List<String> getDoctorsSafely(SingleClientCustomerOrderRpcResponse order) { 1045 private List<String> getDoctorsSafely(SingleClientCustomerOrderRpcResponse order) {
601 - if (order == null) { 1046 + if (order == null) {
602 - return Collections.emptyList(); 1047 + return Collections.emptyList();
603 - } 1048 + }
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 1049
831 - // 合并备注和忌口备注,用分号分割,备注在前 1050 + return order.getCustomerNoticeJson().getDoctorsList();
832 - String remark = orderDetail.getRemark() != null ? orderDetail.getRemark() : ""; 1051 + }
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 1052
846 - Cell dataCell14 = dataRow.createCell(columnNum++); 1053 + /**
847 - dataCell14.setCellValue(orderDetail.getOnlinePay() != null ? orderDetail.getOnlinePay() : ""); 1054 + * 安全获取在线支付描述
848 - dataCell14.setCellStyle(dataStyle); 1055 + */
849 - } 1056 + private String getOnlinePayDescSafely(SingleClientCustomerOrderRpcResponse order) {
1057 + if (order == null) {
1058 + return "";
850 } 1059 }
851 1060
852 - // 自动调整列宽 1061 + try {
853 - for (int i = 0; i < 15; i++) { 1062 + String desc = BaseProtoDescEnum.getDescByProtoEnum(order.getOnlinePay(), OnlinePayDescEnum.class);
854 - sheet.autoSizeColumn(i); 1063 + return desc != null ? desc : "";
1064 + } catch (Exception e) {
1065 + log.warn("获取在线支付描述失败,orderId: {}", order.getId(), e);
1066 + return "";
855 } 1067 }
1068 + }
856 1069
857 - // 将工作簿内容写入字节数组输出流 1070 + /**
858 - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 1071 + * 计算单价
859 - workbook.write(outputStream); 1072 + */
860 - workbook.close(); 1073 + private BigDecimal calculatePrice(Integer price) {
1074 + if (price == null) {
1075 + return BigDecimal.ZERO;
1076 + }
1077 + return new BigDecimal(price).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
1078 + }
861 1079
862 - return outputStream; 1080 + /**
1081 + * 计算总价
1082 + */
1083 + private BigDecimal calculateTotalPrice(Integer price, Integer count) {
1084 + if (price == null || count == null) {
1085 + return BigDecimal.ZERO;
1086 + }
1087 + return new BigDecimal(price)
1088 + .multiply(new BigDecimal(count))
1089 + .divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
1090 + }
1091 +
1092 + /**
1093 + * 创建空的订单Excel
1094 + */
1095 + private ByteArrayOutputStream createEmptyExcelByOrder() {
1096 + try {
1097 + final var emptyData = SettlementDTO.SettlementDataByOrderDto.builder()
1098 + .classifyOrders(Collections.emptyList())
1099 + .build();
1100 + return writeToExcelByOrder(emptyData);
1101 + } catch (IOException e) {
1102 + log.error("创建空Excel失败", e);
1103 + throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
1104 + }
863 } 1105 }
864 1106
865 public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) { 1107 public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) {
...@@ -1249,10 +1491,10 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -1249,10 +1491,10 @@ public class SettlementServiceImpl implements SettlementService {
1249 } 1491 }
1250 1492
1251 // 安全获取餐别名称 1493 // 安全获取餐别名称
1252 - String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap); 1494 + String mealName = getMealNameSafely(orderDetail.getMenuDetailId(), menuDetailMap, mealMap);
1253 1495
1254 // 安全获取SKU名称 1496 // 安全获取SKU名称
1255 - String skuName = getSkuNameSafely(orderDetail, skuMap); 1497 + String skuName = getSkuNameSafely(orderDetail.getSkuId(), skuMap);
1256 1498
1257 // 安全获取忌口信息(列表转字符串) 1499 // 安全获取忌口信息(列表转字符串)
1258 List<String> avoidsList = getAvoidsSafely(order); 1500 List<String> avoidsList = getAvoidsSafely(order);
...@@ -1304,186 +1546,4 @@ public class SettlementServiceImpl implements SettlementService { ...@@ -1304,186 +1546,4 @@ public class SettlementServiceImpl implements SettlementService {
1304 } 1546 }
1305 } 1547 }
1306 1548
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 } 1549 }
......
...@@ -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;
......