From 7e4a750a657679b631264b1bca99c65125dd5b29 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 11 Jun 2019 16:50:48 +0200 Subject: [PATCH 01/50] Prototype for kardex UI --- stock_kardex/__init__.py | 1 + stock_kardex/__manifest__.py | 24 ++ stock_kardex/models/__init__.py | 3 + stock_kardex/models/stock_kardex.py | 124 +++++++++ stock_kardex/models/stock_move_line.py | 0 stock_kardex/models/stock_picking_type.py | 0 stock_kardex/security/ir.model.access.csv | 3 + stock_kardex/static/src/js/kardex.js | 221 ++++++++++++++++ stock_kardex/static/src/scss/kardex_view.scss | 107 ++++++++ stock_kardex/views/stock_kardex_templates.xml | 11 + stock_kardex/views/stock_kardex_views.xml | 248 ++++++++++++++++++ stock_kardex/views/stock_move_line_views.xml | 4 + .../views/stock_picking_type_views.xml | 4 + 13 files changed, 750 insertions(+) create mode 100644 stock_kardex/__init__.py create mode 100644 stock_kardex/__manifest__.py create mode 100644 stock_kardex/models/__init__.py create mode 100644 stock_kardex/models/stock_kardex.py create mode 100644 stock_kardex/models/stock_move_line.py create mode 100644 stock_kardex/models/stock_picking_type.py create mode 100644 stock_kardex/security/ir.model.access.csv create mode 100644 stock_kardex/static/src/js/kardex.js create mode 100644 stock_kardex/static/src/scss/kardex_view.scss create mode 100644 stock_kardex/views/stock_kardex_templates.xml create mode 100644 stock_kardex/views/stock_kardex_views.xml create mode 100644 stock_kardex/views/stock_move_line_views.xml create mode 100644 stock_kardex/views/stock_picking_type_views.xml diff --git a/stock_kardex/__init__.py b/stock_kardex/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/stock_kardex/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_kardex/__manifest__.py b/stock_kardex/__manifest__.py new file mode 100644 index 000000000000..e21161415049 --- /dev/null +++ b/stock_kardex/__manifest__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + 'name': 'Kardex', + 'summary': 'Provides interaction and GUI for Kardex', + 'version': '12.0.1.0.0', + 'category': 'Stock', + 'author': 'Camptocamp', + 'license': 'AGPL-3', + 'depends': [ + 'stock', + 'barcodes', + ], + 'website': 'https://www.camptocamp.com', + 'data': [ + 'views/stock_move_line_views.xml', + 'views/stock_picking_type_views.xml', + 'views/stock_kardex_views.xml', + 'views/stock_kardex_templates.xml', + 'security/ir.model.access.csv', + ], + 'installable': True, +} diff --git a/stock_kardex/models/__init__.py b/stock_kardex/models/__init__.py new file mode 100644 index 000000000000..28f321cfc68e --- /dev/null +++ b/stock_kardex/models/__init__.py @@ -0,0 +1,3 @@ +from . import stock_kardex +from . import stock_move_line +from . import stock_picking_type diff --git a/stock_kardex/models/stock_kardex.py b/stock_kardex/models/stock_kardex.py new file mode 100644 index 000000000000..38491a8e1cb2 --- /dev/null +++ b/stock_kardex/models/stock_kardex.py @@ -0,0 +1,124 @@ +from random import randint + +from odoo import _, api, exceptions, fields, models + + +class StockKardex(models.Model): + _name = 'stock.kardex' + _inherit = 'barcodes.barcode_events_mixin' + _description = 'Stock Kardex' + + name = fields.Char() + address = fields.Char() + mode = fields.Selection( + [('pick', 'Pick'), ('put', 'Put'), ('inventory', 'Inventory')], + default='pick', + required=True, + ) + current_move_line = fields.Many2one(comodel_name='stock.move.line') + + operation_descr = fields.Char( + string="Operation", default="Scan next PID", readonly=True + ) + + # tray information (will come from stock.location or a new tray model) + kardex_tray_x = fields.Integer( + string='X', compute='_compute_kardex_tray_matrix' + ) + kardex_tray_y = fields.Integer( + string='Y', compute='_compute_kardex_tray_matrix' + ) + kardex_tray_matrix = fields.Serialized( + compute='_compute_kardex_tray_matrix' + ) + + # current operation information + picking_id = fields.Many2one( + related='current_move_line.picking_id', readonly=True + ) + product_id = fields.Many2one( + related='current_move_line.product_id', readonly=True + ) + product_uom_id = fields.Many2one( + related='current_move_line.product_uom_id', readonly=True + ) + product_uom_qty = fields.Float( + related='current_move_line.product_uom_qty', readonly=True + ) + qty_done = fields.Float( + related='current_move_line.qty_done', readonly=True + ) + lot_id = fields.Many2one(related='current_move_line.lot_id', readonly=True) + + _barcode_scanned = fields.Char( + "Barcode Scanned", + help="Value of the last barcode scanned.", + store=False, + ) + + def on_barcode_scanned(self, barcode): + raise exceptions.UserError('Scanned barcode: {}'.format(barcode)) + + @api.depends() + def _compute_kardex_tray_matrix(self): + for record in self: + # prototype code, random matrix + cols = randint(4, 8) + rows = randint(1, 3) + selected = [randint(0, cols - 1), randint(0, rows - 1)] + cells = [] + for __ in range(rows): + row = [] + for __ in range(cols): + row.append(randint(0, 1)) + cells.append(row) + + record.kardex_tray_x = selected[0] + 1 + record.kardex_tray_y = selected[1] + 1 + record.kardex_tray_matrix = { + # x, y: position of the selected cell + 'selected': selected, + # 0 is empty, 1 is not + 'cells': cells, + } + + def action_open_screen(self): + self.ensure_one() + screen_xmlid = 'stock_kardex.stock_kardex_view_form_screen' + return { + 'type': 'ir.actions.act_window', + 'res_model': self._name, + 'views': [[self.env.ref(screen_xmlid).id, 'form']], + 'res_id': self.id, + 'target': 'fullscreen', + 'flags': { + 'headless': True, + 'form_view_initial_mode': 'edit', + 'no_breadcrumbs': True, + }, + } + + def action_menu(self): + menu_xmlid = 'stock_kardex.stock_kardex_form_menu' + return { + 'type': 'ir.actions.act_window', + 'res_model': 'stock.kardex', + 'views': [[self.env.ref(menu_xmlid).id, 'form']], + 'name': _('Menu'), + 'target': 'new', + 'res_id': self.id, + } + + def action_quit_screen(self): + action_xmlid = 'stock_kardex.stock_kardex_action' + return self.env.ref(action_xmlid).read()[0] + + # TODO: should the mode be changed on all the kardex at the same time? + def switch_pick(self): + self.mode = 'pick' + + def switch_put(self): + self.mode = 'put' + + def switch_inventory(self): + self.mode = 'inventory' diff --git a/stock_kardex/models/stock_move_line.py b/stock_kardex/models/stock_move_line.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/stock_kardex/models/stock_picking_type.py b/stock_kardex/models/stock_picking_type.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/stock_kardex/security/ir.model.access.csv b/stock_kardex/security/ir.model.access.csv new file mode 100644 index 000000000000..bcc602b1e404 --- /dev/null +++ b/stock_kardex/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_stock_kardex_stock_user,access_stock_kardex stock user,model_stock_kardex,stock.group_stock_user,1,0,0,0 +access_stock_kardex_manager,access_stock_kardex stock manager,model_stock_kardex,stock.group_stock_manager,1,1,1,1 diff --git a/stock_kardex/static/src/js/kardex.js b/stock_kardex/static/src/js/kardex.js new file mode 100644 index 000000000000..d9fafc25340a --- /dev/null +++ b/stock_kardex/static/src/js/kardex.js @@ -0,0 +1,221 @@ +odoo.define('stock_kardex.kardex', function (require) { +"use strict"; + + +var core = require('web.core'); +var KanbanRecord = require('web.KanbanRecord'); +var basicFields = require('web.basic_fields'); +var field_registry = require('web.field_registry'); +var DebouncedField = basicFields.DebouncedField; +var FieldInteger = basicFields.FieldInteger; + +KanbanRecord.include({ + + _openRecord: function () { + if (this.modelName === 'stock.kardex' + && this.$el.hasClass("open_kardex_screen")) { + var self = this; + this._rpc({ + method: 'action_open_screen', + model: self.modelName, + args: [self.id], + }).then(function (result) { + self.do_action(result); + }); + } else { + this._super.apply(this, arguments); + } + }, + +}); + +var ExitButton = FieldInteger.extend({ + tagName: 'button', + className: 'btn btn-danger btn-block btn-lg o_kardex_exit', + events: { + 'click': '_onClick', + }, + _render: function () { + this.$el.text(this.string); + }, + _onClick: function () { + // the only reason to have this field widget is to be able + // to inject clear_breadcrumbs in the action: + // it will revert back to a normal - non-headless - view + this.do_action('stock_kardex.stock_kardex_action', { + clear_breadcrumbs: true, + }); + }, +}); + +var KardexTrayMatrixField = DebouncedField.extend({ + className: 'o_field_kardex_tray_matrix', + tagName: 'canvas', + supportedFieldTypes: ['serialized'], + + cellColorEmpty: '#ffffff', + cellColorNotEmpty: '#4e6bfd', + selectedColor: '#08f46b', + selectedLineWidth: 5, + globalAlpha: 0.8, + cellPadding: 2, + + isSet: function () { + if (Object.keys(this.value).length === 0) { + return false; + } + if (this.value.cells.length === 0) { + return false; + } + return this._super.apply(this, arguments); + }, + + start: function () { + // Setup resize events to redraw the canvas + this._resizeDebounce = this._resizeDebounce.bind(this); + this._resizePromise = null; + $(window).on('resize', this._resizeDebounce); + + var self = this; + return this._super.apply(this, arguments).then(function () { + // _super calls _render(), but the function + // resizeCanvasToDisplaySize would resize the canvas + // to 0 because the actual canvas would still be unknown. + // Call again _render() here but through a setTimeout to + // let the js renderer thread catch up. + self._ready = true; + return self._resizeDebounce(); + }); + }, + + /** + * Debounce the rendering on resize. + * It is useless to render on each resize event. + * + */ + _resizeDebounce: function(){ + clearTimeout(this._resizePromise); + var self = this; + this._resizePromise = setTimeout(function(){ + self._render(); + }, 20); + }, + + destroy: function () { + $(window).off('resize', this._resizeDebounce); + this._super.apply(this, arguments); + }, + + /** + * Render the widget only when it is in the DOM. + * We need the width and height of the widget to draw the canvas. + * + */ + _render: function () { + if (this._ready) { + return this._renderInDOM(); + } + return $.when(); + }, + + /** + * Resize the canvas width and height to the actual size. + * If we don't do that, it will automatically scale to the + * CSS size with blurry squares. + * + */ + resizeCanvasToDisplaySize: function(canvas) { + // look up the size the canvas is being displayed + const width = canvas.clientWidth; + const height = canvas.clientHeight; + + // If it's resolution does not match change it + if (canvas.width !== width || canvas.height !== height) { + canvas.width = width; + canvas.height = height; + return true; + } + + return false; + }, + + /** + * Resize the canvas, clear it and redraw the cells + * Should be called only if the canvas is already in DOM + * + */ + _renderInDOM: function () { + this.canvas = this.$el.find('canvas').context; + var canvas = this.canvas; + var ctx = canvas.getContext('2d'); + this.resizeCanvasToDisplaySize(ctx.canvas); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.save(); + if (this.isSet()) { + var selected = this.value.selected || []; + var cells = this.value.cells; + this._drawMatrix(canvas, ctx, cells, selected); + } + }, + + /** + * Draw the cells in the canvas. + * + */ + _drawMatrix: function (canvas, ctx, cells, selected) { + var colors = { + 0: this.cellColorEmpty, + 1: this.cellColorNotEmpty, + }; + + var cols = cells[0].length; + var rows = cells.length; + var selectedX, selectedY; + if (selected.length) { + selectedX = selected[0]; + // we draw top to bottom, but the highlighted cell should + // be a coordinate from bottom to top: reverse the y axis + selectedY = Math.abs(selected[1] - rows + 1); + } + + var padding = this.cellPadding; + var w = ((canvas.width - padding * cols) / cols); + var h = ((canvas.height - padding * rows) / rows); + + ctx.globalAlpha = this.globalAlpha; + for (var y = 0; y < rows; y++) { + for (var x = 0; x < cols; x++) { + ctx.fillStyle = colors[cells[y][x]]; + var fillWidth = w; + var fillHeight = h; + // cheat: remove the padding at bottom and right + // the cells will be a bit larger but not really noticeable + if (x === cols - 1) {fillWidth += padding;} + if (y === rows - 1) {fillHeight += padding;} + ctx.fillRect( + x * (w + padding), y * (h + padding), + fillWidth, fillHeight + ); + if (selected && selectedX === x && selectedY === y) { + ctx.globalAlpha = 1.0; + ctx.strokeStyle = this.selectedColor; + ctx.lineWidth = this.selectedLineWidth; + ctx.strokeRect(x * (w + padding), y * (h + padding), w, h); + ctx.globalAlpha = this.globalAlpha; + } + } + } + ctx.restore(); + } +}); + + +field_registry.add('exit_button', ExitButton); +field_registry.add('kardex_tray_matrix', KardexTrayMatrixField); + +return { + ExitButton: ExitButton, + KardexTrayMatrixField: KardexTrayMatrixField +}; + +}); diff --git a/stock_kardex/static/src/scss/kardex_view.scss b/stock_kardex/static/src/scss/kardex_view.scss new file mode 100644 index 000000000000..fd381a39128f --- /dev/null +++ b/stock_kardex/static/src/scss/kardex_view.scss @@ -0,0 +1,107 @@ +.o_web_client.o_fullscreen { + $o-kardex-padding: $o-horizontal-padding; + + .o_form_view.o_kardex { + display: flex; + flex-flow: column nowrap; + padding: 0; + + font-size: 16px; + + @include media-breakpoint-up(xl) { + font-size: 18px; + } + + .btn { + font-size: 1em; + padding: 1em; + margin: 0 5px; + } + + .o_kardex_header { + display: flex; + flex-flow: row wrap; + padding: $o-kardex-padding; + } + + .o_kardex_header_content { + display: flex; + flex-flow: row nowrap; + font-size: 2.0em; + flex: 1 0 auto; + align-items: center; + width: 33%; + + &.o_kardex_header_right { + justify-content: flex-end; + } + } + + .o_kardex_actions { + display: flex; + flex-flow: row nowrap; + font-size: 1.2em; + padding: $o-kardex-padding * 0.5; + } + + .o_kardex_operation { + font-size: 2.5em; + padding: 0.5em; + color: #ffffff; + } + + .o_kardex_content { + display: flex; + flex-flow: row nowrap; + flex: 1 0 auto; + align-items: center; + + &.o_kardex_content_right { + justify-content: flex-end; + } + } + + .o_kardex_data { + display: flex; + flex-flow: row wrap; + padding: $o-kardex-padding * 0.5; + + .o_kardex_data_content { + flex-flow: row nowrap; + font-size: 1.2em; + flex: 1 0 auto; + align-items: center; + width: 50%; + + &.o_kardex_tray { + display: flex; + justify-content: flex-end; + + .o_group { + display: block; + } + + canvas { + width: 450px; + background-color: #ffffff; + border: 2px #000000 solid; + } + } + } + } + + } + + .o_kardex_menu { + .btn { + margin-bottom: $o-kardex-padding; + padding: 1em; + font-size: 2em; + text-transform: uppercase; + } + + .o_kardex_exit { + text-align: center; + } + } +} diff --git a/stock_kardex/views/stock_kardex_templates.xml b/stock_kardex/views/stock_kardex_templates.xml new file mode 100644 index 000000000000..340339fdef03 --- /dev/null +++ b/stock_kardex/views/stock_kardex_templates.xml @@ -0,0 +1,11 @@ + + + + + + diff --git a/stock_kardex/views/stock_kardex_views.xml b/stock_kardex/views/stock_kardex_views.xml new file mode 100644 index 000000000000..90e52c65a75b --- /dev/null +++ b/stock_kardex/views/stock_kardex_views.xml @@ -0,0 +1,248 @@ + + + + + stock.kardex.view.form.screen + stock.kardex + 99 + +
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+
+ +
+ + + + + Tray + + + + + SHU-1108 + + + + + + Box Type + + + + B30401 + + + + + + +
+ +
+
+
+ + +
+
+ + + stock.kardex.view.form.menu + stock.kardex + 100 + +
+
+
+
+
+ +
+
+
+
+
+
+ + + stock.kardex.view.form + stock.kardex + +
+ + + + + + + +
+
+
+ + + stock.kardex.kanban + stock.kardex + + + + + + + +
+
+ +
+
+
+ + + +
+ Mode: +
+
+ + + +
+
+
+
+
+
+
+ + + stock.kardex.tree + stock.kardex + + + + + + + + + + + Kardex + ir.actions.act_window + stock.kardex + form + form + + fullscreen + [] + {'form_view_initial_mode': 'edit', 'no_breadcrumbs': True} + +

+ Open the Kardex Interface. +

+
+
+ + + Kardex + ir.actions.act_window + stock.kardex + form + kanban,tree,form + current + [] + {} + +

+ Open the Kardex Interface. +

+
+
+ + + +
diff --git a/stock_kardex/views/stock_move_line_views.xml b/stock_kardex/views/stock_move_line_views.xml new file mode 100644 index 000000000000..1d77a6b31998 --- /dev/null +++ b/stock_kardex/views/stock_move_line_views.xml @@ -0,0 +1,4 @@ + + + + diff --git a/stock_kardex/views/stock_picking_type_views.xml b/stock_kardex/views/stock_picking_type_views.xml new file mode 100644 index 000000000000..1d77a6b31998 --- /dev/null +++ b/stock_kardex/views/stock_picking_type_views.xml @@ -0,0 +1,4 @@ + + + + From bae9b34e22ddc6356b410ce4ee1fb2edf2be5e46 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 14 Jun 2019 15:08:51 +0200 Subject: [PATCH 02/50] Add tray types --- stock_kardex/__manifest__.py | 2 + stock_kardex/data/stock_kardex_tray_type.xml | 74 +++++++++++++++++ stock_kardex/models/__init__.py | 2 + stock_kardex/models/stock_kardex.py | 2 + stock_kardex/models/stock_kardex_tray_type.py | 30 +++++++ stock_kardex/models/stock_location.py | 20 +++++ stock_kardex/security/ir.model.access.csv | 2 + stock_kardex/static/src/scss/kardex_view.scss | 13 +-- .../views/stock_kardex_tray_type_views.xml | 80 +++++++++++++++++++ 9 files changed, 220 insertions(+), 5 deletions(-) create mode 100644 stock_kardex/data/stock_kardex_tray_type.xml create mode 100644 stock_kardex/models/stock_kardex_tray_type.py create mode 100644 stock_kardex/models/stock_location.py create mode 100644 stock_kardex/views/stock_kardex_tray_type_views.xml diff --git a/stock_kardex/__manifest__.py b/stock_kardex/__manifest__.py index e21161415049..f784e62ed00b 100644 --- a/stock_kardex/__manifest__.py +++ b/stock_kardex/__manifest__.py @@ -17,7 +17,9 @@ 'views/stock_move_line_views.xml', 'views/stock_picking_type_views.xml', 'views/stock_kardex_views.xml', + 'views/stock_kardex_tray_type_views.xml', 'views/stock_kardex_templates.xml', + 'data/stock_kardex_tray_type.xml', 'security/ir.model.access.csv', ], 'installable': True, diff --git a/stock_kardex/data/stock_kardex_tray_type.xml b/stock_kardex/data/stock_kardex_tray_type.xml new file mode 100644 index 000000000000..78497088cb9d --- /dev/null +++ b/stock_kardex/data/stock_kardex_tray_type.xml @@ -0,0 +1,74 @@ + + + + + Klein 32x + B10804 + 4 + 8 + + + + Klein 16x + B20802 + 2 + 8 + + + + Klein 8x + B20402 + 2 + 4 + + + + Klein 16x + B40802 + 2 + 8 + + + + Klein 16x + B30404 + 4 + 4 + + + + Gross 32x + B20804 + 4 + 8 + + + + Gross 16x + B30802 + 2 + 8 + + + + Gross 8x + B30402 + 2 + 4 + + + + Gross 4x + B30401 + 1 + 4 + + + + Gross 16x + B30404 + 4 + 4 + + + diff --git a/stock_kardex/models/__init__.py b/stock_kardex/models/__init__.py index 28f321cfc68e..72c066a96f7b 100644 --- a/stock_kardex/models/__init__.py +++ b/stock_kardex/models/__init__.py @@ -1,3 +1,5 @@ from . import stock_kardex +from . import stock_kardex_tray_type from . import stock_move_line +from . import stock_location from . import stock_picking_type diff --git a/stock_kardex/models/stock_kardex.py b/stock_kardex/models/stock_kardex.py index 38491a8e1cb2..4322aae778fc 100644 --- a/stock_kardex/models/stock_kardex.py +++ b/stock_kardex/models/stock_kardex.py @@ -1,3 +1,5 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from random import randint from odoo import _, api, exceptions, fields, models diff --git a/stock_kardex/models/stock_kardex_tray_type.py b/stock_kardex/models/stock_kardex_tray_type.py new file mode 100644 index 000000000000..41496f577db6 --- /dev/null +++ b/stock_kardex/models/stock_kardex_tray_type.py @@ -0,0 +1,30 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class StockKardexTrayType(models.Model): + _name = 'stock.kardex.tray.type' + _description = 'Stock Kardex Tray Type' + + name = fields.Char(required=True) + code = fields.Char(required=True) + rows = fields.Integer(required=True) + cols = fields.Integer(required=True) + active = fields.Boolean(default=True) + tray_matrix = fields.Serialized(compute='_compute_tray_matrix') + # TODO do we want box size, or a many2one to 'product.packaging'? + + @api.depends('rows', 'cols') + def _compute_tray_matrix(self): + for record in self: + # As we only want to show the disposition of + # the tray, we generate a "full" tray, we'll + # see all the boxes on the web widget. + # (0 means empty, 1 means used) + cells = [[1] * record.cols for __ in range(record.rows)] + + record.tray_matrix = {'selected': None, 'cells': cells} + + # TODO prevent to set active=False on a type used in a location diff --git a/stock_kardex/models/stock_location.py b/stock_kardex/models/stock_location.py new file mode 100644 index 000000000000..0a7dcad3e755 --- /dev/null +++ b/stock_kardex/models/stock_location.py @@ -0,0 +1,20 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class StockLocation(models.Model): + _inherit = "stock.location" + + kardey_tray = fields.Boolean() + kardex_tray_type_id = fields.Many2one( + comodel_name="stock.kardex.tray.type", + ondelete="restrict", + # TODO: later, we'll want a wizard to change the type, + # that will check if the sublocations are empty before + # changing. It will disable the sublocations and create + # new ones according to the tray disposition. This field + # will then be readonly. + # readonly=True, + ) diff --git a/stock_kardex/security/ir.model.access.csv b/stock_kardex/security/ir.model.access.csv index bcc602b1e404..32b082c9579b 100644 --- a/stock_kardex/security/ir.model.access.csv +++ b/stock_kardex/security/ir.model.access.csv @@ -1,3 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_stock_kardex_stock_user,access_stock_kardex stock user,model_stock_kardex,stock.group_stock_user,1,0,0,0 access_stock_kardex_manager,access_stock_kardex stock manager,model_stock_kardex,stock.group_stock_manager,1,1,1,1 +access_stock_kardex_tray_type_stock_user,access_stock_kardex_tray_type stock user,model_stock_kardex_tray_type,stock.group_stock_user,1,0,0,0 +access_stock_kardex_tray_type_manager,access_stock_kardex_tray_type stock manager,model_stock_kardex_tray_type,stock.group_stock_manager,1,1,1,1 diff --git a/stock_kardex/static/src/scss/kardex_view.scss b/stock_kardex/static/src/scss/kardex_view.scss index fd381a39128f..c99642ca5045 100644 --- a/stock_kardex/static/src/scss/kardex_view.scss +++ b/stock_kardex/static/src/scss/kardex_view.scss @@ -1,3 +1,8 @@ +.o_field_kardex_tray_matrix { + background-color: #eeeeee; + border: 2px #000000 solid; +} + .o_web_client.o_fullscreen { $o-kardex-padding: $o-horizontal-padding; @@ -80,12 +85,10 @@ .o_group { display: block; } + } - canvas { - width: 450px; - background-color: #ffffff; - border: 2px #000000 solid; - } + .o_field_kardex_tray_matrix { + width: 450px; } } } diff --git a/stock_kardex/views/stock_kardex_tray_type_views.xml b/stock_kardex/views/stock_kardex_tray_type_views.xml new file mode 100644 index 000000000000..41afb453cfa9 --- /dev/null +++ b/stock_kardex/views/stock_kardex_tray_type_views.xml @@ -0,0 +1,80 @@ + + + + + stock.kardex.tray.type.form + stock.kardex.tray.type + +
+
+ +
+
+
+ + + stock.kardex.tray.type.search + stock.kardex.tray.type + + + + + + + + + + + + stock.kardex.tray.type + stock.kardex.tray.type + + + + + + + + + + + + Kardex Tray Types + stock.kardex.tray.type + ir.actions.act_window + form + + + + +

+ Add a Kardex Tray Type +

+ Define the number of rows and cols on a tray, depending of the boxes +size. +

+
+
+ + + +
From 40961543ee2b0f3ad0c95eccd35268ac9250cf43 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 14 Jun 2019 15:57:13 +0200 Subject: [PATCH 03/50] Autogenerate tray sublocations --- stock_kardex/__manifest__.py | 1 + stock_kardex/models/stock_kardex_tray_type.py | 2 + stock_kardex/models/stock_location.py | 67 ++++++++++++++++--- stock_kardex/views/stock_location_views.xml | 19 ++++++ 4 files changed, 81 insertions(+), 8 deletions(-) create mode 100644 stock_kardex/views/stock_location_views.xml diff --git a/stock_kardex/__manifest__.py b/stock_kardex/__manifest__.py index f784e62ed00b..2e52c25717d4 100644 --- a/stock_kardex/__manifest__.py +++ b/stock_kardex/__manifest__.py @@ -14,6 +14,7 @@ ], 'website': 'https://www.camptocamp.com', 'data': [ + 'views/stock_location_views.xml', 'views/stock_move_line_views.xml', 'views/stock_picking_type_views.xml', 'views/stock_kardex_views.xml', diff --git a/stock_kardex/models/stock_kardex_tray_type.py b/stock_kardex/models/stock_kardex_tray_type.py index 41496f577db6..4e3a69ed28c4 100644 --- a/stock_kardex/models/stock_kardex_tray_type.py +++ b/stock_kardex/models/stock_kardex_tray_type.py @@ -28,3 +28,5 @@ def _compute_tray_matrix(self): record.tray_matrix = {'selected': None, 'cells': cells} # TODO prevent to set active=False on a type used in a location + # TODO we should not be able to change cells and rows for types used + # in locations diff --git a/stock_kardex/models/stock_location.py b/stock_kardex/models/stock_location.py index 0a7dcad3e755..c421700bbdce 100644 --- a/stock_kardex/models/stock_location.py +++ b/stock_kardex/models/stock_location.py @@ -1,20 +1,71 @@ # Copyright 2019 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import fields, models +from odoo import _, api, fields, models class StockLocation(models.Model): _inherit = "stock.location" - kardey_tray = fields.Boolean() + kardex_tray = fields.Boolean() kardex_tray_type_id = fields.Many2one( + comodel_name="stock.kardex.tray.type", ondelete="restrict" + ) + + # Only for trays cells (boxes). + # Children of 'kardey_tray' locations, they are automatically generated + generated_for_tray_type_id = fields.Many2one( comodel_name="stock.kardex.tray.type", ondelete="restrict", - # TODO: later, we'll want a wizard to change the type, - # that will check if the sublocations are empty before - # changing. It will disable the sublocations and create - # new ones according to the tray disposition. This field - # will then be readonly. - # readonly=True, + readonly=True, ) + + @api.model + def create(self, vals): + records = super().create(vals) + if vals.get('kardex_tray'): + records._update_tray_sublocations() + return records + + @api.multi + def write(self, vals): + result = super().write(vals) + if vals.get('kardex_tray') or vals.get('kardex_tray_type_id'): + self._update_tray_sublocations() + return result + + @api.multi + def _update_tray_sublocations(self): + # TODO: if any sublocation has stock, raise an error, + # we must be able to change the type of tray only when + # it is empty + values = [] + for location in self: + if not location.kardex_tray: + sublocs = location.child_ids.filtered( + lambda r: r.generated_for_tray_type_id + ) + sublocs.write({'active': False}) + continue + + tray_type = location.kardex_tray_type_id + sublocs = location.child_ids.filtered( + lambda r: r.generated_for_tray_type_id != tray_type + ) + sublocs.write({'active': False}) + + # create accepts several records now + for row in range(1, tray_type.rows + 1): + for col in range(1, tray_type.cols + 1): + subloc_values = { + 'name': _('{} [x{} y{}]').format( + location.name, col, row + ), + 'posx': col, + 'posy': row, + 'location_id': location.id, + 'company_id': location.company_id.id, + 'generated_for_tray_type_id': tray_type.id, + } + values.append(subloc_values) + self.create(values) diff --git a/stock_kardex/views/stock_location_views.xml b/stock_kardex/views/stock_location_views.xml new file mode 100644 index 000000000000..d8e97a32eb07 --- /dev/null +++ b/stock_kardex/views/stock_location_views.xml @@ -0,0 +1,19 @@ + + + + + stock.location.form.kardex + stock.location + + + + + + + + + + + + From 97ba5a81ac3a68307ed327503553b646620bc01a Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 18 Jun 2019 16:42:25 +0200 Subject: [PATCH 04/50] Add kardex attribute on stock locations The kardex_tray field indicates it is a tray, but we still needed to identify a whole kardex shelf. On the 'stock.kardex' model, we must select the corresponding location. --- stock_kardex/models/stock_kardex.py | 9 +++++++++ stock_kardex/models/stock_location.py | 12 ++++++++++++ stock_kardex/views/stock_kardex_views.xml | 1 + stock_kardex/views/stock_location_views.xml | 8 ++++++-- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/stock_kardex/models/stock_kardex.py b/stock_kardex/models/stock_kardex.py index 4322aae778fc..3c82726f0ba4 100644 --- a/stock_kardex/models/stock_kardex.py +++ b/stock_kardex/models/stock_kardex.py @@ -17,6 +17,15 @@ class StockKardex(models.Model): default='pick', required=True, ) + location_id = fields.Many2one( + comodel_name='stock.location', + required=True, + domain="[('kardex', '=', True)]", + context="{'default_kardex': True}", + ondelete='restrict', + help="The Kardex source location for Pick operations " + "and destination location for Put operations.", + ) current_move_line = fields.Many2one(comodel_name='stock.move.line') operation_descr = fields.Char( diff --git a/stock_kardex/models/stock_location.py b/stock_kardex/models/stock_location.py index c421700bbdce..63ea1c17acf2 100644 --- a/stock_kardex/models/stock_location.py +++ b/stock_kardex/models/stock_location.py @@ -7,6 +7,8 @@ class StockLocation(models.Model): _inherit = "stock.location" + kardex = fields.Boolean() + parent_is_kardex = fields.Boolean(compute='_compute_parent_is_kardex') kardex_tray = fields.Boolean() kardex_tray_type_id = fields.Many2one( comodel_name="stock.kardex.tray.type", ondelete="restrict" @@ -20,6 +22,16 @@ class StockLocation(models.Model): readonly=True, ) + @api.depends('location_id.parent_is_kardex') + def _compute_parent_is_kardex(self): + for location in self: + parent = location.location_id + while parent: + if parent.kardex: + location.parent_is_kardex = True + break + parent = parent.location_id + @api.model def create(self, vals): records = super().create(vals) diff --git a/stock_kardex/views/stock_kardex_views.xml b/stock_kardex/views/stock_kardex_views.xml index 90e52c65a75b..2dd8a627e30d 100644 --- a/stock_kardex/views/stock_kardex_views.xml +++ b/stock_kardex/views/stock_kardex_views.xml @@ -145,6 +145,7 @@ + diff --git a/stock_kardex/views/stock_location_views.xml b/stock_kardex/views/stock_location_views.xml index d8e97a32eb07..dbc5e64dde4c 100644 --- a/stock_kardex/views/stock_location_views.xml +++ b/stock_kardex/views/stock_location_views.xml @@ -8,9 +8,13 @@ - + + + + attrs="{'invisible': [('kardex_tray', '=', False)], 'required': [('kardex_tray', '=', True)]}"/> From b2beb624392deb7ccbdbf7aa7fe4c36bd265f495 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 18 Jun 2019 16:43:48 +0200 Subject: [PATCH 05/50] Add basic handling of Pick scenario --- stock_kardex/models/stock_kardex.py | 105 +++++++++++++++++++++- stock_kardex/views/stock_kardex_views.xml | 24 ++++- 2 files changed, 122 insertions(+), 7 deletions(-) diff --git a/stock_kardex/models/stock_kardex.py b/stock_kardex/models/stock_kardex.py index 3c82726f0ba4..2d8372e15c39 100644 --- a/stock_kardex/models/stock_kardex.py +++ b/stock_kardex/models/stock_kardex.py @@ -28,6 +28,14 @@ class StockKardex(models.Model): ) current_move_line = fields.Many2one(comodel_name='stock.move.line') + number_of_ops = fields.Integer( + compute='_compute_number_of_ops', string='Number of Operations' + ) + number_of_ops_all = fields.Integer( + compute='_compute_number_of_ops_all', + string='Number of Operations in all Kardex', + ) + operation_descr = fields.Char( string="Operation", default="Scan next PID", readonly=True ) @@ -70,6 +78,16 @@ class StockKardex(models.Model): def on_barcode_scanned(self, barcode): raise exceptions.UserError('Scanned barcode: {}'.format(barcode)) + @api.depends() + def _compute_number_of_ops(self): + for record in self: + record.number_of_ops = record.count_move_lines_to_do() + + @api.depends() + def _compute_number_of_ops_all(self): + for record in self: + record.number_of_ops_all = record.count_move_lines_to_do_all() + @api.depends() def _compute_kardex_tray_matrix(self): for record in self: @@ -93,7 +111,90 @@ def _compute_kardex_tray_matrix(self): 'cells': cells, } + def _domain_move_lines_to_do(self): + domain = [ + # TODO check state + ('state', '=', 'assigned') + ] + domain_extensions = { + 'pick': [('location_id', 'child_of', self.location_id.id)], + 'put': [('location_dest_id', 'child_of', self.location_id.id)], + # TODO + 'inventory': [('id', '=', 0)], + } + return domain + domain_extensions[self.mode] + + def _domain_move_lines_to_do_all(self): + domain = [ + # TODO check state + ('state', '=', 'assigned') + ] + kardex_locations = self.env['stock.location'].search( + [('kardex', '=', True)] + ) + domain_extensions = { + 'pick': [('location_id', 'child_of', kardex_locations.ids)], + 'put': [('location_dest_id', 'child_of', kardex_locations.ids)], + # TODO + 'inventory': [('id', '=', 0)], + } + return domain + domain_extensions[self.mode] + + def count_move_lines_to_do(self): + self.ensure_one() + return self.env['stock.move.line'].search_count( + self._domain_move_lines_to_do() + ) + + def count_move_lines_to_do_all(self): + self.ensure_one() + return self.env['stock.move.line'].search_count( + self._domain_move_lines_to_do_all() + ) + + def button_release(self): + raise exceptions.UserError(_('what does this one do?')) + + def process_current_pick(self): + # test code, TODO the smart one + # (scan of barcode increments qty, save calls action_done?) + line = self.current_move_line + line.qty_done = line.product_qty + line.move_id._action_done() + + def process_current_put(self): + raise exceptions.UserError(_('Put workflow not implemented')) + + def process_current_inventory(self): + raise exceptions.UserError(_('Inventory workflow not implemented')) + + def button_save(self): + self.ensure_one() + method = 'process_current_{}'.format(self.mode) + getattr(self, method)() + self.select_next_move_line() + if not self.current_move_line: + # sorry not sorry + return { + 'effect': { + 'fadeout': 'slow', + 'message': _('Congrats, you cleared the queue!'), + 'img_url': '/web/static/src/img/smile.svg', + 'type': 'rainbow_man', + } + } + + # TODO call this each time we process a move line + def select_next_move_line(self): + self.ensure_one() + # TODO sort? + next_move_line = self.env['stock.move.line'].search( + self._domain_move_lines_to_do(), limit=1 + ) + self.current_move_line = next_move_line + def action_open_screen(self): + self.select_next_move_line() self.ensure_one() screen_xmlid = 'stock_kardex.stock_kardex_view_form_screen' return { @@ -120,10 +221,6 @@ def action_menu(self): 'res_id': self.id, } - def action_quit_screen(self): - action_xmlid = 'stock_kardex.stock_kardex_action' - return self.env.ref(action_xmlid).read()[0] - # TODO: should the mode be changed on all the kardex at the same time? def switch_pick(self): self.mode = 'pick' diff --git a/stock_kardex/views/stock_kardex_views.xml b/stock_kardex/views/stock_kardex_views.xml index 2dd8a627e30d..f5a1371467db 100644 --- a/stock_kardex/views/stock_kardex_views.xml +++ b/stock_kardex/views/stock_kardex_views.xml @@ -16,6 +16,9 @@
+
@@ -27,13 +30,13 @@
-
From b053444fe453382681bcab94ac2f8976b2897f10 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 18 Jun 2019 17:04:34 +0200 Subject: [PATCH 06/50] Replace random matrix by actual location configuration --- stock_kardex/models/stock_kardex.py | 45 +++++++++++++++++++---- stock_kardex/views/stock_kardex_views.xml | 28 +------------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/stock_kardex/models/stock_kardex.py b/stock_kardex/models/stock_kardex.py index 2d8372e15c39..32ae956988d3 100644 --- a/stock_kardex/models/stock_kardex.py +++ b/stock_kardex/models/stock_kardex.py @@ -1,6 +1,5 @@ # Copyright 2019 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from random import randint from odoo import _, api, exceptions, fields, models @@ -41,6 +40,22 @@ class StockKardex(models.Model): ) # tray information (will come from stock.location or a new tray model) + kardex_tray_location_id = fields.Many2one( + comodel_name='stock.location', + compute='_compute_kardex_tray_matrix', + string='Tray Location', + ) + kardex_tray_name = fields.Char( + compute='_compute_kardex_tray_matrix', string='Tray Name' + ) + kardex_tray_type_id = fields.Many2one( + comodel_name='stock.kardex.tray.type', + compute='_compute_kardex_tray_matrix', + string='Tray Type', + ) + kardex_tray_type_code = fields.Char( + compute='_compute_kardex_tray_matrix', string='Tray Type' + ) kardex_tray_x = fields.Integer( string='X', compute='_compute_kardex_tray_matrix' ) @@ -91,19 +106,33 @@ def _compute_number_of_ops_all(self): @api.depends() def _compute_kardex_tray_matrix(self): for record in self: - # prototype code, random matrix - cols = randint(4, 8) - rows = randint(1, 3) - selected = [randint(0, cols - 1), randint(0, rows - 1)] + modes = { + 'pick': 'location_id', + 'put': 'location_dest_id', + # TODO what to do for inventory? + 'inventory': 'location_id', + } + location = record.current_move_line[modes[record.mode]] + tray_type = location.generated_for_tray_type_id + cols = tray_type.cols + rows = tray_type.rows + selected = [] + if location: + selected = [location.posx - 1, location.posy - 1] cells = [] for __ in range(rows): row = [] for __ in range(cols): - row.append(randint(0, 1)) + # TODO set 1 if we have stock, else 0 + row.append(1) cells.append(row) - record.kardex_tray_x = selected[0] + 1 - record.kardex_tray_y = selected[1] + 1 + record.kardex_tray_location_id = location.id + record.kardex_tray_name = location.name + record.kardex_tray_type_id = tray_type.id + record.kardex_tray_type_code = tray_type.code + record.kardex_tray_x = location.posx + record.kardex_tray_y = location.posy record.kardex_tray_matrix = { # x, y: position of the selected cell 'selected': selected, diff --git a/stock_kardex/views/stock_kardex_views.xml b/stock_kardex/views/stock_kardex_views.xml index f5a1371467db..d5fd549514b5 100644 --- a/stock_kardex/views/stock_kardex_views.xml +++ b/stock_kardex/views/stock_kardex_views.xml @@ -68,32 +68,8 @@
- - - - Tray - - - - - SHU-1108 - - - - - - Box Type - - - - B30401 - - - + + From 404cf86a71ef62891835bca09575143ca1eb1ae6 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 19 Jun 2019 13:57:21 +0200 Subject: [PATCH 07/50] Color cells in blue when contains stock (remove random) Add a tray_matrix widget on stock location form view for convenience: easy to see which cells contain stock or not. --- stock_kardex/models/stock_kardex.py | 13 ++--- stock_kardex/models/stock_kardex_tray_type.py | 6 ++- stock_kardex/models/stock_location.py | 51 +++++++++++++++++++ stock_kardex/static/src/js/kardex.js | 5 +- stock_kardex/views/stock_location_views.xml | 3 ++ 5 files changed, 65 insertions(+), 13 deletions(-) diff --git a/stock_kardex/models/stock_kardex.py b/stock_kardex/models/stock_kardex.py index 32ae956988d3..dc64d90c0f8f 100644 --- a/stock_kardex/models/stock_kardex.py +++ b/stock_kardex/models/stock_kardex.py @@ -114,18 +114,11 @@ def _compute_kardex_tray_matrix(self): } location = record.current_move_line[modes[record.mode]] tray_type = location.generated_for_tray_type_id - cols = tray_type.cols - rows = tray_type.rows selected = [] - if location: - selected = [location.posx - 1, location.posy - 1] cells = [] - for __ in range(rows): - row = [] - for __ in range(cols): - # TODO set 1 if we have stock, else 0 - row.append(1) - cells.append(row) + if location: + selected = location._kardex_cell_coords() + cells = location._tray_cells_matrix() record.kardex_tray_location_id = location.id record.kardex_tray_name = location.name diff --git a/stock_kardex/models/stock_kardex_tray_type.py b/stock_kardex/models/stock_kardex_tray_type.py index 4e3a69ed28c4..9fbb05f637df 100644 --- a/stock_kardex/models/stock_kardex_tray_type.py +++ b/stock_kardex/models/stock_kardex_tray_type.py @@ -23,10 +23,12 @@ def _compute_tray_matrix(self): # the tray, we generate a "full" tray, we'll # see all the boxes on the web widget. # (0 means empty, 1 means used) - cells = [[1] * record.cols for __ in range(record.rows)] - + cells = self._generate_cells_matrix(default_state=1) record.tray_matrix = {'selected': None, 'cells': cells} + def _generate_cells_matrix(self, default_state=0): + return [[default_state] * self.cols for __ in range(self.rows)] + # TODO prevent to set active=False on a type used in a location # TODO we should not be able to change cells and rows for types used # in locations diff --git a/stock_kardex/models/stock_location.py b/stock_kardex/models/stock_location.py index 63ea1c17acf2..43d06e06898c 100644 --- a/stock_kardex/models/stock_location.py +++ b/stock_kardex/models/stock_location.py @@ -13,6 +13,11 @@ class StockLocation(models.Model): kardex_tray_type_id = fields.Many2one( comodel_name="stock.kardex.tray.type", ondelete="restrict" ) + kardex_cell_contains_stock = fields.Boolean( + compute='_compute_kardex_cell_contains_stock', + help="Used to know if a Kardex location is empty.", + ) + tray_matrix = fields.Serialized(compute='_compute_tray_matrix') # Only for trays cells (boxes). # Children of 'kardey_tray' locations, they are automatically generated @@ -22,6 +27,33 @@ class StockLocation(models.Model): readonly=True, ) + # TODO document hierarchy + replace "parent_is_kardex" and kardex_tray + # by an optional selection kardex_view, shuttle, tray, cell + # Kardex View + # -> Shuttle + # -> Tray + # -> Cell + + @api.depends('quant_ids.quantity') + def _compute_kardex_cell_contains_stock(self): + for location in self: + # TODO replace by check on 'cell' only + if not location.parent_is_kardex: + # we skip the others only for performance + continue + quants = location.quant_ids.filtered(lambda r: r.quantity > 0) + location.kardex_cell_contains_stock = bool(quants) + + @api.depends('quant_ids.quantity', 'location_id.kardex_tray_type_id') + def _compute_tray_matrix(self): + for location in self: + if not location.parent_is_kardex: + continue + location.tray_matrix = { + 'selected': location._kardex_cell_coords(), + 'cells': location._tray_cells_matrix(), + } + @api.depends('location_id.parent_is_kardex') def _compute_parent_is_kardex(self): for location in self: @@ -46,6 +78,25 @@ def write(self, vals): self._update_tray_sublocations() return result + def _kardex_cell_coords(self): + # TODO check is a cell + if not self.generated_for_tray_type_id: # is a cell + coords = [] + coords = [self.posx - 1, self.posy - 1] + return coords + + def _tray_cells_matrix(self): + assert self.parent_is_kardex + if self.kardex_tray: + location = self + else: + location = self.location_id + cells = location.kardex_tray_type_id._generate_cells_matrix() + for cell in location.child_ids: + if cell.kardex_cell_contains_stock: + cells[cell.posy - 1][cell.posx - 1] = 1 + return cells + @api.multi def _update_tray_sublocations(self): # TODO: if any sublocation has stock, raise an error, diff --git a/stock_kardex/static/src/js/kardex.js b/stock_kardex/static/src/js/kardex.js index d9fafc25340a..c314fe7870eb 100644 --- a/stock_kardex/static/src/js/kardex.js +++ b/stock_kardex/static/src/js/kardex.js @@ -183,9 +183,12 @@ var KardexTrayMatrixField = DebouncedField.extend({ var h = ((canvas.height - padding * rows) / rows); ctx.globalAlpha = this.globalAlpha; + // again, our matrix is top to bottom (0 is the first line) + // but visually, we want them bottom to top + var reversed_cells = cells.slice().reverse(); for (var y = 0; y < rows; y++) { for (var x = 0; x < cols; x++) { - ctx.fillStyle = colors[cells[y][x]]; + ctx.fillStyle = colors[reversed_cells[y][x]]; var fillWidth = w; var fillHeight = h; // cheat: remove the padding at bottom and right diff --git a/stock_kardex/views/stock_location_views.xml b/stock_kardex/views/stock_location_views.xml index dbc5e64dde4c..e6592d071b3d 100644 --- a/stock_kardex/views/stock_location_views.xml +++ b/stock_kardex/views/stock_location_views.xml @@ -15,6 +15,9 @@ attrs="{'invisible': [('parent_is_kardex', '=', False)]}"/> + From 488b5c739dd6fbb49da492bf2ce2592ffb91c19e Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 19 Jun 2019 13:58:46 +0200 Subject: [PATCH 08/50] Fix UI issues in kardex screen * Display "No operations" when we have cleared the queue * Hide the information fields when there is no operation to do * --- stock_kardex/models/stock_kardex.py | 7 +++++-- stock_kardex/views/stock_kardex_views.xml | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/stock_kardex/models/stock_kardex.py b/stock_kardex/models/stock_kardex.py index dc64d90c0f8f..83ef1fc65c5a 100644 --- a/stock_kardex/models/stock_kardex.py +++ b/stock_kardex/models/stock_kardex.py @@ -25,6 +25,7 @@ class StockKardex(models.Model): help="The Kardex source location for Pick operations " "and destination location for Put operations.", ) + # TODO add _id current_move_line = fields.Many2one(comodel_name='stock.move.line') number_of_ops = fields.Integer( @@ -191,6 +192,8 @@ def process_current_inventory(self): raise exceptions.UserError(_('Inventory workflow not implemented')) def button_save(self): + if not self: + return self.ensure_one() method = 'process_current_{}'.format(self.mode) getattr(self, method)() @@ -206,14 +209,14 @@ def button_save(self): } } - # TODO call this each time we process a move line def select_next_move_line(self): self.ensure_one() - # TODO sort? next_move_line = self.env['stock.move.line'].search( self._domain_move_lines_to_do(), limit=1 ) self.current_move_line = next_move_line + descr = _('Scan next PID') if next_move_line else _('No operations') + self.operation_descr = descr def action_open_screen(self): self.select_next_move_line() diff --git a/stock_kardex/views/stock_kardex_views.xml b/stock_kardex/views/stock_kardex_views.xml index d5fd549514b5..427a0fd6f41a 100644 --- a/stock_kardex/views/stock_kardex_views.xml +++ b/stock_kardex/views/stock_kardex_views.xml @@ -49,10 +49,11 @@
-
+
+
-
+
- +
@@ -146,6 +150,27 @@ + + stock.kardex.manual.barcode.view.form + stock.kardex.manual.barcode + +
+
+
+ +
+
+
+
+
+
+
+
+ stock.kardex.view.form stock.kardex From 2c151ae7637facb92f4c0bde57609a70e7afcc05 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 26 Jun 2019 11:26:48 +0200 Subject: [PATCH 21/50] Add onclick handler on tray matrix widget Allow to specify an action, example on the location view: open the location with the clicked coordinates. --- stock_kardex/models/stock_location.py | 29 +++++++++ stock_kardex/static/src/js/kardex.js | 72 ++++++++++++++++++++- stock_kardex/views/stock_kardex_views.xml | 3 +- stock_kardex/views/stock_location_views.xml | 3 +- 4 files changed, 103 insertions(+), 4 deletions(-) diff --git a/stock_kardex/models/stock_location.py b/stock_kardex/models/stock_location.py index 23938d3a6372..fcfbc72e0813 100644 --- a/stock_kardex/models/stock_location.py +++ b/stock_kardex/models/stock_location.py @@ -73,6 +73,35 @@ def _compute_tray_matrix(self): 'cells': location._tray_cells_matrix(), } + @api.multi + def action_tray_matrix_click(self, coordX, coordY): + self.ensure_one() + if self.kardex_kind == 'cell': + tray = self.location_id + else: + tray = self + location = self.search( + [ + ('id', 'child_of', tray.ids), + # we receive positions counting from 0 but they are stored + # in the "human" format starting from 1 + ('posx', '=', coordX + 1), + ('posy', '=', coordY + 1), + ] + ) + view = self.env.ref('stock.view_location_form') + action = self.env.ref('stock.action_location_form').read()[0] + action.update( + { + 'res_id': location.id, + 'view_mode': 'form', + 'view_type': 'form', + 'view_id': view.id, + 'views': [(view.id, 'form')], + } + ) + return action + @api.model_create_multi def create(self, vals_list): records = super().create(vals_list) diff --git a/stock_kardex/static/src/js/kardex.js b/stock_kardex/static/src/js/kardex.js index c314fe7870eb..83ba2bf385fa 100644 --- a/stock_kardex/static/src/js/kardex.js +++ b/stock_kardex/static/src/js/kardex.js @@ -19,8 +19,8 @@ KanbanRecord.include({ method: 'action_open_screen', model: self.modelName, args: [self.id], - }).then(function (result) { - self.do_action(result); + }).then(function (action) { + self.trigger_up('do_action', {action: action}); }); } else { this._super.apply(this, arguments); @@ -48,10 +48,27 @@ var ExitButton = FieldInteger.extend({ }, }); +/** +* Shows a canvas with the Tray's cells +* +* An action can be configured which is called when a cell is clicked. +* The action must be an action.multi, it will receive the x and y positions +* of the cell clicked (starting from 0). The action must be configured in +* the options of the field and be on the same model: +* +* +* +*/ var KardexTrayMatrixField = DebouncedField.extend({ className: 'o_field_kardex_tray_matrix', tagName: 'canvas', supportedFieldTypes: ['serialized'], + events: { + 'click': '_onClick', + }, cellColorEmpty: '#ffffff', cellColorNotEmpty: '#4e6bfd', @@ -60,6 +77,12 @@ var KardexTrayMatrixField = DebouncedField.extend({ globalAlpha: 0.8, cellPadding: 2, + init: function (parent, name, record, options) { + this._super.apply(this, arguments); + this.nodeOptions = _.defaults(this.nodeOptions, {}); + this.clickAction = 'clickAction' in (options || {}) ? options.clickAction : this.nodeOptions.click_action; + }, + isSet: function () { if (Object.keys(this.value).length === 0) { return false; @@ -78,6 +101,9 @@ var KardexTrayMatrixField = DebouncedField.extend({ var self = this; return this._super.apply(this, arguments).then(function () { + if (self.clickAction) { + self.$el.css('cursor', 'pointer'); + } // _super calls _render(), but the function // resizeCanvasToDisplaySize would resize the canvas // to 0 because the actual canvas would still be unknown. @@ -88,6 +114,48 @@ var KardexTrayMatrixField = DebouncedField.extend({ }); }, + _onClick: function (ev) { + if (!this.isSet()) { + return; + } + if (!this.clickAction) { + return; + } + var width = this.canvas.width, + height = this.canvas.height, + rect = this.canvas.getBoundingClientRect(); + + var clickX = ev.clientX - rect.left, + clickY = ev.clientY - rect.top; + + var cells = this.value.cells, + cols = cells[0].length, + rows = cells.length; + + // we remove 1 to start counting from 0 + var coordX = Math.ceil(clickX * cols / width) - 1, + coordY = Math.ceil(clickY * rows / height) - 1; + // if we click on the last pixel on the bottom or the right + // we would get an offset index + if (coordX >= cols) { coordX = cols - 1; } + if (coordY >= rows) { coordY = rows - 1; } + + // the coordinate we get when we click is from top, + // but we are looking for the coordinate from the bottom + // to match the user's expectations, invert Y + coordY = Math.abs(coordY - rows + 1); + + var self = this; + this._rpc({ + model: this.model, + method: this.clickAction, + args: [[this.res_id], coordX, coordY] + }) + .then(function (action) { + self.trigger_up('do_action', {action: action}); + }); + }, + /** * Debounce the rendering on resize. * It is useless to render on each resize event. diff --git a/stock_kardex/views/stock_kardex_views.xml b/stock_kardex/views/stock_kardex_views.xml index 1103422d2286..4afc46986fd7 100644 --- a/stock_kardex/views/stock_kardex_views.xml +++ b/stock_kardex/views/stock_kardex_views.xml @@ -109,7 +109,8 @@
+ widget="kardex_tray_matrix" + />
diff --git a/stock_kardex/views/stock_location_views.xml b/stock_kardex/views/stock_location_views.xml index 5c8f4d903c60..01ba13039fbc 100644 --- a/stock_kardex/views/stock_location_views.xml +++ b/stock_kardex/views/stock_location_views.xml @@ -8,7 +8,7 @@ @@ -20,6 +20,7 @@ From 2e99fff560dde45fd2ecf47c05d3c22f2772a1b3 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 26 Jun 2019 13:33:23 +0200 Subject: [PATCH 22/50] Rename to stock_vertical_lift Preparing the module to be a generic core for supporting Vertical Lifts / Carousels. The Kardex one willbe a submodule. --- stock_kardex/demo/stock_inventory_demo.xml | 20 -- stock_kardex/demo/stock_location_demo.xml | 102 ----------- stock_kardex/security/ir.model.access.csv | 5 - stock_kardex/tests/__init__.py | 3 - stock_kardex/views/stock_kardex_templates.xml | 11 -- stock_kardex/views/stock_location_views.xml | 50 ----- .../__init__.py | 0 .../__manifest__.py | 18 +- .../data/stock_location.xml | 12 +- .../data/vertical_lift_tray_type.xml | 20 +- .../demo/product_demo.xml | 0 .../demo/stock_inventory_demo.xml | 20 ++ .../demo/stock_location_demo.xml | 102 +++++++++++ .../demo/stock_picking_demo.xml | 12 +- .../demo/vertical_lift_shuttle_demo.xml | 12 +- .../models/__init__.py | 4 +- .../models/stock_location.py | 101 +++++----- .../models/stock_move.py | 14 +- .../models/stock_quant.py | 8 +- .../models/vertical_lift_shuttle.py | 118 ++++++------ .../models/vertical_lift_tray_type.py | 17 +- .../security/ir.model.access.csv | 5 + .../static/src/js/vertical_lift.js | 23 ++- .../static/src/scss/vertical_lift.scss | 44 ++--- stock_vertical_lift/tests/__init__.py | 3 + .../tests/common.py | 18 +- .../tests/test_location.py | 87 +++++---- .../tests/test_vertical_lift_shuttle.py | 172 +++++++++--------- .../tests/test_vertical_lift_tray_type.py | 16 +- .../views/shuttle_screen_templates.xml | 2 +- .../views/stock_location_views.xml | 50 +++++ .../views/stock_vertical_lift_templates.xml | 11 ++ .../views/vertical_lift_shuttle_views.xml | 112 ++++++------ .../views/vertical_lift_tray_type_views.xml | 42 ++--- 34 files changed, 623 insertions(+), 611 deletions(-) delete mode 100644 stock_kardex/demo/stock_inventory_demo.xml delete mode 100644 stock_kardex/demo/stock_location_demo.xml delete mode 100644 stock_kardex/security/ir.model.access.csv delete mode 100644 stock_kardex/tests/__init__.py delete mode 100644 stock_kardex/views/stock_kardex_templates.xml delete mode 100644 stock_kardex/views/stock_location_views.xml rename {stock_kardex => stock_vertical_lift}/__init__.py (100%) rename {stock_kardex => stock_vertical_lift}/__manifest__.py (62%) rename {stock_kardex => stock_vertical_lift}/data/stock_location.xml (52%) rename stock_kardex/data/stock_kardex_tray_type.xml => stock_vertical_lift/data/vertical_lift_tray_type.xml (66%) rename {stock_kardex => stock_vertical_lift}/demo/product_demo.xml (100%) create mode 100644 stock_vertical_lift/demo/stock_inventory_demo.xml create mode 100644 stock_vertical_lift/demo/stock_location_demo.xml rename {stock_kardex => stock_vertical_lift}/demo/stock_picking_demo.xml (71%) rename stock_kardex/demo/stock_kardex_demo.xml => stock_vertical_lift/demo/vertical_lift_shuttle_demo.xml (54%) rename {stock_kardex => stock_vertical_lift}/models/__init__.py (51%) rename {stock_kardex => stock_vertical_lift}/models/stock_location.py (69%) rename {stock_kardex => stock_vertical_lift}/models/stock_move.py (58%) rename {stock_kardex => stock_vertical_lift}/models/stock_quant.py (65%) rename stock_kardex/models/stock_kardex.py => stock_vertical_lift/models/vertical_lift_shuttle.py (73%) rename stock_kardex/models/stock_kardex_tray_type.py => stock_vertical_lift/models/vertical_lift_tray_type.py (84%) create mode 100644 stock_vertical_lift/security/ir.model.access.csv rename stock_kardex/static/src/js/kardex.js => stock_vertical_lift/static/src/js/vertical_lift.js (93%) rename stock_kardex/static/src/scss/kardex_view.scss => stock_vertical_lift/static/src/scss/vertical_lift.scss (72%) create mode 100644 stock_vertical_lift/tests/__init__.py rename {stock_kardex => stock_vertical_lift}/tests/common.py (79%) rename stock_kardex/tests/test_kardex_location.py => stock_vertical_lift/tests/test_location.py (67%) rename stock_kardex/tests/test_kardex.py => stock_vertical_lift/tests/test_vertical_lift_shuttle.py (51%) rename stock_kardex/tests/test_kardex_tray_type.py => stock_vertical_lift/tests/test_vertical_lift_tray_type.py (84%) rename stock_kardex/templates/kardex_screen.xml => stock_vertical_lift/views/shuttle_screen_templates.xml (89%) create mode 100644 stock_vertical_lift/views/stock_location_views.xml create mode 100644 stock_vertical_lift/views/stock_vertical_lift_templates.xml rename stock_kardex/views/stock_kardex_views.xml => stock_vertical_lift/views/vertical_lift_shuttle_views.xml (70%) rename stock_kardex/views/stock_kardex_tray_type_views.xml => stock_vertical_lift/views/vertical_lift_tray_type_views.xml (60%) diff --git a/stock_kardex/demo/stock_inventory_demo.xml b/stock_kardex/demo/stock_inventory_demo.xml deleted file mode 100644 index 4de41d398a04..000000000000 --- a/stock_kardex/demo/stock_inventory_demo.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Starting Kardex Inventory - - - - - - - 30.0 - - - - - - - - diff --git a/stock_kardex/demo/stock_location_demo.xml b/stock_kardex/demo/stock_location_demo.xml deleted file mode 100644 index 7b24f64f0786..000000000000 --- a/stock_kardex/demo/stock_location_demo.xml +++ /dev/null @@ -1,102 +0,0 @@ - - - - - Shuttle 1 - - internal - - - - Tray 1A - T1A - - - internal - - - - Tray 1B - T1B - - - internal - - - - Tray 1C - T1C - - - internal - - - - Shuttle 2 - - internal - - - - Tray 2A - T2A - - - internal - - - - Tray 2B - T2B - - - internal - - - - Tray 2C - T2C - - - internal - - - - Tray 2D - T2D - - - internal - - - - Shuttle 3 - - internal - - - - Tray 3A - T3A - - - internal - - - - Tray 3B - T3B - - - internal - - - - - - - - diff --git a/stock_kardex/security/ir.model.access.csv b/stock_kardex/security/ir.model.access.csv deleted file mode 100644 index 32b082c9579b..000000000000 --- a/stock_kardex/security/ir.model.access.csv +++ /dev/null @@ -1,5 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_stock_kardex_stock_user,access_stock_kardex stock user,model_stock_kardex,stock.group_stock_user,1,0,0,0 -access_stock_kardex_manager,access_stock_kardex stock manager,model_stock_kardex,stock.group_stock_manager,1,1,1,1 -access_stock_kardex_tray_type_stock_user,access_stock_kardex_tray_type stock user,model_stock_kardex_tray_type,stock.group_stock_user,1,0,0,0 -access_stock_kardex_tray_type_manager,access_stock_kardex_tray_type stock manager,model_stock_kardex_tray_type,stock.group_stock_manager,1,1,1,1 diff --git a/stock_kardex/tests/__init__.py b/stock_kardex/tests/__init__.py deleted file mode 100644 index 1907d4cb7b32..000000000000 --- a/stock_kardex/tests/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from . import test_kardex_location -from . import test_kardex_tray_type -from . import test_kardex diff --git a/stock_kardex/views/stock_kardex_templates.xml b/stock_kardex/views/stock_kardex_templates.xml deleted file mode 100644 index 340339fdef03..000000000000 --- a/stock_kardex/views/stock_kardex_templates.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/stock_kardex/views/stock_location_views.xml b/stock_kardex/views/stock_location_views.xml deleted file mode 100644 index 01ba13039fbc..000000000000 --- a/stock_kardex/views/stock_location_views.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - stock.location.form.kardex - stock.location - - - - - - - - - - - - - - - {'readonly': [('kardex_kind', '=', 'cell')]} - - - {'readonly': [('kardex_kind', '=', 'cell')]} - - - - - - stock.location.search.kardex - stock.location - - - - - - - - - - - diff --git a/stock_kardex/__init__.py b/stock_vertical_lift/__init__.py similarity index 100% rename from stock_kardex/__init__.py rename to stock_vertical_lift/__init__.py diff --git a/stock_kardex/__manifest__.py b/stock_vertical_lift/__manifest__.py similarity index 62% rename from stock_kardex/__manifest__.py rename to stock_vertical_lift/__manifest__.py index 1a44afa93e5d..c43fbf678095 100644 --- a/stock_kardex/__manifest__.py +++ b/stock_vertical_lift/__manifest__.py @@ -2,8 +2,8 @@ # Copyright 2019 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { - 'name': 'Kardex', - 'summary': 'Provides interaction and GUI for Kardex', + 'name': 'Vertical Lift', + 'summary': 'Provides the core for integration with Vertical Lifts', 'version': '12.0.1.0.0', 'category': 'Stock', 'author': 'Camptocamp', @@ -12,24 +12,24 @@ 'stock', 'barcodes', 'base_sparse_field', - 'web_notify', + 'web_notify', # OCA/web ], 'website': 'https://www.camptocamp.com', 'demo': [ 'demo/stock_location_demo.xml', - 'demo/stock_kardex_demo.xml', + 'demo/vertical_lift_shuttle_demo.xml', 'demo/product_demo.xml', 'demo/stock_inventory_demo.xml', 'demo/stock_picking_demo.xml', ], 'data': [ 'views/stock_location_views.xml', - 'views/stock_kardex_views.xml', - 'views/stock_kardex_tray_type_views.xml', - 'views/stock_kardex_templates.xml', - 'templates/kardex_screen.xml', + 'views/vertical_lift_shuttle_views.xml', + 'views/vertical_lift_tray_type_views.xml', + 'views/stock_vertical_lift_templates.xml', + 'views/shuttle_screen_templates.xml', 'data/stock_location.xml', - 'data/stock_kardex_tray_type.xml', + 'data/vertical_lift_tray_type.xml', 'security/ir.model.access.csv', ], 'installable': True, diff --git a/stock_kardex/data/stock_location.xml b/stock_vertical_lift/data/stock_location.xml similarity index 52% rename from stock_kardex/data/stock_location.xml rename to stock_vertical_lift/data/stock_location.xml index c6fc59df3e12..462e1d6a1679 100644 --- a/stock_kardex/data/stock_location.xml +++ b/stock_vertical_lift/data/stock_location.xml @@ -1,16 +1,16 @@ - - Kardex View + + Vertical Lift internal - + diff --git a/stock_kardex/data/stock_kardex_tray_type.xml b/stock_vertical_lift/data/vertical_lift_tray_type.xml similarity index 66% rename from stock_kardex/data/stock_kardex_tray_type.xml rename to stock_vertical_lift/data/vertical_lift_tray_type.xml index 323a9cbffb96..419594d8a5b6 100644 --- a/stock_kardex/data/stock_kardex_tray_type.xml +++ b/stock_vertical_lift/data/vertical_lift_tray_type.xml @@ -1,70 +1,70 @@ - + Small 32x B10804 4 8 - + Small 16x B20802 2 8 - + Small 8x B20402 2 4 - + Small 16x B40802 2 8 - + Small 16x B30404 4 4 - + Large 32x B20804 4 8 - + Large 16x B30802 2 8 - + Large 8x B30402 2 4 - + Large 4x B30401 1 4 - + Large 16x B30404 4 diff --git a/stock_kardex/demo/product_demo.xml b/stock_vertical_lift/demo/product_demo.xml similarity index 100% rename from stock_kardex/demo/product_demo.xml rename to stock_vertical_lift/demo/product_demo.xml diff --git a/stock_vertical_lift/demo/stock_inventory_demo.xml b/stock_vertical_lift/demo/stock_inventory_demo.xml new file mode 100644 index 000000000000..4b17fcdcd6ec --- /dev/null +++ b/stock_vertical_lift/demo/stock_inventory_demo.xml @@ -0,0 +1,20 @@ + + + + + Starting Vertical Lift Inventory + + + + + + + 30.0 + + + + + + + + diff --git a/stock_vertical_lift/demo/stock_location_demo.xml b/stock_vertical_lift/demo/stock_location_demo.xml new file mode 100644 index 000000000000..bb87661e8c20 --- /dev/null +++ b/stock_vertical_lift/demo/stock_location_demo.xml @@ -0,0 +1,102 @@ + + + + + Shuttle 1 + + internal + + + + Tray 1A + T1A + + + internal + + + + Tray 1B + T1B + + + internal + + + + Tray 1C + T1C + + + internal + + + + Shuttle 2 + + internal + + + + Tray 2A + T2A + + + internal + + + + Tray 2B + T2B + + + internal + + + + Tray 2C + T2C + + + internal + + + + Tray 2D + T2D + + + internal + + + + Shuttle 3 + + internal + + + + Tray 3A + T3A + + + internal + + + + Tray 3B + T3B + + + internal + + + + + + + + diff --git a/stock_kardex/demo/stock_picking_demo.xml b/stock_vertical_lift/demo/stock_picking_demo.xml similarity index 71% rename from stock_kardex/demo/stock_picking_demo.xml rename to stock_vertical_lift/demo/stock_picking_demo.xml index af59b358865b..520d97925101 100644 --- a/stock_kardex/demo/stock_picking_demo.xml +++ b/stock_vertical_lift/demo/stock_picking_demo.xml @@ -1,16 +1,16 @@ - + - outgoing shipment from kardex + Outgoing shipment from Vertical Lift (demo) - + - + diff --git a/stock_kardex/demo/stock_kardex_demo.xml b/stock_vertical_lift/demo/vertical_lift_shuttle_demo.xml similarity index 54% rename from stock_kardex/demo/stock_kardex_demo.xml rename to stock_vertical_lift/demo/vertical_lift_shuttle_demo.xml index 9cd9c0fb05a8..0dafcc526739 100644 --- a/stock_kardex/demo/stock_kardex_demo.xml +++ b/stock_vertical_lift/demo/vertical_lift_shuttle_demo.xml @@ -1,25 +1,25 @@ - + Shuttle 1 - + 10.0.30.1 pick - + Shuttle 2 - + 10.0.30.2 pick - + Shuttle 3 - + 10.0.30.3 pick diff --git a/stock_kardex/models/__init__.py b/stock_vertical_lift/models/__init__.py similarity index 51% rename from stock_kardex/models/__init__.py rename to stock_vertical_lift/models/__init__.py index 6a0668233699..83e852f12247 100644 --- a/stock_kardex/models/__init__.py +++ b/stock_vertical_lift/models/__init__.py @@ -1,5 +1,5 @@ -from . import stock_kardex -from . import stock_kardex_tray_type +from . import vertical_lift_shuttle +from . import vertical_lift_tray_type from . import stock_location from . import stock_move from . import stock_quant diff --git a/stock_kardex/models/stock_location.py b/stock_vertical_lift/models/stock_location.py similarity index 69% rename from stock_kardex/models/stock_location.py rename to stock_vertical_lift/models/stock_location.py index fcfbc72e0813..ea30e9d7e22a 100644 --- a/stock_kardex/models/stock_location.py +++ b/stock_vertical_lift/models/stock_location.py @@ -8,75 +8,78 @@ class StockLocation(models.Model): _inherit = "stock.location" - kardex_location = fields.Boolean( - 'Is a Kardex View Location?', + vertical_lift_location = fields.Boolean( + 'Is a Vertical Lift View Location?', default=False, - help="Check this box to use it as the view for Kardex shuttles.", + help="Check this box to use it as the view for Vertical Lift Shuttles.", ) - kardex_kind = fields.Selection( + vertical_lift_kind = fields.Selection( selection=[ ('view', 'View'), ('shuttle', 'Shuttle'), ('tray', 'Tray'), ('cell', 'Cell'), ], - compute='_compute_kardex_kind', + compute='_compute_vertical_lift_kind', store=True, ) - kardex_tray_type_id = fields.Many2one( - comodel_name="stock.kardex.tray.type", ondelete="restrict" + vertical_lift_tray_type_id = fields.Many2one( + comodel_name="vertical.lift.tray.type", ondelete="restrict" ) - kardex_cell_contains_stock = fields.Boolean( - compute='_compute_kardex_cell_contains_stock', - help="Used to know if a Kardex location is empty.", + tray_cell_contains_stock = fields.Boolean( + compute='_compute_tray_cell_contains_stock', + help="Used to know if a cell of a Tray location is empty.", ) - tray_matrix = Serialized(compute='_compute_tray_matrix') + tray_matrix = Serialized(string='Cells', compute='_compute_tray_matrix') # TODO document hierarchy - # by an optional selection kardex_view, shuttle, tray, cell - # Kardex View + # Vertical Lift View # -> Shuttle # -> Tray # -> Cell - @api.depends('location_id', 'location_id.kardex_kind', 'kardex_location') - def _compute_kardex_kind(self): + @api.depends( + 'location_id', + 'location_id.vertical_lift_kind', + 'vertical_lift_location', + ) + def _compute_vertical_lift_kind(self): tree = {'view': 'shuttle', 'shuttle': 'tray', 'tray': 'cell'} for location in self: - if location.kardex_location: - location.kardex_kind = 'view' + if location.vertical_lift_location: + location.vertical_lift_kind = 'view' continue - kind = tree.get(location.location_id.kardex_kind) + kind = tree.get(location.location_id.vertical_lift_kind) if kind: - location.kardex_kind = kind + location.vertical_lift_kind = kind @api.depends('quant_ids.quantity') - def _compute_kardex_cell_contains_stock(self): + def _compute_tray_cell_contains_stock(self): for location in self: - if not location.kardex_kind == 'cell': + if not location.vertical_lift_kind == 'cell': # we skip the others only for performance continue quants = location.quant_ids.filtered(lambda r: r.quantity > 0) - location.kardex_cell_contains_stock = bool(quants) + location.tray_cell_contains_stock = bool(quants) @api.depends( 'quant_ids.quantity', - 'kardex_tray_type_id', - 'location_id.kardex_tray_type_id', + 'vertical_lift_tray_type_id', + 'location_id.vertical_lift_tray_type_id', ) def _compute_tray_matrix(self): for location in self: - if location.kardex_kind not in ('tray', 'cell'): + if location.vertical_lift_kind not in ('tray', 'cell'): continue location.tray_matrix = { - 'selected': location._kardex_cell_coords(), - 'cells': location._tray_cells_matrix(), + 'selected': location._tray_cell_coords(), + 'cells': location._tray_cell_matrix(), } @api.multi def action_tray_matrix_click(self, coordX, coordY): self.ensure_one() - if self.kardex_kind == 'cell': + if self.vertical_lift_kind == 'cell': tray = self.location_id else: tray = self @@ -112,10 +115,10 @@ def create(self, vals_list): def write(self, vals): for location in self: trays_to_update = False - if 'kardex_tray_type_id' in vals: - new_tray_type_id = vals.get('kardex_tray_type_id') + if 'vertical_lift_tray_type_id' in vals: + new_tray_type_id = vals.get('vertical_lift_tray_type_id') trays_to_update = ( - location.kardex_tray_type_id.id != new_tray_type_id + location.vertical_lift_tray_type_id.id != new_tray_type_id ) super(StockLocation, location).write(vals) if trays_to_update: @@ -123,9 +126,9 @@ def write(self, vals): return True @api.constrains('active') - def _stock_kardex_check_active(self): + def _vertical_lift_check_active(self): for record in self: - if not record.kardex_kind: + if not record.vertical_lift_kind: continue if record.active: continue @@ -133,35 +136,35 @@ def _stock_kardex_check_active(self): # if at least one of the cell contains stock. # We cannot disable a tray, a shuffle or a view if # at least one of their tray contain stock. - if record.kardex_kind == 'cell': + if record.vertical_lift_kind == 'cell': parent = record.location_id else: parent = record # Add the record to the search: as it has set inactive, it will not # be found by the search. locs = self.search([('id', 'child_of', parent.id)]) | record - if any(loc.kardex_cell_contains_stock for loc in locs): + if any(loc.tray_cell_contains_stock for loc in locs): raise exceptions.ValidationError( _( - "Kardex locations cannot be archived when " + "Vertical Lift locations cannot be archived when " "they contain products." ) ) - def _kardex_cell_coords(self): - if self.kardex_kind != 'cell': + def _tray_cell_coords(self): + if self.vertical_lift_kind != 'cell': return [] return [self.posx - 1, self.posy - 1] - def _tray_cells_matrix(self): - assert self.kardex_kind in ('tray', 'cell') - if self.kardex_kind == 'tray': + def _tray_cell_matrix(self): + assert self.vertical_lift_kind in ('tray', 'cell') + if self.vertical_lift_kind == 'tray': location = self else: # cell location = self.location_id - cells = location.kardex_tray_type_id._generate_cells_matrix() + cells = location.vertical_lift_tray_type_id._generate_cells_matrix() for cell in location.child_ids: - if cell.kardex_cell_contains_stock: + if cell.tray_cell_contains_stock: cells[cell.posy - 1][cell.posx - 1] = 1 return cells @@ -169,19 +172,19 @@ def _tray_cells_matrix(self): def _update_tray_sublocations(self): values = [] for location in self: - if not location.kardex_kind == 'tray': + if not location.vertical_lift_kind == 'tray': continue - tray_type = location.kardex_tray_type_id + tray_type = location.vertical_lift_tray_type_id try: location.child_ids.write({'active': False}) except exceptions.ValidationError: - # trap this check (_stock_kardex_check_active) to display a + # trap this check (_vertical_lift_check_active) to display a # contextual error message raise exceptions.UserError( _( - "Kardex trays cannot be modified when " + "Vertical Lift trays cannot be modified when " "they contain products." ) ) @@ -206,7 +209,7 @@ def _update_tray_sublocations(self): def _create_tray_xmlids(self): """Create external IDs for generated cells - Called from stock/kardex/demo/stock_location_demo.xml. + Called from stock_vertical_lift/demo/stock_location_demo.xml. If the tray has one. Used for the demo/test data. It will not handle properly changing the tray format as the former cells will keep the @@ -215,7 +218,7 @@ def _create_tray_xmlids(self): not a problem and should not be used for other purposes. """ for location in self: - if location.kardex_kind != 'cell': + if location.vertical_lift_kind != 'cell': continue tray = location.location_id tray_external_id = tray.get_external_id().get(tray.id) diff --git a/stock_kardex/models/stock_move.py b/stock_vertical_lift/models/stock_move.py similarity index 58% rename from stock_kardex/models/stock_move.py rename to stock_vertical_lift/models/stock_move.py index dbad4df4cab1..333a143f295c 100644 --- a/stock_kardex/models/stock_move.py +++ b/stock_vertical_lift/models/stock_move.py @@ -11,13 +11,13 @@ class StockMove(models.Model): def write(self, vals): result = super().write(vals) if 'state' in vals: - # We cannot have fields to depends on to invalidate these - # computed fields on stock.kardex. But we know that when the state - # of any move line changes, we can invalidate them as the count - # of assigned move lines may change (and we track this in stock.move, - # not stock.move.line, becaus the state of the lines is a related to - # this one). - self.env['stock.kardex'].invalidate_cache( + # We cannot have fields to depends on to invalidate these computed + # fields on vertical.lift.shuttle. But we know that when the state of + # any move line changes, we can invalidate them as the count of + # assigned move lines may change (and we track this in stock.move, + # not stock.move.line, becaus the state of the lines is a related + # to this one). + self.env['vertical.lift.shuttle'].invalidate_cache( ['number_of_ops', 'number_of_ops_all'] ) return result diff --git a/stock_kardex/models/stock_quant.py b/stock_vertical_lift/models/stock_quant.py similarity index 65% rename from stock_kardex/models/stock_quant.py rename to stock_vertical_lift/models/stock_quant.py index 485bce326511..905484139a7e 100644 --- a/stock_kardex/models/stock_quant.py +++ b/stock_vertical_lift/models/stock_quant.py @@ -9,8 +9,8 @@ class StockQuant(models.Model): def _update_available_quantity(self, *args, **kwargs): result = super()._update_available_quantity(*args, **kwargs) - # We cannot have fields to depends on to invalidate this - # computed fields on stock.kardex. But we know that when the quantity - # of quant changes, we can invalidate the field on the kardex tray. - self.env['stock.kardex'].invalidate_cache(['kardex_tray_qty']) + # We cannot have fields to depends on to invalidate this computed + # fields on vertical.lift.shuttle. But we know that when the quantity + # of quant changes, we can invalidate the field on the shuttles. + self.env['vertical.lift.shuttle'].invalidate_cache(['tray_qty']) return result diff --git a/stock_kardex/models/stock_kardex.py b/stock_vertical_lift/models/vertical_lift_shuttle.py similarity index 73% rename from stock_kardex/models/stock_kardex.py rename to stock_vertical_lift/models/vertical_lift_shuttle.py index 33b857a95198..adddf6a00039 100644 --- a/stock_kardex/models/stock_kardex.py +++ b/stock_vertical_lift/models/vertical_lift_shuttle.py @@ -5,10 +5,10 @@ from odoo.addons.base_sparse_field.models.fields import Serialized -class StockKardex(models.Model): - _name = 'stock.kardex' +class VerticalLiftShuttle(models.Model): + _name = 'vertical.lift.shuttle' _inherit = 'barcodes.barcode_events_mixin' - _description = 'Stock Kardex' + _description = 'Vertical Lift Shuttle' name = fields.Char() address = fields.Char() @@ -20,9 +20,9 @@ class StockKardex(models.Model): location_id = fields.Many2one( comodel_name='stock.location', required=True, - domain="[('kardex_kind', '=', 'shuttle')]", + domain="[('vertical_lift_kind', '=', 'shuttle')]", ondelete='restrict', - help="The Kardex source location for Pick operations " + help="The Shuttle source location for Pick operations " "and destination location for Put operations.", ) simulate = fields.Boolean( @@ -35,7 +35,7 @@ class StockKardex(models.Model): ) number_of_ops_all = fields.Integer( compute='_compute_number_of_ops_all', - string='Number of Operations in all Kardex', + string='Number of Operations in all shuttles', ) operation_descr = fields.Char( @@ -43,31 +43,25 @@ class StockKardex(models.Model): ) # tray information (will come from stock.location or a new tray model) - kardex_tray_location_id = fields.Many2one( + tray_location_id = fields.Many2one( comodel_name='stock.location', - compute='_compute_kardex_tray_matrix', + compute='_compute_tray_matrix', string='Tray Location', ) - kardex_tray_name = fields.Char( - compute='_compute_kardex_tray_matrix', string='Tray Name' - ) - kardex_tray_type_id = fields.Many2one( - comodel_name='stock.kardex.tray.type', - compute='_compute_kardex_tray_matrix', + tray_name = fields.Char(compute='_compute_tray_matrix', string='Tray Name') + tray_type_id = fields.Many2one( + comodel_name='vertical.lift.tray.type', + compute='_compute_tray_matrix', string='Tray Type', ) - kardex_tray_type_code = fields.Char( - compute='_compute_kardex_tray_matrix', string='Tray Code' - ) - kardex_tray_x = fields.Integer( - string='X', compute='_compute_kardex_tray_matrix' + tray_type_code = fields.Char( + compute='_compute_tray_matrix', string='Tray Code' ) - kardex_tray_y = fields.Integer( - string='Y', compute='_compute_kardex_tray_matrix' - ) - kardex_tray_matrix = Serialized(compute='_compute_kardex_tray_matrix') - kardex_tray_qty = fields.Float( - string='Stock Quantity', compute='_compute_kardex_tray_qty' + tray_x = fields.Integer(string='X', compute='_compute_tray_matrix') + tray_y = fields.Integer(string='Y', compute='_compute_tray_matrix') + tray_matrix = Serialized(string='Cells', compute='_compute_tray_matrix') + tray_qty = fields.Float( + string='Stock Quantity', compute='_compute_tray_qty' ) # current operation information @@ -127,7 +121,7 @@ def _compute_product_packagings(self): ] } content = self.env['ir.qweb'].render( - 'stock_kardex.packagings', values + 'stock_vertical_lift.packagings', values ) record.product_packagings = content @@ -141,24 +135,22 @@ def _compute_number_of_ops_all(self): for record in self: record.number_of_ops_all = record.count_move_lines_to_do_all() - @api.depends('kardex_tray_location_id', 'current_move_line_id.product_id') - def _compute_kardex_tray_qty(self): + @api.depends('tray_location_id', 'current_move_line_id.product_id') + def _compute_tray_qty(self): for record in self: - if not ( - record.kardex_tray_location_id and record.current_move_line_id - ): + if not (record.tray_location_id and record.current_move_line_id): continue product = record.current_move_line_id.product_id quants = self.env['stock.quant'].search( [ - ('location_id', '=', record.kardex_tray_location_id.id), + ('location_id', '=', record.tray_location_id.id), ('product_id', '=', product.id), ] ) - record.kardex_tray_qty = sum(quants.mapped('quantity')) + record.tray_qty = sum(quants.mapped('quantity')) @api.depends() - def _compute_kardex_tray_matrix(self): + def _compute_tray_matrix(self): for record in self: modes = { 'pick': 'location_id', @@ -167,22 +159,22 @@ def _compute_kardex_tray_matrix(self): 'inventory': 'location_id', } location = record.current_move_line_id[modes[record.mode]] - tray_type = location.location_id.kardex_tray_type_id + tray_type = location.location_id.vertical_lift_tray_type_id selected = [] cells = [] if location: - selected = location._kardex_cell_coords() - cells = location._tray_cells_matrix() + selected = location._tray_cell_coords() + cells = location._tray_cell_matrix() # this is the current cell - record.kardex_tray_location_id = location.id + record.tray_location_id = location.id # name of the tray where the cell is - record.kardex_tray_name = location.location_id.name - record.kardex_tray_type_id = tray_type.id - record.kardex_tray_type_code = tray_type.code - record.kardex_tray_x = location.posx - record.kardex_tray_y = location.posy - record.kardex_tray_matrix = { + record.tray_name = location.location_id.name + record.tray_type_id = tray_type.id + record.tray_type_code = tray_type.code + record.tray_x = location.posx + record.tray_y = location.posy + record.tray_matrix = { # x, y: position of the selected cell 'selected': selected, # 0 is empty, 1 is not @@ -196,8 +188,8 @@ def _domain_move_lines_to_do(self): ] domain_extensions = { 'pick': [('location_id', 'child_of', self.location_id.id)], - # TODO ensure that we cannot have the same ml in 2 kardex (cannot - # happen with 'pick' as they are in the kardex' location) + # TODO ensure that we cannot have the same ml in 2 shuttles (cannot + # happen with 'pick' as they are in the shuttle's location) 'put': [('location_dest_id', 'child_of', self.location_id.id)], # TODO 'inventory': [('id', '=', 0)], @@ -209,13 +201,13 @@ def _domain_move_lines_to_do_all(self): # TODO check state ('state', '=', 'assigned') ] - # TODO search only in the view being a parent of kardex's location - kardex_locations = self.env['stock.location'].search( - [('kardex_kind', '=', 'view')] + # TODO search only in the view being a parent of shuttle's location + shuttle_locations = self.env['stock.location'].search( + [('vertical_lift_kind', '=', 'view')] ) domain_extensions = { - 'pick': [('location_id', 'child_of', kardex_locations.ids)], - 'put': [('location_dest_id', 'child_of', kardex_locations.ids)], + 'pick': [('location_id', 'child_of', shuttle_locations.ids)], + 'put': [('location_dest_id', 'child_of', shuttle_locations.ids)], # TODO 'inventory': [('id', '=', 0)], } @@ -279,7 +271,9 @@ def select_next_move_line(self): def action_open_screen(self): self.select_next_move_line() self.ensure_one() - screen_xmlid = 'stock_kardex.stock_kardex_view_form_screen' + screen_xmlid = ( + 'stock_vertical_lift.vertical_lift_shuttle_view_form_screen' + ) return { 'type': 'ir.actions.act_window', 'res_model': self._name, @@ -294,10 +288,10 @@ def action_open_screen(self): } def action_menu(self): - menu_xmlid = 'stock_kardex.stock_kardex_form_menu' + menu_xmlid = 'stock_vertical_lift.vertical_lift_shuttle_form_menu' return { 'type': 'ir.actions.act_window', - 'res_model': 'stock.kardex', + 'res_model': 'vertical.lift.shuttle', 'views': [[self.env.ref(menu_xmlid).id, 'form']], 'name': _('Menu'), 'target': 'new', @@ -307,13 +301,13 @@ def action_menu(self): def action_manual_barcode(self): return { 'type': 'ir.actions.act_window', - 'res_model': 'stock.kardex.manual.barcode', + 'res_model': 'vertical.lift.shuttle.manual.barcode', 'view_mode': 'form', 'name': _('Barcode'), 'target': 'new', } - # TODO: should the mode be changed on all the kardex at the same time? + # TODO: should the mode be changed on all the shuttles at the same time? def switch_pick(self): self.mode = 'pick' self.select_next_move_line() @@ -327,17 +321,17 @@ def switch_inventory(self): self.select_next_move_line() -class StockKardexManualBarcode(models.TransientModel): - _name = 'stock.kardex.manual.barcode' +class VerticalLiftShuttleManualBarcode(models.TransientModel): + _name = 'vertical.lift.shuttle.manual.barcode' _description = 'Action to input a barcode' barcode = fields.Char(string="Barcode") @api.multi def button_save(self): - kardex_id = self.env.context.get('active_id') - kardex = self.env['stock.kardex'].browse(kardex_id).exists() - if not kardex: + shuttle_id = self.env.context.get('active_id') + shuttle = self.env['vertical.lift.shuttle'].browse(shuttle_id).exists() + if not shuttle: return if self.barcode: - kardex.on_barcode_scanned(self.barcode) + shuttle.on_barcode_scanned(self.barcode) diff --git a/stock_kardex/models/stock_kardex_tray_type.py b/stock_vertical_lift/models/vertical_lift_tray_type.py similarity index 84% rename from stock_kardex/models/stock_kardex_tray_type.py rename to stock_vertical_lift/models/vertical_lift_tray_type.py index b3ee4810110c..b6dfa0b5615a 100644 --- a/stock_kardex/models/stock_kardex_tray_type.py +++ b/stock_vertical_lift/models/vertical_lift_tray_type.py @@ -5,9 +5,9 @@ from odoo.addons.base_sparse_field.models.fields import Serialized -class StockKardexTrayType(models.Model): - _name = 'stock.kardex.tray.type' - _description = 'Stock Kardex Tray Type' +class VerticalLiftTrayType(models.Model): + _name = 'vertical.lift.tray.type' + _description = 'Vertical Lift Tray Type' name = fields.Char(required=True) code = fields.Char(required=True) @@ -16,7 +16,8 @@ class StockKardexTrayType(models.Model): active = fields.Boolean(default=True) tray_matrix = Serialized(compute='_compute_tray_matrix') location_ids = fields.One2many( - comodel_name='stock.location', inverse_name='kardex_tray_type_id' + comodel_name='stock.location', + inverse_name='vertical_lift_tray_type_id', ) # TODO do we want box size, or a many2one to 'product.packaging'? # TODO add the code in the name_search @@ -35,7 +36,7 @@ def _generate_cells_matrix(self, default_state=0): return [[default_state] * self.cols for __ in range(self.rows)] @api.constrains('active') - def _stock_kardex_check_active(self): + def _vertical_lift_check_active(self): for record in self: if record.active: continue @@ -52,7 +53,7 @@ def _stock_kardex_check_active(self): ) @api.constrains('rows', 'cols') - def _stock_kardex_check_rows_cols(self): + def _vertical_lift_check_rows_cols(self): for record in self: if record.location_ids: location_bullets = [ @@ -69,7 +70,7 @@ def _stock_kardex_check_rows_cols(self): @api.multi def open_locations(self): action = self.env.ref('stock.action_location_form').read()[0] - action['domain'] = [('kardex_tray_type_id', 'in', self.ids)] + action['domain'] = [('vertical_lift_tray_type_id', 'in', self.ids)] if len(self.ids) == 1: - action['context'] = {'default_kardex_tray_type_id': self.id} + action['context'] = {'default_vertical_lift_tray_type_id': self.id} return action diff --git a/stock_vertical_lift/security/ir.model.access.csv b/stock_vertical_lift/security/ir.model.access.csv new file mode 100644 index 000000000000..e87ef767b334 --- /dev/null +++ b/stock_vertical_lift/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_vertical_lift_shuttle_stock_user,access_vertical_lift_shuttle stock user,model_vertical_lift_shuttle,stock.group_stock_user,1,0,0,0 +access_vertical_lift_shuttle_manager,access_vertical_lift_shuttle stock manager,model_vertical_lift_shuttle,stock.group_stock_manager,1,1,1,1 +access_vertical_lift_tray_type_stock_user,access_vertical_lift_tray_type stock user,model_vertical_lift_tray_type,stock.group_stock_user,1,0,0,0 +access_vertical_lift_tray_type_manager,access_vertical_lift_tray_type stock manager,model_vertical_lift_tray_type,stock.group_stock_manager,1,1,1,1 diff --git a/stock_kardex/static/src/js/kardex.js b/stock_vertical_lift/static/src/js/vertical_lift.js similarity index 93% rename from stock_kardex/static/src/js/kardex.js rename to stock_vertical_lift/static/src/js/vertical_lift.js index 83ba2bf385fa..22fe718076a2 100644 --- a/stock_kardex/static/src/js/kardex.js +++ b/stock_vertical_lift/static/src/js/vertical_lift.js @@ -1,7 +1,6 @@ -odoo.define('stock_kardex.kardex', function (require) { +odoo.define('stock_vertical_lift.vertical_lift', function (require) { "use strict"; - var core = require('web.core'); var KanbanRecord = require('web.KanbanRecord'); var basicFields = require('web.basic_fields'); @@ -12,8 +11,8 @@ var FieldInteger = basicFields.FieldInteger; KanbanRecord.include({ _openRecord: function () { - if (this.modelName === 'stock.kardex' - && this.$el.hasClass("open_kardex_screen")) { + if (this.modelName === 'vertical.lift.shuttle' + && this.$el.hasClass("open_shuttle_screen")) { var self = this; this._rpc({ method: 'action_open_screen', @@ -31,7 +30,7 @@ KanbanRecord.include({ var ExitButton = FieldInteger.extend({ tagName: 'button', - className: 'btn btn-danger btn-block btn-lg o_kardex_exit', + className: 'btn btn-danger btn-block btn-lg o_shuttle_exit', events: { 'click': '_onClick', }, @@ -42,7 +41,7 @@ var ExitButton = FieldInteger.extend({ // the only reason to have this field widget is to be able // to inject clear_breadcrumbs in the action: // it will revert back to a normal - non-headless - view - this.do_action('stock_kardex.stock_kardex_action', { + this.do_action('stock_vertical_lift.vertical_lift_shuttle_action', { clear_breadcrumbs: true, }); }, @@ -57,13 +56,13 @@ var ExitButton = FieldInteger.extend({ * the options of the field and be on the same model: * * * */ -var KardexTrayMatrixField = DebouncedField.extend({ - className: 'o_field_kardex_tray_matrix', +var LocationTrayMatrixField = DebouncedField.extend({ + className: 'o_field_location_tray_matrix', tagName: 'canvas', supportedFieldTypes: ['serialized'], events: { @@ -281,12 +280,12 @@ var KardexTrayMatrixField = DebouncedField.extend({ }); -field_registry.add('exit_button', ExitButton); -field_registry.add('kardex_tray_matrix', KardexTrayMatrixField); +field_registry.add('vlift_shuttle_exit_button', ExitButton); +field_registry.add('location_tray_matrix', LocationTrayMatrixField); return { ExitButton: ExitButton, - KardexTrayMatrixField: KardexTrayMatrixField + LocationTrayMatrixField: LocationTrayMatrixField }; }); diff --git a/stock_kardex/static/src/scss/kardex_view.scss b/stock_vertical_lift/static/src/scss/vertical_lift.scss similarity index 72% rename from stock_kardex/static/src/scss/kardex_view.scss rename to stock_vertical_lift/static/src/scss/vertical_lift.scss index 17f812ae0473..0fc24b43e572 100644 --- a/stock_kardex/static/src/scss/kardex_view.scss +++ b/stock_vertical_lift/static/src/scss/vertical_lift.scss @@ -1,12 +1,12 @@ -.o_field_kardex_tray_matrix { +.o_field_location_tray_matrix { background-color: #eeeeee; border: 2px #000000 solid; } .o_web_client.o_fullscreen { - $o-kardex-padding: $o-horizontal-padding; + $o-shuttle-padding: $o-horizontal-padding; - .o_form_view.o_kardex { + .o_form_view.o_vlift_shuttle { display: flex; flex-flow: column nowrap; padding: 0; @@ -23,13 +23,13 @@ margin: 0 5px; } - .o_kardex_header { + .o_shuttle_header { display: flex; flex-flow: row wrap; - padding: $o-kardex-padding; + padding: $o-shuttle-padding; } - .o_kardex_header_content { + .o_shuttle_header_content { display: flex; flex-flow: row nowrap; font-size: 2.0em; @@ -37,49 +37,49 @@ align-items: center; width: 33%; - &.o_kardex_header_right { + &.o_shuttle_header_right { justify-content: flex-end; } } - .o_kardex_actions { + .o_shuttle_actions { display: flex; flex-flow: row nowrap; font-size: 1.2em; - padding: $o-kardex-padding * 0.5; + padding: $o-shuttle-padding * 0.5; } - .o_kardex_operation { + .o_shuttle_operation { text-align: center; font-size: 2.5em; padding: 0.5em; color: #ffffff; } - .o_kardex_content { + .o_shuttle_content { display: flex; flex-flow: row nowrap; flex: 1 0 auto; align-items: center; - &.o_kardex_content_right { + &.o_shuttle_content_right { justify-content: flex-end; } } - .o_kardex_data { + .o_shuttle_data { display: flex; flex-flow: row wrap; - padding: $o-kardex-padding * 0.5; + padding: $o-shuttle-padding * 0.5; - .o_kardex_data_content { + .o_shuttle_data_content { flex-flow: row nowrap; font-size: 1.2em; flex: 1 0 auto; align-items: center; width: 50%; - &.o_kardex_tray { + &.o_shuttle_tray { display: flex; justify-content: flex-end; @@ -88,12 +88,12 @@ } } - .o_field_kardex_tray_matrix { + .o_field_location_tray_matrix { width: 450px; } } - .kardex_highlight { + .o_shuttle_highlight { padding: 6px; border-radius: 10px; } @@ -101,20 +101,20 @@ } - .o_kardex_menu { + .o_vlift_shuttle_menu { .btn { - margin-bottom: $o-kardex-padding; + margin-bottom: $o-shuttle-padding; padding: 1em; font-size: 2em; text-transform: uppercase; } - .o_kardex_exit { + .o_shuttle_exit { text-align: center; } } - .o_kardex_manual_barcode { + .o_vlift_shuttle_manual_barcode { .o_field_char { padding: 1em; font-size: 2em; diff --git a/stock_vertical_lift/tests/__init__.py b/stock_vertical_lift/tests/__init__.py new file mode 100644 index 000000000000..61fbd1fd98e6 --- /dev/null +++ b/stock_vertical_lift/tests/__init__.py @@ -0,0 +1,3 @@ +from . import test_location +from . import test_vertical_lift_tray_type +from . import test_vertical_lift_shuttle diff --git a/stock_kardex/tests/common.py b/stock_vertical_lift/tests/common.py similarity index 79% rename from stock_kardex/tests/common.py rename to stock_vertical_lift/tests/common.py index 5adac3c50cea..10d20e683072 100644 --- a/stock_kardex/tests/common.py +++ b/stock_vertical_lift/tests/common.py @@ -4,18 +4,24 @@ from odoo.tests import common -class KardexCase(common.SavepointCase): +class VerticalLiftCase(common.SavepointCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.kardex = cls.env.ref('stock_kardex.stock_kardex_demo_shuttle_1') - cls.product_socks = cls.env.ref('stock_kardex.product_running_socks') - cls.kardex_view = cls.env.ref('stock_kardex.stock_location_kardex') + cls.shuttle = cls.env.ref( + 'stock_vertical_lift.stock_vertical_lift_demo_shuttle_1' + ) + cls.product_socks = cls.env.ref( + 'stock_vertical_lift.product_running_socks' + ) + cls.vertical_lift_loc = cls.env.ref( + 'stock_vertical_lift.stock_location_vertical_lift' + ) cls.tray_type_small_8x = cls.env.ref( - 'stock_kardex.kardex_tray_type_small_8x' + 'stock_vertical_lift.vertical_lift_tray_type_small_8x' ) cls.tray_type_small_32x = cls.env.ref( - 'stock_kardex.kardex_tray_type_small_32x' + 'stock_vertical_lift.vertical_lift_tray_type_small_32x' ) def _cell_for(self, tray, x=1, y=1): diff --git a/stock_kardex/tests/test_kardex_location.py b/stock_vertical_lift/tests/test_location.py similarity index 67% rename from stock_kardex/tests/test_kardex_location.py rename to stock_vertical_lift/tests/test_location.py index 52b1ca7dc6eb..af24fa761322 100644 --- a/stock_kardex/tests/test_kardex_location.py +++ b/stock_vertical_lift/tests/test_location.py @@ -3,45 +3,48 @@ from odoo import exceptions -from .common import KardexCase +from .common import VerticalLiftCase -class TestKardexLocation(KardexCase): - def test_kardex_kind(self): - # this boolean is what defines a "Kardex View", the upper level +class TestVerticalLiftLocation(VerticalLiftCase): + def test_vertical_lift_kind(self): + # this boolean is what defines a "Vertical Lift View", the upper level # of the tree (View -> Shuttles -> Trays -> Cells) - self.assertTrue(self.kardex_view.kardex_location) - self.assertEqual(self.kardex_view.kardex_kind, 'view') + self.assertTrue(self.vertical_lift_loc.vertical_lift_location) + self.assertEqual(self.vertical_lift_loc.vertical_lift_kind, 'view') # check types accross the hierarchy - shuttles = self.kardex_view.child_ids + shuttles = self.vertical_lift_loc.child_ids self.assertTrue( - all(location.kardex_kind == 'shuttle' for location in shuttles) + all( + location.vertical_lift_kind == 'shuttle' + for location in shuttles + ) ) trays = shuttles.mapped('child_ids') self.assertTrue( - all(location.kardex_kind == 'tray' for location in trays) + all(location.vertical_lift_kind == 'tray' for location in trays) ) cells = trays.mapped('child_ids') self.assertTrue( - all(location.kardex_kind == 'cell' for location in cells) + all(location.vertical_lift_kind == 'cell' for location in cells) ) - def test_kardex_create_shuttle(self): + def test_create_shuttle(self): # any location created directly under the view is a shuttle shuttle_loc = self.env['stock.location'].create( { 'name': 'Shuttle 42', - 'location_id': self.kardex_view.id, + 'location_id': self.vertical_lift_loc.id, 'usage': 'internal', } ) - self.assertEqual(shuttle_loc.kardex_kind, 'shuttle') + self.assertEqual(shuttle_loc.vertical_lift_kind, 'shuttle') - def test_kardex_create_tray(self): + def test_create_tray(self): # any location created directly under a shuttle is a tray shuttle_loc = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_shuttle_1' + 'stock_vertical_lift.stock_location_vertical_lift_demo_shuttle_1' ) tray_type = self.tray_type_small_8x tray_loc = self.env['stock.location'].create( @@ -49,34 +52,34 @@ def test_kardex_create_tray(self): 'name': 'Tray Z', 'location_id': shuttle_loc.id, 'usage': 'internal', - 'kardex_tray_type_id': tray_type.id, + 'vertical_lift_tray_type_id': tray_type.id, } ) - self.assertEqual(tray_loc.kardex_kind, 'tray') + self.assertEqual(tray_loc.vertical_lift_kind, 'tray') self.assertEqual( len(tray_loc.child_ids), tray_type.cols * tray_type.rows # 8 ) - def test_kardex_tray_has_stock(self): + def test_tray_has_stock(self): cell = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_1a_x3y2' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a_x3y2' ) self.assertFalse(cell.quant_ids) - self.assertFalse(cell.kardex_cell_contains_stock) + self.assertFalse(cell.tray_cell_contains_stock) self._update_quantity_in_cell(cell, self.product_socks, 1) self.assertTrue(cell.quant_ids) - self.assertTrue(cell.kardex_cell_contains_stock) + self.assertTrue(cell.tray_cell_contains_stock) self._update_quantity_in_cell(cell, self.product_socks, -1) self.assertTrue(cell.quant_ids) - self.assertFalse(cell.kardex_cell_contains_stock) + self.assertFalse(cell.tray_cell_contains_stock) def test_matrix_empty_tray(self): tray_loc = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_1a' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a' ) - self.assertEqual(tray_loc.kardex_tray_type_id.cols, 4) - self.assertEqual(tray_loc.kardex_tray_type_id.rows, 2) + self.assertEqual(tray_loc.vertical_lift_tray_type_id.cols, 4) + self.assertEqual(tray_loc.vertical_lift_tray_type_id.rows, 2) self.assertEqual( tray_loc.tray_matrix, { @@ -94,7 +97,7 @@ def test_matrix_empty_tray(self): def test_matrix_stock_tray(self): tray_loc = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_1a' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a' ) self._update_quantity_in_cell( self._cell_for(tray_loc, x=1, y=1), self.product_socks, 100 @@ -105,8 +108,8 @@ def test_matrix_stock_tray(self): self._update_quantity_in_cell( self._cell_for(tray_loc, x=4, y=2), self.product_socks, 100 ) - self.assertEqual(tray_loc.kardex_tray_type_id.cols, 4) - self.assertEqual(tray_loc.kardex_tray_type_id.rows, 2) + self.assertEqual(tray_loc.vertical_lift_tray_type_id.cols, 4) + self.assertEqual(tray_loc.vertical_lift_tray_type_id.rows, 2) self.assertEqual( tray_loc.tray_matrix, { @@ -131,7 +134,7 @@ def test_matrix_stock_tray(self): def test_matrix_stock_cell(self): tray_loc = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_1c' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1c' ) cell = self._cell_for(tray_loc, x=7, y=3) self._update_quantity_in_cell(cell, self.product_socks, 100) @@ -141,8 +144,8 @@ def test_matrix_stock_cell(self): self._update_quantity_in_cell( self._cell_for(tray_loc, x=3, y=2), self.product_socks, 100 ) - self.assertEqual(tray_loc.kardex_tray_type_id.cols, 8) - self.assertEqual(tray_loc.kardex_tray_type_id.rows, 4) + self.assertEqual(tray_loc.vertical_lift_tray_type_id.cols, 8) + self.assertEqual(tray_loc.vertical_lift_tray_type_id.rows, 4) self.assertEqual( cell.tray_matrix, { @@ -165,18 +168,18 @@ def test_matrix_stock_cell(self): def test_check_active_empty(self): # this type used by tray T1B, we should not be able to disable it cell = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_1a_x3y2' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a_x3y2' ) - self.assertFalse(cell.kardex_cell_contains_stock) + self.assertFalse(cell.tray_cell_contains_stock) # allowed to archive empty cell cell.active = False def test_check_active_not_empty(self): cell = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_1a_x3y2' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a_x3y2' ) self._update_quantity_in_cell(cell, self.product_socks, 1) - self.assertTrue(cell.kardex_cell_contains_stock) + self.assertTrue(cell.tray_cell_contains_stock) # we cannot archive an empty cell or any parent location = cell @@ -188,22 +191,26 @@ def test_check_active_not_empty(self): # restore state for the next test loop location.active = True parent = location.location_id - location = parent if parent.kardex_kind else None + location = parent if parent.vertical_lift_kind else None def test_change_tray_type_when_empty(self): - tray = self.env.ref('stock_kardex.stock_location_kardex_demo_tray_1a') + tray = self.env.ref( + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a' + ) tray_type = self.tray_type_small_32x - tray.kardex_tray_type_id = tray_type + tray.vertical_lift_tray_type_id = tray_type self.assertEqual( len(tray.child_ids), tray_type.cols * tray_type.rows # 32 ) def test_change_tray_type_error_when_not_empty(self): - tray = self.env.ref('stock_kardex.stock_location_kardex_demo_tray_1a') + tray = self.env.ref( + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a' + ) self._update_quantity_in_cell( self._cell_for(tray, x=1, y=1), self.product_socks, 1 ) tray_type = self.tray_type_small_32x message = 'cannot be modified when they contain products' with self.assertRaisesRegex(exceptions.UserError, message): - tray.kardex_tray_type_id = tray_type + tray.vertical_lift_tray_type_id = tray_type diff --git a/stock_kardex/tests/test_kardex.py b/stock_vertical_lift/tests/test_vertical_lift_shuttle.py similarity index 51% rename from stock_kardex/tests/test_kardex.py rename to stock_vertical_lift/tests/test_vertical_lift_shuttle.py index c561a1cfc711..a8d6631f01e9 100644 --- a/stock_kardex/tests/test_kardex.py +++ b/stock_vertical_lift/tests/test_vertical_lift_shuttle.py @@ -5,63 +5,63 @@ from odoo import _, exceptions -from .common import KardexCase +from .common import VerticalLiftCase -class TestKardexTrayType(KardexCase): +class TestVerticalLiftTrayType(VerticalLiftCase): @classmethod def setUpClass(cls): super().setUpClass() cls.picking_out = cls.env.ref( - 'stock_kardex.stock_picking_out_demo_kardex_1' + 'stock_vertical_lift.stock_picking_out_demo_vertical_lift_1' ) # we have a move line to pick created by demo picking - # stock_picking_out_demo_kardex_1 + # stock_picking_out_demo_vertical_lift_1 cls.out_move_line = cls.picking_out.move_line_ids def test_switch_pick(self): - self.kardex.switch_pick() - self.assertEqual(self.kardex.mode, 'pick') - self.assertEqual(self.kardex.current_move_line_id, self.out_move_line) + self.shuttle.switch_pick() + self.assertEqual(self.shuttle.mode, 'pick') + self.assertEqual(self.shuttle.current_move_line_id, self.out_move_line) def test_switch_put(self): - self.kardex.switch_put() - self.assertEqual(self.kardex.mode, 'put') + self.shuttle.switch_put() + self.assertEqual(self.shuttle.mode, 'put') # TODO check that we have an incoming move when switching self.assertEqual( - self.kardex.current_move_line_id, + self.shuttle.current_move_line_id, self.env['stock.move.line'].browse(), ) def test_switch_inventory(self): - self.kardex.switch_inventory() - self.assertEqual(self.kardex.mode, 'inventory') + self.shuttle.switch_inventory() + self.assertEqual(self.shuttle.mode, 'inventory') # TODO check that we have what we should (what?) self.assertEqual( - self.kardex.current_move_line_id, + self.shuttle.current_move_line_id, self.env['stock.move.line'].browse(), ) def test_pick_action_open_screen(self): - self.kardex.switch_pick() - action = self.kardex.action_open_screen() - self.assertTrue(self.kardex.current_move_line_id) + self.shuttle.switch_pick() + action = self.shuttle.action_open_screen() + self.assertTrue(self.shuttle.current_move_line_id) self.assertEqual(action['type'], 'ir.actions.act_window') - self.assertEqual(action['res_model'], 'stock.kardex') - self.assertEqual(action['res_id'], self.kardex.id) + self.assertEqual(action['res_model'], 'vertical.lift.shuttle') + self.assertEqual(action['res_id'], self.shuttle.id) def test_pick_select_next_move_line(self): - self.kardex.switch_pick() - self.kardex.select_next_move_line() - self.assertEqual(self.kardex.current_move_line_id, self.out_move_line) - self.assertEqual(self.kardex.operation_descr, _('Scan next PID')) + self.shuttle.switch_pick() + self.shuttle.select_next_move_line() + self.assertEqual(self.shuttle.current_move_line_id, self.out_move_line) + self.assertEqual(self.shuttle.operation_descr, _('Scan next PID')) def test_pick_save(self): - self.kardex.switch_pick() - self.kardex.current_move_line_id = self.out_move_line - result = self.kardex.button_save() - self.assertFalse(self.kardex.current_move_line_id) - self.assertEqual(self.kardex.operation_descr, _('No operations')) + self.shuttle.switch_pick() + self.shuttle.current_move_line_id = self.out_move_line + result = self.shuttle.button_save() + self.assertFalse(self.shuttle.current_move_line_id) + self.assertEqual(self.shuttle.operation_descr, _('No operations')) expected_result = { 'effect': { 'fadeout': 'slow', @@ -73,58 +73,58 @@ def test_pick_save(self): self.assertEqual(result, expected_result) def test_pick_related_fields(self): - self.kardex.switch_pick() - ml = self.kardex.current_move_line_id = self.out_move_line + self.shuttle.switch_pick() + ml = self.shuttle.current_move_line_id = self.out_move_line - # Kardex trays related fields + # Trays related fields # For pick, this is the source location, which is the cell where the # product is. - self.assertEqual(self.kardex.kardex_tray_location_id, ml.location_id) + self.assertEqual(self.shuttle.tray_location_id, ml.location_id) self.assertEqual( - self.kardex.kardex_tray_name, + self.shuttle.tray_name, # parent = tray ml.location_id.location_id.name, ) self.assertEqual( - self.kardex.kardex_tray_type_id, + self.shuttle.tray_type_id, # the tray type is on the parent of the cell (on the tray) - ml.location_id.location_id.kardex_tray_type_id, + ml.location_id.location_id.vertical_lift_tray_type_id, ) self.assertEqual( - self.kardex.kardex_tray_type_code, - ml.location_id.location_id.kardex_tray_type_id.code, + self.shuttle.tray_type_code, + ml.location_id.location_id.vertical_lift_tray_type_id.code, ) - self.assertEqual(self.kardex.kardex_tray_x, ml.location_id.posx) - self.assertEqual(self.kardex.kardex_tray_y, ml.location_id.posy) + self.assertEqual(self.shuttle.tray_x, ml.location_id.posx) + self.assertEqual(self.shuttle.tray_y, ml.location_id.posy) # Move line related fields - self.assertEqual(self.kardex.picking_id, ml.picking_id) - self.assertEqual(self.kardex.picking_origin, ml.picking_id.origin) + self.assertEqual(self.shuttle.picking_id, ml.picking_id) + self.assertEqual(self.shuttle.picking_origin, ml.picking_id.origin) self.assertEqual( - self.kardex.picking_partner_id, ml.picking_id.partner_id + self.shuttle.picking_partner_id, ml.picking_id.partner_id ) - self.assertEqual(self.kardex.product_id, ml.product_id) - self.assertEqual(self.kardex.product_uom_id, ml.product_uom_id) - self.assertEqual(self.kardex.product_uom_qty, ml.product_uom_qty) - self.assertEqual(self.kardex.qty_done, ml.qty_done) - self.assertEqual(self.kardex.lot_id, ml.lot_id) + self.assertEqual(self.shuttle.product_id, ml.product_id) + self.assertEqual(self.shuttle.product_uom_id, ml.product_uom_id) + self.assertEqual(self.shuttle.product_uom_qty, ml.product_uom_qty) + self.assertEqual(self.shuttle.qty_done, ml.qty_done) + self.assertEqual(self.shuttle.lot_id, ml.lot_id) def test_pick_count_move_lines(self): - product1 = self.env.ref('stock_kardex.product_running_socks') - product2 = self.env.ref('stock_kardex.product_recovery_socks') + product1 = self.env.ref('stock_vertical_lift.product_running_socks') + product2 = self.env.ref('stock_vertical_lift.product_recovery_socks') # cancel the picking from demo data to start from a clean state self.env.ref( - 'stock_kardex.stock_picking_out_demo_kardex_1' + 'stock_vertical_lift.stock_picking_out_demo_vertical_lift_1' ).action_cancel() # ensure that we have stock in some cells, we'll put product1 - # in the first kardex and product2 in the second + # in the first Shuttle and product2 in the second cell1 = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_1a_x3y2' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a_x3y2' ) self._update_quantity_in_cell(cell1, product1, 50) cell2 = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_2a_x1y1' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_2a_x1y1' ) self._update_quantity_in_cell(cell2, product2, 50) @@ -141,32 +141,34 @@ def test_pick_count_move_lines(self): unassigned = self._create_simple_picking_out(product2, 1) pickings |= unassigned pickings.action_confirm() - # product1 will be taken from the kardex1, product2 from kardex2 + # product1 will be taken from the shuttle1, product2 from shuttle2 pickings.action_assign() - kardex1 = self.kardex - kardex2 = self.env.ref('stock_kardex.stock_kardex_demo_shuttle_2') + shuttle1 = self.shuttle + shuttle2 = self.env.ref( + 'stock_vertical_lift.stock_vertical_lift_demo_shuttle_2' + ) - self.assertEqual(kardex1.number_of_ops, 4) - self.assertEqual(kardex2.number_of_ops, 2) - self.assertEqual(kardex1.number_of_ops_all, 6) - self.assertEqual(kardex2.number_of_ops_all, 6) + self.assertEqual(shuttle1.number_of_ops, 4) + self.assertEqual(shuttle2.number_of_ops, 2) + self.assertEqual(shuttle1.number_of_ops_all, 6) + self.assertEqual(shuttle2.number_of_ops_all, 6) # Process a line, should change the numbers. - kardex1.select_next_move_line() - kardex1.process_current_pick() - self.assertEqual(kardex1.number_of_ops, 3) - self.assertEqual(kardex2.number_of_ops, 2) - self.assertEqual(kardex1.number_of_ops_all, 5) - self.assertEqual(kardex2.number_of_ops_all, 5) + shuttle1.select_next_move_line() + shuttle1.process_current_pick() + self.assertEqual(shuttle1.number_of_ops, 3) + self.assertEqual(shuttle2.number_of_ops, 2) + self.assertEqual(shuttle1.number_of_ops_all, 5) + self.assertEqual(shuttle2.number_of_ops_all, 5) # add stock and make the last one assigned to check the number is updated self._update_quantity_in_cell(cell2, product2, 10) unassigned.action_assign() - self.assertEqual(kardex1.number_of_ops, 3) - self.assertEqual(kardex2.number_of_ops, 3) - self.assertEqual(kardex1.number_of_ops_all, 6) - self.assertEqual(kardex2.number_of_ops_all, 6) + self.assertEqual(shuttle1.number_of_ops, 3) + self.assertEqual(shuttle2.number_of_ops, 3) + self.assertEqual(shuttle1.number_of_ops_all, 6) + self.assertEqual(shuttle2.number_of_ops_all, 6) @unittest.skip('Not implemented') def test_put_count_move_lines(self): @@ -176,43 +178,43 @@ def test_put_count_move_lines(self): def test_inventory_count_move_lines(self): pass + @unittest.skip('Not implemented') def test_on_barcode_scanned(self): # test to implement when the code is implemented - with self.assertRaises(exceptions.UserError): - self.kardex.on_barcode_scanned('foo') + pass def test_button_release(self): # test to implement when the code is implemented with self.assertRaises(exceptions.UserError): - self.kardex.button_release() + self.shuttle.button_release() def test_process_current_pick(self): - self.kardex.switch_pick() - self.kardex.current_move_line_id = self.out_move_line + self.shuttle.switch_pick() + self.shuttle.current_move_line_id = self.out_move_line qty_to_process = self.out_move_line.product_qty - self.kardex.process_current_pick() + self.shuttle.process_current_pick() self.assertEqual(self.out_move_line.state, 'done') self.assertEqual(self.out_move_line.qty_done, qty_to_process) def test_process_current_put(self): # test to implement when the code is implemented with self.assertRaises(exceptions.UserError): - self.kardex.process_current_put() + self.shuttle.process_current_put() def test_process_current_inventory(self): # test to implement when the code is implemented with self.assertRaises(exceptions.UserError): - self.kardex.process_current_inventory() + self.shuttle.process_current_inventory() def test_matrix(self): - self.kardex.switch_pick() - self.kardex.current_move_line_id = self.out_move_line + self.shuttle.switch_pick() + self.shuttle.current_move_line_id = self.out_move_line location = self.out_move_line.location_id # offset by -1 because the fields are for humans expected_x = location.posx - 1 expected_y = location.posy - 1 self.assertEqual( - self.kardex.kardex_tray_matrix, + self.shuttle.tray_matrix, { 'selected': [expected_x, expected_y], # fmt: off @@ -224,13 +226,13 @@ def test_matrix(self): }, ) - def test_kardex_tray_qty(self): + def test_tray_qty(self): cell = self.env.ref( - 'stock_kardex.stock_location_kardex_demo_tray_1a_x3y2' + 'stock_vertical_lift.stock_location_vertical_lift_demo_tray_1a_x3y2' ) self.out_move_line.location_id = cell - self.kardex.current_move_line_id = self.out_move_line + self.shuttle.current_move_line_id = self.out_move_line self._update_quantity_in_cell(cell, self.out_move_line.product_id, 50) - self.assertEqual(self.kardex.kardex_tray_qty, 50) + self.assertEqual(self.shuttle.tray_qty, 50) self._update_quantity_in_cell(cell, self.out_move_line.product_id, -20) - self.assertEqual(self.kardex.kardex_tray_qty, 30) + self.assertEqual(self.shuttle.tray_qty, 30) diff --git a/stock_kardex/tests/test_kardex_tray_type.py b/stock_vertical_lift/tests/test_vertical_lift_tray_type.py similarity index 84% rename from stock_kardex/tests/test_kardex_tray_type.py rename to stock_vertical_lift/tests/test_vertical_lift_tray_type.py index c18b9a3efab3..53dbcc77134f 100644 --- a/stock_kardex/tests/test_kardex_tray_type.py +++ b/stock_vertical_lift/tests/test_vertical_lift_tray_type.py @@ -3,23 +3,23 @@ from odoo import exceptions -from .common import KardexCase +from .common import VerticalLiftCase -class TestKardexTrayType(KardexCase): +class TestVerticalLiftTrayType(VerticalLiftCase): @classmethod def setUpClass(cls): super().setUpClass() cls.used_tray_type = cls.env.ref( - 'stock_kardex.kardex_tray_type_large_16x' + 'stock_vertical_lift.vertical_lift_tray_type_large_16x' ) cls.unused_tray_type = cls.env.ref( - 'stock_kardex.kardex_tray_type_small_16x_3' + 'stock_vertical_lift.vertical_lift_tray_type_small_16x_3' ) - def test_kardex_tray_type(self): + def test_tray_type(self): # any location created directly under the view is a shuttle - tray_type = self.env['stock.kardex.tray.type'].create( + tray_type = self.env['vertical.lift.tray.type'].create( { 'name': 'Test Type', 'code': '🐵', @@ -44,7 +44,7 @@ def test_kardex_tray_type(self): }, ) - def test_kardex_check_active(self): + def test_check_active(self): # this type used by tray T1B, we should not be able to disable it location = self.used_tray_type.location_ids self.assertTrue(location) @@ -55,7 +55,7 @@ def test_kardex_check_active(self): # we can archive unused ones self.unused_tray_type.active = False - def test_kardex_check_cols_rows(self): + def test_check_cols_rows(self): # this type used by tray T1B, we should not be able to modify size location = self.used_tray_type.location_ids self.assertTrue(location) diff --git a/stock_kardex/templates/kardex_screen.xml b/stock_vertical_lift/views/shuttle_screen_templates.xml similarity index 89% rename from stock_kardex/templates/kardex_screen.xml rename to stock_vertical_lift/views/shuttle_screen_templates.xml index 636e44b78d89..3301f4ca70df 100644 --- a/stock_kardex/templates/kardex_screen.xml +++ b/stock_vertical_lift/views/shuttle_screen_templates.xml @@ -1,7 +1,7 @@