-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD] sale_order_rental_stock_forecast: Scheluded for generate "produ…
…ct st ock forecast", modified to search the biggest "expected end date" of the sales orders.
- Loading branch information
1 parent
ebe6f0b
commit 0fcd9e3
Showing
8 changed files
with
211 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
|
||
================================= | ||
Sale order rental stock forecast | ||
================================= | ||
|
||
* Scheluded for generate "product st ock forecast", modified to search | ||
the biggest "expected end date" of the sales orders. | ||
|
||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues | ||
<https://github.com/avanzosc/sale-addons/issues>`_. In case of trouble, please | ||
check there if your issue has already been reported. If you spotted it first, | ||
help us smash it by providing detailed and welcomed feedback. | ||
|
||
Credits | ||
======= | ||
|
||
Contributors | ||
------------ | ||
* Ana Juaristi <[email protected]> | ||
* Alfredo de la Fuente <[email protected]> | ||
|
||
Do not contact contributors directly about support or help with technical issues. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Copyright 2019 Alfredo de la Fuente - AvanzOSC | ||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html | ||
{ | ||
"name": "Sale Order Rental Stock Forecast", | ||
"version": "12.0.1.0.0", | ||
"license": "AGPL-3", | ||
"depends": [ | ||
"sale_order_rental", | ||
"stock_forecast", | ||
], | ||
"author": "AvanzOSC", | ||
"website": "http://www.avanzosc.es", | ||
"category": "Warehouse", | ||
"data": [ | ||
], | ||
"installable": True, | ||
'auto_install': True | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import product_product_stock_forecast | ||
from . import sale_order |
19 changes: 19 additions & 0 deletions
19
sale_order_rental_stock_forecast/models/product_product_stock_forecast.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# Copyright 2019 Alfredo de la Fuente - AvanzOSC | ||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html | ||
from odoo import models | ||
|
||
|
||
class ProductProductStockForecast(models.Model): | ||
_inherit = 'product.product.stock.forecast' | ||
|
||
def _catch_max_fec_for_calc_qty_per_day(self, moves): | ||
date_expected = super( | ||
ProductProductStockForecast, | ||
self)._catch_max_fec_for_calc_qty_per_day(moves) | ||
cond = [('expected_end_date', '!=', False)] | ||
sales = self.env['sale.order'].search(cond) | ||
if sales: | ||
sale = max(sales, key=lambda x: x.expected_end_date) | ||
if sale.expected_end_date > date_expected: | ||
return sale.expected_end_date | ||
return date_expected |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Copyright 2019 Alfredo de la Fuente - AvanzOSC | ||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html | ||
from odoo import models | ||
|
||
|
||
class SaleOrder(models.Model): | ||
_inherit = 'sale.order' | ||
|
||
def action_view_products_stock_forecast_from_sale(self): | ||
res = super( | ||
SaleOrder, self).action_view_products_stock_forecast_from_sale() | ||
if (self.expected_delivery_date and self.expected_end_date and | ||
res.get('domain', False)): | ||
cond = [('product_id', 'in', self.sale_product_ids.ids), | ||
('date', '>=', self.expected_delivery_date), | ||
('date', '<=', self.expected_end_date)] | ||
res['domain'] = cond | ||
return res |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import test_sale_order_rental_stock_forecast |
123 changes: 123 additions & 0 deletions
123
sale_order_rental_stock_forecast/tests/test_sale_order_rental_stock_forecast.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
# -*- coding: utf-8 -*- | ||
# (c) 2016 Alfredo de la Fuente - AvanzOSC | ||
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html | ||
from odoo.tests.common import TransactionCase | ||
from openerp import fields | ||
from dateutil.relativedelta import relativedelta | ||
|
||
|
||
class TestSaleOrderRentalStockForecast(TransactionCase): | ||
|
||
def setUp(self): | ||
super(TestSaleOrderRentalStockForecast, self).setUp() | ||
self.forecast_obj = self.env['product.product.stock.forecast'] | ||
wiz_obj = self.env['stock.immediate.transfer'] | ||
location_obj = self.env['stock.location'] | ||
partner_obj = self.env['res.partner'] | ||
picking_obj = self.env['stock.picking'] | ||
cond = [('code', '=', 'incoming')] | ||
self.in_picking_type = self.env['stock.picking.type'].search( | ||
cond, limit=1) | ||
self.location_supplier = location_obj.search( | ||
[('usage', '=', 'supplier')], limit=1) | ||
self.location_customer = location_obj.search( | ||
[('usage', '=', 'customer')], limit=1) | ||
cond = [('code', '=', 'outgoing')] | ||
self.out_picking_type = self.env['stock.picking.type'].search( | ||
cond, limit=1) | ||
cond = [('supplier', '=', True)] | ||
self.supplier = partner_obj.search(cond, limit=1) | ||
cond = [('customer', '=', True)] | ||
self.customer = partner_obj.search(cond, limit=1) | ||
vals = {'name': 'Product for TestSaleOrderRentalStockForecast', | ||
'type': 'product'} | ||
self.product = self.env['product.product'].create(vals) | ||
picking_vals = { | ||
'partner_id': self.supplier.id, | ||
'picking_type_id': self.in_picking_type.id, | ||
'location_id': self.location_supplier.id, | ||
'location_dest_id': | ||
self.in_picking_type.default_location_dest_id.id} | ||
picking_line_vals = { | ||
'product_id': self.product.id, | ||
'name': self.product.name, | ||
'product_uom_qty': 20, | ||
'product_uom': self.product.uom_id.id} | ||
picking_vals['move_lines'] = [(0, 0, picking_line_vals)] | ||
self.picking = picking_obj.create(picking_vals) | ||
self.picking.action_confirm() | ||
wizard_vals = {'pick_ids': [(6, 0, self.picking.ids)]} | ||
wizard = wiz_obj.create(wizard_vals) | ||
wizard.process() | ||
date_expected = (fields.Datetime.from_string( | ||
self.picking.move_lines[0].date_expected) - relativedelta(years=1)) | ||
date_expected_without_hour = (fields.Datetime.from_string( | ||
self.picking.move_lines[0].date_expected_without_hour) - | ||
relativedelta(years=1)) | ||
self.picking.move_lines[0].write( | ||
{'date_expected': date_expected, | ||
'date_expected_without_hour': date_expected_without_hour}) | ||
self.picking2 = self.picking.copy() | ||
self.picking2.move_lines[0].product_uom_qty = 5 | ||
self.picking2.action_confirm() | ||
wizard_vals = {'pick_ids': [(6, 0, self.picking2.ids)]} | ||
wizard = wiz_obj.create(wizard_vals) | ||
wizard.process() | ||
date_expected = (fields.Datetime.from_string( | ||
self.picking2.move_lines[0].date_expected) + | ||
relativedelta(years=1)) | ||
date_expected_without_hour = (fields.Datetime.from_string( | ||
self.picking2.move_lines[0].date_expected_without_hour) + | ||
relativedelta(years=1)) | ||
self.picking2.move_lines[0].write( | ||
{'date_expected': date_expected, | ||
'date_expected_without_hour': date_expected_without_hour}) | ||
picking_vals = { | ||
'partner_id': self.customer.id, | ||
'picking_type_id': self.out_picking_type.id, | ||
'location_id': self.out_picking_type.default_location_src_id.id, | ||
'location_dest_id': self.location_customer.id} | ||
picking_line_vals = { | ||
'product_id': self.product.id, | ||
'name': self.product.name, | ||
'product_uom_qty': 2, | ||
'product_uom': self.product.uom_id.id} | ||
picking_vals['move_lines'] = [(0, 0, picking_line_vals)] | ||
self.out_picking = picking_obj.create(picking_vals) | ||
self.out_picking.action_confirm() | ||
self.out_picking.move_lines[0].write( | ||
{'date_expected': self.picking2.move_lines[0].date_expected, | ||
'date_expected_without_hour': | ||
self.picking2.move_lines[0].date_expected_without_hour}) | ||
self.today = fields.Date.from_string(fields.Date.today()) | ||
self.today_10 = (self.today + relativedelta(days=10)) | ||
sale_vals = { | ||
'partner_id': self.customer.id, | ||
'expected_delivery_date': self.today, | ||
'expected_end_date': self.today_10} | ||
sale_line_vals = { | ||
'product_id': self.product.id, | ||
'name': self.product.name, | ||
'originator_id': 1, | ||
'product_uom': self.product.uom_id.id, | ||
'price_unit': 25.0} | ||
sale_vals['order_line'] = [(0, 0, sale_line_vals)] | ||
self.sale = self.env['sale.order'].create(sale_vals) | ||
|
||
def test_sale_order_rental_stock_forecast(self): | ||
domain = [('product_id', 'in', [self.product.id]), | ||
('date', '>=', self.today), | ||
('date', '<=', self.today_10)] | ||
res = self.sale.action_view_products_stock_forecast_from_sale() | ||
self.assertEqual(res.get('domain'), domain) | ||
cond = [('product_id', '=', self.product.id)] | ||
forecasts = self.forecast_obj.search(cond) | ||
forecasts = forecasts.filtered( | ||
lambda c: c.qty_available != 0 or c.incoming_qty != 0 or | ||
c.outgoing_qty != 0 or c.virtual_available != 0) | ||
maxforecast = max(forecasts, key=lambda x: x.date) | ||
self.assertEqual(maxforecast.date, self.today_10) | ||
self.assertEqual(maxforecast.qty_available, 25.0) | ||
self.assertEqual(maxforecast.incoming_qty, 0.0) | ||
self.assertEqual(maxforecast.outgoing_qty, 2.0) | ||
self.assertEqual(maxforecast.virtual_available, 23.0) |