From e060de7efc1738e427e4f6ce82cf2778e5088380 Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Thu, 3 Dec 2020 00:17:57 +0100 Subject: [PATCH] [MIG] stock_usability to v14 --- stock_usability/__init__.py | 7 +- stock_usability/__manifest__.py | 18 +- stock_usability/models/__init__.py | 9 + .../procurement_group.py} | 33 +- .../models/procurement_scheduler_log.py | 15 + stock_usability/models/product_template.py | 12 + .../{partner.py => models/res_partner.py} | 6 +- .../models/stock_location_route.py | 11 + stock_usability/models/stock_move.py | 70 +++ stock_usability/models/stock_picking.py | 32 ++ stock_usability/models/stock_quant.py | 15 + .../models/stock_warehouse_orderpoint.py | 50 ++ stock_usability/product.py | 12 - stock_usability/stock.py | 147 ------ stock_usability/stock_view.xml | 429 ------------------ stock_usability/views/procurement_group.xml | 21 + .../procurement_scheduler_log.xml} | 15 +- stock_usability/views/stock_inventory.xml | 39 ++ stock_usability/views/stock_location.xml | 57 +++ stock_usability/views/stock_move.xml | 84 ++++ stock_usability/views/stock_picking.xml | 133 ++++++ stock_usability/views/stock_quant.xml | 64 +++ stock_usability/views/stock_warehouse.xml | 29 ++ stock_usability/wizard/__init__.py | 3 - .../wizard/stock_quantity_history.py | 30 -- .../wizard/stock_quantity_history_view.xml | 23 - 26 files changed, 664 insertions(+), 700 deletions(-) create mode 100644 stock_usability/models/__init__.py rename stock_usability/{procurement.py => models/procurement_group.py} (57%) create mode 100644 stock_usability/models/procurement_scheduler_log.py create mode 100644 stock_usability/models/product_template.py rename stock_usability/{partner.py => models/res_partner.py} (54%) create mode 100644 stock_usability/models/stock_location_route.py create mode 100644 stock_usability/models/stock_move.py create mode 100644 stock_usability/models/stock_picking.py create mode 100644 stock_usability/models/stock_quant.py create mode 100644 stock_usability/models/stock_warehouse_orderpoint.py delete mode 100644 stock_usability/product.py delete mode 100644 stock_usability/stock.py delete mode 100644 stock_usability/stock_view.xml create mode 100644 stock_usability/views/procurement_group.xml rename stock_usability/{procurement_view.xml => views/procurement_scheduler_log.xml} (66%) create mode 100644 stock_usability/views/stock_inventory.xml create mode 100644 stock_usability/views/stock_location.xml create mode 100644 stock_usability/views/stock_move.xml create mode 100644 stock_usability/views/stock_picking.xml create mode 100644 stock_usability/views/stock_quant.xml create mode 100644 stock_usability/views/stock_warehouse.xml delete mode 100644 stock_usability/wizard/__init__.py delete mode 100644 stock_usability/wizard/stock_quantity_history.py delete mode 100644 stock_usability/wizard/stock_quantity_history_view.xml diff --git a/stock_usability/__init__.py b/stock_usability/__init__.py index 444b4bf..9b42961 100644 --- a/stock_usability/__init__.py +++ b/stock_usability/__init__.py @@ -1,7 +1,2 @@ -# -*- coding: utf-8 -*- - -from . import stock -from . import procurement -from . import product -from . import partner +from . import models from . import wizard diff --git a/stock_usability/__manifest__.py b/stock_usability/__manifest__.py index 1d650e6..4acb88c 100644 --- a/stock_usability/__manifest__.py +++ b/stock_usability/__manifest__.py @@ -1,11 +1,11 @@ -# Copyright 2014-2019 Akretion (http://www.akretion.com) +# Copyright 2014-2020 Akretion (http://www.akretion.com) # @author Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { 'name': 'Stock Usability', - 'version': '12.0.1.0.0', + 'version': '14.0.1.0.0', 'category': 'Inventory, Logistic, Storage', 'license': 'AGPL-3', 'summary': 'Several usability enhancements in Warehouse management', @@ -19,7 +19,6 @@ The usability enhancements include: * add a group by Partner in the picking search view (particularly usefull for receptions) * add graph view for pickings * remove ability to translate stock.location, stock.location.route and stock.picking.type -* unactive view "stock.view_production_lot_form_simple" because it doesn't include smart buttons Locate and Traceability Report ; then we only use the main view "stock.view_production_lot_form" like in previous odoo versions This module has been written by Alexis de Lattre from Akretion . """, @@ -27,10 +26,15 @@ This module has been written by Alexis de Lattre from Akretion # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields, api +from odoo import api, fields, models from datetime import datetime import logging @@ -12,29 +12,18 @@ logger = logging.getLogger(__name__) class ProcurementGroup(models.Model): _inherit = 'procurement.group' - @api.model - def _procure_orderpoint_confirm( - self, use_new_cursor=False, company_id=False): - logger.info( - 'procurement scheduler: START to create moves from ' - 'orderpoints') - res = super(ProcurementGroup, self)._procure_orderpoint_confirm( - use_new_cursor=use_new_cursor, company_id=company_id) - logger.info( - 'procurement scheduler: END creation of moves from ' - 'orderpoints') - return res + picking_ids = fields.One2many( + 'stock.picking', 'group_id', string='Pickings', readonly=True) @api.model - def run_scheduler( - self, use_new_cursor=False, company_id=False): + def run_scheduler(self, use_new_cursor=False, company_id=False): '''Inherit to add info logs''' logger.info( 'START procurement scheduler ' '(company ID=%d, uid=%d, use_new_cursor=%s)', company_id, self._uid, use_new_cursor) start_datetime = datetime.now() - res = super(ProcurementGroup, self).run_scheduler( + res = super().run_scheduler( use_new_cursor=use_new_cursor, company_id=company_id) logger.info( 'END procurement scheduler ' @@ -55,13 +44,3 @@ class ProcurementGroup(models.Model): logger.warning( 'Could not create procurement.scheduler.log (error: %s)', e) return res - - -class ProcurementSchedulerLog(models.Model): - _name = 'procurement.scheduler.log' - _description = 'Logs of the Procurement Scheduler' - _order = 'create_date desc' - - company_id = fields.Many2one( - 'res.company', string='Company', readonly=True) - start_datetime = fields.Datetime(string='Start Date', readonly=True) diff --git a/stock_usability/models/procurement_scheduler_log.py b/stock_usability/models/procurement_scheduler_log.py new file mode 100644 index 0000000..0740a05 --- /dev/null +++ b/stock_usability/models/procurement_scheduler_log.py @@ -0,0 +1,15 @@ +# Copyright 2015-2020 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProcurementSchedulerLog(models.Model): + _name = 'procurement.scheduler.log' + _description = 'Logs of the Procurement Scheduler' + _order = 'create_date desc' + + company_id = fields.Many2one( + 'res.company', string='Company', readonly=True) + start_datetime = fields.Datetime(string='Start Date', readonly=True) diff --git a/stock_usability/models/product_template.py b/stock_usability/models/product_template.py new file mode 100644 index 0000000..47131bc --- /dev/null +++ b/stock_usability/models/product_template.py @@ -0,0 +1,12 @@ +# Copyright 2016-2020 Akretion France +# @author: Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = 'product.template' + + tracking = fields.Selection(tracking=True) + sale_delay = fields.Float(tracking=True) diff --git a/stock_usability/partner.py b/stock_usability/models/res_partner.py similarity index 54% rename from stock_usability/partner.py rename to stock_usability/models/res_partner.py index 2c0a88c..759fded 100644 --- a/stock_usability/partner.py +++ b/stock_usability/models/res_partner.py @@ -1,11 +1,11 @@ -# Copyright 2017-2019 Akretion France (https://akretion.com/) +# Copyright 2017-2020 Akretion France (https://akretion.com/) # @author Alexis de Lattre # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import models, fields +from odoo import fields, models class ResPartner(models.Model): _inherit = 'res.partner' - picking_warn = fields.Selection(track_visibility='onchange') + picking_warn = fields.Selection(tracking=True) diff --git a/stock_usability/models/stock_location_route.py b/stock_usability/models/stock_location_route.py new file mode 100644 index 0000000..ba6a856 --- /dev/null +++ b/stock_usability/models/stock_location_route.py @@ -0,0 +1,11 @@ +# Copyright 2014-2020 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class StockLocationRoute(models.Model): + _inherit = 'stock.location.route' + + name = fields.Char(translate=False) diff --git a/stock_usability/models/stock_move.py b/stock_usability/models/stock_move.py new file mode 100644 index 0000000..387e0f1 --- /dev/null +++ b/stock_usability/models/stock_move.py @@ -0,0 +1,70 @@ +# Copyright 2014-2020 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models, _ +from odoo.exceptions import UserError +import logging + +logger = logging.getLogger(__name__) + + +class StockMove(models.Model): + _inherit = 'stock.move' + +# def name_get(self): +# '''name_get of stock_move is important for the reservation of the +# quants: so want to add the name of the customer and the expected date +# in it''' +# res = [] +# for line in self: +# name = '%s > %s' % ( +# line.location_id.name, line.location_dest_id.name) +# if line.product_id.code: +# name = '%s: %s' % (line.product_id.code, name) +# if line.picking_id.origin: +# name = '%s %s' % (line.picking_id.origin, name) +# if line.partner_id: +# name = '%s %s' % (line.partner_id.name, name) +# if line.date_expected: +# name = '%s %s' % (name, line.date_expected) +# res.append((line.id, name)) +# return res + + def button_do_unreserve(self): + for move in self: + move._do_unreserve() + picking = move.picking_id + if picking: + product = move.product_id + picking.message_post(_( + "Product %s qty %s %s unreserved") + % (product.id, product.display_name, + move.product_qty, product.uom_id.name)) + # Copied from do_unreserved of stock.picking + picking.package_level_ids.filtered(lambda p: not p.move_ids).unlink() + + +class StockMoveLine(models.Model): + _inherit = 'stock.move.line' + + # TODO: I think it's not complete + def button_do_unreserve(self): + for moveline in self: + if moveline.state == 'cancel': + continue + elif moveline.state == 'done': + raise UserError(_( + "You cannot unreserve a move line in done state.")) + picking = moveline.move_id.picking_id + if picking: + product = moveline.product_id + picking.message_post(_( + "Product %s qty %s %s unreserved") + % (product.id, product.display_name, + moveline.product_qty, product.uom_id.name)) + # Copied from do_unreserved of stock.picking + picking.package_level_ids.filtered(lambda p: not p.move_ids).unlink() + moveline.unlink() diff --git a/stock_usability/models/stock_picking.py b/stock_usability/models/stock_picking.py new file mode 100644 index 0000000..dee8bfc --- /dev/null +++ b/stock_usability/models/stock_picking.py @@ -0,0 +1,32 @@ +# Copyright 2014-2020 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models, _ +import logging + +logger = logging.getLogger(__name__) + + +class StockPicking(models.Model): + _inherit = 'stock.picking' +# _order = 'id desc' + # In the stock module: _order = "priority desc, scheduled_date asc, id desc" + # The problem is date asc + + partner_id = fields.Many2one(tracking=True) + picking_type_id = fields.Many2one(tracking=True) + move_type = fields.Selection(tracking=True) + is_locked = fields.Boolean(tracking=True) + + def do_unreserve(self): + res = super().do_unreserve() + for pick in self: + pick.message_post(body=_("Picking unreserved.")) + return res + + +class StockPickingType(models.Model): + _inherit = 'stock.picking.type' + + name = fields.Char(translate=False) diff --git a/stock_usability/models/stock_quant.py b/stock_usability/models/stock_quant.py new file mode 100644 index 0000000..0157ae6 --- /dev/null +++ b/stock_usability/models/stock_quant.py @@ -0,0 +1,15 @@ +# Copyright 2014-2020 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import models + + +class StockQuant(models.Model): + _inherit = 'stock.quant' + + def action_stock_move_lines_reserved(self): + self.ensure_one() + action = self.action_view_stock_moves() + action['context'] = {'search_default_todo': True} + return action diff --git a/stock_usability/models/stock_warehouse_orderpoint.py b/stock_usability/models/stock_warehouse_orderpoint.py new file mode 100644 index 0000000..66372a7 --- /dev/null +++ b/stock_usability/models/stock_warehouse_orderpoint.py @@ -0,0 +1,50 @@ +# Copyright 2015-2020 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models +import logging + +logger = logging.getLogger(__name__) + + +class StockWarehouseOrderpoint(models.Model): + _inherit = 'stock.warehouse.orderpoint' + + @api.model + def _procure_orderpoint_confirm( + self, use_new_cursor=False, company_id=False, raise_user_error=True): + logger.info( + 'procurement scheduler: START to create moves from ' + 'orderpoints') + res = super()._procure_orderpoint_confirm( + use_new_cursor=use_new_cursor, company_id=company_id, + raise_user_error=raise_user_error) + logger.info( + 'procurement scheduler: END creation of moves from ' + 'orderpoints') + return res + + # This is for the button shortcut "reordering rules" on + # stock.location form view, so that the location_id has the + # good value, not the default stock location of the first WH of the company + @api.model + def default_get(self, fields_list): + if self._context.get('default_location_id'): + location = self.env['stock.location'].browse( + self._context['default_location_id']) + wh = location.get_warehouse() + if location and wh: + self = self.with_context(default_warehouse_id=wh.id) + return super().default_get(fields_list) + + # This SQL constraint blocks the use of the "active" field + # but I think it's not very useful to have such an "active" field + # on orderpoints ; when you think the order point is bad, you update + # the min/max values, you don't de-active it ! + _sql_constraints = [( + 'company_wh_location_product_unique', + 'unique(company_id, warehouse_id, location_id, product_id)', + 'An orderpoint already exists for the same company, same warehouse, ' + 'same stock location and same product.' + )] diff --git a/stock_usability/product.py b/stock_usability/product.py deleted file mode 100644 index e17af88..0000000 --- a/stock_usability/product.py +++ /dev/null @@ -1,12 +0,0 @@ -# -*- coding: utf-8 -*- -# © 2016 Akretion (Alexis de Lattre ) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import models, fields - - -class ProductTemplate(models.Model): - _inherit = 'product.template' - - tracking = fields.Selection(track_visibility='onchange') - sale_delay = fields.Float(track_visibility='onchange') diff --git a/stock_usability/stock.py b/stock_usability/stock.py deleted file mode 100644 index c71c38f..0000000 --- a/stock_usability/stock.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2014-2019 Akretion (http://www.akretion.com) -# @author Alexis de Lattre -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import models, fields, api, _ -import logging - -logger = logging.getLogger(__name__) - - -class StockPicking(models.Model): - _inherit = 'stock.picking' - _order = 'id desc' - # In the stock module: _order = "priority desc, date asc, id desc" - # The problem is date asc - - partner_id = fields.Many2one(track_visibility='onchange') - picking_type_id = fields.Many2one(track_visibility='onchange') - move_type = fields.Selection(track_visibility='onchange') - # Can be used in view to hide some fields depending of pick type - picking_type_code = fields.Selection(related='picking_type_id.code') - is_locked = fields.Boolean(track_visibility='onchange') - - @api.multi - def do_unreserve(self): - res = super(StockPicking, self).do_unreserve() - for pick in self: - pick.message_post(body=_("Picking unreserved.")) - return res - - -class StockPickingType(models.Model): - _inherit = 'stock.picking.type' - - name = fields.Char(translate=False) - - -class StockLocationRoute(models.Model): - _inherit = 'stock.location.route' - - name = fields.Char(translate=False) - - -class StockWarehouseOrderpoint(models.Model): - _inherit = 'stock.warehouse.orderpoint' - - # This is for the button shortcut "reordering rules" on - # stock.location form view, so that the location_id has the - # good value, not the default stock location of the first WH of the company - @api.model - def default_get(self, fields): - if self._context.get('default_location_id'): - location = self.env['stock.location'].browse( - self._context['default_location_id']) - wh = location.get_warehouse() - if location and wh: - self = self.with_context(default_warehouse_id=wh.id) - return super(StockWarehouseOrderpoint, self).default_get(fields) - - # This SQL constraint blocks the use of the "active" field - # but I think it's not very useful to have such an "active" field - # on orderpoints ; when you think the order point is bad, you update - # the min/max values, you don't de-active it ! - _sql_constraints = [( - 'company_wh_location_product_unique', - 'unique(company_id, warehouse_id, location_id, product_id)', - 'An orderpoint already exists for the same company, same warehouse, ' - 'same stock location and same product.' - )] - - -class StockMove(models.Model): - _inherit = 'stock.move' - - @api.multi - def name_get(self): - '''name_get of stock_move is important for the reservation of the - quants: so want to add the name of the customer and the expected date - in it''' - res = [] - for line in self: - name = '%s > %s' % ( - line.location_id.name, line.location_dest_id.name) - if line.product_id.code: - name = '%s: %s' % (line.product_id.code, name) - if line.picking_id.origin: - name = '%s %s' % (line.picking_id.origin, name) - if line.partner_id: - name = '%s %s' % (line.partner_id.name, name) - if line.date_expected: - name = '%s %s' % (name, line.date_expected) - res.append((line.id, name)) - return res - - def button_do_unreserve(self): - for move in self: - move._do_unreserve() - picking = move.picking_id - if picking: - product = move.product_id - picking.message_post(_( - "Product %s qty %s %s unreserved") - % (product.id, product.display_name, - move.product_qty, product.uom_id.name)) - # Copied from do_unreserved of stock.picking - picking.package_level_ids.filtered(lambda p: not p.move_ids).unlink() - - -class StockMoveLine(models.Model): - _inherit = 'stock.move.line' - - def button_do_unreserve(self): - for moveline in self: - if moveline.state == 'cancel': - continue - elif moveline.state == 'done': - raise UserError(_( - "You cannot unreserve a move line in done state.")) - picking = moveline.move_id.picking_id - if picking: - product = moveline.product_id - picking.message_post(_( - "Product %s qty %s %s unreserved") - % (product.id, product.display_name, - moveline.product_qty, product.uom_id.name)) - # Copied from do_unreserved of stock.picking - picking.package_level_ids.filtered(lambda p: not p.move_ids).unlink() - moveline.unlink() - - -class ProcurementGroup(models.Model): - _inherit = 'procurement.group' - - picking_ids = fields.One2many( - 'stock.picking', 'group_id', string='Pickings', readonly=True) - - -class StockQuant(models.Model): - _inherit = 'stock.quant' - - def action_stock_move_lines_reserved(self): - self.ensure_one() - action = self.action_view_stock_moves() - action['context'] = {'search_default_todo': True} - return action diff --git a/stock_usability/stock_view.xml b/stock_usability/stock_view.xml deleted file mode 100644 index 1443056..0000000 --- a/stock_usability/stock_view.xml +++ /dev/null @@ -1,429 +0,0 @@ - - - - - - - - stock_usability.view_picking_form - stock.picking - - - - {} - - - {'show_address': 1} - {'always_reload': True} - - - - - - 1 - - - - - - - - - - - - - - - - - - - usability.stock.inventory.form - stock.inventory - - - - - product_qty > theoretical_qty - product_qty < theoretical_qty - - - - - - - - usability.stock.inventory.tree - stock.inventory - - - - - - - state == 'draft' - state == 'confirm' - - - - - - stock.usability.quant.tree - stock.quant - - - - 1 - - - 1 - - - - - - stock.usability.quant.form - stock.quant - - -
-
-
-
- - - - - - - Quants - stock.quant - tree,form,pivot - {'search_default_internal_loc': 1} - - - - - - {} - - - - - - - -
diff --git a/stock_usability/views/procurement_group.xml b/stock_usability/views/procurement_group.xml new file mode 100644 index 0000000..e8e0c3e --- /dev/null +++ b/stock_usability/views/procurement_group.xml @@ -0,0 +1,21 @@ + + + + + + + stock_usability.procurement.group.form + procurement.group + + + + + + + + + diff --git a/stock_usability/procurement_view.xml b/stock_usability/views/procurement_scheduler_log.xml similarity index 66% rename from stock_usability/procurement_view.xml rename to stock_usability/views/procurement_scheduler_log.xml index a0fcb08..1cefb61 100644 --- a/stock_usability/procurement_view.xml +++ b/stock_usability/views/procurement_scheduler_log.xml @@ -1,23 +1,12 @@ - - stock_usability.procurement.group.form - procurement.group - - - - - - - - procurement_scheduler_log_tree procurement.scheduler.log @@ -39,6 +28,6 @@ + parent="stock.menu_stock_warehouse_mgmt" sequence="140"/> diff --git a/stock_usability/views/stock_inventory.xml b/stock_usability/views/stock_inventory.xml new file mode 100644 index 0000000..435fac5 --- /dev/null +++ b/stock_usability/views/stock_inventory.xml @@ -0,0 +1,39 @@ + + + + + + + usability.stock.inventory.line.tree + stock.inventory.line + + + + + product_qty > theoretical_qty + product_qty < theoretical_qty + + + + + + usability.stock.inventory.tree + stock.inventory + + + + state == 'draft' + state == 'confirm' + + + + + diff --git a/stock_usability/views/stock_location.xml b/stock_usability/views/stock_location.xml new file mode 100644 index 0000000..ed56749 --- /dev/null +++ b/stock_usability/views/stock_location.xml @@ -0,0 +1,57 @@ + + + + + + + + stock.usability.stock.location.search + stock.location + + + + + + + + + + + + + Reordering Rules + stock.warehouse.orderpoint + {'default_location_id': active_id, 'search_default_location_id': active_id} + + + + stock.usability.stock.location.form + stock.location + + +
+
+
+
+ + + + + +
diff --git a/stock_usability/views/stock_move.xml b/stock_usability/views/stock_move.xml new file mode 100644 index 0000000..9c7f288 --- /dev/null +++ b/stock_usability/views/stock_move.xml @@ -0,0 +1,84 @@ + + + + + + + + + stock.usability.stock.move.form + stock.move + + + + + + + + + + + + + + + + + + + + + + + + stock_usability.move.tree.better.order + stock.move + + + + date desc, picking_id, sequence + + + + + + + 1 + + + + + + + + +