SCRAPE-9: Implement updateDailySummary() aggregation (#14)

Co-authored-by: Stephen Minakian <stephenminakian@gmail.com>
Co-committed-by: Stephen Minakian <stephenminakian@gmail.com>
This commit is contained in:
2026-02-06 00:15:30 -07:00
committed by stephen
parent d8adfbf90c
commit b4978caf31
2 changed files with 647 additions and 0 deletions

View File

@ -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,