email refactor
This commit is contained in:
299
backend/services/email/domain/CustomerServiceEmailService.js
Normal file
299
backend/services/email/domain/CustomerServiceEmailService.js
Normal file
@@ -0,0 +1,299 @@
|
||||
const EmailClient = require("../core/EmailClient");
|
||||
const TemplateManager = require("../core/TemplateManager");
|
||||
|
||||
/**
|
||||
* 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;
|
||||
console.log("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) {
|
||||
console.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) {
|
||||
console.log(
|
||||
`Late return notification sent to customer service for rental ${rental.id}`
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.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) {
|
||||
console.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) {
|
||||
console.log(
|
||||
`Damage report notification sent to customer service for rental ${rental.id}`
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.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) {
|
||||
console.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) {
|
||||
console.log(
|
||||
`Lost item notification sent to customer service for rental ${rental.id}`
|
||||
);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Failed to send lost item notification to customer service:",
|
||||
error
|
||||
);
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CustomerServiceEmailService;
|
||||
Reference in New Issue
Block a user