onRecordCreate((e) => { if (e.record.getString("quote_number") !== "") { e.next(); return; } try { var now = new Date(); var year = now.getFullYear(); var month = String(now.getMonth() + 1).padStart(2, '0'); var prefix = "Q" + year + month; let attempts = 0; let candidate; do { // findRecordsByFilter accepts sort as the 3rd arg. // findFirstRecordByFilter's 3rd arg is params (dbx.Params), // which is why the old "-quote_number" sort string threw // "could not convert -quote_number to dbx.Params". const records = $app.findRecordsByFilter( "quotes", "quote_number != ''", "-quote_number", 1, 0 ); let newNum = 1; if (records && records.length > 0) { var raw = records[0].getString("quote_number"); // Extract trailing digits (handles Q202607011, // legacy Q-2026-07-011, Q1782862717620, etc.). var m = raw.match(/(\d+)$/); if (m) { newNum = parseInt(m[1], 10) + 1 + attempts; } } candidate = prefix + String(newNum).padStart(3, '0'); attempts++; // check if this candidate already exists var exists; try { exists = $app.findFirstRecordByFilter( "quotes", "quote_number = {:num}", { num: candidate } ); } catch (e) { exists = null; // not found throws in some versions } } while (exists && attempts < 5); e.record.set("quote_number", candidate); } catch (err) { console.error("Auto-numbering error:", err); e.record.set("quote_number", "Q" + Date.now()); // fallback that's at least unique } e.next(); }, "quotes");