diff --git a/stock_delivery_route/README.rst b/stock_delivery_route/README.rst new file mode 100644 index 00000000..77695d27 --- /dev/null +++ b/stock_delivery_route/README.rst @@ -0,0 +1,18 @@ +******************************** +Hibou - Warehouse Delivery Route +******************************** + +Define delivery routes per warehouse. Pick the delivery route on the sale order or delivery order. + +Optionally define warehouse routes on the Customer or Customer's Delivery address to pre-select +the delivery route. + +For more information and add-ons, visit `Hibou.io `_. + + +======= +License +======= + +Please see `LICENSE `_. +Copyright Hibou Corp. 2018 \ No newline at end of file diff --git a/stock_delivery_route/__init__.py b/stock_delivery_route/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/stock_delivery_route/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_delivery_route/__manifest__.py b/stock_delivery_route/__manifest__.py new file mode 100644 index 00000000..4ae65bc2 --- /dev/null +++ b/stock_delivery_route/__manifest__.py @@ -0,0 +1,32 @@ +{ + 'name': 'Warehouse Delivery Routes', + 'summary': 'Assign a delivery route to a sale order or picking.', + 'version': '15.0.1.0.0', + 'author': "Hibou Corp. ", + 'category': 'Warehouse', + 'license': 'LGPL-3', + 'complexity': 'expert', + 'images': [], + 'website': "https://hibou.io", + 'description': """ +Warehouse Delivery Routes +========================= + +Assign a delivery route at the time of sale order. +Additionally, set a default route on the customer level. + +""", + 'depends': [ + 'sale_stock', + 'stock_picking_batch', + ], + 'demo': [], + 'data': [ + 'views/partner_views.xml', + 'views/sale_views.xml', + 'views/stock_views.xml', + 'security/ir.model.access.csv', + ], + 'auto_install': False, + 'installable': True, +} diff --git a/stock_delivery_route/models/__init__.py b/stock_delivery_route/models/__init__.py new file mode 100644 index 00000000..920b3030 --- /dev/null +++ b/stock_delivery_route/models/__init__.py @@ -0,0 +1,3 @@ +from . import stock +from . import partner +from . import sale diff --git a/stock_delivery_route/models/partner.py b/stock_delivery_route/models/partner.py new file mode 100644 index 00000000..57a26abc --- /dev/null +++ b/stock_delivery_route/models/partner.py @@ -0,0 +1,7 @@ +from odoo import fields, models + + +class Partner(models.Model): + _inherit = 'res.partner' + + delivery_route_ids = fields.Many2many('stock.warehouse.delivery.route', string="Delivery Routes") diff --git a/stock_delivery_route/models/sale.py b/stock_delivery_route/models/sale.py new file mode 100644 index 00000000..f9fd0d6d --- /dev/null +++ b/stock_delivery_route/models/sale.py @@ -0,0 +1,30 @@ +from odoo import api, fields, models + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + + delivery_route_id = fields.Many2one('stock.warehouse.delivery.route', string='Delivery Route') + + @api.onchange('partner_id', 'partner_shipping_id', 'warehouse_id') + def _prefill_delivery_route(self): + for so in self: + if so.warehouse_id: + for route in so.partner_shipping_id.delivery_route_ids.filtered(lambda d: d.warehouse_id == so.warehouse_id): + so.delivery_route_id = route + break + else: + for route in so.partner_id.delivery_route_ids.filtered(lambda d: d.warehouse_id == so.warehouse_id): + so.delivery_route_id = route + break + else: + so.delivery_route_id = False + else: + so.delivery_route_id = False + + def action_confirm(self): + val = super(SaleOrder, self).action_confirm() + for so in self: + if so.delivery_route_id and so.picking_ids: + so.picking_ids.write({'delivery_route_id': so.delivery_route_id.id}) + return val diff --git a/stock_delivery_route/models/stock.py b/stock_delivery_route/models/stock.py new file mode 100644 index 00000000..e3fedf9f --- /dev/null +++ b/stock_delivery_route/models/stock.py @@ -0,0 +1,41 @@ +from odoo import api, fields, models + + +class Warehouse(models.Model): + _inherit = 'stock.warehouse' + + delivery_route_ids = fields.One2many('stock.warehouse.delivery.route', 'warehouse_id', string='Delivery Routes') + + +class Picking(models.Model): + _inherit = 'stock.picking' + _order = 'sequence asc, priority desc, date asc, id desc' + + sequence = fields.Integer(string='Sequence') + warehouse_id = fields.Many2one('stock.warehouse', related='picking_type_id.warehouse_id') + delivery_route_id = fields.Many2one('stock.warehouse.delivery.route', string='Delivery Route') + partner_address = fields.Char(string='Address', compute='_compute_partner_address') + + def _compute_partner_address(self): + for pick in self: + if pick.partner_id: + pick.partner_address = '%s: %s, %s' % (pick.partner_id.name or '', pick.partner_id.street or '', pick.partner_id.city or '') + else: + pick.partner_address = '' + + +class WarehouseDeliveryRoute(models.Model): + _name = 'stock.warehouse.delivery.route' + + name = fields.Char(string='Name') + warehouse_id = fields.Many2one('stock.warehouse', string='Warehouse') + note = fields.Text(string='Note') + + def name_get(self): + res = [] + for route in self: + res.append((route.id, '[%s] %s' % (route.warehouse_id.code, route.name))) + return res + + + diff --git a/stock_delivery_route/security/ir.model.access.csv b/stock_delivery_route/security/ir.model.access.csv new file mode 100644 index 00000000..e30455da --- /dev/null +++ b/stock_delivery_route/security/ir.model.access.csv @@ -0,0 +1,2 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +"user_stock_warehouse_delivery_route","user stock_warehouse_delivery_route","model_stock_warehouse_delivery_route","base.group_user",1,1,1,1 \ No newline at end of file diff --git a/stock_delivery_route/tests/__init__.py b/stock_delivery_route/tests/__init__.py new file mode 100644 index 00000000..91e10996 --- /dev/null +++ b/stock_delivery_route/tests/__init__.py @@ -0,0 +1 @@ +from . import test_sale_routes diff --git a/stock_delivery_route/tests/test_sale_routes.py b/stock_delivery_route/tests/test_sale_routes.py new file mode 100644 index 00000000..a06c6057 --- /dev/null +++ b/stock_delivery_route/tests/test_sale_routes.py @@ -0,0 +1,22 @@ +from odoo.tests import common + + +class TestSaleRoutes(common.TransactionCase): + + def test_plan_two_warehouses(self): + partner = self.env.ref('base.res_partner_2') + product_1 = self.env.ref('product.product_product_24_product_template') + wh_1 = self.env.ref('stock.warehouse0') + delivery_route = self.env['stock.warehouse.delivery.route'].create({ + 'name': 'Test', + 'warehouse_id': wh_1.id, + }) + so = self.env['sale.order'].create({ + 'warehouse_id': wh_1.id, + 'partner_id': partner.id, + 'order_line': [(0, 0, {'product_id': product_1.product_variant_id.id})], + 'delivery_route_id': delivery_route.id, + }) + so.action_confirm() + self.assertTrue(so.state in ('sale', 'done')) + self.assertEqual(so.picking_ids[0].delivery_route_id, delivery_route) diff --git a/stock_delivery_route/views/partner_views.xml b/stock_delivery_route/views/partner_views.xml new file mode 100644 index 00000000..2583db73 --- /dev/null +++ b/stock_delivery_route/views/partner_views.xml @@ -0,0 +1,17 @@ + + + + res.partner.form.inherit + res.partner + + + + + + + + + + + + \ No newline at end of file diff --git a/stock_delivery_route/views/sale_views.xml b/stock_delivery_route/views/sale_views.xml new file mode 100644 index 00000000..3fa4d46d --- /dev/null +++ b/stock_delivery_route/views/sale_views.xml @@ -0,0 +1,13 @@ + + + + sale.order.form.sale.stock.inherit + sale.order + + + + + + + + \ No newline at end of file diff --git a/stock_delivery_route/views/stock_views.xml b/stock_delivery_route/views/stock_views.xml new file mode 100644 index 00000000..cd8aa8d1 --- /dev/null +++ b/stock_delivery_route/views/stock_views.xml @@ -0,0 +1,87 @@ + + + + + stock.warehouse.inherit + stock.warehouse + + + + + + + + + + +
+ + + + + + + + + +
+
+
+
+
+
+
+ + + + stock.picking.internal.search.inherit + stock.picking + + + + + + + + + + + + stock.picking.tree.search.inherit + stock.picking + + + + + + + + + + + + stock.picking.form.inherit + stock.picking + + + + + + + + + + + + stock_picking_batch.picking.tree.batch.inherit + stock.picking + + + + + + + + + +
\ No newline at end of file