mirror of
https://github.com/OCA/manufacture.git
synced 2025-01-28 16:37:15 +02:00
[FIX] mrp_multi_level: Consider timezone of the warehouse to generate mrp inventory records.
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.addons.base.res.res_partner import _tz_get
|
||||
|
||||
|
||||
class MrpArea(models.Model):
|
||||
@@ -30,6 +31,24 @@ class MrpArea(models.Model):
|
||||
string='Working Hours',
|
||||
related='warehouse_id.calendar_id',
|
||||
)
|
||||
tz = fields.Selection(
|
||||
_tz_get, string='Timezone', required=True,
|
||||
default=lambda self: self._context.get(
|
||||
'tz') or self.env.user.tz or 'UTC',
|
||||
help="This field is used in order to define in which timezone "
|
||||
"the MRP Area will work.")
|
||||
|
||||
@api.model
|
||||
def _datetime_to_date_tz(self, dt_to_convert=None):
|
||||
"""Coverts a datetime to date considering the timezone
|
||||
of MRP Area. If no datetime is provided, it returns today's
|
||||
date in the timezone."""
|
||||
if isinstance(dt_to_convert, str):
|
||||
dt_to_convert = fields.Datetime.from_string(dt_to_convert)
|
||||
return fields.Date.context_today(
|
||||
self.with_context(tz=self.tz),
|
||||
timestamp=dt_to_convert,
|
||||
)
|
||||
|
||||
@api.multi
|
||||
def _get_locations(self):
|
||||
|
||||
@@ -100,6 +100,20 @@ class TestMrpMultiLevel(SavepointCase):
|
||||
'product_id': cls.prod_test.id,
|
||||
'mrp_area_id': cls.mrp_area.id,
|
||||
})
|
||||
# Another product:
|
||||
cls.product_tz = cls.product_obj.create(
|
||||
{
|
||||
"name": "Product Timezone",
|
||||
"type": "product",
|
||||
"list_price": 100.0,
|
||||
"route_ids": [(6, 0, [route_buy])],
|
||||
"seller_ids": [(0, 0, {"name": vendor1.id, "price": 20.0})],
|
||||
}
|
||||
)
|
||||
cls.product_mrp_area_obj.create(
|
||||
{"product_id": cls.product_tz.id, "mrp_area_id": cls.cases_area.id}
|
||||
)
|
||||
|
||||
# Parameters in secondary area with nbr_days set.
|
||||
cls.product_mrp_area_obj.create({
|
||||
'product_id': cls.prod_test.id,
|
||||
@@ -675,3 +689,42 @@ class TestMrpMultiLevel(SavepointCase):
|
||||
self.assertEqual(mrp_invs[0].to_procure, 130)
|
||||
# Net needs = 18, available on-hand = 3 -> 15
|
||||
self.assertEqual(mrp_invs[1].to_procure, 15)
|
||||
|
||||
def test_timezone_handling(self):
|
||||
self.cases_area.tz = "Australia/Sydney"
|
||||
# Sidney timezone -> Oct-Apr/Apr-Oct: UTC+11/UTC+10
|
||||
date_move = datetime(2090, 4, 19, 20, 00) # Apr 20 6/7 am in Sidney
|
||||
sidney_date = "2090-04-20"
|
||||
self._create_picking_in(
|
||||
self.product_tz, 10.0, date_move, location=self.cases_loc
|
||||
)
|
||||
self.mrp_multi_level_wiz.create(
|
||||
{"mrp_area_ids": [(6, 0, self.cases_area.ids)]}
|
||||
).run_mrp_multi_level()
|
||||
inventory = self.mrp_inventory_obj.search(
|
||||
[
|
||||
("mrp_area_id", "=", self.cases_area.id),
|
||||
("product_id", "=", self.product_tz.id),
|
||||
]
|
||||
)
|
||||
self.assertEqual(len(inventory), 1)
|
||||
self.assertEqual(inventory.date, sidney_date)
|
||||
|
||||
def test_timezone_not_set(self):
|
||||
self.wh.calendar_id = False
|
||||
date_move = datetime(2090, 4, 19, 20, 00)
|
||||
no_tz_date = "2090-04-19"
|
||||
self._create_picking_in(
|
||||
self.product_tz, 10.0, date_move, location=self.cases_loc
|
||||
)
|
||||
self.mrp_multi_level_wiz.create(
|
||||
{"mrp_area_ids": [(6, 0, self.cases_area.ids)]}
|
||||
).run_mrp_multi_level()
|
||||
inventory = self.mrp_inventory_obj.search(
|
||||
[
|
||||
("mrp_area_id", "=", self.cases_area.id),
|
||||
("product_id", "=", self.product_tz.id),
|
||||
]
|
||||
)
|
||||
self.assertEqual(len(inventory), 1)
|
||||
self.assertEqual(inventory.date, no_tz_date)
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
</group>
|
||||
<group name="settings">
|
||||
<field name="calendar_id"/>
|
||||
<field name="tz"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models, exceptions, _
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from datetime import date, datetime, timedelta
|
||||
from datetime import date, timedelta
|
||||
import logging
|
||||
from odoo.tools.float_utils import float_round
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -21,8 +20,6 @@ class MultiLevelMrp(models.TransientModel):
|
||||
help="If empty, all areas will be computed.",
|
||||
)
|
||||
|
||||
# TODO: dates are not being correctly computed for supply...
|
||||
|
||||
@api.model
|
||||
def _prepare_product_mrp_area_data(self, product_mrp_area):
|
||||
qty_available = 0.0
|
||||
@@ -73,6 +70,7 @@ class MultiLevelMrp(models.TransientModel):
|
||||
@api.model
|
||||
def _prepare_mrp_move_data_from_stock_move(
|
||||
self, product_mrp_area, move, direction='in'):
|
||||
area = product_mrp_area.mrp_area_id
|
||||
if direction == 'out':
|
||||
mrp_type = 'd'
|
||||
product_qty = -move.product_qty
|
||||
@@ -107,12 +105,13 @@ class MultiLevelMrp(models.TransientModel):
|
||||
else:
|
||||
order_number = move.name
|
||||
origin = "mv"
|
||||
mrp_date = date.today()
|
||||
if datetime.date(datetime.strptime(
|
||||
move.date_expected,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)) > date.today():
|
||||
mrp_date = datetime.date(datetime.strptime(
|
||||
move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT))
|
||||
# The date to display is based on the timezone of the warehouse.
|
||||
today_tz = area._datetime_to_date_tz()
|
||||
move_date_tz = area._datetime_to_date_tz(move.date_expected)
|
||||
if move_date_tz > today_tz:
|
||||
mrp_date = move_date_tz
|
||||
else:
|
||||
mrp_date = today_tz
|
||||
return {
|
||||
'product_id': move.product_id.id,
|
||||
'product_mrp_area_id': product_mrp_area.id,
|
||||
|
||||
Reference in New Issue
Block a user