package com.tourguide.modules.order.service;
|
|
import com.tourguide.modules.operation.entity.OperationScenicSpot;
|
import com.tourguide.modules.operation.entity.ScenicPricing;
|
import com.tourguide.modules.operation.mapper.OperationScenicSpotMapper;
|
import com.tourguide.modules.operation.mapper.ScenicPricingMapper;
|
import com.tourguide.modules.order.domain.OrderStatus;
|
import com.tourguide.modules.order.entity.TourOrder;
|
import com.tourguide.modules.order.mapper.TourOrderMapper;
|
import com.tourguide.modules.system.service.GuideNotificationService;
|
import com.tourguide.modules.user.entity.GuideReceivingSession;
|
import com.tourguide.modules.user.entity.GuideUser;
|
import com.tourguide.modules.user.mapper.GuideRealtimeStatusMapper;
|
import com.tourguide.modules.user.mapper.GuideReceivingSessionMapper;
|
import com.tourguide.modules.user.mapper.GuideUserMapper;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.time.LocalDateTime;
|
import java.util.List;
|
|
@Service
|
public class GuideOrderMatchingService {
|
private final TourOrderMapper orderMapper;
|
private final GuideReceivingSessionMapper sessionMapper;
|
private final GuideUserMapper guideUserMapper;
|
private final GuideRealtimeStatusMapper realtimeStatusMapper;
|
private final OperationScenicSpotMapper scenicMapper;
|
private final ScenicPricingMapper pricingMapper;
|
private final GuideOrderEarningSnapshotService earningSnapshotService;
|
private final GuideNotificationService notificationService;
|
|
public GuideOrderMatchingService(TourOrderMapper orderMapper, GuideReceivingSessionMapper sessionMapper,
|
GuideUserMapper guideUserMapper, GuideRealtimeStatusMapper realtimeStatusMapper,
|
OperationScenicSpotMapper scenicMapper, ScenicPricingMapper pricingMapper,
|
GuideOrderEarningSnapshotService earningSnapshotService,
|
GuideNotificationService notificationService) {
|
this.orderMapper = orderMapper;
|
this.sessionMapper = sessionMapper;
|
this.guideUserMapper = guideUserMapper;
|
this.realtimeStatusMapper = realtimeStatusMapper;
|
this.scenicMapper = scenicMapper;
|
this.pricingMapper = pricingMapper;
|
this.earningSnapshotService = earningSnapshotService;
|
this.notificationService = notificationService;
|
}
|
|
@Transactional
|
public boolean match(Long orderId) {
|
TourOrder order = orderMapper.selectForUpdate(orderId);
|
if (order == null || !OrderStatus.PENDING_ACCEPT.matches(order.getStatus()) || order.getGuideId() != null) return false;
|
if (order.getScenicSpotId() == null || order.getMeetingPointId() == null || order.getServicePackageId() == null) return false;
|
String mode = order.getOrderType().startsWith("GROUP_") ? "GROUP" : "PRIVATE";
|
List<GuideReceivingSession> candidates = sessionMapper.selectMatchCandidates(order.getScenicSpotId(),
|
order.getMeetingPointId(), mode, order.getOrderType());
|
ScenicPricing pricing = pricingMapper.selectById(order.getServicePackageId());
|
OperationScenicSpot scenic = scenicMapper.selectById(order.getScenicSpotId());
|
if (pricing == null || scenic == null) return false;
|
for (GuideReceivingSession session : candidates) {
|
LocalDateTime now = LocalDateTime.now();
|
boolean reserved = "GROUP".equals(mode)
|
? reserveGroup(session, order, pricing, scenic, now)
|
: sessionMapper.assignPrivate(session.getId(), order.getPeopleCount(), now) == 1;
|
if (!reserved) continue;
|
GuideUser guide = guideUserMapper.selectById(session.getGuideId());
|
if (guide == null) continue;
|
order.setReceivingSessionId(session.getId());
|
order.setGuideId(guide.getId());
|
order.setGuideName(guide.getRealName());
|
order.setGuideMobile(guide.getMobile());
|
order.setAcceptedAt(now);
|
order.setStatus(OrderStatus.PENDING_MEETING.getCode());
|
earningSnapshotService.apply(order, guide);
|
orderMapper.updateById(order);
|
guideUserMapper.incrementAcceptedOrderCount(guide.getId());
|
if ("PRIVATE".equals(mode)) realtimeStatusMapper.disableReceiving(guide.getId());
|
notificationService.notifyOrderAssigned(order);
|
return true;
|
}
|
return false;
|
}
|
|
private boolean reserveGroup(GuideReceivingSession session, TourOrder order, ScenicPricing pricing,
|
OperationScenicSpot scenic, LocalDateTime now) {
|
Integer maxPeople = pricing.getMaxParticipants();
|
if (maxPeople == null || maxPeople < 1) return false;
|
int leadMinutes = positive(scenic.getFirstOrderLeadMinutes(), 15);
|
int cutoffMinutes = positive(scenic.getVisitorNoOrderMinutes(), leadMinutes);
|
return sessionMapper.reserveGroupCapacity(session.getId(), order.getPeopleCount(), maxPeople, now,
|
now.plusMinutes(leadMinutes), now.plusMinutes(cutoffMinutes)) == 1;
|
}
|
|
private int positive(Integer value, int fallback) { return value == null || value < 1 ? fallback : value; }
|
}
|