mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] stock_inventory_discrepancy: black, isort
This commit is contained in:
@@ -1,24 +1,22 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
# (http://www.eficent.com)
|
||||
# Copyright 2017-2020 ForgeFlow S.L. (http://www.forgeflow.com)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
{
|
||||
"name": "Stock Inventory Discrepancy",
|
||||
"summary": "Adds the capability to show the discrepancy of every line in "
|
||||
"an inventory and to block the inventory validation when the "
|
||||
"discrepancy is over a user defined threshold.",
|
||||
"an inventory and to block the inventory validation when the "
|
||||
"discrepancy is over a user defined threshold.",
|
||||
"version": "12.0.1.0.0",
|
||||
"author": "Eficent, "
|
||||
"Odoo Community Association (OCA)",
|
||||
"author": "ForgeFlow, Odoo Community Association (OCA)",
|
||||
"website": "https://github.com/OCA/stock-logistics-warehouse",
|
||||
"category": "Warehouse Management",
|
||||
"depends": ["stock"],
|
||||
"data": [
|
||||
'security/stock_inventory_discrepancy_security.xml',
|
||||
'views/stock_inventory_view.xml',
|
||||
'views/stock_warehouse_view.xml',
|
||||
'views/stock_location_view.xml',
|
||||
"security/stock_inventory_discrepancy_security.xml",
|
||||
"views/stock_inventory_view.xml",
|
||||
"views/stock_warehouse_view.xml",
|
||||
"views/stock_location_view.xml",
|
||||
],
|
||||
"license": "AGPL-3",
|
||||
'installable': True,
|
||||
'application': False,
|
||||
"installable": True,
|
||||
"application": False,
|
||||
}
|
||||
|
||||
@@ -1,69 +1,76 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
# Copyright 2017-2020 ForgeFlow S.L.
|
||||
# (http://www.eficent.com)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models, _
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class StockInventory(models.Model):
|
||||
_inherit = 'stock.inventory'
|
||||
_inherit = "stock.inventory"
|
||||
|
||||
INVENTORY_STATE_SELECTION = [
|
||||
('draft', 'Draft'),
|
||||
('cancel', 'Cancelled'),
|
||||
('confirm', 'In Progress'),
|
||||
('pending', 'Pending to Approve'),
|
||||
('done', 'Validated')]
|
||||
("draft", "Draft"),
|
||||
("cancel", "Cancelled"),
|
||||
("confirm", "In Progress"),
|
||||
("pending", "Pending to Approve"),
|
||||
("done", "Validated"),
|
||||
]
|
||||
|
||||
state = fields.Selection(
|
||||
selection=INVENTORY_STATE_SELECTION,
|
||||
string='Status', readonly=True, index=True, copy=False,
|
||||
string="Status",
|
||||
readonly=True,
|
||||
index=True,
|
||||
copy=False,
|
||||
help="States of the Inventory Adjustment:\n"
|
||||
"- Draft: Inventory not started.\n"
|
||||
"- In Progress: Inventory in execution.\n"
|
||||
"- Pending to Approve: Inventory have some discrepancies "
|
||||
"greater than the predefined threshold and it's waiting for the "
|
||||
"Control Manager approval.\n"
|
||||
"- Validated: Inventory Approved.")
|
||||
"- Draft: Inventory not started.\n"
|
||||
"- In Progress: Inventory in execution.\n"
|
||||
"- Pending to Approve: Inventory have some discrepancies "
|
||||
"greater than the predefined threshold and it's waiting for the "
|
||||
"Control Manager approval.\n"
|
||||
"- Validated: Inventory Approved.",
|
||||
)
|
||||
over_discrepancy_line_count = fields.Integer(
|
||||
string='Number of Discrepancies Over Threshold',
|
||||
compute='_compute_over_discrepancy_line_count',
|
||||
store=True)
|
||||
string="Number of Discrepancies Over Threshold",
|
||||
compute="_compute_over_discrepancy_line_count",
|
||||
store=True,
|
||||
)
|
||||
|
||||
@api.multi
|
||||
@api.depends('line_ids.product_qty', 'line_ids.theoretical_qty')
|
||||
@api.depends("line_ids.product_qty", "line_ids.theoretical_qty")
|
||||
def _compute_over_discrepancy_line_count(self):
|
||||
for inventory in self:
|
||||
lines = inventory.line_ids.filtered(
|
||||
lambda line: line.discrepancy_percent > line.
|
||||
discrepancy_threshold
|
||||
lambda line: line.discrepancy_percent > line.discrepancy_threshold
|
||||
)
|
||||
inventory.over_discrepancy_line_count = len(lines)
|
||||
|
||||
@api.multi
|
||||
def action_over_discrepancies(self):
|
||||
self.write({'state': 'pending'})
|
||||
self.write({"state": "pending"})
|
||||
|
||||
def _check_group_inventory_validation_always(self):
|
||||
grp_inv_val = self.env.ref(
|
||||
'stock_inventory_discrepancy.group_'
|
||||
'stock_inventory_validation_always')
|
||||
"stock_inventory_discrepancy.group_" "stock_inventory_validation_always"
|
||||
)
|
||||
if grp_inv_val in self.env.user.groups_id:
|
||||
return True
|
||||
else:
|
||||
raise UserError(
|
||||
_('The Qty Update is over the Discrepancy Threshold.\n '
|
||||
'Please, contact a user with rights to perform '
|
||||
'this action.')
|
||||
_(
|
||||
"The Qty Update is over the Discrepancy Threshold.\n "
|
||||
"Please, contact a user with rights to perform "
|
||||
"this action."
|
||||
)
|
||||
)
|
||||
|
||||
def _action_done(self):
|
||||
for inventory in self:
|
||||
if (inventory.over_discrepancy_line_count and
|
||||
inventory.line_ids.filtered(
|
||||
lambda t: t.discrepancy_threshold > 0.0)):
|
||||
if inventory.env.context.get('normal_view', False):
|
||||
if inventory.over_discrepancy_line_count and inventory.line_ids.filtered(
|
||||
lambda t: t.discrepancy_threshold > 0.0
|
||||
):
|
||||
if inventory.env.context.get("normal_view", False):
|
||||
inventory.action_over_discrepancies()
|
||||
return True
|
||||
else:
|
||||
|
||||
@@ -1,41 +1,46 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
# Copyright 2017-2020 ForgeFlow S.L.
|
||||
# (http://www.eficent.com)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo import api, fields, models
|
||||
|
||||
from odoo.addons import decimal_precision as dp
|
||||
|
||||
|
||||
class StockInventoryLine(models.Model):
|
||||
_inherit = 'stock.inventory.line'
|
||||
_inherit = "stock.inventory.line"
|
||||
|
||||
discrepancy_qty = fields.Float(
|
||||
string='Discrepancy',
|
||||
compute='_compute_discrepancy',
|
||||
string="Discrepancy",
|
||||
compute="_compute_discrepancy",
|
||||
help="The difference between the actual qty counted and the "
|
||||
"theoretical quantity on hand.",
|
||||
digits=dp.get_precision('Product Unit of Measure'), default=0)
|
||||
"theoretical quantity on hand.",
|
||||
digits=dp.get_precision("Product Unit of Measure"),
|
||||
default=0,
|
||||
)
|
||||
discrepancy_percent = fields.Float(
|
||||
string='Discrepancy percent (%)',
|
||||
compute='_compute_discrepancy',
|
||||
string="Discrepancy percent (%)",
|
||||
compute="_compute_discrepancy",
|
||||
digits=(3, 2),
|
||||
help="The discrepancy expressed in percent with theoretical quantity "
|
||||
"as basis")
|
||||
"as basis",
|
||||
)
|
||||
discrepancy_threshold = fields.Float(
|
||||
string='Threshold (%)',
|
||||
string="Threshold (%)",
|
||||
digits=(3, 2),
|
||||
help="Maximum Discrepancy Rate Threshold",
|
||||
compute='_compute_discrepancy_threshold')
|
||||
compute="_compute_discrepancy_threshold",
|
||||
)
|
||||
|
||||
@api.multi
|
||||
@api.depends('theoretical_qty', 'product_qty')
|
||||
@api.depends("theoretical_qty", "product_qty")
|
||||
def _compute_discrepancy(self):
|
||||
for line in self:
|
||||
line.discrepancy_qty = line.product_qty - line.theoretical_qty
|
||||
if line.theoretical_qty:
|
||||
line.discrepancy_percent = 100 * abs(
|
||||
(line.product_qty - line.theoretical_qty) /
|
||||
line.theoretical_qty)
|
||||
(line.product_qty - line.theoretical_qty) / line.theoretical_qty
|
||||
)
|
||||
elif not line.theoretical_qty and line.product_qty:
|
||||
line.discrepancy_percent = 100.0
|
||||
|
||||
@@ -44,8 +49,7 @@ class StockInventoryLine(models.Model):
|
||||
for line in self:
|
||||
whs = line.location_id.get_warehouse()
|
||||
if line.location_id.discrepancy_threshold > 0.0:
|
||||
line.discrepancy_threshold = line.location_id.\
|
||||
discrepancy_threshold
|
||||
line.discrepancy_threshold = line.location_id.discrepancy_threshold
|
||||
elif whs.discrepancy_threshold > 0.0:
|
||||
line.discrepancy_threshold = whs.discrepancy_threshold
|
||||
else:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
# Copyright 2017-2020 ForgeFlow S.L.
|
||||
# (http://www.eficent.com)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
@@ -6,11 +6,12 @@ from odoo import fields, models
|
||||
|
||||
|
||||
class StockLocation(models.Model):
|
||||
_inherit = 'stock.location'
|
||||
_inherit = "stock.location"
|
||||
|
||||
discrepancy_threshold = fields.Float(
|
||||
string='Maximum Discrepancy Rate Threshold',
|
||||
string="Maximum Discrepancy Rate Threshold",
|
||||
digits=(3, 2),
|
||||
help="Maximum Discrepancy Rate allowed for any product when doing "
|
||||
"an Inventory Adjustment. Thresholds defined in Locations have "
|
||||
"preference over Warehouse's ones.")
|
||||
"an Inventory Adjustment. Thresholds defined in Locations have "
|
||||
"preference over Warehouse's ones.",
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
# Copyright 2017-2020 ForgeFlow S.L.
|
||||
# (http://www.eficent.com)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
@@ -6,11 +6,12 @@ from odoo import fields, models
|
||||
|
||||
|
||||
class StockWarehouse(models.Model):
|
||||
_inherit = 'stock.warehouse'
|
||||
_inherit = "stock.warehouse"
|
||||
|
||||
discrepancy_threshold = fields.Float(
|
||||
string='Maximum Discrepancy Rate Threshold',
|
||||
string="Maximum Discrepancy Rate Threshold",
|
||||
digits=(3, 2),
|
||||
help="Maximum Discrepancy Rate allowed for any product when doing "
|
||||
"an Inventory Adjustment. Threshold defined in involved Location "
|
||||
"has preference.")
|
||||
"an Inventory Adjustment. Threshold defined in involved Location "
|
||||
"has preference.",
|
||||
)
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
* Lois Rilo <lois.rilo@eficent.com>
|
||||
* Lois Rilo <lois.rilo@forgeflow.com>
|
||||
* Andreas Dian Sukarno Putro <andreasdian777@gmail.com>
|
||||
* Bhavesh Odedra <bodedra@opensourceintegrators.com>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
<!-- Copyright 2017-2020 ForgeFlow S.L.
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
|
||||
<odoo noupdate="1">
|
||||
|
||||
@@ -1,172 +1,217 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
# Copyright 2017-2020 ForgeFlow S.L.
|
||||
# (http://www.eficent.com)
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tests.common import TransactionCase
|
||||
|
||||
|
||||
class TestInventoryDiscrepancy(TransactionCase):
|
||||
def setUp(self, *args, **kwargs):
|
||||
super(TestInventoryDiscrepancy, self).setUp(*args, **kwargs)
|
||||
self.obj_wh = self.env['stock.warehouse']
|
||||
self.obj_location = self.env['stock.location']
|
||||
self.obj_inventory = self.env['stock.inventory']
|
||||
self.obj_product = self.env['product.product']
|
||||
self.obj_warehouse = self.env['stock.warehouse']
|
||||
self.obj_upd_qty_wizard = self.env['stock.change.product.qty']
|
||||
self.obj_wh = self.env["stock.warehouse"]
|
||||
self.obj_location = self.env["stock.location"]
|
||||
self.obj_inventory = self.env["stock.inventory"]
|
||||
self.obj_product = self.env["product.product"]
|
||||
self.obj_warehouse = self.env["stock.warehouse"]
|
||||
self.obj_upd_qty_wizard = self.env["stock.change.product.qty"]
|
||||
|
||||
self.product1 = self.obj_product.create({
|
||||
'name': 'Test Product 1',
|
||||
'type': 'product',
|
||||
'default_code': 'PROD1',
|
||||
})
|
||||
self.product2 = self.obj_product.create({
|
||||
'name': 'Test Product 2',
|
||||
'type': 'product',
|
||||
'default_code': 'PROD2',
|
||||
})
|
||||
self.test_loc = self.obj_location.create({
|
||||
'name': 'Test Location',
|
||||
'usage': 'internal',
|
||||
'discrepancy_threshold': 0.1
|
||||
})
|
||||
self.test_wh = self.obj_warehouse.create({
|
||||
'name': 'Test WH',
|
||||
'code': 'T',
|
||||
'discrepancy_threshold': 0.2
|
||||
})
|
||||
self.product1 = self.obj_product.create(
|
||||
{"name": "Test Product 1", "type": "product", "default_code": "PROD1"}
|
||||
)
|
||||
self.product2 = self.obj_product.create(
|
||||
{"name": "Test Product 2", "type": "product", "default_code": "PROD2"}
|
||||
)
|
||||
self.test_loc = self.obj_location.create(
|
||||
{"name": "Test Location", "usage": "internal", "discrepancy_threshold": 0.1}
|
||||
)
|
||||
self.test_wh = self.obj_warehouse.create(
|
||||
{"name": "Test WH", "code": "T", "discrepancy_threshold": 0.2}
|
||||
)
|
||||
self.obj_location._parent_store_compute()
|
||||
|
||||
# Create Stock manager able to force validation on inventories.
|
||||
group_stock_man = self.env.ref('stock.group_stock_manager')
|
||||
group_stock_man = self.env.ref("stock.group_stock_manager")
|
||||
group_inventory_all = self.env.ref(
|
||||
'stock_inventory_discrepancy.'
|
||||
'group_stock_inventory_validation_always')
|
||||
self.manager = self.env['res.users'].create({
|
||||
'name': 'Test Manager',
|
||||
'login': 'manager',
|
||||
'email': 'test.manager@example.com',
|
||||
'groups_id': [(6, 0, [group_stock_man.id, group_inventory_all.id])]
|
||||
})
|
||||
group_stock_user = self.env.ref('stock.group_stock_user')
|
||||
self.user = self.env['res.users'].create({
|
||||
'name': 'Test User',
|
||||
'login': 'user',
|
||||
'email': 'test.user@example.com',
|
||||
'groups_id': [(6, 0, [group_stock_user.id])]
|
||||
})
|
||||
"stock_inventory_discrepancy." "group_stock_inventory_validation_always"
|
||||
)
|
||||
self.manager = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test Manager",
|
||||
"login": "manager",
|
||||
"email": "test.manager@example.com",
|
||||
"groups_id": [(6, 0, [group_stock_man.id, group_inventory_all.id])],
|
||||
}
|
||||
)
|
||||
group_stock_user = self.env.ref("stock.group_stock_user")
|
||||
self.user = self.env["res.users"].create(
|
||||
{
|
||||
"name": "Test User",
|
||||
"login": "user",
|
||||
"email": "test.user@example.com",
|
||||
"groups_id": [(6, 0, [group_stock_user.id])],
|
||||
}
|
||||
)
|
||||
|
||||
starting_inv = self.obj_inventory.create({
|
||||
'name': 'Starting inventory',
|
||||
'filter': 'product',
|
||||
'line_ids': [
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_id': self.env.ref(
|
||||
"uom.product_uom_unit").id,
|
||||
'product_qty': 2.0,
|
||||
'location_id': self.test_loc.id,
|
||||
}),
|
||||
(0, 0, {
|
||||
'product_id': self.product2.id,
|
||||
'product_uom_id': self.env.ref(
|
||||
"uom.product_uom_unit").id,
|
||||
'product_qty': 4.0,
|
||||
'location_id': self.test_loc.id,
|
||||
}),
|
||||
],
|
||||
})
|
||||
starting_inv = self.obj_inventory.create(
|
||||
{
|
||||
"name": "Starting inventory",
|
||||
"filter": "product",
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product1.id,
|
||||
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
|
||||
"product_qty": 2.0,
|
||||
"location_id": self.test_loc.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product2.id,
|
||||
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
|
||||
"product_qty": 4.0,
|
||||
"location_id": self.test_loc.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
starting_inv.action_force_done()
|
||||
|
||||
def test_compute_discrepancy(self):
|
||||
"""Tests if the discrepancy is correctly computed.
|
||||
"""
|
||||
inventory = self.obj_inventory.create({
|
||||
'name': 'Test Discrepancy Computation',
|
||||
'location_id': self.test_loc.id,
|
||||
'filter': 'none',
|
||||
'line_ids': [
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_id': self.env.ref(
|
||||
"uom.product_uom_unit").id,
|
||||
'product_qty': 3.0,
|
||||
'location_id': self.test_loc.id,
|
||||
}),
|
||||
(0, 0, {
|
||||
'product_id': self.product2.id,
|
||||
'product_uom_id': self.env.ref(
|
||||
"uom.product_uom_unit").id,
|
||||
'product_qty': 3.0,
|
||||
'location_id': self.test_loc.id,
|
||||
})
|
||||
],
|
||||
})
|
||||
self.assertEqual(inventory.line_ids[0].discrepancy_qty, 1.0,
|
||||
'Wrong Discrepancy qty computation.')
|
||||
self.assertEqual(inventory.line_ids[1].discrepancy_qty, - 1.0,
|
||||
'Wrong Discrepancy qty computation.')
|
||||
inventory = self.obj_inventory.create(
|
||||
{
|
||||
"name": "Test Discrepancy Computation",
|
||||
"location_id": self.test_loc.id,
|
||||
"filter": "none",
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product1.id,
|
||||
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
|
||||
"product_qty": 3.0,
|
||||
"location_id": self.test_loc.id,
|
||||
},
|
||||
),
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product2.id,
|
||||
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
|
||||
"product_qty": 3.0,
|
||||
"location_id": self.test_loc.id,
|
||||
},
|
||||
),
|
||||
],
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
inventory.line_ids[0].discrepancy_qty,
|
||||
1.0,
|
||||
"Wrong Discrepancy qty computation.",
|
||||
)
|
||||
self.assertEqual(
|
||||
inventory.line_ids[1].discrepancy_qty,
|
||||
-1.0,
|
||||
"Wrong Discrepancy qty computation.",
|
||||
)
|
||||
|
||||
def test_discrepancy_validation(self):
|
||||
"""Tests the new workflow"""
|
||||
inventory = self.obj_inventory.create({
|
||||
'name': 'Test Forcing Validation Method',
|
||||
'location_id': self.test_loc.id,
|
||||
'filter': 'none',
|
||||
'line_ids': [
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_id': self.env.ref(
|
||||
"uom.product_uom_unit").id,
|
||||
'product_qty': 3.0,
|
||||
'location_id': self.test_loc.id,
|
||||
}),
|
||||
],
|
||||
})
|
||||
self.assertEqual(inventory.state, 'draft',
|
||||
'Testing Inventory wrongly configurated')
|
||||
self.assertEqual(inventory.line_ids.discrepancy_threshold, 0.1,
|
||||
'Threshold wrongly computed in Inventory Line.')
|
||||
inventory.with_context({'normal_view': True}).action_validate()
|
||||
self.assertEqual(inventory.over_discrepancy_line_count, 1,
|
||||
'Computation of over-discrepancies failed.')
|
||||
self.assertEqual(inventory.state, 'pending',
|
||||
'Inventory Adjustment not changing to Pending to '
|
||||
'Approve.')
|
||||
inventory = self.obj_inventory.create(
|
||||
{
|
||||
"name": "Test Forcing Validation Method",
|
||||
"location_id": self.test_loc.id,
|
||||
"filter": "none",
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product1.id,
|
||||
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
|
||||
"product_qty": 3.0,
|
||||
"location_id": self.test_loc.id,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
inventory.state, "draft", "Testing Inventory wrongly configurated"
|
||||
)
|
||||
self.assertEqual(
|
||||
inventory.line_ids.discrepancy_threshold,
|
||||
0.1,
|
||||
"Threshold wrongly computed in Inventory Line.",
|
||||
)
|
||||
inventory.with_context({"normal_view": True}).action_validate()
|
||||
self.assertEqual(
|
||||
inventory.over_discrepancy_line_count,
|
||||
1,
|
||||
"Computation of over-discrepancies failed.",
|
||||
)
|
||||
self.assertEqual(
|
||||
inventory.state,
|
||||
"pending",
|
||||
"Inventory Adjustment not changing to Pending to " "Approve.",
|
||||
)
|
||||
inventory.sudo(self.manager).action_force_done()
|
||||
self.assertEqual(inventory.state, 'done',
|
||||
'Forcing the validation of the inventory adjustment '
|
||||
'not working properly.')
|
||||
self.assertEqual(
|
||||
inventory.state,
|
||||
"done",
|
||||
"Forcing the validation of the inventory adjustment "
|
||||
"not working properly.",
|
||||
)
|
||||
|
||||
def test_warehouse_threshold(self):
|
||||
"""Tests the behaviour if the threshold is set on the WH."""
|
||||
inventory = self.obj_inventory.create({
|
||||
'name': 'Test Threshold Defined in WH',
|
||||
'location_id': self.test_wh.view_location_id.id,
|
||||
'filter': 'none',
|
||||
'line_ids': [
|
||||
(0, 0, {
|
||||
'product_id': self.product1.id,
|
||||
'product_uom_id': self.env.ref(
|
||||
"uom.product_uom_unit").id,
|
||||
'product_qty': 3.0,
|
||||
'location_id': self.test_wh.lot_stock_id.id,
|
||||
}),
|
||||
],
|
||||
})
|
||||
self.assertEqual(inventory.line_ids.discrepancy_threshold, 0.2,
|
||||
'Threshold wrongly computed in Inventory Line.')
|
||||
inventory = self.obj_inventory.create(
|
||||
{
|
||||
"name": "Test Threshold Defined in WH",
|
||||
"location_id": self.test_wh.view_location_id.id,
|
||||
"filter": "none",
|
||||
"line_ids": [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"product_id": self.product1.id,
|
||||
"product_uom_id": self.env.ref("uom.product_uom_unit").id,
|
||||
"product_qty": 3.0,
|
||||
"location_id": self.test_wh.lot_stock_id.id,
|
||||
},
|
||||
)
|
||||
],
|
||||
}
|
||||
)
|
||||
self.assertEqual(
|
||||
inventory.line_ids.discrepancy_threshold,
|
||||
0.2,
|
||||
"Threshold wrongly computed in Inventory Line.",
|
||||
)
|
||||
|
||||
def test_update_qty_user_error(self):
|
||||
"""Test if a user error raises when a stock user tries to update the
|
||||
qty for a product and the correction is a discrepancy over the
|
||||
threshold."""
|
||||
upd_qty = self.obj_upd_qty_wizard.sudo(self.user).create({
|
||||
'product_id': self.product1.id,
|
||||
'product_tmpl_id': self.product1.product_tmpl_id.id,
|
||||
'new_quantity': 10.0,
|
||||
'location_id': self.test_loc.id,
|
||||
})
|
||||
upd_qty = self.obj_upd_qty_wizard.sudo(self.user).create(
|
||||
{
|
||||
"product_id": self.product1.id,
|
||||
"product_tmpl_id": self.product1.product_tmpl_id.id,
|
||||
"new_quantity": 10.0,
|
||||
"location_id": self.test_loc.id,
|
||||
}
|
||||
)
|
||||
with self.assertRaises(UserError):
|
||||
upd_qty.change_product_qty()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
<!-- Copyright 2017-2020 ForgeFlow S.L.
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
|
||||
<odoo>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
<!-- Copyright 2017-2020 ForgeFlow S.L.
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
|
||||
<odoo>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
|
||||
<!-- Copyright 2017-2020 ForgeFlow S.L.
|
||||
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
|
||||
|
||||
<odoo>
|
||||
|
||||
Reference in New Issue
Block a user