Customer Service Reference

How Invoicing Flows Between Our Systems

A plain-English guide to how Shopify, ShipStation, and Odoo work together for Terre — and why some orders sit in "To Invoice"

Prepared by: Ben · ERP Migration Team
For: Customer Service & Accounts Receivable
Subject: Response to invoicing questions raised

The Big Picture

Before getting into specific orders, it helps to understand what each system actually does. Each platform has a job, and they hand off information to each other.

Shopify Where it starts • Customer places order • Marketplace orders   (Amazon, eBay, Walmart)   flow in through Shopify • Payment captured here • Customer invoices sent   from here (for Terre) • Order is sent to ShipStation • Updates back to Odoo when   shipment ships order info ShipStation Where we ship • Receives orders from   Shopify • Prints shipping labels • Tracking numbers   assigned • Marks order as   "fulfilled" in Shopify • Does NOT talk to   Odoo directly fulfilled status Shopify connector syncs to Odoo every 15 minutes Odoo Books of record • Receives orders from   Shopify (via connector) • Tracks inventory • Keeps internal invoice   records (for accounting) • Records customer   payments • Official accounting   system

The key idea

Shopify is the traffic controller for the order. ShipStation is the shipping department. Odoo is the accounting office.

Important: customer invoices come from Shopify, not Odoo

For Terre today, the invoice that goes to the customer is sent from Shopify. Odoo is our system of record — it keeps an internal invoice record for accounting, tracks inventory, and reconciles payments, but it does not send invoices to customers.

So when Odoo shows an order in "To Invoice" status, that's about Odoo's internal accounting record — not about whether the customer has been invoiced.

Why this still matters for invoicing

Even though Odoo doesn't send the customer invoice, it still needs to know the order shipped so it can record the sale, draw down inventory, and close out the AR record. Odoo learns this when it sees the order marked as fulfilled — a status that flows from ShipStation → Shopify → Odoo. If anything breaks in that chain, the order sits in "To Invoice" waiting for someone to push it through.

Why Some Orders Auto-Invoice — and Some Don't

Customer Service noticed that some orders close out on their own in Odoo and some don't. Here's what's going on under the hood.

Odoo has a "rulebook" for auto-invoicing

For every order that comes in, Odoo checks three things and looks for a matching rule to decide whether to automatically create its internal invoice record:

1. How did they pay? (payment gateway) • Shopify Payments • Amazon • Walmart • eBay • No payment gateway   (invoice / net terms) 2. Is it paid? (financial status) • Paid • Unpaid / pending 3. Has it shipped? (fulfillment status) • Fulfilled (shipped) • Unshipped Each unique combination needs its own rule. We've configured these extensively.
Where we stand today

We've configured this rulebook thoroughly. The way we'd find out a rule is missing is when an order fails to import or update — and right now, the only failures we're seeing are stock-related, not rule-related. So the rulebook itself appears to be in good shape.

But older orders can still get stuck

Even with the rulebook complete, an individual order can still slip through — usually because of a one-off sync hiccup, an older order that pre-dates the current setup, or a stock issue at the time of import. Once an order falls outside the connector's "fresh import" window, Odoo won't go back and re-process it on its own — someone has to push it through manually. That's exactly what happened with order #2135.

What this means in practice

ScenarioResult
Order syncs cleanly through Shopify → Odoo✅ Auto-invoices in Odoo when it ships
Order missed its sync window (older or hiccup)⚠️ Sits in "To Invoice" — needs a manual re-import
Order has a stock issue (not enough inventory)❌ Doesn't import — ends up in the "failed queue"

Observation 1: Nikkel Iron Works #2135

The customer paid, but Odoo never closed out the order. Here's the story.

What actually happened

1 Order shipped on 3/31 ShipStation processed the order and marked it fulfilled in Shopify. 2 Odoo did NOT see the fulfillment For some reason, the Shopify → Odoo sync didn't catch this one. So Odoo thought the order was still un-shipped. 3 Because Odoo didn't see fulfillment, it didn't close out the order Order sat in "To Invoice" status in Odoo — even though Kaya had sent the invoice from Shopify on 4/21 and the customer had paid.

What we did to fix it

I ran the "import/update specific orders" operation in the Odoo → Shopify connector, pointed it at order 2135, and forced Odoo to re-read what Shopify had. Now Odoo correctly shows it as fulfilled and the internal invoice record is in place.

Clearing up one part of the original message

The theory

"The customer used the pay button in the email they received for their invoice."

What really happened

Kaya sent the invoice from Shopify on 4/21 — which is exactly how Terre's process is supposed to work today. That's where the customer's invoice always comes from for us. Shopify still shows the order as unpaid, which suggests payment came in by check.

Next step on this order

Mark the order as paid in Shopify, then confirm Odoo's internal invoice status moves to "In Payment" (or move it manually if not).

Heads up: this likely isn't the only one

Other older orders may be sitting in the same state — fulfilled in Shopify, but Odoo never caught the update. Someone will need to go through Odoo's "To Invoice" list and manually re-import any that are already shipped in Shopify.

Observation 2: Why "To Invoice" Shows Unshipped Orders

When you opened Odoo's "To Invoice" list, you saw 88 lines. Most of those orders haven't shipped yet. Here's why they're showing up there anyway.

The culprit: the "Shopify Discount Product"

When a business customer gets special pricing through Shopify, the discount comes through as a line item on the order called the "Shopify Discount Product". This line is what makes the math work.

That discount item has a setting called "Prepaid / Fixed Price" — meaning Odoo treats it as something that's invoiceable the moment the order is placed, not when it ships.

Sample order with business pricing Widget A × 10 Invoice when delivered ⏳ Widget B × 5 Invoice when delivered ⏳ Shopify Discount Product Invoice IMMEDIATELY ✓ Because just ONE line is ready to invoice... ...the whole order gets flagged "To Invoice" in Odoo — even though the widgets haven't shipped.

The fix when looking at the list

Use the "Shipped Order" filter

When you open Sales App → To Invoice → Orders to Invoice, turn on the "Shipped Order" filter. That hides the noise and shows only orders where physical goods have actually shipped. On the current list this takes it from 90 orders down to just 3 truly invoiceable orders.

Example: Hytrol Conveyor #6802 — the order flagged in the original email. It's on hold in Shopify until 6/23 and appears in "To Invoice" because of the discount-line behavior above, not because we should be invoicing it. With the "Shipped Order" filter on, it won't appear. All 3 of the truly invoiceable orders currently have stock issues that need to be resolved before they can be closed out. The supply chain side is aware.

Long-term fix

Once we have business-customer pricing properly set up in Shopify (without the workaround discount line), this whole problem goes away.

Other Things I Found Along the Way

While digging into the two main observations, three other patterns came up that the team should be aware of.

Finding 1: Orders failing to import into Odoo

There's a section in Odoo called the "Order Queue" — it's where Shopify orders land before being processed. Some of them are getting stuck.

Shipped Order Queue 80 failed lines — stuck on inventory updates Unshipped Order Queue 14 orders not imported at all

Why these are stuck: Both groups are failing for the same general reason — Odoo thinks the inventory isn't there to fulfill them. Some errors come from stock moves that would push a location into negative inventory; others are general low-stock issues.

Translation: 14 orders from Shopify aren't in Odoo at all yet. And 80 more are in Odoo but can't be updated because of stock issues. (Notably: none of these failures are due to missing invoicing rules — they're all inventory-related, which is why we believe the rulebook itself is solid.)

Finding 2: Replacement orders aren't linked to originals

There are 50 orders in Odoo that look like replacement / no-charge orders — all $0, most already invoiced, all created either manually or through our bulk import tool. I've created a saved search in Sales → Orders → Replacement Orders so you can pull them up easily.

The problem

These replacement orders aren't tied back to the original order they're replacing. That makes it hard to answer questions like "did we send a replacement for that complaint?" or to reconcile returns properly. We need a documented return / replacement process.

Finding 3: General data hygiene

The two main issues you raised both come back to the same root cause: we're catching up on history. As we keep tightening up the configuration and clearing the backlog, day-to-day operations should get smoother.

The Road Ahead — What's About to Change

The invoicing picture isn't going to stay where it is today. Here's the direction we're heading so the team knows what to expect.

Retail

Direct to Odoo

Retail customers have more complex workflows. We're bringing them into Odoo directly, bypassing Shopify and ShipStation entirely.

Invoiced from: Odoo

Business

Better Shopify setup

Business customers will get properly configured pricing in Shopify (no more discount-line workaround). This is the only group that will continue to be invoiced from Shopify.

Invoiced from: Shopify

Consumer

Pay before shipping

Consumer customers must pay before we ship. No AR exposure on this group going forward.

Invoiced from: N/A — prepaid

What this means for the "Discount Product" headache

The whole reason the "Shopify Discount Product" exists is to handle business-customer pricing today. Once business customers are properly configured in Shopify, the workaround line goes away — and "To Invoice" in Odoo will finally mean what it sounds like it means.

Going Forward — What Needs to Happen

Here's a clean checklist of what we need to do and what should be on our radar.

Immediate

  1. Mark order #2135 as paid in Shopify, then confirm Odoo's internal invoice status moves to "In Payment".
  2. Find the other stragglers. Pull up Odoo's "To Invoice" list with the Shipped Order filter turned off. Cross-check anything fulfilled in Shopify but stuck in Odoo, and run the "import/update specific orders" operation on each one.
  3. Resolve stock issues on the 3 currently invoiceable orders so they can be closed out.

Short-term

  1. Work through the 80 failed queue lines in the Shipped Order Queue. Each one needs the inventory issue resolved first, then it'll process.
  2. Get the 14 missing orders into Odoo — same root cause, same fix.
  3. Get business-customer pricing handled properly in Shopify. This is the big one — it makes "To Invoice" actually mean "ready to invoice."

Longer-term

  1. Bring retail customers into Odoo directly, bypassing Shopify and ShipStation for their more complex workflows.
  2. Build a return / replacement process that links replacement orders to the original. This will give us proper traceability and clean up the 50 floating $0 orders.

Daily working habit for the team

Quick reference
  • For Terre today, customer invoices come from Shopify. Odoo's "To Invoice" status is internal.
  • In Sales → To Invoice → Orders to Invoice, always turn on the "Shipped Order" filter. That's the real list.
  • Anything in there that has shipped but won't close out → the order probably needs a manual re-import via the Shopify connector. Loop in IT if you're not sure.
  • Remember: ShipStation does not talk to Odoo. If something looks weird, the question is almost always about whether Shopify and Odoo agree on the fulfillment status.
Questions?

Happy to walk through any of this on a screen-share, or dig into specific orders if you find more anomalies. Send them my way.