diff --git a/stock_orderpoint_route/README.rst b/stock_orderpoint_route/README.rst new file mode 100644 index 000000000..5fb6cfbbe --- /dev/null +++ b/stock_orderpoint_route/README.rst @@ -0,0 +1,82 @@ +====================== +Stock Orderpoint Route +====================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-warehouse/tree/11.0/stock_orderpoint_route + :alt: OCA/stock-logistics-warehouse +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-11-0/stock-logistics-warehouse-11-0-stock_orderpoint_route + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/153/11.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to restrict a specific route to be used in the +reordering rules. This route will be used instead of the default determined by +default. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Go to the reordering rule and change the route. Only the routes applicable +for this location or locations above it can be selected. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Eficent + +Contributors +~~~~~~~~~~~~ + +* Jordi Ballester Alomar +* Lois Rilo + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/stock-logistics-warehouse `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_orderpoint_route/__init__.py b/stock_orderpoint_route/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/stock_orderpoint_route/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_orderpoint_route/__manifest__.py b/stock_orderpoint_route/__manifest__.py new file mode 100644 index 000000000..dc18e2937 --- /dev/null +++ b/stock_orderpoint_route/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2019 Eficent Business and IT Consulting Services, S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). +{ + "name": "Stock Orderpoint Route", + "summary": "Allows to force a route to be used when procuring from " + "orderpoints", + "version": "11.0.1.0.0", + "license": "LGPL-3", + "website": "https://github.com/stock-logistics-warehouse", + "author": "Eficent, " + "Odoo Community Association (OCA)", + "category": "Warehouse Management", + "depends": [ + "stock", + ], + "data": [ + "views/stock_warehouse_orderpoint_views.xml", + ], + "installable": True, +} diff --git a/stock_orderpoint_route/models/__init__.py b/stock_orderpoint_route/models/__init__.py new file mode 100644 index 000000000..5024fb8c7 --- /dev/null +++ b/stock_orderpoint_route/models/__init__.py @@ -0,0 +1 @@ +from . import stock_warehouse_orderpoint diff --git a/stock_orderpoint_route/models/stock_warehouse_orderpoint.py b/stock_orderpoint_route/models/stock_warehouse_orderpoint.py new file mode 100644 index 000000000..bbcaaa800 --- /dev/null +++ b/stock_orderpoint_route/models/stock_warehouse_orderpoint.py @@ -0,0 +1,53 @@ +# Copyright 2019 Eficent Business and IT Consulting Services, S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import api, fields, models + + +class StockWarehouseOrderpoint(models.Model): + _inherit = 'stock.warehouse.orderpoint' + + route_ids = fields.Many2many( + 'stock.location.route', string='Allowed routes', + compute='_compute_route_ids', + ) + route_id = fields.Many2one('stock.location.route', string='Route', + domain="[('id', 'in', route_ids)]", + ondelete='restrict') + + @api.depends('product_id', 'warehouse_id', 'location_id') + def _compute_route_ids(self): + route_obj = self.env['stock.location.route'] + for wh in self.mapped('warehouse_id'): + wh_routes = route_obj.search( + [('warehouse_ids', '=', wh.id)]) + for record in self.filtered(lambda r: r.warehouse_id == wh): + routes = route_obj + if record.product_id: + routes += record.product_id.mapped( + 'route_ids' + ) | record.product_id.mapped( + 'categ_id' + ).mapped('total_route_ids') + if record.warehouse_id: + routes |= wh_routes + parents = record.get_parents().ids + record.route_ids = routes.filtered(lambda r: any( + p.location_id.id in parents for p in r.pull_ids)) + + def get_parents(self): + location = self.location_id + result = location + while location.location_id: + location = location.location_id + result |= location + return result + + def _prepare_procurement_values(self, product_qty, date=False, + group=False): + + res = super(StockWarehouseOrderpoint, + self)._prepare_procurement_values(product_qty, date=date, + group=group) + res['route_ids'] = self.route_id + return res diff --git a/stock_orderpoint_route/readme/CONTRIBUTORS.rst b/stock_orderpoint_route/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..daeadd46d --- /dev/null +++ b/stock_orderpoint_route/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Jordi Ballester Alomar +* Lois Rilo diff --git a/stock_orderpoint_route/readme/DESCRIPTION.rst b/stock_orderpoint_route/readme/DESCRIPTION.rst new file mode 100644 index 000000000..b7b4b208b --- /dev/null +++ b/stock_orderpoint_route/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module allows to restrict a specific route to be used in the +reordering rules. This route will be used instead of the default determined by +default. \ No newline at end of file diff --git a/stock_orderpoint_route/readme/USAGE.rst b/stock_orderpoint_route/readme/USAGE.rst new file mode 100644 index 000000000..eb30b124e --- /dev/null +++ b/stock_orderpoint_route/readme/USAGE.rst @@ -0,0 +1,2 @@ +Go to the reordering rule and change the route. Only the routes applicable +for this location or locations above it can be selected. diff --git a/stock_orderpoint_route/static/description/icon.png b/stock_orderpoint_route/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_orderpoint_route/static/description/icon.png differ diff --git a/stock_orderpoint_route/static/description/index.html b/stock_orderpoint_route/static/description/index.html new file mode 100644 index 000000000..69e16318c --- /dev/null +++ b/stock_orderpoint_route/static/description/index.html @@ -0,0 +1,406 @@ + + + + + + +Stock Orderpoint Route + + + +
+

Stock Orderpoint Route

+ + +

Beta License: LGPL-3 OCA/stock-logistics-warehouse Translate me on Weblate Try me on Runbot

+

This module allows to restrict a specific route to be used in the +reordering rules. This route will be used instead of the default determined by +default.

+

Table of contents

+ +
+

Usage

+

Go to the reordering rule and change the route. Only the routes applicable +for this location or locations above it can be selected.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Eficent
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/stock-logistics-warehouse project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/stock_orderpoint_route/tests/__init__.py b/stock_orderpoint_route/tests/__init__.py new file mode 100644 index 000000000..c2355dd9a --- /dev/null +++ b/stock_orderpoint_route/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_orderpoint_route diff --git a/stock_orderpoint_route/tests/test_stock_orderpoint_route.py b/stock_orderpoint_route/tests/test_stock_orderpoint_route.py new file mode 100644 index 000000000..398cd3a65 --- /dev/null +++ b/stock_orderpoint_route/tests/test_stock_orderpoint_route.py @@ -0,0 +1,154 @@ +# Copyright 2017 Eficent Business and IT Consulting Services S.L. +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0). + +from odoo.tests import common + + +class TestStockOrderpointRoute(common.TransactionCase): + def setUp(self): + super(TestStockOrderpointRoute, self).setUp() + + # common models + self.orderpoint_model = self.env[ + 'stock.warehouse.orderpoint'] + self.procurement_group_model = self.env['procurement.group'] + # refs + self.stock_manager_group = \ + self.env.ref('stock.group_stock_manager') + self.stock_multi_locations_group_group = \ + self.env.ref('stock.group_stock_multi_locations') + self.main_company = self.env.ref('base.main_company') + self.warehouse = self.env.ref('stock.warehouse0') + self.categ_unit = self.env.ref('product.product_uom_categ_unit') + self.virtual_loc = self.env.ref('stock.stock_location_customers') + + # common data + self.stock_manager = self._create_user( + 'stock_manager', + [self.stock_manager_group.id, + self.stock_multi_locations_group_group.id], + [self.main_company.id]) + self.product = self._create_product('SH', 'Shoes', False) + + self.ressuply_loc = self.env['stock.location'].create({ + 'name': 'Ressuply', + 'location_id': self.warehouse.view_location_id.id, + }) + + self.ressuply_loc2 = self.env['stock.location'].create({ + 'name': 'Ressuply2', + 'location_id': self.warehouse.view_location_id.id, + }) + + self.route = self.env['stock.location.route'].create({ + 'name': 'Transfer', + 'product_categ_selectable': False, + 'product_selectable': True, + 'company_id': self.main_company.id, + 'sequence': 10, + }) + self.route2 = self.env['stock.location.route'].create({ + 'name': 'Transfer', + 'product_categ_selectable': False, + 'product_selectable': True, + 'company_id': self.main_company.id, + 'sequence': 10, + }) + + self.uom_dozen = self.env['product.uom'].create({ + 'name': 'Test-DozenA', + 'category_id': self.categ_unit.id, + 'factor_inv': 12, + 'uom_type': 'bigger', + 'rounding': 0.001}) + + self.env['procurement.rule'].create({ + 'name': 'Transfer', + 'route_id': self.route.id, + 'location_src_id': self.ressuply_loc.id, + 'location_id': self.warehouse.lot_stock_id.id, + 'action': 'move', + 'picking_type_id': self.warehouse.int_type_id.id, + 'procure_method': 'make_to_stock', + 'warehouse_id': self.warehouse.id, + 'company_id': self.main_company.id, + 'propagate': 'False', + }) + + self.env['procurement.rule'].create({ + 'name': 'Transfer 2', + 'route_id': self.route2.id, + 'location_src_id': self.ressuply_loc2.id, + 'location_id': self.warehouse.lot_stock_id.id, + 'action': 'move', + 'picking_type_id': self.warehouse.int_type_id.id, + 'procure_method': 'make_to_stock', + 'warehouse_id': self.warehouse.id, + 'company_id': self.main_company.id, + 'propagate': 'False', + }) + + def _create_user(self, name, group_ids, company_ids): + return self.env['res.users'].with_context( + {'no_reset_password': True}).create( + {'name': name, + 'password': 'demo', + 'login': name, + 'email': '@'.join([name, '@test.com']), + 'groups_id': [(6, 0, group_ids)], + 'company_ids': [(6, 0, company_ids)] + }) + + def _create_product(self, default_code, name, company_id, **vals): + return self.env['product.product'].create(dict( + name=name, + default_code=default_code, + uom_id=self.env.ref('product.product_uom_unit').id, + company_id=company_id, + type='product', + **vals + )) + + def test_orderpoint_route_01(self): + self.product.route_ids = [(6, 0, [self.route.id, self.route2.id])] + vals = { + 'product_id': self.product.id, + 'product_min_qty': 10.0, + 'product_max_qty': 100.0, + 'company_id': self.main_company.id, + 'warehouse_id': self.warehouse.id, + 'location_id': self.warehouse.lot_stock_id.id, + } + + orderpoint = self.orderpoint_model.sudo( + self.stock_manager).create(vals) + self.assertIn(self.route, orderpoint.route_ids) + self.assertIn(self.route2, orderpoint.route_ids) + orderpoint.route_id = self.route.id + self.procurement_group_model.run_scheduler() + move = self.env['stock.move'].search( + [('product_id', '=', self.product.id), + ('location_id', '=', self.ressuply_loc.id)], limit=1) + self.assertEqual(len(move), 1) + + def test_orderpoint_route_02(self): + self.product.route_ids = [(6, 0, [self.route.id, self.route2.id])] + vals = { + 'product_id': self.product.id, + 'product_min_qty': 10.0, + 'product_max_qty': 100.0, + 'company_id': self.main_company.id, + 'warehouse_id': self.warehouse.id, + 'location_id': self.warehouse.lot_stock_id.id, + } + + orderpoint = self.orderpoint_model.sudo( + self.stock_manager).create(vals) + self.assertIn(self.route, orderpoint.route_ids) + self.assertIn(self.route2, orderpoint.route_ids) + orderpoint.route_id = self.route2.id + self.procurement_group_model.run_scheduler() + move = self.env['stock.move'].search( + [('product_id', '=', self.product.id), + ('location_id', '=', self.ressuply_loc2.id)], limit=1) + self.assertEqual(len(move), 1) diff --git a/stock_orderpoint_route/views/stock_warehouse_orderpoint_views.xml b/stock_orderpoint_route/views/stock_warehouse_orderpoint_views.xml new file mode 100644 index 000000000..565c421d7 --- /dev/null +++ b/stock_orderpoint_route/views/stock_warehouse_orderpoint_views.xml @@ -0,0 +1,19 @@ + + + + + + stock.warehouse.orderpoint.form + stock.warehouse.orderpoint + + + + + + + + + +