diff --git a/addons/account/models/account_fiscal_year.py b/addons/account/models/account_fiscal_year.py index ce031fb3f59e4..8e664c2ea7257 100644 --- a/addons/account/models/account_fiscal_year.py +++ b/addons/account/models/account_fiscal_year.py @@ -2,7 +2,6 @@ from odoo.exceptions import ValidationError from odoo import api, fields, models, _ -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT from datetime import datetime @@ -37,8 +36,8 @@ def _check_dates(self): ''' for fy in self: # Starting date must be prior to the ending date - date_from = datetime.strptime(fy.date_from, DEFAULT_SERVER_DATE_FORMAT) - date_to = datetime.strptime(fy.date_to, DEFAULT_SERVER_DATE_FORMAT) + date_from = fy.date_from + date_to = fy.date_to if date_to < date_from: raise ValidationError(_('The ending date must not be prior to the starting date.')) diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index fa235ee9d67fb..0ba6359b6af4a 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -10,7 +10,8 @@ from werkzeug.urls import url_encode from odoo import api, exceptions, fields, models, _ -from odoo.tools import email_re, email_split, email_escape_char, float_is_zero, float_compare, pycompat +from odoo.tools import email_re, email_split, email_escape_char, float_is_zero, float_compare, \ + pycompat, date_utils from odoo.tools.misc import formatLang from odoo.exceptions import AccessError, UserError, RedirectWarning, ValidationError, Warning @@ -216,7 +217,7 @@ def _get_payment_info_JSON(self): self.payments_widget = json.dumps(False) if self.payment_move_line_ids: info = {'title': _('Less Payment'), 'outstanding': False, 'content': self._get_payments_vals()} - self.payments_widget = json.dumps(info) + self.payments_widget = json.dumps(info, default=date_utils.json_default) @api.one @api.depends('move_id.line_ids.amount_residual') diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py index 431be1b0aa81d..a8e229883d1c9 100644 --- a/addons/account/models/account_journal_dashboard.py +++ b/addons/account/models/account_journal_dashboard.py @@ -76,7 +76,7 @@ def build_graph_data(date, amount): """ self.env.cr.execute(query, (self.id, last_month, today)) for val in self.env.cr.dictfetchall(): - date = datetime.strptime(val['date'], DF) + date = val['date'] if val['date'] != today.strftime(DF): # make sure the last point in the graph is today data[:0] = [build_graph_data(date, amount)] amount -= val['amount'] @@ -92,7 +92,7 @@ def build_graph_data(date, amount): @api.multi def get_bar_graph_datas(self): data = [] - today = datetime.strptime(fields.Date.context_today(self), DF) + today = fields.Date.context_today(self) data.append({'label': _('Past'), 'value':0.0, 'type': 'past'}) day_of_week = int(format_datetime(today, 'e', locale=self._context.get('lang') or 'en_US')) first_day_of_week = today + timedelta(days=-day_of_week+1) diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index bb8a29e0fb1a5..ca4e6d9d370f2 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import time +from datetime import date from collections import OrderedDict from odoo import api, fields, models, _ from odoo.osv import expression @@ -345,10 +346,10 @@ def _post_validate(self): @api.multi def _check_lock_date(self): for move in self: - lock_date = max(move.company_id.period_lock_date or '0000-00-00', move.company_id.fiscalyear_lock_date or '0000-00-00') + lock_date = max(move.company_id.period_lock_date or date.min, move.company_id.fiscalyear_lock_date or date.min) if self.user_has_groups('account.group_account_manager'): lock_date = move.company_id.fiscalyear_lock_date - if move.date <= (lock_date or '0000-00-00'): + if move.date <= (lock_date or date.min): if self.user_has_groups('account.group_account_manager'): message = _("You cannot add/modify entries prior to and inclusive of the lock date %s") % (lock_date) else: @@ -738,7 +739,7 @@ def check_full_reconcile(self): total_debit = 0 total_credit = 0 total_amount_currency = 0 - maxdate = '0000-00-00' + maxdate = date.min to_balance = {} for aml in amls: total_debit += aml.debit @@ -947,7 +948,7 @@ def compute_writeoff_counterpart_vals(values): total = 0 total_currency = 0 writeoff_lines = [] - date = time.strftime('%Y-%m-%d') + date = fields.Date.today() for vals in lines: # Check and complete vals if 'account_id' not in vals or 'journal_id' not in vals: @@ -955,7 +956,7 @@ def compute_writeoff_counterpart_vals(values): if ('debit' in vals) ^ ('credit' in vals): raise UserError(_("Either pass both debit and credit or none.")) if 'date' not in vals: - vals['date'] = self._context.get('date_p') or time.strftime('%Y-%m-%d') + vals['date'] = self._context.get('date_p') or fields.Date.today() if vals['date'] < date: date = vals['date'] if 'name' not in vals: @@ -1369,8 +1370,8 @@ class AccountPartialReconcile(models.Model): def _compute_max_date(self): for rec in self: rec.max_date = max( - fields.Datetime.from_string(rec.debit_move_id.date), - fields.Datetime.from_string(rec.credit_move_id.date) + rec.debit_move_id.date, + rec.credit_move_id.date ) @api.model @@ -1608,6 +1609,6 @@ def _prepare_exchange_diff_move(self, move_date, company): # The move date should be the maximum date between payment and invoice # (in case of payment in advance). However, we should make sure the # move date is not recorded after the end of year closing. - if move_date > (company.fiscalyear_lock_date or '0000-00-00'): + if move_date > (company.fiscalyear_lock_date or date.min): res['date'] = move_date return res diff --git a/addons/account/models/company.py b/addons/account/models/company.py index 89d9d9b4646be..0b5e879ce35f2 100644 --- a/addons/account/models/company.py +++ b/addons/account/models/company.py @@ -9,7 +9,7 @@ from odoo.exceptions import ValidationError, UserError, RedirectWarning from odoo.tools.misc import DEFAULT_SERVER_DATE_FORMAT from odoo.tools.float_utils import float_round, float_is_zero -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, date_utils +from odoo.tools import date_utils class ResCompany(models.Model): @@ -110,16 +110,15 @@ def _check_lock_dates(self, vals): :param vals: The values passed to the write method. ''' period_lock_date = vals.get('period_lock_date') and\ - time.strptime(vals['period_lock_date'], DEFAULT_SERVER_DATE_FORMAT) + fields.Date.from_string(vals['period_lock_date']) fiscalyear_lock_date = vals.get('fiscalyear_lock_date') and\ - time.strptime(vals['fiscalyear_lock_date'], DEFAULT_SERVER_DATE_FORMAT) + fields.Date.from_string(vals['fiscalyear_lock_date']) - previous_month = datetime.strptime(fields.Date.today(), DEFAULT_SERVER_DATE_FORMAT) + relativedelta(months=-1) + previous_month = fields.Date.today() + relativedelta(months=-1) days_previous_month = calendar.monthrange(previous_month.year, previous_month.month) - previous_month = previous_month.replace(day=days_previous_month[1]).timetuple() + previous_month = previous_month.replace(day=days_previous_month[1]) for company in self: - old_fiscalyear_lock_date = company.fiscalyear_lock_date and\ - time.strptime(company.fiscalyear_lock_date, DEFAULT_SERVER_DATE_FORMAT) + old_fiscalyear_lock_date = company.fiscalyear_lock_date # The user attempts to remove the lock date for advisors if old_fiscalyear_lock_date and not fiscalyear_lock_date and 'fiscalyear_lock_date' in vals: @@ -143,7 +142,7 @@ def _check_lock_dates(self, vals): # In case of no new period lock date in vals, fallback to the one defined in the company if not period_lock_date: if company.period_lock_date: - period_lock_date = time.strptime(company.period_lock_date, DEFAULT_SERVER_DATE_FORMAT) + period_lock_date = company.period_lock_date else: continue @@ -182,8 +181,8 @@ def compute_fiscalyear_dates(self, current_date): ], limit=1) if fiscalyear: return { - 'date_from': datetime.strptime(fiscalyear.date_from, DEFAULT_SERVER_DATE_FORMAT).date(), - 'date_to': datetime.strptime(fiscalyear.date_to, DEFAULT_SERVER_DATE_FORMAT).date(), + 'date_from': fiscalyear.date_from, + 'date_to': fiscalyear.date_to, 'record': fiscalyear, } @@ -204,7 +203,7 @@ def compute_fiscalyear_dates(self, current_date): ('date_to', '>=', date_from_str), ], limit=1) if fiscalyear_from: - date_from = datetime.strptime(fiscalyear_from.date_to, DEFAULT_SERVER_DATE_FORMAT).date() + timedelta(days=1) + date_from = fiscalyear_from.date_to + timedelta(days=1) fiscalyear_to = self.env['account.fiscal.year'].search([ ('company_id', '=', self.id), @@ -212,7 +211,7 @@ def compute_fiscalyear_dates(self, current_date): ('date_to', '>=', date_to_str), ], limit=1) if fiscalyear_to: - date_to = datetime.strptime(fiscalyear_to.date_from, DEFAULT_SERVER_DATE_FORMAT).date() - timedelta(days=1) + date_to = fiscalyear_to.date_from - timedelta(days=1) return {'date_from': date_from, 'date_to': date_to} diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py index fc4a7f732ea68..88a6f4e3d88aa 100644 --- a/addons/account/report/account_aged_partner_balance.py +++ b/addons/account/report/account_aged_partner_balance.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import time -from odoo import api, models, _ +from odoo import api, fields, models, _ from odoo.exceptions import UserError from odoo.tools import float_is_zero from datetime import datetime @@ -19,7 +19,8 @@ def _get_partner_move_lines(self, account_type, date_from, target_move, period_l # The context key allow it to appear ctx = self._context periods = {} - start = datetime.strptime(date_from, "%Y-%m-%d") - relativedelta(days=1) + date_from = fields.Date.from_string(date_from) + start = date_from - relativedelta(days=1) for i in range(5)[::-1]: stop = start - relativedelta(days=period_length) periods[str(i)] = { @@ -220,7 +221,7 @@ def _get_report_values(self, docids, data=None): docs = self.env[model].browse(self.env.context.get('active_id')) target_move = data['form'].get('target_move', 'all') - date_from = data['form'].get('date_from', time.strftime('%Y-%m-%d')) + date_from = fields.Date.from_string(data['form'].get('date_from')) or fields.Date.today() if data['form']['result_selection'] == 'customer': account_type = ['receivable'] diff --git a/addons/account/report/account_partner_ledger.py b/addons/account/report/account_partner_ledger.py index ccd2c41d64769..fa7f1206cca0e 100644 --- a/addons/account/report/account_partner_ledger.py +++ b/addons/account/report/account_partner_ledger.py @@ -4,7 +4,6 @@ import time from odoo import api, models, _ from odoo.exceptions import UserError -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT class ReportPartnerLedger(models.AbstractModel): @@ -35,7 +34,6 @@ def _lines(self, data, partner): lang_id = lang._lang_get(lang_code) date_format = lang_id.date_format for r in res: - r['date'] = datetime.strptime(r['date'], DEFAULT_SERVER_DATE_FORMAT).strftime(date_format) r['displayed_name'] = '-'.join( r[field_name] for field_name in ('move_name', 'ref', 'name') if r[field_name] not in (None, '', '/') diff --git a/addons/account/tests/test_account_fiscal_year.py b/addons/account/tests/test_account_fiscal_year.py index e1ce44c38fe07..85785473ee225 100644 --- a/addons/account/tests/test_account_fiscal_year.py +++ b/addons/account/tests/test_account_fiscal_year.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- from odoo.addons.account.tests.account_test_classes import AccountingTestCase -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT import odoo.tests +from odoo import fields from datetime import datetime @@ -19,10 +19,10 @@ def check_compute_fiscal_year(self, company, date, expected_date_from, expected_ :param expected_date_from: The expected date_from after computation. :param expected_date_to: The expected date_to after computation. ''' - current_date = datetime.strptime(date, DEFAULT_SERVER_DATE_FORMAT) + current_date = fields.Date.from_string(date) res = company.compute_fiscalyear_dates(current_date) - self.assertEqual(res['date_from'].strftime(DEFAULT_SERVER_DATE_FORMAT), expected_date_from) - self.assertEqual(res['date_to'].strftime(DEFAULT_SERVER_DATE_FORMAT), expected_date_to) + self.assertEqual(res['date_from'], fields.Date.from_string(expected_date_from)) + self.assertEqual(res['date_to'], fields.Date.from_string(expected_date_to)) def test_default_fiscal_year(self): '''Basic case with a fiscal year xxxx-01-01 - xxxx-12-31.''' diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py index f16f08baac7d7..226108ffbba00 100644 --- a/addons/account/tests/test_reconciliation.py +++ b/addons/account/tests/test_reconciliation.py @@ -1,4 +1,4 @@ -from odoo import api +from odoo import api, fields from odoo.addons.account.tests.account_test_classes import AccountingTestCase from odoo.tests import tagged import time diff --git a/addons/account/wizard/account_report_aged_partner_balance.py b/addons/account/wizard/account_report_aged_partner_balance.py index c1f186b5abbca..178f1f80c380e 100644 --- a/addons/account/wizard/account_report_aged_partner_balance.py +++ b/addons/account/wizard/account_report_aged_partner_balance.py @@ -27,7 +27,7 @@ def _print_report(self, data): if not data['form']['date_from']: raise UserError(_('You must set a start date.')) - start = datetime.strptime(data['form']['date_from'], "%Y-%m-%d") + start = fields.Date.from_string(data['form']['date_from']) for i in range(5)[::-1]: stop = start - relativedelta(days=period_length - 1) diff --git a/addons/account_asset/models/account_asset.py b/addons/account_asset/models/account_asset.py index 36a4ee9ba25f1..ae0b345750854 100644 --- a/addons/account_asset/models/account_asset.py +++ b/addons/account_asset/models/account_asset.py @@ -7,7 +7,6 @@ from odoo import api, fields, models, _ from odoo.exceptions import UserError, ValidationError -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF from odoo.tools import float_compare, float_is_zero @@ -164,7 +163,7 @@ def _compute_board_amount(self, sequence, residual_amount, amount_to_depr, undon if self.prorata: amount = amount_to_depr / self.method_number if sequence == 1: - date = datetime.strptime(self.date, DF) + date = self.date if self.method_period % 12 != 0: month_days = calendar.monthrange(date.year, date.month)[1] days = month_days - date.day + 1 @@ -176,7 +175,7 @@ def _compute_board_amount(self, sequence, residual_amount, amount_to_depr, undon amount = residual_amount * self.method_progress_factor if self.prorata: if sequence == 1: - date = datetime.strptime(self.date, DF) + date = self.date if self.method_period % 12 != 0: month_days = calendar.monthrange(date.year, date.month)[1] days = month_days - date.day + 1 @@ -189,7 +188,7 @@ def _compute_board_amount(self, sequence, residual_amount, amount_to_depr, undon def _compute_board_undone_dotation_nb(self, depreciation_date, total_days): undone_dotation_number = self.method_number if self.method_time == 'end': - end_date = datetime.strptime(self.method_end, DF).date() + end_date = self.method_end undone_dotation_number = 0 while depreciation_date <= end_date: depreciation_date = date(depreciation_date.year, depreciation_date.month, depreciation_date.day) + relativedelta(months=+self.method_period) @@ -213,12 +212,11 @@ def compute_depreciation_board(self): # if we already have some previous validated entries, starting date is last entry + method period if posted_depreciation_line_ids and posted_depreciation_line_ids[-1].depreciation_date: - last_depreciation_date = datetime.strptime(posted_depreciation_line_ids[-1].depreciation_date, DF).date() + last_depreciation_date = fields.Date.from_string(posted_depreciation_line_ids[-1].depreciation_date) depreciation_date = last_depreciation_date + relativedelta(months=+self.method_period) else: # depreciation_date computed from the purchase date depreciation_date = self.date - depreciation_date = datetime.strptime(depreciation_date, DF) if self.date_first_depreciation == 'last_day_period': # depreciation_date = the last day of the month depreciation_date = depreciation_date + relativedelta(day=31) @@ -226,14 +224,12 @@ def compute_depreciation_board(self): if self.method_period == 12: depreciation_date = depreciation_date + relativedelta(month=self.company_id.fiscalyear_last_month) depreciation_date = depreciation_date + relativedelta(day=self.company_id.fiscalyear_last_day) - if datetime.strftime(depreciation_date, DF) < self.date: + if depreciation_date < self.date: depreciation_date = depreciation_date + relativedelta(years=1) elif self.first_depreciation_manual_date and self.first_depreciation_manual_date != self.date: # depreciation_date set manually from the 'first_depreciation_manual_date' field depreciation_date = self.first_depreciation_manual_date - depreciation_date = datetime.strptime(depreciation_date, DF) - depreciation_date = depreciation_date.date() total_days = (depreciation_date.year % 4) and 365 or 366 month_day = depreciation_date.day undone_dotation_number = self._compute_board_undone_dotation_nb(depreciation_date, total_days) @@ -252,7 +248,7 @@ def compute_depreciation_board(self): 'name': (self.code or '') + '/' + str(sequence), 'remaining_value': residual_amount, 'depreciated_value': self.value - (self.salvage_value + residual_amount), - 'depreciation_date': depreciation_date.strftime(DF), + 'depreciation_date': depreciation_date, } commands.append((0, False, vals)) @@ -327,7 +323,7 @@ def _get_disposal_moves(self): # Create a new depr. line with the residual amount and post it sequence = len(asset.depreciation_line_ids) - len(unposted_depreciation_line_ids) + 1 - today = datetime.today().strftime(DF) + today = fields.Datetime.today() vals = { 'amount': asset.value_residual, 'asset_id': asset.id, diff --git a/addons/account_asset/models/account_invoice.py b/addons/account_asset/models/account_invoice.py index c4b960079ec0f..c87bccf2291f6 100644 --- a/addons/account_asset/models/account_invoice.py +++ b/addons/account_asset/models/account_invoice.py @@ -5,7 +5,6 @@ from dateutil.relativedelta import relativedelta from odoo import api, fields, models, _ from odoo.exceptions import UserError -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DF from odoo.addons import decimal_precision as dp @@ -65,10 +64,10 @@ def _get_asset_date(self): if self.invoice_id.type in ['out_invoice', 'out_refund']: self.asset_mrr = self.price_subtotal_signed / months if self.invoice_id.date_invoice: - start_date = datetime.strptime(self.invoice_id.date_invoice, DF).replace(day=1) + start_date = self.invoice_id.date_invoice.replace(day=1) end_date = (start_date + relativedelta(months=months, days=-1)) - self.asset_start_date = start_date.strftime(DF) - self.asset_end_date = end_date.strftime(DF) + self.asset_start_date = start_date + self.asset_end_date = end_date @api.one def asset_create(self): diff --git a/addons/account_budget/models/account_budget.py b/addons/account_budget/models/account_budget.py index 961c957c2d7aa..b2db529a2600f 100644 --- a/addons/account_budget/models/account_budget.py +++ b/addons/account_budget/models/account_budget.py @@ -205,22 +205,21 @@ def _compute_practical_amount(self): @api.multi def _compute_theoritical_amount(self): # beware: 'today' variable is mocked in the python tests and thus, its implementation matter - today = fields.Datetime.from_string(fields.Date.today()) + today = fields.Date.today() for line in self: if line.paid_date: - if fields.Datetime.to_string(today) <= line.paid_date: + if today <= line.paid_date: theo_amt = 0.00 else: theo_amt = line.planned_amount else: - line_timedelta = fields.Datetime.from_string(line.date_to) - fields.Datetime.from_string( - line.date_from) - elapsed_timedelta = today - fields.Datetime.from_string(line.date_from) + line_timedelta = line.date_to - line.date_from + elapsed_timedelta = today - line.date_from if elapsed_timedelta.days < 0: # If the budget line has not started yet, theoretical amount should be zero theo_amt = 0.00 - elif line_timedelta.days > 0 and today < fields.Datetime.from_string(line.date_to): + elif line_timedelta.days > 0 and today < line.date_to: # If today is between the budget line date_from and date_to theo_amt = (elapsed_timedelta.total_seconds() / line_timedelta.total_seconds()) * line.planned_amount else: @@ -265,14 +264,14 @@ def action_open_budget_entries(self): @api.one @api.constrains('date_from', 'date_to') def _line_dates_between_budget_dates(self): - budget_date_from = fields.Datetime.from_string(self.crossovered_budget_id.date_from) - budget_date_to = fields.Datetime.from_string(self.crossovered_budget_id.date_to) + budget_date_from = self.crossovered_budget_id.date_from + budget_date_to = self.crossovered_budget_id.date_to if self.date_from: - date_from = fields.Datetime.from_string(self.date_from) + date_from = self.date_from if date_from < budget_date_from or date_from > budget_date_to: raise ValidationError(_('"Start Date" of the budget line should be included in the Period of the budget')) if self.date_to: - date_to = fields.Datetime.from_string(self.date_to) + date_to = self.date_to if date_to < budget_date_from or date_to > budget_date_to: raise ValidationError(_('"End Date" of the budget line should be included in the Period of the budget')) diff --git a/addons/account_budget/tests/test_theoreticalamount.py b/addons/account_budget/tests/test_theoreticalamount.py index 082d39b9b14a0..c8341e92cf01d 100644 --- a/addons/account_budget/tests/test_theoreticalamount.py +++ b/addons/account_budget/tests/test_theoreticalamount.py @@ -35,29 +35,32 @@ def setUp(self): 'account_ids': [(4, account_rev.id, 0)], }) #create the budget and budget lines - first_january = datetime.now().replace(day=1, month=1) + first_january = Datetime.now().replace(day=1, month=1) self.last_day_of_budget = first_january + timedelta(days=364) # will be 30th of December or 31th in case of leap year + date_from = first_january.date() + date_to = self.last_day_of_budget.date() + crossovered_budget = self.env['crossovered.budget'].create({ 'name': 'test budget name', - 'date_from': str(first_january.date()), - 'date_to': str(self.last_day_of_budget.date()), + 'date_from': date_from, + 'date_to': date_to, }) crossovered_budget_line_obj = self.env['crossovered.budget.lines'] self.line = crossovered_budget_line_obj.create({ 'crossovered_budget_id': crossovered_budget.id, 'general_budget_id': buget_post.id, - 'date_from': str(first_january.date()), - 'date_to': str(self.last_day_of_budget.date()), + 'date_from': date_from, + 'date_to': date_to, 'planned_amount': -364, }) self.paid_date_line = crossovered_budget_line_obj.create({ 'crossovered_budget_id': crossovered_budget.id, 'general_budget_id': buget_post.id, - 'date_from': str(first_january.date()), - 'date_to': str(self.last_day_of_budget.date()), + 'date_from': date_from, + 'date_to': date_to, 'planned_amount': -364, - 'paid_date': str(datetime.now().year) + '-09-09', + 'paid_date': Date.today().replace(day=9, month=9), }) self.patcher = patch('odoo.addons.account_budget.models.account_budget.fields.Date', wraps=Date) @@ -74,7 +77,7 @@ def test_theoritical_amount_without_paid_date(self): ] for date, expected_amount in test_list: _logger.info("Checking theoritical amount for the date: " + date) - self.mock_date.today.return_value = date + self.mock_date.today.return_value = Date.from_string(date) self.assertAlmostEqual(self.line.theoritical_amount, expected_amount) #invalidate the cache of the budget lines to recompute the theoritical amount at next iteration self.line.invalidate_cache() @@ -84,13 +87,13 @@ def test_theoritical_amount_with_paid_date(self): (str(datetime.now().year) + '-01-01', 0), (str(datetime.now().year) + '-01-02', 0), (str(datetime.now().year) + '-09-08', 0), - (str(datetime.now().year) + '-09-09', -364), + (str(datetime.now().year) + '-09-09', 0), (str(datetime.now().year) + '-09-10', -364), (str(self.last_day_of_budget.date()), -364), ] for date, expected_amount in test_list: _logger.info("Checking theoritical amount for the date: " + date) - self.mock_date.today.return_value = date + self.mock_date.today.return_value = Date.from_string(date) self.assertAlmostEqual(self.paid_date_line.theoritical_amount, expected_amount) #invalidate the cache of the budget lines to recompute the theoritical amount at next iteration self.paid_date_line.invalidate_cache() diff --git a/addons/bus/models/bus.py b/addons/bus/models/bus.py index 39de41ec0a22e..cdeee00a313a5 100644 --- a/addons/bus/models/bus.py +++ b/addons/bus/models/bus.py @@ -10,6 +10,7 @@ import odoo from odoo import api, fields, models, SUPERUSER_ID from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT +from odoo.tools import date_utils _logger = logging.getLogger(__name__) @@ -20,7 +21,7 @@ # Bus #---------------------------------------------------------- def json_dump(v): - return json.dumps(v, separators=(',', ':')) + return json.dumps(v, separators=(',', ':'), default=date_utils.json_default) def hashable(key): if isinstance(key, list): diff --git a/addons/bus/models/bus_presence.py b/addons/bus/models/bus_presence.py index b9f4a3ea8c67b..c1da707b21562 100644 --- a/addons/bus/models/bus_presence.py +++ b/addons/bus/models/bus_presence.py @@ -43,11 +43,11 @@ def update(self, inactivity_period): # update the presence or a create a new one if not presence: # create a new presence for the user values['user_id'] = self._uid - values['last_presence'] = last_presence.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + values['last_presence'] = last_presence self.create(values) else: # update the last_presence if necessary, and write values - if datetime.datetime.strptime(presence.last_presence, DEFAULT_SERVER_DATETIME_FORMAT) < last_presence: - values['last_presence'] = last_presence.strftime(DEFAULT_SERVER_DATETIME_FORMAT) + if presence.last_presence < last_presence: + values['last_presence'] = last_presence # Hide transaction serialization errors, which can be ignored, the presence update is not essential with tools.mute_logger('odoo.sql_db'): presence.write(values) diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index 49ab6f28fb696..556ea3578a2af 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -351,7 +351,7 @@ def do_check_alarm_for_one_date(self, one_date, event, event_maxdelta, in_the_ne @api.model def get_next_mail(self): - now = fields.Datetime.now() + now = fields.Datetime.to_string(fields.Datetime.now()) last_notif_mail = self.env['ir.config_parameter'].sudo().get_param('calendar.last_notif_mail', default=now) try: @@ -391,7 +391,7 @@ def get_next_mail(self): if at_least_one and not last_found: # if the precedent event had an alarm but not this one, we can stop the search for this event break else: - in_date_format = datetime.strptime(meeting.start, DEFAULT_SERVER_DATETIME_FORMAT) + in_date_format = meeting.start last_found = self.do_check_alarm_for_one_date(in_date_format, meeting, max_delta, 0, 'email', after=last_notif_mail, missing=True) for alert in last_found: self.do_mail_reminder(alert) @@ -873,9 +873,9 @@ def _compute_dates(self): """ for meeting in self: if meeting.allday: - meeting.start_date = meeting.start + meeting.start_date = meeting.start.date() meeting.start_datetime = False - meeting.stop_date = meeting.stop + meeting.stop_date = meeting.stop.date() meeting.stop_datetime = False meeting.duration = 0.0 @@ -897,13 +897,13 @@ def _inverse_dates(self): enddate = tz.localize(enddate) enddate = enddate.replace(hour=18) enddate = enddate.astimezone(pytz.utc) - meeting.stop = fields.Datetime.to_string(enddate) + meeting.stop = enddate startdate = fields.Datetime.from_string(meeting.start_date) startdate = tz.localize(startdate) # Add "+hh:mm" timezone startdate = startdate.replace(hour=8) # Set 8 AM in localtime startdate = startdate.astimezone(pytz.utc) # Convert to UTC - meeting.start = fields.Datetime.to_string(startdate) + meeting.start = startdate else: meeting.write({'start': meeting.start_datetime, 'stop': meeting.stop_datetime}) @@ -945,9 +945,9 @@ def _check_closing_date(self): @api.onchange('start_datetime', 'duration') def _onchange_duration(self): if self.start_datetime: - start = fields.Datetime.from_string(self.start_datetime) + start = self.start_datetime self.start = self.start_datetime - self.stop = fields.Datetime.to_string(start + timedelta(hours=self.duration)) + self.stop = start + timedelta(hours=self.duration) @api.onchange('start_date') def _onchange_start_date(self): @@ -971,9 +971,9 @@ def _get_ics_file(self): def ics_datetime(idate, allday=False): if idate: if allday: - return fields.Date.from_string(idate) + return idate else: - return fields.Datetime.from_string(idate).replace(tzinfo=pytz.timezone('UTC')) + return idate.replace(tzinfo=pytz.timezone('UTC')) return False try: @@ -989,7 +989,7 @@ def ics_datetime(idate, allday=False): if not meeting.start or not meeting.stop: raise UserError(_("First you have to specify the date of the invitation.")) - event.add('created').value = ics_datetime(time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)) + event.add('created').value = ics_datetime(fields.Datetime.now()) event.add('dtstart').value = ics_datetime(meeting.start, meeting.allday) event.add('dtend').value = ics_datetime(meeting.stop, meeting.allday) event.add('summary').value = meeting.name @@ -1245,7 +1245,8 @@ def get_month_string(freq): return '' def get_end_date(): - end_date_new = ''.join((re.compile('\d')).findall(self.final_date)) + 'T235959Z' if self.final_date else False + final_date = fields.Date.to_string(self.final_date) + end_date_new = ''.join((re.compile('\d')).findall(final_date)) + 'T235959Z' if final_date else False return (self.end_type == 'count' and (';COUNT=' + str(self.count)) or '') +\ ((end_date_new and self.end_type == 'end_date' and (';UNTIL=' + end_date_new)) or '') @@ -1379,6 +1380,7 @@ def detach_recurring_event(self, values=None): meeting_origin = self.browse(real_id) data = self.read(['allday', 'start', 'stop', 'rrule', 'duration'])[0] + d_class = fields.Date if data['allday'] else fields.Datetime if data.get('rrule'): data.update( values, @@ -1387,7 +1389,8 @@ def detach_recurring_event(self, values=None): rrule_type=False, rrule='', recurrency=False, - final_date=datetime.strptime(data.get('start'), DEFAULT_SERVER_DATETIME_FORMAT if data['allday'] else DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=values.get('duration', False) or data.get('duration')) + final_date=d_class.from_string(data.get('start')) \ + + timedelta(hours=values.get('duration', False) or data.get('duration')) ) # do not copy the id diff --git a/addons/calendar/tests/test_calendar.py b/addons/calendar/tests/test_calendar.py index 12547c8f695ac..fbf86ace9e1b8 100644 --- a/addons/calendar/tests/test_calendar.py +++ b/addons/calendar/tests/test_calendar.py @@ -2,7 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import datetime -from datetime import datetime, timedelta +from datetime import datetime, timedelta, time from odoo import fields from odoo.tests.common import TransactionCase @@ -34,7 +34,7 @@ def test_calender_simple_event(self): }) self.assertEqual( - (m.start_datetime, m.stop_datetime), + (str(m.start_datetime), str(m.stop_datetime)), (u'2017-07-12 14:30:00', u'2017-07-12 15:00:00'), "Sanity check" ) @@ -102,8 +102,8 @@ def test_calender_event(self): # I create a recuring rule for my event calendar_event_sprint_review = self.CalendarEvent.create({ 'name': 'Begin of month meeting', - 'start': fields.Date.today() + ' 12:00:00', - 'stop': fields.Date.today() + ' 18:00:00', + 'start': datetime.combine(fields.Date.today(), time(12, 0)), + 'stop': datetime.combine(fields.Date.today(), time(18, 0)), 'recurrency': True, 'rrule': 'FREQ=MONTHLY;INTERVAL=1;COUNT=12;BYDAY=1MO' }) @@ -130,7 +130,7 @@ def test_validation_error(self): 'stop': '2017-07-12 15:00:00', }) self.assertEqual( - (m.start_datetime, m.stop_datetime), + (str(m.start_datetime), str(m.stop_datetime)), (u'2017-07-12 14:30:00', u'2017-07-12 15:00:00'), "Sanity check" ) @@ -154,11 +154,11 @@ def test_validation_error(self): records = m.detach_recurring_event(values) self.assertEqual( - (m.start_datetime, m.stop_datetime), - (u'2017-07-12 14:30:00', u'2017-07-12 15:00:00'), + (str(m.start_datetime), str(m.stop_datetime)), + ('2017-07-12 14:30:00', u'2017-07-12 15:00:00'), ) self.assertEquals( - (records.start_datetime, records.stop_datetime), + (str(records.start_datetime), str(records.stop_datetime)), (u'2017-07-10 15:30:00', u'2017-07-10 16:00:00'), ) @@ -243,7 +243,7 @@ def test_event_activity(self): self.assertEqual(test_record.activity_ids.summary, test_name) self.assertEqual(test_record.activity_ids.note, test_description) self.assertEqual(test_record.activity_ids.user_id, self.env.user) - self.assertEqual(test_record.activity_ids.date_deadline, fields.Date.to_string((now + timedelta(days=-1)).date())) + self.assertEqual(test_record.activity_ids.date_deadline, (now + timedelta(days=-1)).date()) # updating event should update activity test_event.write({ @@ -255,7 +255,7 @@ def test_event_activity(self): self.assertEqual(test_record.activity_ids.summary, '%s2' % test_name) self.assertEqual(test_record.activity_ids.note, test_description2) self.assertEqual(test_record.activity_ids.user_id, test_user) - self.assertEqual(test_record.activity_ids.date_deadline, fields.Date.to_string((now + timedelta(days=-2)).date())) + self.assertEqual(test_record.activity_ids.date_deadline, (now + timedelta(days=-2)).date()) # deleting meeting should delete its activity test_record.activity_ids.unlink() @@ -268,8 +268,8 @@ def test_event_activity(self): ).create({ 'name': test_name, 'description': test_description, - 'start': fields.Datetime.to_string(now + timedelta(days=-1)), - 'stop': fields.Datetime.to_string(now + timedelta(hours=2)), + 'start': now + timedelta(days=-1), + 'stop': now + timedelta(hours=2), 'user_id': self.env.user.id, }) self.assertEqual(test_event.res_model, test_record._name) diff --git a/addons/calendar_sms/models/calendar.py b/addons/calendar_sms/models/calendar.py index d22200b936323..986a46e521014 100644 --- a/addons/calendar_sms/models/calendar.py +++ b/addons/calendar_sms/models/calendar.py @@ -39,7 +39,7 @@ def get_next_mail(self): """ Cron method, overriden here to send SMS reminders as well """ result = super(AlarmManager, self).get_next_mail() - now = fields.Datetime.now() + now = fields.Datetime.to_string(fields.Datetime.now()) last_sms_cron = self.env['ir.config_parameter'].get_param('calendar_sms.last_sms_cron', default=now) cron = self.env['ir.model.data'].get_object('calendar', 'ir_cron_scheduler_alarm') diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index d1032e34b1d8f..35806bddb6fc9 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -1054,7 +1054,7 @@ def retrieve_sales_dashboard(self): meetings = self.env['calendar.event'].search(meetings_domain) for meeting in meetings: if meeting['start']: - start = datetime.strptime(meeting['start'], tools.DEFAULT_SERVER_DATETIME_FORMAT).date() + start = meeting['start'] if start == today: result['meeting']['today'] += 1 if today <= start <= today + timedelta(days=7): diff --git a/addons/event/models/event.py b/addons/event/models/event.py index 8902bbcaa4939..0ff913fb42b9e 100644 --- a/addons/event/models/event.py +++ b/addons/event/models/event.py @@ -347,7 +347,7 @@ class EventRegistration(models.Model): partner_id = fields.Many2one( 'res.partner', string='Contact', states={'done': [('readonly', True)]}) - date_open = fields.Datetime(string='Registration Date', readonly=True, default=lambda self: fields.datetime.now()) # weird crash is directly now + date_open = fields.Datetime(string='Registration Date', readonly=True, default=lambda self: fields.Datetime.now()) # weird crash is directly now date_closed = fields.Datetime(string='Attended Date', readonly=True) event_begin_date = fields.Datetime(string="Event Start Date", related='event_id.date_begin', readonly=True) event_end_date = fields.Datetime(string="Event End Date", related='event_id.date_end', readonly=True) @@ -515,8 +515,8 @@ def action_send_badge_email(self): @api.multi def get_date_range_str(self): self.ensure_one() - today = fields.Datetime.from_string(fields.Datetime.now()) - event_date = fields.Datetime.from_string(self.event_begin_date) + today = fields.Datetime.now() + event_date = self.event_begin_date diff = (event_date.date() - today.date()) if diff.days <= 0: return _('today') diff --git a/addons/event/models/event_mail.py b/addons/event/models/event_mail.py index 680e1d4ba8a62..3c725af4dd151 100644 --- a/addons/event/models/event_mail.py +++ b/addons/event/models/event_mail.py @@ -97,7 +97,7 @@ def _compute_scheduled_date(self): else: date, sign = self.event_id.date_end, 1 - self.scheduled_date = datetime.strptime(date, tools.DEFAULT_SERVER_DATETIME_FORMAT) + _INTERVALS[self.interval_unit](sign * self.interval_nbr) + self.scheduled_date = date + _INTERVALS[self.interval_unit](sign * self.interval_nbr) @api.one def execute(self): @@ -190,7 +190,7 @@ def execute(self): def _compute_scheduled_date(self): if self.registration_id: date_open = self.registration_id.date_open - date_open_datetime = date_open and datetime.strptime(date_open, tools.DEFAULT_SERVER_DATETIME_FORMAT) or fields.datetime.now() + date_open_datetime = date_open or fields.Datetime.now() self.scheduled_date = date_open_datetime + _INTERVALS[self.scheduler_id.interval_unit](self.scheduler_id.interval_nbr) else: self.scheduled_date = False diff --git a/addons/event/tests/test_event_flow.py b/addons/event/tests/test_event_flow.py index 216a581538274..8d3d460462cab 100644 --- a/addons/event/tests/test_event_flow.py +++ b/addons/event/tests/test_event_flow.py @@ -120,7 +120,7 @@ def test_event_date_range(self): self.patcher = patch('odoo.addons.event.models.event.fields.Datetime', wraps=Datetime) self.mock_datetime = self.patcher.start() - self.mock_datetime.now.return_value = Datetime.to_string(datetime.datetime(2015, 12, 31, 12, 0)) + self.mock_datetime.now.return_value = datetime.datetime(2015, 12, 31, 12, 0) self.event_0.registration_ids.event_begin_date = datetime.datetime(2015, 12, 31, 18, 0) self.assertEqual(self.event_0.registration_ids.get_date_range_str(), u'today') @@ -131,7 +131,7 @@ def test_event_date_range(self): self.event_0.registration_ids.event_begin_date = datetime.datetime(2016, 1, 2, 6, 0) self.assertEqual(self.event_0.registration_ids.get_date_range_str(), u'in 2 days') - self.mock_datetime.now.return_value = Datetime.to_string(datetime.datetime(2015, 12, 10, 12, 0)) + self.mock_datetime.now.return_value = datetime.datetime(2015, 12, 10, 12, 0) self.event_0.registration_ids.event_begin_date = datetime.datetime(2016, 1, 25, 6, 0) self.assertEqual(self.event_0.registration_ids.get_date_range_str(), u'next month') diff --git a/addons/event/tests/test_mail_schedule.py b/addons/event/tests/test_mail_schedule.py index 010e5aa87a5d0..0e8f665f1d81a 100644 --- a/addons/event/tests/test_mail_schedule.py +++ b/addons/event/tests/test_mail_schedule.py @@ -13,7 +13,7 @@ class TestMailSchedule(TestEventCommon): @mute_logger('odoo.addons.base.models.ir_model', 'odoo.models') def test_00_event_mail_schedule(self): """ Test mail scheduling for events """ - now = fields.datetime.now() + now = fields.Datetime.now() event_date_begin = now + relativedelta(days=1) event_date_end = now + relativedelta(days=3) @@ -56,7 +56,7 @@ def test_00_event_mail_schedule(self): # verify that subscription scheduler was auto-executed after each registration self.assertEqual(len(schedulers[0].mail_registration_ids), 2, 'event: incorrect number of mail scheduled date') - mails = self.env['mail.mail'].search([('subject', 'ilike', 'registration'), ('date', '>=', datetime.datetime.strftime(now, tools.DEFAULT_SERVER_DATETIME_FORMAT))], order='date DESC', limit=3) + mails = self.env['mail.mail'].search([('subject', 'ilike', 'registration'), ('date', '>=', now)], order='date DESC', limit=3) self.assertEqual(len(mails), 2, 'event: wrong number of registration mail sent') for registration in schedulers[0].mail_registration_ids: @@ -65,7 +65,7 @@ def test_00_event_mail_schedule(self): # check before event scheduler schedulers = self.EventMail.search([('event_id', '=', test_event.id), ('interval_type', '=', 'before_event')]) self.assertEqual(len(schedulers), 1, 'event: wrong scheduler creation') - self.assertEqual(schedulers[0].scheduled_date, datetime.datetime.strftime(event_date_begin + relativedelta(days=-1), tools.DEFAULT_SERVER_DATETIME_FORMAT), 'event: incorrect scheduled date') + self.assertEqual(schedulers[0].scheduled_date, event_date_begin + relativedelta(days=-1), 'event: incorrect scheduled date') # execute event reminder scheduler explicitly schedulers[0].execute() @@ -73,7 +73,7 @@ def test_00_event_mail_schedule(self): self.assertTrue(schedulers[0].mail_sent, 'event: reminder scheduler should have sent an email') self.assertTrue(schedulers[0].done, 'event: reminder scheduler should be done') - mails = self.env['mail.mail'].search([('subject', 'ilike', 'TestEventMail'), ('date', '>=', datetime.datetime.strftime(now, tools.DEFAULT_SERVER_DATETIME_FORMAT))], order='date DESC', limit=3) + mails = self.env['mail.mail'].search([('subject', 'ilike', 'TestEventMail'), ('date', '>=', now)], order='date DESC', limit=3) self.assertEqual(len(mails), 3, 'event: wrong number of reminders in outgoing mail queue') diff --git a/addons/fleet/models/fleet_vehicle.py b/addons/fleet/models/fleet_vehicle.py index 6f19be439fc6d..609ecbe6e4f43 100644 --- a/addons/fleet/models/fleet_vehicle.py +++ b/addons/fleet/models/fleet_vehicle.py @@ -299,9 +299,9 @@ def _compute_vehicle_log_name(self): for record in self: name = record.vehicle_id.name if not name: - name = record.date + name = str(record.date) elif record.date: - name += ' / ' + record.date + name += ' / ' + str(record.date) record.name = name @api.onchange('vehicle_id') diff --git a/addons/fleet/models/fleet_vehicle_cost.py b/addons/fleet/models/fleet_vehicle_cost.py index 95d7b5fc9cadd..f066286c38840 100644 --- a/addons/fleet/models/fleet_vehicle_cost.py +++ b/addons/fleet/models/fleet_vehicle_cost.py @@ -145,7 +145,7 @@ def _compute_contract_name(self): if record.cost_subtype_id.name: name += ' / ' + record.cost_subtype_id.name if record.date: - name += ' / ' + record.date + name += ' / ' + str(record.date) record.name = name @api.depends('expiration_date', 'state') @@ -231,7 +231,7 @@ def scheduler_manage_auto_costs(self): if not contract.start_date or contract.cost_frequency == 'no': continue found = False - last_cost_date = contract.start_date + startdate = contract.start_date if contract.generated_cost_ids: last_autogenerated_cost = VehicleCost.search([ ('contract_id', '=', contract.id), @@ -239,12 +239,11 @@ def scheduler_manage_auto_costs(self): ], offset=0, limit=1, order='date desc') if last_autogenerated_cost: found = True - last_cost_date = last_autogenerated_cost.date - startdate = fields.Date.from_string(last_cost_date) + startdate = last_autogenerated_cost.date.date() if found: startdate += deltas.get(contract.cost_frequency) - today = fields.Date.from_string(fields.Date.context_today(self)) - while (startdate <= today) & (startdate <= fields.Date.from_string(contract.expiration_date)): + today = fields.Date.context_today(self) + while (startdate <= today) & (startdate <= contract.expiration_date): data = { 'amount': contract.cost_generated, 'date': fields.Date.context_today(self), diff --git a/addons/gamification/models/challenge.py b/addons/gamification/models/challenge.py index 93cd77a22cddc..48868407f249c 100644 --- a/addons/gamification/models/challenge.py +++ b/addons/gamification/models/challenge.py @@ -141,11 +141,11 @@ def _get_next_report_date(self): report period. """ for challenge in self: - last = fields.Datetime.from_string(challenge.last_report_date).date() + last = challenge.last_report_date offset = self.REPORT_OFFSETS.get(challenge.report_message_frequency) if offset: - challenge.next_report_date = fields.Date.to_string(last + offset) + challenge.next_report_date = last + offset else: challenge.next_report_date = False diff --git a/addons/google_calendar/models/google_calendar.py b/addons/google_calendar/models/google_calendar.py index a422438778ce5..b02f7586e75c2 100644 --- a/addons/google_calendar/models/google_calendar.py +++ b/addons/google_calendar/models/google_calendar.py @@ -193,12 +193,12 @@ class GoogleCalendar(models.AbstractModel): def generate_data(self, event, isCreating=False): if event.allday: start_date = event.start_date - final_date = (datetime.strptime(event.stop_date, tools.DEFAULT_SERVER_DATE_FORMAT) + timedelta(days=1)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT) + final_date = event.stop_date + timedelta(days=1) type = 'date' vstype = 'dateTime' else: - start_date = fields.Datetime.context_timestamp(self, fields.Datetime.from_string(event.start)).isoformat('T') - final_date = fields.Datetime.context_timestamp(self, fields.Datetime.from_string(event.stop)).isoformat('T') + start_date = fields.Datetime.context_timestamp(self, event.start).isoformat('T') + final_date = fields.Datetime.context_timestamp(self, event.stop).isoformat('T') type = 'dateTime' vstype = 'date' attendee_list = [] @@ -852,9 +852,9 @@ def update_events(self, lastSync=False): return True def check_and_sync(self, oe_event, google_event): - if datetime.strptime(oe_event.oe_update_date, "%Y-%m-%d %H:%M:%S.%f") > datetime.strptime(google_event['updated'], "%Y-%m-%dT%H:%M:%S.%fz"): + if oe_event.oe_update_date > datetime.strptime(google_event['updated'], "%Y-%m-%dT%H:%M:%S.%fz"): self.update_to_google(oe_event, google_event) - elif datetime.strptime(oe_event.oe_update_date, "%Y-%m-%d %H:%M:%S.%f") < datetime.strptime(google_event['updated'], "%Y-%m-%dT%H:%M:%S.%fz"): + elif oe_event.oe_update_date < datetime.strptime(google_event['updated'], "%Y-%m-%dT%H:%M:%S.%fz"): self.update_from_google(oe_event, google_event, 'write') def get_sequence(self, instance_id): diff --git a/addons/hr_attendance/models/hr_attendance.py b/addons/hr_attendance/models/hr_attendance.py index 7a88460c20a60..cadccfcf6d0e0 100644 --- a/addons/hr_attendance/models/hr_attendance.py +++ b/addons/hr_attendance/models/hr_attendance.py @@ -1,10 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from datetime import datetime - from odoo import models, fields, api, exceptions, _ -from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT class HrAttendance(models.Model): @@ -43,8 +40,7 @@ def name_get(self): def _compute_worked_hours(self): for attendance in self: if attendance.check_out: - delta = datetime.strptime(attendance.check_out, DEFAULT_SERVER_DATETIME_FORMAT) - datetime.strptime( - attendance.check_in, DEFAULT_SERVER_DATETIME_FORMAT) + delta = attendance.check_out - attendance.check_in attendance.worked_hours = delta.total_seconds() / 3600.0 @api.constrains('check_in', 'check_out') diff --git a/addons/hr_contract/tests/test_auto_status.py b/addons/hr_contract/tests/test_auto_status.py index fb755bdb82f63..efb7de51f9ae0 100644 --- a/addons/hr_contract/tests/test_auto_status.py +++ b/addons/hr_contract/tests/test_auto_status.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from datetime import datetime +from datetime import date, datetime from odoo.tests.common import TransactionCase from dateutil.relativedelta import relativedelta @@ -37,13 +37,13 @@ def test_contract_enddate(self): self.assertEquals(self.contract.state, 'close') def test_contract_pending_visa_expire(self): - self.employee.visa_expire = datetime.now() + relativedelta(days=30) + self.employee.visa_expire = date.today() + relativedelta(days=30) self.test_contract.update(dict(date_end=False)) self.contract = self.contracts.create(self.test_contract) self.apply_cron() self.assertEquals(self.contract.state, 'pending') - self.employee.visa_expire = datetime.now() + relativedelta(days=-5) + self.employee.visa_expire = date.today() + relativedelta(days=-5) self.test_contract.update({ 'date_start': datetime.now() + relativedelta(days=-50), 'state': 'pending', diff --git a/addons/hr_holidays/models/hr_leave.py b/addons/hr_holidays/models/hr_leave.py index 523f2b5a6952b..c2e2e2df44f07 100644 --- a/addons/hr_holidays/models/hr_leave.py +++ b/addons/hr_holidays/models/hr_leave.py @@ -376,12 +376,12 @@ def add_follower(self, employee_id): def _check_leave_type_validity(self): for leave in self: if leave.holiday_status_id.validity_start and leave.holiday_status_id.validity_stop: - vstart = fields.Datetime.from_string(leave.holiday_status_id.validity_start) - vstop = fields.Datetime.from_string(leave.holiday_status_id.validity_stop) - dfrom = fields.Datetime.from_string(leave.date_from) - dto = fields.Datetime.from_string(leave.date_to) + vstart = leave.holiday_status_id.validity_start + vstop = leave.holiday_status_id.validity_stop + dfrom = leave.date_from + dto = leave.date_to - if dfrom and dto and (dfrom < vstart or dto > vstop): + if dfrom and dto and (dfrom.date() < vstart or dto.date() > vstop): raise UserError(_('You can take %s only between %s and %s') % (leave.holiday_status_id.display_name, \ leave.holiday_status_id.validity_start, leave.holiday_status_id.validity_stop)) diff --git a/addons/hr_holidays/models/hr_leave_allocation.py b/addons/hr_holidays/models/hr_leave_allocation.py index 1f5274dda95bc..297a510030a50 100644 --- a/addons/hr_holidays/models/hr_leave_allocation.py +++ b/addons/hr_holidays/models/hr_leave_allocation.py @@ -288,9 +288,9 @@ def add_follower(self, employee_id): def _check_leave_type_validity(self): for allocation in self: if allocation.holiday_status_id.validity_start and allocation.holiday_status_id.validity_stop: - vstart = fields.Datetime.from_string(allocation.holiday_status_id.validity_start) - vstop = fields.Datetime.from_string(allocation.holiday_status_id.validity_stop) - today = fields.Datetime.from_string(fields.Datetime.now()) + vstart = allocation.holiday_status_id.validity_start + vstop = allocation.holiday_status_id.validity_stop + today = fields.Date.today() if vstart > today or vstop < today: raise UserError(_('You can allocate %s only between %s and %s') % (allocation.holiday_status_id.display_name, diff --git a/addons/hr_holidays/tests/test_accrual_allocations.py b/addons/hr_holidays/tests/test_accrual_allocations.py index 3a3d1150f3adc..8250f88f0a75b 100644 --- a/addons/hr_holidays/tests/test_accrual_allocations.py +++ b/addons/hr_holidays/tests/test_accrual_allocations.py @@ -90,7 +90,7 @@ def test_accrual_base_leaves(self): employee = self.env['hr.employee'].browse(self.employee_hruser_id) # Getting the previous work date - df = employee.resource_calendar_id.plan_days(-2, fields.Datetime.from_string(fields.Datetime.now())).date() + df = employee.resource_calendar_id.plan_days(-2, fields.Datetime.now()).date() leave_0 = Leave.create({ 'name': 'Leave for hruser', @@ -173,7 +173,7 @@ def test_accrual_new_employee(self): """ Allocation = self.env['hr.leave.allocation'].sudo(self.user_hrmanager_id).with_context(tracking_disable=True) - self.set_employee_create_date(self.employee_emp_id, fields.Datetime.now()) + self.set_employee_create_date(self.employee_emp_id, fields.Datetime.to_string(fields.Datetime.now())) alloc_0 = Allocation.create({ 'name': 'one shot one kill', diff --git a/addons/hr_recruitment/models/hr_recruitment.py b/addons/hr_recruitment/models/hr_recruitment.py index 67ca1548bfd04..6149bc159f704 100644 --- a/addons/hr_recruitment/models/hr_recruitment.py +++ b/addons/hr_recruitment/models/hr_recruitment.py @@ -1,9 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from datetime import datetime - -from odoo import api, fields, models, tools, SUPERUSER_ID +from odoo import api, fields, models, SUPERUSER_ID from odoo.tools.translate import _ from odoo.exceptions import UserError @@ -176,13 +174,13 @@ def _default_company_id(self): @api.one def _compute_day(self): if self.date_open: - date_create = datetime.strptime(self.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT) - date_open = datetime.strptime(self.date_open, tools.DEFAULT_SERVER_DATETIME_FORMAT) + date_create = self.create_date + date_open = self.date_open self.day_open = (date_open - date_create).total_seconds() / (24.0 * 3600) if self.date_closed: - date_create = datetime.strptime(self.create_date, tools.DEFAULT_SERVER_DATETIME_FORMAT) - date_closed = datetime.strptime(self.date_closed, tools.DEFAULT_SERVER_DATETIME_FORMAT) + date_create = self.create_date + date_closed = self.date_closed self.day_close = (date_closed - date_create).total_seconds() / (24.0 * 3600) self.delay_close = self.day_close - self.day_open diff --git a/addons/l10n_be_hr_payroll_fleet/models/fleet.py b/addons/l10n_be_hr_payroll_fleet/models/fleet.py index 4605584cb0dc3..c72f10117baf8 100644 --- a/addons/l10n_be_hr_payroll_fleet/models/fleet.py +++ b/addons/l10n_be_hr_payroll_fleet/models/fleet.py @@ -5,7 +5,7 @@ from odoo import api, fields, models -from odoo.fields import Datetime +from odoo.fields import Datetime, Date class FleetVehicle(models.Model): @@ -80,17 +80,18 @@ def create(self, vals): def _get_acquisition_date(self): self.ensure_one() return babel.dates.format_date( - date=Datetime.from_string(self.acquisition_date), + date=self.acquisition_date, format='MMMM y', locale=self._context.get('lang') or 'en_US' ) def _get_car_atn(self, acquisition_date, car_value, fuel_type, co2): # Compute the correction coefficient from the age of the car - now = Datetime.from_string(Datetime.now()) - start = Datetime.from_string(acquisition_date) - if start: - number_of_month = (now.year - start.year) * 12.0 + now.month - start.month + int(bool(now.day - start.day + 1)) + now = Date.today() + if acquisition_date: + number_of_month = ((now.year - acquisition_date.year) * 12.0 + now.month - + acquisition_date.month + + int(bool(now.day - acquisition_date.day + 1))) if number_of_month <= 12: age_coefficient = 1.00 elif number_of_month <= 24: diff --git a/addons/l10n_fr_fec/wizard/account_fr_fec.py b/addons/l10n_fr_fec/wizard/account_fr_fec.py index bd8e4cc44c0e6..b18518cffe0cb 100644 --- a/addons/l10n_fr_fec/wizard/account_fr_fec.py +++ b/addons/l10n_fr_fec/wizard/account_fr_fec.py @@ -5,11 +5,10 @@ import base64 import io -from datetime import datetime from odoo import api, fields, models, _ from odoo.exceptions import Warning -from odoo.tools import pycompat, DEFAULT_SERVER_DATE_FORMAT +from odoo.tools import pycompat class AccountFrFec(models.TransientModel): @@ -68,7 +67,7 @@ def do_query_unaffected_earnings(self): ''' company = self.env.user.company_id formatted_date_from = self.date_from.replace('-', '') - date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATE_FORMAT) + date_from = self.date_from formatted_date_year = date_from.year self._cr.execute( sql_query, (formatted_date_year, formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id)) @@ -174,7 +173,7 @@ def generate_fec(self): AND aat.type not in ('receivable', 'payable') ''' formatted_date_from = self.date_from.replace('-', '') - date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATE_FORMAT) + date_from = self.date_from formatted_date_year = date_from.year self._cr.execute( sql_query, (formatted_date_year, formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id)) diff --git a/addons/l10n_in_hr_payroll/report/report_payroll_advice.py b/addons/l10n_in_hr_payroll/report/report_payroll_advice.py index 0a29469440448..51bc88994ede0 100644 --- a/addons/l10n_in_hr_payroll/report/report_payroll_advice.py +++ b/addons/l10n_in_hr_payroll/report/report_payroll_advice.py @@ -2,7 +2,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import time -from datetime import datetime from odoo import api, models @@ -16,8 +15,8 @@ def get_month(self, input_date): } slip = self.env['hr.payslip'].search([('date_from', '<=', input_date), ('date_to', '>=', input_date)], limit=1) if slip: - from_date = datetime.strptime(slip.date_from, '%Y-%m-%d') - to_date = datetime.strptime(slip.date_to, '%Y-%m-%d') + from_date = slip.date_from + to_date = slip.date_to res['from_name'] = from_date.strftime('%d') + '-' + from_date.strftime('%B') + '-' + from_date.strftime('%Y') res['to_name'] = to_date.strftime('%d') + '-' + to_date.strftime('%B') + '-' + to_date.strftime('%Y') return res diff --git a/addons/lunch/models/lunch.py b/addons/lunch/models/lunch.py index 0108165c2b040..4decde206fda6 100644 --- a/addons/lunch/models/lunch.py +++ b/addons/lunch/models/lunch.py @@ -123,9 +123,9 @@ def _check_date(self): """ Prevents the user to create an order in the past """ - date_order = datetime.datetime.strptime(self.date, '%Y-%m-%d') - date_today = datetime.datetime.strptime(fields.Date.context_today(self), '%Y-%m-%d') - if (date_order < date_today): + date_order = self.date + date_today = fields.Date.context_today(self) + if date_order < date_today: raise ValidationError(_('The date of your order is in the past.')) @api.one diff --git a/addons/mail/models/mail_activity.py b/addons/mail/models/mail_activity.py index dbb56e2d132e5..72263a134c0d5 100644 --- a/addons/mail/models/mail_activity.py +++ b/addons/mail/models/mail_activity.py @@ -172,7 +172,9 @@ def _compute_state(self): def _onchange_activity_type_id(self): if self.activity_type_id: self.summary = self.activity_type_id.summary - self.date_deadline = (datetime.now() + timedelta(days=self.activity_type_id.days)) + # Date.context_today is correct because date_deadline is a Date and is meant to be + # expressed in user TZ + self.date_deadline = fields.Date.context_today(self) + timedelta(days=self.activity_type_id.days) @api.onchange('recommended_activity_type_id') def _onchange_recommended_activity_type_id(self): diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py index 97d141af0c76c..2aa38083d25b7 100644 --- a/addons/mail/models/mail_template.py +++ b/addons/mail/models/mail_template.py @@ -30,7 +30,7 @@ def format_date(env, date, pattern=False): def format_tz(env, dt, tz=False, format=False): record_user_timestamp = env.user.sudo().with_context(tz=tz or env.user.sudo().tz or 'UTC') - timestamp = datetime.datetime.strptime(dt, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timestamp = fields.Datetime.from_string(dt) ts = fields.Datetime.context_timestamp(record_user_timestamp, timestamp) diff --git a/addons/mail/models/mail_tracking_value.py b/addons/mail/models/mail_tracking_value.py index 5e758c45482e4..874ce4fde9a35 100644 --- a/addons/mail/models/mail_tracking_value.py +++ b/addons/mail/models/mail_tracking_value.py @@ -46,8 +46,8 @@ def create_tracking_values(self, initial_value, new_value, col_name, col_info, t }) elif col_info['type'] == 'date': values.update({ - 'old_value_datetime': initial_value and datetime.strftime(datetime.combine(datetime.strptime(initial_value, tools.DEFAULT_SERVER_DATE_FORMAT), datetime.min.time()), tools.DEFAULT_SERVER_DATETIME_FORMAT) or False, - 'new_value_datetime': new_value and datetime.strftime(datetime.combine(datetime.strptime(new_value, tools.DEFAULT_SERVER_DATE_FORMAT), datetime.min.time()), tools.DEFAULT_SERVER_DATETIME_FORMAT) or False, + 'old_value_datetime': initial_value and fields.Datetime.to_string(datetime.combine(fields.Date.from_string(initial_value), datetime.min.time())) or False, + 'new_value_datetime': new_value and fields.Datetime.to_string(datetime.combine(fields.Date.from_string(new_value), datetime.min.time())) or False, }) elif col_info['type'] == 'boolean': values.update({ @@ -88,8 +88,8 @@ def get_display_value(self, type): result.append(record['%s_value_datetime' % type]) elif record.field_type == 'date': if record['%s_value_datetime' % type]: - new_date = datetime.strptime(record['%s_value_datetime' % type], tools.DEFAULT_SERVER_DATETIME_FORMAT).date() - result.append(new_date.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)) + new_date = record['%s_value_datetime' % type] + result.append(fields.Date.to_string(new_date)) else: result.append(record['%s_value_datetime' % type]) elif record.field_type == 'boolean': diff --git a/addons/membership/models/account_invoice.py b/addons/membership/models/account_invoice.py index 85b158e495944..66e4942649f90 100644 --- a/addons/membership/models/account_invoice.py +++ b/addons/membership/models/account_invoice.py @@ -3,6 +3,8 @@ from odoo import api, fields, models +from datetime import date + class Invoice(models.Model): _inherit = 'account.invoice' @@ -36,7 +38,8 @@ def write(self, vals): # Product line has changed to a membership product date_from = line.product_id.membership_date_from date_to = line.product_id.membership_date_to - if line.invoice_id.date_invoice > (date_from or '0000-00-00') and line.invoice_id.date_invoice < (date_to or '0000-00-00'): + if (line.invoice_id.date_invoice > (date_from or date.min) and + line.invoice_id.date_invoice < (date_to or date.min)): date_from = line.invoice_id.date_invoice MemberLine.create({ 'partner': line.invoice_id.partner_id.id, @@ -62,7 +65,10 @@ def create(self, vals): # Product line is a membership product date_from = invoice_line.product_id.membership_date_from date_to = invoice_line.product_id.membership_date_to - if date_from and date_from < (invoice_line.invoice_id.date_invoice or '0000-00-00') < (date_to or '0000-00-00'): + if (date_from and + date_from < + (invoice_line.invoice_id.date_invoice or date.min) < + (date_to or date.min)): date_from = invoice_line.invoice_id.date_invoice MemberLine.create({ 'partner': invoice_line.invoice_id.partner_id.id, diff --git a/addons/mrp/tests/test_order.py b/addons/mrp/tests/test_order.py index 415014b6ba0fb..c3fc2a45ce3ca 100644 --- a/addons/mrp/tests/test_order.py +++ b/addons/mrp/tests/test_order.py @@ -59,7 +59,7 @@ def test_basic(self): }) inventory.action_validate() - test_date_planned = datetime.now() - timedelta(days=1) + test_date_planned = Dt.now() - timedelta(days=1) test_quantity = 2.0 self.bom_1.routing_id = False man_order = self.env['mrp.production'].sudo(self.user_mrp_user).create({ @@ -76,7 +76,7 @@ def test_basic(self): # check production move production_move = man_order.move_finished_ids - self.assertEqual(production_move.date, Dt.to_string(test_date_planned)) + self.assertEqual(production_move.date, test_date_planned) self.assertEqual(production_move.product_id, self.product_4) self.assertEqual(production_move.product_uom, man_order.product_uom_id) self.assertEqual(production_move.product_qty, man_order.product_qty) @@ -85,7 +85,7 @@ def test_basic(self): # check consumption moves for move in man_order.move_raw_ids: - self.assertEqual(move.date, Dt.to_string(test_date_planned)) + self.assertEqual(move.date, test_date_planned) first_move = man_order.move_raw_ids.filtered(lambda move: move.product_id == self.product_2) self.assertEqual(first_move.product_qty, test_quantity / self.bom_1.product_qty * self.product_4.uom_id.factor_inv * 2) first_move = man_order.move_raw_ids.filtered(lambda move: move.product_id == self.product_1) diff --git a/addons/point_of_sale/models/pos_config.py b/addons/point_of_sale/models/pos_config.py index 7d65a44b4026e..21f70997ea947 100644 --- a/addons/point_of_sale/models/pos_config.py +++ b/addons/point_of_sale/models/pos_config.py @@ -6,7 +6,6 @@ from odoo import api, fields, models, _ from odoo.exceptions import ValidationError -from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT class AccountCashboxLine(models.Model): @@ -209,7 +208,7 @@ def _compute_current_session_user(self): pos_config.pos_session_username = session[0].user_id.name pos_config.pos_session_state = session[0].state pos_config.pos_session_duration = ( - datetime.now() - datetime.strptime(session[0].start_at, DATETIME_FORMAT) + datetime.now() - session[0].start_at ).days if session[0].start_at else 0 else: pos_config.pos_session_username = False diff --git a/addons/point_of_sale/wizard/pos_payment.py b/addons/point_of_sale/wizard/pos_payment.py index e4b494baddea6..2b8a7eeb9a869 100644 --- a/addons/point_of_sale/wizard/pos_payment.py +++ b/addons/point_of_sale/wizard/pos_payment.py @@ -32,7 +32,7 @@ def _default_amount(self): journal_id = fields.Many2one('account.journal', string='Payment Mode', required=True, default=_default_journal) amount = fields.Float(digits=(16, 2), required=True, default=_default_amount) payment_name = fields.Char(string='Payment Reference') - payment_date = fields.Date(string='Payment Date', required=True, default=lambda *a: fields.Datetime.now()) + payment_date = fields.Date(string='Payment Date', required=True, default=lambda *a: fields.Date.today()) @api.onchange('session_id') def _on_change_session(self): diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 36b8aa3aa8ec1..30969fa29cdb7 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -171,7 +171,7 @@ def copy(self, default=None): for line in new_po.order_line: seller = line.product_id._select_seller( partner_id=line.partner_id, quantity=line.product_qty, - date=line.order_id.date_order and line.order_id.date_order[:10], uom_id=line.product_uom) + date=line.order_id.date_order and line.order_id.date_order.date(), uom_id=line.product_uom) line.date_planned = line._get_date_planned(seller) return new_po @@ -526,7 +526,7 @@ def _get_date_planned(self, seller, po=False): """ date_order = po.date_order if po else self.order_id.date_order if date_order: - return datetime.strptime(date_order, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=seller.delay if seller else 0) + return date_order + relativedelta(days=seller.delay if seller else 0) else: return datetime.today() + relativedelta(days=seller.delay if seller else 0) @@ -590,7 +590,7 @@ def _onchange_quantity(self): seller = self.product_id._select_seller( partner_id=self.partner_id, quantity=self.product_qty, - date=self.order_id.date_order and self.order_id.date_order[:10], + date=self.order_id.date_order and self.order_id.date_order.date(), uom_id=self.product_uom, params=params) diff --git a/addons/purchase_requisition/models/purchase_requisition.py b/addons/purchase_requisition/models/purchase_requisition.py index 0e96a3de9f707..d9b969ec5b91f 100644 --- a/addons/purchase_requisition/models/purchase_requisition.py +++ b/addons/purchase_requisition/models/purchase_requisition.py @@ -280,7 +280,7 @@ def _prepare_purchase_order_line(self, name, product_qty=0.0, price_unit=0.0, ta 'product_qty': product_qty, 'price_unit': price_unit, 'taxes_id': [(6, 0, taxes_ids)], - 'date_planned': requisition.schedule_date or fields.Date.today(), + 'date_planned': requisition.schedule_date or fields.Datetime.now(), 'account_analytic_id': self.account_analytic_id.id, 'analytic_tag_ids': self.analytic_tag_ids.ids, 'move_dest_ids': self.move_dest_id and [(4, self.move_dest_id.id)] or [] diff --git a/addons/purchase_stock/models/stock_rule.py b/addons/purchase_stock/models/stock_rule.py index b89361f7b5d68..1419f5566f883 100644 --- a/addons/purchase_stock/models/stock_rule.py +++ b/addons/purchase_stock/models/stock_rule.py @@ -98,7 +98,7 @@ def _update_purchase_order_line(self, product_id, product_qty, product_uom, valu seller = product_id._select_seller( partner_id=partner, quantity=line.product_qty + procurement_uom_po_qty, - date=line.order_id.date_order and line.order_id.date_order[:10], + date=line.order_id.date_order and line.order_id.date_order.date(), uom_id=product_id.uom_po_id) price_unit = self.env['account.tax']._fix_tax_included_price_company(seller.price, line.product_id.supplier_taxes_id, line.taxes_id, values['company_id']) if seller else 0.0 @@ -118,7 +118,7 @@ def _prepare_purchase_order_line(self, product_id, product_qty, product_uom, val seller = product_id._select_seller( partner_id=partner, quantity=procurement_uom_po_qty, - date=po.date_order and po.date_order[:10], + date=po.date_order and po.date_order.date(), uom_id=product_id.uom_po_id) taxes = product_id.supplier_taxes_id diff --git a/addons/purchase_stock/tests/test_purchase_lead_time.py b/addons/purchase_stock/tests/test_purchase_lead_time.py index f251cf4984d20..c7bad00f5abc6 100644 --- a/addons/purchase_stock/tests/test_purchase_lead_time.py +++ b/addons/purchase_stock/tests/test_purchase_lead_time.py @@ -29,19 +29,17 @@ def test_00_product_company_level_delays(self): # Check order date of purchase order order_date = fields.Datetime.from_string(date_planned) - timedelta(days=company.po_lead) - timedelta(days=self.product_1.seller_ids.delay) - po_order_date = fields.Datetime.to_string(order_date) - self.assertEqual(purchase.date_order, po_order_date, 'Order date should be equal to: Date of the procurement order - Purchase Lead Time - Delivery Lead Time.') + self.assertEqual(purchase.date_order, order_date, 'Order date should be equal to: Date of the procurement order - Purchase Lead Time - Delivery Lead Time.') # Check scheduled date of purchase order schedule_date = order_date + timedelta(days=self.product_1.seller_ids.delay) - po_schedule_date = fields.Datetime.to_string(schedule_date) - self.assertEqual(purchase.date_planned, po_schedule_date, 'Schedule date should be equal to: Order date of Purchase order + Delivery Lead Time.') + self.assertEqual(purchase.date_planned, schedule_date, 'Schedule date should be equal to: Order date of Purchase order + Delivery Lead Time.') # check the picking created or not self.assertTrue(purchase.picking_ids, "Picking should be created.") # Check scheduled date of In Type shipment - self.assertEqual(purchase.picking_ids.scheduled_date, po_schedule_date, 'Schedule date of In type shipment should be equal to: schedule date of purchase order.') + self.assertEqual(purchase.picking_ids.scheduled_date, schedule_date, 'Schedule date of In type shipment should be equal to: schedule date of purchase order.') def test_01_product_level_delay(self): """ To check schedule dates of multiple purchase order line of the same purchase order, @@ -68,21 +66,18 @@ def test_01_product_level_delay(self): order_line_pro_1 = purchase2.order_line.filtered(lambda r: r.product_id == self.product_1) order_line_pro_2 = purchase2.order_line.filtered(lambda r: r.product_id == self.product_2) order_date = fields.Datetime.from_string(date_planned1) - timedelta(days=self.product_1.seller_ids.delay) - po_order_date = fields.Datetime.to_string(order_date) - self.assertEqual(purchase2.date_order, po_order_date, 'Order date should be equal to: Date of the procurement order - Delivery Lead Time.') + self.assertEqual(purchase2.date_order, order_date, 'Order date should be equal to: Date of the procurement order - Delivery Lead Time.') # Check scheduled date of purchase order line for product_1 schedule_date_1 = order_date + timedelta(days=self.product_1.seller_ids.delay) - schedule_date_line_1 = fields.Datetime.to_string(schedule_date_1) - self.assertEqual(order_line_pro_1.date_planned, schedule_date_line_1, 'Schedule date of purchase order line for product_1 should be equal to: Order date of purchase order + Delivery Lead Time of product_1.') + self.assertEqual(order_line_pro_1.date_planned, schedule_date_1, 'Schedule date of purchase order line for product_1 should be equal to: Order date of purchase order + Delivery Lead Time of product_1.') # Check scheduled date of purchase order line for product_2 schedule_date_2 = order_date + timedelta(days=self.product_2.seller_ids.delay) - schedule_date_line_2 = fields.Datetime.to_string(schedule_date_2) - self.assertEqual(order_line_pro_2.date_planned, schedule_date_line_2, 'Schedule date of purchase order line for product_2 should be equal to: Order date of purchase order + Delivery Lead Time of product_2.') + self.assertEqual(order_line_pro_2.date_planned, schedule_date_2, 'Schedule date of purchase order line for product_2 should be equal to: Order date of purchase order + Delivery Lead Time of product_2.') # Check scheduled date of purchase order - po_schedule_date = min(schedule_date_line_1, schedule_date_line_2) + po_schedule_date = min(schedule_date_1, schedule_date_2) self.assertEqual(purchase2.date_planned, po_schedule_date, 'Schedule date of purchase order should be minimum of schedule dates of purchase order lines.') # Check the picking created or not @@ -121,13 +116,11 @@ def test_02_product_route_level_delays(self): # Check order date of purchase order order_date = fields.Datetime.from_string(date_planned) - timedelta(days=self.product_1.seller_ids.delay + rule_delay) - po_order_date = fields.Datetime.to_string(order_date) - self.assertEqual(purchase.date_order, po_order_date, 'Order date should be equal to: Date of the procurement order - Delivery Lead Time(supplier and pull rules).') + self.assertEqual(purchase.date_order, order_date, 'Order date should be equal to: Date of the procurement order - Delivery Lead Time(supplier and pull rules).') # Check scheduled date of purchase order schedule_date = order_date + timedelta(days=self.product_1.seller_ids.delay + rule_delay) - po_schedule_date = fields.Datetime.to_string(schedule_date) - self.assertEqual(date_planned, po_schedule_date, 'Schedule date should be equal to: Order date of Purchase order + Delivery Lead Time(supplier and pull rules).') + self.assertEqual(date_planned, str(schedule_date), 'Schedule date should be equal to: Order date of Purchase order + Delivery Lead Time(supplier and pull rules).') # Check the picking crated or not self.assertTrue(purchase.picking_ids, "Picking should be created.") @@ -135,10 +128,8 @@ def test_02_product_route_level_delays(self): # Check scheduled date of Internal Type shipment incoming_shipment1 = self.env['stock.picking'].search([('move_lines.product_id', 'in', (self.product_1.id, self.product_2.id)), ('picking_type_id', '=', self.warehouse_1.int_type_id.id), ('location_id', '=', self.warehouse_1.wh_input_stock_loc_id.id), ('location_dest_id', '=', self.warehouse_1.wh_qc_stock_loc_id.id)]) incoming_shipment1_date = order_date + timedelta(days=self.product_1.seller_ids.delay) - incoming_shipment1_schedule_date = fields.Datetime.to_string(incoming_shipment1_date) - self.assertEqual(incoming_shipment1.scheduled_date, incoming_shipment1_schedule_date, 'Schedule date of Internal Type shipment for input stock location should be equal to: schedule date of purchase order + push rule delay.') + self.assertEqual(incoming_shipment1.scheduled_date, incoming_shipment1_date, 'Schedule date of Internal Type shipment for input stock location should be equal to: schedule date of purchase order + push rule delay.') incoming_shipment2 = self.env['stock.picking'].search([('picking_type_id', '=', self.warehouse_1.int_type_id.id), ('location_id', '=', self.warehouse_1.wh_qc_stock_loc_id.id), ('location_dest_id', '=', self.warehouse_1.lot_stock_id.id)]) incoming_shipment2_date = schedule_date - timedelta(days=incoming_shipment2.move_lines[0].rule_id.delay) - incoming_shipment2_schedule_date = fields.Datetime.to_string(incoming_shipment2_date) - self.assertEqual(incoming_shipment2.scheduled_date, incoming_shipment2_schedule_date, 'Schedule date of Internal Type shipment for quality control stock location should be equal to: schedule date of Internal type shipment for input stock location + push rule delay..') + self.assertEqual(incoming_shipment2.scheduled_date, incoming_shipment2_date, 'Schedule date of Internal Type shipment for quality control stock location should be equal to: schedule date of Internal type shipment for input stock location + push rule delay..') diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index 6ae3a5ab513f7..e1d0f7319f65e 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -163,9 +163,9 @@ def _compute_access_url(self): order.access_url = '/my/orders/%s' % (order.id) def _compute_is_expired(self): - now = datetime.now() + today = fields.Date.today() for order in self: - if order.validity_date and fields.Datetime.from_string(order.validity_date) < now: + if order.validity_date and order.validity_date < today: order.is_expired = True else: order.is_expired = False diff --git a/addons/sale_order_dates/models/sale_order.py b/addons/sale_order_dates/models/sale_order.py index f02552adfdf78..aeb9982e03946 100644 --- a/addons/sale_order_dates/models/sale_order.py +++ b/addons/sale_order_dates/models/sale_order.py @@ -39,8 +39,8 @@ def _compute_expected_date(self): def _compute_effective_date(self): for order in self: pickings = order.picking_ids.filtered(lambda x: x.state == 'done' and x.location_dest_id.usage == 'customer') - dates_list = pickings.mapped('date_done') - order.effective_date = dates_list and min(dates_list) + dates_list = [date for date in pickings.mapped('date_done') if date] + order.effective_date = dates_list and min(dates_list).date() @api.onchange('commitment_date') def onchange_commitment_date(self): diff --git a/addons/sale_order_dates/tests/test_commitment_date.py b/addons/sale_order_dates/tests/test_commitment_date.py index 3b9494702ed53..d55b1d35134fc 100644 --- a/addons/sale_order_dates/tests/test_commitment_date.py +++ b/addons/sale_order_dates/tests/test_commitment_date.py @@ -17,6 +17,6 @@ def test_sale_order_commitment_date(self): # I verify that the Procurements and Stock Moves have been generated with the correct date security_delay = timedelta(days=new_order.company_id.security_lead) commitment_date = fields.Datetime.from_string(new_order.commitment_date) - right_date = fields.Datetime.to_string(commitment_date - security_delay) + right_date = commitment_date - security_delay for line in new_order.order_line: self.assertEqual(line.move_ids[0].date_expected, right_date, "The expected date for the Stock Move is wrong") diff --git a/addons/sale_order_dates/tests/test_expected_date.py b/addons/sale_order_dates/tests/test_expected_date.py index a565621cb4c7d..5286ee72dc25b 100644 --- a/addons/sale_order_dates/tests/test_expected_date.py +++ b/addons/sale_order_dates/tests/test_expected_date.py @@ -46,32 +46,36 @@ def test_sale_order_expected_date(self): # if Shipping Policy is set to `direct`(when SO is in draft state) then expected date should be # current date + shortest lead time from all of it's order lines - expected_date = fields.Datetime.to_string(fields.Datetime.from_string(fields.Datetime.now()) + timedelta(days=5)) - self.assertEquals(expected_date, sale_order.expected_date, "Wrong expected date on sale order!") + expected_date = fields.Datetime.now() + timedelta(days=5) + self.assertAlmostEqual(expected_date, sale_order.expected_date, + msg="Wrong expected date on sale order!", delta=timedelta(seconds=1)) # if Shipping Policy is set to `one`(when SO is in draft state) then expected date should be # current date + longest lead time from all of it's order lines sale_order.write({'picking_policy': 'one'}) - expected_date = fields.Datetime.to_string(fields.Datetime.from_string(fields.Datetime.now()) + timedelta(days=15)) - self.assertEquals(expected_date, sale_order.expected_date, "Wrong expected date on sale order!") + expected_date = fields.Datetime.now() + timedelta(days=15) + self.assertAlmostEquals(expected_date, sale_order.expected_date, + msg="Wrong expected date on sale order!", delta=timedelta(seconds=1)) sale_order.action_confirm() # Setting confirmation date of SO to 5 days from today so that the expected/effective date could be checked # against real confirmation date - confirm_date = fields.Datetime.from_string(fields.Datetime.now()) + timedelta(days=5) + confirm_date = fields.Datetime.now() + timedelta(days=5) sale_order.write({'confirmation_date': confirm_date}) # if Shipping Policy is set to `one`(when SO is confirmed) then expected date should be # SO confirmation date + longest lead time from all of it's order lines - expected_date = fields.Datetime.to_string(confirm_date + timedelta(days=15)) - self.assertEquals(expected_date, sale_order.expected_date, "Wrong expected date on sale order!") + expected_date = confirm_date + timedelta(days=15) + self.assertAlmostEqual(expected_date, sale_order.expected_date, + msg="Wrong expected date on sale order!", delta=timedelta(seconds=1)) # if Shipping Policy is set to `direct`(when SO is confirmed) then expected date should be # SO confirmation date + shortest lead time from all of it's order lines sale_order.write({'picking_policy': 'direct'}) - expected_date = fields.Datetime.to_string(confirm_date + timedelta(days=5)) - self.assertEquals(expected_date, sale_order.expected_date, "Wrong expected date on sale order!") + expected_date = confirm_date + timedelta(days=5) + self.assertAlmostEqual(expected_date, sale_order.expected_date, + msg="Wrong expected date on sale order!", delta=timedelta(seconds=1)) # Check effective date, it should be date on which the first shipment successfully delivered to customer picking = sale_order.picking_ids[0] diff --git a/addons/sale_stock/models/sale_order.py b/addons/sale_stock/models/sale_order.py index bb469c21b866b..43ce0fbbe1732 100644 --- a/addons/sale_stock/models/sale_order.py +++ b/addons/sale_stock/models/sale_order.py @@ -280,13 +280,13 @@ def _prepare_procurement_values(self, group_id=False): """ values = super(SaleOrderLine, self)._prepare_procurement_values(group_id) self.ensure_one() - date_planned = datetime.strptime(self.order_id.confirmation_date, DEFAULT_SERVER_DATETIME_FORMAT)\ + date_planned = self.order_id.confirmation_date\ + timedelta(days=self.customer_lead or 0.0) - timedelta(days=self.order_id.company_id.security_lead) values.update({ 'company_id': self.order_id.company_id, 'group_id': group_id, 'sale_line_id': self.id, - 'date_planned': date_planned.strftime(DEFAULT_SERVER_DATETIME_FORMAT), + 'date_planned': date_planned, 'route_ids': self.route_id, 'warehouse_id': self.order_id.warehouse_id or False, 'partner_dest_id': self.order_id.partner_shipping_id diff --git a/addons/stock/models/product.py b/addons/stock/models/product.py index 3a9b6f0fb0cf6..5c91fff6af294 100644 --- a/addons/stock/models/product.py +++ b/addons/stock/models/product.py @@ -93,7 +93,9 @@ def _compute_quantities_dict(self, lot_id, owner_id, package_id, from_date=False domain_quant_loc, domain_move_in_loc, domain_move_out_loc = self._get_domain_locations() domain_quant = [('product_id', 'in', self.ids)] + domain_quant_loc dates_in_the_past = False - if to_date and to_date < fields.Datetime.now(): #Only to_date as to_date will correspond to qty_available + # only to_date as to_date will correspond to qty_available + to_date = fields.Datetime.to_datetime(to_date) + if to_date and to_date < fields.Datetime.now(): dates_in_the_past = True domain_move_in = [('product_id', 'in', self.ids)] + domain_move_in_loc diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 35b18f0f0af8a..827f9c5a6ee01 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -426,11 +426,11 @@ def write(self, vals): if 'date_expected' in propagated_changes_dict: propagated_changes_dict.pop('date_expected') if propagated_date_field: - current_date = datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) - new_date = datetime.strptime(vals.get(propagated_date_field), DEFAULT_SERVER_DATETIME_FORMAT) + current_date = move.date_expected + new_date = fields.Datetime.from_string(vals.get(propagated_date_field)) delta_days = (new_date - current_date).total_seconds() / 86400 if abs(delta_days) >= move.company_id.propagation_minimum_delta: - old_move_date = datetime.strptime(move.move_dest_ids[0].date_expected, DEFAULT_SERVER_DATETIME_FORMAT) + old_move_date = move.move_dest_ids[0].date_expected new_move_date = (old_move_date + relativedelta.relativedelta(days=delta_days or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT) propagated_changes_dict['date_expected'] = new_move_date #For pushed moves as well as for pulled moves, propagate by recursive call of write(). diff --git a/addons/stock/models/stock_rule.py b/addons/stock/models/stock_rule.py index c2ea9f222931a..11beb7338a25d 100644 --- a/addons/stock/models/stock_rule.py +++ b/addons/stock/models/stock_rule.py @@ -136,7 +136,7 @@ def _run_push(self, move): Care this function is not call by method run. It is called explicitely in stock_move.py inside the method _push_apply """ - new_date = (datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta(days=self.delay)).strftime(DEFAULT_SERVER_DATETIME_FORMAT) + new_date = fields.Datetime.to_string(move.date_expected + relativedelta(days=self.delay)) if self.auto == 'transparent': move.write({ 'date': new_date, @@ -193,7 +193,9 @@ def _get_stock_move_values(self, product_id, product_qty, product_uom, location_ :param procurement: browse record :rtype: dictionary ''' - date_expected = (datetime.strptime(values['date_planned'], DEFAULT_SERVER_DATETIME_FORMAT) - relativedelta(days=self.delay or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT) + date_expected = fields.Datetime.to_string( + fields.Datetime.from_string(values['date_planned']) - relativedelta(days=self.delay or 0) + ) # it is possible that we've already got some move done, so check for the done qty and create # a new move with the correct qty qty_left = product_qty diff --git a/addons/stock/tests/test_move.py b/addons/stock/tests/test_move.py index a65365cc801ef..f3fee888e0de5 100644 --- a/addons/stock/tests/test_move.py +++ b/addons/stock/tests/test_move.py @@ -3602,8 +3602,9 @@ def test_in_date_2(self): ('product_id', '=', self.product3.id), ('lot_id', '=', lot1.id), ]) - from datetime import datetime, timedelta - initial_in_date_lot1 = datetime.now() - timedelta(days=5) + from odoo.fields import Datetime + from datetime import timedelta + initial_in_date_lot1 = Datetime.now() - timedelta(days=5) quant_lot1.in_date = initial_in_date_lot1 # Move one quant to pack location @@ -3626,8 +3627,7 @@ def test_in_date_2(self): # As lot1 has an older date and FIFO is set by default, it's the one that should be # in pack. self.assertEqual(len(quant_in_pack), 1) - from odoo.fields import Datetime - self.assertEqual(quant_in_pack.in_date, Datetime.to_string(initial_in_date_lot1)) + self.assertAlmostEqual(quant_in_pack.in_date, initial_in_date_lot1, delta=timedelta(seconds=1)) self.assertEqual(quant_in_pack.lot_id, lot1) # Now, edit the move line and actually move the other lot @@ -3640,7 +3640,7 @@ def test_in_date_2(self): ('lot_id', '=', lot1.id), ]) self.assertEqual(quant_lot1.location_id, self.stock_location) - self.assertEqual(quant_lot1.in_date, Datetime.to_string(initial_in_date_lot1)) + self.assertAlmostEqual(quant_lot1.in_date, initial_in_date_lot1, delta=timedelta(seconds=1)) # Check that lo2 is in pack with is right in_date quant_lot2 = self.env['stock.quant'].search([ @@ -3649,7 +3649,7 @@ def test_in_date_2(self): ('lot_id', '=', lot2.id), ]) self.assertEqual(quant_lot2.location_id, self.pack_location) - self.assertEqual(quant_lot2.in_date, initial_in_date_lot2) + self.assertAlmostEqual(quant_lot2.in_date, initial_in_date_lot2, delta=timedelta(seconds=1)) def test_in_date_3(self): """ Check that, when creating a move line on a done stock move, the lot and its incoming @@ -3707,8 +3707,9 @@ def test_in_date_3(self): ('product_id', '=', self.product3.id), ('lot_id', '=', lot1.id), ]) - from datetime import datetime, timedelta - initial_in_date_lot1 = datetime.now() - timedelta(days=5) + from odoo.fields import Datetime + from datetime import timedelta + initial_in_date_lot1 = Datetime.now() - timedelta(days=5) quant_lot1.in_date = initial_in_date_lot1 # Move one quant to pack location @@ -3741,12 +3742,11 @@ def test_in_date_3(self): ('product_id', '=', self.product3.id), ]) self.assertEqual(len(quants), 2) - from odoo.fields import Datetime for quant in quants: if quant.lot_id == lot1: - self.assertEqual(quant.in_date, Datetime.to_string(initial_in_date_lot1)) + self.assertAlmostEqual(quant.in_date, initial_in_date_lot1, delta=timedelta(seconds=1)) elif quant.lot_id == lot2: - self.assertEqual(quant.in_date, initial_in_date_lot2) + self.assertAlmostEqual(quant.in_date, initial_in_date_lot2, delta=timedelta(seconds=1)) def test_transit_1(self): """ Receive some products, send some to transit, check the product's `available_qty` diff --git a/addons/stock/tests/test_quant.py b/addons/stock/tests/test_quant.py index 9fb150341669d..749c10e57e3f1 100644 --- a/addons/stock/tests/test_quant.py +++ b/addons/stock/tests/test_quant.py @@ -763,7 +763,8 @@ def test_in_date_5(self): 'product_id': product1.id, }) - in_date1 = datetime.now() + from odoo.fields import Datetime + in_date1 = Datetime.now() self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0, lot_id=lot1, in_date=in_date1) quant = self.env['stock.quant'].search([ @@ -773,10 +774,9 @@ def test_in_date_5(self): self.assertEqual(len(quant), 1) self.assertEqual(quant.quantity, 1) self.assertEqual(quant.lot_id.id, lot1.id) - from odoo.fields import Datetime - self.assertEqual(quant.in_date, Datetime.to_string(in_date1)) + self.assertEqual(quant.in_date, in_date1) - in_date2 = datetime.now() - timedelta(days=5) + in_date2 = Datetime.now() - timedelta(days=5) self.env['stock.quant']._update_available_quantity(product1, stock_location, 1.0, lot_id=lot1, in_date=in_date2) quant = self.env['stock.quant'].search([ @@ -786,4 +786,4 @@ def test_in_date_5(self): self.assertEqual(len(quant), 1) self.assertEqual(quant.quantity, 2) self.assertEqual(quant.lot_id.id, lot1.id) - self.assertEqual(quant.in_date, Datetime.to_string(in_date2)) + self.assertEqual(quant.in_date, in_date2) diff --git a/addons/stock_account/tests/test_stockvaluation.py b/addons/stock_account/tests/test_stockvaluation.py index 200e91af00b5f..df22e8a382f48 100644 --- a/addons/stock_account/tests/test_stockvaluation.py +++ b/addons/stock_account/tests/test_stockvaluation.py @@ -4,7 +4,7 @@ from datetime import timedelta from odoo.exceptions import UserError -from odoo.fields import Date +from odoo.fields import Date, Datetime from odoo.tests.common import TransactionCase @@ -3260,7 +3260,7 @@ def test_move_in_or_out(self): def test_at_date_standard_1(self): self.product1.product_tmpl_id.cost_method = 'standard' - now = Date.from_string(Date.today()) + now = Datetime.now() date1 = now - timedelta(days=8) date2 = now - timedelta(days=7) date3 = now - timedelta(days=6) @@ -3387,42 +3387,42 @@ def test_at_date_standard_1(self): self.assertEqual(self.product1.stock_value, 712.5) # Quantity available at date - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).qty_available, 0) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_available, 10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).qty_available, 30) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).qty_available, 15) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).qty_available, 15) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_available, -5) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date7)).qty_available, -5) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date8)).qty_available, 95) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).qty_available, 0) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_available, 10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).qty_available, 30) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).qty_available, 15) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).qty_available, 15) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_available, -5) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date7)).qty_available, -5) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date8)).qty_available, 95) # Valuation at date - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).stock_value, 100) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).stock_value, 300) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).stock_value, 150) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).stock_value, 75) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).stock_value, -25) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date8)).stock_value, 712.5) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).stock_value, 100) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).stock_value, 300) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).stock_value, 150) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).stock_value, 75) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).stock_value, -25) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date8)).stock_value, 712.5) # Quantity at date - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date1)).qty_at_date, 0.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_at_date, 10.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date3)).qty_at_date, 30.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date4)).qty_at_date, 15.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date5)).qty_at_date, 15.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_at_date, -5.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date7)).qty_at_date, -5.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date8)).qty_at_date, 95.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).qty_at_date, 0.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_at_date, 10.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).qty_at_date, 30.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).qty_at_date, 15.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).qty_at_date, 15.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_at_date, -5.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date7)).qty_at_date, -5.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date8)).qty_at_date, 95.0) # edit the done quantity of move1, decrease it - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_available, 10) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_at_date, 10.0) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_available, 10) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_at_date, 10.0) move1.quantity_done = 5 move1.account_move_ids.write({'date': date2}) # the quantity at date will reflect the change directly - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_available, 5) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_at_date, 5.0) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_available, 5) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_at_date, 5.0) # as when we decrease a quantity on a recreipt, we consider it as a out move with the price # of today, the value will be decrease of 100 - (5*7.5) @@ -3430,22 +3430,22 @@ def test_at_date_standard_1(self): # the valuatin at date will take the qty at date * the standard price at date, that's why # it is different. - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).stock_value, 50) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).stock_value, 50) # edit move 4, send 15 instead of 20 # we now have +5 + 20 - 15 -20 = -10 * a standard price of 5 - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_available, -10.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_at_date, -10.0) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).stock_value, -50) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_available, -10.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_at_date, -10.0) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).stock_value, -50) move4.quantity_done = 15 move4.account_move_ids.write({'date': date6}) # -(20*5) + (5*7.5) self.assertEqual(move4.value, -62.5) # we now have +5 + 20 - 15 -15 = -5 * a standard price of 5 - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_available, -5.0) - self.assertAlmostEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_at_date, -5.0) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).stock_value, -25) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_available, -5.0) + self.assertAlmostEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_at_date, -5.0) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).stock_value, -25) def test_at_date_fifo_1(self): """ Make some operations at different dates, check that the results of the valuation at @@ -3454,7 +3454,7 @@ def test_at_date_fifo_1(self): """ self.product1.product_tmpl_id.cost_method = 'fifo' - now = Date.from_string(Date.today()) + now = Datetime.now() date1 = now - timedelta(days=8) date2 = now - timedelta(days=7) date3 = now - timedelta(days=6) @@ -3580,18 +3580,18 @@ def test_at_date_fifo_1(self): # ending: manual valuation # --------------------------------------------------------------------- self.product1.product_tmpl_id.valuation = 'manual_periodic' - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).qty_at_date, 20) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).stock_value, 200) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_at_date, 30) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).stock_value, 320) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).qty_at_date, 15) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).stock_value, 160) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).qty_at_date, -5) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).stock_value, -125) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).qty_at_date, 95) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).stock_value, 1375) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_at_date, 95) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).stock_value, 1375) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).qty_at_date, 20) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).stock_value, 200) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_at_date, 30) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).stock_value, 320) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).qty_at_date, 15) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).stock_value, 160) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).qty_at_date, -5) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).stock_value, -125) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).qty_at_date, 95) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).stock_value, 1375) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_at_date, 95) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).stock_value, 1375) self.assertEqual(self.product1.qty_at_date, 95) self.assertEqual(self.product1.stock_value, 1375) @@ -3599,25 +3599,25 @@ def test_at_date_fifo_1(self): # ending: perpetual valuation # --------------------------------------------------------------------- self.product1.product_tmpl_id.valuation = 'real_time' - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).qty_at_date, 10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).stock_value, 100) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_at_date, 20) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).stock_value, 220) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).qty_at_date, 5) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).stock_value, 60) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).qty_at_date, -15) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).stock_value, -180) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).qty_at_date, 85) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).stock_value, 1320) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_at_date, 85) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).stock_value, 1275) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).qty_at_date, 10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).stock_value, 100) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_at_date, 20) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).stock_value, 220) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).qty_at_date, 5) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).stock_value, 60) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).qty_at_date, -15) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).stock_value, -180) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).qty_at_date, 85) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).stock_value, 1320) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_at_date, 85) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).stock_value, 1275) self.assertEqual(self.product1.qty_at_date, 95) self.assertEqual(self.product1.stock_value, 1375) def test_at_date_fifo_2(self): self.product1.product_tmpl_id.cost_method = 'fifo' - now = Date.from_string(Date.today()) + now = Datetime.now() date1 = now - timedelta(days=8) date2 = now - timedelta(days=7) date3 = now - timedelta(days=6) @@ -3741,18 +3741,18 @@ def test_at_date_fifo_2(self): # ending: manual valuation # --------------------------------------------------------------------- self.product1.product_tmpl_id.valuation = 'manual_periodic' - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).qty_at_date, 10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).stock_value, 100) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_at_date, 20) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).stock_value, 250) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).qty_at_date, -10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).stock_value, -200) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).qty_at_date, 0) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).stock_value, 0) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).qty_at_date, 10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).stock_value, 100) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_at_date, 10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).stock_value, 100) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).qty_at_date, 10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).stock_value, 100) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_at_date, 20) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).stock_value, 250) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).qty_at_date, -10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).stock_value, -200) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).qty_at_date, 0) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).stock_value, 0) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).qty_at_date, 10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).stock_value, 100) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_at_date, 10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).stock_value, 100) self.assertEqual(self.product1.qty_at_date, 10) self.assertEqual(self.product1.stock_value, 100) @@ -3760,17 +3760,17 @@ def test_at_date_fifo_2(self): # ending: perpetual valuation # --------------------------------------------------------------------- self.product1.product_tmpl_id.valuation = 'real_time' - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).qty_at_date, 10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date1)).stock_value, 100) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).qty_at_date, 20) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date2)).stock_value, 250) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).qty_at_date, -10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date3)).stock_value, -150) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).qty_at_date, 0) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date4)).stock_value, 50) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).qty_at_date, 10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date5)).stock_value, 150) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).qty_at_date, 10) - self.assertEqual(self.product1.with_context(to_date=Date.to_string(date6)).stock_value, 100) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).qty_at_date, 10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date1)).stock_value, 100) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).qty_at_date, 20) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date2)).stock_value, 250) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).qty_at_date, -10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date3)).stock_value, -150) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).qty_at_date, 0) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date4)).stock_value, 50) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).qty_at_date, 10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date5)).stock_value, 150) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).qty_at_date, 10) + self.assertEqual(self.product1.with_context(to_date=Datetime.to_string(date6)).stock_value, 100) self.assertEqual(self.product1.qty_at_date, 10) self.assertEqual(self.product1.stock_value, 100) diff --git a/addons/stock_dropshipping/tests/test_lifo_price.py b/addons/stock_dropshipping/tests/test_lifo_price.py index ea9c424435423..a93c1c1a4e003 100644 --- a/addons/stock_dropshipping/tests/test_lifo_price.py +++ b/addons/stock_dropshipping/tests/test_lifo_price.py @@ -86,7 +86,7 @@ def test_lifoprice(self): with out_form.move_ids_without_package.new() as move: move.product_id = product_lifo_icecream move.quantity_done = 20.0 - move.date_expected = fields.Date.context_today(self.env['stock.move.line']) + move.date_expected = fields.Datetime.now() outgoing_lifo_shipment = out_form.save() # I assign this outgoing shipment diff --git a/addons/web/models/ir_qweb.py b/addons/web/models/ir_qweb.py index 757f30dc1e27e..34d2ecb0d5dd5 100644 --- a/addons/web/models/ir_qweb.py +++ b/addons/web/models/ir_qweb.py @@ -41,7 +41,7 @@ def record_to_html(self, record, field_name, options): if max_width or max_height: max_size = '%sx%s' % (max_width, max_height) - sha = hashlib.sha1(getattr(record, '__last_update').encode('utf-8')).hexdigest()[0:7] + sha = hashlib.sha1(str(getattr(record, '__last_update')).encode('utf-8')).hexdigest()[0:7] max_size = '' if max_size is None else '/%s' % max_size avoid_if_small = '&avoid_if_small=true' if options.get('avoid_if_small') else '' src = '/web/image/%s/%s/%s%s?unique=%s%s' % (record._name, record.id, field_name, max_size, sha, avoid_if_small) diff --git a/addons/website/models/website.py b/addons/website/models/website.py index 40c1ce0ae6eba..819d4777cdd91 100644 --- a/addons/website/models/website.py +++ b/addons/website/models/website.py @@ -540,7 +540,7 @@ def enumerate_pages(self, query_string=None, force=False): if page.view_id and page.view_id.priority != 16: record['__priority'] = min(round(page.view_id.priority / 32.0, 1), 1) if page['write_date']: - record['__lastmod'] = page['write_date'][:10] + record['__lastmod'] = page['write_date'].date() yield record @api.multi @@ -563,7 +563,7 @@ def search_pages(self, needle=None, limit=None): def image_url(self, record, field, size=None): """ Returns a local url that points to the image field of a given browse record. """ sudo_record = record.sudo() - sha = hashlib.sha1(getattr(sudo_record, '__last_update').encode('utf-8')).hexdigest()[0:7] + sha = hashlib.sha1(str(getattr(sudo_record, '__last_update')).encode('utf-8')).hexdigest()[0:7] size = '' if size is None else '/%s' % size return '/web/image/%s/%s/%s%s?unique=%s' % (record._name, record.id, field, size, sha) diff --git a/addons/website_blog/models/website_blog.py b/addons/website_blog/models/website_blog.py index 3741ee16035f7..6ff422579fd60 100644 --- a/addons/website_blog/models/website_blog.py +++ b/addons/website_blog/models/website_blog.py @@ -221,7 +221,8 @@ def write(self, vals): result = True for post in self: copy_vals = dict(vals) - if 'website_published' in vals and 'published_date' not in vals and (post.published_date or '') <= fields.Datetime.now(): + if ('website_published' in vals and 'published_date' not in vals and + (not post.published_date or post.published_date <= fields.Datetime.now())): copy_vals['published_date'] = vals['website_published'] and fields.Datetime.now() or False result &= super(BlogPost, self).write(copy_vals) self._check_for_publication(vals) diff --git a/addons/website_blog/views/website_blog_templates.xml b/addons/website_blog/views/website_blog_templates.xml index 248cd5dec155d..44d1d4a9ffa85 100644 --- a/addons/website_blog/views/website_blog_templates.xml +++ b/addons/website_blog/views/website_blog_templates.xml @@ -562,14 +562,14 @@