Skip to content

Commit

Permalink
Merge pull request #56 from nbessi/routes_in_so_line
Browse files Browse the repository at this point in the history
Add automatic relation of SO line and logisitc route based on sourced_by...
  • Loading branch information
jgrandguillaume committed Nov 12, 2014
2 parents 49a9181 + 51361dd commit 2f56ed3
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 23 deletions.
19 changes: 12 additions & 7 deletions sale_quotation_sourcing/__openerp__.py
Expand Up @@ -40,11 +40,16 @@
and the manually sourced one.
The drop shipping case is handled as well, with a warning to check if the
destination locations of the procurement and the sourced PO are
consistent. Since the stock_dropshipping module contains little more than
preconfigured Routes, Rules, and Picking Types, we do not depend
on it but we are fully compatible. The Routes and Rules are recreated in
the tests in order to avoid requiring stock_dropshipping in production.
destination locations of the procurement and the sourced PO are consistent.
In addition to that, when the user sources a sale line with a purchase
line, the system tries to choose automatically an appropriate route (MTO or
drophipping).
This on_change method is the only place where the module stock_dropshipping
is used, otherwise it contains little more than preconfigured Routes,
Rules, and Picking Types. All other code and the tests do not use it. That
dependency can be easily removed later if it is needed to manually
configure dropshipping and MTO routes.
Note: the package nose is required to run the tests. It is not noted in the
external dependencies since it is not required in production.
Expand All @@ -55,9 +60,9 @@
'website': "http://www.camptocamp.com",

'category': 'Sales',
'version': '0.1',
'version': '0.2',

'depends': ['sale_stock', 'purchase'],
'depends': ['sale_stock', 'purchase', 'stock_dropshipping'],
'data': ['views/sale_order_sourcing.xml',
'views/sale_order.xml',
'security/group.xml',
Expand Down
66 changes: 66 additions & 0 deletions sale_quotation_sourcing/model/sale_order.py
Expand Up @@ -73,3 +73,69 @@ class SaleOrderLine(models.Model):
def needs_sourcing(self):
return any(line.manually_sourced and not line.sourced_by
for line in self)

@api.model
def _get_po_location_usage(self, purchase_order_line):
"""Retrieve the destination location usage of a PO
from a PO line
:param purchase_order_line: record of `purchase.order.line` Model
:type purchase_order_line: :py:class:`openerp.models.Model`
:return: PO location usage
:rtype: str
"""
return purchase_order_line.order_id.location_id.usage

@api.model
def _find_route_from_usage(self, usage):
"""Return the routes to assing on SO lines
based on a location usage.
If no match return None.
At the moment this method returns the standard dropshipping and MTO
routes. This method will work in many cases, but we could improve it to
find dropshipping-like and MTO-like routes that have been configured
afterwards.
See onchange_dest_address_in in the module purchase_delivery_address
for a similar situation.
:param usage: stock.location Model usage
:type usage: str
:return: a record of `stock.location.route`
:rtype: :py:class:`openerp.models.Model` or None
"""
if usage == 'customer':
return self.env.ref('stock_dropshipping.route_drop_shipping')
elif usage == 'internal':
return self.env.ref('stock.route_warehouse0_mto')
else:
return None

@api.one
@api.onchange('sourced_by')
@api.constrains('sourced_by')
def set_route_form_so(self):
"""Set route on SO line based on fields sourced_by.
Wee look for the PO related
to current SO line by the sourced_by fields.
If the PO has a destination location with usage
"customer" we apply the dropshipping route to current SO line.
If the PO has a destination location with usage
"internal" we apply the make to order route to current SO line.
As there is no trigger decorator that works on
non computed fields we use constrains decorator instead.
"""
if not self.sourced_by:
return
usage = self._get_po_location_usage(self.sourced_by)
route = self._find_route_from_usage(usage)
if route:
self.route_id = route
30 changes: 14 additions & 16 deletions sale_quotation_sourcing/test/test_manual_sourcing_dropshipping.yml
@@ -1,19 +1,13 @@
-
I select for this file a user that is not admin
Feature. Manual sourcing of a dropshipping sale
Scenario. Check consistency between a dropshipping sale and a purchase with destination Stock
-
Background. I log in as Fiona
-
!context
uid: 'res_users_fiona'
-
I create a RFQ. I do not configure the destination location, so it will be
Stock.
-
!record {model: purchase.order, id: po_5}:
partner_id: base.res_partner_6
order_line:
- product_id: product.product_product_7
product_qty: 8
-
I create a quotation with a manually sourced dropshipping line.
Given I have a Sale with dropshipping route
-
!record {model: sale.order, id: so_5}:
partner_id: base.res_partner_3
Expand All @@ -23,16 +17,20 @@
manually_sourced: 1
route_id: route_drop_shipping
-
I source it directly in the sale order line.
When I source it with a purchase with destination Stock
-
!record {model: purchase.order, id: po_5}:
partner_id: base.res_partner_6
order_line:
- product_id: product.product_product_7
product_qty: 8
-
!python {model: sale.order, id: so_5}: |
po = self.env['purchase.order'].browse(ref('po_5'))
self.order_line[0].sourced_by = po.order_line[0]
-
I confirm the sale order and I should be blocked.
Then the sale should have a route with origin Stock
-
!python {model: sale.order, id: so_5}: |
from nose.tools import *
from openerp.exceptions import Warning
with assert_raises(Warning):
self.action_button_confirm()
assert_equal('internal', self.order_line[0].route_id.pull_ids[0].location_src_id.usage)
21 changes: 21 additions & 0 deletions sale_quotation_sourcing/tests/__init__.py
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_sourced_by
49 changes: 49 additions & 0 deletions sale_quotation_sourcing/tests/test_sourced_by.py
@@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Nicolas Bessi
# Copyright 2014 Camptocamp SA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import openerp.tests.common as test_common


class TestSourcedBy(test_common.TransactionCase):

def test_get_route_from_usage(self):
so_line_model = self.env['sale.order.line']
ds_route = self.env.ref('stock_dropshipping.route_drop_shipping')
mto_route = self.env.ref('stock.route_warehouse0_mto')
self.assertTrue(ds_route)
self.assertTrue(mto_route)
self.assertEqual(
so_line_model._find_route_from_usage('customer'),
ds_route
)
self.assertEquals(
so_line_model._find_route_from_usage('internal'),
mto_route
)
self.assertEquals(
so_line_model._find_route_from_usage('supplier'),
None
)

def test_get_po_usage(self):
so_line_model = self.env['sale.order.line']
po_line = self.env.ref('purchase.purchase_order_2').order_line[0]
usage = so_line_model._get_po_location_usage(po_line)
self.assertEqual(usage, 'internal')

0 comments on commit 2f56ed3

Please sign in to comment.