Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# generated from manifests external_dependencies
bs4
text_unidecode
356 changes: 356 additions & 0 deletions sale_saleor/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
================
Saleor Connector
================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:3121e15b61abc31e2b22374b9a2b21d602f1e17a276a9e4b3a3436917b32691d
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fe--commerce-lightgray.png?logo=github
:target: https://github.com/OCA/e-commerce/tree/18.0/sale_saleor
:alt: OCA/e-commerce
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-sale_saleor
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/e-commerce&target_branch=18.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

Saleor Connector for Odoo
=========================

The ``sale_saleor`` module provides a two-way connector between Odoo and
the Saleor e-commerce platform. It focuses on synchronizing sales
channels, orders, payments, promotions, and vouchers while keeping Odoo
as the central business backend, with explicit flows in both directions:

- From Odoo to Saleor: push sales orders, payment status, product
variant stock levels by warehouse, loyalty programs and vouchers
defined in Odoo.
- From Saleor to Odoo: receive orders, order updates and payment events
via webhooks and reflect them in ``sale.order`` records in Odoo.

Scope
-----

This module does not replace Odoo's standard sales and inventory flows.
Instead, it extends them so that you can:

- Link a single Saleor account to your Odoo database.
- Synchronize Saleor channels with Odoo currencies, countries,
warehouses and locations.
- Exchange order and payment information between Saleor and Odoo.
- Push Odoo loyalty programs and vouchers to Saleor promotions and
vouchers.
- Mark Saleor-origin quotations as abandoned in Odoo based on
per-channel delays.

Key Features
------------

- **Saleor account management (``saleor.account``)**

- Stores the Saleor base URL, credentials and SSL verification
settings.
- Automatically generates webhook target URLs (customer, order, draft
order, payment) from the configured Odoo base URL.
- Manages the Saleor App ID, token, webhook IDs and shared secret used
for HMAC verification.
- Enforces that only one Saleor account can be active at a time.

- **Saleor channels (``saleor.channel``)**

- Maps Saleor channels to Odoo currencies, default countries, shipping
zones, warehouses and locations.
- Synchronizes channels to Saleor, including linked
warehouses/locations that are marked as Saleor warehouses.
- Prevents changing the currency once a channel has been synced to
Saleor (unless explicitly bypassed from context).
- Provides a cron job to mark Saleor quotations as abandoned based on
a channel-specific delay.

- **Sales orders (``sale.order``)**

- Extends sales orders with fields such as ``saleor_order_id``,
``saleor_channel_id`` and detailed Saleor payment state.
- Provides an action to push orders from Odoo to Saleor by creating
and completing a draft order with addresses and order lines.
- Provides an action to mark the related Saleor order as paid from
Odoo.
- Validates required data before syncing (Saleor channel, product
variants, address requirements for specific countries, etc.).

- **Webhooks from Saleor**

- ``/saleor/webhook/order_created_updated`` handles ``ORDER_CREATED``
and ``ORDER_UPDATED`` events:

- Fetches full order details from Saleor via API.
- Skips orders that are explicitly marked as originating from Odoo
in metadata (to avoid loops).
- Creates or updates the corresponding ``sale.order`` in Odoo.

- ``/saleor/webhook/order_payment`` handles ``ORDER_PAID`` and
``ORDER_FULLY_PAID`` events:

- Locates the related ``sale.order`` using ``saleor_order_id``.
- Updates payment-related fields and posts messages on the order.

- **Promotions and loyalty programs (``loyalty.program``)**

- Supports programs of type ``saleor``.
- Builds a minimal promotion payload (type, description, validity
dates) to reduce compatibility issues across Saleor versions.
- Synchronizes programs to Saleor promotions and upserts promotion
rules.

- **Saleor vouchers (``saleor.voucher``)**

- Prepares Saleor voucher payloads including discount type/value, date
and usage limits, countries, channel listings and requirements.
- Collects and sends voucher codes, and adds additional codes after
creation/update when needed.
- Automatically activates voucher codes and ensures a start date is
set.

- **Stock and variants**

- Provides a job to update Saleor variant stock quantities by
warehouse.

**Table of contents**

.. contents::
:local:

Configuration
=============

Initial Configuration
---------------------

Configure the Saleor account

::


1. Open the menu that manages ``saleor.account`` records.
2. Create a new record with at least:

* **Name**: a descriptive name (for example, ``Saleor Production``).
* **Saleor Base URL**: the base URL of the Saleor API.
* **Email / Password**: credentials of a Saleor staff user to obtain JWT
tokens (or an app token if supported by your setup).
* **Odoo Base URL**: the public URL of the Odoo instance.

3. Enable the **Active** flag on the account that should be used in
production. Only one Saleor account can be active at a time.

Once saved, the module will compute webhook target URLs (customer, order,
draft order, payment) from the Odoo base URL. You should configure
corresponding webhooks in Saleor using these URLs and the shared secret.

Configure Saleor channels
~~~~~~~~~~~~~~~~~~~~~~~~~

1. Open the ``saleor.channel`` menu.
2. Create a channel and configure:

* **Name** and **Slug** to match the channel in Saleor.
* **Status** set to *Active* when the channel is ready to sync.
* **Currency** and **Default Country** to match Saleor settings.
* **Shipping Zones** using corresponding Saleor shipping zones.
* **Warehouses / Locations** that are marked as Saleor warehouses and have a
remote Saleor warehouse ID.

3. Save the channel. When a channel is created in *Active* status or key
fields are changed, the connector will automatically synchronize it to
Saleor.

.. warning::

Once a channel has been synchronized to Saleor, its currency cannot be
changed unless explicitly bypassed via technical context.

Configure promotions (optional)

- For loyalty programs and promotions based on ``loyalty.program``:

- Create programs with ``program_type = 'saleor'``.
- Configure the discount type (catalogue/order), description, date
range, rules and channels.
- Use the *Saleor Promotion Sync* action to push programs to Saleor
promotions. Batch synchronization is supported.

Configure vouchers (optional)

::


* For vouchers based on ``saleor.voucher``:

* Define the voucher type and value, limits, minimum requirements, countries
and channel listings.
* Add one or more voucher codes; the module will automatically activate
codes and set a start date if missing.
* Use the *Saleor Sync* action on vouchers to push them to Saleor.

Usage
=====

Requirements
------------

- A running Saleor instance reachable from the Odoo server.
- An Odoo URL that Saleor can reach in order to call webhooks.

Main Flows
----------

Pushing orders from Odoo to Saleor

::


This flow is used when orders are created in Odoo but should also exist in
Saleor:

1. Create a ``sale.order`` in Odoo as usual.
2. Set the **Saleor Channel** field to a synced ``saleor.channel``.
3. Ensure all products that must be sent to Saleor have a
``saleor_variant_id``.
4. Use the *Sync to Saleor* action on the order.

The connector will:

* Build the order payload including billing/shipping addresses, order lines
(variant and quantity) and customer identity (user or email).
* Create or update a draft order in Saleor, apply the shipping method and
complete the order.
* Store the ``saleor_order_id`` on the Odoo order and post links to the Saleor
dashboard in the chatter.

You can also use the *Mark paid in Saleor* action to notify Saleor that the
order has been paid in Odoo (for example, offline payments).

Note:
For customers in certain countries (for example, US/CA), a state/province
may be required. The connector validates this and raises an error if needed
information is missing.

Receiving orders and updates from Saleor (webhooks)

When Saleor is the main source of order creation:

1. In Saleor, configure webhooks:

- **Order created/updated** →
``/saleor/webhook/order_created_updated``.
- **Order paid / fully paid** → ``/saleor/webhook/order_payment``.

2. Use the same App/account and secret that are stored on the
``saleor.account`` in Odoo.

When events occur:

- ``ORDER_CREATED`` / ``ORDER_UPDATED``:

- Odoo fetches the full order from Saleor.
- The connector creates or updates a ``sale.order`` in Odoo.

- ``ORDER_PAID`` / ``ORDER_FULLY_PAID``:

- The connector locates the related ``sale.order`` using
``saleor_order_id``.
- Payment-related fields are updated and a message is posted in the
chatter.

Orders explicitly marked as originating from Odoo (metadata
``odoo_origin``) are ignored by the webhook flow to avoid loops.

Abandoned cart / quotation handling

::


The cron method ``cron_mark_abandoned_saleor_orders`` periodically:

* Finds Saleor-origin quotations (with ``saleor_order_id``) still in
``draft``/``sent`` state and not yet marked as abandoned.
* Compares their age with the ``abandoned_cart_delay_hours`` configured on the
related ``saleor.channel``.
* Marks qualifying quotations as abandoned and posts an explanatory message on
each order.

Stock Synchronization
---------------------

The connector exposes a job to update Saleor product variant stock quantities
by warehouse (``job_variant_stock_update``) to push stock changes to Saleor.

Best Practices
--------------

* Keep exactly one ``saleor.account`` active to avoid ambiguity when
processing webhooks.
* Ensure ``odoo_base_url`` points to the external URL that Saleor can reach
and configure SSL verification appropriately.
* Avoid changing channel currencies after initial synchronization.
* Regularly verify that product variants, warehouses and locations are synced
and have their corresponding Saleor IDs.
* Monitor logs and queue jobs for synchronization errors and fix data issues
early.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/e-commerce/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/e-commerce/issues/new?body=module:%20sale_saleor%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* Kencove

Contributors
------------

- `Trobz <https://trobz.com/>`__:

- Khoi (Kien Kim) <khoikk@trobz.com>

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/e-commerce <https://github.com/OCA/e-commerce/tree/18.0/sale_saleor>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
7 changes: 7 additions & 0 deletions sale_saleor/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright 2025 Kencove (https://www.kencove.com/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from . import models
from . import utils
from . import controllers
from . import wizard
Loading