const MODULES = [ { id:'overview', title:'1. The Queue', steps:[ { visual:'v_landing', badge:'Module 1 · Step 1 of 3', heading:'Where bills come from', body:'Vendor invoices arrive by email and are read automatically. The system extracts the vendor, amounts and line items, then creates a draft bill in Odoo. Bills that need a human decision land in the Bill Review Queue — this screen is your daily worklist.', points:[['📧','Invoice emailed to accounts@ — no manual downloading'],['🤖','AI reads the PDF/spreadsheet and drafts the bill'],['👀','Anything uncertain waits here for you']] }, { visual:'v_cards', badge:'Module 1 · Step 2 of 3', heading:'The four stat cards', body:'The top of the screen shows four clickable cards. Each is a bucket of bills waiting on you. Click a card to see only that bucket.', points:[['🟦','Light review — looks right, quick check then post'],['🟨','Manual review — something needs fixing before posting'],['🟪','Vendor unknown — the system could not match the sender'],['🟥','Failed — processing hit an error, needs a retry or dismiss']] }, { visual:'v_cards', badge:'Module 1 · Step 3 of 3', heading:'Work oldest first', body:'Items are listed with their age. Clear the oldest items first — the goal is that nothing sits in the queue for more than a couple of days.', tip:{title:'Why speed matters', text:'Bills stuck in review delay vendor payments and month-end close. A short queue means the automation is doing its job.'} } ]}, { id:'review', title:'2. Reviewing a Bill', steps:[ { visual:'v_rowbtns', badge:'Module 2 · Step 1 of 3', heading:'Open the bill and the document', body:'Every queue row has two buttons: Open bill (the draft in Odoo) and View document (the original invoice the vendor sent). Open both — best in side-by-side windows — so you can compare what the vendor sent against what the system drafted.', points:[['📄','View document = the vendor\u2019s original invoice'],['🧾','Open bill = the Odoo draft the system created']] }, { visual:'v_compare', badge:'Module 2 · Step 2 of 3', heading:'Check the three essentials', body:'On every bill, confirm three things against the original document: the vendor is right, the total matches to the cent, and the invoice number/date are correct.', points:[['🏢','Vendor name matches the document'],['💲','Total matches exactly'],['#️⃣','Invoice reference and date correct']] }, { visual:'v_compare', badge:'Module 2 · Step 3 of 3', heading:'Check the account coding', body:'Scan the bill lines. The system pre-codes each line to a general ledger account using what it has learned from past bills. If a line is coded to the wrong account, change it on the bill before posting.', tip:{title:'Your corrections teach the system', text:'Every account you fix is captured overnight and becomes a rule. Fix it once on the bill and the next invoice from that vendor codes itself correctly.'} } ]}, { id:'vendor', title:'3. Vendor Unknown', steps:[ { visual:'v_vunknown', badge:'Module 3 · Step 1 of 2', heading:'When the sender was not matched', body:'Bills in the Vendor unknown bucket were read successfully, but the system could not confidently match the sender to a vendor in Odoo. The row shows the vendor name as it appeared on the document.', warn:{title:'Don\u2019t guess', text:'If two similar vendors exist (e.g. two MFD entities), open the document and check the ABN before assigning.'} }, { visual:'v_vsearch', badge:'Module 3 · Step 2 of 2', heading:'Search and assign', body:'Type in the vendor search box on the row, pick the correct vendor from the list, and confirm. The item is re-queued and the system finishes creating the bill with that vendor attached.', tip:{title:'This is also learning', text:'The name-to-vendor match you make helps the system recognise that sender in future.'} } ]}, { id:'gst', title:'4. GST Tools', steps:[ { visual:'v_gstlow', badge:'Module 4 · Step 1 of 2', heading:'GST ×1.1 — bill total too low', body:'Sometimes the extracted line amounts exclude GST, so the Odoo bill total is about 10% under the invoice total. The GST ×1.1 button multiplies every line by 1.1 in one click so the totals match.', points:[['🔍','Symptom: Odoo total \u2248 invoice total \u00F7 1.1'],['🖱️','One click fixes all lines']] }, { visual:'v_gsthigh', badge:'Module 4 · Step 2 of 2', heading:'GST ÷1.1 — lines include GST', body:'The opposite case: line amounts already include GST, so tax is being added twice. GST ×1.1 divides the lines back to ex-GST amounts, applying up to a 5-cent rounding adjustment so the total still matches to the cent.', warn:{title:'Use once, then re-check', text:'After clicking either GST button, re-compare the bill total to the document before posting. Never click twice.'} } ]}, { id:'actions', title:'5. Post, Dismiss, Retry', steps:[ { visual:'v_approve', badge:'Module 5 · Step 1 of 3', heading:'Approve & post', body:'When the vendor, total and coding all check out, click Approve & post. The bill posts to the ledger (or moves into its approval route if one applies) and disappears from the queue.', points:[['✅','Approve & post = done, off your list'],['🧠','Anything you fixed first is learned overnight']] }, { visual:'v_dismiss', badge:'Module 5 · Step 2 of 3', heading:'Dismiss the noise', body:'Not everything in the queue is a bill — statements, remittances, marketing images and email signatures sometimes slip through. If an item is not a vendor invoice, click Dismiss to clear it.', warn:{title:'Dismiss is not delete-the-bill', text:'Dismiss clears the queue item. If a draft bill was already created for a non-invoice, delete that draft in Odoo too.'} }, { visual:'v_retry', badge:'Module 5 · Step 3 of 3', heading:'Retry failed items', body:'Items in the Failed bucket hit a processing error. Click Retry to push the document through again — transient errors usually clear on retry. If the same item fails repeatedly, tell Glen and include the document name.', tip:{title:'Stale items self-clean', text:'If a bill is posted or deleted directly in Odoo, its queue entry clears itself automatically — no action needed.'} } ]}, { id:'flags', title:'6. Red Flags', steps:[ { visual:'v_mismatch', badge:'Module 6 · Step 1 of 2', heading:'Company mismatch badge', body:'A red badge on a row means the bill\u2019s company does not match the mailbox the document arrived in — for example a Sensitive Freight (Co2) invoice drafted under TSS (Co1). Stop and check which entity the invoice is actually addressed to before posting.', warn:{title:'Wrong company = wrong ledger', text:'Posting to the wrong entity means intercompany cleanup later. Always resolve the red badge first.'} }, { visual:'v_dupes', badge:'Module 6 · Step 2 of 2', heading:'Watch for duplicates', body:'Vendors sometimes email the same invoice twice, or to two mailboxes. The system catches most duplicates, but if a bill looks familiar, search the vendor\u2019s invoice number in Odoo before posting.', points:[['🔁','Same invoice number + same vendor = duplicate'],['🛑','Dismiss the duplicate, keep the original']] } ]}, { id:'swap', title:'7. Company Swap Tool', steps:[ { visual:'v_swap_button', badge:'Module 7 · Step 1 of 3', heading:'When a bill lands under the wrong company', body:'Sometimes a vendor invoice gets drafted under the wrong TSS entity — for example a Sensitive Freight cost that should sit under TSS, or the reverse. Instead of deleting and re-keying the bill, open it and use the Swap Company button on the bill form (manager access only).', points:[['🔀','Moves ONE bill to the correct company — nothing is deleted'],['🔒','Manager-only — talk to Glen or Sue if you don’t see the button']] }, { visual:'v_swap_check', badge:'Module 7 · Step 2 of 3', heading:'It refuses before it guesses', body:'Before moving anything, the tool checks that every account and tax on the bill has an approved mapping between the two companies, and that the bill is fully unpaid. If anything is missing or the bill has already had a payment applied, it stops and lists exactly what’s wrong instead of half-completing the move.', warn:{title:'Already paid = it won’t move', text:'A bill with any payment activity cannot be swapped between companies. That protects the ledger — if this happens, leave a note for Glen rather than trying to force it.'} }, { visual:'v_swap_done', badge:'Module 7 · Step 3 of 3', heading:'After a successful swap', body:'The bill’s company, journal, and every line’s account/tax are remapped automatically, and it re-posts under the new company. A chatter note on the bill records exactly what moved and when, and an activity is raised so someone re-checks the analytic coding.', points:[['💬','Chatter note is the audit trail — no need to log it anywhere else'],['📌','Re-check analytic coding after a swap, it isn’t carried over']] } ]}, { id:'xcodup', title:'8. Cross-Company Duplicate Alert (email)', steps:[ { visual:'v_dupemail', badge:'Module 8 · Step 1 of 3', heading:'The same invoice, billed to two companies', body:'When the pipeline detects the exact same vendor document ingested as a bill in two different TSS companies, it no longer just sits as a quiet flag on the bill. It appears as its own section — "Cross-Company Duplicates Needing Action" — inside the twice-daily bill-rejection digest email, with the vendor, both bills, and how many times you’ve already been reminded.', points:[['📧','Arrives in the same digest email as rejected-bill queries'],['🔁','Repeats every digest until you action it — it will not go away on its own']] }, { visual:'v_dupebuttons', badge:'Module 8 · Step 2 of 3', heading:'Two real choices, right in the email', body:'Each pair shows three buttons. "Cancel [bill] — duplicate" cancels whichever bill is the erroneous re-keyed copy — no login required, click straight from the email. "Not a duplicate — dismiss" clears the flag on both bills if it turns out they’re genuinely separate charges that happened to match.', points:[['❌','Cancel = this specific bill was a mistake, remove it'],['✅','Dismiss = both bills are legitimate, stop asking']] }, { visual:'v_dupeblocked', badge:'Module 8 · Step 3 of 3', heading:'If cancel is refused', body:'Cancel only works on a bill that hasn’t been paid yet — that’s deliberate, this tool catches duplicates BEFORE money moves, not after. If a bill already has payment applied, clicking Cancel shows a plain message explaining why and asks you to dismiss instead or hand it to Glen/Sue for manual handling.', warn:{title:'Already paid = handle it manually', text:'Reversing a payment is out of scope for this button on purpose. If you see this message, flag the pair to Glen rather than retrying the click.'} } ]} ]; function renderVisual(key){ const chrome = u => `
'+st.body+'
'; if(st.tip)h+='Remember: fix coding on the bill before posting — every correction you make teaches the system.
'+ '