Skip to content

Commit

Permalink
[ADD] 3 modules to handle recursing creation
Browse files Browse the repository at this point in the history
  • Loading branch information
legalsylvain committed Nov 22, 2024
1 parent e0e1a0f commit 145238c
Show file tree
Hide file tree
Showing 36 changed files with 487 additions and 0 deletions.
Empty file.
1 change: 1 addition & 0 deletions create_recursive_abstract/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
15 changes: 15 additions & 0 deletions create_recursive_abstract/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "Recursive creation tools",
"summary": "Create recursively parents item.",
"version": "16.0.1.0.0",
"category": "Tools",
"author": "GRAP",
"website": "https://github.com/grap/grap-odoo-incubator",
"license": "AGPL-3",
"depends": ["base"],
"installable": True,
}
1 change: 1 addition & 0 deletions create_recursive_abstract/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import create_recursive_mixin
56 changes: 56 additions & 0 deletions create_recursive_abstract/models/create_recursive_mixin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api, models


class CreateRecursiveMixin(models.AbstractModel):
_name = "create.recursive.mixin"
_description = "Mixin providing recurring creation of parents"

def _create_recursive_get_or_create_parent_id(self, item_name):
data = self.name_search(name=item_name, operator="=")
if data:
return data[0][0]
else:
parent_id, _parent_name = self.name_create(item_name)
return parent_id

Check warning on line 18 in create_recursive_abstract/models/create_recursive_mixin.py

View check run for this annotation

Codecov / codecov/patch

create_recursive_abstract/models/create_recursive_mixin.py#L17-L18

Added lines #L17 - L18 were not covered by tests

# Workaround.
# If a model, like (product.category), overwrite the name_create
# function, it will fail, so we add that workaround.
@api.model
def name_create(self, name):
return self._name_create(name)

@api.model
def _name_create(self, name):
"""Natively, this function is called if a search of 'name' fails
to create simply an item, with {'name': name} value.
This overload will alter the function if the name contains a '/'.
For exemple, if the name is 'Parent / Child', it will not create
an item with such name. It will:
- search an item named 'Parent' (or create it if it doesn't exist)
- then, create an item named 'Child' with the parent found as parent_id.
"""
if "/" in name:
splitted_name = name.split("/")
parent_name = (" / ".join([x.strip() for x in splitted_name[:-1]])).strip()
item_name = splitted_name[-1:][0].strip()
parent_id = self._create_recursive_get_or_create_parent_id(parent_name)
item = self.create({"name": item_name, "parent_id": parent_id})
return item.name_get()[0]
return super().name_create(name)

Check warning on line 44 in create_recursive_abstract/models/create_recursive_mixin.py

View check run for this annotation

Codecov / codecov/patch

create_recursive_abstract/models/create_recursive_mixin.py#L44

Added line #L44 was not covered by tests

@api.model_create_multi
def create(self, vals_list):
for value in vals_list:
if "name" in value:
value["name"] = value["name"].replace("/", "-").strip()
return super().create(vals_list)

def write(self, vals):
if "name" in vals:
vals["name"] = vals["name"].replace("/", "-").strip()
return super().write(vals)
1 change: 1 addition & 0 deletions create_recursive_abstract/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Sylvain LE GAL <https://twitter.com/legalsylvain>
7 changes: 7 additions & 0 deletions create_recursive_abstract/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This module is a technical tools to create recursively parents,
when creating items, if the name contains one or many **'/'** chars.

See implementation in the following modules:

- ``create_recursive_product_category``
- ``create_recursive_pos_category``
10 changes: 10 additions & 0 deletions create_recursive_abstract/readme/DEVELOP.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
This module define a new mixin ``create.recursive.mixin`` that can be used
on any model that contains the following code.

.. code:: python
_parent_name = "parent_id"
_parent_store = True
_rec_name = "complete_name"
(See example in the ``product.category`` model in the odoo ``product`` module)
1 change: 1 addition & 0 deletions create_recursive_abstract/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_create_recursive_abstract
38 changes: 38 additions & 0 deletions create_recursive_abstract/tests/fake_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models


class ModelCreateRecursiveMixin(models.Model):
_name = "model.create.recursive.mixin"
_description = "model.create.recursive.mixin"
_inherit = ["create.recursive.mixin"]
_parent_name = "parent_id"
_parent_store = True
_rec_name = "complete_name"

name = fields.Char()

parent_id = fields.Many2one(comodel_name="model.create.recursive.mixin")

parent_path = fields.Char(index=True, unaccent=False)

complete_name = fields.Char(
compute="_compute_complete_name", recursive=True, store=True
)

@api.depends("name", "parent_id.complete_name")
def _compute_complete_name(self):
for category in self:
if category.parent_id:
category.complete_name = (
f"{category.parent_id.complete_name} / {category.name}"
)
else:
category.complete_name = category.name

# @api.model
# def name_create(self, name):
# return self._name_create(name)
46 changes: 46 additions & 0 deletions create_recursive_abstract/tests/test_create_recursive_abstract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo_test_helper import FakeModelLoader

from odoo.tests.common import TransactionCase


class TestModule(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# Load a test model using odoo_test_helper
cls.loader = FakeModelLoader(cls.env, cls.__module__)
cls.loader.backup_registry()
from .fake_models import ModelCreateRecursiveMixin

cls.loader.update_registry((ModelCreateRecursiveMixin,))

cls.model = cls.env["model.create.recursive.mixin"]

cls.parent_item = cls.model.create({"name": "Parent"})

cls.child_item = cls.model.create(
{"name": "Child", "parent_id": cls.parent_item.id}
)

@classmethod
def tearDownClass(cls):
cls.loader.restore_registry()
return super().tearDownClass()

def test_remove_slash_create(self):
item = self.model.create({"name": "Fruits / Vegetables"})
self.assertEqual(item.name, "Fruits - Vegetables")

def test_remove_slash_write(self):
self.parent_item.write({"name": "Fruits / Vegetables"})
self.assertEqual(self.parent_item.name, "Fruits - Vegetables")

def test_name_create(self):
res = self.model.name_create("Parent / Child / New Category")
categ = self.model.browse(res[0])
self.assertEqual(categ.name, "New Category")
self.assertEqual(categ.parent_id, self.child_item)
64 changes: 64 additions & 0 deletions create_recursive_pos_category/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
====================================================================
GRAP - Custom Import Product Supplierinfo Quantity Multiplier Module
====================================================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:9b8df078c1fb893b68650c2ee64e375d840edd6d1f8f7bfdb0f1a4da37012215
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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-grap%2Fgrap--odoo--import-lightgray.png?logo=github
:target: https://github.com/grap/grap-odoo-import/tree/16.0/grap_custom_import_product_supplierinfo_qty_multiplier
:alt: grap/grap-odoo-import

|badge1| |badge2| |badge3|

This module improve the "import" features provided by Odoo.

* ``product.product``:

* Allow to recover ``multiplier_qty`` field in the supplier info level.

**Table of contents**

.. contents::
:local:

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

Bugs are tracked on `GitHub Issues <https://github.com/grap/grap-odoo-import/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/grap/grap-odoo-import/issues/new?body=module:%20grap_custom_import_product_supplierinfo_qty_multiplier%0Aversion:%2016.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
~~~~~~~

* GRAP

Contributors
~~~~~~~~~~~~

* Sylvain LE GAL <https://twitter.com/legalsylvain>

Maintainers
~~~~~~~~~~~

This module is part of the `grap/grap-odoo-import <https://github.com/grap/grap-odoo-import/tree/16.0/grap_custom_import_product_supplierinfo_qty_multiplier>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions create_recursive_pos_category/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
15 changes: 15 additions & 0 deletions create_recursive_pos_category/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright (C) 2019 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "GRAP - Custom Product Import - Point Of Sale Module",
"summary": "Extra GRAP Tools to import product data for" " Point of sale module",
"version": "16.0.1.0.0",
"category": "Tools",
"author": "GRAP",
"website": "https://github.com/grap/grap-odoo-incubator",
"license": "AGPL-3",
"depends": ["create_recursive_abstract", "pos_category_complete_name"],
"installable": True,
}
1 change: 1 addition & 0 deletions create_recursive_pos_category/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import pos_category
10 changes: 10 additions & 0 deletions create_recursive_pos_category/models/pos_category.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import models


class PosCategory(models.Model):
_name = "pos.category"
_inherit = ["pos.category", "create.recursive.mixin"]
1 change: 1 addition & 0 deletions create_recursive_pos_category/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Sylvain LE GAL <https://twitter.com/legalsylvain>
14 changes: 14 additions & 0 deletions create_recursive_pos_category/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Implement the recursive creation of parent for the model PoS Categories.
(``pos.category``).

In the product view, if a user enter in the PoS category field the name
**'Chairs / Little'**, it will not create a category with such name.
Instead, it will look for a category named **'Chairs'** (and create it if it
doesn't exists), then create a new category named **'Little'** with the category
**'Chairs'** as parent.

If a user create or update the name of a PoS category, any **'/'** char will
be replaced by the char **'-'**.

At the installation, all **'/'** in the names of the PoS categories
will be replaced by **'-'**.
1 change: 1 addition & 0 deletions create_recursive_pos_category/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_module
33 changes: 33 additions & 0 deletions create_recursive_pos_category/tests/test_module.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo.tests.common import TransactionCase


class TestModule(TransactionCase):
@classmethod
def setUpClass(cls):
super().setUpClass()

cls.model = cls.env["pos.category"]

cls.parent_item = cls.model.create({"name": "Parent"})

cls.child_item = cls.model.create(
{"name": "Child", "parent_id": cls.parent_item.id}
)

def test_remove_slash_create(self):
item = self.model.create({"name": "Fruits / Vegetables"})
self.assertEqual(item.name, "Fruits - Vegetables")

def test_remove_slash_write(self):
self.parent_item.write({"name": "Fruits / Vegetables"})
self.assertEqual(self.parent_item.name, "Fruits - Vegetables")

def test_name_create(self):
res = self.model.name_create("Parent / Child / New Category")
categ = self.model.browse(res[0])
self.assertEqual(categ.name, "New Category")
self.assertEqual(categ.parent_id, self.child_item)
Loading

0 comments on commit 145238c

Please sign in to comment.