[ADD] stock_request_kanban

This commit is contained in:
Enric Tobella
2018-04-25 18:03:25 +02:00
committed by Bernat Puig Font
parent d08f2eace0
commit 7416737d3f
21 changed files with 841 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
====================
Stock Request Kanban
====================
On most companies there is products that must be purchased often but cannot be
stored as a usual product because no consumption moves are made.
Usually, they are stored as consumables or putaway rules are defined.
In both cases, reordering rules cannot be used.
This module allows to use stock request as reordering rules for this kind of
products.
It is created following the concept of lean kanban cards.
Usage
=====
Creation
--------
* Go to 'Stock Requests / Stock Requests Kanban' and create a new Kanban.
* Indicate a product, quantity and location.
* Press 'Save'.
* Print the kanban and put it in the storage of the product
Request kanban
--------------
This should be used if you want to create the kanban when the card is consumed.
* Once the product is consumed, take the card
* Go to 'Stock Requests / Order Kanban Card'
* Scan the card
* The stock request is created
Request kanban batch
--------------------
This should be used when you will store the cards and create request orders
for kanbans later.
* Once the product is consumed, take the card and store it
* Create a store request order
* Press the scan button
* Scan all the pending kanban cards
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/153/11.0
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/stock-logistics-warehouse/issues>`_. In case of
trouble, please check there if your issue has already been reported. If you
spotted it first, help us smash it by providing detailed and welcomed feedback.
Credits
=======
Contributors
------------
* Enric Tobella <etobella@creublanca.es>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

View File

@@ -0,0 +1,5 @@
# Copyright 2018 Creu Blanca
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import models
from . import wizard

View File

@@ -0,0 +1,28 @@
# Copyright 2018 Creu Blanca
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
'name': 'Stock Request kanban',
'version': '11.0.1.0.0',
'category': 'Reporting',
'website': 'https://github.com/eficent/cb-addons',
'author': 'Creu Blanca, Eficent, Odoo Community Association (OCA)',
'license': 'AGPL-3',
'summary': 'Adds a stock request order, and takes stock requests as lines',
'depends': [
'stock_request',
'barcodes',
],
'data': [
'data/stock_request_sequence_data.xml',
'report/report_paper_format.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',
'report/stock_request_kanban_templates.xml',
'security/ir.model.access.csv',
],
'installable': True,
'application': False,
}

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="seq_stock_request_kanban" model="ir.sequence">
<field name="name">Stock Request Kanban</field>
<field name="code">stock.request.kanban</field>
<field name="prefix">KB</field>
<field name="padding">5</field>
<field name="company_id" eval="False"/>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,5 @@
# Copyright 2018 Creu Blanca
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import stock_request
from . import stock_request_kanban

View File

@@ -0,0 +1,10 @@
# Copyright 2018 Creu Blanca
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import models, fields
class StockRequest(models.Model):
_inherit = 'stock.request'
kanban_id = fields.Many2one('stock.request.kanban', readonly=True)

View File

@@ -0,0 +1,19 @@
# Copyright 2018 Creu Blanca
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, models, fields
class StockRequestKanban(models.Model):
_name = 'stock.request.kanban'
_description = 'Stock Request Kanban'
_inherit = 'stock.request.abstract'
active = fields.Boolean(default=True)
@api.model
def create(self, vals):
if vals.get('name', '/') == '/':
vals['name'] = self.env['ir.sequence'].next_by_code(
'stock.request.kanban')
return super().create(vals)

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="kanban_paper_format" model="report.paperformat">
<field name="name">Kanban format</field>
<field name="format">A4</field>
<field name="orientation">Portrait</field>
<field name="margin_top">0.0</field>
<field name="margin_bottom">0.0</field>
<field name="margin_left">0.0</field>
<field name="margin_right">0.0</field>
<field name="header_spacing">0</field>
<field name="dpi">72</field>
</record>
</odoo>

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2017 Eficent
License LGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<template id="report_simple_label">
<div class="col-xs-3" style="padding:0;height:350px;">
<div class="col-xs-6"
style="height:30%;border:2px solid black;text-align:center;vertical-align:middle;display:table;">
<div style="display: table-cell; vertical-align: middle;">
<strong t-field="o.product_id.default_code"
t-if="o.product_id.default_code"/>
</div>
</div>
<div class="col-xs-6"
style="height:30%;border:2px solid black;text-align:center;vertical-align:middle;display:table;">
<div style="display: table-cell; vertical-align: middle;">
<strong t-field="o.location_id.name"/>
</div>
</div>
<div class="col-xs-12 align-middle"
style="height:40%;border:2px solid black;text-align:center;vertical-align:middle;display:table;">
<div style="display: table-cell; vertical-align: middle;">
<strong t-field="o.product_id.name"/>
</div>
</div>
<div class="col-xs-6"
style="height:10%;border:2px solid black;text-align:center;vertical-align:middle;display:table;">
<div style="display: table-cell; vertical-align: middle;">
<span t-esc="float(o.product_qty)"/>
<span t-field="o.product_id.uom_id.name"/>
</div>
</div>
<div class="col-xs-6"
style="height:10%;border:2px solid black;text-align:center;vertical-align:middle;display:table;">
<div style="display: table-cell; vertical-align: middle;">
<span t-esc="float(o.product_uom_qty)"/>
<span t-field="o.product_uom_id.name"/>
</div>
</div>
<div class="col-xs-12"
style="height:10%;border:2px solid black;text-align:center;vertical-align:middle;display:table;">
<div style="display: table-cell; vertical-align: middle;">
<span t-field="o.name"/>
</div>
</div>
<div class="col-xs-12" style="height:10%;">
<img t-att-src="'/report/barcode/%s/%s?width=%s&amp;height=%s' % ('Standard39', o.name, 320, 20)"
style="height:80%; width: 100%;"/>
</div>
</div>
</template>
<template id="report_kanban_label">
<t t-call="web.basic_layout">
<t t-foreach="docs" t-as="o">
<div class="page">
<t t-call="stock_request_kanban.report_simple_label">
<t t-set="o" t-value="o"/>
</t>
</div>
</t>
</t>
</template>
<report
id="action_report_kanban"
string="Print kanban"
model="stock.request.kanban"
report_type="qweb-pdf"
name="stock_request_kanban.report_kanban_label"
file="stock_request_kanban.report_kanban_label"
paperformat="stock_request_kanban.kanban_paper_format"
menu="True"/>
</odoo>

View File

@@ -0,0 +1,3 @@
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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_stock_request_kanban_user stock request kanban user model_stock_request_kanban stock_request.group_stock_request_user 1 1 1
3 access_stock_request_kanban_manager stock request kanban manager model_stock_request_kanban stock_request.group_stock_request_manager 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

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

View File

@@ -0,0 +1,166 @@
# 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 odoo.exceptions import ValidationError
from reportlab.graphics.barcode import getCodes
class TestKanban(TransactionCase):
def setUp(self):
super().setUp()
self.main_company = self.env.ref('base.main_company')
self.warehouse = self.env.ref('stock.warehouse0')
self.categ_unit = self.env.ref('product.product_uom_categ_unit')
# common data
self.company_2 = self.env['res.company'].create({
'name': 'Comp2',
})
self.wh2 = self.env['stock.warehouse'].search(
[('company_id', '=', self.company_2.id)], limit=1)
self.ressuply_loc = self.env['stock.location'].create({
'name': 'Ressuply',
'location_id': self.warehouse.view_location_id.id,
})
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.uom_dozen = self.env['product.uom'].create({
'name': 'Test-DozenA',
'category_id': self.categ_unit.id,
'factor_inv': 12,
'uom_type': 'bigger',
'rounding': 0.001})
self.env['procurement.rule'].create({
'name': 'Transfer',
'route_id': self.route.id,
'location_src_id': self.ressuply_loc.id,
'location_id': self.warehouse.lot_stock_id.id,
'action': 'move',
'picking_type_id': self.warehouse.int_type_id.id,
'procure_method': 'make_to_stock',
'warehouse_id': self.warehouse.id,
'company_id': self.main_company.id,
'propagate': 'False',
})
def test_onchanges(self):
kanban = self.env['stock.request.kanban'].new({})
kanban.product_id = self.product
kanban.onchange_product_id()
kanban.company_id = self.main_company
kanban.onchange_company_id()
self.assertTrue(kanban.warehouse_id)
kanban.warehouse_id = self.wh2
kanban.onchange_warehouse_id()
self.assertEqual(kanban.company_id, self.company_2)
kanban.location_id = self.warehouse.view_location_id
kanban.onchange_location_id()
self.assertEqual(kanban.company_id, self.main_company)
self.assertEqual(kanban.warehouse_id, self.warehouse)
def test_create(self):
kanban = self.env['stock.request.kanban'].new({})
kanban.product_id = self.product
kanban.onchange_product_id()
kanban.product_uom_qty = 1
kanban = kanban.create(kanban._convert_to_write(kanban._cache))
self.assertTrue(kanban.company_id)
self.assertEqual(kanban.route_ids, self.route)
def test_order_barcodes(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,
})
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,
})
kanban_3 = self.env['stock.request.kanban'].create({
'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,
})
order = self.env['stock.request.order'].create({
'company_id': self.main_company.id,
'warehouse_id': self.warehouse.id,
'location_id': self.warehouse.lot_stock_id.id,
})
wizard = self.env['wizard.stock.request.order.kanban'].with_context(
default_order_id=order.id
).create({})
with self.assertRaises(ValidationError):
wizard.on_barcode_scanned(kanban_1.name)
self.pass_code(wizard, kanban_1.name)
self.assertEqual(wizard.status_state, 0)
self.assertTrue(order.stock_request_ids.filtered(
lambda r: r.kanban_id == kanban_1
))
self.pass_code(wizard, kanban_2.name)
self.assertTrue(order.stock_request_ids.filtered(
lambda r: r.kanban_id == kanban_2
))
self.assertEqual(wizard.status_state, 0)
self.pass_code(wizard, kanban_1.name)
self.assertEqual(wizard.status_state, 1)
self.pass_code(wizard, kanban_2.name+kanban_1.name)
self.assertEqual(wizard.status_state, 1)
with self.assertRaises(ValidationError):
self.pass_code(wizard, kanban_3.name)
def test_barcodes(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,
})
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,
})
wizard = self.env['wizard.stock.request.kanban'].with_context(
).create({})
with self.assertRaises(ValidationError):
wizard.on_barcode_scanned(kanban_1.name)
self.assertFalse(self.env['stock.request'].search(
[('kanban_id', '=', kanban_1.id)])
)
self.pass_code(wizard, kanban_1.name)
self.assertEqual(wizard.status_state, 0)
self.assertTrue(self.env['stock.request'].search(
[('kanban_id', '=', kanban_1.id)])
)
self.assertFalse(self.env['stock.request'].search(
[('kanban_id', '=', kanban_2.id)])
)
self.pass_code(wizard, kanban_2.name)
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])

View File

@@ -0,0 +1,146 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2017 Eficent
License LGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_stock_request_kanban_tree" model="ir.ui.view">
<field name="name">stock.request.kanban.tree</field>
<field name="model">stock.request.kanban</field>
<field name="arch" type="xml">
<tree string="Stock Requests" decoration-muted="active == 'false'" decoration-bf="message_needaction==True">
<field name="message_needaction" invisible="1"/>
<field name="name"/>
<field name="warehouse_id" groups="stock.group_stock_multi_locations"/>
<field name="location_id" groups="stock.group_stock_multi_locations"/>
<field name="route_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
<field name="product_id"/>
<field name="product_uom_id"
options="{'no_open': True, 'no_create': True}" groups="product.group_uom"/>
<field name="product_uom_qty"/>
<field name="active" invisible="1"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="stock_request_kanban_search">
<field name="name">stock.request.kanban.search</field>
<field name="model">stock.request.kanban</field>
<field name="arch" type="xml">
<search string="Stock Requests Kanban">
<field name="name" string="Stock Requests Kanban"/>
<field name="warehouse_id" groups="stock.group_stock_multi_locations"/>
<field name="location_id" groups="stock.group_stock_multi_locations"/>
<field name="company_id" groups="base.group_multi_company"/>
<field name="product_id"/>
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
<group expand="0" string="Group By">
<filter string="Warehouse" domain="[]" context="{'group_by':'warehouse_id'}"/>
<filter string="Location" domain="[]" context="{'group_by':'location_id'}"/>
</group>
</search>
</field>
</record>
<record id="view_stock_request_kanban_form" model="ir.ui.view">
<field name="name">stock.request.kanban.form</field>
<field name="model">stock.request.kanban</field>
<field name="arch" type="xml">
<form string="Stock Requests">
<header/>
<sheet>
<div class="oe_button_box" name="button_box"/>
<div class="oe_title">
<label string="Stock Request Kanban" />
<h1>
<field name="name" readonly="1"/>
</h1>
</div>
<group>
<group>
<field name="product_id"/>
</group>
<group>
<field name="warehouse_id" widget="selection" groups="stock.group_stock_multi_locations"/>
<field name="product_uom_id"
options="{'no_open': True, 'no_create': True}" groups="product.group_uom"/>
<field name="location_id" groups="stock.group_stock_multi_locations"/>
<field name="route_id"
options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
<field name="route_ids" invisible="1"/>
<field name="procurement_group_id"
groups="stock.group_adv_location"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
</group>
<group name="quantities">
<field name="product_uom_qty"/>
</group>
</group>
</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>
<!-- Partner Kanban View -->
<record model="ir.ui.view" id="stock_request_kanban_kanban_view">
<field name="name">stock.request.kanban.kanban</field>
<field name="model">stock.request.kanban</field>
<field name="arch" type="xml">
<kanban class="o_res_partner_kanban">
<field name="id"/>
<field name="name"/>
<field name="product_id"/>
<field name="display_name"/>
<field name="warehouse_id"/>
<field name="location_id"/>
<field name="product_qty"/>
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_global_click o_res_partner_kanban">
<div class="o_kanban_image">
<img t-att-src="kanban_image('product.product', 'image_small', record.product_id.raw_value)"/>
</div>
<div class="oe_kanban_details">
<strong class="o_kanban_record_title"><field name="display_name"/></strong>
<div class="o_kanban_tags_section"/>
<ul>
<li t-if="record.product_id.raw_value"><field name="product_id"/></li>
<li t-if="record.warehouse_id.raw_value" groups="stock.group_stock_multi_locations"><field name="warehouse_id"/></li>
<li t-if="record.location_id.raw_value" groups="stock.group_stock_multi_locations"><field name="location_id"/></li>
<li t-if="record.product_qty"><field name="product_qty"/></li>
</ul>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="stock_request_kanban_action" model="ir.actions.act_window">
<field name="name">Stock Request Kanbans</field>
<field name="res_model">stock.request.kanban</field>
<field name="type">ir.actions.act_window</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to add a Stock Request Kanban.
</p>
</field>
</record>
<menuitem id="stock_request_kanban_menu"
name="Stock Requests Kanbans"
parent="stock_request.menu_stock_request_root"
action="stock_request_kanban_action"
groups="stock_request.group_stock_request_manager"
sequence="30"/>
</odoo>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record model="ir.ui.view" id="stock_request_order_form">
<field name="name">stock.request.order.form</field>
<field name="model">stock.request.order</field>
<field name="inherit_id" ref="stock_request.stock_request_order_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button name="%(stock_request_kanban.wizard_stock_request_order_kanban_action)d"
type="action"
icon="fa-barcode"
string="Scan"
states="draft"
class="oe_read_only"
/>
</xpath>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,6 @@
# Copyright 2018 Creu Blanca
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from . import wizard_stock_request_kanban_abstract
from . import wizard_stock_request_kanban
from . import wizard_stock_request_order_kanban

View File

@@ -0,0 +1,14 @@
# 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 models
class WizardStockRequestOrderKanbanAbstract(models.TransientModel):
_name = "wizard.stock.request.kanban"
_inherit = "wizard.stock.request.kanban.abstract"
def barcode_ending(self):
self.stock_request_id.action_confirm()
return

View File

@@ -0,0 +1,90 @@
# 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, _
from odoo.exceptions import ValidationError
from reportlab.graphics.barcode import getCodes
class WizardStockRequestOrderKanbanAbstract(models.AbstractModel):
_name = "wizard.stock.request.kanban.abstract"
_inherit = "barcodes.barcode_events_mixin"
kanban_id = fields.Many2one(
'stock.request.kanban',
readonly=True,
)
stock_request_id = fields.Many2one(
'stock.request',
readonly=True,
)
status = fields.Text(
readonly=True,
default="Start scanning",
)
status_state = fields.Integer(
default=0,
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)
])
if not self.kanban_id:
self.status = _("Barcode %s does not correspond to any "
"Kanban. Try with another barcode or "
"press Close to finish scanning.") % barcode
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
def validate_kanban(self, barcode):
'''
It must return True if the kanban is valid, False otherwise
:param barcode:
: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,
}

View File

@@ -0,0 +1,56 @@
<?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_request_kanban_form" model="ir.ui.view">
<field name="name">wizard.stock.request.kanban.form</field>
<field name="model">wizard.stock.request.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="stock_request_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_request_kanban_action"
name="Add Kanban"
res_model="wizard.stock.request.kanban"
view_mode="form"
view_type="form"
target="new"/>
<menuitem
id="menu_wizard_stock_request_kanban"
action="wizard_stock_request_kanban_action"
name="Order Kanban Card" parent="stock_request.menu_stock_request_root"
sequence="20"/>
</odoo>

View File

@@ -0,0 +1,53 @@
# 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, _
from odoo.exceptions import ValidationError
class WizardStockRequestOrderKanban(models.TransientModel):
_name = "wizard.stock.request.order.kanban"
_inherit = "wizard.stock.request.kanban.abstract"
order_id = fields.Many2one(
'stock.request.order',
required=True
)
def validate_kanban(self, barcode):
res = super().validate_kanban(barcode)
if self.order_id.stock_request_ids.filtered(
lambda r: r.kanban_id == self.kanban_id
):
self.status = _("Barcode %s is on the order") % barcode
self.status_state = 1
return False
if self.order_id.state != 'draft':
raise ValidationError(_(
'Lines only can be added on orders with draft state'))
if not self.order_id.company_id:
self.order_id.company_id = self.kanban_id.company_id
elif self.order_id.company_id != self.kanban_id.company_id:
raise ValidationError(_('Company must be the same'))
if (
self.kanban_id.procurement_group_id and
self.order_id.procurement_group_id !=
self.kanban_id.procurement_group_id
):
raise ValidationError(_('Procurement group must be the same'))
if self.order_id.location_id != self.kanban_id.location_id:
raise ValidationError(_('Location must be the same'))
if self.order_id.warehouse_id != self.kanban_id.warehouse_id:
raise ValidationError(_('Warehouse must be the same'))
return res
def stock_request_kanban_values(self):
res = super().stock_request_kanban_values()
res['order_id'] = self.order_id.id,
res['expected_date'] = self.order_id.expected_date,
return res
def barcode_ending(self):
super().barcode_ending()
self.order_id = self.stock_request_id.order_id

View File

@@ -0,0 +1,31 @@
<?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_request_order_kanban_form" model="ir.ui.view">
<field name="name">wizard.stock.request.order.kanban.form</field>
<field name="model">wizard.stock.request.order.kanban</field>
<field name="mode">primary</field>
<field name="inherit_id" ref="wizard_stock_request_kanban_form"/>
<field name="arch" type="xml">
<field name="kanban_id" position="after">
<field name="order_id" invisible="1"/>
</field>
</field>
</record>
<act_window id="wizard_stock_request_order_kanban_action"
name="Add Kanban"
res_model="wizard.stock.request.order.kanban"
view_mode="form"
view_type="form"
context="{'default_order_id': active_id}"
target="new"/>
</odoo>