Files
rentall-app/backend/services/lateReturnService.js
2025-10-06 15:41:48 -04:00

114 lines
3.5 KiB
JavaScript

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;