diff --git a/sale_order_volume/models/__init__.py b/sale_order_volume/models/__init__.py index fc3553c0e..7f5bce193 100644 --- a/sale_order_volume/models/__init__.py +++ b/sale_order_volume/models/__init__.py @@ -1,2 +1,4 @@ +from . import product_category_volume from . import res_config_settings +from . import sale_order_line from . import sale_order diff --git a/sale_order_volume/models/product_category_volume.py b/sale_order_volume/models/product_category_volume.py new file mode 100644 index 000000000..eff068a5b --- /dev/null +++ b/sale_order_volume/models/product_category_volume.py @@ -0,0 +1,16 @@ +# © 2016 Robin Keunen, Coop IT Easy SCRL. +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ProductCategoryVolume(models.Model): + _name = "product.category.volume" + _description = "Product Volume by Category" + + sale_order_id = fields.Many2one(comodel_name="sale.order", string="Sale Order") + category_id = fields.Many2one( + comodel_name="product.category", string="Product Category" + ) + volume = fields.Float(string="Volume (m³)") + pallet_count = fields.Integer(string="# Pallets") diff --git a/sale_order_volume/models/sale_order.py b/sale_order_volume/models/sale_order.py index ddc2c0e6f..a1f2265b7 100644 --- a/sale_order_volume/models/sale_order.py +++ b/sale_order_volume/models/sale_order.py @@ -5,39 +5,13 @@ from odoo import api, fields, models -def _compute_volume(order_line): - return order_line.product_id.volume * order_line.product_uom_qty - - def _compute_pallet_count(volume, pallet_volume): - if not pallet_volume or not volume: + if not pallet_volume: return 0 - if volume <= pallet_volume: - return 1 - if volume % pallet_volume == 0: - return volume // pallet_volume - return (volume // pallet_volume) + 1 - - -class ProductCategoryVolume(models.Model): - _name = "product.category.volume" - _description = "Product Volume by Category" - - sale_order_id = fields.Many2one(comodel_name="sale.order", string="Sale Order") - category_id = fields.Many2one( - comodel_name="product.category", string="Product Category" - ) - volume = fields.Float(string="Volume (m³)") - pallet_count = fields.Integer(string="# Pallets") - - @api.model - def get_default_pallet_volume(self): - return ( - self.env["ir.config_parameter"] - .sudo() - .get_param("sale_order_volume.pallet_volume") - or 0 - ) + quotient, remainder = divmod(volume, pallet_volume) + if remainder: + return quotient + 1 + return quotient class SaleOrder(models.Model): @@ -57,14 +31,15 @@ class SaleOrder(models.Model): string="Volume per Product Category", ) - @api.depends("order_line", "order_line.product_id", "order_line.product_uom_qty") + @api.depends("order_line", "order_line.volume") def _compute_order_volume(self): + for order in self: order_lines = order.order_line.filtered( lambda ol: ol.state not in ["cancel"] ) - order.volume = sum(_compute_volume(ol) for ol in order_lines) + order.volume = sum(ol.product_id.volume for ol in order_lines) order.pallet_count = _compute_pallet_count( order.volume, float(self.get_default_pallet_volume()) ) @@ -83,24 +58,21 @@ def compute_order_product_category_volumes(self): order_lines = self.order_line.filtered(lambda ol: ol.state not in ["cancel"]) - accumulator = defaultdict(list) + volume_per_category = defaultdict(float) for order_line in order_lines: category_id = order_line.product_id.categ_id.id - volume = _compute_volume(order_line) - accumulator[category_id].append(volume) - - volume_per_category = [ - (category_id, sum(volumes)) for category_id, volumes in accumulator.items() - ] + volume_per_category[category_id] += order_line.volume existing_categories = { vpc.category_id.id: vpc for vpc in self.volume_per_category } - for category_id, volume in volume_per_category: + for category_id, volume in volume_per_category.items(): pallet_count = _compute_pallet_count( volume, float(self.get_default_pallet_volume()) ) + # TODO: what if there is an existing category_id of which no + # products are in the order anymore? if category_id in existing_categories: existing_categories[category_id].volume = volume existing_categories[category_id].pallet_count = pallet_count diff --git a/sale_order_volume/models/sale_order_line.py b/sale_order_volume/models/sale_order_line.py new file mode 100644 index 000000000..274e92015 --- /dev/null +++ b/sale_order_volume/models/sale_order_line.py @@ -0,0 +1,16 @@ +# SPDX-FileCopyrightText: 2023 Coop IT Easy SC +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +from odoo import api, fields, models + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + volume = fields.Float(compute="_compute_volume", store=True) + + @api.depends("product_id.volume", "product_uom_qty") + def _compute_volume(self): + for line in self: + line.volume = line.product_id.volume * line.product_uom_qty diff --git a/sale_order_volume/tests/test_sale_order_volume.py b/sale_order_volume/tests/test_sale_order_volume.py index 464dbc2cf..8d3fe28e2 100644 --- a/sale_order_volume/tests/test_sale_order_volume.py +++ b/sale_order_volume/tests/test_sale_order_volume.py @@ -2,13 +2,10 @@ # Robin Keunen # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). -import unittest - from odoo.tests import TransactionCase class SaleOrderVolumeCase(TransactionCase): - @unittest.expectedFailure def test_sale_order_volumes(self): sale_order = self.browse_ref("sale.sale_order_4") product = self.browse_ref("product.product_delivery_01") @@ -28,7 +25,7 @@ def test_sale_order_volumes(self): ) self.assertEqual(service_volume.volume, 0) - self.assertEqual(service_volume.pallet_count, 1) + self.assertEqual(service_volume.pallet_count, 0) self.assertEqual(office_furniture_volume.volume, 15.6) # (15.6 (volume) // 1.75 (pallet volume)) + 1 = 9 self.assertEqual(office_furniture_volume.pallet_count, 9)