zhuyifan

feat(order): add support for partial order refund and not serve status

......@@ -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
......
......@@ -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;
}
......
......@@ -240,6 +240,7 @@ 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 modifications = orderDetailBatchUpdateDto.getDetails().stream().map(d -> {
......@@ -280,9 +281,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 +322,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 +361,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()
......@@ -396,7 +400,7 @@ public class OrderServiceRpcClient {
// 替换菜品的操作记录
List<SingleOperationDto> operations = new ArrayList<>();
for (OrderDetailDto originalDetail : originalOrderDetails) {
if (!idsOfNeedUpdateMenuDetails.contains(originalDetail.getId()) && !idsOfAddCount.contains(originalDetail.getId())) {
if (!totalIds.contains(originalDetail.getId())) {
continue;
}
OrderOperationType orderOperationType = OrderOperationType.UNKNOWN_OPERATION_TYPE;
......@@ -404,6 +408,8 @@ public class OrderServiceRpcClient {
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 = "";
......
......@@ -38,6 +38,7 @@ 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.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
......@@ -66,333 +67,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.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);
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(true)
.setTransactionId(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 +406,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);
}
}
}
}
......