Module 21 · business · intermediate
Solutions 21 · Overdue Invoice Chaser
None of these have been run against live Gmail, Google Sheets, Stripe or Slack accounts yet.
Exercise 1
- In
plan.js, before composing, remember the mapping:($getWorkflowStaticData('global').numbers ??= {})[inv.number] = inv.invoice_id; - New workflow: Gmail Trigger (query
subject:invoice -from:me newer_than:1d, Simplify on) → Code:const m = $json.Subject.match(/invoice ([A-Z0-9-]+)/i); return m ? [{ json: { number: m[1], from: $json.From, snippet: $json.snippet } }] : []; - Static data belongs to the chaser workflow, so add a small
GET ar/lookup?number=lane to the chaser (Webhook → Code returning{ invoice_id: numbers[number] }→ Respond), then call it here with HTTP Request. - → HTTP Request POST
/webhook/ar/pausewith{ "invoice_id": "{{ $json.invoice_id }}", "reason": "customer replied", "until": "{{ $now.plus({ days: 5 }).toISODate() }}" } - → Gmail Send to the owner:
Reply about {{ $('Code').item.json.number }} from {{ $('Code').item.json.from }}: {{ $('Code').item.json.snippet }}.
Exercise 2
Add a third branch: Invoices from API? false → IF Use Sheet? (a new source setting) → Google Sheets Get Row(s) → Normalize Invoices. In normalize.js:
const fromSheet = $('Get Invoice Rows').isExecuted;
if (fromSheet) invoices = $('Get Invoice Rows').all().map((r) => fromSimple(r.json));
fromSimple already reads these column names and defaults status to open; paid rows are skipped by the plan.
Exercise 3
In Get Stripe Invoices → Options → Pagination: mode Update a Parameter in Each Request, parameter starting_after (query) = {{ $response.body.data[$response.body.data.length - 1].id }}, Pagination Complete When {{ !$response.body.has_more }}. The node then outputs one item per page, so in normalize.js read every page:
const pages = $('Get Stripe Invoices').all().map((i) => i.json);
invoices = pages.flatMap((p) => p.data ?? []).map(fromStripe);
has_more = false;
Stretch
After Summary Day? add Slack Send Message with text {{ $json.summary_text }} (it's already plain text with a "Largest overdue" list), On Error → Continue.