diff --git a/src/lib/server/sheets.ts b/src/lib/server/sheets.ts index fd62874..26532dd 100644 --- a/src/lib/server/sheets.ts +++ b/src/lib/server/sheets.ts @@ -12,20 +12,43 @@ async function getToken(credJson: string): Promise { return token; } +async function sheetIsEmpty( + spreadsheetId: string, + range: string, + token: string +): Promise { + const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${range}`; + const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } }); + if (!res.ok) return true; + const body = await res.json(); + return !body.values || body.values.length === 0; +} + +export const HEADER_ROW = [ + 'Date', 'Shift', 'Type', 'Calc ID', + 'Gross Tips', 'CC Fee Rate', 'CC Fees', 'Net Tips', + 'Kitchen %', 'Kitchen Pool', 'Liquor Sales', 'Bar Liquor %', 'Bar Pool', 'FOH Pool', + 'Name', 'Role', 'FOH Share', 'Bar Share', 'Kitchen Share', 'Total', +]; + /** * Append rows to a Google Sheet. - * Values are plain strings/numbers; Sheets will auto-detect dates and numbers. + * Writes the header row first only when the sheet is empty. */ export async function appendToSheet( spreadsheetId: string, sheetName: string, - values: (string | number)[][], + dataRows: (string | number)[][], credJson: string ): Promise { const token = await getToken(credJson); - const range = encodeURIComponent(`'${sheetName}'`); - const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${range}:append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS`; + const range = encodeURIComponent(`'${sheetName}'!A1`); + const base = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}`; + + const empty = await sheetIsEmpty(spreadsheetId, range, token); + const values = empty ? [HEADER_ROW, ...dataRows] : dataRows; + const url = `${base}/values/${range}:append?valueInputOption=USER_ENTERED&insertDataOption=INSERT_ROWS`; const res = await fetch(url, { method: 'POST', headers: { diff --git a/src/routes/api/export/+server.ts b/src/routes/api/export/+server.ts index dc4fae0..9ed5c02 100644 --- a/src/routes/api/export/+server.ts +++ b/src/routes/api/export/+server.ts @@ -26,15 +26,13 @@ export const POST: RequestHandler = async ({ request, locals }) => { const credJson = process.env.GOOGLE_SERVICE_ACCOUNT_JSON; if (!credJson) error(400, 'GOOGLE_SERVICE_ACCOUNT_JSON env var not set.'); - // Build the row matching PRD OR-8 - const headerRow = [ - 'Date', 'Shift', 'Gross Tips', 'CC Fee Rate', 'CC Fees', 'Tips After Fees', - 'Kitchen %', 'Kitchen Pool', 'Liquor Sales', 'Bar Liquor %', 'Bar Pool', 'FOH Pool', - ...dists.map(d => d.name), - ]; + // Columns: Date, Shift, Type, Calc ID, + // Gross Tips, CC Fee Rate, CC Fees, Net Tips, + // Kitchen %, Kitchen Pool, Liquor Sales, Bar Liquor %, Bar Pool, FOH Pool, + // Name, Role, FOH Share, Bar Share, Kitchen Share, Total - const dataRow = [ - calc.date, calc.shift, + const summaryRow: (string | number)[] = [ + calc.date, calc.shift, 'summary', calc.id, formatCents(calc.gross_tips_cents), `${(calc.cc_fee_rate * 100).toFixed(1)}%`, formatCents(calc.cc_fees_cents), @@ -45,14 +43,24 @@ export const POST: RequestHandler = async ({ request, locals }) => { `${(calc.bar_liquor_pct * 100).toFixed(0)}%`, formatCents(calc.bar_pool_cents), formatCents(calc.foh_pool_cents), - ...dists.map(d => formatCents(d.total_cents)), + '', '', '', '', '', '', ]; + const staffRows: (string | number)[][] = dists.map(d => [ + calc.date, calc.shift, 'staff', calc.id, + '', '', '', '', '', '', '', '', '', '', + d.name, d.role, + formatCents(d.foh_share_cents), + formatCents(d.bar_pool_share_cents), + formatCents(d.kitchen_share_cents), + formatCents(d.total_cents), + ]); + try { await appendToSheet( spreadsheetId, settings.google_sheets_sheet_name || 'Tip History', - [headerRow, dataRow], + [summaryRow, ...staffRows], credJson ); } catch (e) {