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
102 changes: 102 additions & 0 deletions product_packaging_template/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
==========================
Product Packaging Template
==========================

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

.. |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%2Fproduct--attribute-lightgray.png?logo=github
:target: https://github.com/OCA/product-attribute/tree/18.0/product_packaging_template
:alt: OCA/product-attribute
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_packaging_template
: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/product-attribute&target_branch=18.0
:alt: Try me on Runboat

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

Product packaging are defined at product variant level. It means that if
a product template has 25 variants, and all of them are sold in the same
packaging, one must define all the product packaging one by one on the
variants.

The aim of this module is to be able to define the product packaging at
template level. It will then create the product packaging on all
variants automatically.

Features
--------

- When a product packaging template is created, create the product
packaging on all variants;
- When a product packaging template is updated, update the product
packaging on all variants;
- When a product packaging template is deleted, delete the product
packaging on all variants;
- When a new product variant is created, create all the product
packaging defined by the product packaging templates.

**Table of contents**

.. contents::
:local:

Usage
=====

To see the new table containing product packaging templates on product
templates, one must have the special group "Products: Can manage
packaging at template level".

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

Bugs are tracked on `GitHub Issues <https://github.com/OCA/product-attribute/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/product-attribute/issues/new?body=module:%20product_packaging_template%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
-------

* ACSONE SA/NV

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

- Marie Lejeune <marie.lejeune@acsone.eu>

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/product-attribute <https://github.com/OCA/product-attribute/tree/18.0/product_packaging_template>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions product_packaging_template/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
21 changes: 21 additions & 0 deletions product_packaging_template/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2025 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Product Packaging Template",
"summary": """Allows to define product packaging at template level""",
"version": "18.0.1.0.0",
"license": "AGPL-3",
"author": "ACSONE SA/NV, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/product-attribute",
"depends": [
"product",
],
"data": [
"security/groups.xml",
"security/product_packaging_template.xml",
"views/product_template.xml",
"views/product_packaging_template.xml",
],
"installable": True,
}
4 changes: 4 additions & 0 deletions product_packaging_template/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import product_packaging
from . import product_packaging_template
from . import product_product
from . import product_template
10 changes: 10 additions & 0 deletions product_packaging_template/models/product_packaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2025 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ProductPackaging(models.Model):
_inherit = "product.packaging"

packaging_tmpl_id = fields.Many2one("product.packaging.template", readonly=True)
68 changes: 68 additions & 0 deletions product_packaging_template/models/product_packaging_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Copyright 2025 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import api, fields, models


class ProductPackagingTemplate(models.Model):
_name = "product.packaging.template"
_description = "Product Packaging Template"

name = fields.Char("Product Packaging", required=True)
sequence = fields.Integer(
default=1, help="The first in the sequence is the default one."
)
product_tmpl_id = fields.Many2one(
"product.template",
string="Product Template",
check_company=True,
required=True,
ondelete="cascade",
)
qty = fields.Float(
"Contained Quantity",
default=1,
digits="Product Unit of Measure",
help="Quantity of products contained in the packaging.",
)
company_id = fields.Many2one("res.company", "Company", index=True)
packaging_ids = fields.One2many("product.packaging", "packaging_tmpl_id")

@api.model_create_multi
def create(self, vals_list):
res = super().create(vals_list)
for pt in res:
pt.product_tmpl_id.product_variant_ids._create_packaging_from_template(
template=pt
)
return res

def write(self, vals):
"""
Propagate changes on packages at variant level.
"""
res = super().write(vals)
self._propagate_to_packaging(vals)
return res

@api.model
def _get_values_to_propagate(self, vals):
return {key: vals[key] for key in {"name", "sequence", "qty"} if key in vals}

def _propagate_to_packaging(self, vals):
values_to_propagate = self._get_values_to_propagate(vals)
if values_to_propagate:
self.mapped("packaging_ids").write(values_to_propagate)

def unlink(self):
self.mapped("packaging_ids").unlink()
return super().unlink()

def _prepare_create_values_for_packaging(self):
self.ensure_one()
return {
"name": self.name,
"sequence": self.sequence,
"qty": self.qty,
"company_id": self.company_id.id,
"packaging_tmpl_id": self.id,
}
28 changes: 28 additions & 0 deletions product_packaging_template/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright 2025 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, models


class ProductProduct(models.Model):
_inherit = "product.product"

def _create_packaging_from_template(self, template):
base_values = template._prepare_create_values_for_packaging()
create_values = []
for product in self:
product_values = base_values.copy()
product_values.update({"product_id": product.id})
create_values.append(product_values)
self.env["product.packaging"].create(create_values)

@api.model_create_multi
def create(self, vals_list):
"""
Create all packaging from templates when creating a new variant
"""
res = super().create(vals_list)
for variant in res:
for pt in variant.product_tmpl_id.packaging_tmpl_ids:
variant._create_packaging_from_template(template=pt)
return res
12 changes: 12 additions & 0 deletions product_packaging_template/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2025 ACSONE SA/NV
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ProductTemplate(models.Model):
_inherit = "product.template"

packaging_tmpl_ids = fields.One2many(
"product.packaging.template", "product_tmpl_id"
)
3 changes: 3 additions & 0 deletions product_packaging_template/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
1 change: 1 addition & 0 deletions product_packaging_template/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Marie Lejeune \<<marie.lejeune@acsone.eu>\>
14 changes: 14 additions & 0 deletions product_packaging_template/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Product packaging are defined at product variant level. It means that if a product template
has 25 variants, and all of them are sold in the same packaging, one must define all the product packaging
one by one on the variants.

The aim of this module is to be able to define the product packaging at template level.
It will then create the product packaging on all variants automatically.

Features
--------

* When a product packaging template is created, create the product packaging on all variants;
* When a product packaging template is updated, update the product packaging on all variants;
* When a product packaging template is deleted, delete the product packaging on all variants;
* When a new product variant is created, create all the product packaging defined by the product packaging templates.
1 change: 1 addition & 0 deletions product_packaging_template/readme/USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
To see the new table containing product packaging templates on product templates, one must have the special group "Products: Can manage packaging at template level".
14 changes: 14 additions & 0 deletions product_packaging_template/security/groups.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2025 ACSONE SA/NV
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="group_can_manage_packaging_templates" model="res.groups">
<field name="name">Product: Can manage packaging at template level</field>
<field name="category_id" ref="base.module_category_hidden" />
<field
name="implied_ids"
eval="[Command.set([ref('product.group_stock_packaging')])]"
/>
<field name="users" eval="[Command.link(ref('base.user_root'))]" />
</record>
</odoo>
17 changes: 17 additions & 0 deletions product_packaging_template/security/product_packaging_template.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2025 ACSONE SA/NV
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<odoo>
<record model="ir.model.access" id="product_packaging_template_manager_access">
<field name="name">product.packaging.template manager access</field>
<field name="model_id" ref="model_product_packaging_template" />
<field
name="group_id"
ref="product_packaging_template.group_can_manage_packaging_templates"
/>
<field name="perm_read" eval="1" />
<field name="perm_create" eval="1" />
<field name="perm_write" eval="1" />
<field name="perm_unlink" eval="1" />
</record>
</odoo>
Loading