- A supplier sends an invoice by email.
- Saving one attachment is easy. Deciding what those files mean is not.
- Should they become one invoice?
- That was the client problem in a B2B procurement platform built on Medusa.
The client problem
A supplier sends an invoice by email. The message contains three PDFs: the invoice, a continuation page and a revised copy sent moments later.
Saving one attachment is easy. Deciding what those files mean is not.
Should they become one invoice? In which order? Is the newest file an additional page or a replacement? Which version did the buyer review? And what happens if an extraction callback finishes while an operator is changing the decision?
That was the client problem in a B2B procurement platform built on Medusa. Supplier invoices arrived through email and order-page uploads, while buyers needed one reliable document for reconciliation and payment.
We built an invoice-source model around each PDF. Every source keeps its origin, file identity, attachment position, extracted data, mapping and review status. Accepted sources are assembled into the active invoice in deterministic order. Replacements preserve the relationship with the previous evidence, and validation freezes further edits.
The result is not merely a PDF viewer. It is an explainable answer to a finance question: which supplier evidence authorised this payment decision?
The client problem: one invoice is not always one file
Accounts-payable workflows often assume a clean input: one purchase order, one invoice number, one PDF.
Real supplier communication is messier. A long invoice may be split across attachments. A vendor may resend a corrected document with the same reference. An email can include unrelated notes. A buyer may upload a replacement from the order page while an earlier emailed copy is still being processed.
If the platform stores only “the invoice PDF”, each new upload overwrites the meaning of the previous one. Nobody can later explain which pages were reviewed, why one copy was rejected or how a replacement became active.
If it stores every file without a decision model, the opposite problem appears: finance sees a folder of PDFs but no authoritative invoice.
We separated source evidence from the active document. The source records what arrived. Review decides what participates. The active invoice is rebuilt from the accepted set.
Create one canonical source for every PDF
When an inbound email arrives, the platform saves all attachments but creates invoice-source records only for PDFs. Each record keeps the inbound message, original filename, stored file, sender, subject and original attachment index.
An email with two invoice PDFs therefore creates two independent sources rather than silently selecting the first attachment. A text note can remain part of the received email without being mistaken for invoice evidence.
The source also carries the business fields that evolve during processing: supplier, order, invoice reference, extraction status, extracted values, mapping origin and human review status.
This makes the lifecycle visible. A file can be pending while extraction runs, accepted after review, rejected as irrelevant, identified as a duplicate or superseded by a newer source.
The important design choice is that the original file remains identifiable throughout those transitions. Review changes its role; it does not erase where it came from.
Keep machine extraction subordinate to the source
The extraction service does not become the invoice.
It enriches a source with an invoice number, date, vendor, totals, line items and confidence data. If the operator corrects the mapping, the source records that the decision became manual and when it changed.
This matters when several PDFs are involved. Each attachment may complete extraction at a different time. One may have a clear reference, another may need manual review and a third may be a duplicate. Collapsing them into one extraction job would make it difficult to understand which result belonged to which bytes.
By attaching extracted data to the individual source, the review interface can show the file beside the interpretation produced for that file. The buyer can accept useful evidence without granting automatic authority to every model output.
Processing status is also explicit. Failed extraction can be reviewed or waived through an authorised path; it is not silently treated as completed.
Order accepted files deterministically before merging
Several accepted PDFs may legitimately form one supplier invoice.
The platform sorts sources by upload time, with the source identifier as a stable tie-breaker. It then reads the accepted files in that order, copies every page from the first PDF, then every page from the next, and saves a new aggregate document.
Focused tests verify that page order follows source order. A two-file invoice therefore remains readable instead of becoming a random shuffle determined by database return order.
The merge also validates that the selected files are genuine PDFs with pages. Invalid bytes or an empty selection cannot become the active invoice.
The aggregate stores the combined reference numbers and becomes the convenient document that accounts payable opens. The underlying sources still explain exactly which files contributed to it.
This gives operators one practical PDF without sacrificing the provenance of its parts.
Treat duplicate references as a review decision
The same supplier can send the same invoice reference more than once.
That may mean duplicate delivery, a corrected copy or a multi-part document. A matching number alone cannot safely decide which interpretation is correct.
The review workflow finds other sources for the same supplier, order and normalised invoice reference. An operator can mark a source as a duplicate of a specific existing source, or explicitly allow matching references when the files are legitimate parts of the active set.
When the ordinary activation path encounters several copies with the same reference, the newest source wins and older copies become superseded. Tests cover that transition and confirm that metadata from the active source remains connected to the order.
The platform therefore avoids two dangerous shortcuts: counting every repeated file as another payable invoice, or deleting an older copy before its relationship to the replacement is understood.
Rebuild the active invoice from reviewed sources
Accepting or deactivating a source changes the active evidence set.
The platform responds by rebuilding the aggregate PDF from all currently accepted sources for that supplier and order. It also synchronises the order metadata used by the purchasing journey.
If the accepted set becomes empty, the active aggregate can be removed. If one accepted source is rejected, the remaining accepted files form the next version. If a new source is accepted, it joins the ordered set.
This is more reliable than patching an existing PDF in place. The active document is a materialised view of current review decisions. Rebuilding it from the source set makes the relationship reproducible.
The operation also includes recovery behaviour. If creating or activating the new aggregate fails, the service restores the previous replacement where possible and removes the incomplete new file. Tests exercise restoration after partial status failures.
Give invoice replacement its own business journey
A buyer may discover after review that the supplier document is wrong and request a replacement.
That is not the same as casually uploading another attachment. The request records the original document, original PDF, source identifiers, references, tax amount, candidate sources and a review decision for each candidate.
Each candidate must be reviewed. At least one must be included before the replacement set is ready. Included candidates become accepted; rejected candidates remain excluded; the formerly active sources become superseded.
The new aggregate is built while preserving the previous PDF for the replacement history. The request then closes with the selected source identifiers and the operator who resolved it.
This gives the merchant a clear before-and-after story: these files supported the original invoice; these candidates were reviewed; this set became the replacement.
It also keeps tax changes tied to the same controlled transition instead of leaving financial metadata behind when the document changes.
Prevent two reviewers from creating two active truths
Invoice review can receive concurrent actions.
An administrator may accept a source while another request deactivates it. A replacement completion may run while an extraction result changes a candidate. Without coordination, both actions could build different aggregates and whichever finishes last would silently win.
The platform serialises source-set mutations for an order with a database advisory transaction lock. Activation, deactivation and replacement completion enter the same order-level critical section before rebuilding the aggregate.
The replacement flow also rechecks reviewed candidates immediately before applying the decision. If a reference, extraction state or required tax confirmation changed after review, completion stops with a conflict rather than publishing an obsolete choice.
The buyer invoice comparison carries its own version fingerprint. A browser submission based on older comparison data cannot validate a newer state by accident.
These guards turn review into a controlled state transition rather than a collection of independent buttons.
Freeze source mutation after buyer validation
Once the buyer has validated the invoice for payment progression, the evidence should stop moving underneath that decision.
The mutation paths check the order's invoice-validation state before changing source mapping, activation or replacement. A validated invoice rejects ordinary source edits.
This is a business lock, not a claim that every database row is physically immutable. Its purpose is precise: the document and source set used for buyer validation cannot be casually rewritten through the normal review workflow afterwards.
If the commercial reality changes, the platform uses an explicit correction or replacement journey that can carry its own audit information. It does not pretend the original decision never happened.
That distinction is essential for accounts payable. A source history is useful only when the point of financial approval has a stable meaning.
Show operators the history they need
The review interface can list sources by supplier, order, status and origin. Each entry exposes the filename, reference, extraction state, mapping state and review decision needed to understand its role.
Operators can answer practical questions without inspecting storage buckets:
- Which PDFs arrived in the supplier's email?
- Which attachment was accepted?
- Was another copy rejected or marked duplicate?
- Which files were merged into the active invoice?
- Did a human change the extracted mapping?
- Which replacement candidates were included?
- Has buyer validation frozen the document?
This is where the source model creates operational value. The platform does not merely retain files; it turns their relationships into a reviewable business record.
Why Medusa was the right foundation
Medusa already gave the project orders, users, files, workflows and event-driven extension points. The client needed invoice evidence to participate in a longer purchasing journey that included receiving, reconciliation and payment validation.
We added source records, extraction states, human review, deterministic PDF aggregation, duplicate handling, replacement transitions and order-level locking around those commerce primitives.
On a rigid commerce platform, invoice intake often lives in a detached document tool. The order sees one final URL, while the history of how that document became authoritative lives elsewhere.
Medusa let us keep the evidence lifecycle connected to the purchase order and its business state. The engine remained the foundation; the client-specific accounts-payable capability became part of the platform.
A practical invoice-evidence checklist
Before accepting supplier invoices from email or uploads, define:
- Does every PDF become an identifiable source record?
- Is the original filename, sender and attachment position preserved?
- Is extracted data attached to the exact file it describes?
- Can operators distinguish pending, accepted, rejected, duplicate and superseded sources?
- How are matching invoice references reviewed?
- Is source ordering deterministic before PDF merge?
- Are invalid or empty PDFs rejected?
- Can the active invoice be rebuilt from the accepted set?
- What happens if rebuilding the aggregate fails halfway through?
- Does replacement preserve the relationship to previous evidence?
- Are all replacement candidates reviewed before activation?
- Are concurrent source-set changes serialised per order?
- Does a stale comparison submission fail safely?
- Are ordinary mutations blocked after buyer validation?
These questions separate a document upload feature from an accounts-payable evidence system.
The broader lesson
The client did not need somewhere to put invoice PDFs.
They needed one active document that finance could use and a traceable explanation of how it was assembled.
We modelled every PDF as its own source, kept extraction and manual review attached to that source, merged accepted pages in deterministic order and made duplicate and replacement decisions explicit. Order-level locking protects concurrent transitions, while buyer validation freezes the evidence used for payment progression.
For the supplier, email remains a familiar channel. For the operator, every file has a clear status. For accounts payable, the active invoice is no longer an unexplained attachment: it is the result of a controlled review journey.
