Files
rentall-app/backend/services/email/domain/CustomerServiceEmailService.js
2026-01-10 20:47:29 -05:00

301 lines
10 KiB
JavaScript

const EmailClient = require("../core/EmailClient");
const TemplateManager = require("../core/TemplateManager");
const logger = require("../../../utils/logger");
/**
* CustomerServiceEmailService handles all customer service alert emails
* This service is responsible for:
* - Sending late return notifications to CS team
* - Sending damage report notifications to CS team
* - Sending lost item notifications to CS team
*/
class CustomerServiceEmailService {
constructor() {
this.emailClient = new EmailClient();
this.templateManager = new TemplateManager();
this.initialized = false;
}
/**
* Initialize the customer service email service
* @returns {Promise<void>}
*/
async initialize() {
if (this.initialized) return;
await Promise.all([
this.emailClient.initialize(),
this.templateManager.initialize(),
]);
this.initialized = true;
logger.info("Customer Service Email Service initialized successfully");
}
/**
* Send late return notification to customer service
* @param {Object} rental - Rental object
* @param {number} rental.id - Rental ID
* @param {Date} rental.endDateTime - Scheduled end date/time
* @param {Date} rental.actualReturnDateTime - Actual return date/time
* @param {Object} rental.item - Item object with name property
* @param {Object} owner - Owner user object
* @param {string} owner.firstName - Owner's first name
* @param {string} owner.lastName - Owner's last name
* @param {string} owner.email - Owner's email
* @param {Object} renter - Renter user object
* @param {string} renter.firstName - Renter's first name
* @param {string} renter.lastName - Renter's last name
* @param {string} renter.email - Renter's email
* @param {Object} lateCalculation - Late fee calculation
* @param {number} lateCalculation.lateHours - Hours late
* @param {number} lateCalculation.lateFee - Late fee amount
* @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
*/
async sendLateReturnToCustomerService(rental, owner, renter, lateCalculation) {
if (!this.initialized) {
await this.initialize();
}
try {
const csEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
if (!csEmail) {
logger.warn("No customer service email configured");
return { success: false, error: "No customer service email configured" };
}
// Format dates
const scheduledEnd = new Date(rental.endDateTime).toLocaleString();
const actualReturn = new Date(rental.actualReturnDateTime).toLocaleString();
const variables = {
rentalId: rental.id,
itemName: rental.item.name,
ownerName: `${owner.firstName} ${owner.lastName}`,
ownerEmail: owner.email,
renterName: `${renter.firstName} ${renter.lastName}`,
renterEmail: renter.email,
scheduledEnd,
actualReturn,
hoursLate: lateCalculation.lateHours.toFixed(1),
lateFee: lateCalculation.lateFee.toFixed(2),
};
const htmlContent = await this.templateManager.renderTemplate(
"lateReturnToCS",
variables
);
const result = await this.emailClient.sendEmail(
csEmail,
"Late Return Detected - Action Required",
htmlContent
);
if (result.success) {
logger.info(
`Late return notification sent to customer service for rental ${rental.id}`
);
}
return result;
} catch (error) {
logger.error(
"Failed to send late return notification to customer service:",
error
);
return { success: false, error: error.message };
}
}
/**
* Send damage report notification to customer service
* @param {Object} rental - Rental object
* @param {number} rental.id - Rental ID
* @param {Object} rental.item - Item object with name property
* @param {Object} owner - Owner user object
* @param {string} owner.firstName - Owner's first name
* @param {string} owner.lastName - Owner's last name
* @param {string} owner.email - Owner's email
* @param {Object} renter - Renter user object
* @param {string} renter.firstName - Renter's first name
* @param {string} renter.lastName - Renter's last name
* @param {string} renter.email - Renter's email
* @param {Object} damageAssessment - Damage assessment details
* @param {string} damageAssessment.description - Damage description
* @param {boolean} damageAssessment.canBeFixed - Whether item can be repaired
* @param {number} [damageAssessment.repairCost] - Repair cost if applicable
* @param {boolean} damageAssessment.needsReplacement - Whether item needs replacement
* @param {number} [damageAssessment.replacementCost] - Replacement cost if applicable
* @param {Object} damageAssessment.feeCalculation - Fee calculation details
* @param {string} damageAssessment.feeCalculation.type - Fee type (repair/replacement)
* @param {number} damageAssessment.feeCalculation.amount - Fee amount
* @param {Array} [damageAssessment.proofOfOwnership] - Proof of ownership documents
* @param {Object} [lateCalculation] - Late fee calculation (optional)
* @param {number} [lateCalculation.lateFee] - Late fee amount
* @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
*/
async sendDamageReportToCustomerService(
rental,
owner,
renter,
damageAssessment,
lateCalculation = null
) {
if (!this.initialized) {
await this.initialize();
}
try {
const csEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
if (!csEmail) {
logger.warn("No customer service email configured");
return { success: false, error: "No customer service email configured" };
}
// Calculate total fees (ensure numeric values)
const damageFee = parseFloat(damageAssessment.feeCalculation.amount) || 0;
const lateFee = parseFloat(lateCalculation?.lateFee || 0);
const totalFees = damageFee + lateFee;
// Determine fee type description
let feeTypeDescription = "";
if (damageAssessment.feeCalculation.type === "repair") {
feeTypeDescription = "Repair Cost";
} else if (damageAssessment.feeCalculation.type === "replacement") {
feeTypeDescription = "Replacement Cost";
} else {
feeTypeDescription = "Damage Assessment Fee";
}
const variables = {
rentalId: rental.id,
itemName: rental.item.name,
ownerName: `${owner.firstName} ${owner.lastName}`,
ownerEmail: owner.email,
renterName: `${renter.firstName} ${renter.lastName}`,
renterEmail: renter.email,
damageDescription: damageAssessment.description,
canBeFixed: damageAssessment.canBeFixed ? "Yes" : "No",
repairCost: damageAssessment.repairCost
? damageAssessment.repairCost.toFixed(2)
: "N/A",
needsReplacement: damageAssessment.needsReplacement ? "Yes" : "No",
replacementCost: damageAssessment.replacementCost
? damageAssessment.replacementCost.toFixed(2)
: "N/A",
feeTypeDescription,
damageFee: damageFee.toFixed(2),
lateFee: lateFee.toFixed(2),
totalFees: totalFees.toFixed(2),
hasProofOfOwnership:
damageAssessment.proofOfOwnership &&
damageAssessment.proofOfOwnership.length > 0
? "Yes"
: "No",
};
const htmlContent = await this.templateManager.renderTemplate(
"damageReportToCS",
variables
);
const result = await this.emailClient.sendEmail(
csEmail,
"Damage Report Filed - Action Required",
htmlContent
);
if (result.success) {
logger.info(
`Damage report notification sent to customer service for rental ${rental.id}`
);
}
return result;
} catch (error) {
logger.error(
"Failed to send damage report notification to customer service:",
error
);
return { success: false, error: error.message };
}
}
/**
* Send lost item notification to customer service
* @param {Object} rental - Rental object
* @param {number} rental.id - Rental ID
* @param {Date} rental.endDateTime - Scheduled return date
* @param {Date} rental.itemLostReportedAt - When loss was reported
* @param {Object} rental.item - Item object
* @param {string} rental.item.name - Item name
* @param {number} rental.item.replacementCost - Item replacement cost
* @param {Object} owner - Owner user object
* @param {string} owner.firstName - Owner's first name
* @param {string} owner.lastName - Owner's last name
* @param {string} owner.email - Owner's email
* @param {Object} renter - Renter user object
* @param {string} renter.firstName - Renter's first name
* @param {string} renter.lastName - Renter's last name
* @param {string} renter.email - Renter's email
* @returns {Promise<{success: boolean, messageId?: string, error?: string}>}
*/
async sendLostItemToCustomerService(rental, owner, renter) {
if (!this.initialized) {
await this.initialize();
}
try {
const csEmail = process.env.CUSTOMER_SUPPORT_EMAIL;
if (!csEmail) {
logger.warn("No customer service email configured");
return { success: false, error: "No customer service email configured" };
}
// Format dates
const reportedAt = new Date(rental.itemLostReportedAt).toLocaleString();
const scheduledReturnDate = new Date(rental.endDateTime).toLocaleString();
const variables = {
rentalId: rental.id,
itemName: rental.item.name,
ownerName: `${owner.firstName} ${owner.lastName}`,
ownerEmail: owner.email,
renterName: `${renter.firstName} ${renter.lastName}`,
renterEmail: renter.email,
reportedAt,
scheduledReturnDate,
replacementCost: parseFloat(rental.item.replacementCost).toFixed(2),
};
const htmlContent = await this.templateManager.renderTemplate(
"lostItemToCS",
variables
);
const result = await this.emailClient.sendEmail(
csEmail,
"Lost Item Claim Filed - Action Required",
htmlContent
);
if (result.success) {
logger.info(
`Lost item notification sent to customer service for rental ${rental.id}`
);
}
return result;
} catch (error) {
logger.error(
"Failed to send lost item notification to customer service:",
error
);
return { success: false, error: error.message };
}
}
}
module.exports = CustomerServiceEmailService;