diff --git a/addons/product_expiry/__openerp__.py b/addons/product_expiry/__openerp__.py index 7b62ad60f1a..f5916003f74 100644 --- a/addons/product_expiry/__openerp__.py +++ b/addons/product_expiry/__openerp__.py @@ -1,7 +1,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. { 'name' : 'Products Expiration Date', - 'version' : '1.0', 'category' : 'Specific Industry Applications', 'depends' : ['stock'], 'demo' : ['data/product_expiry_demo.xml'], @@ -18,10 +17,8 @@ Following dates can be tracked: Also implements the removal strategy First Expiry First Out (FEFO) widely used, for example, in food industries. """, - 'data': ['views/product_expiry_view.xml', + 'data': ['views/production_lot_views.xml', 'views/product_template_views.xml', 'views/stock_quant_views.xml', 'data/product_expiry_data.xml'], - 'auto_install': False, - 'installable': True, } diff --git a/addons/product_expiry/data/product_expiry_data.xml b/addons/product_expiry/data/product_expiry_data.xml index b2ce4a4c95a..d9c2831bfa0 100644 --- a/addons/product_expiry/data/product_expiry_data.xml +++ b/addons/product_expiry/data/product_expiry_data.xml @@ -1,10 +1,8 @@ - - - + + First Expiry First Out (FEFO) fefo - - + diff --git a/addons/product_expiry/data/product_expiry_demo.xml b/addons/product_expiry/data/product_expiry_demo.xml index 4df0db7459f..c034f12c006 100644 --- a/addons/product_expiry/data/product_expiry_demo.xml +++ b/addons/product_expiry/data/product_expiry_demo.xml @@ -1,5 +1,5 @@ - + @@ -87,4 +87,4 @@ - + diff --git a/addons/product_expiry/models/__init__.py b/addons/product_expiry/models/__init__.py index 751af480a33..e12dbbbfcc3 100644 --- a/addons/product_expiry/models/__init__.py +++ b/addons/product_expiry/models/__init__.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import production_lot +import production_lot +import product_product import stock_quant -import product_product \ No newline at end of file diff --git a/addons/product_expiry/models/product_product.py b/addons/product_expiry/models/product_product.py index 1d660f2cf34..709a3127619 100644 --- a/addons/product_expiry/models/product_product.py +++ b/addons/product_expiry/models/product_product.py @@ -1,21 +1,17 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import datetime - -import openerp -from openerp.osv import fields, osv +from odoo import fields, models -class product_product(osv.osv): +class ProductTemplate(models.Model): _inherit = 'product.template' - _columns = { - 'life_time': fields.integer('Product Life Time', - help='When a new a Serial Number is issued, this is the number of days before the goods may become dangerous and must not be consumed.'), - 'use_time': fields.integer('Product Use Time', - help='When a new a Serial Number is issued, this is the number of days before the goods starts deteriorating, without being dangerous yet.'), - 'removal_time': fields.integer('Product Removal Time', - help='When a new a Serial Number is issued, this is the number of days before the goods should be removed from the stock.'), - 'alert_time': fields.integer('Product Alert Time', - help='When a new a Serial Number is issued, this is the number of days before an alert should be notified.'), - } + + life_time = fields.Integer(string='Product Life Time', + help='When a new a Serial Number is issued, this is the number of days before the goods may become dangerous and must not be consumed.') + use_time = fields.Integer(string='Product Use Time', + help='When a new a Serial Number is issued, this is the number of days before the goods starts deteriorating, without being dangerous yet.') + removal_time = fields.Integer(string='Product Removal Time', + help='When a new a Serial Number is issued, this is the number of days before the goods should be removed from the stock.') + alert_time = fields.Integer(string='Product Alert Time', + help='When a new a Serial Number is issued, this is the number of days before an alert should be notified.') diff --git a/addons/product_expiry/models/production_lot.py b/addons/product_expiry/models/production_lot.py index 9bfc169442e..d6d1b0fa7b9 100644 --- a/addons/product_expiry/models/production_lot.py +++ b/addons/product_expiry/models/production_lot.py @@ -1,52 +1,47 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. - import datetime - -import openerp -from openerp.osv import fields, osv +from odoo import api, fields, models -class stock_production_lot(osv.osv): +class StockProductionLot(models.Model): _inherit = 'stock.production.lot' - def _get_date(dtype): - """Return a function to compute the limit date for this type""" - def calc_date(self, cr, uid, context=None): - """Compute the limit date for a given date""" - if context is None: - context = {} - if not context.get('product_id', False): - date = False - else: - product = openerp.registry(cr.dbname)['product.product'].browse( - cr, uid, context['product_id']) - duration = getattr(product, dtype) - # set date to False when no expiry time specified on the product - date = duration and (datetime.datetime.today() - + datetime.timedelta(days=duration)) - return date and date.strftime('%Y-%m-%d %H:%M:%S') or False - return calc_date + life_date = fields.Datetime(string='End of Life Date', + help='This is the date on which the goods with this Serial Number may become dangerous and must not be consumed.') + use_date = fields.Datetime(string='Best before Date', + help='This is the date on which the goods with this Serial Number start deteriorating, without being dangerous yet.') + removal_date = fields.Datetime(string='Removal Date', + help='This is the date on which the goods with this Serial Number should be removed from the stock.') + alert_date = fields.Datetime(string='Alert Date', + help="This is the date on which an alert should be notified about the goods with this Serial Number.") + + def _get_dates(self, product_id=None): + """Returns dates based on number of days configured in current lot's product.""" + mapped_fields = { + 'life_date': 'life_time', + 'use_date': 'use_time', + 'removal_date': 'removal_time', + 'alert_date': 'alert_time' + } + res = dict.fromkeys(mapped_fields.keys(), False) + product = self.env['product.product'].browse(product_id) or self.product_id + if product: + for field in mapped_fields.keys(): + duration = getattr(product, mapped_fields[field]) + if duration: + date = datetime.datetime.now() + datetime.timedelta(days=duration) + res[field] = fields.Datetime.to_string(date) + return res - _columns = { - 'life_date': fields.datetime('End of Life Date', - help='This is the date on which the goods with this Serial Number may become dangerous and must not be consumed.'), - 'use_date': fields.datetime('Best before Date', - help='This is the date on which the goods with this Serial Number start deteriorating, without being dangerous yet.'), - 'removal_date': fields.datetime('Removal Date', - help='This is the date on which the goods with this Serial Number should be removed from the stock.'), - 'alert_date': fields.datetime('Alert Date', - help="This is the date on which an alert should be notified about the goods with this Serial Number."), - } # Assign dates according to products data - def create(self, cr, uid, vals, context=None): - context = dict(context or {}) - context['product_id'] = vals.get('product_id', context.get('default_product_id')) - return super(stock_production_lot, self).create(cr, uid, vals, context=context) + @api.model + def create(self, vals): + vals.update(self._get_dates(vals.get('product_id'))) + return super(StockProductionLot, self).create(vals) - _defaults = { - 'life_date': _get_date('life_time'), - 'use_date': _get_date('use_time'), - 'removal_date': _get_date('removal_time'), - 'alert_date': _get_date('alert_time'), - } + @api.onchange('product_id') + def _onchange_product(self): + dates_dict = self._get_dates() + for field, value in dates_dict.items(): + setattr(self, field, value) diff --git a/addons/product_expiry/models/stock_quant.py b/addons/product_expiry/models/stock_quant.py index 71826a61611..87ee21e6b0d 100644 --- a/addons/product_expiry/models/stock_quant.py +++ b/addons/product_expiry/models/stock_quant.py @@ -1,29 +1,16 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -import datetime - -import openerp -from openerp.osv import fields, osv +from odoo import api, fields, models -class stock_quant(osv.osv): +class StockQuant(models.Model): _inherit = 'stock.quant' - def _get_quants(self, cr, uid, ids, context=None): - return self.pool.get('stock.quant').search(cr, uid, [('lot_id', 'in', ids)], context=context) + removal_date = fields.Datetime(related='lot_id.removal_date', store=True) - _columns = { - 'removal_date': fields.related('lot_id', 'removal_date', type='datetime', string='Removal Date', - store={ - 'stock.quant': (lambda self, cr, uid, ids, ctx: ids, ['lot_id'], 20), - 'stock.production.lot': (_get_quants, ['removal_date'], 20), - }), - } - - def apply_removal_strategy(self, cr, uid, qty, move, ops=False, domain=None, removal_strategy='fifo', context=None): + @api.model + def apply_removal_strategy(self, qty, move, ops=False, domain=None, removal_strategy='fifo'): if removal_strategy == 'fefo': - order = 'removal_date, in_date, id' - return self._quants_get_order(cr, uid, qty, move, ops=ops, domain=domain, orderby=order, context=context) - return super(stock_quant, self).apply_removal_strategy(cr, uid, qty, move, ops=ops, domain=domain, - removal_strategy=removal_strategy, context=context) + return self._quants_get_order(qty, move, ops=ops, domain=domain, orderby='removal_date, in_date, id') + return super(StockQuant, self).apply_removal_strategy(qty, move, ops=ops, domain=domain, removal_strategy=removal_strategy) diff --git a/addons/product_expiry/views/product_expiry_view.xml b/addons/product_expiry/views/product_expiry_view.xml deleted file mode 100644 index ac5a8bfdf4c..00000000000 --- a/addons/product_expiry/views/product_expiry_view.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - stock.production.lot.form - stock.production.lot - - - - - - - - - - - - - - - - - - - diff --git a/addons/product_expiry/views/product_template_views.xml b/addons/product_expiry/views/product_template_views.xml index c47c385be7c..9f654eb192c 100644 --- a/addons/product_expiry/views/product_template_views.xml +++ b/addons/product_expiry/views/product_template_views.xml @@ -1,8 +1,7 @@ - - - - - product.normal.form + + + + product.template.inherit.form product.template @@ -16,5 +15,4 @@ - - \ No newline at end of file + diff --git a/addons/product_expiry/views/production_lot_views.xml b/addons/product_expiry/views/production_lot_views.xml new file mode 100644 index 00000000000..92b2040de6a --- /dev/null +++ b/addons/product_expiry/views/production_lot_views.xml @@ -0,0 +1,22 @@ + + + + stock.production.lot.inherit.form + stock.production.lot + + + + + + + + + + + + + + + + + diff --git a/addons/product_expiry/views/stock_quant_views.xml b/addons/product_expiry/views/stock_quant_views.xml index 33a8b42a60f..d3e0839580f 100644 --- a/addons/product_expiry/views/stock_quant_views.xml +++ b/addons/product_expiry/views/stock_quant_views.xml @@ -1,8 +1,7 @@ - - - - - stock.quant.form + + + + stock.quant.inherit.form stock.quant @@ -11,5 +10,4 @@ - - \ No newline at end of file +