const { Rental, Item } = require("../models"); const emailService = require("./emailService"); class LateReturnService { /** * Calculate late fees based on actual return time vs scheduled end time * @param {Object} rental - Rental instance with populated item data * @param {Date} actualReturnDateTime - When the item was actually returned * @returns {Object} - { lateHours, lateFee, isLate } */ static calculateLateFee(rental, actualReturnDateTime) { const scheduledEnd = new Date(rental.endDateTime); const actualReturn = new Date(actualReturnDateTime); // Calculate hours late const hoursLate = (actualReturn - scheduledEnd) / (1000 * 60 * 60); if (hoursLate <= 0) { return { lateHours: 0, lateFee: 0.0, isLate: false, }; } let lateFee = 0; let pricingType = "daily"; const billableDays = Math.ceil(hoursLate / 24); // Calculate late fees per day, deriving daily rate from available pricing tiers if (rental.item?.pricePerDay && rental.item.pricePerDay > 0) { // Daily pricing - charge per day late lateFee = billableDays * parseFloat(rental.item.pricePerDay); } else if (rental.item?.pricePerWeek && rental.item.pricePerWeek > 0) { // Weekly pricing - derive daily rate and charge per day late const dailyRate = parseFloat(rental.item.pricePerWeek) / 7; lateFee = billableDays * dailyRate; } else if (rental.item?.pricePerMonth && rental.item.pricePerMonth > 0) { // Monthly pricing - derive daily rate and charge per day late const dailyRate = parseFloat(rental.item.pricePerMonth) / 30; lateFee = billableDays * dailyRate; } else if (rental.item?.pricePerHour && rental.item.pricePerHour > 0) { // Hourly pricing - derive daily rate and charge per day late const dailyRate = parseFloat(rental.item.pricePerHour) * 24; lateFee = billableDays * dailyRate; } else { // Free borrows - charge $10 per day late lateFee = billableDays * 10.0; } return { lateHours: hoursLate, lateFee: parseFloat(lateFee.toFixed(2)), isLate: true, pricingType, }; } /** * Process late return and update rental with fees * @param {string} rentalId - Rental ID * @param {Date} actualReturnDateTime - When item was returned * @param {string} notes - Optional notes about the return * @returns {Object} - Updated rental with late fee information */ static async processLateReturn(rentalId, actualReturnDateTime, notes = null) { const rental = await Rental.findByPk(rentalId, { include: [{ model: Item, as: "item" }], }); if (!rental) { throw new Error("Rental not found"); } if (rental.status !== "active") { throw new Error("Can only process late returns for active rentals"); } const lateCalculation = this.calculateLateFee(rental, actualReturnDateTime); const updates = { actualReturnDateTime: new Date(actualReturnDateTime), status: lateCalculation.isLate ? "returned_late" : "completed", }; if (notes) { updates.notes = notes; } const updatedRental = await rental.update(updates); // Send notification to customer service if late return detected if (lateCalculation.isLate && lateCalculation.lateFee > 0) { await emailService.sendLateReturnToCustomerService( updatedRental, lateCalculation ); } return { rental: updatedRental, lateCalculation, }; } } module.exports = LateReturnService;