Odoo18-Base/addons/product_expiry/models/stock_move.py
2025-01-06 10:57:38 +07:00

84 lines
4.2 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import datetime
import dateutil.parser as dparser
from re import findall as re_findall
from odoo import fields, models
from odoo.tools import get_lang
class StockMove(models.Model):
_inherit = "stock.move"
use_expiration_date = fields.Boolean(
string='Use Expiration Date', related='product_id.use_expiration_date')
def _generate_serial_move_line_commands(self, field_data, location_dest_id=False, origin_move_line=None):
"""Override to add a default `expiration_date` into the move lines values."""
move_lines_commands = super()._generate_serial_move_line_commands(field_data, location_dest_id, origin_move_line)
if self.product_id.use_expiration_date:
date = fields.Datetime.today() + datetime.timedelta(days=self.product_id.expiration_time)
for move_line_command in move_lines_commands:
move_line_vals = move_line_command[2]
if 'expiration_date' not in move_line_vals:
move_line_vals['expiration_date'] = date
return move_lines_commands
def _convert_string_into_field_data(self, string, options):
res = super()._convert_string_into_field_data(string, options)
if not res:
try:
datetime = dparser.parse(string, **options)
if self and not self.use_expiration_date:
# The datetime was correctly parsed but this move's product doesn't use expiration date.
return "ignore"
return {'expiration_date': datetime}
except ValueError:
pass
return res
def _get_formating_options(self, strings):
options = super()._get_formating_options(strings)
separators = "-/ "
date_regex = f'[^{separators}]+'
for string in strings:
# Searches for a date.
date_data = re_findall(date_regex, string)
if len(date_data) < 2: # Not enough data.
continue
value_1, value_2 = date_data[:2]
if re_findall('[a-zA-Z]', value_1):
# Assumes the first value is the mounth (written in letters). Don't add any option
# as mounth as the first date's value is the default behavior for `dateutil.parse`.
break
# Try to guess if the first data is the day or the year.
if int(value_1) > 31:
options['yearfirst'] = True
break
elif int(value_1) > 12 and (re_findall('[a-zA-Z]', value_2) or int(value_2) <= 12):
options['dayfirst'] = True
break
else: # Too ambiguous, gets the option from the user's lang's date setting.
user_lang_format = get_lang(self.env).date_format
if re_findall('^%[mbB]', user_lang_format): # First parameter is for month.
return options
elif re_findall('^%[djaA]', user_lang_format): # First parameter is for day.
options['dayfirst'] = True
break
elif re_findall('^%[yY]', user_lang_format): # First parameter is for year.
options['yearfirst'] = True
break
return options
def _update_reserved_quantity(self, need, location_id, lot_id=None, package_id=None, owner_id=None, strict=True):
if self.product_id.use_expiration_date:
return super(StockMove, self.with_context(with_expiration=self.date))._update_reserved_quantity(need, location_id, lot_id, package_id, owner_id, strict)
return super()._update_reserved_quantity(need, location_id, lot_id, package_id, owner_id, strict)
def _get_available_quantity(self, location_id, lot_id=None, package_id=None, owner_id=None, strict=False, allow_negative=False):
if self.product_id.use_expiration_date:
return super(StockMove, self.with_context(with_expiration=self.date))._get_available_quantity(location_id, lot_id, package_id, owner_id, strict, allow_negative)
return super()._get_available_quantity(location_id, lot_id, package_id, owner_id, strict, allow_negative)