Skip to content

Instantly share code, notes, and snippets.

@yelizariev
Last active May 18, 2024 19:13
Show Gist options
  • Save yelizariev/900b66fcc5cffc0cd92b04bc1f8c2ef4 to your computer and use it in GitHub Desktop.
Save yelizariev/900b66fcc5cffc0cd92b04bc1f8c2ef4 to your computer and use it in GitHub Desktop.
Woo ✨ Commerce

¡Welcome!

image

You are reading the developer documentation for the WooCommerce Odoo Connector.

Steps:

  1. Install Sync 🪬 Studio.
  2. Open Sync 🪬 Studio, click [New], paste the URL of this gist, then click [Import].
  3. Follow the documentation.

WooCommerce Sandbox

To install local WooCommerce add following specification to your docker-compose.yml::

services:

  # ...

  woo_db:
    image: mysql:5.7
    volumes:
        - woo_db:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: pass
      MYSQL_DATABASE: woo
      MYSQL_USER: woo
      MYSQL_PASSWORD: woo

  woo:
    image: wordpress:latest
    depends_on:
      - woo_db
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_HOST: woo_db:3306
      WORDPRESS_DB_USER: woo
      WORDPRESS_DB_PASSWORD: woo
      WORDPRESS_DB_NAME: woo
    volumes:
      - woo:/var/www/html/wp-content

  woo_ssl:
    image: foxylion/nginx-self-signed-https
    depends_on:
      - woo
    environment:
      REMOTE_URL: http://woo:80

volumes:
  woo:
  woo_db:

Open http://localhost:8080/wp-admin/ and follow setup instructions

Navigate to Plugins >> Add New >> search for "woocommerce", click [Install Now] and then [Activate].

Add some products.

Open Odoo and configure the sync project settings:

  • API_URL to https://woo_ssl.
  • API_VERIFY_SSL to 0

image

WooCommerce Connector

This project synchronizes Odoo and WooCommerce products.

For the initial setup, navigate to the SECRETS.🔐 tab.

If you need to synchronizes other models,
you can check the Sync 🪬 Studio documentation, contact us by email at info@odoomagic.com,
or ask questions in our Telegram ✈️ Group.

How it Works

Sync 🪬 Studio updates records in two directions: from Odoo to WooCommerce (Woo), and from WooCommerce to Odoo. Whenever an update occurs, if the target system does not have the product, it will be created and linked to the original product. If the product is already linked, it will simply be updated.

There are three ways to make updates:

  • Manual: Via the [Magic ✨] button.
  • Automatic on updates at Odoo: For example, when a product is created in Odoo, it will also be created in WooCommerce. Note that this works in one direction only (from Odoo to WooCommerce).
  • Cron updates: These are disabled by default. To activate, open the corresponding 🦋 task and navigate to the Cron tab.
from woocommerce import API
log_transmission = MAGIC.log_transmission
log = MAGIC.log
if not all(
[SECRETS.WOO_URL, PARAMS.API_VERSION, SECRETS.CONSUMER_KEY, SECRETS.CONSUMER_SECRET]
):
raise MAGIC.UserError("WooCommerce API Credentials are not set")
wcapi = API(
url=SECRETS.WOO_URL,
consumer_key=SECRETS.CONSUMER_KEY,
consumer_secret=SECRETS.CONSUMER_SECRET,
wp_api=True,
version=PARAMS.API_VERSION,
verify_ssl=PARAMS.API_VERIFY_SSL != "0",
)
def wcapi_request(method, endpoint, data=None, **kwargs):
log_transmission(
"WooCommerce",
"{} {}\n{}\n{}".format(method.upper(), endpoint, data, kwargs),
)
method = method.lower()
if method in {"post", "put"}:
r = MAGIC.getattr(wcapi, method)(endpoint, data, **kwargs)
elif method in {"get", "delete", "options"}:
r = MAGIC.getattr(wcapi, method)(endpoint, **kwargs)
else:
raise UserError(_("Unknown method: %s"), method)
log("RESPONSE: {}\n{}".format(r.status_code, r.text))
return r.json()
# CORE.*
export(wcapi_request)
PRODUCT_REL="woo_product"
def product_x2odoo(data):
# TODO: images
# TODO: price
return {
"name": data['name'],
"description": data['permalink'],
}
def product_odoo2x(odoo):
# TODO: images
# TODO: price
return {
"name": odoo.name
}
def x_product2ref(data):
return data["id"]
def x_product_get_all():
# TODO: fetch all pages
return CORE.wcapi_request("get", "products", params={"per_page": 100})
def x_product_create(odoo):
data = product_odoo2x(odoo)
res = CORE.wcapi_request("post", "products", data)
return res['id']
def x_product_update(ref, odoo):
data = product_odoo2x(odoo)
res = CORE.wcapi_request("put", "products/%s" % ref, data)
return ref
def odoo_product_get_all(to_create=False, to_update=False):
all_records = MAGIC.env["product.product"].search([])
if to_create and to_update:
return all_records
linked = all_records.search_links(PRODUCT_REL).mapped(lambda link: link.odoo)
if to_create:
return all_records - linked
if to_update:
return linked
def odoo_product_create(data):
vals = product_x2odoo(data)
MAGIC.log("env[\"product.product\"].create(%s)" % vals, MAGIC.LOG_DEBUG)
return MAGIC.env["product.product"].with_context(sync_x2odoo=True).create(vals)
def odoo_product_update(odoo, data):
vals = product_x2odoo(data)
MAGIC.log("%s.write(%s)" % (odoo, vals), MAGIC.LOG_DEBUG)
return odoo.with_context(sync_x2odoo=True).write(vals)
PRODUCT_SYNC = {
"relation": PRODUCT_REL,
"x": {
"get_ref": x_product2ref,
"create": x_product_create,
"update": x_product_update,
},
"odoo": {
"create": odoo_product_create,
"update": odoo_product_update,
}
}
def sync_products_x2odoo(data=None, create=False, update=False):
if data is None:
data = x_product_get_all()
return MAGIC.sync_x2odoo(data, PRODUCT_SYNC, create=create, update=update)
def sync_products_odoo2x(records=None, create=False, update=False):
if records is None:
records = odoo_product_get_all(to_create=create, to_update=update)
return MAGIC.sync_odoo2x(records, PRODUCT_SYNC, create=create, update=update)
# LIB.*
export(sync_products_odoo2x, sync_products_x2odoo)

对祖先智慧的敬意

Permission is hereby granted, free of charge, to any person obtaining a copy of this 紫色💃饺子 and associated documentation files (the "紫色💃饺子"), to deal in the 紫色💃饺子 without restriction, including without limitation the rights to use✨, copy✨, modify✨, merge✨, publish✨, distribute✨, sublicense✨, and/or sell✨ copies of the 紫色💃饺子, and to permit persons to whom the 紫色💃饺子 is furnished to do so, subject to the following conditions:

每位古智慧的接受者都应向其致敬,并在所有智慧的副本中保留许可通知。

永恒之门:年轻的武士在攀爬和研究长城上的铭文中领悟祖先智慧

THE 紫色💃饺子 IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 紫色💃饺子 OR THE USE OR OTHER DEALINGS IN THE 紫色💃饺子.

API_VERIFY_SSL API_VERSION
1
wc/v3

API_VERIFY_SSL

Set to 0 when you need to test with self-signed certificates.

API_VERSION

Refer to the docs for details.

WOO_URL CONSUMER_KEY CONSUMER_SECRET

Quick ☀️ Start

Follow the official docs to obtain REST API credentials.

Additionally, you need to activate Pretty permalinks in the WooCommerce Admin Dashboard: Settings > Permalinks. For example, in WordPress v5.6, you can select the Post name option.

WOO_URL

For the WOO_URL, simply use the URL of the WooCommerce website, ensuring it has an https prefix.

Python dependencies

And one more thing, you need to install Python dependencies:

pip install woocommerce

image

Once you're done, you're ready to open the task 🦋 "Setup" and click the Magic ✨ Button.

Troubleshooting

  • Enable Odoo 🙈 Debug mode.
  • Go to the menu [[ Settings ]] >> Technical >> Parameters >> System Parameters.
  • Check that the web.base.url parameter is correctly configured, ensuring it's not set to localhost and includes the https prefix. The URL should be accessible via the internet. If you're using a local Odoo instance, you can still set up an HTTPS connection. For details, see the sync/README.rst file in the Sync 🪬 Studio repository.
  • When running Odoo, use --db-filter=^YOUR_DATABASE_NAME$ or ensure that you have only one database.
  • In wordpress, in menu Settings > General Settings check that WordPress Address (URL) and Site Address (URL) have address http://localhost:80
  • Be sure that cron in WordPress is working. You can install plugin https://wordpress.org/plugins/wp-crontrol/ to get more information about cron
  • To get webhook logs in Wordpress: open menu WooCommerce >> Status >> Logs, select log file and click [View]
  • Remember that webhooks in Wordpress works via cron, so you may need to wait up to 1 minute before webhook is fired
  • Verify that the Sync Project isn't archived.
TEMPLATE_PLACE_HOLDER
multi line value

The template parameters are currently not in use.

However, you can check the 🔧 Settings 🌹 tab.

"""
TITLE: "Products: push from Odoo to WooCommerce"
MAGIC_BUTTON: PRODUCTS_ODOO2WOO
DB_TRIGGERS:
- name: ODOO_PRODUCTS_CREATE
model: product.product
trigger: on_create_or_write
CRON:
- name: CRON
interval_number: 1
interval_type: days
"""
def handle_button():
LIB.sync_products_odoo2x(create=True, update=True)
def handle_db(records):
# TODO: ignore event if it happened during woo2odoo upgrade (e.g. via temporary System Parameter)
return LIB.sync_products_odoo2x(records, create=True, update=True)
def handle_cron():
handle_button()
"""
TITLE: "Products: fetch from WooCommerce to Odoo"
MAGIC_BUTTON: CREATE_PRODUCTS_WOO2ODOO
CRON:
- name: CRON_PRODUCTS_WOO2ODOO
interval_number: 1
interval_type: days
WEBHOOK:
- name: WOO_PRODUCT_CREATED
webhook_type: json
- name: WOO_PRODUCT_UPDATED
webhook_type: json
- name: WOO_PRODUCT_DELETED
webhook_type: json
"""
def handle_button():
LIB.sync_products_x2odoo(create=True, update=True)
def handle_cron():
handle_button()
def handle_webhook(httprequest):
data = MAGIC.json.loads(httprequest.data.decode())
MAGIC.log("Woo payload:\n{}".format(MAGIC.json.dumps(data, indent=4, sort_keys=True)))
if trigger == "WOO_PRODUCT_CREATED":
LIB.sync_products_x2odoo([data], PRODUCT_SYNC, create=True)
elif trigger == "WOO_PRODUCT_UPDATED":
LIB.sync_products_x2odoo([data], PRODUCT_SYNC, create=True, update=True)
elif trigger == "WOO_PRODUCT_DELETED":
# TODO
pass
"""
TITLE: "Setup"
MAGIC_BUTTON: SETUP_WOO_WEBHOOKS
"""
def handle_button():
for topic, webhook in (
("product.created", WEBHOOKS.WOO_PRODUCT_CREATED),
("product.updated", WEBHOOKS.WOO_PRODUCT_UPDATED),
("product.deleted", WEBHOOKS.WOO_PRODUCT_DELETED)
):
data = {
"name": topic,
"topic": topic,
"delivery_url": webhook
}
CORE.wcapi_request("post", "webhooks", data)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment