Shopify Store Management
Shopify Store Management connects a Shopify store to Odoo. This page is the installation and configuration guide for the module you downloaded from your ECOSIRE dashboard. Everything below describes the shopify_store_management module as it ships today.
| Technical name | shopify_store_management |
| Odoo versions | 17.0, 18.0, 19.0 (Community or Enterprise) |
| Current shipped version | 17.0 → 17.0.2.2.2, 18.0 → 18.0.2.2.2, 19.0 → 19.0.2.2.2 |
| Price | $499 USD — one-time, per Odoo version |
| Odoo module licence | OPL-1 |
| Category | Connector |
Requirements
| Requirement | Detail |
|---|---|
| Odoo | 17.0, 18.0 or 19.0, Community or Enterprise. Self-hosted or Odoo.sh — Odoo Online (SaaS) cannot install third-party modules |
| Odoo apps | base, sale_management, stock, account, delivery, mail, web, portal, product, contacts, digest — Odoo installs any that are missing |
| Python packages | requests |
| Platform account | A Shopify seller/partner account with API access |
Install the Python packages into the same interpreter that runs Odoo:
sudo -u odoo pip install requests
Installation
1. Download the ZIP for your Odoo version
Sign in at ecosire.com and open your dashboard downloads. The archive for each Odoo major version is published separately, so pick the one matching the Odoo series you run.
2. Extract into your addons path
unzip shopify_store_management_v19_*.zip -d /opt/odoo/addons/
ls /opt/odoo/addons/shopify_store_management/__manifest__.py # sanity check
The archive contains a single top-level shopify_store_management/ directory. If your ls check fails, the module folder ended up one level too deep — move it up so __manifest__.py sits directly inside shopify_store_management/.
3. Restart Odoo and install
sudo systemctl restart odoo
- Go to Apps and click Update Apps List (developer mode must be on).
- Search for Shopify Store Management and click Install.
- Odoo pulls in the Odoo apps listed above automatically.
When the install finishes, a Shopify menu appears in the main Odoo app switcher.
Configuration
Connect to Shopify
Open Shopify → Configuration → Instances and create a record (model shopify.instance). The connection fields are:
| Label | Technical name | Required | Values |
|---|---|---|---|
| — | shop_url | Yes | Text |
| — | api_key | No | Text |
| — | password | No | Text |
| — | shared_secret | No | Text |
| — | access_token | No | Text |
| API Version | api_version | Yes | Selection |
Where the Label column shows —, the module does not set an explicit label and Odoo derives one from the technical name, so the wording on screen may differ slightly. The technical name is the reliable identifier.
Create a custom app in your Shopify admin and copy the Admin API Access Token. Shop URL is your *.myshopify.com domain. API Version is a dropdown on the instance — pin it to a version Shopify still supports.
The same record carries 4 behaviour checkboxes — auto_validate_inventory, auto_confirm_order, auto_create_invoice, auto_validate_invoice. They gate what the connector is allowed to do automatically once it is connected. Leave anything you are not ready for switched off, and turn them on one at a time.
Credentials are issued from the Shopify admin (custom app) or Shopify Partners — see shopify.dev/docs. The connector talks to your own shop domain — https://<shop>.myshopify.com/admin.
When the fields are filled in, click Test Connection. The record's status moves to connected only when the platform answers successfully — do not run a first import until it does.
Public endpoints: the OAuth install and callback URLs
Filling in an Admin API access token by hand (above) is one way to connect. The other is Shopify's OAuth flow, and it needs two publicly reachable URLs on your Odoo instance. These are the only endpoints on this module served without an Odoo login.
| Endpoint | Method | Auth | Set it in the Shopify app as |
|---|---|---|---|
/shopify/install | GET | public (no Odoo session) | App URL — where Shopify sends the merchant to start or reopen the app |
/shopify/callback | GET | public (no Odoo session) | Allowed redirection URL — where Shopify returns after the merchant approves |
Use your real host, e.g. https://erp.example.com/shopify/install and https://erp.example.com/shopify/callback. The connector builds the redirect_uri it sends to Shopify from the web.base.url system parameter, so that value must already be your real HTTPS URL: turn on developer mode, open Settings → Technical → System Parameters, and set web.base.url to the address your users browse to. If it is wrong, Shopify rejects the redirect as a mismatch.
Before you start the flow, the shopify.instance record must exist and carry API key (api_key) and Shared secret (shared_secret) from your Shopify app, and its Shop URL must be the *.myshopify.com domain. If the instance is missing those, /shopify/install simply sends you to the Instances form in Odoo instead of starting the flow.
What each endpoint does:
/shopify/installvalidates that theshopparameter is a real<name>.myshopify.comdomain, finds the matching instance, verifies Shopify's request HMAC when one is present, mints a one-time randomstatenonce onto the instance, and redirects the merchant tohttps://<shop>/admin/oauth/authorizewith the connector's requested scopes./shopify/callbackis the return leg. It re-validates the shop domain, verifies the HMAC against your shared secret, checks the returnedstatematches the nonce it issued (so a replayed or forged callback is refused), then exchanges the authorization code for a permanent access token server-side. On success it stores the token and granted scopes on the instance, clears the nonce, sets the instance to connected, and drops you on the instance form in Odoo. Any failure renders a plain error page with a link back to Odoo — it never silently half-connects.
The scopes requested are read/write on products, orders, customers, inventory, fulfilments and shipping, plus read_all_orders and read_locations. Your Shopify app must be configured to grant them, or the authorize step will fail.
The first successful OAuth connection sets Order Import Cutoff on the instance to that moment, if it is not already set. Historic orders placed before you connected are deliberately not imported — only orders placed afterwards sync into Odoo. Clear or backdate that field yourself if you do want the history.
Scheduled actions
The module installs 17 scheduled actions (Settings → Technical → Scheduled Actions):
| Scheduled action | Runs every | Enabled on install |
|---|---|---|
| Shopify: Sync Products | 30 minutes | Yes |
| Shopify: Sync Orders | 15 minutes | Yes |
| Shopify: Sync Customers | 60 minutes | Yes |
| Shopify: Sync Inventory | 10 minutes | Yes |
| Shopify: Process Queue Jobs | 5 minutes | Yes |
| Shopify: Import Payout Reports | 6 hours | Yes |
| Shopify: Import Refunds | 30 minutes | Yes |
| Shopify: Auto Risk Detection | 30 minutes | Yes |
| Shopify: Generate Analytics | 4 hours | Yes |
| Shopify: Webhook Health Check | 60 minutes | Yes |
| Shopify: Cleanup Old Logs | 24 hours | Yes |
| Shopify: Process Workflows | 10 minutes | Yes |
| Shopify: Daily Summary Report | 1 days | Yes |
| Shopify: Push Inventory to Shopify | 1 hours | Yes |
| Shopify: Push Product Changes to Shopify | 1 hours | Yes |
| Shopify: Auto-Publish New Products to Shopify | 1 hours | Yes |
| Shopify: Auto Delist / Relist by Stock | 15 minutes | Yes |
The four Odoo → Shopify actions run on a schedule but do nothing until the matching per-instance toggle is switched on, so a fresh install never writes to a live store by itself.
Intervals above are the shipped defaults. Adjust them to your volume — but be aware that the platform, not Odoo, sets the API rate limits, and shortening a sync interval is the usual cause of throttling errors in the logs.
Using the module
The Shopify menu is laid out as:
- Shopify → Dashboard
- Shopify → Orders
- Shopify → Refunds
- Shopify → Products
- Shopify → Customers
- Shopify → Payouts
- Shopify → Analytics
- Shopify → Operations — Run Operations, Queue Jobs, Logs
- Shopify → Configuration — Instances, Locations, Payment Gateways, Scheduled Actions, Webhooks, Webhook Receipts
A normal first run is:
- Test Connection until the instance reads connected.
- Review the mapping records (categories, order statuses, payment and shipping methods) so imported data lands on the right Odoo records.
- Run a small import first — restrict it by date or by a handful of products — and check the results before letting the scheduled actions take over.
- Watch the Logs view during the first full sync. Every sync writes a log line; failures are recorded there rather than raised at the user.
Module-specific notes
- API Version is a required dropdown. Shopify retires API versions on a schedule — if calls start failing after months of working, check that the pinned version is still supported.
- Shop URL must be the
*.myshopify.comdomain, not a custom storefront domain. - Use the Authorize button for the OAuth flow, or paste an Admin API access token from a custom app created in your Shopify admin.
Troubleshooting
Syncing
| Symptom | Cause and fix |
|---|---|
| Test Connection fails | Re-check every required field in the table above. Most failures are a mistyped secret, or credentials created for the sandbox while the connector points at production (or vice-versa). |
| Nothing syncs even though the connection is fine | The scheduled actions are disabled at the Odoo level, or Odoo's cron worker is not running. Check Settings → Technical → Scheduled Actions and that --max-cron-threads is greater than zero. |
| Sync starts then stops part-way | Read the Logs view for that run. Rate limiting and rejected field values are the two common causes; both are logged with the platform's own error text. |
| Records import but map to the wrong Odoo values | Fix the mapping records under the module's configuration, then re-run the import. |
| Duplicated products or customers | Run the initial import once. If a first attempt half-finished, check the existing records before re-running rather than importing on top. |
The requests library is required | requests is missing from Odoo's Python environment. Install it into the interpreter that runs Odoo. |
Version history
| Odoo version | Version you download today |
|---|---|
| 17.0 | 17.0.2.2.2 |
| 18.0 | 18.0.2.2.2 |
| 19.0 | 19.0.2.2.2 |
ECOSIRE module versions are <odoo major>.<module major>.<minor>.<patch>, so 19.0.2.2.2 is the Odoo 19 build of module version 2.2.2. Your installed version is shown in Apps.
What changed in 2.2.2 (19.0.2.2.2, 25 Sep 2026)
- Product image import now works. The image downloader stored the raw bytes of the downloaded picture instead of the text form Odoo 19 requires, so every product in a run with Import Product Images switched on was rejected and rolled back silently — the setting appeared to work and the catalogue arrived without pictures.
- Payouts in a foreign currency no longer assume a 1:1 exchange rate. When no exchange rate was recorded, the payout's base-currency amount silently equalled its gross amount. A payout in that state now flags Exchange Rate Missing and leaves the base-currency amount at zero until a rate is recorded, so a wrong figure is never posted to your books.
- The Shopify order number is now stored. The order number your customers and your team quote (
#1001) is recorded on every imported order; the field was displayed and searchable but was never filled in. - A new Shopify page on the sales order shows which store an order came from, the Shopify order number, and the payment and fulfilment status Shopify reports.
What changed in 2.2.1 (19.0.2.2.1, 25 Sep 2026)
- Gift-card orders no longer create a duplicate product. A Shopify gift-card line carries no variant or product id, so it used to fall through to the create-a-new-product path and one new "Gift Card" product accumulated per gift card sold. Gift-card lines now map to the gift-card product configured on the instance.
- Three calls now go through the module's own API client — setting a smart-collection order, completing a draft order and bulk-setting customer addresses. Calling the HTTP library directly meant a failure there was not logged or raised the way every other call's failure is.
- The unused
Signature Requiredshipping-method flag was removed: it was declared, shown on no screen and read by no code. - The App Store listing page was regenerated from the current design template.
What changed in 2.2.0 (19.0.2.2.0, 17 Sep 2026)
- Complete Admin API surface — the connector reaches every callable operation of the Shopify Admin REST reference, one client method each, run through a store-operations service that wraps every per-record loop in a savepoint and leaves a sync-log receipt. The 20 routes the reference marks withdrawn are deliberately not addressed.
- Operations Center with 14 new store operations, including Store Snapshot, Import Draft Orders, Abandoned Checkouts Report, Import Discounts & Codes, Import Payment Disputes, Import Tender Transactions, Import Inventory Item Costs, Export Product Costs, Import Fulfillment Services, Import Carrier Services, Import Marketing Events, Import Store Events, Import Shipping Countries and Check Deprecated API Calls.
- New buttons on the record forms — order: Import Transactions, Capture Payment, Preview Refund, Hold / Release Fulfillment, Reopen on Shopify. Customer: Import Addresses, Find on Shopify, Fetch Orders, Send Account Invite. Instance: Store Snapshot, Payments Balance, Deprecated API Calls.
- Quotation → Shopify draft order (Send to Shopify as Draft Order on a draft or sent quotation) and Delivery → Update Shopify Tracking.
- Metafield sync, owner-scoped to products, orders and customers, writing the Odoo internal reference.
What changed in 2.1.0 (19.0.2.1.0, 5 Sep 2026)
- Payout finance mapping corrected — fees are derived from the Shopify Payments payout summary, the net is the payout amount, and the documented
canceledstatus no longer crashes the status selection. - Balance transactions accept every documented type (
charge,refund,dispute,reserve,adjustment,credit,debit,payout,payout_failure,payout_cancellation); values outside the list import as "Other" with the raw value preserved. - Payouts, balance transactions, collections, locations and gateway-discovery orders follow Link-header pagination — stores with more than one page are no longer silently truncated.
- Payout bookkeeping fixed end to end: the statement links (
shopify_payout_id,shopify_transaction_id) are declared, so bank statements and reconciliation work; a payout without a bank journal now names the setting to fix instead of raising a raw database error; statement lines are booked in the payout's own journal with a readable label; "Skip Import" actually skips. - Company isolation hardened — the OAuth callback binds the returned state to one exact company instance, customer matching never crosses companies nor clears
company_id, and every Shopify model carries a company record rule. - Fabricated carrier integrations removed — no carrier API is integrated, so the generic carrier probe, the shipping-label generator and the credentialed tracking lookup are gone.