Merge pull request #1168 from camptocamp/13-pkg-by-qty-new-modules-2535

[13.0] Add glue modules for displaying qty by packaging
This commit is contained in:
Simone Orsi
2021-06-11 11:24:52 +02:00
committed by GitHub
38 changed files with 363 additions and 1 deletions

View File

@@ -0,0 +1 @@
../../../../stock_packaging_calculator_packaging_type

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

View File

@@ -0,0 +1 @@
../../../../stock_product_qty_by_packaging

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

View File

@@ -0,0 +1 @@
../../../../stock_vertical_lift_qty_by_packaging

View File

@@ -0,0 +1,6 @@
import setuptools
setuptools.setup(
setup_requires=['setuptools-odoo'],
odoo_addon=True,
)

View File

@@ -0,0 +1 @@
wait for the bot ;)

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,16 @@
# Copyright 2021 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
{
"name": "Stock packaging calculator packaging type",
"summary": "Glue module for packaging type",
"version": "13.0.1.0.0",
"development_status": "Alpha",
"category": "Warehouse Management",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "LGPL-3",
"application": False,
"installable": True,
"auto_install": True,
"depends": ["stock_packaging_calculator", "product_packaging_type"],
}

View File

@@ -0,0 +1,2 @@
from . import product
from . import product_qty_by_packaging_mixin

View File

@@ -0,0 +1,25 @@
# Copyright 2021 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
from odoo import models
class Product(models.Model):
_inherit = "product.product"
def _packaging_name_getter(self, packaging):
return packaging.packaging_type_id.name
def _qty_by_packaging_as_str(self, packaging, qty):
# By default use packaging type code
qty_by_packaging_type_fname = self.env.context.get(
"qty_by_packaging_type_fname", "code"
)
compact_mode = self.env.context.get("qty_by_packaging_type_compact", True)
sep = "" if compact_mode else " "
# Override to use packaging type code
if packaging and packaging.packaging_type_id:
name = packaging.packaging_type_id[qty_by_packaging_type_fname]
return f"{qty}{sep}{name}"
else:
return super()._qty_by_packaging_as_str(packaging, qty)

View File

@@ -0,0 +1,23 @@
# Copyright 2021 Camptocamp SA
# @author: Simone Orsi <simone.orsi@camptocamp.com>
# @author: Sébastien Alix <sebastien.alix@camptocamp.com>
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
from odoo import api, models
class ProductQtyByPackagingMixin(models.AbstractModel):
"""Allow displaying product qty by packaging.
"""
_inherit = "product.qty_by_packaging.mixin"
# Amazing.. unlike `api.depends`, `depends_context` cannot use a lambda
# to delegate lookup. Hence we are forced to override and call super.
@api.depends_context(
"lang",
"qty_by_pkg_total_units",
"qty_by_packaging_type_fname",
"qty_by_packaging_type_compact",
)
def _compute_product_qty_by_packaging_display(self):
super()._compute_product_qty_by_packaging_display()

View File

@@ -0,0 +1 @@
* Simone Orsi <simone.orsi@camptocamp.com>

View File

@@ -0,0 +1,3 @@
Glue module for `stock_packaging_calculator` and `product_packaging_type`.
Mainly to use packaging type's code instead of packaging's name.

View File

@@ -0,0 +1 @@
from . import test_packaging_by_qty

View File

@@ -0,0 +1,51 @@
# Copyright 2021 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
from odoo.addons.stock_packaging_calculator.tests.common import TestCommon
from odoo.addons.stock_packaging_calculator.tests.utils import make_pkg_values
class TestCalc(TestCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.type_retail_box = cls.env["product.packaging.type"].create(
{"name": "Retail Box", "code": "PACK", "sequence": 3}
)
cls.type_transport_box = cls.env["product.packaging.type"].create(
{"name": "Transport Box", "code": "CASE", "sequence": 4}
)
cls.type_pallet = cls.env["product.packaging.type"].create(
{"name": "Pallet", "code": "PALLET", "sequence": 5}
)
cls.pkg_box.packaging_type_id = cls.type_retail_box
cls.pkg_big_box.packaging_type_id = cls.type_transport_box
cls.pkg_pallet.packaging_type_id = cls.type_pallet
def test_calc_1(self):
expected = [
make_pkg_values(self.pkg_pallet, qty=1, name=self.type_pallet.name),
make_pkg_values(self.pkg_big_box, qty=3, name=self.type_transport_box.name),
make_pkg_values(self.pkg_box, qty=1, name=self.type_retail_box.name),
make_pkg_values(self.uom_unit, qty=5),
]
self.assertEqual(self.product_a.product_qty_by_packaging(2655), expected)
def test_calc_2(self):
expected = [
make_pkg_values(self.pkg_big_box, qty=1, name=self.type_transport_box.name),
make_pkg_values(self.pkg_box, qty=3, name=self.type_retail_box.name),
]
self.assertEqual(self.product_a.product_qty_by_packaging(350), expected)
def test_as_str(self):
self.assertEqual(self.product_a.product_qty_by_packaging_as_str(10), "")
self.assertEqual(self.product_a.product_qty_by_packaging_as_str(100), "2PACK")
self.assertEqual(
self.product_a.product_qty_by_packaging_as_str(250), "1CASE,\xa01PACK"
)
self.assertEqual(
self.product_a.with_context(
qty_by_packaging_type_fname="name", qty_by_packaging_type_compact=False,
).product_qty_by_packaging_as_str(250),
"1 Transport Box,\xa01 Retail Box",
)

View File

@@ -0,0 +1 @@
wait for the bot ;)

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,16 @@
# Copyright 2020 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
{
"name": "Stock packaging calculator",
"summary": "Compute product quantity to pick by packaging",
"version": "13.0.1.0.0",
"development_status": "Alpha",
"category": "Warehouse Management",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "LGPL-3",
"application": False,
"installable": True,
"depends": ["stock_packaging_calculator", "stock"],
"data": ["views/stock_picking.xml"],
}

View File

@@ -0,0 +1,3 @@
from . import stock_move
from . import stock_move_line
from . import stock_quant

View File

@@ -0,0 +1,13 @@
# Copyright 2020 Camptocamp SA
# @author: Simone Orsi <simone.orsi@camptocamp.com>
# @author: Sébastien Alix <sebastien.alix@camptocamp.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import models
class StockMove(models.Model):
_name = "stock.move"
_inherit = ["stock.move", "product.qty_by_packaging.mixin"]
_qty_by_pkg__qty_field_name = "product_uom_qty"

View File

@@ -0,0 +1,13 @@
# Copyright 2020 Camptocamp SA
# @author: Simone Orsi <simone.orsi@camptocamp.com>
# @author: Sébastien Alix <sebastien.alix@camptocamp.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
from odoo import models
class StockMoveLine(models.Model):
_name = "stock.move.line"
_inherit = ["stock.move.line", "product.qty_by_packaging.mixin"]
_qty_by_pkg__qty_field_name = "product_qty"

View File

@@ -0,0 +1,13 @@
# Copyright 2020 Camptocamp SA
# @author: Simone Orsi <simone.orsi@camptocamp.com>
# @author: Sébastien Alix <sebastien.alix@camptocamp.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models
class StockQuant(models.Model):
_name = "stock.quant"
_inherit = ["stock.quant", "product.qty_by_packaging.mixin"]
_qty_by_pkg__qty_field_name = "quantity"

View File

@@ -0,0 +1,2 @@
Simone Orsi <simone.orsi@camptocamp.com>
Sébastien Alix <sebastien.alix@camptocamp.com>

View File

@@ -0,0 +1 @@
Glue module for `stock_packaging_calculator` and `stock`.

View File

@@ -0,0 +1 @@
from . import test_stock

View File

@@ -0,0 +1,63 @@
# Copyright 2021 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
from odoo.addons.stock_packaging_calculator.tests.common import TestCommon
# from odoo.addons.stock_packaging_calculator.tests.utils import make_pkg_values
class TestStock(TestCommon):
@classmethod
def setUpClass(cls):
super().setUpClass()
ref = cls.env.ref
cls.stock_location = ref("stock.stock_location_stock")
cls.sub_location = cls.env["stock.location"].create(
{"name": "Sub", "location_id": cls.stock_location.id}
)
cls.wh = cls.env.ref("stock.warehouse0")
cls.picking_type = cls.wh.out_type_id
cls.product_a.type = "product"
cls.env["stock.quant"]._update_available_quantity(
cls.product_a, cls.stock_location, 2825
)
cls.move = cls.env["stock.move"].create(
{
"name": "test",
"product_id": cls.product_a.id,
"location_id": cls.stock_location.id,
"location_dest_id": cls.sub_location.id,
"product_uom": cls.product_a.uom_id.id,
"product_uom_qty": 2825,
"state": "waiting",
"picking_type_id": cls.picking_type.id,
}
)
cls.move._assign_picking()
cls.move._action_assign()
cls.move_line = cls.move.move_line_ids[0]
cls.move_line.product_uom_qty = 1470
cls.quant = cls.env["stock.quant"].create(
{
"location_id": cls.stock_location.id,
"product_id": cls.product_a.id,
"quantity": 3190.0,
}
)
def test_move(self):
self.assertEqual(
self.move.product_qty_by_packaging_display,
"1 Pallet,\xa04 Big Box,\xa025 Units",
)
def test_move_line(self):
self.assertEqual(
self.move_line.product_qty_by_packaging_display,
"7 Big Box,\xa01 Box,\xa020 Units",
)
def test_quant(self):
self.assertEqual(
self.quant.product_qty_by_packaging_display,
"1 Pallet,\xa05 Big Box,\xa03 Box,\xa040 Units",
)

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_picking_form" model="ir.ui.view">
<field name="name">stock.view.picking.form</field>
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form" />
<field name="arch" type="xml">
<xpath
expr="//field[@name='move_ids_without_package']/tree/field[@name='product_uom']"
position="after"
>
<field name="product_qty_by_packaging_display" />
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1 @@
Kardex device proxy.

View File

@@ -6,7 +6,7 @@ import os
import ssl
import time
import aiohttp
import aiohttp # pylint: disable=missing-manifest-dependency
_logger = logging.getLogger(__name__)

View File

@@ -0,0 +1 @@
wait fot the bot ;)

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,19 @@
# Copyright 2021 Camptocamp SA
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl)
{
"name": "Stock vertical lift qty by packaging",
"summary": """
Glue module for `stock_product_qty_by_packaging` and `stock_vertical_lift`.
""",
"version": "13.0.1.0.0",
"development_status": "Alpha",
"category": "Warehouse Management",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"author": "Camptocamp, Odoo Community Association (OCA)",
"license": "LGPL-3",
"application": False,
"installable": True,
"auto_install": True,
"depends": ["stock_product_qty_by_packaging", "stock_vertical_lift"],
"data": ["views/vertical_lift_operation_base_views.xml"],
}

View File

@@ -0,0 +1 @@
from . import vertical_lift_operation_base

View File

@@ -0,0 +1,22 @@
# Copyright 2020 Camptocamp SA
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
class VerticalLiftOperationTransfer(models.AbstractModel):
_inherit = "vertical.lift.operation.transfer"
product_qty_by_packaging_display = fields.Char(
compute="_compute_product_qty_by_packaging_display"
)
@api.depends("current_move_line_id.product_qty")
def _compute_product_qty_by_packaging_display(self):
# Seems the ctx key is not propagated on a related field
# nor from the field definition, nor from the field declaration in the view.
# Hence, we are forced to use a computed field.
for rec in self.with_context(qty_by_pkg_total_units=True):
rec.product_qty_by_packaging_display = (
rec.current_move_line_id.product_qty_by_packaging_display
)

View File

@@ -0,0 +1,2 @@
Simone Orsi <simone.orsi@camptocamp.com>
Sébastien Alix <sebastien.alix@camptocamp.com>

View File

@@ -0,0 +1 @@
Glue module for `stock_product_qty_by_packaging` and `stock_vertical_lift`.

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="vertical_lift_operation_transfer_screen_view" model="ir.ui.view">
<field name="name">vertical.lift.operation.transfer.screen.view</field>
<field name="model">vertical.lift.operation.transfer</field>
<field
name="inherit_id"
ref="stock_vertical_lift.vertical_lift_operation_transfer_screen_view"
/>
<field name="arch" type="xml">
<!-- Display only full qty by packaging and units -->
<xpath expr="//field[@name='product_uom_id']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='product_uom_qty']" position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<xpath expr="//field[@name='product_uom_id']" position="after">
<field
name="product_qty_by_packaging_display"
class="oe_inline ml8 text-white"
/>
</xpath>
</field>
</record>
</odoo>