fix: rewrite booking sheet parser to match actual VotC sheet structure
- Fix venue header detection ('Occupancy Commons Hub' not just 'Commons Hub')
- Dynamically find room # and bed type columns (not hardcoded positions)
- Carry room numbers down for multi-bed rooms
- Expand range from A:G to A:L to capture all 4 week columns
- Change default tab name to 'VotC26 Occupancy'
- Add BOOKING_SHEET_ID to docker-compose.yml
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
78b2ba0499
commit
396b6d1c7e
|
|
@ -101,17 +101,20 @@ async function parseBookingSheet() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const sheetId = process.env.BOOKING_SHEET_ID || process.env.GOOGLE_SHEET_ID;
|
const sheetId = process.env.BOOKING_SHEET_ID || process.env.GOOGLE_SHEET_ID;
|
||||||
const sheetName = process.env.BOOKING_SHEET_TAB || 'Booking Sheet';
|
const sheetName = process.env.BOOKING_SHEET_TAB || 'VotC26 Occupancy';
|
||||||
|
|
||||||
const response = await sheets.spreadsheets.values.get({
|
const response = await sheets.spreadsheets.values.get({
|
||||||
spreadsheetId: sheetId,
|
spreadsheetId: sheetId,
|
||||||
range: `${sheetName}!A:G`,
|
range: `${sheetName}!A:L`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const rows = response.data.values || [];
|
const rows = response.data.values || [];
|
||||||
const beds = [];
|
const beds = [];
|
||||||
let currentVenue = null;
|
let currentVenue = null;
|
||||||
let weekColIndexes = {};
|
let weekColIndexes = {};
|
||||||
|
let currentRoom = null;
|
||||||
|
let bedTypeCol = -1;
|
||||||
|
let roomCol = -1;
|
||||||
|
|
||||||
for (let i = 0; i < rows.length; i++) {
|
for (let i = 0; i < rows.length; i++) {
|
||||||
const row = rows[i];
|
const row = rows[i];
|
||||||
|
|
@ -119,34 +122,50 @@ async function parseBookingSheet() {
|
||||||
// Empty row — reset venue context
|
// Empty row — reset venue context
|
||||||
currentVenue = null;
|
currentVenue = null;
|
||||||
weekColIndexes = {};
|
weekColIndexes = {};
|
||||||
|
currentRoom = null;
|
||||||
|
bedTypeCol = -1;
|
||||||
|
roomCol = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const firstCell = (row[0] || '').toString().trim();
|
const firstCell = (row[0] || '').toString().trim();
|
||||||
|
|
||||||
// Check if this is a venue header
|
// Check if this is a venue header
|
||||||
if (firstCell === 'Commons Hub' || firstCell === 'Herrnhof Villa') {
|
if (firstCell.startsWith('Occupancy Commons Hub') || firstCell === 'Commons Hub') {
|
||||||
currentVenue = firstCell;
|
currentVenue = 'Commons Hub';
|
||||||
weekColIndexes = {};
|
weekColIndexes = {};
|
||||||
|
currentRoom = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (firstCell === 'Herrnhof Villa') {
|
||||||
|
currentVenue = 'Herrnhof Villa';
|
||||||
|
weekColIndexes = {};
|
||||||
|
currentRoom = null;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this is the column header row (contains "Room" and week columns)
|
// Check if this is the column header row (look for week headers)
|
||||||
if (firstCell.toLowerCase() === 'room' && currentVenue) {
|
if (currentVenue && !Object.keys(weekColIndexes).length) {
|
||||||
|
let foundWeeks = false;
|
||||||
for (let c = 0; c < row.length; c++) {
|
for (let c = 0; c < row.length; c++) {
|
||||||
const header = (row[c] || '').toString().trim();
|
const header = (row[c] || '').toString().trim();
|
||||||
if (WEEK_COLUMNS.includes(header)) {
|
if (WEEK_COLUMNS.includes(header)) {
|
||||||
weekColIndexes[header] = c;
|
weekColIndexes[header] = c;
|
||||||
|
foundWeeks = true;
|
||||||
}
|
}
|
||||||
|
if (header.toLowerCase() === 'room #' || header.toLowerCase() === 'room') roomCol = c;
|
||||||
|
if (header.toLowerCase() === 'bed type') bedTypeCol = c;
|
||||||
}
|
}
|
||||||
continue;
|
if (foundWeeks) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a venue and week columns, this is a bed row
|
// If we have a venue and week columns, this is a bed row
|
||||||
if (currentVenue && Object.keys(weekColIndexes).length > 0 && firstCell) {
|
if (currentVenue && Object.keys(weekColIndexes).length > 0 && roomCol >= 0 && bedTypeCol >= 0) {
|
||||||
const room = firstCell;
|
const roomCell = (row[roomCol] || '').toString().trim();
|
||||||
const bedType = (row[1] || '').toString().trim();
|
if (roomCell) currentRoom = roomCell;
|
||||||
if (!bedType) continue;
|
|
||||||
|
const bedType = (row[bedTypeCol] || '').toString().trim();
|
||||||
|
if (!bedType || !currentRoom) continue;
|
||||||
|
|
||||||
const occupancy = {};
|
const occupancy = {};
|
||||||
for (const [week, colIdx] of Object.entries(weekColIndexes)) {
|
for (const [week, colIdx] of Object.entries(weekColIndexes)) {
|
||||||
|
|
@ -156,7 +175,7 @@ async function parseBookingSheet() {
|
||||||
|
|
||||||
beds.push({
|
beds.push({
|
||||||
venue: currentVenue,
|
venue: currentVenue,
|
||||||
room,
|
room: currentRoom,
|
||||||
bedType,
|
bedType,
|
||||||
rowIndex: i,
|
rowIndex: i,
|
||||||
weekColumns: { ...weekColIndexes },
|
weekColumns: { ...weekColIndexes },
|
||||||
|
|
@ -265,7 +284,7 @@ async function assignBooking(guestName, accommodationType, selectedWeeks) {
|
||||||
// Write guest name to the selected week columns
|
// Write guest name to the selected week columns
|
||||||
const sheets = await getSheetsClient();
|
const sheets = await getSheetsClient();
|
||||||
const sheetId = process.env.BOOKING_SHEET_ID || process.env.GOOGLE_SHEET_ID;
|
const sheetId = process.env.BOOKING_SHEET_ID || process.env.GOOGLE_SHEET_ID;
|
||||||
const sheetName = process.env.BOOKING_SHEET_TAB || 'Booking Sheet';
|
const sheetName = process.env.BOOKING_SHEET_TAB || 'VotC26 Occupancy';
|
||||||
|
|
||||||
// Convert week values to column headers
|
// Convert week values to column headers
|
||||||
const weekHeaders = selectedWeeks.map(w => `Week ${w.replace('week', '')}`);
|
const weekHeaders = selectedWeeks.map(w => `Week ${w.replace('week', '')}`);
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ services:
|
||||||
- SMTP_USER=contact@valleyofthecommons.com
|
- SMTP_USER=contact@valleyofthecommons.com
|
||||||
- SMTP_PASS=${SMTP_PASS}
|
- SMTP_PASS=${SMTP_PASS}
|
||||||
- EMAIL_FROM=Valley of the Commons <contact@valleyofthecommons.com>
|
- EMAIL_FROM=Valley of the Commons <contact@valleyofthecommons.com>
|
||||||
|
- BOOKING_SHEET_ID=1kjVy5jfGSG2vcavqkbrw_CHSn4-HY-OE3NAgyjUUpkk
|
||||||
|
- BOOKING_SHEET_TAB=VotC26 Occupancy
|
||||||
depends_on:
|
depends_on:
|
||||||
votc-db:
|
votc-db:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue