Skip to content

Commit

Permalink
[ADD] sale_order_rental_stock_forecast: Scheluded for generate "produ…
Browse files Browse the repository at this point in the history
…ct st ock forecast", modified to search the biggest "expected end date" of the sales orders.
  • Loading branch information
alfredoavanzosc committed Mar 12, 2020
1 parent ebe6f0b commit 0fcd9e3
Show file tree
Hide file tree
Showing 8 changed files with 211 additions and 0 deletions.
29 changes: 29 additions & 0 deletions sale_order_rental_stock_forecast/README.rst
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.
1 change: 1 addition & 0 deletions sale_order_rental_stock_forecast/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
18 changes: 18 additions & 0 deletions sale_order_rental_stock_forecast/__manifest__.py
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
}
2 changes: 2 additions & 0 deletions sale_order_rental_stock_forecast/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import product_product_stock_forecast
from . import sale_order
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
18 changes: 18 additions & 0 deletions sale_order_rental_stock_forecast/models/sale_order.py
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
1 change: 1 addition & 0 deletions sale_order_rental_stock_forecast/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_sale_order_rental_stock_forecast
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)

0 comments on commit 0fcd9e3

Please sign in to comment.