Overnight Invoice Posting into a Legacy ERP
Contoso's finance team posts about 900 vendor invoices per business day into a 2012-era Win32 ERP client that exposes no API and no database access. Volume spikes to roughly 2,000 invoices on the final two business days of each month. Posting must run overnight and must never create duplicate ledger entries. Invoices over $10,000 require a controller's approval before posting, and approvals sometimes sit for two days. Today one Windows 10 virtual machine runs a single long desktop flow that opens the ERP, posts everything it can, and emails a summary. When the VM reboots, the run is lost and nobody knows which invoices were posted. The tenant has Power Platform premium licensing and a Dataverse-enabled environment. IT will not open inbound firewall ports.
1. Should the posting flow run attended or unattended, and where should the human approval step live relative to the desktop flow session?
Read the worked answer
Unattended. The work is high-volume, scheduled overnight, and has no human in the loop at posting time - that is the definition of unattended RPA. Attended execution would require someone signed in to Power Automate for desktop at 2 a.m. and would tie up a named user's session; it also cannot be triggered reliably by a scheduled cloud flow without that session being present.
Keep the approval outside the desktop session. Approvals can take two days; a desktop flow session must not sit idle holding a machine and an ERP connection for that long. Put the wait in the cloud flow:
- Scheduled cloud flow retrieves the invoice list from the source system.
- For each invoice, if
Amount > 10000, start an approval action; otherwise mark it pre-approved. - Only approved invoices get written to the work queue (a Dataverse table with
InvoiceId,Status,ClaimedBy,AttemptCount). - The desktop flow consumes queue rows and posts them.
This splits a multi-day business process from a short, mechanical screen-scraping step, so a reboot or a slow approver affects only one part of the pipeline. It also makes the approval decision auditable in Dataverse rather than buried in a flow run history.
2. Design the work-queue and duplication-control approach. Which component must own idempotency, and how do you detect that an invoice already posted?
Read the worked answer
The desktop flow must be idempotent, because it is the only component that knows whether the ERP accepted a posting. A queue item being marked 'completed' is not proof; the run can die between the ERP commit and the status update.
Approach:
- Queue rows move
Pending → Claimed → Posted | Failed, withClaimedByand a timestamp so a stranded claim can be reclaimed after a timeout rather than being processed twice concurrently. - Before posting, the desktop flow uses the ERP's own search/lookup screen to check whether a voucher already exists for that
InvoiceId(the ERP's external reference field). If it exists, skip the posting step and jump straight to marking the rowPosted. This makes a re-run safe after a crash. - The ERP entry itself carries
InvoiceIdas the reference so the check is a single deterministic lookup, not a fuzzy amount/vendor match. - Wrap the posting block in On block error handling: on any failure, set the queue row to
Failedwith the error text and the step name, close the ERP session cleanly, and let the orchestrator retry with a boundedAttemptCount. - Exceptions (e.g. vendor on hold, currency mismatch) route to a separate
NeedsReviewstate rather than being retried forever, so the nightly run does not stall on one bad invoice.
The reasoning: at-least-once delivery is unavoidable with screen automation, so the design must convert it to effectively-once through a business-key check inside the target system.
3. Month-end requires roughly 2,000 postings in one night window. What changes to the machine and flow topology do you recommend, and what limits still apply?
Read the worked answer
A single machine running one desktop flow sequentially cannot absorb a 2x spike inside a fixed overnight window, and a single machine is also a single point of failure for the whole process.
Recommended topology:
- Register two to three on-premises machines into a machine group, sharing one on-premises data gateway. The cloud flow targets the machine group, so the platform dispatches each desktop flow run to whichever machine is free. Each machine runs one unattended desktop flow run at a time, so N machines ≈ N concurrent postings.
- Keep each desktop flow run short and scoped to one queue item. A long flow that loops internally holds a machine for the whole batch and defeats the scheduler's ability to parallelise and to recover from a crash.
- Because the ERP is a shared system of record, verify with the ERP owners that parallel sessions and concurrent postings in the same ledger period are supported; if the ledger locks by period, parallelism buys nothing for that month and you should instead move the cut-off earlier. This is the constraint that most often invalidates the obvious answer.
- Add a backlog gauge: count of
Pendingrows at the start of the window, surfaced to the ops team, so the 2,000-day is visible before it fails.
Also keep a warm standby: registering machines in a group means losing one VM degrades throughput but does not stop the process.