Merge remote-tracking branch 'origin/dev' into dev

# Conflicts:
#	src/test/java/com/chint/RouteApplicationTests.java
This commit is contained in:
huangxh3 2024-02-21 08:27:42 +08:00
commit 23ceb54308
37 changed files with 521 additions and 109 deletions

View File

@ -9,10 +9,21 @@ import lombok.EqualsAndHashCode;
public class OrderStatusChangeCommand extends Command {
private Long orderId;
private String orderNo;
private String outStatus;
private Integer orderEventType;
public OrderStatusChangeCommand eventType(Integer eventType) {
this.orderEventType = eventType;
return this;
}
public OrderStatusChangeCommand orderNo(String orderNo) {
this.orderNo = orderNo;
return this;
}
public OrderStatusChangeCommand outStatus(String outStatus) {
this.outStatus = outStatus;
return this;
}
}

View File

@ -3,13 +3,12 @@ package com.chint.application.dtos.response;
import cn.hutool.core.bean.BeanUtil;
import com.chint.domain.aggregates.order.Leg;
import com.chint.domain.aggregates.order.LegExtensionField;
import com.chint.domain.aggregates.order.OrderDetail;
import com.chint.domain.value_object.enums.CurrencyType;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
@ -25,17 +24,19 @@ public class LegRes {
private String createTime;
private LocationRes originLocation;
private LocationRes destinationLocation;
@Transient
private String amount;
@Transient
private String legTypeName;
@Transient
private String legTypeEnName;
private Integer amountType;
private String amountTypeName;
private String amountTypeEnName;
private Integer legStatus;
@Transient
private String legStatusName;
@Transient
private CurrencyType currencyType;
@Transient
private List<OrderDetail> orderDetails; //这个属性不做持久化保存 根据下单事件进行获取
public static LegRes copyFrom(Leg leg) {
@ -44,6 +45,12 @@ public class LegRes {
legRes.startTime = dateTimeFormatter.format(leg.getStartTime());
legRes.endTime = dateTimeFormatter.format(leg.getEndTime());
legRes.createTime = dateTimeFormatter.format(leg.getCreateTime());
LegExtensionField legExtensionField = leg.getLegExtensionField();
if (legExtensionField != null) {
legRes.setAmountType(legExtensionField.getAmountType());
legRes.setAmountTypeName(legExtensionField.getAmountTypeName());
legRes.setAmountTypeEnName(legExtensionField.getAmountTypeEnName());
}
return legRes;
}
}

View File

@ -89,9 +89,7 @@ public class OrderController {
@ApiOperation("审批通过行程规划单")
@PostMapping("/success")
public Result<String> approvalOrder(@RequestBody ApprovalLegData approvalLegData) {
orderApplicationService.reject(approvalLegData);
orderApplicationService.approvalSuccess(approvalLegData);
return Result.Success(SUCCESS);
}
}

View File

@ -71,8 +71,12 @@ public class OrderApplicationService {
public RouteOrder deleteLegToOrder(DeleteLegData deleteLegData) {
RouteOrder order = Optional.ofNullable(routeRepository.queryById(deleteLegData.getRouteId()))
.orElseThrow(() -> new NotFoundException(NOT_FOUND));
if (order.getOrderStatus().equals(ORDER_STATUS_PREPARE)) {
order.deleteLeg(deleteLegData.getLegNo());
return orderDomainService.saveOrder(order);
} else {
throw new OrderException(INVALID_REQUEST);
}
}
@Transactional
@ -114,7 +118,8 @@ public class OrderApplicationService {
}
@Transactional
public void approval(ApprovalLegData data) {
public void approvalSuccess(ApprovalLegData data) {
Command.of(OrderApprovalCommand.class).actualNo(data.getActualOrderNo()).sendToQueue();
}
}

View File

@ -123,6 +123,7 @@ public class Leg {
this.legStatusName = translateLegStatus(this.legStatus);
if (legType != null) {
this.legTypeName = translateLegType(this.legType);
this.legTypeEnName = translateLegTypeEn(this.legType);
}
return this;
}
@ -165,6 +166,17 @@ public class Leg {
};
}
public String translateLegTypeEn(int type) {
return switch (type) {
case LEG_TYPE_TRAIN -> LEG_TYPE_TRAIN_EN_NAME;
case LEG_TYPE_AIRPLANE -> LEG_TYPE_AIRPLANE_EN_NAME;
case LEG_TYPE_HOTEL -> LEG_TYPE_HOTEL_EN_NAME;
case LEG_TYPE_TAXI -> LEG_TYPE_TAXI_EN_NAME;
case LEG_TYPE_OTHER -> LEG_TYPE_OTHER_EN_NAME;
default -> "未知类型";
};
}
public Leg addEvent(LegEvent event) {
if (eventList == null) {
eventList = new ArrayList<>();

View File

@ -21,6 +21,7 @@ public class LegExtensionField {
private String expenseExplanation;
private String originDescription;
private String destinationDescription;
private String estimatedAmount;
public LegExtensionField reloadStatus() {

View File

@ -15,13 +15,15 @@ import static com.chint.infrastructure.constant.Constant.*;
public class OrderEvent {
@Id
private Long orderEventId;
@Column("route_id")
private Long routeId;
@Column("order_id")
private Long orderId;
private Integer eventType;
@Transient
private String eventName;
private String outStatusName;
private LocalDateTime happenTime;
public String translateOrderEvent(int event) {
@ -46,4 +48,11 @@ public class OrderEvent {
orderEvent.setEventType(eventType);
return orderEvent;
}
public static OrderEvent of(Integer eventType, String outStatusName) {
OrderEvent orderEvent = new OrderEvent();
orderEvent.setEventType(eventType);
orderEvent.setOutStatusName(outStatusName);
return orderEvent;
}
}

View File

@ -171,6 +171,14 @@ public class RouteOrder extends BaseEntity {
if (this.supplierName != null) {
this.supplierCNName = translateOrderSupplierName(this.supplierName);
}
if (this.approveEvents != null && !this.approveEvents.isEmpty()) {
this.approvalStatus = this.approveEvents.stream()
.max(Comparator.comparingLong(ApprovalEvent::getApprovalEventId))
.get()
.reloadStatus()
.getEventName();
}
return this;
}

View File

@ -1,5 +1,6 @@
package com.chint.domain.factoriy.leg;
import cn.hutool.core.bean.BeanUtil;
import com.chint.domain.aggregates.order.Leg;
import com.chint.domain.aggregates.order.LegExtensionField;
import com.chint.domain.factoriy.location.LocationFactory;
@ -44,9 +45,17 @@ public class RouteLegFactory implements LegFactory {
leg.setLegExtensionField(legExtensionField);
}
leg.setStartTime(LocalDateTime.parse(data.getStartTime(), formatter));
if (data.getEndTime() != null) {
leg.setEndTime(LocalDateTime.parse(data.getEndTime(), formatter));
} else {
leg.setEndTime(LocalDateTime.parse(data.getStartTime(), formatter));
}
leg.setOriginId(data.getOriginId());
if (data.getDestinationId() != null) {
leg.setDestinationId(data.getDestinationId());
} else {
leg.setDestinationId(data.getOriginId());
}
leg.setCreateTime(LocalDateTime.now());
if (data.getLegId() != null) {
leg.setLegId(data.getLegId());
@ -56,11 +65,6 @@ public class RouteLegFactory implements LegFactory {
private static LegExtensionField getLegExtensionField(LegData data) {
LegExtensionFieldData legExtensionFieldData = data.getLegExtensionFieldData();
LegExtensionField legExtensionField = new LegExtensionField();
legExtensionField.setAmountType(legExtensionFieldData.getAmountType());
legExtensionField.setExpenseExplanation(legExtensionFieldData.getExpenseExplanation());
legExtensionField.setOriginDescription(legExtensionFieldData.getOriginDescription());
legExtensionField.setDestinationDescription(legExtensionFieldData.getDestinationDescription());
return legExtensionField;
return BeanUtil.copyProperties(legExtensionFieldData, LegExtensionField.class);
}
}

View File

@ -7,5 +7,5 @@ import com.chint.domain.value_object.OrderLegData;
public interface OrderDetailFactory {
OrderDetail create(OrderLegData orderLegData);
OrderEvent createEvent(Integer eventType);
OrderEvent createEvent(Integer eventType,String outStatus);
}

View File

@ -5,15 +5,19 @@ import com.chint.domain.aggregates.order.OrderEvent;
import com.chint.domain.value_object.OrderLegData;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
@Component
public class OrderDetailFactoryImpl implements OrderDetailFactory {
@Override
public OrderDetail create(OrderLegData orderLegData) {
return OrderDetail.of(orderLegData.getOrderNo(), orderLegData.getSupplierName());
return OrderDetail.of(orderLegData.getOutOrderNo(), orderLegData.getSupplierName());
}
@Override
public OrderEvent createEvent(Integer eventType) {
return OrderEvent.of(eventType);
public OrderEvent createEvent(Integer eventType, String outStatus) {
OrderEvent orderEvent = OrderEvent.of(eventType, outStatus);
orderEvent.setHappenTime(LocalDateTime.now());
return orderEvent;
}
}

View File

@ -8,4 +8,6 @@ public interface OrderDetailRepository {
OrderDetail findById(Long orderDetailId);
Optional<OrderDetail> findByOrderNo(String orderNo);
OrderDetail save(OrderDetail orderDetail);
}

View File

@ -13,6 +13,8 @@ public interface RouteRepository {
RouteOrder findByActualOrderNo(String actualOrderNo);
RouteOrder findByOrderNo(String orderNo);
RouteOrder save(RouteOrder routeOrder);

View File

@ -5,11 +5,13 @@ import com.chint.application.commands.OrderCreateCommand;
import com.chint.application.commands.OrderStatusChangeCommand;
import com.chint.domain.aggregates.order.ApprovalEvent;
import com.chint.domain.aggregates.order.Leg;
import com.chint.domain.aggregates.order.OrderEvent;
import com.chint.domain.aggregates.order.RouteOrder;
import com.chint.domain.aggregates.user.User;
import com.chint.domain.factoriy.order.RouteOrderFactory;
import com.chint.domain.factoriy.order_detail.OrderDetailFactory;
import com.chint.domain.repository.LocationRepository;
import com.chint.domain.repository.OrderDetailRepository;
import com.chint.domain.repository.RouteRepository;
import com.chint.domain.repository.UserRepository;
import com.chint.domain.value_object.UserLoginParam;
@ -40,6 +42,9 @@ public class OrderDomainService {
@Autowired
private OrderDetailFactory orderDetailFactory;
@Autowired
private OrderDetailRepository orderDetailRepository;
public RouteOrder saveOrder(RouteOrder routeOrder) {
return routeRepository.save(routeOrder);
}
@ -77,8 +82,13 @@ public class OrderDomainService {
this.saveOrder(route);
});
}
@ListenTo(command = "OrderStatusChangeCommand", order = 0)
public void orderDetailStatusChange(OrderStatusChangeCommand command) {
// orderDetailFactory.createEvent(command.get)
orderDetailRepository.findByOrderNo(command.getOrderNo()).ifPresent(orderDetail -> {
OrderEvent event = orderDetailFactory.createEvent(command.getOrderEventType(),command.getOutStatus());
orderDetail.addOrderEvent(event);
orderDetailRepository.save(orderDetail);
});
}
}

View File

@ -2,6 +2,7 @@ package com.chint.domain.service.leg_event;
import com.chint.application.commands.*;
import com.chint.domain.aggregates.order.*;
import com.chint.domain.aggregates.user.User;
import com.chint.domain.exceptions.CommandException;
import com.chint.domain.factoriy.leg_event.LegEventFactory;
import com.chint.domain.factoriy.order.RouteOrderFactory;
@ -9,11 +10,13 @@ import com.chint.domain.factoriy.order_detail.OrderDetailFactory;
import com.chint.domain.repository.LegRepository;
import com.chint.domain.repository.OrderDetailRepository;
import com.chint.domain.repository.RouteRepository;
import com.chint.domain.repository.UserRepository;
import com.chint.domain.service.order_sync.SyncAdapter;
import com.chint.domain.value_object.ApproveLegData;
import com.chint.domain.value_object.OrderLegData;
import com.chint.domain.value_object.PayLegData;
import com.chint.domain.value_object.SyncLegData;
import com.chint.infrastructure.util.BaseContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -46,6 +49,9 @@ public class LegEventHandler implements LegEventService {
@Autowired
private OrderDetailRepository orderDetailRepository;
@Autowired
private UserRepository userRepository;
@Transactional
@Override
public void prepareLeg(LegPrepareCommand command) {
@ -106,25 +112,31 @@ public class LegEventHandler implements LegEventService {
@Override
public void routeUpdateOrder(RouteUpdateOrderCommand command) {
OrderLegData data = command.getData();
String actualOrderNo = data.getActualOrderNo();
RouteOrder routeOrder = routeRepository.findByActualOrderNo(actualOrderNo);
String orderNo = data.getSelfOrderNo();
RouteOrder routeOrder = routeRepository.findByOrderNo(orderNo);
//获取行程规划单创建者作为该订单
Long employeeNo = routeOrder.getUserId();
User byUserEmployeeNo = userRepository.findByUserEmployeeNo(employeeNo);
BaseContext.setCurrentUser(byUserEmployeeNo);
//首先查询到行程规划订单 从routOrder当中查询是否以及存在该订单
Optional<OrderDetail> byOrderNo = routeOrder.getOrderDetails()
.stream()
.filter(orderDetail -> orderDetail.getOrderNo().equals(data.getOrderNo()))
.filter(orderDetail -> orderDetail.getOrderNo().equals(data.getOutOrderNo()))
.findFirst();
if (byOrderNo.isPresent()) {
//如果订单以及存在了对订单的状态进行更新
OrderEvent event = orderDetailFactory.createEvent(data.getOrderStatus());
OrderDetail orderDetail = byOrderNo.get();
orderDetail.addOrderEvent(event);
} else {
if (byOrderNo.isEmpty())
// {
// //如果订单以及存在了对订单的状态进行更新
// OrderEvent event = orderDetailFactory.createEvent(data.getOrderStatus(), data.getOriginOrderStatus());
// OrderDetail orderDetail = byOrderNo.get();
// orderDetail.addOrderEvent(event);
// } else
{
//否则创建新的订单添加到routeOrder
OrderDetail orderDetail = orderDetailFactory.create(data)
.price(data.getPrice()).productType(data.getProductType());
//为订单添加订单已下单事件
OrderEvent orderEvent = orderDetailFactory.createEvent(ORDER_EVENT_PREPARE);
orderDetail.addOrderEvent(orderEvent);
// OrderEvent orderEvent = orderDetailFactory.createEvent(ORDER_EVENT_PREPARE, data.getOriginOrderStatus());
// orderDetail.addOrderEvent(orderEvent);
routeOrder.addOrderDetail(orderDetail);
//结合外部订单信息筛选最合适的leg节点 触发下单事件
routeOrder.getLegItems()
@ -184,10 +196,19 @@ public class LegEventHandler implements LegEventService {
@Transactional
@Override
public void rejectLeg(LegRejectCommand command) {
RouteOrder routeOrder = routeRepository.findByActualOrderNo(command.getData().getActualOrderNo());
RouteOrder routeOrder = routeRepository.findByActualOrderNo(command.getData().getActualOrderNo()).reloadStatus();
if (routeOrder.getOrderStatus() >= ORDER_STATUS_NOT_ORDERED) {
//这里查看routeOrder的状态 如果是已经同步过的订单 需要取消同步到供应商的订单
if (!syncAdapter.of(routeOrder.getSupplierName()).cancelSyncSupplierOrder(routeOrder)) {
throw new CommandException("订单取消失败");
}
}
LegEvent legEvent = legEventFactory.creatLegEvent(command.getLegEventType());
routeOrder.getLegItems().forEach(leg -> leg.addEvent(legEvent));
//为每一个行程节点添加审批拒绝时间 routeOrder 也添加审批拒绝时间
//为每一个行程节点添加审批拒绝时间 routeOrder 也添加审批拒绝事件
ApprovalEvent approvalEvent = routeOrderFactory.createApprovalEvent(APPROVAL_EVENT_FAIL);
routeOrder.addApprovalEvent(approvalEvent);
routeRepository.save(routeOrder);
}
}

View File

@ -42,15 +42,26 @@ public class CTripOrderSyncAdapter implements SupplierOrderSync {
@Override
public boolean syncSupplierOrder(RouteOrder order) {
System.out.println("开始同步协程订单");
User currentUser = BaseContext.getCurrentUser();
ApproveOrderNo approveOrderNo = order.getApproveOrderNo();
RankInfo rankInfo = RankInfo.of(currentUser.getRankCode());
Map<Integer, List<Leg>> collect = orderDomainService.queryLocation(order.getLegItems())
.stream().collect(Collectors.groupingBy(Leg::getLegType));
ApprovalRequest approvalRequestParam = getApprovalRequestParam(order);
ApprovalResult approval = approvalRequest.approval(approvalRequestParam);
return approval.getSetApprovalResult().getStatus().getSuccess();
}
@Override
public boolean cancelSyncSupplierOrder(RouteOrder order) {
System.out.println("开始取消协程订单");
ApprovalRequest approvalRequestParam = getApprovalRequestParam(order);
ApprovalResult approval = approvalRequest.cancelApprovalOrder(approvalRequestParam);
return approval.getSetApprovalResult().getStatus().getSuccess();
}
private ApprovalRequest getApprovalRequestParam(RouteOrder order) {
User currentUser = BaseContext.getCurrentUser();
RankInfo rankInfo = RankInfo.of(currentUser.getRankCode());
ApprovalRequest approvalRequestParam = ApprovalRequest
.buildApproval(order.getRouteOrderNo(), String.valueOf(currentUser.getEmployeeNo()), rankInfo);
Map<Integer, List<Leg>> collect = orderDomainService.queryLocation(order.getLegItems())
.stream().collect(Collectors.groupingBy(Leg::getLegType));
collect.forEach((k, v) -> {
switch (k) {
case LEG_TYPE_TRAIN -> approvalRequestParam.withTrain(generateTrainList(v));
@ -59,9 +70,7 @@ public class CTripOrderSyncAdapter implements SupplierOrderSync {
case LEG_TYPE_TAXI -> approvalRequestParam.withQuickCar(generateCarList(v));
}
});
ApprovalResult approval = approvalRequest.approval(approvalRequestParam);
return approval.getSetApprovalResult().getStatus().getSuccess();
return approvalRequestParam;
}
private List<HotelEndorsementDetail> generateHotelList(List<Leg> legs) {

View File

@ -81,6 +81,11 @@ public class LYOrderSyncAdapter implements SupplierOrderSync {
return Boolean.parseBoolean(success);
}
@Override
public boolean cancelSyncSupplierOrder(RouteOrder order) {
return false;
}
//同程Leg集合解析
private List<AOSItem> getAosItems(RouteOrder order) {
List<AOSItem> aosItems = new ArrayList<>();

View File

@ -6,4 +6,6 @@ import com.chint.domain.factoriy.order.RouteOrderFactory;
public interface SupplierOrderSync {
boolean syncSupplierOrder(RouteOrder order);
boolean cancelSyncSupplierOrder(RouteOrder order);
}

View File

@ -28,9 +28,9 @@ public class CTripOrderDataAdapter implements OrderDataAdapter {
ItineraryEntity itineraryEntity = itineraryList.get(0);
OrderLegData.Builder builder = OrderLegData.builder()
.actualOrderNo(itineraryEntity.getJourneyNO())
.supplierName(SUPPLIER_C_TRIP);
String journeyNo = itineraryEntity.getHotelOrderInfoList().get(0).getJourneyNo();
System.out.println(journeyNo);
OrderLegData.Builder elementList = findSingleElementList(itineraryEntity, builder);
if (elementList == null) {
return Optional.empty();
@ -46,7 +46,10 @@ public class CTripOrderDataAdapter implements OrderDataAdapter {
if (hotelOrderInfoList != null && hotelOrderInfoList.size() == 1) {
HotelOrderInfoEntity hotelOrderInfoEntity = hotelOrderInfoList.get(0);
return builder.productType(LEG_TYPE_HOTEL)
.orderNo(hotelOrderInfoEntity.getOrderId())
.selfOrderNo(hotelOrderInfoEntity.getJourneyNo())
.outOrderNo(hotelOrderInfoEntity.getOrderID())
.orderStatus(translateHotelOrderStatus(hotelOrderInfoEntity.getOrderDetailStatus()))
.originOrderStatus(hotelOrderInfoEntity.getOrderDetailStatus())
.price(hotelOrderInfoEntity.getAmount());
}
// 处理航班订单
@ -54,7 +57,10 @@ public class CTripOrderDataAdapter implements OrderDataAdapter {
if (flightOrderInfoList != null && flightOrderInfoList.size() == 1) {
FlightOrderInfoEntity flightOrderInfo = flightOrderInfoList.get(0);
return builder.productType(LEG_TYPE_AIRPLANE)
.orderNo(flightOrderInfo.getBasicInfo().getOrderID())
.selfOrderNo(flightOrderInfo.getBasicInfo().getJourneyID())
.outOrderNo(flightOrderInfo.getBasicInfo().getOrderID())
.orderStatus(translateFlightOrderStatus(flightOrderInfo.getBasicInfo().getOrderStatus()))
.originOrderStatus(flightOrderInfo.getBasicInfo().getOrderStatus())
.price(flightOrderInfo.getFlightOrderFeeDetailList().get(0).getPayCurrency());
}
@ -63,7 +69,9 @@ public class CTripOrderDataAdapter implements OrderDataAdapter {
if (trainOrderInfoList != null && trainOrderInfoList.size() == 1) {
TrainOrderInfoEntity trainOrderInfo = trainOrderInfoList.get(0);
return builder.productType(LEG_TYPE_TRAIN)
.orderNo(trainOrderInfo.getBasicInfo().getOrderID())
.outOrderNo(trainOrderInfo.getBasicInfo().getOrderID())
.orderStatus(translateTrainOrderStatus(trainOrderInfo.getBasicInfo().getOrderStatus()))
.originOrderStatus(trainOrderInfo.getBasicInfo().getOrderStatus())
.price(String.valueOf(trainOrderInfo.getOrderPaymentList().get(0).getFeeAmount()));
}
@ -72,7 +80,9 @@ public class CTripOrderDataAdapter implements OrderDataAdapter {
if (carOrderInfoList != null && carOrderInfoList.size() == 1) {
CarOrderInfoEntity carOrderInfo = carOrderInfoList.get(0);
return builder.productType(LEG_TYPE_TAXI)
.orderNo(String.valueOf(carOrderInfo.getBasicInfo().getOrderId()))
.outOrderNo(String.valueOf(carOrderInfo.getBasicInfo().getOrderId()))
.orderStatus(translateCarOrderStatus(carOrderInfo.getBasicInfo().getOrderStatus()))
.originOrderStatus(carOrderInfo.getBasicInfo().getOrderStatus())
.price(String.valueOf(carOrderInfo.getPaymentInfoList().get(0).getAmount()));
}

View File

@ -28,7 +28,7 @@ public class LYOrderDataAdapter implements OrderDataAdapter {
return Optional.of(
OrderLegData.builder()
.productType(LEG_TYPE_TRAIN)
.orderNo(data.getOrderNo())
.outOrderNo(data.getOrderNo())
.price(String.valueOf( data.getTotalAmount()))
.actualOrderNo(data.getOutOrderNo())
.supplierName(SUPPLIER_L_Y)

View File

@ -17,7 +17,9 @@ public class SupplierServiceImpl implements SupplierService {
orderDataAdapterSelector
.of(callbackData.getSupplierName())
.adapt(callbackData)
.ifPresent(data ->
Command.of(RouteUpdateOrderCommand.class).data(data).sendToQueue());
.ifPresent(data -> {
System.out.println(data);
Command.of(RouteUpdateOrderCommand.class).data(data).sendToQueue();
});
}
}

View File

@ -14,4 +14,6 @@ public class LegExtensionFieldData {
private String originDescription;
@ApiModelProperty("目的地详细")
private String destinationDescription;
@ApiModelProperty("预估金额")
private String estimatedAmount;
}

View File

@ -9,7 +9,8 @@ import lombok.NoArgsConstructor;
@Data
public class OrderLegData {
private String actualOrderNo;
private String orderNo;
private String selfOrderNo;
private String outOrderNo;
private String supplierName;
private Integer productType;
private String price;
@ -18,10 +19,13 @@ public class OrderLegData {
private OrderLegData(Builder builder) {
this.actualOrderNo = builder.actualOrderNo;
this.orderNo = builder.orderNo;
this.outOrderNo = builder.outOrderNo;
this.selfOrderNo = builder.selfOrderNo;
this.supplierName = builder.supplierName;
this.productType = builder.productType;
this.price = builder.price;
this.orderStatus = builder.orderStatus;
this.originOrderStatus = builder.originOrderStatus;
}
public static Builder builder() {
@ -31,7 +35,8 @@ public class OrderLegData {
// Builder class
public static class Builder {
private String actualOrderNo;
private String orderNo;
private String selfOrderNo;
private String outOrderNo;
private String supplierName;
private Integer productType;
private String price;
@ -46,8 +51,13 @@ public class OrderLegData {
return this;
}
public Builder orderNo(String orderNo) {
this.orderNo = orderNo;
public Builder selfOrderNo(String selfOrderNo) {
this.selfOrderNo = selfOrderNo;
return this;
}
public Builder outOrderNo(String outOrderNo) {
this.outOrderNo = outOrderNo;
return this;
}

View File

@ -7,6 +7,8 @@ public class SupplierCallbackData {
private String supplierName;
private String employeeNo;
private Integer productType; //用于区分同程搜索数据
private Integer selfOrderStatus;
private String outOrderStatus;
private Object data;
public static SupplierCallbackData of(String supplierName, String employeeNo) {
@ -16,6 +18,12 @@ public class SupplierCallbackData {
return supplierCallbackData;
}
public static SupplierCallbackData of(String supplierName) {
SupplierCallbackData supplierCallbackData = new SupplierCallbackData();
supplierCallbackData.setSupplierName(supplierName);
return supplierCallbackData;
}
public SupplierCallbackData data(Object data) {
this.data = data;
return this;

View File

@ -25,4 +25,9 @@ public class OrderDetailRepositoryImpl implements OrderDetailRepository {
public Optional<OrderDetail> findByOrderNo(String orderNo) {
return Optional.ofNullable(orderDetailRepository.findByOrderNo(orderNo));
}
@Override
public OrderDetail save(OrderDetail orderDetail) {
return orderDetailRepository.save(orderDetail);
}
}

View File

@ -42,6 +42,11 @@ public class RouteRepositoryImpl implements RouteRepository {
return jdbcRouteRepository.findByApproveOrderNo_ActualOrderNo(actualOrderNo);
}
@Override
public RouteOrder findByOrderNo(String orderNo) {
return jdbcRouteRepository.findByRouteOrderNo(orderNo);
}
@Override
public RouteOrder save(RouteOrder routeOrder) {
return jdbcRouteRepository.save(routeOrder);

View File

@ -16,4 +16,6 @@ public interface JdbcRouteRepository extends CrudRepository<RouteOrder, Long> {
RouteOrder findByApproveOrderNo_ActualOrderNo(String approveOrderNo_actualOrderNo);
RouteOrder findByRouteOrderNo(String routeOrderNo);
}

View File

@ -1,16 +1,19 @@
package com.chint.infrastructure.util;
import javax.crypto.*;
import java.io.UnsupportedEncodingException;
import com.chint.interfaces.rest.ctrip.dto.put.CTripNotification;
import org.apache.commons.codec.digest.DigestUtils;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.*;
import static com.chint.infrastructure.constant.Constant.AES_SECRET;
import static com.chint.infrastructure.constant.Constant.C_TRIP_REQUEST_SECRET;
public class Digest {
@ -71,4 +74,58 @@ public class Digest {
throw new RuntimeException(e);
}
}
public static String getPutCTripStatusSign(String corpId,
String productType,
String orderStatus,
String orderId) {
//构造字典
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("secret", C_TRIP_REQUEST_SECRET);
hashMap.put("corpId", corpId);
hashMap.put("productType", productType);
hashMap.put("orderId", orderId);
hashMap.put("orderStatus", orderStatus);
//排序
Collection<String> collection = hashMap.keySet();
ArrayList<String> list = new ArrayList<String>(collection);
Collections.sort(list);
//拼接
String str = "";
for (int i = 0; i < list.size(); i++) {
str += list.get(i) + "=" + hashMap.get(list.get(i));
if (i != list.size() - 1)
str += "&";
}
//SH1加密
return DigestUtils.sha1Hex(str).toUpperCase();
}
public static String getPutCTripEventSign(CTripNotification postRequest) {
//构造字典
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put("secret", C_TRIP_REQUEST_SECRET);
hashMap.put("corpId", postRequest.getCorpId());
hashMap.put("uid", postRequest.getUId());
hashMap.put("messageCategory", postRequest.getMessageCategory());
hashMap.put("messageType", postRequest.getMessageType());
hashMap.put("businessId", postRequest.getBusinessId());
hashMap.put("businessType", postRequest.getBusinessType());
//排序
Collection<String> collection = hashMap.keySet();
ArrayList<String> list = new ArrayList<>(collection);
Collections.sort(list);
//拼接
StringBuilder sb = new StringBuilder();
for (int i = 0; i < list.size(); i++) {
sb.append(list.get(i));
sb.append("=");
sb.append(hashMap.get(list.get(i)));
if (i != list.size() - 1)
sb.append("&");
}
//SH1加密
return DigestUtils.shaHex(sb.toString()).toUpperCase();
}
}

View File

@ -29,4 +29,13 @@ public class CTripApprovalRequest {
approvalRequest.setAuth(Authentication.of(C_TRIP_APP_KEY, ticket));
return postRequest.post(approvalUrl, approvalRequestOut, ApprovalResult.class);
}
public ApprovalResult cancelApprovalOrder(ApprovalRequest approvalRequest) {
ApprovalRequestOut approvalRequestOut = new ApprovalRequestOut();
approvalRequestOut.setRequest(approvalRequest);
String ticket = ticketRequest.loadTicket();
approvalRequest.setStatus(0);
approvalRequest.setAuth(Authentication.of(C_TRIP_APP_KEY, ticket));
return postRequest.post(approvalUrl, approvalRequestOut, ApprovalResult.class);
}
}

View File

@ -1,9 +1,11 @@
package com.chint.interfaces.rest.ctrip.dto.put;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class CTripStatusResponse {
private String errno;
private String errmsg;

View File

@ -12,7 +12,7 @@ import java.util.List;
public class ItineraryEntity {
// 行程单号
private String JourneyNO; // 行程单号
private String JourneyNo; // 行程单号
// 酒店订单信息列表
private List<HotelOrderInfoEntity> HotelOrderInfoList; // 酒店订单信息列表
// 航班订单信息列表

View File

@ -10,5 +10,6 @@ public class BasicInfo {
private String orderStatus;
private String orderStatusCode;
private String UID;
private String JourneyID;
// Other fields and getters/setters
}

View File

@ -6,7 +6,7 @@ import java.util.List;
@Data
public class HotelOrderInfoEntity {
private String OrderId; // 订单ID
private String OrderID; // 订单ID
private String TripId; // 旅行ID
private String Uid; // 用户ID
private String PreEmployeeId; // 预订员工ID

View File

@ -1,7 +1,10 @@
package com.chint.interfaces.rest.ctrip.in;
import com.chint.application.commands.OrderStatusChangeCommand;
import com.chint.domain.service.supplier.SupplierService;
import com.chint.domain.value_object.SupplierCallbackData;
import com.chint.infrastructure.echo_framework.command.Command;
import com.chint.infrastructure.util.Digest;
import com.chint.interfaces.rest.ctrip.CTripOrderSearchRequest;
import com.chint.interfaces.rest.ctrip.dto.put.CTripNoteResponse;
import com.chint.interfaces.rest.ctrip.dto.put.CTripNotification;
@ -14,7 +17,7 @@ import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import static com.chint.infrastructure.constant.Constant.SUPPLIER_C_TRIP;
import static com.chint.infrastructure.constant.Constant.*;
@RestController
@RequestMapping("/public/CTrip")
@ -27,25 +30,200 @@ public class CTripNoteController {
@Autowired
private CTripOrderSearchRequest cTripOrderSearchRequest;
@PostMapping("/event")
public CTripNoteResponse noteEvent(@RequestBody CTripNotification cTripNotification) {
if (cTripNotification.getContent() != null && cTripNotification.getPreEmployeeID() != null) {
//成功触发消息需要查询对于的订单信息調用订单查询的服务来查询该订单详情
SupplierCallbackData supplierCallbackData =
SupplierCallbackData.of(SUPPLIER_C_TRIP, cTripNotification.getPreEmployeeID());
SearchOrderResponse response = cTripOrderSearchRequest
.searchOrderResponseByOrderId(cTripNotification.getBusinessId());
supplierCallbackData.data(response);
supplierService.handleSupplierCallback(supplierCallbackData);
return new CTripNoteResponse("0", "成功收到消息");
}
return new CTripNoteResponse("1", "未收到消息");
}
// @PostMapping("/event")
// public CTripNoteResponse noteEvent(@RequestBody CTripNotification cTripNotification) {
// String putCTripEventSign = Digest.getPutCTripEventSign(cTripNotification);
// if (!putCTripEventSign.equals(cTripNotification.getSign())) {
// return new CTripNoteResponse("1", "sign错误");
// }
//
// if (cTripNotification.getContent() != null && cTripNotification.getPreEmployeeID() != null) {
// //成功触发消息需要查询对于的订单信息調用订单查询的服务来查询该订单详情
// SupplierCallbackData supplierCallbackData =
// SupplierCallbackData.of(SUPPLIER_C_TRIP, cTripNotification.getPreEmployeeID());
// SearchOrderResponse response = cTripOrderSearchRequest
// .searchOrderResponseByOrderId(cTripNotification.getBusinessId());
// supplierCallbackData.data(response);
// supplierService.handleSupplierCallback(supplierCallbackData);
// return new CTripNoteResponse("0", "成功收到消息");
// }
// return new CTripNoteResponse("1", "未收到消息");
// }
@PostMapping("/status")
public CTripStatusResponse statusEvent(@RequestBody CTripStatusNotification cTripStatusNotification) {
// if()
String productType = cTripStatusNotification.getProductType();
String orderStatus = cTripStatusNotification.getOrderStatus();
String orderId = cTripStatusNotification.getOrderId();
String putCTripSign = Digest.getPutCTripStatusSign(cTripStatusNotification.getCorpId(), productType, orderStatus, orderId);
if (!putCTripSign.equals(cTripStatusNotification.getSign())) {
return new CTripStatusResponse("1", "sign错误");
}
if (orderStatus != null && orderId != null) {
return null;
SupplierCallbackData supplierCallbackData =
SupplierCallbackData.of(SUPPLIER_C_TRIP);
SearchOrderResponse response = cTripOrderSearchRequest
.searchOrderResponseByOrderId(orderId);
supplierCallbackData.data(response);
supplierService.handleSupplierCallback(supplierCallbackData);
OrderStatusChangeCommand command = Command.of(OrderStatusChangeCommand.class)
.orderNo(orderId)
.outStatus(orderStatus);
switch (productType) {
case "FlightInternational":
case "FlightDomestic":
command.eventType(mapFlightStatus(orderStatus));
break;
case "HotelMember":
case "HotelContract":
command.eventType(mapHotelStatus(orderStatus));
break;
case "Train":
case "OverseaTrain":
command.eventType(mapTrainStatus(orderStatus));
break;
case "CarPickUpInternational":
case "CarRentalDomestic":
case "CarImmediately":
case "CarPickUpDomesticNew":
case "CarCharterDomestic":
case "BusTicket":
command.eventType(mapCarStatus(orderStatus));
break;
}
command.sendToQueue();
return new CTripStatusResponse("0", "成功收到消息");
}
return new CTripStatusResponse("1", "未收到消息");
}
public Integer mapFlightStatus(String status) {
return switch (status) {
case "Submitted" -> ORDER_EVENT_PREPARE; // "已提交"映射到准备下单
case "Confirmed" -> ORDER_EVENT_ORDERED; // "已客户确认"映射到已下单
case "Ticketed" -> ORDER_EVENT_PAYED; // "已出票"可能意味着已经支付完成
case "Cancelled" -> ORDER_EVENT_CANCEL; // "已取消"映射到取消
case "Refunded" -> ORDER_EVENT_REFUND; // "已经退票"映射到退票
case "RefundCancelled" ->
// 可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "Dealt" ->
// "已经成交"可能意味着订单已完成但没有直接映射可能需要新的状态常量
ORDER_EVENT_PAYED;
case "Rebooked" -> ORDER_EVENT_PAYED;
case "rebookSuccess" -> ORDER_EVENT_CHANGE; // "改签成功"映射到改签
case "RebookedFailed" ->
// "改签失败"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "RebookSubmitted" ->
// "改签提交"可能意味着改签过程开始但没有直接映射
ORDER_EVENT_PAYED;
case "RebookConfirmed" ->
// "改签确认"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "RebookToBePaid" ->
// "改签待支付"可能意味着改签了但未支付但没有直接映射
ORDER_EVENT_PAYED;
case "RebookCancelled" ->
// "改签取消"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "Paid" -> ORDER_EVENT_PAYED; // "已支付"映射到已预定
case "RefundSuccess" -> ORDER_EVENT_REFUND; // "退票成功(退款成功)"映射到退票
default ->
// 处理未知或未映射的状态
-1;
};
}
public Integer mapHotelStatus(String status) {
return switch (status) {
case "Submitted" -> ORDER_EVENT_PREPARE; // "已提交"映射到准备状态
case "Confirmed" -> ORDER_EVENT_ORDERED; // "已客户确认"映射到已下单
case "Cancelled" -> ORDER_EVENT_CANCEL; // "已取消"映射到取消
case "Wait" ->
// "确认中"可能表示订单正在处理中但没有直接映射可能需要新的状态常量
ORDER_EVENT_ORDERED;
case "Paid" -> ORDER_EVENT_PAYED; // "已支付"映射到已预定
case "Dealt" ->
// "已经成交"可能表示订单已完成但没有直接映射可能需要新的状态常量
ORDER_EVENT_PAYED;
case "CheckIn" ->
// "入店打卡"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "CheckOut" ->
// "离店打卡"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "CancellationFailed" ->
// "取消失败"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "submitFailed" ->
// "提交失败"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PREPARE;
default ->
// 处理未知或未映射的状态
-1;
};
}
public Integer mapTrainStatus(String status) {
return switch (status) {
case "Submitted" -> ORDER_EVENT_PREPARE; // "已提交"映射到准备状态
case "Ticketed" ->
// "已出票"可能表示订单已完成出票但没有直接的映射可能需要新的状态常量或使用现有的常量
ORDER_EVENT_PAYED;
case "Cancelled" -> ORDER_EVENT_CANCEL; // "已取消"映射到取消状态
case "Refunded" -> ORDER_EVENT_REFUND; // "已经退票"映射到退票状态
case "Rebooked" -> ORDER_EVENT_CHANGE; // "已经改签"映射到改签状态
case "IssueTicketFailed" ->
// "出票失败"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_ORDERED;
case "RebookedFailed" ->
// "改签失败"也可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "SubmitRefund" ->
// "退票成功"可能最接近"已经退票"但具体映射取决于业务逻辑
ORDER_EVENT_REFUND; // 使用退票状态作为近似映射
case "Paid" -> ORDER_EVENT_PAYED; // "已支付"映射到已预定状态
default ->
// 处理未知或未映射的状态
-1;
};
}
public Integer mapCarStatus(String status) {
return switch (status) {
case "Cancelled" -> ORDER_EVENT_CANCEL; // "已取消"映射到取消状态
case "Dealt" ->
// "已经成交"可能意味着订单已经确认或完成但没有直接映射可能需要新的状态常量
ORDER_EVENT_PAYED;
case "WaitReply" ->
// "等待应答"可能表示订单正在等待确认但没有直接映射可能需要新的状态常量
ORDER_EVENT_ORDERED;
case "WaitService" ->
// "等待接驾"可能表示服务即将开始但没有直接映射可能需要新的状态常量
ORDER_EVENT_ORDERED;
case "Redispatched" ->
// "改派中"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "DriverArrived" ->
// "司机已到达"可能需要新的状态常量因为它没有直接映射
ORDER_EVENT_PAYED;
case "InService" ->
// "正在服务"表示服务正在进行中但没有直接映射可能需要新的状态常量
ORDER_EVENT_PAYED;
case "EndService" ->
// "行程结束"可能意味着服务已完成但没有直接映射可能需要新的状态常量
ORDER_EVENT_PAYED;
case "Canceling" ->
// "取消中"可能表示订单正在取消过程中但没有直接映射可能需要新的状态常量
ORDER_EVENT_REFUND;
default ->
// 处理未知或未映射的状态
-1;
};
}
}

View File

@ -1,6 +1,6 @@
spring:
profiles:
active: test
active: dev
datasource:
driver-class-name: ${chint.datasource.driver-class-name}
url: jdbc:mysql://${chint.datasource.host}:${chint.datasource.port}/${chint.datasource.database}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true

View File

@ -135,10 +135,10 @@ public class CTripTest {
System.out.println(gson.toJson(estimate));
}
// @Test
@Test
void search() {
BaseContext.setCurrentUser(user);
SearchOrderResponse response = orderSearchRequest.searchOrder("actual12345622");
SearchOrderResponse response = orderSearchRequest.searchOrderResponseByOrderId("30469349853");
System.out.println(response);
}

View File

@ -7,11 +7,14 @@ import com.chint.domain.repository.LocationRepository;
import com.chint.domain.repository.RouteRepository;
import com.chint.infrastructure.util.Digest;
import com.chint.interfaces.rest.user.UserHttpRequest;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
import java.util.*;
import static com.chint.infrastructure.constant.Constant.C_TRIP_REQUEST_SECRET;
@SpringBootTest
class RouteApplicationTests {
@ -22,6 +25,9 @@ class RouteApplicationTests {
@Autowired
private LocationRepository locationRepository;
@Autowired
private RouteRepository routeRepository;
private User user = new User(1L, 230615020L, 1, "卢麟哲", "1033719135@qq.com", "15857193365");
@ -32,9 +38,9 @@ class RouteApplicationTests {
@Test
void loginSign() {
String sfno = "231116009";
String sfno = "230615020";
String syscode = "abc";
String billcode = "GG123456";
String billcode = "KKK12321412323";
String sec = "Superdandan";
String timespan = "12312321412312";
String s = Digest.md5(sfno + syscode + billcode + sec + timespan);
@ -56,4 +62,9 @@ class RouteApplicationTests {
locationRepository.saveAll(all);
}
@Test
void deleteRouteOrder(){
routeRepository.deleteById(57L);
}
}