Odoo imports sales orders from a spreadsheet, and it can read a purchase order XML sent by another Odoo database.
PDF, JPG, PNG, BMP, HEIC, TIFF
Submit your purchase orders
Drop documents here, or choose a file
Up to 50 files per batch
Uploading...
Odoo imports sales orders from a spreadsheet, and it can read a purchase order XML sent by another Odoo database. It will not read the PDF your customer emailed. Upload that PO here and get the customer PO number, the ship-to and every line with product, quantity, unit and price, laid out the way Import records expects.
Odoo is good at importing a clean file. The time goes into producing that file from purchase orders that each customer formats their own way.
The Upload button on the Quotations dashboard reads UBL XML, the format Odoo exports. A PO printed from SAP, NetSuite or a customer portal is a plain PDF, and there is nothing in it for Odoo to parse.
Odoo document digitization is built for vendor bills and, less commonly, customer invoices and credit notes. Customer purchase orders are not on the list.
Customers order by their own codes. Odoo matches an imported product by name, internal reference or External ID, so every buyer code needs a lookup before the file will load.
Odoo says so plainly in its import documentation. A file with a shifted column creates wrong quotations that someone then cancels by hand.
Upload the purchase order your customer sent. The AI reads the header and every line and returns structured data you can paste into an Odoo import template, so creating the quotation becomes a mapping step instead of a typing job.
No per-customer template. Works on digital PDFs, scans and photographed pages from any buyer system.
A 40-line restocking order comes back as 40 rows with part number, description, quantity, unit of measure and unit price.
Header fields on the first row and line fields below, which is exactly how Odoo reads an order with several Order Lines.
The buyer PO number sits in its own column, so it maps to Customer Reference and never to your own SO number.
Odoo gives you three ways to create sales orders without typing them. The first is Import records: open Sales, go to the Orders list, open the gear or Favorites menu, and choose Import records. Odoo accepts CSV, XLS, XLSX and ODS files, lets you map each column to a field, and has a Test button that checks the file before anything is written. Its own documentation is blunt about the stakes: imports are permanent and cannot be undone.
The second is the purchase-to-sales EDI flow. When your customer also runs Odoo, their purchase order can be exported as a UBL XML file, and you upload it, or drag it, onto the Quotations dashboard. Odoo then builds a sales order with the customer and the lines filled in. The third is the external API, where an integration creates a sale.order record and its order_line entries directly.
Notice what all three assume: that the order already exists as structured data. Most customer POs in the United States do not. They arrive as a PDF from someone else's ERP, a portal download or a scanned fax. That document is the gap this page fills. You upload it and get the rows the import screen or the API needs.
An Odoo sales order is one record with many Order Lines, so the import file is not one flat row per order. The first row carries the order fields (Customer, Customer Reference, Order Date, Delivery Address) together with the first line (Order Lines/Product, Order Lines/Quantity, Order Lines/Unit Price). Every following line for the same order goes on its own row with the order columns left blank. A new value in the Customer column starts the next order.
That layout trips people up because a spreadsheet exported from somewhere else repeats the header on every line, and Odoo then creates one order per line. The extraction returns header and lines separately, so building the Odoo layout is a paste, not a rebuild.
The buyer's PO number goes in Customer Reference (the client_order_ref field on the sales order). Your own number, such as S00042, comes from the Odoo sequence, so leave it out of the file. Keeping the customer reference populated is what lets your team find the order when the buyer calls, and it prints on the delivery slip and invoice.
Odoo matches a product in an import by its name, by its internal reference, or by External ID. Standard Odoo keeps vendor product codes on the purchase side but has no built-in table of customer part numbers, so the lookup from a buyer code to your product has to happen before the file loads. The extraction keeps the part number exactly as printed, next to the description, so you can map it once per customer in the spreadsheet and reuse that mapping on every order that account sends. Unknown codes show up as a blank cell, not as a failed import.
If a weekend leaves 30 purchase orders in the shared inbox, run them through bulk purchase order upload, up to 50 files in one pass, and get one consistent file back. Long orders are covered by purchase order line item extraction, which returns every row rather than a summary.
If part of the business runs on another ERP, the pattern is the same with different field names. See Business Central sales order import, NetSuite sales order import and QuickBooks sales order import. For the buying side of Odoo, where you are the one issuing the purchase order, use purchase order to Odoo instead.
What comes off the customer document and where it lands in an Odoo import file. Labels follow the standard Sales app; technical names are shown for API users.
| Odoo import column | Technical field | Where it comes from | Notes |
|---|---|---|---|
| Customer | partner_id | The buying company, matched to an existing contact. | Match by name or External ID |
| Customer Reference | client_order_ref | The purchase order number printed on the customer PO. | Prints on delivery and invoice |
| Order Date | date_order | The PO date on the document. | Use a date Odoo can parse |
| Delivery Address | partner_shipping_id | The ship-to block on the PO. | Contact must exist |
| Delivery Date | commitment_date | The need-by date the buyer asked for. | Optional |
| Payment Terms | payment_term_id | Terms printed on the PO, checked against your agreement. | Usually from the customer |
| Order Lines/Product | order_line/product_id | The customer part number, mapped to your product. | Product must exist |
| Order Lines/Description | order_line/name | The line description from the PO. | Defaults from the product |
| Order Lines/Quantity | order_line/product_uom_qty | Ordered quantity on each line. | Per line |
| Order Lines/Unit Price | order_line/price_unit | The price the buyer printed. | Pricelist can set it instead |
Four steps from the customer attachment to a quotation in Odoo.
Drop in the PDF, the scan or the email attachment. Up to 50 files per bulk upload, with no per-customer setup.
Tip: Portal downloads and forwarded attachments work the same way.
Check the header and lines on screen, then map buyer part numbers to your products and the customer name to the Odoo contact.
Tip: Keep the mapping sheet; the same account sends the same codes.
Take Excel or CSV with the order fields on the first row and each line below, or pull JSON through the API for an integration.
Tip: Leave the order columns blank on continuation rows.
In Sales, open Orders, choose Import records, map the columns, press Test, then Import. Review the new quotations and confirm them.
Tip: Imports cannot be undone, so test a single order first.
Open the Sales app, go to Orders, and choose Import records from the gear or Favorites menu. Upload a CSV, XLS, XLSX or ODS file, map each column to a field, press Test to check it, then Import. Put the order fields on the first row and each extra line on its own row with the order columns blank.
Only when the PDF comes from another Odoo database as UBL XML, or embeds that XML. Upload it on the Quotations dashboard and Odoo fills in the customer and lines. A plain PDF from another ERP has no data layer to read, so it needs to be extracted into rows first.
No. Odoo documents digitization mainly for vendor bills and refunds, and less commonly for customer invoices and credit notes. Customer purchase orders are not covered, which is why order desks extract them before importing.
In Customer Reference, the client_order_ref field. Your own sales order number comes from the Odoo sequence, so leave it out of the import file. The customer reference prints on the delivery slip and invoice and makes the order easy to find later.
Use one row per line. The first row holds the order fields plus the first line, using columns like Order Lines/Product and Order Lines/Quantity. Following rows fill only the Order Lines columns and leave the order columns empty, so Odoo attaches them to the same order.
Because the order columns are repeated on every row. Odoo treats a filled Customer cell as the start of a new order. Clear the order columns on continuation rows, or group the lines under one header row, and test again before importing.
No. Odoo states that imports are permanent and cannot be undone. Use the Test button, import one order first, and keep the source file so you can find and cancel anything that went wrong.
Match them before importing. Odoo resolves a product by name, internal reference or External ID, and standard Odoo has no customer part number table. Keep a per-customer mapping sheet from buyer code to your internal reference and apply it to the extracted rows.
No. PurchaseOrders reads the customer purchase order and returns structured data as Excel, CSV or JSON. It does not install in Odoo and does not create, confirm or deliver orders. You load the rows through Import records, the API or your own integration.
The same workflow on Zoho Inventory.
The buying side: POs you issue.
The same workflow on Business Central.
The same workflow on NetSuite.
The same workflow on QuickBooks.
The full order entry workflow.
Choose your plan