Migrate stock_reserve_rule to 13.0

This commit is contained in:
Guewen Baconnier
2019-12-16 08:30:12 +01:00
committed by Sébastien Alix
parent fdab54b432
commit dfc97bb24d
8 changed files with 63 additions and 75 deletions

View File

@@ -1,29 +1,26 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
{
'name': 'Stock Reservation Rules',
'summary': 'Configure reservation rules by location',
'version': '12.0.1.0.0',
'author': "Camptocamp, Odoo Community Association (OCA)",
'website': "https://github.com/OCA/stock-logistics-warehouse",
'category': 'Stock Management',
'depends': [
'stock',
'product_packaging_type', # OCA/product-attribute
"name": "Stock Reservation Rules",
"summary": "Configure reservation rules by location",
"version": "13.0.1.0.0",
"author": "Camptocamp, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"category": "Stock Management",
"depends": ["stock", "product_packaging_type"], # OCA/product-attribute
"demo": [
"demo/product_demo.xml",
"demo/stock_location_demo.xml",
"demo/stock_reserve_rule_demo.xml",
"demo/stock_inventory_demo.xml",
"demo/stock_picking_demo.xml",
],
'demo': [
'demo/product_demo.xml',
'demo/stock_location_demo.xml',
'demo/stock_reserve_rule_demo.xml',
'demo/stock_inventory_demo.xml',
'demo/stock_picking_demo.xml',
"data": [
"views/stock_reserve_rule_views.xml",
"security/ir.model.access.csv",
"security/stock_reserve_rule_security.xml",
],
'data': [
'views/stock_reserve_rule_views.xml',
'security/ir.model.access.csv',
'security/stock_reserve_rule_security.xml',
],
'installable': True,
'development_status': 'Alpha',
'license': 'AGPL-3',
"installable": True,
"development_status": "Alpha",
"license": "AGPL-3",
}

View File

@@ -12,7 +12,6 @@
<field name="tracking">none</field>
<field name="uom_id" ref="uom.product_uom_unit"/>
<field name="uom_po_id" ref="uom.product_uom_unit"/>
<field name="property_stock_inventory" ref="stock.location_inventory"/>
</record>
</odoo>

View File

@@ -27,8 +27,11 @@
<field name="location_id" ref="stock_location_zone_c_bin_1_demo"/>
</record>
<function model="stock.inventory" name="action_validate">
<function model="stock.inventory" name="_action_start">
<function eval="[[('state','=','draft'),('id', '=', ref('stock_reserve_rule.stock_inventory_1_demo'))]]" model="stock.inventory" name="search"/>
</function>
<function model="stock.inventory" name="action_validate">
<function eval="[[('state','=','confirm'),('id', '=', ref('stock_reserve_rule.stock_inventory_1_demo'))]]" model="stock.inventory" name="search"/>
</function>
</odoo>

View File

@@ -84,8 +84,7 @@ class StockMove(models.Model):
break
need_zero = (
float_compare(still_need, 0, precision_rounding=rounding)
!= 1
float_compare(still_need, 0, precision_rounding=rounding) != 1
)
if need_zero:
# useless to eval the other rules when still_need <= 0

View File

@@ -27,4 +27,4 @@ class StockQuant(models.Model):
seen[location] = seen[location] | quant
else:
seen[location] = quant
return [(location, quants) for location, quants in seen.items()]
return [(loc, quants) for loc, quants in seen.items()]

View File

@@ -1,9 +1,9 @@
# Copyright 2019 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import fields, models
from odoo.tools.safe_eval import safe_eval
from odoo.osv import expression
from odoo.tools.float_utils import float_compare
from odoo.tools.safe_eval import safe_eval
def _default_sequence(record):
@@ -33,8 +33,7 @@ class StockReserveRule(models.Model):
sequence = fields.Integer(default=lambda s: _default_sequence(s))
active = fields.Boolean(default=True)
company_id = fields.Many2one(
comodel_name="res.company",
default=lambda self: self.env.user.company_id.id,
comodel_name="res.company", default=lambda self: self.env.user.company_id.id
)
location_id = fields.Many2one(comodel_name="stock.location", required=True)
@@ -143,9 +142,7 @@ class StockReserveRuleRemoval(models.Model):
def _eval_quant_domain(self, quants, domain):
quant_domain = [("id", "in", quants.ids)]
return self.env["stock.quant"].search(
expression.AND([quant_domain, domain])
)
return self.env["stock.quant"].search(expression.AND([quant_domain, domain]))
def _filter_quants(self, move, quants):
domain = safe_eval(self.quant_domain) or []
@@ -206,7 +203,6 @@ class StockReserveRuleRemoval(models.Model):
(
sum(quants.mapped("quantity"))
- sum(quants.mapped("reserved_quantity")),
quants,
location,
)
for location, quants in quants_per_bin
@@ -217,7 +213,7 @@ class StockReserveRuleRemoval(models.Model):
# Propose the largest quants first, so we have as less operations
# as possible. We take goods only if we empty the bin.
rounding = fields.first(quants).product_id.uom_id.rounding
for location_quantity, quants, location in bins:
for location_quantity, location in bins:
if location_quantity <= 0:
continue
@@ -253,9 +249,7 @@ class StockReserveRuleRemoval(models.Model):
rounding = product.uom_id.rounding
def is_greater_eq(value, other):
return (
float_compare(value, other, precision_rounding=rounding) >= 0
)
return float_compare(value, other, precision_rounding=rounding) >= 0
for pack_quantity in packaging_quantities:
# Get quants quantity on each loop because they may change.
@@ -266,7 +260,6 @@ class StockReserveRuleRemoval(models.Model):
(
sum(quants.mapped("quantity"))
- sum(quants.mapped("reserved_quantity")),
quants,
location,
)
for location, quants in quants_per_bin
@@ -274,12 +267,10 @@ class StockReserveRuleRemoval(models.Model):
reverse=True,
)
for location_quantity, quants, location in bins:
for location_quantity, location in bins:
if location_quantity <= 0:
continue
enough_for_packaging = is_greater_eq(
location_quantity, pack_quantity
)
enough_for_packaging = is_greater_eq(location_quantity, pack_quantity)
asked_more_than_packaging = is_greater_eq(need, pack_quantity)
if enough_for_packaging and asked_more_than_packaging:
# compute how much packaging we can get

View File

@@ -101,9 +101,7 @@ class TestReserveRule(common.SavepointCase):
return picking
def _update_qty_in_location(self, location, product, quantity):
self.env["stock.quant"]._update_available_quantity(
product, location, quantity
)
self.env["stock.quant"]._update_available_quantity(product, location, quantity)
def _create_rule(self, rule_values, removal_values):
rule_config = {
@@ -113,6 +111,8 @@ class TestReserveRule(common.SavepointCase):
}
rule_config.update(rule_values)
self.env["stock.reserve.rule"].create(rule_config)
# workaround for https://github.com/odoo/odoo/pull/41900
self.env["stock.reserve.rule"].invalidate_cache()
def _setup_packagings(self, product, packagings):
"""Create packagings on a product
@@ -219,7 +219,7 @@ class TestReserveRule(common.SavepointCase):
],
)
self.assertEqual(move.state, "partially_available")
self.assertEqual(move.reserved_availability, 300.)
self.assertEqual(move.reserved_availability, 300.0)
def test_rule_fallback(self):
reserve = self.env["stock.location"].create(
@@ -254,7 +254,7 @@ class TestReserveRule(common.SavepointCase):
],
)
self.assertEqual(move.state, "assigned")
self.assertEqual(move.reserved_availability, 400.)
self.assertEqual(move.reserved_availability, 400.0)
def test_rule_domain(self):
self._update_qty_in_location(self.loc_zone1_bin1, self.product1, 100)
@@ -355,9 +355,9 @@ class TestReserveRule(common.SavepointCase):
self.assertRecordValues(
ml,
[
{"location_id": self.loc_zone1_bin2.id, "product_qty": 150.},
{"location_id": self.loc_zone2_bin1.id, "product_qty": 50.},
{"location_id": self.loc_zone3_bin1.id, "product_qty": 50.},
{"location_id": self.loc_zone1_bin2.id, "product_qty": 150.0},
{"location_id": self.loc_zone2_bin1.id, "product_qty": 50.0},
{"location_id": self.loc_zone3_bin1.id, "product_qty": 50.0},
],
)
self.assertEqual(move.state, "assigned")
@@ -389,8 +389,8 @@ class TestReserveRule(common.SavepointCase):
self.assertRecordValues(
ml,
[
{"location_id": self.loc_zone1_bin1.id, "product_qty": 50.},
{"location_id": self.loc_zone2_bin1.id, "product_qty": 30.},
{"location_id": self.loc_zone1_bin1.id, "product_qty": 50.0},
{"location_id": self.loc_zone2_bin1.id, "product_qty": 30.0},
],
)
self.assertEqual(move.state, "assigned")
@@ -424,8 +424,8 @@ class TestReserveRule(common.SavepointCase):
self.assertRecordValues(
ml,
[
{"location_id": self.loc_zone1_bin2.id, "product_qty": 60.},
{"location_id": self.loc_zone2_bin1.id, "product_qty": 20.},
{"location_id": self.loc_zone1_bin2.id, "product_qty": 60.0},
{"location_id": self.loc_zone2_bin1.id, "product_qty": 20.0},
],
)
self.assertEqual(move.state, "assigned")
@@ -433,10 +433,7 @@ class TestReserveRule(common.SavepointCase):
def test_rule_packaging(self):
self._setup_packagings(
self.product1,
[
("Pallet", 500, self.pallet),
("Retail Box", 50, self.retail_box),
],
[("Pallet", 500, self.pallet), ("Retail Box", 50, self.retail_box)],
)
self._update_qty_in_location(self.loc_zone1_bin1, self.product1, 40)
self._update_qty_in_location(self.loc_zone1_bin2, self.product1, 510)
@@ -470,9 +467,9 @@ class TestReserveRule(common.SavepointCase):
self.assertRecordValues(
ml,
[
{"location_id": self.loc_zone1_bin2.id, "product_qty": 500.},
{"location_id": self.loc_zone2_bin1.id, "product_qty": 50.},
{"location_id": self.loc_zone3_bin1.id, "product_qty": 40.},
{"location_id": self.loc_zone1_bin2.id, "product_qty": 500.0},
{"location_id": self.loc_zone2_bin1.id, "product_qty": 50.0},
{"location_id": self.loc_zone3_bin1.id, "product_qty": 40.0},
],
)
self.assertEqual(move.state, "assigned")
@@ -553,9 +550,9 @@ class TestReserveRule(common.SavepointCase):
self.assertRecordValues(
ml,
[
{"location_id": self.loc_zone1_bin2.id, "product_qty": 500.},
{"location_id": self.loc_zone2_bin2.id, "product_qty": 50.},
{"location_id": self.loc_zone3_bin1.id, "product_qty": 10.},
{"location_id": self.loc_zone1_bin2.id, "product_qty": 500.0},
{"location_id": self.loc_zone2_bin2.id, "product_qty": 50.0},
{"location_id": self.loc_zone3_bin1.id, "product_qty": 10.0},
],
)
self.assertEqual(move.state, "assigned")

View File

@@ -7,17 +7,20 @@
<field name="arch" type="xml">
<form string="Stock Reservation Rule">
<div class="oe_button_box" name="button_box">
<button name="toggle_active" type="object" class="oe_stat_button" icon="fa-archive">
<field name="active" widget="boolean_button" options='{"terminology": "archive"}'/>
</button>
</div>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<label for="name" class="oe_edit_only"/>
<h1><field name="name"/></h1>
<group string="Rule Applicability" name="configuration">
<field name="location_id"/>
<field name="fallback_location_id"/>
<field name="rule_domain" widget="domain" options="{'model': 'stock.move'}" />
<field name="company_id" groups="base.group_multi_company"/>
<group>
<field name="active" invisible="1"/>
<field name="location_id"/>
<field name="fallback_location_id"/>
</group>
<group>
<field name="rule_domain" widget="domain" options="{'model': 'stock.move', 'in_dialog': true}" />
<field name="company_id" groups="base.group_multi_company"/>
</group>
</group>
<group string="Removal Rules" name="rule">
<field name="rule_removal_ids" nolabel="1">
@@ -36,7 +39,7 @@
widget="many2many_tags"
attrs="{'invisible': [('removal_strategy', '!=', 'packaging')]}"
/>
<field name="quant_domain" widget="domain" options="{'model': 'stock.quant'}" />
<field name="quant_domain" widget="domain" options="{'model': 'stock.quant', 'in_dialog': true}" />
</group>
</form>
</field>
@@ -74,7 +77,6 @@
<field name="name">Stock Reservation Rules</field>
<field name="res_model">stock.reserve.rule</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_id" ref="view_stock_reserve_rule_tree"/>
<field name="search_view_id" ref="view_stock_reserve_rule_search"/>
<field name="context"></field>