zhuyifan

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

......@@ -60,4 +60,5 @@ public class PayController {
public String cancel(@Valid @RequestBody PayDTO.PayRefundRequestDto payRefundRequestDto) {
return payServiceClient.orderPayRefund(payRefundRequestDto);
}
}
\ No newline at end of file
......
package com.infoloop.tianting.model.bo;
import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum;
import lombok.Data;
@Data
public class OrderDetailBO {
private int id;
public int skuId;
private String skuName;
private Integer price;
private int count;
private String adjustSkuRemark;
private ServeStatusEnum serveStatus;
}
......@@ -520,6 +520,7 @@ public class OrderDbDTO {
private Integer count;
private String adjustSkuRemark;
private String serveStatus;
private Integer price;
}
......@@ -730,6 +731,10 @@ public class OrderDbDTO {
@Builder.Default
private Boolean shouldUpdateServeStatus = false;
@ApiModelProperty(value = "价格")
@Builder.Default
private Integer price = null;
@ApiModelProperty(value = "出餐状态: 默认未出餐=1; 不出餐=2; 已出餐=3")
@Builder.Default
private ServeStatusEnum serveStatus = ServeStatusEnum.SERVE_NOT_START;
......
......@@ -9,6 +9,8 @@ import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@ApiModel(description = "支付DTO")
public class PayDTO {
......@@ -31,6 +33,7 @@ public class PayDTO {
@AllArgsConstructor
public static class PayRefundRequestDto {
private Integer orderId;
private List<Integer> orderDetailIds;
private String hospitalCode;
}
......
......@@ -18,6 +18,9 @@ public class PaymentCallbackResult {
@JacksonXmlProperty(localName = "TransSN")
private String transSN;
@JacksonXmlProperty(localName = "TradeReferenceNo")
private String tradeReferenceNo;
@JacksonXmlProperty(localName = "TransType")
private String transType;
......
......@@ -103,6 +103,8 @@ public class SettlementDTO {
private String remark;
private String avoidRemark;
private String onlinePay;
private String operationType;
private String transactionId;
}
@Data
......
......@@ -22,6 +22,8 @@ import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderBy
import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByIdsRpcRequest;
import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrderDetailsByOrderIdsRpcRequest;
import com.infoloop.tianting.clientcustomerorderservice.GetClientCustomerOrdersByCustomerIdRpcRequest;
import com.infoloop.tianting.clientcustomerorderservice.GetOrderOperationRecordsByOrderIdsRequest;
import com.infoloop.tianting.clientcustomerorderservice.GetOrderOperationRecordsByOrderIdsResponse;
import com.infoloop.tianting.clientcustomerorderservice.MealDetail;
import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum;
import com.infoloop.tianting.clientcustomerorderservice.OrderOperationRecordCreation;
......@@ -240,8 +242,10 @@ public class OrderServiceRpcClient {
final var operator = operatorServiceRpcClient.getCOperatorById(operatorLoginInfo.getId());
final var idsOfNeedUpdateMenuDetails = new ArrayList<Integer>();
final var idsOfAddCount = new ArrayList<Integer>();
final var idsOfNoReject = new ArrayList<Integer>();
List<OrderDetailDto> originalOrderDetails = new ArrayList<>();
List<OrderDetailDto> newOrderDetails;
final var orderDetailsMap = orderDetailBatchUpdateDto.getDetails().stream().collect(Collectors.toMap(OrderDbDTO.OrderDetailUpdateDto::getId, Function.identity()));
final var modifications = orderDetailBatchUpdateDto.getDetails().stream().map(d -> {
var mealDetail = MealDetail.newBuilder().build();
Integer menuDetailId = 0;
......@@ -280,9 +284,11 @@ public class OrderServiceRpcClient {
.build();
}
}
ServeStatusEnum serveStatus = ServeStatusEnum.UNKNOWN_SERVE_STATUS;
if (d.getShouldUpdateServeStatus()) {
if (d.getServeStatus() == ServeStatusEnum.SERVE_REJECT) {
idsOfNoReject.add(d.getId());
}
serveStatus = d.getServeStatus();
}
Integer count = 0;
......@@ -319,7 +325,8 @@ public class OrderServiceRpcClient {
.build();
final var totalIds = new ArrayList<>(idsOfNeedUpdateMenuDetails);
totalIds.addAll(idsOfAddCount);
if (!idsOfNeedUpdateMenuDetails.isEmpty() || !idsOfAddCount.isEmpty()) {
totalIds.addAll(idsOfNoReject);
if (!totalIds.isEmpty()) {
final var orgionalResponseList = getClientCustomerOrderDetailsByIds(totalIds);
originalOrderDetails = orgionalResponseList.stream().map(d -> OrderDetailDto.builder()
.id(d.getId())
......@@ -357,7 +364,7 @@ public class OrderServiceRpcClient {
}
final var res = orderServiceRpcBlockingStub.batchUpdateClientCustomerOrderDetails(request);
if (res.getIsUpdated()) {
if (!idsOfNeedUpdateMenuDetails.isEmpty() || !idsOfAddCount.isEmpty()) {
if (!totalIds.isEmpty()) {
final var newResponseList = getClientCustomerOrderDetailsByIds(totalIds);
newOrderDetails = newResponseList.stream().map(d ->
OrderDetailDto.builder()
......@@ -392,15 +399,21 @@ public class OrderServiceRpcClient {
.updateSource(d.getUpdateSource().getNumber())
.updatedAt(DateUtil.formatDate(d.getUpdatedAt()))
.updatedBy(d.getUpdatedBy())
.build()).collect(Collectors.toList());
.build()).toList();
// 替换菜品的操作记录
List<SingleOperationDto> operations = new ArrayList<>();
for (OrderDetailDto originalDetail : originalOrderDetails) {
if (!totalIds.contains(originalDetail.getId())) {
continue;
}
final var orderDetailUpdateDto = orderDetailsMap.get(originalDetail.getId());
OrderOperationType orderOperationType = OrderOperationType.UNKNOWN_OPERATION_TYPE;
if (idsOfNeedUpdateMenuDetails.contains(originalDetail.getId())) {
orderOperationType = OrderOperationType.REPLACE_DISHES;
} else if (idsOfAddCount.contains(originalDetail.getId())) {
orderOperationType = OrderOperationType.ADD_DISHES;
} else if (idsOfNoReject.contains(originalDetail.getId())) {
orderOperationType = OrderOperationType.NOT_SERVE;
}
String originalDetailStr;
String newDetailStr = "";
......@@ -413,6 +426,7 @@ public class OrderServiceRpcClient {
.count(newDetail.get().getCount())
.adjustSkuRemark(newDetail.get().getAdjustSkuRemark())
.serveStatus(newDetail.get().getServeStatus().name())
.price(orderDetailUpdateDto.getPrice() == null ? newDetail.get().getPrice() : orderDetailUpdateDto.getPrice())
.build();
newDetailStr = JsonUtil.writeAsJson(List.of(newOrderDetailOperation));
}
......@@ -423,6 +437,7 @@ public class OrderServiceRpcClient {
.count(originalDetail.getCount())
.adjustSkuRemark(originalDetail.getAdjustSkuRemark())
.serveStatus(originalDetail.getServeStatus().name())
.price(originalDetail.getPrice())
.build();
originalDetailStr = JsonUtil.writeAsJson(List.of(originalOrderDetailOperation));
final var operation = SingleOperationDto.builder()
......@@ -471,7 +486,6 @@ public class OrderServiceRpcClient {
.setCreationSource(batchOperationDto.getCreationSource())
.build();
return orderServiceRpcBlockingStub.batchCreateOrderOperationRecords(request);
}
public QueryClientCustomerOrdersByPaginationRpcResponse queryClientCustomerOrdersByPagination(QueryOrderByPaginationDto queryOrderDto) {
......@@ -489,6 +503,14 @@ public class OrderServiceRpcClient {
return orderServiceRpcBlockingStub.queryClientCustomerOrdersByPagination(request);
}
public GetOrderOperationRecordsByOrderIdsResponse getOrderOperationRecordsByOrderIds(int enterpriseId, List<Integer> orderIds) {
final var request = GetOrderOperationRecordsByOrderIdsRequest.newBuilder()
.setEnterpriseId(enterpriseId)
.addAllOrderIds(orderIds)
.build();
return orderServiceRpcBlockingStub.getOrderOperationRecordsByOrderIds(request);
}
public QueryClientCustomerOrdersByConditionRpcResponse queryClientCustomerOrdersByCondition(OrderDbDTO.QueryOrderDto queryOrderDto) {
final var request = QueryClientCustomerOrdersByConditionRpcRequest.newBuilder()
.setShouldFilterStatus(true)
......
......@@ -38,6 +38,8 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
......@@ -66,333 +68,338 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class PayServiceClient {
private final RestTemplate restTemplate;
private final RestTemplate restTemplate;
private final BusinessConfig businessConfig;
private final BusinessConfig businessConfig;
private final OrderServiceRpcClient orderServiceRpcClient;
private final OrderServiceRpcClient orderServiceRpcClient;
private final ClientResourceTagServiceRpcClient clientResourceTagServiceRpcClient;
private final ClientResourceTagServiceRpcClient clientResourceTagServiceRpcClient;
private final EnterpriseResourceServiceRpcClient enterpriseResourceServiceRpcClient;
private final EnterpriseResourceServiceRpcClient enterpriseResourceServiceRpcClient;
private final XmlMapper xmlMapper = new XmlMapper();
private final XmlMapper xmlMapper = new XmlMapper();
public PayResponseDto payInform(PayInformRequestDto payRequestDto) {
final var orderById =
orderServiceRpcClient.getOrderById(Integer.valueOf(payRequestDto.getOrderId()));
if (orderById == null
|| orderById.getPayStatus() == PayStatusEnum.PAY_CANCELED
|| orderById.getStatus() == OrderStatusEnum.ORDER_CANCELED) {
log.info("Order {} not found or canceled, skipping.", payRequestDto.getOrderId());
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_CANCEL);
}
String url = MessageFormat.format(businessConfig.getPayUrl(), businessConfig.getPayClientId());
String requestDate = DateUtil.formatDate(LocalDateTime.now(), DateUtil.YMDHMS);
ThirdPartyPayInformRequestDto jsonData = buildRequestData(payRequestDto, requestDate);
String jsonDataString;
try {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.UpperCamelCaseStrategy());
jsonDataString = objectMapper.writeValueAsString(jsonData);
} catch (JsonProcessingException e) {
log.error("Failed to serialize request data", e);
throw new IllegalArgumentException("支付信息获取失败: JSON 解析错误");
public PayResponseDto payInform(PayInformRequestDto payRequestDto) {
final var orderById =
orderServiceRpcClient.getOrderById(Integer.valueOf(payRequestDto.getOrderId()));
if (orderById == null
|| orderById.getPayStatus() == PayStatusEnum.PAY_CANCELED
|| orderById.getStatus() == OrderStatusEnum.ORDER_CANCELED) {
log.info("Order {} not found or canceled, skipping.", payRequestDto.getOrderId());
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_CANCEL);
}
String url = MessageFormat.format(businessConfig.getPayUrl(), businessConfig.getPayClientId());
String requestDate = DateUtil.formatDate(LocalDateTime.now(), DateUtil.YMDHMS);
ThirdPartyPayInformRequestDto jsonData = buildRequestData(payRequestDto, requestDate);
String jsonDataString;
try {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.UpperCamelCaseStrategy());
jsonDataString = objectMapper.writeValueAsString(jsonData);
} catch (JsonProcessingException e) {
log.error("Failed to serialize request data", e);
throw new IllegalArgumentException("支付信息获取失败: JSON 解析错误");
}
HttpEntity<String> requestEntity = new HttpEntity<>(jsonDataString, createHeaders());
log.info("payInform request: {}", jsonDataString);
ResponseEntity<String> responseEntity =
restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
return processResponse(responseEntity);
}
HttpEntity<String> requestEntity = new HttpEntity<>(jsonDataString, createHeaders());
log.info("payInform request: {}", jsonDataString);
ResponseEntity<String> responseEntity =
restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);
return processResponse(responseEntity);
}
private ThirdPartyPayInformRequestDto buildRequestData(
PayInformRequestDto payRequestDto, String requestDate) {
ThirdPartyPayInformRequestDto jsonData = new ThirdPartyPayInformRequestDto();
jsonData.setClientId(businessConfig.getPayClientId());
jsonData.setTradeId(payRequestDto.getOrderId());
jsonData.setRequestDate(requestDate);
jsonData.setRequestSource("OFWXApplet");
jsonData.setPayerOpenId(LoginContextHolder.getOpenId());
jsonData.setHospitalCode(payRequestDto.getHospitalCode());
jsonData.setPID(LoginContextHolder.getOpenId());
jsonData.setRemark("");
jsonData.setTransAmount(payRequestDto.getPrice());
jsonData.setTradeDesc("");
jsonData.setSign(
EncryptionUtil.sha1Encryption(
businessConfig.getPayClientId()
+ payRequestDto.getOrderId()
+ requestDate
+ businessConfig.getPayClientId()));
return jsonData;
}
private HttpHeaders createHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
private PayResponseDto processResponse(ResponseEntity<String> responseEntity) {
if (!responseEntity.getStatusCode().is2xxSuccessful() || responseEntity.getBody() == null) {
log.error("payInform failed with response: {}", responseEntity.getBody());
throw new IllegalArgumentException("支付信息获取失败");
}
try {
log.info("processResponse response: {}", responseEntity.getBody());
return xmlMapper.readValue(responseEntity.getBody(), PayResponseDto.class);
} catch (Exception e) {
log.error("Failed to parse XML response", e);
throw new RuntimeException("支付信息结果解析失败", e);
private ThirdPartyPayInformRequestDto buildRequestData(
PayInformRequestDto payRequestDto, String requestDate) {
ThirdPartyPayInformRequestDto jsonData = new ThirdPartyPayInformRequestDto();
jsonData.setClientId(businessConfig.getPayClientId());
jsonData.setTradeId(payRequestDto.getOrderId());
jsonData.setRequestDate(requestDate);
jsonData.setRequestSource("OFWXApplet");
jsonData.setPayerOpenId(LoginContextHolder.getOpenId());
jsonData.setHospitalCode(payRequestDto.getHospitalCode());
jsonData.setPID(LoginContextHolder.getOpenId());
jsonData.setRemark("");
jsonData.setTransAmount(payRequestDto.getPrice());
jsonData.setTradeDesc("");
jsonData.setSign(
EncryptionUtil.sha1Encryption(
businessConfig.getPayClientId()
+ payRequestDto.getOrderId()
+ requestDate
+ businessConfig.getPayClientId()));
return jsonData;
}
}
public boolean callback(PaymentCallbackDTO paymentCallbackDTO) {
log.info("callback request received: {}", paymentCallbackDTO);
try {
final var paymentCallbackResult =
xmlMapper.readValue(paymentCallbackDTO.getPayResult(), PaymentCallbackResult.class);
log.info("Parsed paymentCallbackResult: {}", paymentCallbackResult);
final var orderId = Integer.parseInt(paymentCallbackResult.getTradeId());
final var orderById = orderServiceRpcClient.getOrderById(orderId);
if (orderById == null) {
log.error("Order not found, orderId: {}", orderId);
return false;
}
log.info("Order callback, orderId: {}", orderId);
private HttpHeaders createHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
final var transType = paymentCallbackResult.getTransType();
if (transType.equals("00")) {
if (orderById.getPayStatus() != PayStatusEnum.TO_PAY
&& orderById.getPayStatus() != PayStatusEnum.IN_PROGRESS) {
log.error("Order status is not TO_PAY or IN_PROGRESS, orderId: {}", orderId);
return true;
private PayResponseDto processResponse(ResponseEntity<String> responseEntity) {
if (!responseEntity.getStatusCode().is2xxSuccessful() || responseEntity.getBody() == null) {
log.error("payInform failed with response: {}", responseEntity.getBody());
throw new IllegalArgumentException("支付信息获取失败");
}
long payTime;
try {
payTime =
DateUtil.parseDate(paymentCallbackResult.getTransDate(), "yyyyMMddHHmmss").getTime();
} catch (ParseException e) {
log.error("Failed to parse TransDate: {}", paymentCallbackResult.getTransDate(), e);
throw new IllegalArgumentException("支付时间格式错误: " + paymentCallbackResult.getTransDate(), e);
log.info("processResponse response: {}", responseEntity.getBody());
return xmlMapper.readValue(responseEntity.getBody(), PayResponseDto.class);
} catch (Exception e) {
log.error("Failed to parse XML response", e);
throw new RuntimeException("支付信息结果解析失败", e);
}
BigDecimal realAmount;
}
public boolean callback(PaymentCallbackDTO paymentCallbackDTO) {
log.info("callback request received: {}", paymentCallbackDTO);
try {
realAmount = Convert.toBigDecimal(paymentCallbackResult.getRealAmount());
if (realAmount == null) {
throw new NumberFormatException("RealAmount is null or empty");
}
} catch (NumberFormatException e) {
log.error("Invalid RealAmount value: {}", paymentCallbackResult.getRealAmount(), e);
throw new IllegalArgumentException("支付金额错误: " + paymentCallbackResult.getRealAmount(), e);
}
final var build =
ClientCustomerOrderModification.newBuilder()
.setId(orderId)
.setShouldUpdatePayTime(true)
.setPayTime(payTime)
.setShouldUpdatePayPrice(true)
.setPayPrice(realAmount.multiply(new BigDecimal("100")).intValue())
.setShouldUpdatePayStatus(true)
.setPayStatus(PayStatusEnum.SUCCEED)
.setShouldUpdateStatus(true)
.setStatus(OrderStatusEnum.PREPARING)
.setShouldUpdateTransactionId(true)
.setTransactionId(paymentCallbackResult.getTransSN())
.build();
final var updateResponse =
orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
log.info("callback updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
if (updateResponse.getIsUpdated()) {
String createdAt = Instant.ofEpochMilli(orderById.getCreatedAt())
.atZone(DateUtil.CHINA_ZONE)
.minusHours(8)
.format(DateUtil.Y_M_D_H_M_S);
String payTimed = Instant.ofEpochMilli(orderById.getPayTime())
.atZone(DateUtil.CHINA_ZONE)
.minusHours(8)
.format(DateUtil.Y_M_D_H_M_S);
final var orderPaymentSuccessData =
OrderPaymentSuccessData.builder()
.orderId(orderById.getId())
.orderCode(orderById.getOrderCode())
.createTime(createdAt)
.payTime(payTimed)
.build();
final var data =
SocketMessage.<OrderPaymentSuccessData>builder()
.type(MessageTypeEnum.ORDER)
.noticeType(NoticeTypeEnum.ORDER_PAYMENT_SUCCESS)
.subject(NoticeTypeEnum.ORDER_PAYMENT_SUCCESS.getDescription())
.message("您的订单:" + orderById.getOrderCode() + " 支付成功啦,快去查看吧~")
.data(orderPaymentSuccessData)
.build();
WebSocketServer.sendMessageToUser(
UserSessionKey.builder()
.userId(orderById.getOpenId())
.userType(UserTypeEnum.MICRO)
.build(),
data);
if (LocalDate.now().equals(DateUtil.toLocalDate(orderById.getMealTime()))) {
final var orderCreateSuccessData =
OrderCreateSuccessData.builder().orderId(orderById.getId()).build();
final var createOrderData =
SocketMessage.<OrderCreateSuccessData>builder()
.type(MessageTypeEnum.ORDER)
.noticeType(NoticeTypeEnum.ORDER_CREATED)
.subject(NoticeTypeEnum.ORDER_CREATED.getDescription())
.message("有新的订单下单成功啦,快去查看吧~")
.data(orderCreateSuccessData)
.build();
final var clientOperatorIds =
clientResourceTagServiceRpcClient
.getOperatorIdsByStallIds(List.of(orderById.getStallId())).stream()
.map(SingleResourceLabelEntityRefsResponse::getEntityId)
.distinct()
.collect(Collectors.toList());
final var enterpriseOperatorIds =
enterpriseResourceServiceRpcClient.getOperatorIdsByStallId(
orderById.getEnterpriseId(), orderById.getStallId());
final var userAuthData = new ArrayList<UserAuthData>();
userAuthData.addAll(
clientOperatorIds.stream()
.map(
e ->
UserAuthData.builder()
.operatorId(e)
.userType(UserTypeEnum.CLIENT)
.build())
.collect(Collectors.toList()));
userAuthData.addAll(
enterpriseOperatorIds.stream()
.map(e -> UserAuthData.builder().operatorId(e).userType(UserTypeEnum.KDS).build())
.collect(Collectors.toList()));
log.info("received userAuthData:{}", JsonUtil.writeAsJson(userAuthData));
try {
WebSocketServer.sendMessageByUserTypes(
List.of(UserTypeEnum.CLIENT, UserTypeEnum.KDS), userAuthData, createOrderData);
} catch (IOException e) {
log.error("Failed to send message to user", e);
final var paymentCallbackResult =
xmlMapper.readValue(paymentCallbackDTO.getPayResult(), PaymentCallbackResult.class);
log.info("Parsed paymentCallbackResult: {}", paymentCallbackResult);
final var orderId = Integer.parseInt(paymentCallbackResult.getTradeId());
final var orderById = orderServiceRpcClient.getOrderById(orderId);
if (orderById == null) {
log.error("Order not found, orderId: {}", orderId);
return false;
}
}
log.info("Order callback, orderId: {}", orderId);
final var transType = paymentCallbackResult.getTransType();
if (transType.equals("00")) {
if (orderById.getPayStatus() != PayStatusEnum.TO_PAY
&& orderById.getPayStatus() != PayStatusEnum.IN_PROGRESS) {
log.error("Order status is not TO_PAY or IN_PROGRESS, orderId: {}", orderId);
return true;
}
long payTime;
try {
payTime =
DateUtil.parseDate(paymentCallbackResult.getTransDate(), "yyyyMMddHHmmss").getTime();
} catch (ParseException e) {
log.error("Failed to parse TransDate: {}", paymentCallbackResult.getTransDate(), e);
throw new IllegalArgumentException("支付时间格式错误: " + paymentCallbackResult.getTransDate(), e);
}
BigDecimal realAmount;
try {
realAmount = Convert.toBigDecimal(paymentCallbackResult.getRealAmount());
if (realAmount == null) {
throw new NumberFormatException("RealAmount is null or empty");
}
} catch (NumberFormatException e) {
log.error("Invalid RealAmount value: {}", paymentCallbackResult.getRealAmount(), e);
throw new IllegalArgumentException("支付金额错误: " + paymentCallbackResult.getRealAmount(), e);
}
final var build =
ClientCustomerOrderModification.newBuilder()
.setId(orderId)
.setShouldUpdatePayTime(true)
.setPayTime(payTime)
.setShouldUpdatePayPrice(true)
.setPayPrice(realAmount.multiply(new BigDecimal("100")).intValue())
.setShouldUpdatePayStatus(true)
.setPayStatus(PayStatusEnum.SUCCEED)
.setShouldUpdateStatus(true)
.setStatus(OrderStatusEnum.PREPARING)
.setShouldUpdateTransactionId(StringUtils.isNotEmpty(paymentCallbackResult.getTradeReferenceNo()))
.setTransactionId(StringUtils.isNotEmpty(paymentCallbackResult.getTradeReferenceNo()) ? paymentCallbackResult.getTradeReferenceNo() : "")
.build();
final var updateResponse =
orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
log.info("callback updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
if (updateResponse.getIsUpdated()) {
String createdAt = Instant.ofEpochMilli(orderById.getCreatedAt())
.atZone(DateUtil.CHINA_ZONE)
.minusHours(8)
.format(DateUtil.Y_M_D_H_M_S);
String payTimed = Instant.ofEpochMilli(orderById.getPayTime())
.atZone(DateUtil.CHINA_ZONE)
.minusHours(8)
.format(DateUtil.Y_M_D_H_M_S);
final var orderPaymentSuccessData =
OrderPaymentSuccessData.builder()
.orderId(orderById.getId())
.orderCode(orderById.getOrderCode())
.createTime(createdAt)
.payTime(payTimed)
.build();
final var data =
SocketMessage.<OrderPaymentSuccessData>builder()
.type(MessageTypeEnum.ORDER)
.noticeType(NoticeTypeEnum.ORDER_PAYMENT_SUCCESS)
.subject(NoticeTypeEnum.ORDER_PAYMENT_SUCCESS.getDescription())
.message("您的订单:" + orderById.getOrderCode() + " 支付成功啦,快去查看吧~")
.data(orderPaymentSuccessData)
.build();
WebSocketServer.sendMessageToUser(
UserSessionKey.builder()
.userId(orderById.getOpenId())
.userType(UserTypeEnum.MICRO)
.build(),
data);
if (LocalDate.now().equals(DateUtil.toLocalDate(orderById.getMealTime()))) {
final var orderCreateSuccessData =
OrderCreateSuccessData.builder().orderId(orderById.getId()).build();
final var createOrderData =
SocketMessage.<OrderCreateSuccessData>builder()
.type(MessageTypeEnum.ORDER)
.noticeType(NoticeTypeEnum.ORDER_CREATED)
.subject(NoticeTypeEnum.ORDER_CREATED.getDescription())
.message("有新的订单下单成功啦,快去查看吧~")
.data(orderCreateSuccessData)
.build();
final var clientOperatorIds =
clientResourceTagServiceRpcClient
.getOperatorIdsByStallIds(List.of(orderById.getStallId())).stream()
.map(SingleResourceLabelEntityRefsResponse::getEntityId)
.distinct()
.collect(Collectors.toList());
final var enterpriseOperatorIds =
enterpriseResourceServiceRpcClient.getOperatorIdsByStallId(
orderById.getEnterpriseId(), orderById.getStallId());
final var userAuthData = new ArrayList<UserAuthData>();
userAuthData.addAll(
clientOperatorIds.stream()
.map(
e ->
UserAuthData.builder()
.operatorId(e)
.userType(UserTypeEnum.CLIENT)
.build())
.collect(Collectors.toList()));
userAuthData.addAll(
enterpriseOperatorIds.stream()
.map(e -> UserAuthData.builder().operatorId(e).userType(UserTypeEnum.KDS).build())
.collect(Collectors.toList()));
log.info("received userAuthData:{}", JsonUtil.writeAsJson(userAuthData));
try {
WebSocketServer.sendMessageByUserTypes(
List.of(UserTypeEnum.CLIENT, UserTypeEnum.KDS), userAuthData, createOrderData);
} catch (IOException e) {
log.error("Failed to send message to user", e);
}
}
}
return updateResponse.getIsUpdated();
} else {
final var build =
ClientCustomerOrderModification.newBuilder()
.setId(orderId)
.setShouldUpdatePayStatus(true)
.setPayStatus(PayStatusEnum.REFUND)
.build();
final var updateResponse =
orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
log.info("callback updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
return updateResponse.getIsUpdated();
}
} catch (JsonProcessingException e) {
log.error("Failed to parse XML response, raw XML: {}", paymentCallbackDTO.getPayResult(), e);
throw new RuntimeException("支付/退款通知结果解析失败", e);
} catch (Exception e) {
log.error("Unexpected error in callback, request: {}", paymentCallbackDTO, e);
throw new RuntimeException("支付/退款通知处理失败", e);
}
}
public boolean waiting(Integer orderId) {
final var orderById = orderServiceRpcClient.getOrderById(orderId);
if (orderById == null) {
log.error("waiting Order not found, orderId: {}", orderId);
return false;
}
if (orderById.getPayStatus() != PayStatusEnum.TO_PAY) {
log.info("waiting Order {} already processed, skipping.", orderId);
return false;
}
return updateResponse.getIsUpdated();
} else {
final var build =
ClientCustomerOrderModification.newBuilder()
.setId(orderId)
.setShouldUpdatePayStatus(true)
.setPayStatus(PayStatusEnum.REFUND)
.build();
ClientCustomerOrderModification.newBuilder()
.setId(orderId)
.setShouldUpdatePayStatus(true)
.setPayStatus(PayStatusEnum.IN_PROGRESS)
.build();
final var updateResponse =
orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
log.info("callback updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
log.info("waiting updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
return updateResponse.getIsUpdated();
}
} catch (JsonProcessingException e) {
log.error("Failed to parse XML response, raw XML: {}", paymentCallbackDTO.getPayResult(), e);
throw new RuntimeException("支付/退款通知结果解析失败", e);
} catch (Exception e) {
log.error("Unexpected error in callback, request: {}", paymentCallbackDTO, e);
throw new RuntimeException("支付/退款通知处理失败", e);
}
}
public boolean waiting(Integer orderId) {
final var orderById = orderServiceRpcClient.getOrderById(orderId);
if (orderById == null) {
log.error("waiting Order not found, orderId: {}", orderId);
return false;
}
if (orderById.getPayStatus() != PayStatusEnum.TO_PAY) {
log.info("waiting Order {} already processed, skipping.", orderId);
return false;
}
final var build =
ClientCustomerOrderModification.newBuilder()
.setId(orderId)
.setShouldUpdatePayStatus(true)
.setPayStatus(PayStatusEnum.IN_PROGRESS)
.build();
final var updateResponse =
orderServiceRpcClient.updateClientCustomerOrderPaymentResult(orderById, build);
log.info("waiting updateClientCustomerOrder result: {}", updateResponse.getIsUpdated());
return updateResponse.getIsUpdated();
}
public String orderPayRefund(PayRefundRequestDto payRefundRequestDto) {
Integer orderId = payRefundRequestDto.getOrderId();
final var orderById = orderServiceRpcClient.getOrderById(orderId);
if (orderById == null) {
log.error("Order not found, orderId: {}", orderId);
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_FOUND);
}
if (orderById.getOnlinePay() != OnlinePayEnum.ONLINE) {
log.info("Order {} is not online pay.", orderId);
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_ONLINE_PAY);
}
if (orderById.getPayStatus() != PayStatusEnum.SUCCEED) {
log.info("Order {} pay is not succeed.", orderId);
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_SUCCESS);
}
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
LocalDateTime tomorrowZero = tomorrow.atStartOfDay();
LocalDateTime orderPayTime = DateUtil.toLocalDateTime(orderById.getPayTime()).minusHours(8);
if (!orderPayTime.isBefore(tomorrowZero)) {
log.info("Order {} pay is beyond cancel time.", orderId);
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
}
public String orderPayRefund(PayRefundRequestDto payRefundRequestDto) {
Integer orderId = payRefundRequestDto.getOrderId();
final var orderById = orderServiceRpcClient.getOrderById(orderId);
if (orderById == null) {
log.error("Order not found, orderId: {}", orderId);
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_FOUND);
}
if (orderById.getOnlinePay() != OnlinePayEnum.ONLINE) {
log.info("Order {} is not online pay.", orderId);
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_ONLINE_PAY);
}
if (orderById.getPayStatus() != PayStatusEnum.SUCCEED) {
log.info("Order {} pay is not succeed.", orderId);
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_NOT_SUCCESS);
}
LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);
LocalDateTime tomorrowZero = tomorrow.atStartOfDay();
LocalDateTime orderPayTime = DateUtil.toLocalDateTime(orderById.getPayTime()).minusHours(8);
if (!orderPayTime.isBefore(tomorrowZero)) {
log.info("Order {} pay is beyond cancel time.", orderId);
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
}
BigDecimal detailPrice = BigDecimal.ZERO;
if (CollectionUtils.isNotEmpty(payRefundRequestDto.getOrderDetailIds())) {
final var orderDetails = orderServiceRpcClient.getClientCustomerOrderDetailsByIds(payRefundRequestDto.getOrderDetailIds());
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);
}
String appId = businessConfig.getPayClientId();
String appId = businessConfig.getPayClientId();
// 构建paycontent
String payTime = Instant.ofEpochMilli(orderById.getPayTime())
.atZone(DateUtil.CHINA_ZONE)
.minusHours(8)
.format(DateUtil.YMDHMS);
// 构建paycontent
String payTime = Instant.ofEpochMilli(orderById.getPayTime())
.atZone(DateUtil.CHINA_ZONE)
.minusHours(8)
.format(DateUtil.YMDHMS);
BigDecimal price =
new BigDecimal(orderById.getPayPrice())
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).negate();
BigDecimal price = detailPrice.compareTo(BigDecimal.ZERO) == 0 ?
new BigDecimal(orderById.getPayPrice()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).negate()
: detailPrice.negate();
String payContentStr =
orderById.getId()
+ "^"
+ "01"
+ "^"
+ "^"
+ orderById.getOpenId()
+ "^"
+ orderById.getOrderCode()
+ "^"
+ price
+ "^"
+ payTime
+ "^"
+ orderById.getTransactionId()
+ "^"
+ payRefundRequestDto.getHospitalCode()
+ "^"
+ "^"
+ LoginContextHolder.getId()
+ "^"
+ LoginContextHolder.getName();
String payContent =
URLEncoder.encode(
Base64.encodeBase64String(payContentStr.getBytes()), StandardCharsets.UTF_8);
String payContentStr =
orderById.getId()
+ "^"
+ "01"
+ "^"
+ "^"
+ orderById.getOpenId()
+ "^"
+ orderById.getOrderCode()
+ "^"
+ price
+ "^"
+ payTime
+ "^"
+ orderById.getTransactionId()
+ "^"
+ payRefundRequestDto.getHospitalCode()
+ "^"
+ "^"
+ LoginContextHolder.getId()
+ "^"
+ LoginContextHolder.getName();
String payContent =
URLEncoder.encode(
Base64.encodeBase64String(payContentStr.getBytes()), StandardCharsets.UTF_8);
// 构建signinfo
String signInfoStr = appId + orderById.getId() + payTime + businessConfig.getRefundSecurityKey();
String signInfo = DigestUtils.sha1Hex(signInfoStr.getBytes());
// 构建signinfo
String signInfoStr = appId + orderById.getId() + payTime + businessConfig.getRefundSecurityKey();
String signInfo = DigestUtils.sha1Hex(signInfoStr.getBytes());
// 构建请求
try {
String url = businessConfig.getCancelPayUrl() + "?" + "appid=" + appId + "&paycontent=" + payContent + "&signinfo=" + signInfo;
log.info("cancel order pay url:{}", url);
// 构建请求
try {
String url = businessConfig.getCancelPayUrl() + "?" + "appid=" + appId + "&paycontent=" + payContent + "&signinfo=" + signInfo;
log.info("cancel order pay url:{}", url);
// Request request =
// new Request.Builder().url(url).get().build();
// Response payResponse = client.newCall(request).execute();
......@@ -400,10 +407,10 @@ public class PayServiceClient {
// throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
// }
// String htmlContent = payResponse.body().string();
return url;
} catch (Exception e) {
log.error(e.getMessage());
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
return url;
} catch (Exception e) {
log.error(e.getMessage());
throw ClientEndExceptions.BusinessException.build(ErrorCodeEnum.ORDER_PAY_REFUND_FAILED);
}
}
}
}
......
......@@ -2,8 +2,11 @@ package com.infoloop.tianting.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.infoloop.tianting.SingleDishSkuByIdsRpcResponse;
import com.infoloop.tianting.clientcustomerorderservice.OnlinePayEnum;
import com.infoloop.tianting.clientcustomerorderservice.OrderOperationRecord;
import com.infoloop.tianting.clientcustomerorderservice.OrderOperationType;
import com.infoloop.tianting.clientcustomerorderservice.OrderStatusEnum;
import com.infoloop.tianting.clientcustomerorderservice.PayStatusEnum;
import com.infoloop.tianting.clientcustomerorderservice.ServeStatusEnum;
......@@ -17,6 +20,7 @@ import com.infoloop.tianting.exception.ClientEndExceptions.BusinessException;
import com.infoloop.tianting.exception.ErrorCodeEnum;
import com.infoloop.tianting.menuservice.SingleMenuDetailRpcResponse;
import com.infoloop.tianting.menuservice.SingleMenuRpcResponse;
import com.infoloop.tianting.model.bo.OrderDetailBO;
import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderByConditionDto;
import com.infoloop.tianting.model.dto.OrderDbDTO.QueryOrderDto;
import com.infoloop.tianting.model.dto.SettlementDTO;
......@@ -39,8 +43,10 @@ import com.infoloop.tianting.service.client.OrderServiceRpcClient;
import com.infoloop.tianting.service.client.SkuServiceRpcClient;
import com.infoloop.tianting.setmealscheduleservice.SingleMealRpcResponse;
import com.infoloop.tianting.utils.DateUtil;
import com.infoloop.tianting.utils.JsonUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
......@@ -71,7 +77,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Slf4j
@Service
......@@ -295,6 +303,408 @@ public class SettlementServiceImpl implements SettlementService {
return dateList;
}
/**
* 按订单维度生成Excel
*/
private static ByteArrayOutputStream writeToExcelByOrder(SettlementDTO.SettlementDataByOrderDto settlementDataDto)
throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("客人结算");
// 创建表头样式(黑色边框)
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 创建数据行样式(浅灰色边框)
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
int rowNum = 0;
// 创建表头
Row titleRow = sheet.createRow(rowNum++);
int columnNum = 0;
Cell cell0 = titleRow.createCell(columnNum++);
cell0.setCellValue("用餐时间");
cell0.setCellStyle(headerStyle);
Cell cell1 = titleRow.createCell(columnNum++);
cell1.setCellValue("订单号");
cell1.setCellStyle(headerStyle);
Cell cell2 = titleRow.createCell(columnNum++);
cell2.setCellValue("餐别");
cell2.setCellStyle(headerStyle);
Cell cell3 = titleRow.createCell(columnNum++);
cell3.setCellValue("房间号");
cell3.setCellStyle(headerStyle);
Cell cell4 = titleRow.createCell(columnNum++);
cell4.setCellValue("客户姓名");
cell4.setCellStyle(headerStyle);
Cell cell5 = titleRow.createCell(columnNum++);
cell5.setCellValue("客户腕带号");
cell5.setCellStyle(headerStyle);
Cell cell6 = titleRow.createCell(columnNum++);
cell6.setCellValue("忌口信息");
cell6.setCellStyle(headerStyle);
Cell cell7 = titleRow.createCell(columnNum++);
cell7.setCellValue("医嘱信息");
cell7.setCellStyle(headerStyle);
Cell cell8 = titleRow.createCell(columnNum++);
cell8.setCellValue("餐单名称");
cell8.setCellStyle(headerStyle);
Cell cell9 = titleRow.createCell(columnNum++);
cell9.setCellValue("菜品名称");
cell9.setCellStyle(headerStyle);
Cell cell10 = titleRow.createCell(columnNum++);
cell10.setCellValue("菜品份数");
cell10.setCellStyle(headerStyle);
Cell cell11 = titleRow.createCell(columnNum++);
cell11.setCellValue("菜品单价");
cell11.setCellStyle(headerStyle);
Cell cell12 = titleRow.createCell(columnNum++);
cell12.setCellValue("菜品金额");
cell12.setCellStyle(headerStyle);
Cell cell13 = titleRow.createCell(columnNum++);
cell13.setCellValue("菜品状态");
cell13.setCellStyle(headerStyle);
Cell cell14 = titleRow.createCell(columnNum++);
cell14.setCellValue("交易码");
cell14.setCellStyle(headerStyle);
Cell cell15 = titleRow.createCell(columnNum++);
cell15.setCellValue("备注");
cell15.setCellStyle(headerStyle);
Cell cell16 = titleRow.createCell(columnNum++);
cell16.setCellValue("支付方式");
cell16.setCellStyle(headerStyle);
// 填充数据
final var classifyOrders = settlementDataDto.getClassifyOrders();
if (classifyOrders != null) {
for (SettlementDTO.SettlementOrderDetail orderDetail : classifyOrders) {
Row dataRow = sheet.createRow(rowNum++);
columnNum = 0;
Cell dataCell0 = dataRow.createCell(columnNum++);
dataCell0.setCellValue(orderDetail.getMealTime() != null ? orderDetail.getMealTime() : "");
dataCell0.setCellStyle(dataStyle);
Cell dataCell1 = dataRow.createCell(columnNum++);
dataCell1.setCellValue(orderDetail.getCode() != null ? orderDetail.getCode() : "");
dataCell1.setCellStyle(dataStyle);
Cell dataCell2 = dataRow.createCell(columnNum++);
dataCell2.setCellValue(orderDetail.getMealName() != null ? orderDetail.getMealName() : "");
dataCell2.setCellStyle(dataStyle);
Cell dataCell3 = dataRow.createCell(columnNum++);
dataCell3.setCellValue(orderDetail.getRoomNo() != null ? orderDetail.getRoomNo() : "");
dataCell3.setCellStyle(dataStyle);
Cell dataCell4 = dataRow.createCell(columnNum++);
dataCell4.setCellValue(orderDetail.getCustomerName() != null ? orderDetail.getCustomerName() : "");
dataCell4.setCellStyle(dataStyle);
Cell dataCell5 = dataRow.createCell(columnNum++);
dataCell5.setCellValue(orderDetail.getHISCustomerNo() != null ? orderDetail.getHISCustomerNo() : "");
dataCell5.setCellStyle(dataStyle);
// 忌口列表转字符串
String avoidsStr = orderDetail.getAvoids() != null ? String.join(", ", orderDetail.getAvoids()) : "";
Cell dataCell6 = dataRow.createCell(columnNum++);
dataCell6.setCellValue(avoidsStr);
dataCell6.setCellStyle(dataStyle);
// 医嘱列表转字符串
String doctorsStr = orderDetail.getDoctors() != null ? String.join(", ", orderDetail.getDoctors()) : "";
Cell dataCell7 = dataRow.createCell(columnNum++);
dataCell7.setCellValue(doctorsStr);
dataCell7.setCellStyle(dataStyle);
Cell dataCell8 = dataRow.createCell(columnNum++);
dataCell8.setCellValue(orderDetail.getMenuName() != null ? orderDetail.getMenuName() : "");
dataCell8.setCellStyle(dataStyle);
Cell dataCell9 = dataRow.createCell(columnNum++);
dataCell9.setCellValue(orderDetail.getSkuName() != null ? orderDetail.getSkuName() : "");
dataCell9.setCellStyle(dataStyle);
Cell dataCell10 = dataRow.createCell(columnNum++);
dataCell10.setCellValue(orderDetail.getCount() != null ? orderDetail.getCount() : 0);
dataCell10.setCellStyle(dataStyle);
// 价格
Cell dataCell11 = dataRow.createCell(columnNum++);
if (orderDetail.getPrice() != null) {
dataCell11.setCellValue(orderDetail.getPrice().doubleValue());
} else {
dataCell11.setCellValue(0.0);
}
dataCell11.setCellStyle(dataStyle);
// 总价
Cell dataCell12 = dataRow.createCell(columnNum++);
if (orderDetail.getTotalPrice() != null) {
dataCell12.setCellValue(orderDetail.getTotalPrice().doubleValue());
} else {
dataCell12.setCellValue(0.0);
}
dataCell12.setCellStyle(dataStyle);
// 状态
Cell dataCell13 = dataRow.createCell(columnNum++);
dataCell13.setCellValue(orderDetail.getOperationType());
dataCell13.setCellStyle(dataStyle);
Cell dataCell14 = dataRow.createCell(columnNum++);
dataCell14.setCellValue(orderDetail.getTransactionId() != null ? orderDetail.getTransactionId() : "");
dataCell14.setCellStyle(dataStyle);
// 合并备注和忌口备注,用分号分割,备注在前
String remark = orderDetail.getRemark() != null ? orderDetail.getRemark() : "";
String avoidRemark = orderDetail.getAvoidRemark() != null ? orderDetail.getAvoidRemark() : "";
String combinedRemark = "";
if (!remark.isEmpty() && !avoidRemark.isEmpty()) {
combinedRemark = remark + ";" + avoidRemark;
} else if (!remark.isEmpty()) {
combinedRemark = remark;
} else if (!avoidRemark.isEmpty()) {
combinedRemark = avoidRemark;
}
Cell dataCell15 = dataRow.createCell(columnNum++);
dataCell15.setCellValue(combinedRemark);
dataCell15.setCellStyle(dataStyle);
Cell dataCell16 = dataRow.createCell(columnNum++);
dataCell16.setCellValue(orderDetail.getOnlinePay() != null ? orderDetail.getOnlinePay() : "");
dataCell16.setCellStyle(dataStyle);
}
}
// 自动调整列宽
for (int i = 0; i < 17; i++) {
sheet.autoSizeColumn(i);
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
return outputStream;
}
/**
* 生成分餐表Excel
*/
private static ByteArrayOutputStream writeToExcelBySeparateMeal(SeparateMealDataDto separateMealDataDto)
throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("分餐表");
// 创建标题样式(合并单元格标题)
CellStyle titleStyle = workbook.createCellStyle();
titleStyle.setAlignment(HorizontalAlignment.CENTER);
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
titleStyle.setBorderTop(BorderStyle.THIN);
titleStyle.setBorderBottom(BorderStyle.THIN);
titleStyle.setBorderLeft(BorderStyle.THIN);
titleStyle.setBorderRight(BorderStyle.THIN);
titleStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
Font titleFont = workbook.createFont();
titleFont.setBold(true);
titleFont.setFontHeightInPoints((short) 16);
titleStyle.setFont(titleFont);
// 创建表头样式(黑色边框)
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 创建数据行样式(浅灰色边框)
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
int rowNum = 0;
// 第一行:创建合并单元格标题
Row mainTitleRow = sheet.createRow(rowNum++);
Cell mainTitleCell = mainTitleRow.createCell(0);
mainTitleCell.setCellValue("住院客户分餐表");
mainTitleCell.setCellStyle(titleStyle);
// 合并第一行的8列
CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 8);
sheet.addMergedRegion(titleRegion);
// 为合并区域设置边框
RegionUtil.setBorderTop(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderBottom(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderLeft(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderRight(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setTopBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setBottomBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setLeftBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setRightBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
// 第二行:创建表头
Row titleRow = sheet.createRow(rowNum++);
int columnNum = 0;
Cell cell0 = titleRow.createCell(columnNum++);
cell0.setCellValue("餐别");
cell0.setCellStyle(headerStyle);
Cell cell1 = titleRow.createCell(columnNum++);
cell1.setCellValue("房间号");
cell1.setCellStyle(headerStyle);
Cell cell2 = titleRow.createCell(columnNum++);
cell2.setCellValue("客户姓名");
cell2.setCellStyle(headerStyle);
Cell cell3 = titleRow.createCell(columnNum++);
cell3.setCellValue("医嘱信息");
cell3.setCellStyle(headerStyle);
Cell cell4 = titleRow.createCell(columnNum++);
cell4.setCellValue("餐单名称");
cell4.setCellStyle(headerStyle);
Cell cell5 = titleRow.createCell(columnNum++);
cell5.setCellValue("菜品名称");
cell5.setCellStyle(headerStyle);
Cell cell6 = titleRow.createCell(columnNum++);
cell6.setCellValue("菜品数量");
cell6.setCellStyle(headerStyle);
Cell cell7 = titleRow.createCell(columnNum++);
cell7.setCellValue("忌口信息");
cell7.setCellStyle(headerStyle);
Cell cell8 = titleRow.createCell(columnNum++);
cell8.setCellValue("备注");
cell8.setCellStyle(headerStyle);
// 填充数据
final var mealDetails = separateMealDataDto.getMealDetails();
if (mealDetails != null) {
for (SeparateMealDetail mealDetail : mealDetails) {
Row dataRow = sheet.createRow(rowNum++);
columnNum = 0;
Cell dataCell0 = dataRow.createCell(columnNum++);
dataCell0.setCellValue(mealDetail.getMealName() != null ? mealDetail.getMealName() : "");
dataCell0.setCellStyle(dataStyle);
Cell dataCell1 = dataRow.createCell(columnNum++);
dataCell1.setCellValue(mealDetail.getRoomNo() != null ? mealDetail.getRoomNo() : "");
dataCell1.setCellStyle(dataStyle);
Cell dataCell2 = dataRow.createCell(columnNum++);
dataCell2.setCellValue(mealDetail.getCustomerName() != null ? mealDetail.getCustomerName() : "");
dataCell2.setCellStyle(dataStyle);
Cell dataCell3 = dataRow.createCell(columnNum++);
dataCell3.setCellValue(mealDetail.getDoctors() != null ? mealDetail.getDoctors() : "");
dataCell3.setCellStyle(dataStyle);
Cell dataCell4 = dataRow.createCell(columnNum++);
dataCell4.setCellValue(mealDetail.getMenuName() != null ? mealDetail.getMenuName() : "");
dataCell4.setCellStyle(dataStyle);
Cell dataCell5 = dataRow.createCell(columnNum++);
dataCell5.setCellValue(mealDetail.getSkuName() != null ? mealDetail.getSkuName() : "");
dataCell5.setCellStyle(dataStyle);
Cell dataCell6 = dataRow.createCell(columnNum++);
dataCell6.setCellValue(mealDetail.getCount() != null ? mealDetail.getCount() : 0);
dataCell6.setCellStyle(dataStyle);
Cell dataCell7 = dataRow.createCell(columnNum++);
dataCell7.setCellValue(mealDetail.getAvoids() != null ? mealDetail.getAvoids() : "");
dataCell7.setCellStyle(dataStyle);
Cell dataCell8 = dataRow.createCell(columnNum++);
dataCell8.setCellValue(mealDetail.getRemark() != null ? mealDetail.getRemark() : "");
dataCell8.setCellStyle(dataStyle);
}
}
// 自动调整列宽
for (int i = 0; i < 9; i++) {
sheet.autoSizeColumn(i);
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
return outputStream;
}
/**
* 创建空的分餐表Excel(无数据)
*/
private static ByteArrayOutputStream createEmptyExcelBySeparateMeal() {
try {
SeparateMealDataDto emptyData = SeparateMealDataDto.builder()
.mealDetails(new ArrayList<>())
.build();
return writeToExcelBySeparateMeal(emptyData);
} catch (IOException e) {
log.error("创建空分餐表Excel失败", e);
throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
}
}
@Override
public ByteArrayOutputStream generateOrderSettlementExcel(SettlementRequestDto settlementRequest) {
if (settlementRequest.getDimension().equals(SettlementDimensionEnum.BY_SKU)) {
......@@ -369,13 +779,11 @@ public class SettlementServiceImpl implements SettlementService {
.collect(Collectors.toList());
if (orderIds.isEmpty()) {
log.warn("筛选后无有效订单,enterpriseId: {}", enterpriseId);
return createEmptyExcelByOrder();
}
// 构建订单映射
final var orderMap = orderList.stream()
.filter(o -> o.getId() != 0)
final var orderMap = orderList.stream().filter(o -> o.getId() != 0)
.collect(Collectors.toMap(SingleClientCustomerOrderRpcResponse::getId, o -> o, (o1, o2) -> o1));
// 查询订单详情
......@@ -384,86 +792,60 @@ public class SettlementServiceImpl implements SettlementService {
log.warn("未查询到订单详情数据,orderIds: {}", orderIds);
return createEmptyExcelByOrder();
}
// 订单详情按订单ID分组
final var orderDetailGroupByOrderId = orderDetailList.stream()
.filter(Objects::nonNull)
.filter(d -> !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT))
.collect(Collectors.groupingBy(SingleClientCustomerOrderDetailRpcResponse::getOrderId));
// 获取SKU数据
List<Integer> skuIds = orderDetailList.stream()
.filter(Objects::nonNull)
.filter(d -> !d.getServeStatus().equals(ServeStatusEnum.SERVE_REJECT))
.map(SingleClientCustomerOrderDetailRpcResponse::getSkuId)
final var orderDetailGroupByOrderId = orderDetailList.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(SingleClientCustomerOrderDetailRpcResponse::getOrderId));
final var orderOperationRecordsByOrderIds = orderServiceRpcClient.getOrderOperationRecordsByOrderIds(LoginContextHolder.getEnterpriseId(), orderIds).getResponsesList();
// 订单操作记录按订单ID分组
final var orderOperationRecordByOrderId = orderOperationRecordsByOrderIds.stream().filter(Objects::nonNull).collect(Collectors.groupingBy(OrderOperationRecord::getOrderId));
List<Integer> skuIds = Stream.concat(
orderOperationRecordsByOrderIds.stream()
.filter(e -> StringUtils.isNoneBlank(e.getOriginalOrderDetailJson()))
.flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {}).stream())
.map(OrderDetailBO::getSkuId),
orderDetailList.stream()
.filter(Objects::nonNull)
.map(SingleClientCustomerOrderDetailRpcResponse::getSkuId)
)
.distinct()
.collect(Collectors.toList());
final var skuResponse = skuServiceRpcClient.getDishSkusByIds(skuIds);
final List<SingleDishSkuByIdsRpcResponse> skus = skuResponse != null ? skuResponse.getResponseList() : new ArrayList<>();
final var skuMap = skus.stream()
.filter(Objects::nonNull)
.filter(s -> s.getId() != 0)
.collect(Collectors.toMap(SingleDishSkuByIdsRpcResponse::getId, s -> s, (s1, s2) -> s1));
final List<SingleDishSkuByIdsRpcResponse> skus = skuResponse.getResponseList();
final var skuMap = skus.stream().collect(Collectors.toMap(SingleDishSkuByIdsRpcResponse::getId, s -> s, (s1, s2) -> s1));
// 获取餐别数据
final var mealResponse = mealServiceRpcClient.getAllMeals(enterpriseId);
final List<SingleMealRpcResponse> meals = mealResponse != null ? mealResponse.getResponsesList() : new ArrayList<>();
final var mealMap = meals.stream()
.filter(Objects::nonNull)
.filter(m -> m.getId() != 0)
.collect(Collectors.toMap(SingleMealRpcResponse::getId, m -> m, (m1, m2) -> m1));
final var mealMap = meals.stream().collect(Collectors.toMap(SingleMealRpcResponse::getId, m -> m, (m1, m2) -> m1));
// 获取菜单数据
List<Integer> menuIds = orderList.stream()
.filter(Objects::nonNull)
.map(SingleClientCustomerOrderRpcResponse::getMenuId)
.filter(id -> id != 0)
.distinct()
.collect(Collectors.toList());
List<Integer> menuIds = orderList.stream().map(SingleClientCustomerOrderRpcResponse::getMenuId).distinct().collect(Collectors.toList());
final var menuResponse = menuServiceRpcClient.getMenusByIds(enterpriseId, menuIds);
final List<SingleMenuRpcResponse> menuList = menuResponse != null ? menuResponse.getResponsesList() : new ArrayList<>();
final var menuMap = menuList.stream()
.filter(Objects::nonNull)
.filter(m -> m.getId() != 0)
.collect(Collectors.toMap(SingleMenuRpcResponse::getId, m -> m, (m1, m2) -> m1));
final var menuMap = menuList.stream().collect(Collectors.toMap(SingleMenuRpcResponse::getId, m -> m, (m1, m2) -> m1));
// 获取菜单详情数据
final var menuDetailResponse = menuServiceRpcClient.queryMenuDetailsByMenuIds(enterpriseId, menuIds);
final List<SingleMenuDetailRpcResponse> menuDetailList = menuDetailResponse != null ? menuDetailResponse.getResponsesList() : new ArrayList<>();
final var menuDetailMap = menuDetailList.stream()
.filter(Objects::nonNull)
.filter(m -> m.getId() != 0)
.collect(Collectors.toMap(SingleMenuDetailRpcResponse::getId, m -> m, (m1, m2) -> m1));
final List<SingleMenuDetailRpcResponse> menuDetailList = menuDetailResponse.getResponsesList();
final var menuDetailMap = menuDetailList.stream().collect(Collectors.toMap(SingleMenuDetailRpcResponse::getId, m -> m, (m1, m2) -> m1));
// 获取客户数据
List<Integer> customerIds = orderList.stream()
.filter(Objects::nonNull)
.map(SingleClientCustomerOrderRpcResponse::getCustomerId)
.filter(id -> id != 0)
.distinct()
.collect(Collectors.toList());
List<Integer> customerIds = orderList.stream().map(SingleClientCustomerOrderRpcResponse::getCustomerId).distinct().collect(Collectors.toList());
final var customerResponse = clientCustomerServiceRpcClient.getClientCustomersByIds(enterpriseId, customerIds);
final List<SingleClientCustomerRpcResponse> customers = customerResponse != null ? customerResponse.getResponsesList() : new ArrayList<>();
final var customerMap = customers.stream()
.filter(Objects::nonNull)
.filter(c -> c.getId() != 0)
.collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1));
final List<SingleClientCustomerRpcResponse> customers = customerResponse.getResponsesList();
final var customerMap = customers.stream().collect(Collectors.toMap(SingleClientCustomerRpcResponse::getId, c -> c, (c1, c2) -> c1));
// 构建结算订单明细
final var classifyOrders = new ArrayList<SettlementDTO.SettlementOrderDetail>();
for (Integer orderId : orderIds) {
final var orderDetails = orderDetailGroupByOrderId.getOrDefault(orderId, Collections.emptyList());
final var order = orderMap.get(orderId);
// 订单为空则跳过
if (order == null) {
log.warn("订单不存在,orderId: {}", orderId);
continue;
}
// 获取菜单信息
final var menu = menuMap.get(order.getMenuId());
final String menuName = menu != null ? menu.getName() : "";
......@@ -473,52 +855,76 @@ public class SettlementServiceImpl implements SettlementService {
final String customerName = customer != null ? customer.getName() : "";
final String hisCustomerNo = customer != null ? customer.getHISCustomerNo() : "";
// 处理每个订单详情
for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) {
if (orderDetail == null) {
continue;
}
final var orderOperationRecords = orderOperationRecordByOrderId.getOrDefault(orderId, Collections.emptyList());
// 安全获取餐别名称
String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap);
Map<Integer, OrderDetailBO> addOriginalDetailMap = orderOperationRecords.stream()
.filter(e -> e.getType() == OrderOperationType.ADD_DISHES)
.flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {
}).stream())
.collect(Collectors.toMap(OrderDetailBO::getId, Function.identity(), (a, b) -> a));
// 安全获取SKU名称
String skuName = getSkuNameSafely(orderDetail, skuMap);
Map<Integer, OrderDetailBO> replaceOriginalDetailMap = orderOperationRecords.stream()
.filter(e -> e.getType() == OrderOperationType.REPLACE_DISHES)
.flatMap(e -> JsonUtil.readJsonAs(e.getOriginalOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {
}).stream())
.collect(Collectors.toMap(OrderDetailBO::getId, Function.identity(), (a, b) -> a));
// 安全获取房间号
String roomNo = getRoomNoSafely(order);
Map<Integer, OrderDetailBO> replaceAdjustDetailMap = orderOperationRecords.stream()
.filter(e -> e.getType() == OrderOperationType.REPLACE_DISHES)
.flatMap(e -> JsonUtil.readJsonAs(e.getAdjustOrderDetailJson(), new TypeReference<List<OrderDetailBO>>() {
}).stream())
.collect(Collectors.toMap(OrderDetailBO::getId, Function.identity(), (a, b) -> a));
// 安全获取忌口和医嘱
List<String> avoids = getAvoidsSafely(order);
List<String> doctors = getDoctorsSafely(order);
for (SingleClientCustomerOrderDetailRpcResponse orderDetail : orderDetails) {
// 1. 先处理加餐
if (addOriginalDetailMap.containsKey(orderDetail.getId())
&& addOriginalDetailMap.get(orderDetail.getId()).getCount() != orderDetail.getCount()) {
final var orderDetailBO = addOriginalDetailMap.get(orderDetail.getId());
SettlementDTO.SettlementOrderDetail beforeChange = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetailBO.getSkuId(), orderDetailBO.getCount(), orderDetail.getPrice(), "订餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(beforeChange);
SettlementDTO.SettlementOrderDetail afterChange = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetailBO.getSkuId(), orderDetail.getCount() - orderDetailBO.getCount(), orderDetail.getPrice(), "加餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(afterChange);
}
// 安全获取在线支付描述
String onlinePayDesc = getOnlinePayDescSafely(order);
// 2. 再处理换菜
if (replaceOriginalDetailMap.containsKey(orderDetail.getId())
&& !Objects.equals(replaceOriginalDetailMap.get(orderDetail.getId()).getSkuId(), orderDetail.getSkuId())) {
final var orderDetailBO = replaceOriginalDetailMap.get(orderDetail.getId());
final var orderDetailAdjustBO = replaceAdjustDetailMap.get(orderDetail.getId());
SettlementDTO.SettlementOrderDetail beforeChange = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetailBO.getSkuId(), orderDetailBO.getCount(), orderDetailBO.getPrice(), "换菜前", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(beforeChange);
SettlementDTO.SettlementOrderDetail afterChange = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetailAdjustBO.getPrice(), "换菜后", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(afterChange);
}
// 构建订单详情
order.getOrderCode();
order.getRemark();
order.getAvoidRemark();
SettlementDTO.SettlementOrderDetail settlementOrderDetail = SettlementDTO.SettlementOrderDetail.builder()
.mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "")
.code(order.getOrderCode())
.mealName(mealName)
.roomNo(roomNo)
.customerName(customerName)
.HISCustomerNo(hisCustomerNo)
.avoids(avoids)
.doctors(doctors)
.menuName(menuName)
.skuName(skuName)
.count(orderDetail.getCount() != 0 ? orderDetail.getCount() : 0)
.price(calculatePrice(orderDetail.getPrice()))
.totalPrice(calculateTotalPrice(orderDetail.getPrice(), orderDetail.getCount()))
.remark(order.getRemark())
.avoidRemark(order.getAvoidRemark())
.onlinePay(onlinePayDesc)
.build();
classifyOrders.add(settlementOrderDetail);
// 3. 判断已退款
if (orderDetail.getServeStatus() == ServeStatusEnum.SERVE_REJECT) {
SettlementDTO.SettlementOrderDetail refundRecord1 = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "订餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(refundRecord1);
SettlementDTO.SettlementOrderDetail refundRecord2 = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), -orderDetail.getCount(), orderDetail.getPrice(), "已退款", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(refundRecord2);
}
// 4. 如果既不是加餐,也不是换菜,也不是退款,才记录“订餐”
boolean isNormal = !(addOriginalDetailMap.containsKey(orderDetail.getId())
&& addOriginalDetailMap.get(orderDetail.getId()).getCount() != orderDetail.getCount())
&& !(replaceOriginalDetailMap.containsKey(orderDetail.getId())
&& !Objects.equals(replaceOriginalDetailMap.get(orderDetail.getId()).getSkuId(), orderDetail.getSkuId()))
&& orderDetail.getServeStatus() != ServeStatusEnum.SERVE_REJECT;
if (isNormal) {
SettlementDTO.SettlementOrderDetail normalRecord = buildSettlementOrderDetail(
order, orderDetail.getMenuDetailId(), orderDetail.getSkuId(), orderDetail.getCount(), orderDetail.getPrice(), "订餐", menuName, customerName, hisCustomerNo, menuDetailMap, mealMap, skuMap);
classifyOrders.add(normalRecord);
}
}
}
// 构建结算数据
......@@ -535,17 +941,57 @@ public class SettlementServiceImpl implements SettlementService {
}
}
private SettlementDTO.SettlementOrderDetail buildSettlementOrderDetail(SingleClientCustomerOrderRpcResponse order,
int menuDetailId,
int skuId,
int count,
Integer price,
String operationType,
String menuName,
String customerName,
String hisCustomerNo,
Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
Map<Integer, SingleMealRpcResponse> mealMap,
Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
String mealName = getMealNameSafely(menuDetailId, menuDetailMap, mealMap);
String skuName = getSkuNameSafely(skuId, skuMap);
String roomNo = getRoomNoSafely(order);
List<String> avoids = getAvoidsSafely(order);
List<String> doctors = getDoctorsSafely(order);
String onlinePayDesc = getOnlinePayDescSafely(order);
return SettlementDTO.SettlementOrderDetail.builder()
.mealTime(order.getMealTime() != 0L ? LocalDateTimeUtil.of(order.getMealTime()).format(DateUtil.YYYY_MM_DD_LEFT_SYMBOL) : "")
.code(order.getOrderCode())
.mealName(mealName)
.roomNo(roomNo)
.customerName(customerName)
.HISCustomerNo(hisCustomerNo)
.avoids(avoids)
.doctors(doctors)
.menuName(menuName)
.skuName(skuName)
.count(count)
.price(calculatePrice(price))
.totalPrice(calculateTotalPrice(price, count))
.remark(order.getRemark())
.avoidRemark(order.getAvoidRemark())
.onlinePay(onlinePayDesc)
.operationType(operationType)
.transactionId(operationType.equals("已退款") ? "" : order.getTransactionId())
.build();
}
/**
* 安全获取餐别名称
*/
private String getMealNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail,
Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
Map<Integer, SingleMealRpcResponse> mealMap) {
if (orderDetail == null || orderDetail.getMenuDetailId() == 0) {
private String getMealNameSafely(int menuDetailId,
Map<Integer, SingleMenuDetailRpcResponse> menuDetailMap,
Map<Integer, SingleMealRpcResponse> mealMap) {
if (menuDetailId == 0) {
return "";
}
final var menuDetail = menuDetailMap.get(orderDetail.getMenuDetailId());
final var menuDetail = menuDetailMap.get(menuDetailId);
if (menuDetail == null || menuDetail.getMealId() == 0) {
return "";
}
......@@ -557,13 +1003,12 @@ public class SettlementServiceImpl implements SettlementService {
/**
* 安全获取SKU名称
*/
private String getSkuNameSafely(SingleClientCustomerOrderDetailRpcResponse orderDetail,
Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
if (orderDetail == null || orderDetail.getSkuId() == 0) {
private String getSkuNameSafely(int skuId,
Map<Integer, SingleDishSkuByIdsRpcResponse> skuMap) {
if (skuId == 0) {
return "";
}
final var sku = skuMap.get(orderDetail.getSkuId());
final var sku = skuMap.get(skuId);
return sku != null ? sku.getName() : "";
}
......@@ -598,268 +1043,65 @@ public class SettlementServiceImpl implements SettlementService {
* 安全获取医嘱列表
*/
private List<String> getDoctorsSafely(SingleClientCustomerOrderRpcResponse order) {
if (order == null) {
return Collections.emptyList();
}
return order.getCustomerNoticeJson().getDoctorsList();
}
/**
* 安全获取在线支付描述
*/
private String getOnlinePayDescSafely(SingleClientCustomerOrderRpcResponse order) {
if (order == null) {
return "";
}
try {
String desc = BaseProtoDescEnum.getDescByProtoEnum(order.getOnlinePay(), OnlinePayDescEnum.class);
return desc != null ? desc : "";
} catch (Exception e) {
log.warn("获取在线支付描述失败,orderId: {}", order.getId(), e);
return "";
}
}
/**
* 计算单价
*/
private BigDecimal calculatePrice(Integer price) {
if (price == null) {
return BigDecimal.ZERO;
}
return new BigDecimal(price).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
/**
* 计算总价
*/
private BigDecimal calculateTotalPrice(Integer price, Integer count) {
if (price == null || count == null) {
return BigDecimal.ZERO;
}
return new BigDecimal(price)
.multiply(new BigDecimal(count))
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
/**
* 创建空的订单Excel
*/
private ByteArrayOutputStream createEmptyExcelByOrder() {
try {
final var emptyData = SettlementDTO.SettlementDataByOrderDto.builder()
.classifyOrders(Collections.emptyList())
.build();
return writeToExcelByOrder(emptyData);
} catch (IOException e) {
log.error("创建空Excel失败", e);
throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
}
}
/**
* 按订单维度生成Excel
*/
private static ByteArrayOutputStream writeToExcelByOrder(SettlementDTO.SettlementDataByOrderDto settlementDataDto)
throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("客人结算");
// 创建表头样式(黑色边框)
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 创建数据行样式(浅灰色边框)
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
int rowNum = 0;
// 创建表头
Row titleRow = sheet.createRow(rowNum++);
int columnNum = 0;
Cell cell0 = titleRow.createCell(columnNum++);
cell0.setCellValue("用餐时间");
cell0.setCellStyle(headerStyle);
Cell cell1 = titleRow.createCell(columnNum++);
cell1.setCellValue("订单号");
cell1.setCellStyle(headerStyle);
Cell cell2 = titleRow.createCell(columnNum++);
cell2.setCellValue("餐别");
cell2.setCellStyle(headerStyle);
Cell cell3 = titleRow.createCell(columnNum++);
cell3.setCellValue("房间号");
cell3.setCellStyle(headerStyle);
Cell cell4 = titleRow.createCell(columnNum++);
cell4.setCellValue("客户姓名");
cell4.setCellStyle(headerStyle);
Cell cell5 = titleRow.createCell(columnNum++);
cell5.setCellValue("客户腕带号");
cell5.setCellStyle(headerStyle);
Cell cell6 = titleRow.createCell(columnNum++);
cell6.setCellValue("忌口信息");
cell6.setCellStyle(headerStyle);
Cell cell7 = titleRow.createCell(columnNum++);
cell7.setCellValue("医嘱信息");
cell7.setCellStyle(headerStyle);
Cell cell8 = titleRow.createCell(columnNum++);
cell8.setCellValue("餐单名称");
cell8.setCellStyle(headerStyle);
Cell cell9 = titleRow.createCell(columnNum++);
cell9.setCellValue("菜品名称");
cell9.setCellStyle(headerStyle);
Cell cell10 = titleRow.createCell(columnNum++);
cell10.setCellValue("菜品份数");
cell10.setCellStyle(headerStyle);
Cell cell11 = titleRow.createCell(columnNum++);
cell11.setCellValue("菜品单价");
cell11.setCellStyle(headerStyle);
Cell cell12 = titleRow.createCell(columnNum++);
cell12.setCellValue("菜品金额");
cell12.setCellStyle(headerStyle);
Cell cell13 = titleRow.createCell(columnNum++);
cell13.setCellValue("备注");
cell13.setCellStyle(headerStyle);
Cell cell14 = titleRow.createCell(columnNum++);
cell14.setCellValue("支付方式");
cell14.setCellStyle(headerStyle);
// 填充数据
final var classifyOrders = settlementDataDto.getClassifyOrders();
if (classifyOrders != null) {
for (SettlementDTO.SettlementOrderDetail orderDetail : classifyOrders) {
Row dataRow = sheet.createRow(rowNum++);
columnNum = 0;
Cell dataCell0 = dataRow.createCell(columnNum++);
dataCell0.setCellValue(orderDetail.getMealTime() != null ? orderDetail.getMealTime() : "");
dataCell0.setCellStyle(dataStyle);
Cell dataCell1 = dataRow.createCell(columnNum++);
dataCell1.setCellValue(orderDetail.getCode() != null ? orderDetail.getCode() : "");
dataCell1.setCellStyle(dataStyle);
Cell dataCell2 = dataRow.createCell(columnNum++);
dataCell2.setCellValue(orderDetail.getMealName() != null ? orderDetail.getMealName() : "");
dataCell2.setCellStyle(dataStyle);
Cell dataCell3 = dataRow.createCell(columnNum++);
dataCell3.setCellValue(orderDetail.getRoomNo() != null ? orderDetail.getRoomNo() : "");
dataCell3.setCellStyle(dataStyle);
Cell dataCell4 = dataRow.createCell(columnNum++);
dataCell4.setCellValue(orderDetail.getCustomerName() != null ? orderDetail.getCustomerName() : "");
dataCell4.setCellStyle(dataStyle);
Cell dataCell5 = dataRow.createCell(columnNum++);
dataCell5.setCellValue(orderDetail.getHISCustomerNo() != null ? orderDetail.getHISCustomerNo() : "");
dataCell5.setCellStyle(dataStyle);
// 忌口列表转字符串
String avoidsStr = orderDetail.getAvoids() != null ? String.join(", ", orderDetail.getAvoids()) : "";
Cell dataCell6 = dataRow.createCell(columnNum++);
dataCell6.setCellValue(avoidsStr);
dataCell6.setCellStyle(dataStyle);
// 医嘱列表转字符串
String doctorsStr = orderDetail.getDoctors() != null ? String.join(", ", orderDetail.getDoctors()) : "";
Cell dataCell7 = dataRow.createCell(columnNum++);
dataCell7.setCellValue(doctorsStr);
dataCell7.setCellStyle(dataStyle);
Cell dataCell8 = dataRow.createCell(columnNum++);
dataCell8.setCellValue(orderDetail.getMenuName() != null ? orderDetail.getMenuName() : "");
dataCell8.setCellStyle(dataStyle);
Cell dataCell9 = dataRow.createCell(columnNum++);
dataCell9.setCellValue(orderDetail.getSkuName() != null ? orderDetail.getSkuName() : "");
dataCell9.setCellStyle(dataStyle);
Cell dataCell10 = dataRow.createCell(columnNum++);
dataCell10.setCellValue(orderDetail.getCount() != null ? orderDetail.getCount() : 0);
dataCell10.setCellStyle(dataStyle);
// 价格
Cell dataCell11 = dataRow.createCell(columnNum++);
if (orderDetail.getPrice() != null) {
dataCell11.setCellValue(orderDetail.getPrice().doubleValue());
} else {
dataCell11.setCellValue(0.0);
}
dataCell11.setCellStyle(dataStyle);
// 总价
Cell dataCell12 = dataRow.createCell(columnNum++);
if (orderDetail.getTotalPrice() != null) {
dataCell12.setCellValue(orderDetail.getTotalPrice().doubleValue());
} else {
dataCell12.setCellValue(0.0);
}
dataCell12.setCellStyle(dataStyle);
if (order == null) {
return Collections.emptyList();
}
// 合并备注和忌口备注,用分号分割,备注在前
String remark = orderDetail.getRemark() != null ? orderDetail.getRemark() : "";
String avoidRemark = orderDetail.getAvoidRemark() != null ? orderDetail.getAvoidRemark() : "";
String combinedRemark = "";
if (!remark.isEmpty() && !avoidRemark.isEmpty()) {
combinedRemark = remark + ";" + avoidRemark;
} else if (!remark.isEmpty()) {
combinedRemark = remark;
} else if (!avoidRemark.isEmpty()) {
combinedRemark = avoidRemark;
}
Cell dataCell13 = dataRow.createCell(columnNum++);
dataCell13.setCellValue(combinedRemark);
dataCell13.setCellStyle(dataStyle);
return order.getCustomerNoticeJson().getDoctorsList();
}
Cell dataCell14 = dataRow.createCell(columnNum++);
dataCell14.setCellValue(orderDetail.getOnlinePay() != null ? orderDetail.getOnlinePay() : "");
dataCell14.setCellStyle(dataStyle);
}
/**
* 安全获取在线支付描述
*/
private String getOnlinePayDescSafely(SingleClientCustomerOrderRpcResponse order) {
if (order == null) {
return "";
}
// 自动调整列宽
for (int i = 0; i < 15; i++) {
sheet.autoSizeColumn(i);
try {
String desc = BaseProtoDescEnum.getDescByProtoEnum(order.getOnlinePay(), OnlinePayDescEnum.class);
return desc != null ? desc : "";
} catch (Exception e) {
log.warn("获取在线支付描述失败,orderId: {}", order.getId(), e);
return "";
}
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
/**
* 计算单价
*/
private BigDecimal calculatePrice(Integer price) {
if (price == null) {
return BigDecimal.ZERO;
}
return new BigDecimal(price).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
return outputStream;
/**
* 计算总价
*/
private BigDecimal calculateTotalPrice(Integer price, Integer count) {
if (price == null || count == null) {
return BigDecimal.ZERO;
}
return new BigDecimal(price)
.multiply(new BigDecimal(count))
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
/**
* 创建空的订单Excel
*/
private ByteArrayOutputStream createEmptyExcelByOrder() {
try {
final var emptyData = SettlementDTO.SettlementDataByOrderDto.builder()
.classifyOrders(Collections.emptyList())
.build();
return writeToExcelByOrder(emptyData);
} catch (IOException e) {
log.error("创建空Excel失败", e);
throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
}
}
public ByteArrayOutputStream generateOrderSettlementExcelBySku(SettlementRequestDto settlementRequest) {
......@@ -1249,10 +1491,10 @@ public class SettlementServiceImpl implements SettlementService {
}
// 安全获取餐别名称
String mealName = getMealNameSafely(orderDetail, menuDetailMap, mealMap);
String mealName = getMealNameSafely(orderDetail.getMenuDetailId(), menuDetailMap, mealMap);
// 安全获取SKU名称
String skuName = getSkuNameSafely(orderDetail, skuMap);
String skuName = getSkuNameSafely(orderDetail.getSkuId(), skuMap);
// 安全获取忌口信息(列表转字符串)
List<String> avoidsList = getAvoidsSafely(order);
......@@ -1304,186 +1546,4 @@ public class SettlementServiceImpl implements SettlementService {
}
}
/**
* 生成分餐表Excel
*/
private static ByteArrayOutputStream writeToExcelBySeparateMeal(SeparateMealDataDto separateMealDataDto)
throws IOException {
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("分餐表");
// 创建标题样式(合并单元格标题)
CellStyle titleStyle = workbook.createCellStyle();
titleStyle.setAlignment(HorizontalAlignment.CENTER);
titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);
titleStyle.setBorderTop(BorderStyle.THIN);
titleStyle.setBorderBottom(BorderStyle.THIN);
titleStyle.setBorderLeft(BorderStyle.THIN);
titleStyle.setBorderRight(BorderStyle.THIN);
titleStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
titleStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
Font titleFont = workbook.createFont();
titleFont.setBold(true);
titleFont.setFontHeightInPoints((short) 16);
titleStyle.setFont(titleFont);
// 创建表头样式(黑色边框)
CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setBorderTop(BorderStyle.THIN);
headerStyle.setBorderBottom(BorderStyle.THIN);
headerStyle.setBorderLeft(BorderStyle.THIN);
headerStyle.setBorderRight(BorderStyle.THIN);
headerStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
headerStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 创建数据行样式(浅灰色边框)
CellStyle dataStyle = workbook.createCellStyle();
dataStyle.setBorderTop(BorderStyle.THIN);
dataStyle.setBorderBottom(BorderStyle.THIN);
dataStyle.setBorderLeft(BorderStyle.THIN);
dataStyle.setBorderRight(BorderStyle.THIN);
dataStyle.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
dataStyle.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex());
int rowNum = 0;
// 第一行:创建合并单元格标题
Row mainTitleRow = sheet.createRow(rowNum++);
Cell mainTitleCell = mainTitleRow.createCell(0);
mainTitleCell.setCellValue("住院客户分餐表");
mainTitleCell.setCellStyle(titleStyle);
// 合并第一行的8列
CellRangeAddress titleRegion = new CellRangeAddress(0, 0, 0, 8);
sheet.addMergedRegion(titleRegion);
// 为合并区域设置边框
RegionUtil.setBorderTop(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderBottom(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderLeft(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setBorderRight(BorderStyle.THIN, titleRegion, sheet);
RegionUtil.setTopBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setBottomBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setLeftBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
RegionUtil.setRightBorderColor(IndexedColors.BLACK.getIndex(), titleRegion, sheet);
// 第二行:创建表头
Row titleRow = sheet.createRow(rowNum++);
int columnNum = 0;
Cell cell0 = titleRow.createCell(columnNum++);
cell0.setCellValue("餐别");
cell0.setCellStyle(headerStyle);
Cell cell1 = titleRow.createCell(columnNum++);
cell1.setCellValue("房间号");
cell1.setCellStyle(headerStyle);
Cell cell2 = titleRow.createCell(columnNum++);
cell2.setCellValue("客户姓名");
cell2.setCellStyle(headerStyle);
Cell cell3 = titleRow.createCell(columnNum++);
cell3.setCellValue("医嘱信息");
cell3.setCellStyle(headerStyle);
Cell cell4 = titleRow.createCell(columnNum++);
cell4.setCellValue("餐单名称");
cell4.setCellStyle(headerStyle);
Cell cell5 = titleRow.createCell(columnNum++);
cell5.setCellValue("菜品名称");
cell5.setCellStyle(headerStyle);
Cell cell6 = titleRow.createCell(columnNum++);
cell6.setCellValue("菜品数量");
cell6.setCellStyle(headerStyle);
Cell cell7 = titleRow.createCell(columnNum++);
cell7.setCellValue("忌口信息");
cell7.setCellStyle(headerStyle);
Cell cell8 = titleRow.createCell(columnNum++);
cell8.setCellValue("备注");
cell8.setCellStyle(headerStyle);
// 填充数据
final var mealDetails = separateMealDataDto.getMealDetails();
if (mealDetails != null) {
for (SeparateMealDetail mealDetail : mealDetails) {
Row dataRow = sheet.createRow(rowNum++);
columnNum = 0;
Cell dataCell0 = dataRow.createCell(columnNum++);
dataCell0.setCellValue(mealDetail.getMealName() != null ? mealDetail.getMealName() : "");
dataCell0.setCellStyle(dataStyle);
Cell dataCell1 = dataRow.createCell(columnNum++);
dataCell1.setCellValue(mealDetail.getRoomNo() != null ? mealDetail.getRoomNo() : "");
dataCell1.setCellStyle(dataStyle);
Cell dataCell2 = dataRow.createCell(columnNum++);
dataCell2.setCellValue(mealDetail.getCustomerName() != null ? mealDetail.getCustomerName() : "");
dataCell2.setCellStyle(dataStyle);
Cell dataCell3 = dataRow.createCell(columnNum++);
dataCell3.setCellValue(mealDetail.getDoctors() != null ? mealDetail.getDoctors() : "");
dataCell3.setCellStyle(dataStyle);
Cell dataCell4 = dataRow.createCell(columnNum++);
dataCell4.setCellValue(mealDetail.getMenuName() != null ? mealDetail.getMenuName() : "");
dataCell4.setCellStyle(dataStyle);
Cell dataCell5 = dataRow.createCell(columnNum++);
dataCell5.setCellValue(mealDetail.getSkuName() != null ? mealDetail.getSkuName() : "");
dataCell5.setCellStyle(dataStyle);
Cell dataCell6 = dataRow.createCell(columnNum++);
dataCell6.setCellValue(mealDetail.getCount() != null ? mealDetail.getCount() : 0);
dataCell6.setCellStyle(dataStyle);
Cell dataCell7 = dataRow.createCell(columnNum++);
dataCell7.setCellValue(mealDetail.getAvoids() != null ? mealDetail.getAvoids() : "");
dataCell7.setCellStyle(dataStyle);
Cell dataCell8 = dataRow.createCell(columnNum++);
dataCell8.setCellValue(mealDetail.getRemark() != null ? mealDetail.getRemark() : "");
dataCell8.setCellStyle(dataStyle);
}
}
// 自动调整列宽
for (int i = 0; i < 9; i++) {
sheet.autoSizeColumn(i);
}
// 将工作簿内容写入字节数组输出流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
workbook.write(outputStream);
workbook.close();
return outputStream;
}
/**
* 创建空的分餐表Excel(无数据)
*/
private static ByteArrayOutputStream createEmptyExcelBySeparateMeal() {
try {
SeparateMealDataDto emptyData = SeparateMealDataDto.builder()
.mealDetails(new ArrayList<>())
.build();
return writeToExcelBySeparateMeal(emptyData);
} catch (IOException e) {
log.error("创建空分餐表Excel失败", e);
throw BusinessException.build(ErrorCodeEnum.GENERATE_EXCEL_ERROR);
}
}
}
......
......@@ -2,6 +2,7 @@ package com.infoloop.tianting.utils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
......@@ -41,6 +42,14 @@ public class JsonUtil {
}
}
public static <T> T readJsonAs(final String json, final TypeReference<T> typeRef) {
try {
return OBJECT_MAPPER.readValue(json, typeRef);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static <T> T convertValue(final Object object, final Class<T> clazz) {
return OBJECT_MAPPER.convertValue(object, clazz);
}
......
......@@ -32,6 +32,7 @@ service ClientCustomerOrderServiceRpc {
// 操作记录
rpc GetOrderOperationRecordsByOrderId (GetOrderOperationRecordsByOrderIdRequest) returns (GetOrderOperationRecordsByOrderIdResponse) {}
rpc GetOrderOperationRecordsByOrderIds (GetOrderOperationRecordsByOrderIdsRequest) returns (GetOrderOperationRecordsByOrderIdsResponse) {}
rpc BatchCreateOrderOperationRecords (BatchCreateOrderOperationRecordsRequest) returns (BatchCreateOrderOperationRecordsResponse) {}
......@@ -624,6 +625,15 @@ message GetOrderOperationRecordsByOrderIdResponse {
repeated OrderOperationRecord responses = 1;
}
message GetOrderOperationRecordsByOrderIdsRequest {
int32 enterpriseId = 1;
repeated int32 orderIds = 2;
}
message GetOrderOperationRecordsByOrderIdsResponse {
repeated OrderOperationRecord responses = 1;
}
message OrderOperationRecordCreation {
int32 orderId = 1;
OrderOperationType type = 2;
......