condition check lambda
This commit is contained in:
53
lambdas/conditionCheckReminder/README.md
Normal file
53
lambdas/conditionCheckReminder/README.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Condition Check Reminder Lambda
|
||||
|
||||
Sends email reminders to owners and renters to complete condition checks at key points in the rental lifecycle.
|
||||
|
||||
## Check Types
|
||||
|
||||
| Check Type | Recipient | Timing |
|
||||
|------------|-----------|--------|
|
||||
| `pre_rental_owner` | Owner | 24 hours before rental start |
|
||||
| `rental_start_renter` | Renter | At rental start |
|
||||
| `rental_end_renter` | Renter | At rental end |
|
||||
| `post_rental_owner` | Owner | 24 hours after rental end |
|
||||
|
||||
## Local Development
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
```bash
|
||||
cd lambdas/shared && npm install
|
||||
cd ../conditionCheckReminder && npm install
|
||||
```
|
||||
|
||||
### Set Up Environment
|
||||
|
||||
```bash
|
||||
cp .env.example .env.dev
|
||||
# Edit .env.dev with your DATABASE_URL
|
||||
```
|
||||
|
||||
### Run Locally
|
||||
|
||||
```bash
|
||||
# Default: rental ID 1, check type pre_rental_owner
|
||||
npm run local
|
||||
|
||||
# Specify rental ID and check type
|
||||
node -r dotenv/config test-local.js dotenv_config_path=.env.dev 123 rental_start_renter
|
||||
```
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description | Example |
|
||||
|----------|-------------|---------|
|
||||
| `DATABASE_URL` | PostgreSQL connection string | `postgresql://user:pass@localhost:5432/rentall` |
|
||||
| `FRONTEND_URL` | Frontend URL for email links | `http://localhost:3000` |
|
||||
| `SES_FROM_EMAIL` | Sender email address | `noreply@villageshare.app` |
|
||||
| `EMAIL_ENABLED` | Enable/disable email sending | `false` |
|
||||
| `SCHEDULE_GROUP_NAME` | EventBridge schedule group | `condition-check-reminders-dev` |
|
||||
| `AWS_REGION` | AWS region | `us-east-1` |
|
||||
|
||||
## Deployment
|
||||
|
||||
See [infrastructure/cdk/README.md](../../infrastructure/cdk/README.md) for deployment instructions.
|
||||
222
lambdas/conditionCheckReminder/handler.js
Normal file
222
lambdas/conditionCheckReminder/handler.js
Normal file
@@ -0,0 +1,222 @@
|
||||
const path = require("path");
|
||||
const {
|
||||
SchedulerClient,
|
||||
DeleteScheduleCommand,
|
||||
} = require("@aws-sdk/client-scheduler");
|
||||
const { queries, email, logger } = require("../shared");
|
||||
const { conditionCheckExists } = require("./queries");
|
||||
|
||||
let schedulerClient = null;
|
||||
|
||||
/**
|
||||
* Get or create an EventBridge Scheduler client.
|
||||
*/
|
||||
function getSchedulerClient() {
|
||||
if (!schedulerClient) {
|
||||
schedulerClient = new SchedulerClient({
|
||||
region: process.env.AWS_REGION || "us-east-1",
|
||||
});
|
||||
}
|
||||
return schedulerClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a one-time EventBridge schedule after it has fired.
|
||||
* @param {string} scheduleName - Name of the schedule to delete
|
||||
*/
|
||||
async function deleteSchedule(scheduleName) {
|
||||
try {
|
||||
const client = getSchedulerClient();
|
||||
const groupName =
|
||||
process.env.SCHEDULE_GROUP_NAME || "condition-check-reminders";
|
||||
|
||||
await client.send(
|
||||
new DeleteScheduleCommand({
|
||||
Name: scheduleName,
|
||||
GroupName: groupName,
|
||||
})
|
||||
);
|
||||
|
||||
logger.info("Deleted schedule after execution", {
|
||||
scheduleName,
|
||||
groupName,
|
||||
});
|
||||
} catch (error) {
|
||||
// Log but don't fail - schedule may have already been deleted
|
||||
logger.warn("Failed to delete schedule", {
|
||||
scheduleName,
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get email content based on check type.
|
||||
* @param {string} checkType - Type of condition check
|
||||
* @param {Object} rental - Rental with item, owner, renter details
|
||||
* @returns {Object} Email content (subject, title, message, recipient)
|
||||
*/
|
||||
function getEmailContent(checkType, rental) {
|
||||
const itemName = rental.item.name;
|
||||
const frontendUrl = process.env.FRONTEND_URL;
|
||||
|
||||
const content = {
|
||||
pre_rental_owner: {
|
||||
recipient: rental.owner,
|
||||
subject: `Condition Check Reminder: ${itemName}`,
|
||||
title: "Pre-Rental Condition Check",
|
||||
message: `Please take photos of "${itemName}" before the rental begins tomorrow. This helps protect both you and the renter.`,
|
||||
deadline: email.formatEmailDate(rental.startDateTime),
|
||||
},
|
||||
rental_start_renter: {
|
||||
recipient: rental.renter,
|
||||
subject: `Document Item Condition: ${itemName}`,
|
||||
title: "Rental Start Condition Check",
|
||||
message: `Please take photos when you receive "${itemName}" to document its condition. This protects you in case of any disputes.`,
|
||||
deadline: email.formatEmailDate(
|
||||
new Date(new Date(rental.startDateTime).getTime() + 24 * 60 * 60 * 1000)
|
||||
),
|
||||
},
|
||||
rental_end_renter: {
|
||||
recipient: rental.renter,
|
||||
subject: `Return Condition Check: ${itemName}`,
|
||||
title: "Rental End Condition Check",
|
||||
message: `Please take photos when returning "${itemName}" to document its condition before handoff.`,
|
||||
deadline: email.formatEmailDate(rental.endDateTime),
|
||||
},
|
||||
post_rental_owner: {
|
||||
recipient: rental.owner,
|
||||
subject: `Review Return: ${itemName}`,
|
||||
title: "Post-Rental Condition Check",
|
||||
message: `Please take photos and mark the return status for "${itemName}". This completes the rental process.`,
|
||||
deadline: email.formatEmailDate(
|
||||
new Date(new Date(rental.endDateTime).getTime() + 48 * 60 * 60 * 1000)
|
||||
),
|
||||
},
|
||||
};
|
||||
|
||||
return content[checkType];
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a condition check reminder.
|
||||
* @param {string} rentalId - UUID of the rental
|
||||
* @param {string} checkType - Type of condition check
|
||||
* @param {string} scheduleName - Name of the EventBridge schedule (for cleanup)
|
||||
* @returns {Promise<Object>} Result of the operation
|
||||
*/
|
||||
async function processReminder(rentalId, checkType, scheduleName) {
|
||||
logger.info("Processing condition check reminder", {
|
||||
rentalId,
|
||||
checkType,
|
||||
scheduleName,
|
||||
});
|
||||
|
||||
try {
|
||||
// 1. Check if condition check already exists (skip if yes)
|
||||
const exists = await conditionCheckExists(rentalId, checkType);
|
||||
if (exists) {
|
||||
logger.info("Condition check already exists, skipping reminder", {
|
||||
rentalId,
|
||||
checkType,
|
||||
});
|
||||
|
||||
// Still delete the schedule
|
||||
if (scheduleName) {
|
||||
await deleteSchedule(scheduleName);
|
||||
}
|
||||
|
||||
return { success: true, skipped: true, reason: "condition_check_exists" };
|
||||
}
|
||||
|
||||
// 2. Fetch rental details
|
||||
const rental = await queries.getRentalWithDetails(rentalId);
|
||||
if (!rental) {
|
||||
logger.error("Rental not found", { rentalId });
|
||||
return { success: false, error: "rental_not_found" };
|
||||
}
|
||||
|
||||
// 3. Check rental status - only send for active rentals
|
||||
const validStatuses = ["confirmed", "active", "completed"];
|
||||
if (!validStatuses.includes(rental.status)) {
|
||||
logger.info("Rental status not valid for reminder", {
|
||||
rentalId,
|
||||
status: rental.status,
|
||||
});
|
||||
|
||||
if (scheduleName) {
|
||||
await deleteSchedule(scheduleName);
|
||||
}
|
||||
|
||||
return { success: true, skipped: true, reason: "invalid_rental_status" };
|
||||
}
|
||||
|
||||
// 4. Get email content and send
|
||||
const emailContent = getEmailContent(checkType, rental);
|
||||
if (!emailContent) {
|
||||
logger.error("Unknown check type", { checkType });
|
||||
return { success: false, error: "unknown_check_type" };
|
||||
}
|
||||
|
||||
// 5. Load and render the email template
|
||||
const templatePath = path.join(
|
||||
__dirname,
|
||||
"templates",
|
||||
"conditionCheckReminderToUser.html"
|
||||
);
|
||||
const template = await email.loadTemplate(templatePath);
|
||||
|
||||
const htmlBody = email.renderTemplate(template, {
|
||||
title: emailContent.title,
|
||||
message: emailContent.message,
|
||||
itemName: rental.item.name,
|
||||
deadline: emailContent.deadline,
|
||||
recipientName: emailContent.recipient.firstName,
|
||||
});
|
||||
|
||||
// 6. Send the email
|
||||
const result = await email.sendEmail(
|
||||
emailContent.recipient.email,
|
||||
emailContent.subject,
|
||||
htmlBody
|
||||
);
|
||||
|
||||
if (!result.success) {
|
||||
logger.error("Failed to send reminder email", {
|
||||
rentalId,
|
||||
checkType,
|
||||
error: result.error,
|
||||
});
|
||||
return { success: false, error: result.error };
|
||||
}
|
||||
|
||||
logger.info("Sent condition check reminder", {
|
||||
rentalId,
|
||||
checkType,
|
||||
to: emailContent.recipient.email,
|
||||
messageId: result.messageId,
|
||||
});
|
||||
|
||||
// 7. Delete the one-time schedule
|
||||
if (scheduleName) {
|
||||
await deleteSchedule(scheduleName);
|
||||
}
|
||||
|
||||
return { success: true, messageId: result.messageId };
|
||||
} catch (error) {
|
||||
logger.error("Error processing condition check reminder", {
|
||||
rentalId,
|
||||
checkType,
|
||||
error: error.message,
|
||||
stack: error.stack,
|
||||
});
|
||||
|
||||
return { success: false, error: error.message };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
processReminder,
|
||||
getEmailContent,
|
||||
deleteSchedule,
|
||||
};
|
||||
68
lambdas/conditionCheckReminder/index.js
Normal file
68
lambdas/conditionCheckReminder/index.js
Normal file
@@ -0,0 +1,68 @@
|
||||
const { processReminder } = require("./handler");
|
||||
const { logger } = require("../shared");
|
||||
|
||||
/**
|
||||
* Lambda handler for condition check reminder emails.
|
||||
*
|
||||
* Invoked by EventBridge Scheduler with a payload containing:
|
||||
* - rentalId: UUID of the rental
|
||||
* - checkType: Type of check (pre_rental_owner, rental_start_renter, rental_end_renter, post_rental_owner)
|
||||
* - scheduleName: Name of the schedule (for cleanup after execution)
|
||||
*
|
||||
* @param {Object} event - EventBridge Scheduler event
|
||||
* @returns {Promise<Object>} Result of the reminder processing
|
||||
*/
|
||||
exports.handler = async (event) => {
|
||||
logger.info("Lambda invoked", { event });
|
||||
|
||||
// Extract payload - EventBridge Scheduler sends it directly
|
||||
const { rentalId, checkType, scheduleName } = event;
|
||||
|
||||
// Validate required fields
|
||||
if (!rentalId) {
|
||||
logger.error("Missing rentalId in event payload");
|
||||
return {
|
||||
statusCode: 400,
|
||||
body: JSON.stringify({ error: "Missing rentalId" }),
|
||||
};
|
||||
}
|
||||
|
||||
if (!checkType) {
|
||||
logger.error("Missing checkType in event payload");
|
||||
return {
|
||||
statusCode: 400,
|
||||
body: JSON.stringify({ error: "Missing checkType" }),
|
||||
};
|
||||
}
|
||||
|
||||
// Validate checkType
|
||||
const validCheckTypes = [
|
||||
"pre_rental_owner",
|
||||
"rental_start_renter",
|
||||
"rental_end_renter",
|
||||
"post_rental_owner",
|
||||
];
|
||||
|
||||
if (!validCheckTypes.includes(checkType)) {
|
||||
logger.error("Invalid checkType", { checkType, validCheckTypes });
|
||||
return {
|
||||
statusCode: 400,
|
||||
body: JSON.stringify({ error: "Invalid checkType" }),
|
||||
};
|
||||
}
|
||||
|
||||
// Process the reminder
|
||||
const result = await processReminder(rentalId, checkType, scheduleName);
|
||||
|
||||
if (result.success) {
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: JSON.stringify(result),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
statusCode: 500,
|
||||
body: JSON.stringify(result),
|
||||
};
|
||||
}
|
||||
};
|
||||
5709
lambdas/conditionCheckReminder/package-lock.json
generated
Normal file
5709
lambdas/conditionCheckReminder/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
lambdas/conditionCheckReminder/package.json
Normal file
18
lambdas/conditionCheckReminder/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "condition-check-reminder-lambda",
|
||||
"version": "1.0.0",
|
||||
"description": "Lambda function for sending condition check reminder emails",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-scheduler": "^3.896.0",
|
||||
"@rentall/lambda-shared": "file:../shared"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dotenv": "^17.2.3",
|
||||
"jest": "^30.1.3"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"local": "node -r dotenv/config test-local.js dotenv_config_path=.env.dev"
|
||||
}
|
||||
}
|
||||
22
lambdas/conditionCheckReminder/queries.js
Normal file
22
lambdas/conditionCheckReminder/queries.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const { query } = require("../shared/db/connection");
|
||||
|
||||
/**
|
||||
* Check if a condition check already exists for a rental and check type.
|
||||
* @param {string} rentalId - UUID of the rental
|
||||
* @param {string} checkType - Type of check (pre_rental_owner, rental_start_renter, etc.)
|
||||
* @returns {Promise<boolean>} True if a condition check exists
|
||||
*/
|
||||
async function conditionCheckExists(rentalId, checkType) {
|
||||
const result = await query(
|
||||
`SELECT id FROM "ConditionChecks"
|
||||
WHERE "rentalId" = $1 AND "checkType" = $2
|
||||
LIMIT 1`,
|
||||
[rentalId, checkType]
|
||||
);
|
||||
|
||||
return result.rows.length > 0;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
conditionCheckExists,
|
||||
};
|
||||
@@ -0,0 +1,266 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>{{title}}</title>
|
||||
<style>
|
||||
/* Reset styles */
|
||||
body,
|
||||
table,
|
||||
td,
|
||||
p,
|
||||
a,
|
||||
li,
|
||||
blockquote {
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
}
|
||||
table,
|
||||
td {
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
img {
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
/* Base styles */
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100% !important;
|
||||
min-width: 100%;
|
||||
height: 100%;
|
||||
background-color: #f8f9fa;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||
Oxygen, Ubuntu, Cantarell, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
/* Container */
|
||||
.email-container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background-color: #ffffff;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 40px 30px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
letter-spacing: -1px;
|
||||
}
|
||||
|
||||
.tagline {
|
||||
color: #e9ecef;
|
||||
font-size: 14px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
.content {
|
||||
padding: 40px 30px;
|
||||
}
|
||||
|
||||
.content h1 {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin: 0 0 20px 0;
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.content h2 {
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
margin: 30px 0 15px 0;
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
.content p {
|
||||
margin: 0 0 16px 0;
|
||||
color: #6c757d;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.content strong {
|
||||
color: #495057;
|
||||
}
|
||||
|
||||
/* Button */
|
||||
.button {
|
||||
display: inline-block;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: #ffffff !important;
|
||||
text-decoration: none;
|
||||
padding: 16px 32px;
|
||||
border-radius: 6px;
|
||||
font-weight: 600;
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
/* Info box */
|
||||
.info-box {
|
||||
background-color: #e3f2fd;
|
||||
border-left: 4px solid #2196f3;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
|
||||
.info-box p {
|
||||
margin: 0;
|
||||
color: #1565c0;
|
||||
}
|
||||
|
||||
.info-box .icon {
|
||||
font-size: 24px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Alert box */
|
||||
.alert-box {
|
||||
background-color: #fff3cd;
|
||||
border-left: 4px solid #ffc107;
|
||||
padding: 20px;
|
||||
margin: 20px 0;
|
||||
border-radius: 0 6px 6px 0;
|
||||
}
|
||||
|
||||
.alert-box p {
|
||||
margin: 0;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
.footer {
|
||||
background-color: #f8f9fa;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
border-top: 1px solid #e9ecef;
|
||||
}
|
||||
|
||||
.footer p {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 14px;
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #667eea;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media only screen and (max-width: 600px) {
|
||||
.email-container {
|
||||
margin: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.header,
|
||||
.content,
|
||||
.footer {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.content h1 {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: block;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="email-container">
|
||||
<div class="header">
|
||||
<div class="logo">Village Share</div>
|
||||
<div class="tagline">Your trusted rental marketplace</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
<p>{{message}}</p>
|
||||
|
||||
<div class="info-box">
|
||||
<p><strong>Rental Item:</strong> {{itemName}}</p>
|
||||
<p><strong>Deadline:</strong> {{deadline}}</p>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Taking condition photos helps protect both renters and owners by
|
||||
providing clear documentation of the item's state. This is an
|
||||
important step in the rental process.
|
||||
</p>
|
||||
|
||||
<div class="alert-box">
|
||||
<p>
|
||||
<strong>Important:</strong> Please complete this condition check as
|
||||
soon as possible. Missing this deadline may affect dispute
|
||||
resolution if issues arise.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h2>What to photograph:</h2>
|
||||
<ul>
|
||||
<li>Overall view of the item</li>
|
||||
<li>Any existing damage or wear</li>
|
||||
<li>Serial numbers or identifying marks</li>
|
||||
<li>Accessories or additional components</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
If you have any questions about the condition check process, please
|
||||
don't hesitate to contact our support team.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>© 2025 Village Share. All rights reserved.</p>
|
||||
<p>
|
||||
You received this email because you have an active rental on Village
|
||||
Share.
|
||||
</p>
|
||||
<p>
|
||||
If you have any questions, please
|
||||
<a href="mailto:support@villageshare.app">contact our support team</a
|
||||
>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
41
lambdas/conditionCheckReminder/test-local.js
Normal file
41
lambdas/conditionCheckReminder/test-local.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Local test script for the condition check reminder lambda
|
||||
*
|
||||
* Usage:
|
||||
* 1. Set environment variables (or create a .env file)
|
||||
* 2. Run: node test-local.js
|
||||
*
|
||||
* Required environment variables:
|
||||
* - DATABASE_URL: PostgreSQL connection string
|
||||
* - FRONTEND_URL: Frontend URL for email links
|
||||
* - SES_FROM_EMAIL: Email sender address
|
||||
* - EMAIL_ENABLED: Set to 'false' to skip actual email sending
|
||||
* - SCHEDULE_GROUP_NAME: EventBridge schedule group name
|
||||
* - AWS_REGION: AWS region
|
||||
*/
|
||||
|
||||
const { handler } = require('./index');
|
||||
|
||||
// Test event - modify these values as needed
|
||||
const testEvent = {
|
||||
rentalId: parseInt(process.argv[2]) || 1, // Pass rental ID as CLI arg or default to 1
|
||||
checkType: process.argv[3] || 'pre_rental_owner' // Options: pre_rental_owner, rental_start_renter, rental_end_renter, post_rental_owner
|
||||
};
|
||||
|
||||
console.log('Running condition check reminder lambda locally...');
|
||||
console.log('Event:', JSON.stringify(testEvent, null, 2));
|
||||
console.log('---');
|
||||
|
||||
handler(testEvent)
|
||||
.then(result => {
|
||||
console.log('---');
|
||||
console.log('Success!');
|
||||
console.log('Result:', JSON.stringify(result, null, 2));
|
||||
process.exit(0);
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('---');
|
||||
console.error('Error:', err.message);
|
||||
console.error(err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user