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"; // Check if item has hourly or daily pricing if (rental.item?.pricePerHour && rental.item.pricePerHour > 0) { // Hourly pricing - charge per hour late lateFee = hoursLate * parseFloat(rental.item.pricePerHour); pricingType = "hourly"; } else if (rental.item?.pricePerDay && rental.item.pricePerDay > 0) { // Daily pricing - charge per day late (rounded up) const billableDays = Math.ceil(hoursLate / 24); lateFee = billableDays * parseFloat(rental.item.pricePerDay); pricingType = "daily"; } else { // Free borrows: determine pricing type based on rental duration const rentalStart = new Date(rental.startDateTime); const rentalEnd = new Date(rental.endDateTime); const rentalDurationHours = (rentalEnd - rentalStart) / (1000 * 60 * 60); if (rentalDurationHours <= 24) { // Hourly rental - charge $10 per hour late lateFee = hoursLate * 10.0; pricingType = "hourly"; } else { // Daily rental - charge $10 per day late const billableDays = Math.ceil(hoursLate / 24); lateFee = billableDays * 10.0; pricingType = "daily"; } } 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;