Implement updateDailySummary() aggregation function
All checks were successful
CI/CD Pipeline - Apartment API / Scan Dependencies (pull_request) Successful in 12s
CI/CD Pipeline - Apartment API / Run Linting (pull_request) Successful in 9m36s
CI/CD Pipeline - Apartment API / Run Tests (pull_request) Successful in 9m51s
CI/CD Pipeline - Apartment API / Send Webhook Notification (pull_request) Successful in 2s
CI/CD Pipeline - Apartment API / Build & Push Image (pull_request) Has been skipped
CI/CD Pipeline - Apartment API / Deploy to Production (pull_request) Has been skipped
All checks were successful
CI/CD Pipeline - Apartment API / Scan Dependencies (pull_request) Successful in 12s
CI/CD Pipeline - Apartment API / Run Linting (pull_request) Successful in 9m36s
CI/CD Pipeline - Apartment API / Run Tests (pull_request) Successful in 9m51s
CI/CD Pipeline - Apartment API / Send Webhook Notification (pull_request) Successful in 2s
CI/CD Pipeline - Apartment API / Build & Push Image (pull_request) Has been skipped
CI/CD Pipeline - Apartment API / Deploy to Production (pull_request) Has been skipped
Add daily summary aggregation that tracks apartment inventory changes: - Upsert summaries by date key for idempotent operation - Track new_units, rented_units, and stale_units arrays with counts - Calculate net_change (new - rented) and total_available_today - Fetch previous day summary for total_available_yesterday - Compute turnover_rate as percentage of rented vs yesterday available - Handle edge cases: zero division, missing previous day, month boundaries - Full test coverage with 22 tests across all functional areas
This commit is contained in:
@ -369,6 +369,21 @@ function convertDataTypes(unit) {
|
||||
};
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Date Helpers
|
||||
// ============================================================
|
||||
|
||||
/**
|
||||
* Calculate yesterday's date from a given date string.
|
||||
* @param {string} dateStr - Date in YYYY-MM-DD format
|
||||
* @returns {string} Yesterday's date in YYYY-MM-DD format
|
||||
*/
|
||||
function getYesterday(dateStr) {
|
||||
const date = new Date(dateStr + 'T00:00:00Z');
|
||||
date.setUTCDate(date.getUTCDate() - 1);
|
||||
return date.toISOString().split('T')[0];
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Database Operations
|
||||
// ============================================================
|
||||
@ -535,6 +550,75 @@ async function markStaleUnits(db, currentUnitCodes, date, logger) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update daily summary document.
|
||||
* Upserts by date field (YYYY-MM-DD format).
|
||||
* Fetches yesterday's summary for comparison metrics.
|
||||
* Calculates turnover_rate as (rentedUnits / yesterdayTotal * 100).
|
||||
*
|
||||
* @param {Db} db - MongoDB database instance
|
||||
* @param {Object} summaryData - Summary data
|
||||
* @param {string} summaryData.date - Date in YYYY-MM-DD format
|
||||
* @param {Array<string>} summaryData.newUnits - Unit codes added today
|
||||
* @param {Array<string>} summaryData.rentedUnits - Unit codes removed today
|
||||
* @param {number} summaryData.staleUnitsCount - Count of stale units
|
||||
* @param {number} summaryData.totalAvailable - Total available units today
|
||||
* @param {Object} logger - Logger instance
|
||||
* @returns {Promise<Object>} MongoDB updateOne result
|
||||
*/
|
||||
async function updateDailySummary(db, summaryData, logger) {
|
||||
const collection = db.collection(config.COLLECTIONS.DAILY_SUMMARIES);
|
||||
const { date, newUnits, rentedUnits, staleUnitsCount, totalAvailable } = summaryData;
|
||||
|
||||
// Calculate yesterday's date for comparison
|
||||
const yesterday = getYesterday(date);
|
||||
|
||||
// Get yesterday's summary for comparison
|
||||
const yesterdaySummary = await collection.findOne({ date: yesterday });
|
||||
const yesterdayTotal = yesterdaySummary?.total_available_today || 0;
|
||||
|
||||
const summary = {
|
||||
date,
|
||||
timestamp: new Date().toISOString(),
|
||||
new_units: newUnits,
|
||||
rented_units: rentedUnits,
|
||||
stale_units: [], // Stale units list is not tracked per PRD
|
||||
new_units_count: newUnits.length,
|
||||
rented_units_count: rentedUnits.length,
|
||||
stale_units_count: staleUnitsCount,
|
||||
net_change: newUnits.length - rentedUnits.length,
|
||||
total_available_today: totalAvailable,
|
||||
total_available_yesterday: yesterdayTotal,
|
||||
turnover_rate: yesterdayTotal > 0
|
||||
? Math.round((rentedUnits.length / yesterdayTotal) * 10000) / 100
|
||||
: 0
|
||||
};
|
||||
|
||||
try {
|
||||
const result = await collection.updateOne(
|
||||
{ date },
|
||||
{ $set: summary },
|
||||
{ upsert: true }
|
||||
);
|
||||
|
||||
logger.info('Daily summary updated', {
|
||||
date,
|
||||
newUnits: newUnits.length,
|
||||
rentedUnits: rentedUnits.length,
|
||||
totalAvailable
|
||||
});
|
||||
|
||||
return result;
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Failed to update daily summary', {
|
||||
errorType: error.name,
|
||||
errorMessage: error.message
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
fetchPage,
|
||||
parseUnits,
|
||||
@ -542,7 +626,9 @@ module.exports = {
|
||||
upsertUnits,
|
||||
insertPrices,
|
||||
markStaleUnits,
|
||||
updateDailySummary,
|
||||
// Export helpers for testing
|
||||
getYesterday,
|
||||
parseInteger,
|
||||
parsePositiveInteger,
|
||||
parseIntegerOrString,
|
||||
|
||||
Reference in New Issue
Block a user