Skip to content

Commit

Permalink
[IMP] product_import: Import products asynchronously
Browse files Browse the repository at this point in the history
  • Loading branch information
florentx committed Dec 3, 2024
1 parent aefd8e9 commit 2a26180
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 27 deletions.
3 changes: 3 additions & 0 deletions product_import/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@
"stock",
# OCA/edi
"base_business_document_import",
# OCA/queue
"queue_job",
],
"data": [
"security/ir.model.access.csv",
"wizard/product_import_view.xml",
"data/job_function.xml",
],
}
14 changes: 14 additions & 0 deletions product_import/data/job_function.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<odoo noupdate="1">

<record id="channel_product_import" model="queue.job.channel">
<field name="name">product_import</field>
<field name="parent_id" ref="queue_job.channel_root" />
</record>

<record id="job_create_update_product" model="queue.job.function">
<field name="model_id" ref="model_product_import" />
<field name="method">_create_update_product</field>
<field name="channel_id" ref="channel_product_import" />
</record>

</odoo>
1 change: 0 additions & 1 deletion product_import/static/description/index.html
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
Expand Down
7 changes: 4 additions & 3 deletions product_import/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ class TestCommon(SavepointCase):
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.wiz_model = cls.env["product.import"]
# Execute directly, no job
cls.wiz_model = cls.env["product.import"].with_context(queue_job__no_delay=True)
cls.supplier = cls.env["res.partner"].create({"name": "Catalogue Vendor"})

def _mock(self, method_name):
return mock.patch.object(type(self.wiz_model), method_name)
def _mock(self, method_name, **kw):
return mock.patch.object(type(self.wiz_model), method_name, **kw)

@property
def wiz_form(self):
Expand Down
10 changes: 8 additions & 2 deletions product_import/tests/test_product_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,15 @@ def test_get_company_id(self):

def test_product_import(self):
# product.product
products = self.wiz_model._create_products(
self.parsed_catalog, seller=self.supplier
product_obj = self.env["product.product"].with_context(active_test=False)
existing = product_obj.search([], order="id")

wiz = self.wiz_model.create(
{"product_file": b"", "product_filename": "test_import.xml"}
)
with self._mock("parse_product_catalogue", return_value=self.parsed_catalog):
wiz.import_button()
products = product_obj.search([], order="id") - existing
self.assertEqual(len(products), 3)
for product, parsed in zip(products, PARSED_CATALOG["products"]):

Expand Down
44 changes: 24 additions & 20 deletions product_import/wizard/product_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,14 +195,21 @@ def _prepare_product(self, parsed_product, chatter_msg, seller=None):
return product_vals

@api.model
def create_product(self, parsed_product, chatter_msg, seller=None):
def _create_update_product(self, parsed_product, seller_id):
"""Create / Update a product.
This method is called from a queue job.
"""
chatter_msg = []

seller = self.env["res.partner"].browse(seller_id)
product_vals = self._prepare_product(parsed_product, chatter_msg, seller=seller)
if not product_vals:
return False
product = product_vals.pop("recordset", None)
if product:
product.write(product_vals)
logger.info("Product %d updated", product.id)
logger.debug("Product %s updated", product.default_code)
else:
product_active = product_vals.pop("active")
product = self.env["product.product"].create(product_vals)
Expand All @@ -211,23 +218,10 @@ def create_product(self, parsed_product, chatter_msg, seller=None):
# all characteristics into product.template
product.flush()
product.action_archive()
logger.info("Product %d created", product.id)
return product
logger.debug("Product %s created", product.default_code)

@api.model
def _create_products(self, catalogue, seller, filename=None):
products = self.env["product.product"].browse()
for product in catalogue.get("products"):
record = self.create_product(
product,
catalogue["chatter_msg"],
seller=seller,
)
if record:
products |= record
self._bdimport.post_create_or_update(catalogue, seller, doc_filename=filename)
logger.info("Products updated for vendor %d", seller.id)
return products
log_msg = f"Product created/updated {product.id}\n" + "\n".join(chatter_msg)
return log_msg

def import_button(self):
self.ensure_one()
Expand All @@ -237,7 +231,17 @@ def import_button(self):
raise UserError(_("This catalogue doesn't have any product!"))
company_id = self._get_company_id(catalogue)
seller = self._get_seller(catalogue)
self.with_context(product_company_id=company_id)._create_products(
catalogue, seller, filename=self.product_filename
wiz = self.with_context(product_company_id=company_id)
# Create products asynchronously
for product_vals in catalogue["products"]:
# One job per product
wiz.with_delay()._create_update_product(product_vals, seller.id)
# Save imported file as attachment
self._bdimport.post_create_or_update(
catalogue, seller, doc_filename=self.product_filename
)
logger.info(
"Update for vendor %s: %d products", seller.name, len(catalogue["products"])
)

return {"type": "ir.actions.act_window_close"}
8 changes: 7 additions & 1 deletion product_import_ubl/tests/test_ubl_catalogue_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,13 @@ class TestUblOrderImport(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.env = cls.env(
context={
**cls.env.context,
"tracking_disable": True,
"queue_job__no_delay": True,
}
)
cls.supplier = cls.env["res.partner"].create(
{"name": "Medical", "ref": "78456123"}
)
Expand Down

0 comments on commit 2a26180

Please sign in to comment.