mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
Merge branch 'mig/15.0/sale_planner_delivery_route' into '15.0'
mig/15.0/sale_planner_delivery_route into 15.0 See merge request hibou-io/hibou-odoo/suite!1148
This commit is contained in:
15
sale_planner_delivery_route/README.rst
Normal file
15
sale_planner_delivery_route/README.rst
Normal file
@@ -0,0 +1,15 @@
|
||||
**************************************************
|
||||
Hibou - Sale Planner with Warehouse Delivery Route
|
||||
**************************************************
|
||||
|
||||
Calculates the closest delivery route during order planning.
|
||||
|
||||
For more information and add-ons, visit `Hibou.io <https://hibou.io/>`_.
|
||||
|
||||
|
||||
=======
|
||||
License
|
||||
=======
|
||||
|
||||
Please see `LICENSE <https://github.com/hibou-io/hibou-odoo-suite/blob/master/LICENSE>`_.
|
||||
Copyright Hibou Corp. 2018
|
||||
2
sale_planner_delivery_route/__init__.py
Normal file
2
sale_planner_delivery_route/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import wizard
|
||||
from . import models
|
||||
29
sale_planner_delivery_route/__manifest__.py
Normal file
29
sale_planner_delivery_route/__manifest__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
'name': 'Sale Order Planner - Delivery Route',
|
||||
'summary': 'Plans to the closest delivery route.',
|
||||
'version': '15.0.1.0.0',
|
||||
'author': "Hibou Corp.",
|
||||
'category': 'Sale',
|
||||
'license': 'LGPL-3',
|
||||
'complexity': 'expert',
|
||||
'images': [],
|
||||
'website': "https://hibou.io",
|
||||
'description': """
|
||||
Sale Order Planner - Delivery Route
|
||||
===================================
|
||||
|
||||
Plans to the closest delivery route.
|
||||
|
||||
""",
|
||||
'depends': [
|
||||
'stock_delivery_route',
|
||||
'sale_planner',
|
||||
],
|
||||
'demo': [],
|
||||
'data': [
|
||||
'wizard/order_planner_views.xml',
|
||||
'views/stock_views.xml',
|
||||
],
|
||||
'auto_install': True,
|
||||
'installable': True,
|
||||
}
|
||||
1
sale_planner_delivery_route/models/__init__.py
Normal file
1
sale_planner_delivery_route/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import stock
|
||||
8
sale_planner_delivery_route/models/stock.py
Normal file
8
sale_planner_delivery_route/models/stock.py
Normal file
@@ -0,0 +1,8 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class DeliveryRoute(models.Model):
|
||||
_inherit = 'stock.warehouse.delivery.route'
|
||||
|
||||
latitude = fields.Float(string='Latitude', digits=(12, 6))
|
||||
longitude = fields.Float(string='Longitude', digits=(12, 6))
|
||||
1
sale_planner_delivery_route/tests/__init__.py
Normal file
1
sale_planner_delivery_route/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import test_planner
|
||||
34
sale_planner_delivery_route/tests/test_planner.py
Normal file
34
sale_planner_delivery_route/tests/test_planner.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from odoo.addons.sale_planner.tests.test_planner import TestPlanner
|
||||
|
||||
|
||||
class TestPlannerRoute(TestPlanner):
|
||||
def setUp(self):
|
||||
super(TestPlannerRoute, self).setUp()
|
||||
self.route_near = self.env['stock.warehouse.delivery.route'].create({
|
||||
'name': 'Route 1',
|
||||
'warehouse_id': self.warehouse_1.id,
|
||||
'latitude': 48.02995,
|
||||
'longitude': -122.14771,
|
||||
})
|
||||
self.route_far = self.env['stock.warehouse.delivery.route'].create({
|
||||
'name': 'Route Far',
|
||||
'warehouse_id': self.warehouse_1.id,
|
||||
'latitude': 47.82093,
|
||||
'longitude': -122.31513,
|
||||
})
|
||||
|
||||
def test_planner_creation(self):
|
||||
self.env['sale.order.line'].create({
|
||||
'order_id': self.so.id,
|
||||
'product_id': self.product_1.id,
|
||||
'name': 'demo',
|
||||
})
|
||||
both_wh_ids = self.both_wh_ids()
|
||||
planner = self.env['sale.order.make.plan'].with_context(warehouse_domain=[('id', 'in', both_wh_ids)],
|
||||
skip_plan_shipping=True).create({'order_id': self.so.id})
|
||||
self.assertTrue(planner.planning_option_ids, 'Must have one or more plans.')
|
||||
self.assertEqual(planner.planning_option_ids.delivery_route_id, self.route_near)
|
||||
self.so.partner_id.partner_latitude = 47.82093
|
||||
planner = self.env['sale.order.make.plan'].with_context(warehouse_domain=[('id', 'in', both_wh_ids)],
|
||||
skip_plan_shipping=True).create({'order_id': self.so.id})
|
||||
self.assertEqual(planner.planning_option_ids.delivery_route_id, self.route_far)
|
||||
18
sale_planner_delivery_route/views/stock_views.xml
Normal file
18
sale_planner_delivery_route/views/stock_views.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="view_warehouse_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.warehouse.inherit</field>
|
||||
<field name="model">stock.warehouse</field>
|
||||
<field name="inherit_id" ref="stock_delivery_route.view_warehouse_inherit" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='delivery_route_ids']/tree" position="inside">
|
||||
<field name="latitude"/>
|
||||
<field name="longitude"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='delivery_route_ids']/form//field[@name='warehouse_id']" position="after">
|
||||
<field name="latitude"/>
|
||||
<field name="longitude"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
1
sale_planner_delivery_route/wizard/__init__.py
Normal file
1
sale_planner_delivery_route/wizard/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import order_planner
|
||||
38
sale_planner_delivery_route/wizard/order_planner.py
Normal file
38
sale_planner_delivery_route/wizard/order_planner.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from odoo import api, fields, models
|
||||
from odoo.addons.sale_planner.wizard.order_planner import distance
|
||||
|
||||
|
||||
class SaleOrderMakePlan(models.TransientModel):
|
||||
_inherit = 'sale.order.make.plan'
|
||||
|
||||
def generate_base_option(self, order_fake):
|
||||
option = super(SaleOrderMakePlan, self).generate_base_option(order_fake)
|
||||
option['delivery_route_id'] = self.find_closest_route(option, order_fake)
|
||||
return option
|
||||
|
||||
def find_closest_route(self, option, order_fake):
|
||||
warehouse = self.env['stock.warehouse'].browse(option['warehouse_id'])
|
||||
if warehouse.delivery_route_ids:
|
||||
partner = order_fake.partner_shipping_id
|
||||
if not partner.date_localization:
|
||||
partner.geo_localize()
|
||||
return self._find_closest_route_id(warehouse.delivery_route_ids,
|
||||
partner.partner_latitude,
|
||||
partner.partner_longitude)
|
||||
return False
|
||||
|
||||
def _find_closest_route_id(self, routes, latitude, longitude):
|
||||
distances = {distance(latitude, longitude, route.latitude, route.longitude): route.id for route in routes}
|
||||
route_id = distances[min(distances)]
|
||||
return route_id
|
||||
|
||||
def _order_fields_for_option(self, option):
|
||||
vals = super(SaleOrderMakePlan, self)._order_fields_for_option(option)
|
||||
vals['delivery_route_id'] = option.delivery_route_id.id
|
||||
return vals
|
||||
|
||||
|
||||
class SaleOrderPlanningOption(models.TransientModel):
|
||||
_inherit = 'sale.order.planning.option'
|
||||
|
||||
delivery_route_id = fields.Many2one('stock.warehouse.delivery.route', string='Delivery Route')
|
||||
13
sale_planner_delivery_route/wizard/order_planner_views.xml
Normal file
13
sale_planner_delivery_route/wizard/order_planner_views.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="view_plan_sale_order_inherit" model="ir.ui.view">
|
||||
<field name="name">view.plan.sale.order.inherit</field>
|
||||
<field name="model">sale.order.make.plan</field>
|
||||
<field name="inherit_id" ref="sale_planner.view_plan_sale_order"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='warehouse_id']" position="after">
|
||||
<field name="delivery_route_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user