// From syncSquareToSheet()
// Logic: Batch processing with Idempotency & Staff Recovery
function syncSquareToSheet() {
const props = PropertiesService.getScriptProperties();
const nowIso = new Date().toISOString();
// Resume from last sync cursor
const beginIso = props.getProperty(SYNC_CURSOR_KEY) || isoDaysAgo_(30);
const payments = fetchPaymentsUpdatedSince_(beginIso, nowIso);
// Batch Fetch related Orders to minimize API calls (N+1 problem)
const orderIds = unique_(payments.map(p => p.order_id));
const ordersById = batchRetrieveOrders_(orderIds);
// Heuristic: Pre-fetch booking info to resolve missing staff
const bookingInfo = prefetchBookingInfo_(ordersById);
payments.forEach(p => {
const row = buildProcessedRow_(
p, ordersById[p.order_id], catalogInfo, staffById,
customersById, commissionData, bookingInfo
);
if (paymentRowIndex[p.id]) {
updates.push({row: paymentRowIndex[p.id], values: row});
} else {
appends.push(row);
}
});
props.setProperty(SYNC_CURSOR_KEY, nowIso);
}