[IMP] stock_inventory_verification_request: black, isort, prettier

This commit is contained in:
Joan Sisquella
2024-07-29 15:49:55 +02:00
parent fc79936d91
commit b22c141b7c
12 changed files with 534 additions and 389 deletions

View File

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

View File

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

View File

@@ -4,11 +4,10 @@
{
"name": "Stock Inventory Verification Request",
"summary": "Adds the capability to request a Slot Verification when "
"a inventory is Pending to Approve",
"a inventory is Pending to Approve",
"version": "12.0.3.0.1",
"maintainers": ['LoisRForgeFlow'],
"author": "ForgeFlow, "
"Odoo Community Association (OCA)",
"maintainers": ["LoisRForgeFlow"],
"author": "ForgeFlow, " "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"category": "Warehouse",
"depends": [
@@ -16,14 +15,14 @@
"mail",
],
"data": [
'security/ir.model.access.csv',
'security/stock_security.xml',
'views/stock_slot_verification_request_view.xml',
'views/stock_inventory_view.xml',
'views/stock_location_view.xml',
'data/slot_verification_request_sequence.xml',
"security/ir.model.access.csv",
"security/stock_security.xml",
"views/stock_slot_verification_request_view.xml",
"views/stock_inventory_view.xml",
"views/stock_location_view.xml",
"data/slot_verification_request_sequence.xml",
],
"license": "AGPL-3",
'installable': True,
'application': False,
"installable": True,
"application": False,
}

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ForgeFlow S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo noupdate="1">
<record id="seq_slot_verification_request" model="ir.sequence">
@@ -9,7 +8,7 @@
<field name="code">stock.slot.verification.request</field>
<field name="prefix">SVR/%(range_year)s/</field>
<field name="padding">5</field>
<field name="company_id" eval="False"/>
<field name="company_id" eval="False" />
</record>
</odoo>

View File

@@ -6,16 +6,19 @@ from odoo import api, fields, models
class StockInventory(models.Model):
_inherit = 'stock.inventory'
_inherit = "stock.inventory"
requested_verification = fields.Boolean(
string='Requested Verification?', copy=False)
string="Requested Verification?", copy=False
)
slot_verification_ids = fields.One2many(
comodel_name='stock.slot.verification.request',
string='Slot Verification Requests', inverse_name='inventory_id')
comodel_name="stock.slot.verification.request",
string="Slot Verification Requests",
inverse_name="inventory_id",
)
solving_slot_verification_request_id = fields.Many2one(
comodel_name="stock.slot.verification.request",
help="This Inventory adjustment was created from the specified SVR."
help="This Inventory adjustment was created from the specified SVR.",
)
@api.multi
@@ -23,41 +26,48 @@ class StockInventory(models.Model):
self.ensure_one()
self.requested_verification = True
for line in self.line_ids:
if line.discrepancy_threshold and (line.discrepancy_percent >
line.discrepancy_threshold):
self.env['stock.slot.verification.request'].create({
'inventory_id': self.id,
'inventory_line_id': line.id,
'location_id': line.location_id.id,
'state': 'wait',
'product_id': line.product_id.id,
'company_id': self.company_id.id,
})
if line.discrepancy_threshold and (
line.discrepancy_percent > line.discrepancy_threshold
):
self.env["stock.slot.verification.request"].create(
{
"inventory_id": self.id,
"inventory_line_id": line.id,
"location_id": line.location_id.id,
"state": "wait",
"product_id": line.product_id.id,
"company_id": self.company_id.id,
}
)
class StockInventoryLine(models.Model):
_inherit = 'stock.inventory.line'
_rec_name = 'product_id'
_inherit = "stock.inventory.line"
_rec_name = "product_id"
slot_verification_ids = fields.One2many(
comodel_name='stock.slot.verification.request',
inverse_name='inventory_line_id',
string='Slot Verification Request')
comodel_name="stock.slot.verification.request",
inverse_name="inventory_line_id",
string="Slot Verification Request",
)
@api.multi
def action_open_svr(self):
"""Open the corresponding Slot Verification Request directly from the
Inventory Lines."""
request_svr_ids = self.mapped('slot_verification_ids').ids
action = self.env.ref('stock_inventory_verification_request.'
'action_slot_verification_request')
request_svr_ids = self.mapped("slot_verification_ids").ids
action = self.env.ref(
"stock_inventory_verification_request." "action_slot_verification_request"
)
result = action.read()[0]
if len(request_svr_ids) > 1:
result['domain'] = [('id', 'in', request_svr_ids)]
result["domain"] = [("id", "in", request_svr_ids)]
elif len(request_svr_ids) == 1:
view = self.env.ref(
'stock_inventory_verification_request.stock_'
'slot_verification_request_form_view', False)
result['views'] = [(view and view.id or False, 'form')]
result['res_id'] = request_svr_ids[0] or False
"stock_inventory_verification_request.stock_"
"slot_verification_request_form_view",
False,
)
result["views"] = [(view and view.id or False, "form")]
result["res_id"] = request_svr_ids[0] or False
return result

View File

@@ -10,22 +10,27 @@ class StockLocation(models.Model):
slot_verification_ids = fields.One2many(
comodel_name="stock.slot.verification.request",
string="Slot Verification Requests", inverse_name="location_id")
string="Slot Verification Requests",
inverse_name="location_id",
)
@api.multi
def action_open_svr(self):
"""Open the corresponding Slot Verification Request directly from the
Location."""
request_svr_ids = self.mapped("slot_verification_ids").ids
action = self.env.ref("stock_inventory_verification_request."
"action_slot_verification_request")
action = self.env.ref(
"stock_inventory_verification_request." "action_slot_verification_request"
)
result = action.read()[0]
if len(request_svr_ids) > 1:
result["domain"] = [("id", "in", request_svr_ids)]
elif len(request_svr_ids) == 1:
view = self.env.ref(
"stock_inventory_verification_request.stock_"
"slot_verification_request_form_view", False)
"slot_verification_request_form_view",
False,
)
result["views"] = [(view and view.id or False, "form")]
result["res_id"] = request_svr_ids[0] or False
return result

View File

@@ -6,20 +6,22 @@ from odoo import api, fields, models
class SlotVerificationRequest(models.Model):
_name = 'stock.slot.verification.request'
_inherit = 'mail.thread'
_name = "stock.slot.verification.request"
_inherit = "mail.thread"
_description = "Slot Verification Request"
@api.model
def _default_company(self):
company_id = self.env['res.company']._company_default_get(self._name)
company_id = self.env["res.company"]._company_default_get(self._name)
return company_id
@api.model
def create(self, vals):
if not vals.get('name') or vals.get('name') == '/':
vals['name'] = self.env['ir.sequence'].next_by_code(
'stock.slot.verification.request') or '/'
if not vals.get("name") or vals.get("name") == "/":
vals["name"] = (
self.env["ir.sequence"].next_by_code("stock.slot.verification.request")
or "/"
)
return super(SlotVerificationRequest, self).create(vals)
@api.multi
@@ -38,164 +40,182 @@ class SlotVerificationRequest(models.Model):
rec.created_inventory_count = len(rec.created_inventory_ids)
name = fields.Char(
default="/", required=True,
readonly=True, states={'wait': [('readonly', False)]})
inventory_id = fields.Many2one(
comodel_name='stock.inventory',
string='Inventory Adjustment',
readonly=True)
inventory_line_id = fields.Many2one(
comodel_name='stock.inventory.line',
string='Inventory Line',
readonly=True)
location_id = fields.Many2one(
comodel_name='stock.location',
string='Location',
default="/",
required=True,
readonly=True, states={'wait': [('readonly', False)]},
readonly=True,
states={"wait": [("readonly", False)]},
)
inventory_id = fields.Many2one(
comodel_name="stock.inventory", string="Inventory Adjustment", readonly=True
)
inventory_line_id = fields.Many2one(
comodel_name="stock.inventory.line", string="Inventory Line", readonly=True
)
location_id = fields.Many2one(
comodel_name="stock.location",
string="Location",
required=True,
readonly=True,
states={"wait": [("readonly", False)]},
track_visibility="onchange",
)
company_id = fields.Many2one(
comodel_name='res.company', string='Company',
comodel_name="res.company",
string="Company",
required=True,
default=_default_company,
readonly=True,
)
state = fields.Selection(selection=[
('wait', 'Waiting Actions'),
('open', 'In Progress'),
('cancelled', 'Cancelled'),
('done', 'Solved')
], string='Status', default='wait',
state = fields.Selection(
selection=[
("wait", "Waiting Actions"),
("open", "In Progress"),
("cancelled", "Cancelled"),
("done", "Solved"),
],
string="Status",
default="wait",
track_visibility="onchange",
)
responsible_id = fields.Many2one(
comodel_name='res.users',
string='Assigned to',
comodel_name="res.users",
string="Assigned to",
track_visibility="onchange",
)
product_id = fields.Many2one(
comodel_name='product.product',
string='Product',
readonly=True, states={'wait': [('readonly', False)]},
comodel_name="product.product",
string="Product",
readonly=True,
states={"wait": [("readonly", False)]},
track_visibility="onchange",
)
notes = fields.Text(string='Notes')
notes = fields.Text(string="Notes")
involved_move_ids = fields.Many2many(
comodel_name='stock.move',
relation='slot_verification_move_involved_rel',
column1='slot_verification_request_id',
column2='move_id',
string='Involved Stock Moves')
involved_move_count = fields.Integer(
compute='_compute_involved_move_count'
comodel_name="stock.move",
relation="slot_verification_move_involved_rel",
column1="slot_verification_request_id",
column2="move_id",
string="Involved Stock Moves",
)
involved_move_count = fields.Integer(compute="_compute_involved_move_count")
involved_inv_line_ids = fields.Many2many(
comodel_name='stock.inventory.line',
relation='slot_verification_inv_line_involved_rel',
column1='slot_verification_request_id',
column2='inventory_line_id',
string='Involved Inventory Lines')
involved_inv_line_count = fields.Integer(
compute='_compute_involved_inv_line_count')
comodel_name="stock.inventory.line",
relation="slot_verification_inv_line_involved_rel",
column1="slot_verification_request_id",
column2="inventory_line_id",
string="Involved Inventory Lines",
)
involved_inv_line_count = fields.Integer(compute="_compute_involved_inv_line_count")
created_inventory_ids = fields.One2many(
comodel_name="stock.inventory",
string="Created Inventories",
inverse_name="solving_slot_verification_request_id",
help="These inventory adjustment were created from this SVR.",
)
created_inventory_count = fields.Integer(
compute='_compute_created_inventory_count')
created_inventory_count = fields.Integer(compute="_compute_created_inventory_count")
@api.multi
def _get_involved_moves_domain(self):
domain = ['|', ('location_id', '=', self.location_id.id),
('location_dest_id', '=', self.location_id.id)]
domain = [
"|",
("location_id", "=", self.location_id.id),
("location_dest_id", "=", self.location_id.id),
]
if self.product_id:
domain.append(('product_id', '=', self.product_id.id))
domain.append(("product_id", "=", self.product_id.id))
return domain
@api.multi
def _get_involved_lines_domain(self):
domain = [('location_id', '=', self.location_id.id)]
domain = [("location_id", "=", self.location_id.id)]
if self.product_id:
domain.append(('product_id', '=', self.product_id.id))
domain.append(("product_id", "=", self.product_id.id))
return domain
@api.multi
def _get_involved_lines_and_locations(self):
involved_moves = self.env['stock.move'].search(
self._get_involved_moves_domain())
involved_lines = self.env['stock.inventory.line'].search(
self._get_involved_lines_domain())
involved_moves = self.env["stock.move"].search(
self._get_involved_moves_domain()
)
involved_lines = self.env["stock.inventory.line"].search(
self._get_involved_lines_domain()
)
return involved_moves, involved_lines
@api.multi
def action_confirm(self):
self.write({'state': 'open'})
self.write({"state": "open"})
for rec in self:
involved_moves, involved_lines = \
rec._get_involved_lines_and_locations()
involved_moves, involved_lines = rec._get_involved_lines_and_locations()
rec.involved_move_ids = involved_moves
rec.involved_inv_line_ids = involved_lines
return True
@api.multi
def action_cancel(self):
self.write({'state': 'cancelled'})
self.write({"state": "cancelled"})
return True
@api.multi
def action_solved(self):
self.write({'state': 'done'})
self.write({"state": "done"})
return True
@api.multi
def action_view_moves(self):
action = self.env.ref('stock.stock_move_action')
action = self.env.ref("stock.stock_move_action")
result = action.read()[0]
result['context'] = {}
moves_ids = self.mapped('involved_move_ids').ids
result["context"] = {}
moves_ids = self.mapped("involved_move_ids").ids
if len(moves_ids) > 1:
result['domain'] = [('id', 'in', moves_ids)]
result["domain"] = [("id", "in", moves_ids)]
elif len(moves_ids) == 1:
res = self.env.ref('stock.view_move_form', False)
result['views'] = [(res and res.id or False, 'form')]
result['res_id'] = moves_ids and moves_ids[0] or False
res = self.env.ref("stock.view_move_form", False)
result["views"] = [(res and res.id or False, "form")]
result["res_id"] = moves_ids and moves_ids[0] or False
return result
@api.multi
def action_view_inv_lines(self):
action = self.env.ref(
'stock_inventory_verification_request.action_inv_adj_line_tree')
"stock_inventory_verification_request.action_inv_adj_line_tree"
)
result = action.read()[0]
result['context'] = {}
line_ids = self.mapped('involved_inv_line_ids').ids
result["context"] = {}
line_ids = self.mapped("involved_inv_line_ids").ids
if len(line_ids) > 1:
result['domain'] = [('id', 'in', line_ids)]
result["domain"] = [("id", "in", line_ids)]
elif len(line_ids) == 1:
res = self.env.ref('stock_inventory_verification_request.'
'view_inventory_line_form', False)
result['views'] = [(res and res.id or False, 'form')]
result['res_id'] = line_ids and line_ids[0] or False
res = self.env.ref(
"stock_inventory_verification_request." "view_inventory_line_form",
False,
)
result["views"] = [(res and res.id or False, "form")]
result["res_id"] = line_ids and line_ids[0] or False
return result
def action_create_inventory_adjustment(self):
self.ensure_one()
inventory = self.env["stock.inventory"].sudo().create({
"name": "Inventory Adjustment from %s" % self.name,
"filter": "product" if self.product_id else "none",
"location_id": self.location_id.id,
"product_id": self.product_id.id,
"solving_slot_verification_request_id": self.id,
"company_id": self.company_id.id,
})
action = self.env.ref('stock.action_inventory_form')
inventory = (
self.env["stock.inventory"]
.sudo()
.create(
{
"name": "Inventory Adjustment from %s" % self.name,
"filter": "product" if self.product_id else "none",
"location_id": self.location_id.id,
"product_id": self.product_id.id,
"solving_slot_verification_request_id": self.id,
"company_id": self.company_id.id,
}
)
)
action = self.env.ref("stock.action_inventory_form")
result = action.read()[0]
res = self.env.ref('stock.view_inventory_form', False)
result['views'] = [(res and res.id or False, 'form')]
result['res_id'] = inventory.id
res = self.env.ref("stock.view_inventory_form", False)
result["views"] = [(res and res.id or False, "form")]
result["res_id"] = inventory.id
return result
@api.multi

View File

@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record id="stock_slot_verification_request_comp_rule" model="ir.rule">
<field name="name">Stock Slot Verification Request multi-company</field>
<field name="model_id" ref="model_stock_slot_verification_request"/>
<field name="global" eval="True"/>
<field name="domain_force">['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
<field name="model_id" ref="model_stock_slot_verification_request" />
<field name="global" eval="True" />
<field
name="domain_force"
>['|',('company_id','=',False),('company_id','child_of',[user.company_id.id])]</field>
</record>
</odoo>

View File

@@ -7,146 +7,181 @@ from odoo.exceptions import AccessError
class TestStockVerificationRequest(common.SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
# disable tracking test suite wise
cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True))
cls.user_model = cls.env["res.users"].with_context(
no_reset_password=True)
cls.user_model = cls.env["res.users"].with_context(no_reset_password=True)
cls.obj_wh = cls.env['stock.warehouse']
cls.obj_location = cls.env['stock.location']
cls.obj_inventory = cls.env['stock.inventory']
cls.obj_product = cls.env['product.product']
cls.obj_svr = cls.env['stock.slot.verification.request']
cls.obj_move = cls.env['stock.move']
cls.obj_wh = cls.env["stock.warehouse"]
cls.obj_location = cls.env["stock.location"]
cls.obj_inventory = cls.env["stock.inventory"]
cls.obj_product = cls.env["product.product"]
cls.obj_svr = cls.env["stock.slot.verification.request"]
cls.obj_move = cls.env["stock.move"]
cls.product1 = cls.obj_product.create({
'name': 'Test Product 1',
'type': 'product',
'default_code': 'PROD1',
})
cls.product2 = cls.obj_product.create({
'name': 'Test Product 2',
'type': 'product',
'default_code': 'PROD2',
})
cls.test_loc = cls.obj_location.create({
'name': 'Test Location',
'usage': 'internal',
'discrepancy_threshold': 0.1
})
cls.product1 = cls.obj_product.create(
{
"name": "Test Product 1",
"type": "product",
"default_code": "PROD1",
}
)
cls.product2 = cls.obj_product.create(
{
"name": "Test Product 2",
"type": "product",
"default_code": "PROD2",
}
)
cls.test_loc = cls.obj_location.create(
{"name": "Test Location", "usage": "internal", "discrepancy_threshold": 0.1}
)
# Create Stock manager able to force validation on inventories.
group_stock_man = cls.env.ref('stock.group_stock_manager')
group_stock_man = cls.env.ref("stock.group_stock_manager")
group_inventory_all = cls.env.ref(
'stock_inventory_discrepancy.'
'group_stock_inventory_validation_always')
cls.manager = cls.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 = cls.env.ref('stock.group_stock_user')
cls.user = cls.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"
)
cls.manager = cls.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 = cls.env.ref("stock.group_stock_user")
cls.user = cls.env["res.users"].create(
{
"name": "Test User",
"login": "user",
"email": "test.user@example.com",
"groups_id": [(6, 0, [group_stock_user.id])],
}
)
cls.starting_inv = cls.obj_inventory.create({
'name': 'Starting inventory',
'filter': 'product',
'line_ids': [
(0, 0, {
'product_id': cls.product1.id,
'product_uom_id': cls.env.ref(
"uom.product_uom_unit").id,
'product_qty': 2.0,
'location_id': cls.test_loc.id,
}),
(0, 0, {
'product_id': cls.product2.id,
'product_uom_id': cls.env.ref(
"uom.product_uom_unit").id,
'product_qty': 4.0,
'location_id': cls.test_loc.id,
}),
],
})
cls.starting_inv = cls.obj_inventory.create(
{
"name": "Starting inventory",
"filter": "product",
"line_ids": [
(
0,
0,
{
"product_id": cls.product1.id,
"product_uom_id": cls.env.ref("uom.product_uom_unit").id,
"product_qty": 2.0,
"location_id": cls.test_loc.id,
},
),
(
0,
0,
{
"product_id": cls.product2.id,
"product_uom_id": cls.env.ref("uom.product_uom_unit").id,
"product_qty": 4.0,
"location_id": cls.test_loc.id,
},
),
],
}
)
cls.starting_inv.action_force_done()
def test_svr_creation(self):
"""Tests the creation of Slot Verification Requests."""
inventory = self.obj_inventory.create({
'name': 'Generate over discrepancy in both lines.',
'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,
})
],
})
inventory.with_context({'normal_view': True}).action_validate()
self.assertEqual(inventory.state, 'pending',
'Inventory Adjustment not changing to Pending to '
'Approve.')
inventory = self.obj_inventory.create(
{
"name": "Generate over discrepancy in both lines.",
"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,
},
),
],
}
)
inventory.with_context({"normal_view": True}).action_validate()
self.assertEqual(
inventory.state,
"pending",
"Inventory Adjustment not changing to Pending to " "Approve.",
)
previous_count = len(self.obj_svr.search([]))
inventory.sudo(self.user).action_request_verification()
current_count = len(self.obj_svr.search([]))
self.assertEqual(current_count, previous_count + 2,
'Slot Verification Request not created.')
self.assertEqual(
current_count, previous_count + 2, "Slot Verification Request not created."
)
# Test the method to open SVR from inventory lines:
inventory.line_ids[0].action_open_svr()
def test_svr_workflow(self):
"""Tests workflow of Slot Verification Request."""
test_svr = self.env['stock.slot.verification.request'].create({
'location_id': self.test_loc.id,
'state': 'wait',
'product_id': self.product1.id,
})
self.assertEqual(test_svr.state, 'wait',
'Slot Verification Request not created from scratch.')
test_svr = self.env["stock.slot.verification.request"].create(
{
"location_id": self.test_loc.id,
"state": "wait",
"product_id": self.product1.id,
}
)
self.assertEqual(
test_svr.state,
"wait",
"Slot Verification Request not created from scratch.",
)
with self.assertRaises(AccessError):
test_svr.sudo(self.user).action_confirm()
test_svr.sudo(self.manager).action_confirm()
self.assertEqual(test_svr.state, 'open',
'Slot Verification Request not confirmed properly.')
self.assertEqual(
test_svr.state, "open", "Slot Verification Request not confirmed properly."
)
test_svr.sudo(self.manager).action_solved()
self.assertEqual(test_svr.state, 'done',
'Slot Verification Request not marked as solved.')
self.assertEqual(
test_svr.state, "done", "Slot Verification Request not marked as solved."
)
test_svr.sudo(self.manager).action_cancel()
self.assertEqual(test_svr.state, 'cancelled',
'Slot Verification Request not marked as cancelled.')
self.assertEqual(
test_svr.state,
"cancelled",
"Slot Verification Request not marked as cancelled.",
)
def test_view_methods(self):
"""Tests the methods used to handle de UI."""
test_svr = self.env['stock.slot.verification.request'].create({
'location_id': self.test_loc.id,
'state': 'wait',
'product_id': self.product1.id,
})
test_svr = self.env["stock.slot.verification.request"].create(
{
"location_id": self.test_loc.id,
"state": "wait",
"product_id": self.product1.id,
}
)
test_svr.sudo(self.manager).action_confirm()
self.assertEqual(test_svr.involved_move_count, 1,
'Unexpected involved move')
self.assertEqual(test_svr.involved_inv_line_count, 1,
'Unexpected involved inventory line')
self.assertEqual(test_svr.involved_move_count, 1, "Unexpected involved move")
self.assertEqual(
test_svr.involved_inv_line_count, 1, "Unexpected involved inventory line"
)
test_svr.action_view_inv_lines()
test_svr.action_view_moves()

View File

@@ -1,41 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ForgeFlow S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_inventory_form" model="ir.ui.view">
<field name="name">Inventory form view - SVR extension</field>
<field name="model">stock.inventory</field>
<field name="inherit_id" ref="stock_inventory_discrepancy.view_inventory_form"/>
<field
name="inherit_id"
ref="stock_inventory_discrepancy.view_inventory_form"
/>
<field name="arch" type="xml">
<xpath expr="//button[@name='action_validate']"
position="after">
<button name="action_request_verification"
string="Request Verification" type="object"
class="oe_highlight"
attrs="{'invisible': ['|',('state', '!=', 'pending'),('requested_verification', '=', True)]}"
groups="stock.group_stock_user"/>
<xpath expr="//button[@name='action_validate']" position="after">
<button
name="action_request_verification"
string="Request Verification"
type="object"
class="oe_highlight"
attrs="{'invisible': ['|',('state', '!=', 'pending'),('requested_verification', '=', True)]}"
groups="stock.group_stock_user"
/>
</xpath>
<field name="name" position="after">
<field name="requested_verification" invisible="1"/>
<field name="requested_verification" invisible="1" />
</field>
<notebook position="inside">
<page string="Slot Verification Requests"
groups="stock.group_stock_manager">
<page
string="Slot Verification Requests"
groups="stock.group_stock_manager"
>
<group>
<field name="slot_verification_ids" nolabel="1"/>
<field name="slot_verification_ids" nolabel="1" />
</group>
</page>
</notebook>
<xpath expr="//field[@name='line_ids']/tree/field[@name='discrepancy_threshold']"
position="after">
<field name="slot_verification_ids" invisible="1"/>
<button string="Slot Verification Request"
attrs="{'invisible': [('slot_verification_ids', '=', [])]}"
name="action_open_svr"
type="object"
icon="fa-sticky-note"/>
<xpath
expr="//field[@name='line_ids']/tree/field[@name='discrepancy_threshold']"
position="after"
>
<field name="slot_verification_ids" invisible="1" />
<button
string="Slot Verification Request"
attrs="{'invisible': [('slot_verification_ids', '=', [])]}"
name="action_open_svr"
type="object"
icon="fa-sticky-note"
/>
</xpath>
</field>
</record>
@@ -47,32 +57,32 @@
<form string="Inventory Line">
<sheet>
<div class="oe_title">
<h3>Inventory Adjustment Line <field name="id"/></h3>
<h3>Inventory Adjustment Line <field name="id" /></h3>
</div>
<group>
<group col="2">
<field name="product_id" readonly="1"/>
<field name="inventory_id" readonly="1"/>
<field name="state"/>
<field name="create_date" readonly="1"/>
<field name="location_id" readonly="1"/>
<field name="package_id" readonly="1"/>
<field name="partner_id" readonly="1"/>
<field name="prod_lot_id" readonly="1"/>
<field name="company_id"/>
<field name="product_id" readonly="1" />
<field name="inventory_id" readonly="1" />
<field name="state" />
<field name="create_date" readonly="1" />
<field name="location_id" readonly="1" />
<field name="package_id" readonly="1" />
<field name="partner_id" readonly="1" />
<field name="prod_lot_id" readonly="1" />
<field name="company_id" />
</group>
<group col="2">
<field name="theoretical_qty"/>
<field name="product_qty" readonly="1"/>
<field name="product_uom_id" readonly="1"/>
<field name="discrepancy_qty"/>
<label for="discrepancy_percent"/>
<field name="theoretical_qty" />
<field name="product_qty" readonly="1" />
<field name="product_uom_id" readonly="1" />
<field name="discrepancy_qty" />
<label for="discrepancy_percent" />
<div>
<field name="discrepancy_percent" class="oe_inline"/> %
<field name="discrepancy_percent" class="oe_inline" /> %
</div>
<label for="discrepancy_threshold"/>
<label for="discrepancy_threshold" />
<div>
<field name="discrepancy_threshold" class="oe_inline"/> %
<field name="discrepancy_threshold" class="oe_inline" /> %
</div>
</group>
</group>
@@ -84,10 +94,10 @@
<record id="view_inventory_line_tree" model="ir.ui.view">
<field name="name">Inventory Line tree view - discrepancy extension</field>
<field name="model">stock.inventory.line</field>
<field name="inherit_id" ref="stock.stock_inventory_line_tree"/>
<field name="inherit_id" ref="stock.stock_inventory_line_tree" />
<field name="arch" type="xml">
<field name="location_id" position="after">
<field name="create_date" readonly="1"/>
<field name="create_date" readonly="1" />
</field>
</field>
</record>
@@ -96,7 +106,7 @@
<field name="name">Open Inventory Adjustment Lines</field>
<field name="res_model">stock.inventory.line</field>
<field name="view_type">form</field>
<field name="view_id" ref="stock.stock_inventory_line_tree"/>
<field name="view_id" ref="stock.stock_inventory_line_tree" />
</record>
</odoo>

View File

@@ -1,18 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ForgeFlow S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_location_form" model="ir.ui.view">
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_form"/>
<field name="inherit_id" ref="stock.view_location_form" />
<field name="arch" type="xml">
<button name="toggle_active" position="before">
<button string="Slot Verification Request"
name="action_open_svr"
type="object"
icon="fa-sticky-note"/>
<button
string="Slot Verification Request"
name="action_open_svr"
type="object"
icon="fa-sticky-note"
/>
</button>
</field>
</record>

View File

@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!-- Copyright 2020 ForgeFlow S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="stock_slot_verification_request_tree_view" model="ir.ui.view">
@@ -9,15 +8,15 @@
<field name="model">stock.slot.verification.request</field>
<field name="arch" type="xml">
<tree string="Stock Slot Verification Request">
<field name="name"/>
<field name="location_id"/>
<field name="product_id"/>
<field name="create_uid" readonly="1"/>
<field name="create_date" readonly="1"/>
<field name="responsible_id"/>
<field name="inventory_id"/>
<field name="state"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="name" />
<field name="location_id" />
<field name="product_id" />
<field name="create_uid" readonly="1" />
<field name="create_date" readonly="1" />
<field name="responsible_id" />
<field name="inventory_id" />
<field name="state" />
<field name="company_id" groups="base.group_multi_company" />
</tree>
</field>
</record>
@@ -28,71 +27,110 @@
<field name="arch" type="xml">
<form string="Stock Slot Verification Request">
<header>
<button name="action_create_inventory_adjustment"
type="object" states="open" string="Create Inventory Adjustment"
class="oe_highlight" />
<button name="action_confirm"
type="object" states="wait" string="Confirm"
class="oe_highlight" />
<button name="action_solved"
type="object" states="open" string="Mark as Solved"/>
<button name="action_cancel"
type="object" states="open"
string="Mark as Cancelled"/>
<field name="state" widget="statusbar"
statusbar_visible="wait,open,done"/>
<button
name="action_create_inventory_adjustment"
type="object"
states="open"
string="Create Inventory Adjustment"
class="oe_highlight"
/>
<button
name="action_confirm"
type="object"
states="wait"
string="Confirm"
class="oe_highlight"
/>
<button
name="action_solved"
type="object"
states="open"
string="Mark as Solved"
/>
<button
name="action_cancel"
type="object"
states="open"
string="Mark as Cancelled"
/>
<field
name="state"
widget="statusbar"
statusbar_visible="wait,open,done"
/>
</header>
<sheet>
<div class="oe_button_box" name="button_box"
attrs="{'invisible':
[('state', 'not in', ('open'))]}">
<button name="action_view_inventories"
type="object" class="oe_stat_button"
icon="fa-building-o">
<field name="created_inventory_count"
widget="statinfo"
help="Inventory Adjustments created from this SVR."
modifiers="{'readonly': true}"
string="Inv. Adj. Created"/>
<div
class="oe_button_box"
name="button_box"
attrs="{'invisible':
[('state', 'not in', ('open'))]}"
>
<button
name="action_view_inventories"
type="object"
class="oe_stat_button"
icon="fa-building-o"
>
<field
name="created_inventory_count"
widget="statinfo"
help="Inventory Adjustments created from this SVR."
modifiers="{'readonly': true}"
string="Inv. Adj. Created"
/>
</button>
<button name="action_view_moves"
type="object" class="oe_stat_button"
icon="fa-arrows-h">
<field name="involved_move_count"
widget="statinfo"
help="Stock Moves related to the given location and product."
modifiers="{'readonly': true}"
string="Stock Moves Involved"/>
<button
name="action_view_moves"
type="object"
class="oe_stat_button"
icon="fa-arrows-h"
>
<field
name="involved_move_count"
widget="statinfo"
help="Stock Moves related to the given location and product."
modifiers="{'readonly': true}"
string="Stock Moves Involved"
/>
</button>
<button name="action_view_inv_lines"
type="object" class="oe_stat_button"
icon="fa-list">
<field name="involved_inv_line_count"
widget="statinfo"
help="Inventory Adjustment Lines related to the given location and product."
modifiers="{'readonly': true}"
string="Inv. Adj. Lines Involved"/>
<button
name="action_view_inv_lines"
type="object"
class="oe_stat_button"
icon="fa-list"
>
<field
name="involved_inv_line_count"
widget="statinfo"
help="Inventory Adjustment Lines related to the given location and product."
modifiers="{'readonly': true}"
string="Inv. Adj. Lines Involved"
/>
</button>
</div>
<div class="oe_title">
<label string="Slot Verification Request" for="name"/>
<label string="Slot Verification Request" for="name" />
<h1>
<field name="name"/>
<field name="name" />
</h1>
</div>
<group>
<group>
<field name="location_id"/>
<field name="product_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="create_uid" readonly="1"/>
<field name="create_date" readonly="1"/>
<field name="responsible_id"/>
<field name="inventory_id"/>
<field name="inventory_line_id"/>
<field name="location_id" />
<field name="product_id" />
<field
name="company_id"
groups="base.group_multi_company"
/>
<field name="create_uid" readonly="1" />
<field name="create_date" readonly="1" />
<field name="responsible_id" />
<field name="inventory_id" />
<field name="inventory_line_id" />
</group>
<group>
<field name="notes"/>
<field name="notes" />
</group>
</group>
</sheet>
@@ -109,36 +147,55 @@
<field name="model">stock.slot.verification.request</field>
<field name="arch" type="xml">
<search string="Stock Slot Verification Request">
<field name="name"/>
<field name="location_id"/>
<field name="product_id"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="responsible_id"/>
<separator/>
<filter name="wait_state" string="Waiting Actions"
domain="[('state','=', 'wait')]"/>
<filter name="open_state" string="In Progress"
domain="[('state','=', 'open')]"/>
<filter name="done_state" string="Done"
domain="[('state','=', 'done')]"/>
<filter name="cancelled_state" string="Cancelled"
domain="[('state','=', 'cancelled')]"/>
<separator/>
<filter name="assigned_to_user" string="Assigned to me"
domain="[('responsible_id','=', uid)]"/>
<field name="name" />
<field name="location_id" />
<field name="product_id" />
<field name="company_id" groups="base.group_multi_company" />
<field name="responsible_id" />
<separator />
<filter
name="wait_state"
string="Waiting Actions"
domain="[('state','=', 'wait')]"
/>
<filter
name="open_state"
string="In Progress"
domain="[('state','=', 'open')]"
/>
<filter
name="done_state"
string="Done"
domain="[('state','=', 'done')]"
/>
<filter
name="cancelled_state"
string="Cancelled"
domain="[('state','=', 'cancelled')]"
/>
<separator />
<filter
name="assigned_to_user"
string="Assigned to me"
domain="[('responsible_id','=', uid)]"
/>
</search>
</field>
</record>
<act_window id="action_slot_verification_request"
name="Stock Slot Verification Request"
res_model="stock.slot.verification.request"
context="{'search_default_wait_state':1,'search_default_open_state':1}"
view_mode="tree,form" />
<menuitem id="menu_slot_verification_request"
name="Slot Verification Request"
parent="stock.menu_stock_warehouse_mgmt"
sequence="31"
action="action_slot_verification_request" />
<act_window
id="action_slot_verification_request"
name="Stock Slot Verification Request"
res_model="stock.slot.verification.request"
context="{'search_default_wait_state':1,'search_default_open_state':1}"
view_mode="tree,form"
/>
<menuitem
id="menu_slot_verification_request"
name="Slot Verification Request"
parent="stock.menu_stock_warehouse_mgmt"
sequence="31"
action="action_slot_verification_request"
/>
</odoo>