Google Scripts批量生成发票不跳过已完成行、超时重启重复执行求助
Google Apps Script 发票生成脚本故障修复方案
1 跳过已处理行逻辑失效根因
- 列索引不匹配:Google Sheets的列编号采用1基计数(A列对应值为1),而
getDataRange().getValues()返回的二维数组采用0基索引。你的代码中将"DONE"标识写入第31列(sheet.getRange(index + 1, 31).setValue("DONE")),但判断已处理行时读取的是row[31],实际第31列对应的数组索引是30,判断条件永远无法命中,导致跳过逻辑完全不生效。 - 数据快照问题:脚本启动时一次性读取所有行数据存储到内存的
rows数组中,本次运行过程中写入表格的"DONE"标识不会同步更新内存数组,因此本次运行中处理过的行也不会被跳过,进一步浪费运行时间。
2 超时问题优化方案
针对大数据量下超时的问题,做以下优化:
- 减少API调用频次,相比原逻辑逐行调用写入接口,优化后控制单次处理行数避免不必要的性能损耗
- 增加单次运行处理行数限制,避免触达Google Apps Script单次运行时长上限(免费版为6分钟)
- 每次运行前重新读取最新表格数据,从第一个未处理的行开始执行,无需额外存储进度
3 修复后代码
function onOpen() { const ui = SpreadsheetApp.getUi(); const menu = ui.createMenu('AutoFill Docs'); menu.addItem('Create New Docs', 'createNewGoogleDocs') menu.addToUi(); } function createNewGoogleDocs() { // 配置参数,可根据实际需求修改 const TEMPLATE_ID = '1yXfcXTESCHqKsfMcgkhYJ9MdVwYoLYPhH1MRv4RyPk0'; const DEST_FOLDER_ID = '1TXEumNJXfgFzPtKLBOAKJBXG-yNnjseQ'; const SHEET_NAME = 'Export Worksheet'; const DONE_COL_INDEX = 31; // 存储DONE标识的列(表格1基列号) const URL_COL_INDEX = 30; // 存储发票URL的列(表格1基列号) const MAX_RUN_COUNT = 20; // 单次运行最多处理行数,可根据实际运行速度调整 const googleDocTemplate = DriveApp.getFileById(TEMPLATE_ID); const destinationFolder = DriveApp.getFolderById(DEST_FOLDER_ID); const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME); const rows = sheet.getDataRange().getValues(); let processedCount = 0; // 跳过表头遍历所有行 for (let index = 1; index < rows.length; index++) { const row = rows[index]; // 修复索引匹配问题,0基数组对应1基列号需减1 if (row[DONE_COL_INDEX - 1] === 'DONE') continue; // 达到单次处理上限直接退出 if (processedCount >= MAX_RUN_COUNT) break; // 原发票生成逻辑保留 const copy = googleDocTemplate.makeCopy(`${row[4]}, ${row[0]} Invoice`, destinationFolder); const doc = DocumentApp.openById(copy.getId()); const body = doc.getBody(); const friendlyDate = new Date(row[3]).toLocaleDateString(); body.replaceText('{{Full Address}}', row[4]); body.replaceText('{{unit}}', row[5]); body.replaceText('{{Total}}', row[15]); body.replaceText('{{Account Num}}', row[2]); body.replaceText('{{Owner 1}}', row[6]); body.replaceText('{{Owner 2}}', row[7]); body.replaceText('{{CO Name}}', row[17]); body.replaceText('{{St Address}}', row[20]); body.replaceText('{{Address 1}}', row[18]); body.replaceText('{{City}}', row[21]); body.replaceText('{{State}}', row[22]); body.replaceText('{{CO Zip}}', row[23]); body.replaceText('{{invoice #}}', row[0]); doc.saveAndClose(); const url = doc.getUrl(); // 写入当前行的URL和DONE标识 sheet.getRange(index + 1, URL_COL_INDEX).setValue(url); sheet.getRange(index + 1, DONE_COL_INDEX).setValue("DONE"); processedCount++; } }
使用说明
你可以根据脚本单次运行的实际时长调整MAX_RUN_COUNT的数值:如果运行一次还剩很多时间就调大,仍然超时就调小。多次点击菜单运行即可处理完全部数据,每次都会从上次中断的位置继续执行。
内容的提问来源于stack exchange,提问作者Phant Productions
相关产品推荐
相关产品推荐

