From 92a7f8c13fa6bc84a66f973f9454971d346fd801 Mon Sep 17 00:00:00 2001 From: qdp-odoo <qdp@odoo.com> Date: Wed, 8 Jul 2020 12:36:17 +0000 Subject: [PATCH] [IMP] base, tests: use freezegun lib to mock dates and datetimes closes odoo/odoo#54227 Related: odoo/enterprise#11742 Signed-off-by: Olivier Dony (odo) <odo@openerp.com> --- addons/account/tests/common.py | 28 --- .../tests/test_account_journal_dashboard.py | 172 +++++++++--------- .../test_reconciliation_matching_rules.py | 5 +- .../account_edi_facturx/tests/test_facturx.py | 122 +++++++------ debian/control | 1 + requirements.txt | 1 + setup.cfg | 1 + setup.py | 2 +- 8 files changed, 155 insertions(+), 177 deletions(-) diff --git a/addons/account/tests/common.py b/addons/account/tests/common.py index 7bf7c391b186..0cebdeb16ee8 100644 --- a/addons/account/tests/common.py +++ b/addons/account/tests/common.py @@ -6,10 +6,7 @@ from odoo.tests.common import SavepointCase, HttpCase, tagged, Form import time import logging -import datetime -from contextlib import contextmanager -from unittest.mock import patch _logger = logging.getLogger(__name__) @@ -986,31 +983,6 @@ class AccountTestInvoicingCommon(SavepointCase): ], }) - @contextmanager - def mocked_today(self, forced_today): - ''' Helper to make easily a python "with statement" mocking the "today" date. - :param forced_today: The expected "today" date as a str or Date object. - :return: An object to be used like 'with self.mocked_today(<today>):'. - ''' - - if isinstance(forced_today, str): - forced_today_date = fields.Date.from_string(forced_today) - forced_today_datetime = fields.Datetime.from_string(forced_today) - elif isinstance(forced_today, datetime.datetime): - forced_today_datetime = forced_today - forced_today_date = forced_today_datetime.date() - else: - forced_today_date = forced_today - forced_today_datetime = datetime.datetime.combine(forced_today_date, datetime.time()) - - def today(*args, **kwargs): - return forced_today_date - - with patch.object(fields.Date, 'today', today): - with patch.object(fields.Date, 'context_today', today): - with patch.object(fields.Datetime, 'now', return_value=forced_today_datetime): - yield - @classmethod def init_invoice(cls, move_type, partner=None, invoice_date=None): move_form = Form(cls.env['account.move'].with_context(default_move_type=move_type)) diff --git a/addons/account/tests/test_account_journal_dashboard.py b/addons/account/tests/test_account_journal_dashboard.py index 41f7023ff76c..316b8a0ee84a 100644 --- a/addons/account/tests/test_account_journal_dashboard.py +++ b/addons/account/tests/test_account_journal_dashboard.py @@ -1,94 +1,94 @@ # -*- coding: utf-8 -*- +from freezegun import freeze_time + from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests import tagged - @tagged('post_install', '-at_install') class TestAccountJournalDashboard(AccountTestInvoicingCommon): + @freeze_time("2019-01-22") def test_customer_invoice_dashboard(self): - with self.mocked_today('2019-01-22'): - - journal = self.company_data['default_journal_sale'] - - invoice = self.env['account.move'].create({ - 'move_type': 'out_invoice', - 'journal_id': journal.id, - 'partner_id': self.partner_a.id, - 'invoice_date': '2019-01-21', - 'date': '2019-01-21', - 'invoice_line_ids': [(0, 0, { - 'product_id': self.product_a.id, - 'quantity': 40.0, - 'name': 'product test 1', - 'discount': 10.00, - 'price_unit': 2.27, - })] - }) - refund = self.env['account.move'].create({ - 'move_type': 'out_refund', - 'journal_id': journal.id, - 'partner_id': self.partner_a.id, - 'invoice_date': '2019-01-21', - 'date': '2019-01-21', - 'invoice_line_ids': [(0, 0, { - 'product_id': self.product_a.id, - 'quantity': 1.0, - 'name': 'product test 1', - 'price_unit': 13.3, - })] - }) - - # Check Draft - dashboard_data = journal.get_journal_dashboard_datas() - - self.assertEqual(dashboard_data['number_draft'], 2) - self.assertIn('68.42', dashboard_data['sum_draft']) - - self.assertEqual(dashboard_data['number_waiting'], 0) - self.assertIn('0.00', dashboard_data['sum_waiting']) - - # Check Both - invoice.post() - - dashboard_data = journal.get_journal_dashboard_datas() - self.assertEqual(dashboard_data['number_draft'], 1) - self.assertIn('-13.30', dashboard_data['sum_draft']) - - self.assertEqual(dashboard_data['number_waiting'], 1) - self.assertIn('81.72', dashboard_data['sum_waiting']) - - # Check waiting payment - refund.post() - - dashboard_data = journal.get_journal_dashboard_datas() - self.assertEqual(dashboard_data['number_draft'], 0) - self.assertIn('0.00', dashboard_data['sum_draft']) - - self.assertEqual(dashboard_data['number_waiting'], 2) - self.assertIn('68.42', dashboard_data['sum_waiting']) - - # Check partial - receivable_account = refund.line_ids.mapped('account_id').filtered(lambda a: a.internal_type == 'receivable') - payment = self.env['account.payment'].create({ - 'amount': 10.0, - 'payment_type': 'outbound', - 'partner_type': 'customer', - 'partner_id': self.partner_a.id, - }) - payment.action_post() - - (refund + payment.move_id).line_ids\ - .filtered(lambda line: line.account_internal_type == 'receivable')\ - .reconcile() - - dashboard_data = journal.get_journal_dashboard_datas() - self.assertEqual(dashboard_data['number_draft'], 0) - self.assertIn('0.00', dashboard_data['sum_draft']) - - self.assertEqual(dashboard_data['number_waiting'], 2) - self.assertIn('78.42', dashboard_data['sum_waiting']) - - dashboard_data = journal.get_journal_dashboard_datas() - self.assertEqual(dashboard_data['number_late'], 2) - self.assertIn('78.42', dashboard_data['sum_late']) + journal = self.company_data['default_journal_sale'] + + invoice = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'journal_id': journal.id, + 'partner_id': self.partner_a.id, + 'invoice_date': '2019-01-21', + 'date': '2019-01-21', + 'invoice_line_ids': [(0, 0, { + 'product_id': self.product_a.id, + 'quantity': 40.0, + 'name': 'product test 1', + 'discount': 10.00, + 'price_unit': 2.27, + })] + }) + refund = self.env['account.move'].create({ + 'move_type': 'out_refund', + 'journal_id': journal.id, + 'partner_id': self.partner_a.id, + 'invoice_date': '2019-01-21', + 'date': '2019-01-21', + 'invoice_line_ids': [(0, 0, { + 'product_id': self.product_a.id, + 'quantity': 1.0, + 'name': 'product test 1', + 'price_unit': 13.3, + })] + }) + + # Check Draft + dashboard_data = journal.get_journal_dashboard_datas() + + self.assertEqual(dashboard_data['number_draft'], 2) + self.assertIn('68.42', dashboard_data['sum_draft']) + + self.assertEqual(dashboard_data['number_waiting'], 0) + self.assertIn('0.00', dashboard_data['sum_waiting']) + + # Check Both + invoice.post() + + dashboard_data = journal.get_journal_dashboard_datas() + self.assertEqual(dashboard_data['number_draft'], 1) + self.assertIn('-13.30', dashboard_data['sum_draft']) + + self.assertEqual(dashboard_data['number_waiting'], 1) + self.assertIn('81.72', dashboard_data['sum_waiting']) + + # Check waiting payment + refund.post() + + dashboard_data = journal.get_journal_dashboard_datas() + self.assertEqual(dashboard_data['number_draft'], 0) + self.assertIn('0.00', dashboard_data['sum_draft']) + + self.assertEqual(dashboard_data['number_waiting'], 2) + self.assertIn('68.42', dashboard_data['sum_waiting']) + + # Check partial + receivable_account = refund.line_ids.mapped('account_id').filtered(lambda a: a.internal_type == 'receivable') + payment = self.env['account.payment'].create({ + 'amount': 10.0, + 'payment_type': 'outbound', + 'partner_type': 'customer', + 'partner_id': self.partner_a.id, + }) + payment.action_post() + + (refund + payment.move_id).line_ids\ + .filtered(lambda line: line.account_internal_type == 'receivable')\ + .reconcile() + + dashboard_data = journal.get_journal_dashboard_datas() + self.assertEqual(dashboard_data['number_draft'], 0) + self.assertIn('0.00', dashboard_data['sum_draft']) + + self.assertEqual(dashboard_data['number_waiting'], 2) + self.assertIn('78.42', dashboard_data['sum_waiting']) + + dashboard_data = journal.get_journal_dashboard_datas() + self.assertEqual(dashboard_data['number_late'], 2) + self.assertIn('78.42', dashboard_data['sum_late']) diff --git a/addons/account/tests/test_reconciliation_matching_rules.py b/addons/account/tests/test_reconciliation_matching_rules.py index fb3a902c8e9d..bb68dab220b8 100644 --- a/addons/account/tests/test_reconciliation_matching_rules.py +++ b/addons/account/tests/test_reconciliation_matching_rules.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- -from odoo import fields +from freezegun import freeze_time + from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests.common import Form from odoo.tests import tagged @@ -625,7 +626,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon): self.env['account.reconcile.model'].flush() - with self.mocked_today('2017-01-01'): + with freeze_time('2017-01-01'): self._check_statement_matching(matching_rule, { statement_line.id: {'aml_ids': (move_line_1 + move_line_2).ids, 'model': matching_rule} }, statements=statement) diff --git a/addons/account_edi_facturx/tests/test_facturx.py b/addons/account_edi_facturx/tests/test_facturx.py index 98a0f056ef54..faf1e89c38ed 100644 --- a/addons/account_edi_facturx/tests/test_facturx.py +++ b/addons/account_edi_facturx/tests/test_facturx.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- +from freezegun import freeze_time + from odoo.addons.account.tests.account_test_xml import AccountTestEdiCommon from odoo.tests import tagged @@ -151,74 +153,74 @@ class TestAccountEdiFacturx(AccountTestEdiCommon): </CrossIndustryInvoice> ''' + @freeze_time('2017-02-01') def test_facturx(self): ''' Test the generated Facturx Edi attachment without any modification of the invoice. ''' - with self.mocked_today('2017-02-01'): - self.invoice.post() + self.invoice.post() - xml_content = self.facturx_edi_format._export_invoice_to_attachment(self.invoice)['datas'] - current_etree = self.get_xml_tree_from_string(xml_content) - expected_etree = self.get_xml_tree_from_string(self.expected_invoice_facturx_values) - self.assertXmlTreeEqual(current_etree, expected_etree) + xml_content = self.facturx_edi_format._export_invoice_to_attachment(self.invoice)['datas'] + current_etree = self.get_xml_tree_from_string(xml_content) + expected_etree = self.get_xml_tree_from_string(self.expected_invoice_facturx_values) + self.assertXmlTreeEqual(current_etree, expected_etree) + @freeze_time('2017-02-01') def test_facturx_group_of_taxes(self): ''' Same as above with a group of taxes. ''' self.invoice.write({ 'invoice_line_ids': [(1, self.invoice.invoice_line_ids.id, {'tax_ids': [(6, 0, self.tax_group.ids)]})], }) - with self.mocked_today('2017-02-01'): - self.invoice.post() - - xml_content = self.facturx_edi_format._export_invoice_to_attachment(self.invoice)['datas'] - current_etree = self.get_xml_tree_from_string(xml_content) - expected_etree = self.with_applied_xpath( - self.get_xml_tree_from_string(self.expected_invoice_facturx_values), - ''' - <xpath expr="//GrossPriceProductTradePrice/ChargeAmount" position="replace"> - <ChargeAmount currencyID="Gol">275.000</ChargeAmount> - </xpath> - <xpath expr="//SpecifiedLineTradeSettlement" position="replace"> - <SpecifiedLineTradeSettlement> - <ApplicableTradeTax> - <RateApplicablePercent>10.0</RateApplicablePercent> - </ApplicableTradeTax> - <ApplicableTradeTax> - <RateApplicablePercent>20.0</RateApplicablePercent> - </ApplicableTradeTax> - <SpecifiedTradeSettlementLineMonetarySummation> - <LineTotalAmount currencyID="Gol">1000.000</LineTotalAmount> - </SpecifiedTradeSettlementLineMonetarySummation> - </SpecifiedLineTradeSettlement> - </xpath> - <xpath expr="//ApplicableHeaderTradeSettlement" position="replace"> - <ApplicableHeaderTradeSettlement> - <ApplicableTradeTax> - <CalculatedAmount currencyID="Gol">220.000</CalculatedAmount> - <BasisAmount currencyID="Gol">1100.000</BasisAmount> - <RateApplicablePercent>20.0</RateApplicablePercent> - </ApplicableTradeTax> - <ApplicableTradeTax> - <CalculatedAmount currencyID="Gol">100.000</CalculatedAmount> - <BasisAmount currencyID="Gol">1000.000</BasisAmount> - <RateApplicablePercent>10.0</RateApplicablePercent> - </ApplicableTradeTax> - <SpecifiedTradePaymentTerms> - <DueDateDateTime> - <DateTimeString>20170101</DateTimeString> - </DueDateDateTime> - </SpecifiedTradePaymentTerms> - <SpecifiedTradeSettlementHeaderMonetarySummation> - <LineTotalAmount currencyID="Gol">1000.000</LineTotalAmount> - <TaxBasisTotalAmount currencyID="Gol">1000.000</TaxBasisTotalAmount> - <TaxTotalAmount currencyID="Gol">320.000</TaxTotalAmount> - <GrandTotalAmount currencyID="Gol">1320.000</GrandTotalAmount> - <TotalPrepaidAmount currencyID="Gol">0.000</TotalPrepaidAmount> - <DuePayableAmount currencyID="Gol">1320.000</DuePayableAmount> - </SpecifiedTradeSettlementHeaderMonetarySummation> - </ApplicableHeaderTradeSettlement> - </xpath> - ''', - ) - self.assertXmlTreeEqual(current_etree, expected_etree) + self.invoice.post() + + xml_content = self.facturx_edi_format._export_invoice_to_attachment(self.invoice)['datas'] + current_etree = self.get_xml_tree_from_string(xml_content) + expected_etree = self.with_applied_xpath( + self.get_xml_tree_from_string(self.expected_invoice_facturx_values), + ''' + <xpath expr="//GrossPriceProductTradePrice/ChargeAmount" position="replace"> + <ChargeAmount currencyID="Gol">275.000</ChargeAmount> + </xpath> + <xpath expr="//SpecifiedLineTradeSettlement" position="replace"> + <SpecifiedLineTradeSettlement> + <ApplicableTradeTax> + <RateApplicablePercent>10.0</RateApplicablePercent> + </ApplicableTradeTax> + <ApplicableTradeTax> + <RateApplicablePercent>20.0</RateApplicablePercent> + </ApplicableTradeTax> + <SpecifiedTradeSettlementLineMonetarySummation> + <LineTotalAmount currencyID="Gol">1000.000</LineTotalAmount> + </SpecifiedTradeSettlementLineMonetarySummation> + </SpecifiedLineTradeSettlement> + </xpath> + <xpath expr="//ApplicableHeaderTradeSettlement" position="replace"> + <ApplicableHeaderTradeSettlement> + <ApplicableTradeTax> + <CalculatedAmount currencyID="Gol">220.000</CalculatedAmount> + <BasisAmount currencyID="Gol">1100.000</BasisAmount> + <RateApplicablePercent>20.0</RateApplicablePercent> + </ApplicableTradeTax> + <ApplicableTradeTax> + <CalculatedAmount currencyID="Gol">100.000</CalculatedAmount> + <BasisAmount currencyID="Gol">1000.000</BasisAmount> + <RateApplicablePercent>10.0</RateApplicablePercent> + </ApplicableTradeTax> + <SpecifiedTradePaymentTerms> + <DueDateDateTime> + <DateTimeString>20170101</DateTimeString> + </DueDateDateTime> + </SpecifiedTradePaymentTerms> + <SpecifiedTradeSettlementHeaderMonetarySummation> + <LineTotalAmount currencyID="Gol">1000.000</LineTotalAmount> + <TaxBasisTotalAmount currencyID="Gol">1000.000</TaxBasisTotalAmount> + <TaxTotalAmount currencyID="Gol">320.000</TaxTotalAmount> + <GrandTotalAmount currencyID="Gol">1320.000</GrandTotalAmount> + <TotalPrepaidAmount currencyID="Gol">0.000</TotalPrepaidAmount> + <DuePayableAmount currencyID="Gol">1320.000</DuePayableAmount> + </SpecifiedTradeSettlementHeaderMonetarySummation> + </ApplicableHeaderTradeSettlement> + </xpath> + ''', + ) + self.assertXmlTreeEqual(current_etree, expected_etree) diff --git a/debian/control b/debian/control index c8fdd67b96c9..3b5cb117ef89 100644 --- a/debian/control +++ b/debian/control @@ -22,6 +22,7 @@ Depends: python3-decorator, python3-docutils, python3-feedparser, + python3-freezegun, python3-html2text, python3-pil, python3-jinja2, diff --git a/requirements.txt b/requirements.txt index 693b83479077..26fb9582b70a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ decorator==4.3.0 docutils==0.14 ebaysdk==2.1.5 feedparser==5.2.1 +freezegun==0.3.11 gevent==1.1.2 ; sys_platform != 'win32' and python_version < '3.7' gevent==1.3.7 ; sys_platform != 'win32' and python_version >= '3.7' gevent==1.4.0 ; sys_platform == 'win32' diff --git a/setup.cfg b/setup.cfg index 0523f3f81c1b..5881e460d350 100644 --- a/setup.cfg +++ b/setup.cfg @@ -17,6 +17,7 @@ requires = python3-decorator python3-docutils python3-feedparser + python3-freezegun python3-gevent python3-greenlet python3-html2text diff --git a/setup.py b/setup.py index 6142915cdded..355d07c71fa2 100644 --- a/setup.py +++ b/setup.py @@ -64,6 +64,6 @@ setup( 'SSL': ['pyopenssl'], }, tests_require=[ - 'mock', + 'freezegun', ], ) -- GitLab