This Script Eats Glass and Smiles // AUTOMATED CHECK SIGNOFFS
>> NODE: ctrlaltcorp.dev
>> AUTHOR: HOTCHIP
>> TIME: [20251010-0900]
Paperwork: the ghost of a dead tree, haunting the living with pointless ritual.
The Corp® told me everything was secure. They called the paperwork "best practice."
>>Cute.Back in February 2023 I duct-taped something together so a payroll could hand a physical check to a human and collect a signature without invoking an entire platform migration. It was small, it worked, and it lived. That's the point reliability > elegance.
This thing, in one sentence
Copy a Docs template, read the Data sheet, sort by location, make a grouped document with NAME / DATE / CHECK / SIGNATURE rows, hand it off to the printer. Humans sign. Job done.
Why I wrote it
Because people still want to physically sign things. Because payroll doesn’t want CSVs! They want a single, printable page per location. Because infrastructure can be overthought and overengineered. Because operations need a lever they can pull without calling six teams at 9PM.
How it behaves (Operator log)
- Make a copy of a Docs template into a destination folder.
- Read the sheet (display values so dates look human).
- Sort rows by the location column so rows group together.
- Walk the rows; when the location changes, add a header and a fresh table; append rows with a long signature line.
- Save, close, and display a clickable link in a dialog for payroll to open and print.
>> [2023-02-14 03:17] cron: none, run manually from spreadsheet menu
>> [2023-02-14 03:17] Template: locked (owner only)
>> [2023-02-14 03:17] rows: 214
>> [2023-02-14 03:17] destinationFolder: /Payroll/SignDocs
>> [2023-02-14 03:19] saved: Sign Doc 2-14-2023.docx (link presented)
Snippets
Here’s a sanitized taste of the script’s structure so you know what you’re reading when you open it in the editor. Nothing dangerous. Just logic.
// copy template to destination
const googleDocTemplate = DriveApp.getFileById('TEMPLATE_ID');
const destinationFolder = DriveApp.getFolderById('DEST_ID');
const docCopy = googleDocTemplate.makeCopy("Sign Doc "+ theDate(), destinationFolder);
const doc = DocumentApp.openById(docCopy.getId());
// read and sort
sheet.setFrozenRows(1);
sheet.sort(6, true); // sort by column 6 (location)
sheet.setFrozenRows(0);
const rows = sheet.getDataRange().getDisplayValues();
// iterate rows, insert header/table when location changes
rows.forEach(function(row, index) {
if (index === 0) return; // skip header
if (index === 1) { /* init header & table */ }
if (where !== row[4]) { /* page break + new header + new table */ }
// append row into table with signature cell
});
doc.saveAndClose();
You can view the full, sanitized script on GitHub.
Why this survived production
- Small blast radius. It writes files in one folder and never touches live payroll systems. You can nuke it and nothing else dies. Hell most people don't even know it's alive.
- Low ceremony. No deployments, no CI—a person clicks a menu and gets a printable doc. That UX reduction matters more than brittle architecture.
- Transparent output. If it misbehaves you open the doc and immediately see the problem. No distributed tracing required.
Where the ugliness lives (and why I accepted it)
- Hard-coded indexes:
row[4]is the location column. If someone reorders the sheet it silently mis-groups. Keep your schema documented and frozen. - Sorting behavior: the script mutates sheet freeze settings. That annoys power users who like their UI pinned. In practice, payroll runs are controlled, document the expectation.
- Printer variance: some printers ignore set widths. Signature lines are long underscores because text underlines survive the printer tantrums more reliably than cell widths.
- Performance: fine for hundreds, clunky for tens of thousands. If your Corp® grows into the millions, rethink the approach, but you won’t be reading this post then anyway you cog.
Admin checklist
- Lock the template: make template owner only; script uses a copy-per-run.
- Document sheet schema: freeze a header row and include explicit column names.
- Test after G Suite changes: Google API updates are small nightmares, run a test after admin changes.
- Keep 30–90 day backups of generated docs for reprints; name them with the date.
- Log lightly: add a single Logger.log that prints the header row detected at the start. That saved me.
If you inherit this script (and you will, in some form)
Don’t rewrite it on your first Monday. Run it. Read the output. Add one small sanity check that the header row contains the expected column names. That tiny telemetry will save you a support ticket and a panic in the payroll kernal.
Final thoughts
Architecture porn is sexy. Duct tape is reliable. This script isn’t a manifesto about microservices or cloud-native purity—it’s a tool in the toolbox that kepts payroll moving and checks signed. It’s ugly, but it works. That’s a kind of ugly I respect.
>> END OF TRANSMISSION
- HotChip
Note: This post is a retrospective/operational write-up. No exploit code or sensitive data is published here. This is not financial advice. This is not legal advice. This is not Corp® advice. This is not medical advice. This is not a joke.