Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

package com.spice.profitmandi.service;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.spice.profitmandi.dao.entity.logistics.PublicHolidays;
import com.spice.profitmandi.dao.repository.logistics.PublicHolidaysRepository;

/**
 * Service for working days calculations that excludes:
 * - Sundays (Saturdays are working days)
 * - Public holidays from the database
 */
@Service
public class WorkingDaysService {

    @Autowired
    private PublicHolidaysRepository publicHolidaysRepository;

    /**
     * Checks if a given date is a working day (not Sunday, not holiday).
     * Note: Saturdays are considered working days.
     */
    public boolean isWorkingDay(LocalDate date) {
        if (date == null) {
            return false;
        }

        // Check if Sunday (Saturdays are working days)
        if (date.getDayOfWeek() == DayOfWeek.SUNDAY) {
            return false;
        }

        // Check holiday
        PublicHolidays holiday = publicHolidaysRepository.selectByDate(date);
        return holiday == null;
    }

    /**
     * Counts working days between two dates (excludes Sundays and holidays).
     * Note: Saturdays are considered working days.
     *
     * @param startDate Start date (inclusive)
     * @param endDate   End date (exclusive)
     * @return Number of working days
     */
    public int countWorkingDays(LocalDate startDate, LocalDate endDate) {
        if (startDate == null || endDate == null || !startDate.isBefore(endDate)) {
            return 0;
        }

        // Get all holidays in the date range for efficient lookup
        List<PublicHolidays> holidays = publicHolidaysRepository.selectAllBetweenDates(startDate, endDate);
        Set<LocalDate> holidayDates = holidays.stream()
                .map(PublicHolidays::getDate)
                .collect(Collectors.toSet());

        int workingDays = 0;
        LocalDate current = startDate;

        while (current.isBefore(endDate)) {
            boolean isSunday = current.getDayOfWeek() == DayOfWeek.SUNDAY;
            boolean isHoliday = holidayDates.contains(current);

            if (!isSunday && !isHoliday) {
                workingDays++;
            }
            current = current.plusDays(1);
        }

        return workingDays;
    }

    /**
     * Counts working days from a LocalDateTime to now.
     */
    public int countWorkingDaysSince(LocalDateTime startDateTime) {
        if (startDateTime == null) {
            return 0;
        }
        return countWorkingDays(startDateTime.toLocalDate(), LocalDate.now());
    }

    /**
     * Adds working days to a date (excludes Sundays and holidays).
     * Note: Saturdays are considered working days.
     */
    public LocalDate addWorkingDays(LocalDate startDate, int workingDaysToAdd) {
        if (startDate == null || workingDaysToAdd <= 0) {
            return startDate;
        }

        // Estimate end date range for holiday lookup (add buffer for Sundays/holidays)
        LocalDate estimatedEndDate = startDate.plusDays(workingDaysToAdd + 10);
        List<PublicHolidays> holidays = publicHolidaysRepository.selectAllBetweenDates(startDate, estimatedEndDate);
        Set<LocalDate> holidayDates = holidays.stream()
                .map(PublicHolidays::getDate)
                .collect(Collectors.toSet());

        LocalDate result = startDate;
        int addedDays = 0;

        while (addedDays < workingDaysToAdd) {
            result = result.plusDays(1);
            boolean isSunday = result.getDayOfWeek() == DayOfWeek.SUNDAY;
            boolean isHoliday = holidayDates.contains(result);

            if (!isSunday && !isHoliday) {
                addedDays++;
            }
        }

        return result;
    }

    /**
     * Checks if deadline has been exceeded based on working days.
     */
    public boolean isDeadlineExceeded(LocalDateTime startDateTime, int workingDaysLimit) {
        if (startDateTime == null) {
            return false;
        }
        int elapsedWorkingDays = countWorkingDaysSince(startDateTime);
        return elapsedWorkingDays >= workingDaysLimit;
    }

    /**
     * Returns working days remaining before deadline.
     */
    public int getWorkingDaysRemaining(LocalDateTime startDateTime, int workingDaysLimit) {
        if (startDateTime == null) {
            return 0;
        }
        int elapsedWorkingDays = countWorkingDaysSince(startDateTime);
        return workingDaysLimit - elapsedWorkingDays;
    }

    /**
     * Gets the deadline date given start date and working days.
     */
    public LocalDate getDeadlineDate(LocalDate startDate, int workingDays) {
        return addWorkingDays(startDate, workingDays);
    }
}