Skip to content

Commit

Permalink
[ADD] product_packaging_container_deposit
Browse files Browse the repository at this point in the history
  • Loading branch information
santostelmo committed Oct 25, 2023
1 parent 3c7a16c commit 0afbf44
Show file tree
Hide file tree
Showing 17 changed files with 888 additions and 0 deletions.
78 changes: 78 additions & 0 deletions product_packaging_container_deposit/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
===================================
Product Packaging Container Deposit
===================================

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |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/16.0/product_packaging_container_deposit
: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-16-0/product-attribute-16-0-product_packaging_container_deposit
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/product-attribute&target_branch=16.0
:alt: Try me on Runboat

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

Allow to indicate on a product packaging package type that it comes with a container deposit. The deposit product should be a service product.
For instance, you can create a package type "plastic box" and indicate as container deposit "plastic box deposit".

Use the corresponding sales and purchase modules to add the deposit fees in the order. Each packaging level can have a deposit. The biggest package type of each packaging level will be used in the computation unless a specific package type is given on the order line.

**Table of contents**

.. contents::
:local:

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 smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/product-attribute/issues/new?body=module:%20product_packaging_container_deposit%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
~~~~~~~

* Camptocamp
* BCIM

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

* Telmo Santos <[email protected]>
* Jacques-Etienne Baudoux (BCIM) <[email protected]>

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/16.0/product_packaging_container_deposit>`_ 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_container_deposit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
22 changes: 22 additions & 0 deletions product_packaging_container_deposit/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2023 Camptocamp (<https://www.camptocamp.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
"name": "Product Packaging Container Deposit",
"version": "16.0.1.0.0",
"development_status": "Beta",
"category": "Product",
"summary": "Add container deposit fees in a order",
"author": "Camptocamp, BCIM, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/product-attribute",
"license": "AGPL-3",
"depends": [
"stock",
"product_packaging_level",
],
"data": [
"views/stock_package_type_views.xml",
],
"installable": True,
"auto_install": False,
}
4 changes: 4 additions & 0 deletions product_packaging_container_deposit/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import stock_package_type
from . import product_product
from . import container_deposit_order_line_mixin
from . import container_deposit_order_mixin
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Copyright 2023 Camptocamp (<https://www.camptocamp.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import api, fields, models


class OrderLineMixin(models.AbstractModel):
"""
Provide common features to order lines.
Supported order lines: purchase.order.line, sale.order.line.
"""

_name = "container.deposit.order.line.mixin"
_description = "Container Deposit Order Line Mixin"

is_container_deposit = fields.Boolean()

def _get_product_qty_field(self):
raise NotImplementedError()

def _get_product_qty_delivered_received_field(self):
raise NotImplementedError()

def _get_order_lines_container_deposit_quantities(self):
"""Get container deposit quantities by product.
:return: a dict with quantity of container deposit
{
container_deposit_product: [quantity, quantity_delivered_received]
}
"""
deposit_product_qties = {}
for line in self:
line_deposit_qties = (
line.product_id.get_product_container_deposit_quantities(
line[self._get_product_qty_field()],
forced_packaging=line.product_packaging_id,
)
)
line_deposit_dlvd_rcvd_qties = (
line.product_id.get_product_container_deposit_quantities(
line[self._get_product_qty_delivered_received_field()],
forced_packaging=line.product_packaging_id,
)
)

for plevel in line_deposit_qties:
product = line_deposit_qties[plevel][0]
qty = line_deposit_qties[plevel][1]
if qty == 0:
continue
if plevel in line_deposit_dlvd_rcvd_qties:
dlvd_rcvd = line_deposit_dlvd_rcvd_qties[plevel][1]
else:
dlvd_rcvd = 0
if product in deposit_product_qties:
deposit_product_qties[product][0] += qty
deposit_product_qties[product][1] += dlvd_rcvd
else:
deposit_product_qties[product] = [qty, dlvd_rcvd]
return deposit_product_qties

@api.model_create_multi
def create(self, vals_list):
lines = super().create(vals_list)
if not self.env.context.get(
"skip_update_container_deposit"
) and not self.env.context.get("from_copy"):
orders = lines.mapped("order_id")
orders.update_order_container_deposit_quantity()
return lines

def write(self, vals):
res = super().write(vals)
# Context var to avoid recursive calls when updating container deposit
if not self.env.context.get("skip_update_container_deposit") and (
self._get_product_qty_field() in vals
or self._get_product_qty_delivered_received_field() in vals
):
self.order_id.update_order_container_deposit_quantity()
return res
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Copyright 2023 Camptocamp (<https://www.camptocamp.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import models


class OrderMixin(models.AbstractModel):
"""This mixin should only be inherited by purchase.order and sale.order models."""

_name = "container.deposit.order.mixin"
_description = "Container Deposit Order Mixin"

def prepare_deposit_container_line(self, product, qty):
self.ensure_one()
values = {
"name": product.name,
"product_id": product.id,
self.order_line._get_product_qty_field(): qty,
"is_container_deposit": True,
"order_id": self.id,
# Bottom of the order
"sequence": 999,
}
return values

def _get_order_line_field(self):
raise NotImplementedError()

def update_order_container_deposit_quantity(self):
if self.env.context.get("skip_update_container_deposit"):
return
self = self.with_context(skip_update_container_deposit=True)
for order in self:
# Lines to compute container deposit
lines_to_comp_deposit = order[self._get_order_line_field()].filtered(
lambda ln: (
ln.product_packaging_id.package_type_id.container_deposit_product_id
)
or line.product_id.packaging_ids
)
deposit_container_qties = (
lines_to_comp_deposit._get_order_lines_container_deposit_quantities()
)
for line in self[self._get_order_line_field()]:
if not line.is_container_deposit:
continue
qty, qty_dlvd_rcvd = deposit_container_qties.pop(
line["product_id"], [False, False]
)
if not qty:
if order.state == "draft":
line.unlink()
else:
line.write(
{
line._get_product_qty_field(): 0,
}
)
else:
line.write(
{
line._get_product_qty_field(): qty,
line._get_product_qty_delivered_received_field(): qty_dlvd_rcvd,
}
)
values_lst = []
for product in deposit_container_qties:
if deposit_container_qties[product][0] > 0:
values = order.prepare_deposit_container_line(
product, deposit_container_qties[product][0]
)
values_lst.append(values)
order[self._get_order_line_field()].create(values_lst)

def copy(self, default=None):
return super(
OrderMixin, self.with_context(skip_update_container_deposit=True)
).copy(default=default)
43 changes: 43 additions & 0 deletions product_packaging_container_deposit/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright 2023 Camptocamp (<https://www.camptocamp.com>).
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html)

from odoo import models
from odoo.tools import groupby


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

def get_product_container_deposit_quantities(self, qty, forced_packaging=False):
"""Get the quantity of deposit per packaging level for a given product quantity
:return a dict with quantity of deposit per packaging level for a given product quantity
{
"PL1": (CP1, QTY),
"PLn": (CPn, QTYn)
}
"""

def get_sort_key(packaging):
return (
packaging.packaging_level_id,
packaging != forced_packaging,
packaging.qty < qty,
-packaging.qty,
)

pack_qties = {}
if qty > 0:
# Sort by forced_packaging, fitting packagings, biggest packaging
packagings = self.packaging_ids.sorted(key=get_sort_key)
for plevel, packs in groupby(packagings, lambda p: p.packaging_level_id):
container_deposit = packs[
0
].package_type_id.container_deposit_product_id
if not container_deposit:
continue
pack_qties[plevel] = (
container_deposit,
qty // packs[0].qty,
)
return pack_qties
12 changes: 12 additions & 0 deletions product_packaging_container_deposit/models/stock_package_type.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2023 Camptocamp (<https://www.camptocamp.com>).
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class PackageType(models.Model):
_inherit = "stock.package.type"

container_deposit_product_id = fields.Many2one(
"product.product", domain=[("type", "=", "service")]
)
2 changes: 2 additions & 0 deletions product_packaging_container_deposit/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Telmo Santos <[email protected]>
* Jacques-Etienne Baudoux (BCIM) <[email protected]>
4 changes: 4 additions & 0 deletions product_packaging_container_deposit/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Allow to indicate on a product packaging package type that it comes with a container deposit. The deposit product should be a service product.
For instance, you can create a package type "plastic box" and indicate as container deposit "plastic box deposit".

Use the corresponding sales and purchase modules to add the deposit fees in the order. Each packaging level can have a deposit. The biggest package type of each packaging level will be used in the computation unless a specific package type is given on the order line.
Loading

0 comments on commit 0afbf44

Please sign in to comment.