Reads each receipt or invoice you link, pulls out supplier, date, total and tax, and adds a row to your expenses sheet.
Uses
Google Sheets
OpenAI
Turn receipts and invoices into expense rows
receiptLinks to blank.Set receiptLinks to blank.spreadsheetUrl to blank.Set spreadsheetUrl to blank.expensesTab to Expenses.Set expensesTab to Expenses.reviewTab to Needs review.Set reviewTab to Needs review.maxDocuments to 25.Set maxDocuments to 25.recordedOn.Get today's date and save it as recordedOn.recordedLinks to an empty list.Set recordedLinks to an empty list.recordedLinksErrorIf a step below fails, save the error as recordedLinksErrorTry
spreadsheetUrl. Save it as expenseTabRows.Read the rows of spreadsheetUrl. Save it as expenseTabRows.spreadsheetUrl. Save it as reviewTabRows.Read the rows of spreadsheetUrl. Save it as reviewTabRows.column_8 from every item in expenseTabRows.rows and save it as expenseLinks.Get column_8 from every item in expenseTabRows.rows and save it as expenseLinks.column_8 from every item in reviewTabRows.rows and save it as reviewLinks.Get column_8 from every item in reviewTabRows.rows and save it as reviewLinks.expenseLinks and reviewLinks into one list and save it as recordedLinks.Combine expenseLinks and reviewLinks into one list and save it as recordedLinks.On error
recordedLinksError.message), so nothing was read or added: without them, receipts recorded earlier could be added twice. Check the address in 'spreadsheetUrl', that both tabs exist with exactly those names, and that the Google account connected to Lodol can edit the sheet, then run it again.Stop and report a problem: Could not read the links already recorded on the '@expensesTab' and '@reviewTab' tabs (recordedLinksError.message), so nothing was read or added: without them, receipts recorded earlier could be added twice. Check the address in 'spreadsheetUrl', that both tabs exist with exactly those names, and that the Google account connected to Lodol can edit the sheet, then run it again.documentsRead to 0.Set documentsRead to 0.expensesAdded to 0.Set expensesAdded to 0.sentForReview to 0.Set sentForReview to 0.alreadyRecorded to 0.Set alreadyRecorded to 0.linksLeft to 0.Set linksLeft to 0.unreadLinks to an empty list.Set unreadLinks to an empty list.lastReadError to blank.Set lastReadError to blank.rawLink in receiptLinks split by a new line:For each rawLink in receiptLinks split by a new line:rawLink and save it as link.Trim rawLink and save it as link.link is emptyIf link is emptyYes
No
No steps
recordedLinks contains link is yesIf recordedLinks contains link is yesYes
alreadyRecorded.Add 1 to alreadyRecorded.No
No steps
documentsRead is greater than or equal to maxDocumentsIf documentsRead is greater than or equal to maxDocumentsYes
linksLeft.Add 1 to linksLeft.No
No steps
documentsRead.Add 1 to documentsRead.link doesn't start with http (ignoring case)If link doesn't start with http (ignoring case)Yes
badLinkRow to [recordedOn, , , , , , , link, This is not a web address. Use a link that opens the PDF or image directly.].Set badLinkRow to [recordedOn, , , , , , , link, This is not a web address. Use a link that opens the PDF or image directly.].reviewTab in spreadsheetUrl.Add a row to reviewTab in spreadsheetUrl.link to the end of recordedLinks and save it as recordedLinks.Add link to the end of recordedLinks and save it as recordedLinks.sentForReview.Add 1 to sentForReview.No
No steps
invoice to nothing.Set invoice to nothing.readErrorIf a step below fails, save the error as readErrorTry
receiptReading.Run an AI agent: Read the attached receipt or invoice and pull out who issued it, its date, its number, it… and save it as receiptReading.invoice to receiptReading.output.Change invoice to receiptReading.output.On error
link to the end of unreadLinks and save it as unreadLinks.Add link to the end of unreadLinks and save it as unreadLinks.lastReadError to readError.message.Change lastReadError to readError.message.supplier to blank.Set supplier to blank.missingSupplierIf a step below fails, save the error as missingSupplierTry
invoice.vendor_name and save it as supplier.Trim invoice.vendor_name and save it as supplier.On error
supplier to blank.Change supplier to blank.invoiceDate to blank.Set invoiceDate to blank.missingInvoiceDateIf a step below fails, save the error as missingInvoiceDateTry
invoice.invoice_date and save it as invoiceDate.Trim invoice.invoice_date and save it as invoiceDate.On error
invoiceDate to blank.Change invoiceDate to blank.invoiceNumber to blank.Set invoiceNumber to blank.missingInvoiceNumberIf a step below fails, save the error as missingInvoiceNumberTry
invoice.invoice_number and save it as invoiceNumber.Trim invoice.invoice_number and save it as invoiceNumber.On error
invoiceNumber to blank.Change invoiceNumber to blank.currency to blank.Set currency to blank.missingCurrencyIf a step below fails, save the error as missingCurrencyTry
invoice.currency and save it as currency.Trim invoice.currency and save it as currency.On error
currency to blank.Change currency to blank.total to invoice.total.Set total to invoice.total.tax to invoice.tax.Set tax to invoice.tax.readerIsConfident to invoice.requires_review is false.Set readerIsConfident to invoice.requires_review is false.reviewReason to blank.Set reviewReason to blank.supplier is emptyIf supplier is emptyYes
reviewReason to reviewReasonNo supplier name was read.Change reviewReason to reviewReasonNo supplier name was read.No
No steps
invoiceDate is emptyIf invoiceDate is emptyYes
reviewReason to reviewReasonNo date was read.Change reviewReason to reviewReasonNo date was read.No
No steps
total is emptyIf total is emptyYes
reviewReason to reviewReasonNo total was read.Change reviewReason to reviewReasonNo total was read.No
No steps
readerIsConfident is noIf readerIsConfident is noYes
reviewReason to reviewReasonThe reader was not confident about this document.Change reviewReason to reviewReasonThe reader was not confident about this document.No
No steps
problem in invoice.validation_errors:For each problem in invoice.validation_errors:problemText to blank.Set problemText to blank.problemErrorIf a step below fails, save the error as problemErrorTry
problem.description and save it as problemText.Trim problem.description and save it as problemText.On error
problemText to blank.Change problemText to blank.problemText isn't emptyIf problemText isn't emptyYes
reviewReason to reviewReason@problemText .Change reviewReason to reviewReason@problemText .No
No steps
totalCell to blank.Set totalCell to blank.total isn't emptyIf total isn't emptyYes
totalCell to total.Change totalCell to total.No
No steps
taxCell to blank.Set taxCell to blank.tax isn't emptyIf tax isn't emptyYes
taxCell to tax.Change taxCell to tax.No
No steps
expenseRow to [recordedOn, supplier, invoiceDate, invoiceNumber, totalCell, taxCell, currency, link].Set expenseRow to [recordedOn, supplier, invoiceDate, invoiceNumber, totalCell, taxCell, currency, link].reviewReason is emptyIf reviewReason is emptyYes
expensesTab in spreadsheetUrl.Add a row to expensesTab in spreadsheetUrl.link to the end of recordedLinks and save it as recordedLinks.Add link to the end of recordedLinks and save it as recordedLinks.expensesAdded.Add 1 to expensesAdded.No
reviewReason to the end of expenseRow and save it as reviewRow.Add reviewReason to the end of expenseRow and save it as reviewRow.reviewTab in spreadsheetUrl.Add a row to reviewTab in spreadsheetUrl.link to the end of recordedLinks and save it as recordedLinks.Add link to the end of recordedLinks and save it as recordedLinks.sentForReview.Add 1 to sentForReview.Added to '@expensesTab': @expensesAdded. Sent to '@reviewTab' for a person to check: @sentForReview. Already recorded, so skipped: @alreadyRecorded. and save it as runSummary.Build the text Added to '@expensesTab': @expensesAdded. Sent to '@reviewTab' for a person to check: @sentForReview. Already recorded, so skipped: @alreadyRecorded. and save it as runSummary.unreadLinks isn't emptyIf unreadLinks isn't emptyYes
unreadLinks with a new line and save it as unreadList.Join unreadLinks with a new line and save it as unreadList.runSummary These links could not be opened or read, so nothing was recorded for them and they are tried again on the next run:Stop and report a problem: runSummary These links could not be opened or read, so nothing was recorded for them and they are tried again on the next run:
unreadList
The error was: lastReadError
Each link must open the receipt itself (a PDF, PNG, JPG or WEBP file) without signing in. Fix or remove these links in 'receiptLinks'.No
No steps
linksLeft is greater than 0If linksLeft is greater than 0Yes
runSummary Links left for the next run: linksLeft (at most maxDocuments are read per run). Run it again to carry on; links already recorded are skipped.Finish the run: runSummary Links left for the next run: linksLeft (at most maxDocuments are read per run). Run it again to carry on; links already recorded are skipped.No
No steps
documentsRead is 0If documentsRead is 0Yes
No
No steps
runSummary.Finish the run: runSummary.