email plus return item statuses
This commit is contained in:
113
backend/services/lateReturnService.js
Normal file
113
backend/services/lateReturnService.js
Normal file
@@ -0,0 +1,113 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user