301 lines
10 KiB
JavaScript
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;
|