mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
[IMP] Kanban: Add Inventory managament
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
|
||||
{
|
||||
'name': 'Stock Request kanban',
|
||||
'version': '11.0.1.0.0',
|
||||
'version': '11.0.1.0.1',
|
||||
'category': 'Reporting',
|
||||
'website': 'https://github.com/OCA/stock-logistics-warehouse',
|
||||
'author': 'Creu Blanca, Eficent, Odoo Community Association (OCA)',
|
||||
@@ -16,10 +16,12 @@
|
||||
'data': [
|
||||
'data/stock_request_sequence_data.xml',
|
||||
'report/report_paper_format.xml',
|
||||
'wizard/wizard_stock_inventory_kanban_views.xml',
|
||||
'wizard/wizard_stock_request_kanban_views.xml',
|
||||
'wizard/wizard_stock_request_order_kanban_views.xml',
|
||||
'views/stock_request_order_views.xml',
|
||||
'views/stock_request_kanban_views.xml',
|
||||
'views/stock_inventory_kanban_views.xml',
|
||||
'views/stock_request_menu.xml',
|
||||
'report/stock_request_kanban_templates.xml',
|
||||
'security/ir.model.access.csv',
|
||||
|
||||
@@ -3,3 +3,4 @@
|
||||
|
||||
from . import stock_request
|
||||
from . import stock_request_kanban
|
||||
from . import stock_inventory_kanban
|
||||
|
||||
140
stock_request_kanban/models/stock_inventory_kanban.py
Normal file
140
stock_request_kanban/models/stock_inventory_kanban.py
Normal file
@@ -0,0 +1,140 @@
|
||||
# Copyright 2018 Creu Blanca
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, models, fields
|
||||
|
||||
|
||||
class StockInventoryKanban(models.Model):
|
||||
_name = 'stock.inventory.kanban'
|
||||
_description = 'Inventory for Kanban'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
|
||||
name = fields.Char(
|
||||
readonly=True, states={'draft': [('readonly', False)]}, copy=False,
|
||||
)
|
||||
state = fields.Selection(
|
||||
[
|
||||
('draft', 'Draft'),
|
||||
('in_progress', 'In progress'),
|
||||
('finished', 'Finished'),
|
||||
('closed', 'Closed'),
|
||||
('cancelled', 'Cancelled')
|
||||
],
|
||||
required=True, default='draft', readonly=True, copy=False,
|
||||
track_visibility='onchange'
|
||||
)
|
||||
warehouse_ids = fields.Many2many(
|
||||
'stock.warehouse', string='Warehouse',
|
||||
ondelete="cascade",
|
||||
readonly=True, states={'draft': [('readonly', False)]},
|
||||
)
|
||||
location_ids = fields.Many2many(
|
||||
'stock.location', string='Location',
|
||||
domain=[('usage', 'in', ['internal', 'transit'])],
|
||||
ondelete="cascade",
|
||||
readonly=True, states={'draft': [('readonly', False)]},
|
||||
)
|
||||
product_ids = fields.Many2many(
|
||||
'product.product', string='Product',
|
||||
domain=[('type', 'in', ['product', 'consu'])],
|
||||
ondelete='cascade',
|
||||
readonly=True, states={'draft': [('readonly', False)]},
|
||||
)
|
||||
kanban_ids = fields.Many2many(
|
||||
'stock.request.kanban',
|
||||
relation='stock_inventory_kanban_kanban',
|
||||
readonly=True, copy=False,
|
||||
)
|
||||
scanned_kanban_ids = fields.Many2many(
|
||||
'stock.request.kanban',
|
||||
relation='stock_inventory_kanban_scanned_kanban',
|
||||
readonly=True, copy=False,
|
||||
)
|
||||
missing_kanban_ids = fields.Many2many(
|
||||
'stock.request.kanban',
|
||||
readonly=True,
|
||||
compute='_compute_missing_kanban'
|
||||
)
|
||||
|
||||
@api.depends('kanban_ids', 'scanned_kanban_ids')
|
||||
def _compute_missing_kanban(self):
|
||||
for rec in self:
|
||||
rec.missing_kanban_ids = rec.kanban_ids.filtered(
|
||||
lambda r: r.id not in rec.scanned_kanban_ids.ids
|
||||
)
|
||||
|
||||
def _get_inventory_kanban_domain(self):
|
||||
domain = []
|
||||
if self.warehouse_ids:
|
||||
domain.append(('warehouse_id', 'in', self.warehouse_ids.ids))
|
||||
if self.product_ids:
|
||||
domain.append(('product_id', 'in', self.product_ids.ids))
|
||||
if self.location_ids:
|
||||
domain.append(('location_id', 'in', self.location_ids.ids))
|
||||
return domain
|
||||
|
||||
def _start_inventory_values(self):
|
||||
return {
|
||||
'state': 'in_progress'
|
||||
}
|
||||
|
||||
def _finish_inventory_values(self):
|
||||
return {
|
||||
'state': 'finished'
|
||||
}
|
||||
|
||||
def _close_inventory_values(self):
|
||||
return {
|
||||
'state': 'closed'
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def calculate_kanbans(self):
|
||||
for rec in self:
|
||||
if rec.state == 'draft':
|
||||
rec.kanban_ids = self.env['stock.request.kanban'].search(
|
||||
rec._get_inventory_kanban_domain()
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def start_inventory(self):
|
||||
self.calculate_kanbans()
|
||||
self.write(self._start_inventory_values())
|
||||
|
||||
@api.multi
|
||||
def finish_inventory(self):
|
||||
self.write(self._finish_inventory_values())
|
||||
|
||||
@api.multi
|
||||
def close_inventory(self):
|
||||
self.write(self._close_inventory_values())
|
||||
|
||||
@api.multi
|
||||
def print_missing_kanbans(self):
|
||||
""" Print the missing kanban cards in order to restore them
|
||||
"""
|
||||
self.ensure_one()
|
||||
return self.env.ref(
|
||||
'stock_request_kanban.action_report_kanban').report_action(
|
||||
self.missing_kanban_ids
|
||||
)
|
||||
|
||||
def _cancel_inventory_values(self):
|
||||
return {
|
||||
'state': 'cancelled',
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def cancel(self):
|
||||
self.write(self._cancel_inventory_values())
|
||||
|
||||
def _to_draft_inventory_values(self):
|
||||
return {
|
||||
'state': 'draft',
|
||||
'kanban_ids': [(5, 0)],
|
||||
'scanned_kanban_ids': [(5, 0)],
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def to_draft(self):
|
||||
self.write(self._to_draft_inventory_values())
|
||||
@@ -1,7 +1,9 @@
|
||||
# Copyright 2018 Creu Blanca
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import api, models, fields
|
||||
from odoo import api, models, fields, _
|
||||
from odoo.exceptions import ValidationError
|
||||
from reportlab.graphics.barcode import getCodes
|
||||
|
||||
|
||||
class StockRequestKanban(models.Model):
|
||||
@@ -17,3 +19,23 @@ class StockRequestKanban(models.Model):
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code(
|
||||
'stock.request.kanban')
|
||||
return super().create(vals)
|
||||
|
||||
@api.model
|
||||
def get_barcode_format(self):
|
||||
return 'Standard39'
|
||||
|
||||
@api.model
|
||||
def _recompute_barcode(self, barcode):
|
||||
bcc = getCodes()[self.get_barcode_format()](value=barcode[:-1])
|
||||
bcc.validate()
|
||||
bcc.encode()
|
||||
if bcc.encoded[1:-1] != barcode:
|
||||
raise ValidationError(_('CRC is not valid'))
|
||||
return barcode[:-1]
|
||||
|
||||
@api.model
|
||||
def search_barcode(self, barcode):
|
||||
recomputed_barcode = self._recompute_barcode(barcode)
|
||||
return self.env['stock.request.kanban'].search([
|
||||
('name', '=', recomputed_barcode)
|
||||
])
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_stock_request_kanban_user,stock request kanban user,model_stock_request_kanban,stock_request.group_stock_request_user,1,1,1,
|
||||
access_stock_request_kanban_manager,stock request kanban manager,model_stock_request_kanban,stock_request.group_stock_request_manager,1,1,1,1
|
||||
access_stock_inventory_kanban_user,stock inventory kanban user,model_stock_inventory_kanban,stock_request.group_stock_request_user,1,1,1,
|
||||
access_stock_inventory_kanban_manager,stock inventory kanban manager,model_stock_inventory_kanban,stock_request.group_stock_request_manager,1,1,1,1
|
||||
|
||||
|
@@ -1 +1,2 @@
|
||||
from . import test_kanban
|
||||
from . import test_inventory_kanban
|
||||
|
||||
16
stock_request_kanban/tests/base_test.py
Normal file
16
stock_request_kanban/tests/base_test.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Copyright 2017 Creu Blanca
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
from reportlab.graphics.barcode import getCodes
|
||||
|
||||
|
||||
class TestBaseKanban(TransactionCase):
|
||||
|
||||
def pass_code(self, wizard, code):
|
||||
bcc = getCodes()[
|
||||
self.env['stock.request.kanban'].get_barcode_format()](value=code)
|
||||
bcc.validate()
|
||||
bcc.encode()
|
||||
wizard.on_barcode_scanned(bcc.encoded[1:-1])
|
||||
102
stock_request_kanban/tests/test_inventory_kanban.py
Normal file
102
stock_request_kanban/tests/test_inventory_kanban.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# Copyright 2017 Creu Blanca
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from .base_test import TestBaseKanban
|
||||
|
||||
|
||||
class TestKanban(TestBaseKanban):
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.main_company = self.env.ref('base.main_company')
|
||||
self.route = self.env['stock.location.route'].create({
|
||||
'name': 'Transfer',
|
||||
'product_categ_selectable': False,
|
||||
'product_selectable': True,
|
||||
'company_id': self.main_company.id,
|
||||
'sequence': 10,
|
||||
})
|
||||
self.product = self.env['product.product'].create({
|
||||
'name': 'Product',
|
||||
'route_ids': [(4, self.route.id)],
|
||||
'company_id': False,
|
||||
})
|
||||
self.product_2 = self.env['product.product'].create({
|
||||
'name': 'Product 2',
|
||||
'route_ids': [(4, self.route.id)],
|
||||
'company_id': False,
|
||||
})
|
||||
self.kanban_1 = self.env['stock.request.kanban'].create({
|
||||
'product_id': self.product.id,
|
||||
'product_uom_id': self.product.uom_id.id,
|
||||
'product_uom_qty': 1,
|
||||
})
|
||||
self.kanban_2 = self.env['stock.request.kanban'].create({
|
||||
'product_id': self.product.id,
|
||||
'product_uom_id': self.product.uom_id.id,
|
||||
'product_uom_qty': 1,
|
||||
})
|
||||
self.kanban_3 = self.env['stock.request.kanban'].create({
|
||||
'product_id': self.product_2.id,
|
||||
'product_uom_id': self.product.uom_id.id,
|
||||
'product_uom_qty': 1,
|
||||
})
|
||||
|
||||
def test_inventory_warehouse(self):
|
||||
inventory = self.env['stock.inventory.kanban'].create({
|
||||
'warehouse_ids': [(4, self.kanban_1.warehouse_id.id)],
|
||||
})
|
||||
inventory.start_inventory()
|
||||
self.assertIn(self.kanban_1, inventory.kanban_ids)
|
||||
self.assertIn(self.kanban_1, inventory.missing_kanban_ids)
|
||||
|
||||
def test_inventory_location(self):
|
||||
inventory = self.env['stock.inventory.kanban'].create({
|
||||
'location_ids': [(4, self.kanban_1.location_id.id)],
|
||||
})
|
||||
inventory.start_inventory()
|
||||
self.assertIn(self.kanban_1, inventory.kanban_ids)
|
||||
self.assertIn(self.kanban_1, inventory.missing_kanban_ids)
|
||||
|
||||
def test_inventory_product(self):
|
||||
inventory = self.env['stock.inventory.kanban'].create({
|
||||
'product_ids': [(4, self.product.id)],
|
||||
})
|
||||
inventory.start_inventory()
|
||||
self.assertIn(self.kanban_1, inventory.kanban_ids)
|
||||
self.assertNotIn(self.kanban_3, inventory.kanban_ids)
|
||||
self.assertIn(self.kanban_1, inventory.missing_kanban_ids)
|
||||
self.assertEqual(inventory.state, 'in_progress')
|
||||
wizard = self.env['wizard.stock.inventory.kanban'].with_context(
|
||||
default_inventory_kanban_id=inventory.id
|
||||
).create({})
|
||||
self.pass_code(wizard, self.kanban_3.name)
|
||||
self.assertEqual(wizard.status_state, 1)
|
||||
self.pass_code(wizard, self.kanban_1.name)
|
||||
self.assertEqual(wizard.status_state, 0)
|
||||
self.assertNotIn(self.kanban_1, inventory.missing_kanban_ids)
|
||||
self.assertIn(self.kanban_1, inventory.scanned_kanban_ids)
|
||||
self.pass_code(wizard, self.kanban_1.name)
|
||||
self.assertEqual(wizard.status_state, 1)
|
||||
self.assertNotIn(self.kanban_1, inventory.missing_kanban_ids)
|
||||
self.assertIn(self.kanban_1, inventory.scanned_kanban_ids)
|
||||
inventory.finish_inventory()
|
||||
self.assertEqual(inventory.state, 'finished')
|
||||
inventory.close_inventory()
|
||||
self.assertEqual(inventory.state, 'closed')
|
||||
|
||||
def test_cancel_inventory(self):
|
||||
inventory = self.env['stock.inventory.kanban'].create({
|
||||
'product_ids': [(4, self.product.id)],
|
||||
})
|
||||
inventory.start_inventory()
|
||||
self.assertIn(self.kanban_1, inventory.kanban_ids)
|
||||
self.assertNotIn(self.kanban_3, inventory.kanban_ids)
|
||||
self.assertIn(self.kanban_1, inventory.missing_kanban_ids)
|
||||
self.assertEqual(inventory.state, 'in_progress')
|
||||
inventory.cancel()
|
||||
self.assertEqual(inventory.state, 'cancelled')
|
||||
inventory.to_draft()
|
||||
self.assertEqual(inventory.state, 'draft')
|
||||
self.assertFalse(inventory.kanban_ids)
|
||||
self.assertFalse(inventory.scanned_kanban_ids)
|
||||
@@ -2,12 +2,11 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo.tests.common import TransactionCase
|
||||
from odoo.exceptions import ValidationError
|
||||
from reportlab.graphics.barcode import getCodes
|
||||
from .base_test import TestBaseKanban
|
||||
|
||||
|
||||
class TestKanban(TransactionCase):
|
||||
class TestKanban(TestBaseKanban):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -21,6 +20,11 @@ class TestKanban(TransactionCase):
|
||||
})
|
||||
self.wh2 = self.env['stock.warehouse'].search(
|
||||
[('company_id', '=', self.company_2.id)], limit=1)
|
||||
self.wh3 = self.env['stock.warehouse'].create({
|
||||
'name': 'Warehouse TEst',
|
||||
'code': 'WH-TEST',
|
||||
'company_id': self.main_company.id,
|
||||
})
|
||||
|
||||
self.ressuply_loc = self.env['stock.location'].create({
|
||||
'name': 'Ressuply',
|
||||
@@ -97,9 +101,9 @@ class TestKanban(TransactionCase):
|
||||
'product_id': self.product.id,
|
||||
'product_uom_id': self.product.uom_id.id,
|
||||
'product_uom_qty': 1,
|
||||
'company_id': self.company_2.id,
|
||||
'warehouse_id': self.wh2.id,
|
||||
'location_id': self.wh2.lot_stock_id.id,
|
||||
'company_id': self.main_company.id,
|
||||
'warehouse_id': self.wh3.id,
|
||||
'location_id': self.wh3.lot_stock_id.id,
|
||||
})
|
||||
order = self.env['stock.request.order'].create({
|
||||
'company_id': self.main_company.id,
|
||||
@@ -158,9 +162,3 @@ class TestKanban(TransactionCase):
|
||||
self.assertTrue(self.env['stock.request'].search(
|
||||
[('kanban_id', '=', kanban_2.id)])
|
||||
)
|
||||
|
||||
def pass_code(self, wizard, code):
|
||||
bcc = getCodes()[wizard.get_barcode_format()](value=code)
|
||||
bcc.validate()
|
||||
bcc.encode()
|
||||
wizard.on_barcode_scanned(bcc.encoded[1:-1])
|
||||
|
||||
95
stock_request_kanban/views/stock_inventory_kanban_views.xml
Normal file
95
stock_request_kanban/views/stock_inventory_kanban_views.xml
Normal file
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_stock_inventory_kanban_tree" model="ir.ui.view">
|
||||
<field name="name">stock.inventory.kanban.tree</field>
|
||||
<field name="model">stock.inventory.kanban</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Stock Inventories">
|
||||
<field name="name"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_stock_inventory_kanban_form" model="ir.ui.view">
|
||||
<field name="name">stock.inventory.kanban.form</field>
|
||||
<field name="model">stock.inventory.kanban</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Stock Inventories">
|
||||
<header>
|
||||
<button name="start_inventory" type="object" string="Start"
|
||||
states="draft" class="btn-primary"
|
||||
/>
|
||||
<button name="finish_inventory" type="object" string="Finish"
|
||||
states="in_progress" class="btn-primary"
|
||||
/>
|
||||
<button name="print_missing_kanbans" type="object" string="Print missing"
|
||||
states="finished"
|
||||
/>
|
||||
<button name="close_inventory" type="object" string="Close"
|
||||
states="finished" class="btn-primary"
|
||||
/>
|
||||
<button name="cancel" type="object" string="Cancel"
|
||||
states="draft,in_progress,finished"
|
||||
/>
|
||||
<button name="to_draft" type="object" string="Set to draft"
|
||||
states="cancelled"
|
||||
/>
|
||||
<field name="state" widget="statusbar"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button name="%(stock_request_kanban.wizard_stock_inventory_kanban_action)d"
|
||||
type="action"
|
||||
icon="fa-barcode"
|
||||
string="Scan"
|
||||
states="in_progress"
|
||||
class="oe_read_only"
|
||||
/>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<label string="Inventory Kanban" />
|
||||
<h1>
|
||||
<field name="name" readonly="1"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<field name="warehouse_ids" widget="many2many_tags" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="location_ids" widget="many2many_tags" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="product_ids" widget="many2many_tags"/>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Kanban" id="kanban">
|
||||
<field name="kanban_ids"/>
|
||||
</page>
|
||||
<page string="Missing" id="missing">
|
||||
<field name="missing_kanban_ids"/>
|
||||
</page>
|
||||
<page string="Scanned" id="scanned">
|
||||
<field name="scanned_kanban_ids"/>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
<field name="message_follower_ids" widget="mail_followers"/>
|
||||
<field name="activity_ids" widget="mail_activity"/>
|
||||
<field name="message_ids" widget="mail_thread"/>
|
||||
</div>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="stock_inventory_kanban_action" model="ir.actions.act_window">
|
||||
<field name="name">Stock Inventory Kanbans</field>
|
||||
<field name="res_model">stock.inventory.kanban</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="oe_view_nocontent_create">
|
||||
Click to add a Stock Inventory Kanban.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -13,4 +13,10 @@
|
||||
parent="stock_request.menu_stock_request_operations"
|
||||
action="wizard_stock_request_kanban_action"
|
||||
sequence="40"/>
|
||||
|
||||
<menuitem id="menu_wizard_stock_inventory_kanban"
|
||||
name="Inventory"
|
||||
parent="stock_request.menu_stock_request_operations"
|
||||
action="stock_inventory_kanban_action"
|
||||
sequence="60"/>
|
||||
</odoo>
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
from . import wizard_stock_request_kanban_abstract
|
||||
from . import wizard_stock_request_kanban
|
||||
from . import wizard_stock_request_order_kanban
|
||||
from . import wizard_stock_inventory_kanban
|
||||
|
||||
37
stock_request_kanban/wizard/wizard_stock_inventory_kanban.py
Normal file
37
stock_request_kanban/wizard/wizard_stock_inventory_kanban.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright 2017 Creu Blanca
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import fields, models, _
|
||||
|
||||
|
||||
class WizardStockRequestOrderKanbanAbstract(models.TransientModel):
|
||||
_name = "wizard.stock.inventory.kanban"
|
||||
_inherit = "wizard.stock.request.kanban.abstract"
|
||||
|
||||
inventory_kanban_id = fields.Many2one(
|
||||
'stock.inventory.kanban',
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
def barcode_ending(self):
|
||||
super().barcode_ending()
|
||||
self.inventory_kanban_id.write({
|
||||
'scanned_kanban_ids': [(4, self.kanban_id.id)]
|
||||
})
|
||||
|
||||
def validate_kanban(self, barcode):
|
||||
res = super().validate_kanban(barcode)
|
||||
if not self.inventory_kanban_id.kanban_ids.filtered(
|
||||
lambda r: r == self.kanban_id
|
||||
):
|
||||
self.status = _("Barcode %s is not in the inventory") % barcode
|
||||
self.status_state = 1
|
||||
return False
|
||||
if self.inventory_kanban_id.scanned_kanban_ids.filtered(
|
||||
lambda r: r == self.kanban_id
|
||||
):
|
||||
self.status = _("Barcode %s is already scanned") % barcode
|
||||
self.status_state = 1
|
||||
return False
|
||||
return res
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!--
|
||||
Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
Copyright 2017 Creu Blanca
|
||||
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
-->
|
||||
|
||||
<odoo>
|
||||
|
||||
<record id="wizard_stock_inventory_kanban_form" model="ir.ui.view">
|
||||
<field name="name">wizard.stock.inventory.kanban.form</field>
|
||||
<field name="model">wizard.stock.inventory.kanban</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Add Kanban">
|
||||
<div class="alert alert-success text-center o_form_header"
|
||||
role="alert" style="margin-bottom:0px;"
|
||||
attrs="{'invisible':[('status_state', '!=', 0)]}">
|
||||
<bold><field name="status"/></bold>
|
||||
</div>
|
||||
<div class="alert alert-danger alert-dismissable text-center"
|
||||
role="alert" style="margin-bottom:0px;"
|
||||
attrs="{'invisible':[('status_state', '=', 0)]}">
|
||||
<bold><field name="status"/></bold>
|
||||
</div>
|
||||
<field name="status_state" invisible="1"/>
|
||||
<field name="kanban_id" invisible="1"/>
|
||||
<field name="inventory_kanban_id" invisible="1"/>
|
||||
<field name="_barcode_scanned" widget="barcode_handler"
|
||||
invisible="1"/>
|
||||
<footer>
|
||||
<button
|
||||
name="action_cancel"
|
||||
string="Close"
|
||||
class="oe_link"
|
||||
special="cancel"
|
||||
/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window id="wizard_stock_inventory_kanban_action"
|
||||
name="Add Kanban"
|
||||
res_model="wizard.stock.inventory.kanban"
|
||||
view_mode="form"
|
||||
view_type="form"
|
||||
context="{'default_inventory_kanban_id': active_id}"
|
||||
target="new"/>
|
||||
|
||||
</odoo>
|
||||
@@ -2,13 +2,43 @@
|
||||
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import models
|
||||
from odoo import fields, models, _
|
||||
|
||||
|
||||
class WizardStockRequestOrderKanbanAbstract(models.TransientModel):
|
||||
_name = "wizard.stock.request.kanban"
|
||||
_inherit = "wizard.stock.request.kanban.abstract"
|
||||
|
||||
stock_request_id = fields.Many2one(
|
||||
'stock.request',
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
def barcode_ending(self):
|
||||
super().barcode_ending()
|
||||
self.stock_request_id = self.env['stock.request'].create(
|
||||
self.stock_request_kanban_values()
|
||||
)
|
||||
self.status_state = 0
|
||||
self.status = _('Added kanban %s for product %s' % (
|
||||
self.stock_request_id.kanban_id.name,
|
||||
self.stock_request_id.product_id.display_name
|
||||
))
|
||||
self.stock_request_ending()
|
||||
|
||||
def stock_request_ending(self):
|
||||
self.stock_request_id.action_confirm()
|
||||
return
|
||||
|
||||
def stock_request_kanban_values(self):
|
||||
return {
|
||||
'company_id': self.kanban_id.company_id.id,
|
||||
'procurement_group_id':
|
||||
self.kanban_id.procurement_group_id.id or False,
|
||||
'location_id': self.kanban_id.location_id.id or False,
|
||||
'warehouse_id': self.kanban_id.warehouse_id.id or False,
|
||||
'product_id': self.kanban_id.product_id.id,
|
||||
'product_uom_id': self.kanban_id.product_uom_id.id or False,
|
||||
'route_id': self.kanban_id.route_id.id or False,
|
||||
'product_uom_qty': self.kanban_id.product_uom_qty,
|
||||
'kanban_id': self.kanban_id.id,
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
|
||||
|
||||
from odoo import fields, models, _
|
||||
from odoo.exceptions import ValidationError
|
||||
from reportlab.graphics.barcode import getCodes
|
||||
|
||||
|
||||
class WizardStockRequestOrderKanbanAbstract(models.AbstractModel):
|
||||
@@ -15,10 +13,6 @@ class WizardStockRequestOrderKanbanAbstract(models.AbstractModel):
|
||||
'stock.request.kanban',
|
||||
readonly=True,
|
||||
)
|
||||
stock_request_id = fields.Many2one(
|
||||
'stock.request',
|
||||
readonly=True,
|
||||
)
|
||||
status = fields.Text(
|
||||
readonly=True,
|
||||
default="Start scanning",
|
||||
@@ -28,23 +22,9 @@ class WizardStockRequestOrderKanbanAbstract(models.AbstractModel):
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
def get_barcode_format(self):
|
||||
return 'Standard39'
|
||||
|
||||
def validate_barcode(self, barcode):
|
||||
bcc = getCodes()[self.get_barcode_format()](value=barcode[:-1])
|
||||
bcc.validate()
|
||||
bcc.encode()
|
||||
if bcc.encoded[1:-1] != barcode:
|
||||
raise ValidationError(_('CRC is not valid'))
|
||||
return barcode[:-1]
|
||||
|
||||
def on_barcode_scanned(self, barcode):
|
||||
barcode = self.validate_barcode(barcode)
|
||||
|
||||
self.kanban_id = self.env['stock.request.kanban'].search([
|
||||
('name', '=', barcode)
|
||||
])
|
||||
self.kanban_id = self.env['stock.request.kanban'].search_barcode(
|
||||
barcode)
|
||||
if not self.kanban_id:
|
||||
self.status = _("Barcode %s does not correspond to any "
|
||||
"Kanban. Try with another barcode or "
|
||||
@@ -52,20 +32,11 @@ class WizardStockRequestOrderKanbanAbstract(models.AbstractModel):
|
||||
self.status_state = 1
|
||||
return
|
||||
if self.validate_kanban(barcode):
|
||||
self.stock_request_id = self.env['stock.request'].create(
|
||||
self.stock_request_kanban_values()
|
||||
)
|
||||
self.status_state = 0
|
||||
|
||||
self.status = _('Added kanban %s for product %s' % (
|
||||
self.stock_request_id.kanban_id.name,
|
||||
self.stock_request_id.product_id.display_name
|
||||
))
|
||||
self.barcode_ending()
|
||||
return
|
||||
|
||||
def barcode_ending(self):
|
||||
return
|
||||
pass
|
||||
|
||||
def validate_kanban(self, barcode):
|
||||
'''
|
||||
@@ -74,17 +45,3 @@ class WizardStockRequestOrderKanbanAbstract(models.AbstractModel):
|
||||
:return:
|
||||
'''
|
||||
return True
|
||||
|
||||
def stock_request_kanban_values(self):
|
||||
return {
|
||||
'company_id': self.kanban_id.company_id.id,
|
||||
'procurement_group_id':
|
||||
self.kanban_id.procurement_group_id.id or False,
|
||||
'location_id': self.kanban_id.location_id.id or False,
|
||||
'warehouse_id': self.kanban_id.warehouse_id.id or False,
|
||||
'product_id': self.kanban_id.product_id.id,
|
||||
'product_uom_id': self.kanban_id.product_uom_id.id or False,
|
||||
'route_id': self.kanban_id.route_id.id or False,
|
||||
'product_uom_qty': self.kanban_id.product_uom_qty,
|
||||
'kanban_id': self.kanban_id.id,
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ from odoo.exceptions import ValidationError
|
||||
|
||||
class WizardStockRequestOrderKanban(models.TransientModel):
|
||||
_name = "wizard.stock.request.order.kanban"
|
||||
_inherit = "wizard.stock.request.kanban.abstract"
|
||||
_inherit = "wizard.stock.request.kanban"
|
||||
|
||||
order_id = fields.Many2one(
|
||||
'stock.request.order',
|
||||
@@ -48,6 +48,9 @@ class WizardStockRequestOrderKanban(models.TransientModel):
|
||||
res['expected_date'] = self.order_id.expected_date,
|
||||
return res
|
||||
|
||||
def stock_request_ending(self):
|
||||
return
|
||||
|
||||
def barcode_ending(self):
|
||||
super().barcode_ending()
|
||||
self.order_id = self.stock_request_id.order_id
|
||||
|
||||
Reference in New Issue
Block a user