MealOrderServiceImpl.java 10.4 KB
package com.infoloop.tianting.service.impl;

import com.infoloop.tianting.context.LoginContextHolder;
import com.infoloop.tianting.enums.QueryMealOrderStatusEnum;
import com.infoloop.tianting.exception.ClientEndExceptions;
import com.infoloop.tianting.exception.ErrorCodeEnum;
import com.infoloop.tianting.mealorderservice.MealOrderCreation;
import com.infoloop.tianting.mealorderservice.MealOrderOrderMethodEnum;
import com.infoloop.tianting.mealorderservice.MenuSchedule;
import com.infoloop.tianting.mealorderservice.SingleMealOrderRpcResponse;
import com.infoloop.tianting.model.common.CreatedResult;
import com.infoloop.tianting.model.dto.MealOrderDTO;
import com.infoloop.tianting.model.vo.DeliveryRuleVO;
import com.infoloop.tianting.model.vo.MealOrderVO;
import com.infoloop.tianting.service.MealOrderService;
import com.infoloop.tianting.service.client.ClientInventoryServiceRpcClient;
import com.infoloop.tianting.service.client.DeliveryRuleServiceRpcClient;
import com.infoloop.tianting.service.client.MealOrderServiceRpcClient;
import com.infoloop.tianting.utils.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class MealOrderServiceImpl implements MealOrderService {

    private final MealOrderServiceRpcClient mealOrderServiceRpcClient;

    private final ClientInventoryServiceRpcClient clientInventoryServiceRpcClient;

    private final DeliveryRuleServiceRpcClient deliveryRuleServiceRpcClient;

    @Override
    public List<MealOrderVO> queryMealOrders(MealOrderDTO.QueryMealOrderDTO queryMealOrderDTO) {
        final var loginInfo = LoginContextHolder.getLoginInfo();
        var mealOrderRpcResponses = mealOrderServiceRpcClient.queryMealOrdersByCondition(loginInfo.getEnterpriseId(), loginInfo.getId(), null, null);
        final var today = LocalDate.now();
        final var lastWeekStart = today.minusWeeks(1).with(DayOfWeek.MONDAY).atStartOfDay().atZone(DateUtil.CHINA_ZONE).toInstant().toEpochMilli();
        final var lastWeekEnd = today.minusWeeks(1).with(DayOfWeek.SUNDAY).atTime(LocalTime.MAX).atZone(DateUtil.CHINA_ZONE).toInstant().toEpochMilli();
        final var thisWeekStart = today.with(DayOfWeek.MONDAY).atStartOfDay().atZone(DateUtil.CHINA_ZONE).toInstant().toEpochMilli();
        if (queryMealOrderDTO.getStatus() == QueryMealOrderStatusEnum.COMPLETED) {
            mealOrderRpcResponses = mealOrderRpcResponses.stream().filter(e -> e.getReserveDate() < lastWeekStart).toList();
        } else if (queryMealOrderDTO.getStatus() == QueryMealOrderStatusEnum.UNDER_WAY) {
            mealOrderRpcResponses = mealOrderRpcResponses.stream().filter(e -> e.getReserveDate() >= lastWeekStart && e.getReserveDate() <= lastWeekEnd).toList();
        } else if (queryMealOrderDTO.getStatus() == QueryMealOrderStatusEnum.BE_BOOKED) {
            mealOrderRpcResponses = mealOrderRpcResponses.stream().filter(e -> e.getReserveDate() > thisWeekStart).toList();
        }
        return mealOrderRpcResponses.stream().map(this::getMealOrderById).toList();
    }

    @Override
    public CreatedResult<MealOrderVO> createMealOrder(MealOrderDTO.CreateMealOrderDTO createMealOrderDTO) {
        final var loginInfo = LoginContextHolder.getLoginInfo();
        final var deliveryRule = this.getDeliveryRule();
        final var now = LocalDateTime.now();
        final var nowWithinRange = isNowWithinRange(deliveryRule, now);
        if (!nowWithinRange) {
            throw ClientEndExceptions.IncorrectRequestValue.build(ErrorCodeEnum.MEAL_ORDER_TIME_NOT_IN_RANGE);
        }
        final var reserveDinerMealOrders = mealOrderServiceRpcClient.queryReserveMealOrdersByDinerIds(loginInfo.getEnterpriseId(), Collections.singletonList(createMealOrderDTO.getDinerId()));
        if (!reserveDinerMealOrders.isEmpty()) {
            throw ClientEndExceptions.IncorrectRequestValue.build(ErrorCodeEnum.DINER_ALREADY_RESERVED);
        }
        final var dinerById = mealOrderServiceRpcClient.getDinerById(loginInfo.getEnterpriseId(), createMealOrderDTO.getDinerId());
        if (dinerById == null) {
            throw ClientEndExceptions.IncorrectRequestValue.build(ErrorCodeEnum.DINER_NOT_FOUND);
        }
        final var clientById = clientInventoryServiceRpcClient.getClientById(loginInfo.getEnterpriseId(), dinerById.getClientId());
        if (clientById == null) {
            throw ClientEndExceptions.IncorrectRequestValue.build(ErrorCodeEnum.CLIENT_NOT_FOUND);
        }
        if (clientById.getClient().getStatus() != 1) {
            throw ClientEndExceptions.IncorrectRequestValue.build(ErrorCodeEnum.CLIENT_NOT_ENABLED);
        }
        final var gradeClassById = mealOrderServiceRpcClient.getGradeClassById(loginInfo.getEnterpriseId(), dinerById.getClassId());
        if (gradeClassById == null) {
            throw ClientEndExceptions.IncorrectRequestValue.build(ErrorCodeEnum.GRADE_CLASS_NOT_FOUND);
        }
        final var latestMealMenuRecords = mealOrderServiceRpcClient.queryLatestMealMenuRecordsByClientIds(loginInfo.getEnterpriseId(), Collections.singletonList(dinerById.getClientId()));
        if (latestMealMenuRecords.isEmpty()) {
            throw ClientEndExceptions.IncorrectRequestValue.build(ErrorCodeEnum.MEAL_MENU_NOT_FOUND);
        }
        final var mealOrder = mealOrderServiceRpcClient.createMealOrder(loginInfo, MealOrderCreation.newBuilder()
                .setClientId(dinerById.getClientId())
                .setMenuId(latestMealMenuRecords.get(0).getId())
                .setAccountId(loginInfo.getId())
                .setOrderMethod(MealOrderOrderMethodEnum.MEAL_ORDER_METHOD_MICRO)
                .setDinerId(createMealOrderDTO.getDinerId())
                .setDinerName(dinerById.getName())
                .setClientName(clientById.getClient().getName())
                .setGradeName(gradeClassById.getGradeName())
                .setClassName(gradeClassById.getClassName())
                .setStudentNo(dinerById.getStudentNo())
                .setReserveDate(now.atZone(DateUtil.CHINA_ZONE).toInstant().toEpochMilli())
                .addAllMeals(createMealOrderDTO.getMeals().stream().map(e -> MenuSchedule.newBuilder()
                        .setDate(e.getDate())
                        .setMenu(e.getMenu())
                        .build()).toList())
                .build());
        return CreatedResult.<MealOrderVO>builder().id(mealOrder.getId()).isCreated(mealOrder.getIsCreated()).build();
    }

    @Override
    public MealOrderVO getMealOrderById(SingleMealOrderRpcResponse mealOrder) {
        return MealOrderVO.builder()
                .id(mealOrder.getId())
                .clientId(mealOrder.getClientId())
                .menuId(mealOrder.getMenuId())
                .accountId(mealOrder.getAccountId())
                .orderMethod(mealOrder.getOrderMethod())
                .dinerId(mealOrder.getDinerId())
                .dinerName(mealOrder.getDinerName())
                .clientName(mealOrder.getClientName())
                .gradeName(mealOrder.getGradeName())
                .className(mealOrder.getClassName())
                .studentNo(mealOrder.getStudentNo())
                .reserveDate(DateUtil.formatDate(mealOrder.getReserveDate()))
                .meals(mealOrder.getMealsList().stream().map(e -> MealOrderVO.Meals.builder().date(e.getDate()).menu(e.getMenu()).build()).toList())
                .build();
    }

    @Override
    public DeliveryRuleVO getDeliveryRule() {
        final var rule = deliveryRuleServiceRpcClient.getDefaultDeliveryTemplateAndRule(LoginContextHolder.getEnterpriseId()).getRule();
        if (rule.getConfigJson().getRulesList().isEmpty()) {
            return DeliveryRuleVO.builder().build();
        }
        return DeliveryRuleVO.builder()
                .startTime(rule.getConfigJson().getRules(0).getStartTime())
                .endTime(rule.getConfigJson().getRules(0).getEndTime())
                .monday(rule.getConfigJson().getRules(0).getMonday())
                .tuesday(rule.getConfigJson().getRules(0).getTuesday())
                .wednesday(rule.getConfigJson().getRules(0).getWednesday())
                .thursday(rule.getConfigJson().getRules(0).getThursday())
                .friday(rule.getConfigJson().getRules(0).getFriday())
                .saturday(rule.getConfigJson().getRules(0).getSaturday())
                .sunday(rule.getConfigJson().getRules(0).getSunday())
                .build();
    }

    private static boolean isNowWithinRange(DeliveryRuleVO rule, LocalDateTime now) {
        if (rule == null || rule.getStartTime() == null || rule.getEndTime() == null) {
            return false;
        }
        final var startTime = LocalTime.parse(rule.getStartTime(), DateUtil.HH_MM_SS);
        final var endTime = LocalTime.parse(rule.getEndTime(), DateUtil.HH_MM_SS);
        final var enabledDays = new ArrayList<DayOfWeek>();
        if (Boolean.TRUE.equals(rule.getMonday())) enabledDays.add(DayOfWeek.MONDAY);
        if (Boolean.TRUE.equals(rule.getTuesday())) enabledDays.add(DayOfWeek.TUESDAY);
        if (Boolean.TRUE.equals(rule.getWednesday())) enabledDays.add(DayOfWeek.WEDNESDAY);
        if (Boolean.TRUE.equals(rule.getThursday())) enabledDays.add(DayOfWeek.THURSDAY);
        if (Boolean.TRUE.equals(rule.getFriday())) enabledDays.add(DayOfWeek.FRIDAY);
        if (Boolean.TRUE.equals(rule.getSaturday())) enabledDays.add(DayOfWeek.SATURDAY);
        if (Boolean.TRUE.equals(rule.getSunday())) enabledDays.add(DayOfWeek.SUNDAY);
        if (enabledDays.isEmpty()) {
            return false;
        }
        final var minDay = Collections.min(enabledDays);
        final var maxDay = Collections.max(enabledDays);
        final var today = now.toLocalDate();
        final var startDateTime = getThisWeekDate(today, minDay).atTime(startTime);
        final var endDateTime = getThisWeekDate(today,maxDay).atTime(endTime);
        return !now.isBefore(startDateTime) && !now.isAfter(endDateTime);
    }

    private static LocalDate getThisWeekDate(LocalDate now, DayOfWeek day) {
        LocalDate monday = now.with(DayOfWeek.MONDAY);
        return monday.plusDays(day.getValue() - 1L); // MONDAY 是 1,SUNDAY 是 7
    }
}