[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>
This commit is contained in:
committed by
Christophe Monniez
parent
da6c9027f4
commit
92a7f8c13f
@@ -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))
|
||||
|
||||
@@ -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']
|
||||
|
||||
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,
|
||||
})]
|
||||
})
|
||||
|
||||
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()
|
||||
|
||||
# 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_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'])
|
||||
|
||||
self.assertEqual(dashboard_data['number_waiting'], 0)
|
||||
self.assertIn('0.00', dashboard_data['sum_waiting'])
|
||||
# Check Both
|
||||
invoice.post()
|
||||
|
||||
# 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'])
|
||||
|
||||
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'])
|
||||
|
||||
self.assertEqual(dashboard_data['number_waiting'], 1)
|
||||
self.assertIn('81.72', dashboard_data['sum_waiting'])
|
||||
# Check waiting payment
|
||||
refund.post()
|
||||
|
||||
# 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'])
|
||||
|
||||
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'])
|
||||
|
||||
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()
|
||||
|
||||
# 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()
|
||||
|
||||
(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'])
|
||||
|
||||
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'])
|
||||
|
||||
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'])
|
||||
dashboard_data = journal.get_journal_dashboard_datas()
|
||||
self.assertEqual(dashboard_data['number_late'], 2)
|
||||
self.assertIn('78.42', dashboard_data['sum_late'])
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
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)
|
||||
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)
|
||||
|
||||
Vendored
+1
@@ -22,6 +22,7 @@ Depends:
|
||||
python3-decorator,
|
||||
python3-docutils,
|
||||
python3-feedparser,
|
||||
python3-freezegun,
|
||||
python3-html2text,
|
||||
python3-pil,
|
||||
python3-jinja2,
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -17,6 +17,7 @@ requires =
|
||||
python3-decorator
|
||||
python3-docutils
|
||||
python3-feedparser
|
||||
python3-freezegun
|
||||
python3-gevent
|
||||
python3-greenlet
|
||||
python3-html2text
|
||||
|
||||
Reference in New Issue
Block a user