From 002f89bd84d45d5657fa1e2ddac57d83b0c07248 Mon Sep 17 00:00:00 2001 From: wan Date: Fri, 2 Apr 2021 10:33:24 +0000 Subject: [PATCH] [FIX] account: never set default for invoice_date MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For customer invoices: * do not set default date because if you prepare an invoice (and it gets a default date), then validate it the next day, the date will be wrong * set the date when posting if it wasn't set, because why not? For vendor bills: * do not set default date because you rarely encode a bill at the bill date. Forcing the user to enter it reduces risks of user error (duplicated vendor bill) * do not set it when posting, same reason. opw-2492862 Related #68368 Closes #68367 closes odoo/odoo#69639 X-original-commit: 41041d8016d11f017d92d28f32ab2cf42f1349a9 Related: odoo/enterprise#17866 Signed-off-by: Laurent Smet Signed-off-by: William André (wan) --- addons/account/i18n/account.pot | 6 ++++++ addons/account/models/account_move.py | 20 +++++++++++++------ .../tests/test_product_margin.py | 1 + .../tests/test_purchase_order_report.py | 1 + .../tests/test_purchase_order.py | 2 ++ .../tests/test_stockvaluation.py | 7 +++++++ addons/sale/tests/test_reinvoice.py | 7 ++++++- addons/sale/tests/test_sale_order.py | 1 + addons/sale_timesheet/tests/test_reinvoice.py | 17 ++++++++++------ .../tests/test_stockvaluation.py | 1 + .../tests/test_stock_landed_costs_purchase.py | 1 + .../tests/test_stockvaluationlayer.py | 7 ++++++- .../static/tests/tours/main_flow.js | 9 +++++++++ 13 files changed, 66 insertions(+), 14 deletions(-) diff --git a/addons/account/i18n/account.pot b/addons/account/i18n/account.pot index ef2840dbafe..4ac8cfa3d01 100644 --- a/addons/account/i18n/account.pot +++ b/addons/account/i18n/account.pot @@ -11561,6 +11561,12 @@ msgid "" " for vendor/customer accounts." msgstr "" +#. module: account +#: code:addons/account/models/account_move.py:0 +#, python-format +msgid "The Bill/Refund date is required to validate this document." +msgstr "" + #. module: account #: model:ir.model.fields,help:account.field_account_bank_statement__country_code #: model:ir.model.fields,help:account.field_account_bank_statement_line__country_code diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 3b9ac529ba8..5607fbf28aa 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -113,8 +113,10 @@ class AccountMove(models.Model): return journal + # TODO remove in master @api.model def _get_default_invoice_date(self): + warnings.warn("Method '_get_default_invoice_date()' is deprecated and has been removed.", DeprecationWarning) return fields.Date.context_today(self) if self._context.get('default_move_type', 'entry') in self.get_purchase_types(include_receipts=True) else False @api.model @@ -274,8 +276,7 @@ class AccountMove(models.Model): string='Salesperson', default=lambda self: self.env.user) invoice_date = fields.Date(string='Invoice/Bill Date', readonly=True, index=True, copy=False, - states={'draft': [('readonly', False)]}, - default=_get_default_invoice_date) + states={'draft': [('readonly', False)]}) invoice_date_due = fields.Date(string='Due Date', readonly=True, index=True, copy=False, states={'draft': [('readonly', False)]}) invoice_origin = fields.Char(string='Origin', readonly=True, tracking=True, @@ -1668,7 +1669,11 @@ class AccountMove(models.Model): duplicated_moves = self.browse([r[0] for r in self._cr.fetchall()]) if duplicated_moves: raise ValidationError(_('Duplicated vendor reference detected. You probably encoded twice the same vendor bill/credit note:\n%s') % "\n".join( - duplicated_moves.mapped(lambda m: "%(partner)s - %(ref)s - %(date)s" % {'ref': m.ref, 'partner': m.partner_id.display_name, 'date': format_date(self.env, m.date)}) + duplicated_moves.mapped(lambda m: "%(partner)s - %(ref)s - %(date)s" % { + 'ref': m.ref, + 'partner': m.partner_id.display_name, + 'date': format_date(self.env, m.invoice_date), + }) )) def _check_balanced(self): @@ -2515,9 +2520,12 @@ class AccountMove(models.Model): # lines are recomputed accordingly. # /!\ 'check_move_validity' must be there since the dynamic lines will be recomputed outside the 'onchange' # environment. - if not move.invoice_date and move.is_invoice(include_receipts=True): - move.invoice_date = fields.Date.context_today(self) - move.with_context(check_move_validity=False)._onchange_invoice_date() + if not move.invoice_date: + if move.is_sale_document(include_receipts=True): + move.invoice_date = fields.Date.context_today(self) + move.with_context(check_move_validity=False)._onchange_invoice_date() + elif move.is_purchase_document(include_receipts=True): + raise UserError(_("The Bill/Refund date is required to validate this document.")) # When the accounting date is prior to the tax lock date, move it automatically to today. # /!\ 'check_move_validity' must be there since the dynamic lines will be recomputed outside the 'onchange' diff --git a/addons/product_margin/tests/test_product_margin.py b/addons/product_margin/tests/test_product_margin.py index 17f6f376988..161b09d3f50 100644 --- a/addons/product_margin/tests/test_product_margin.py +++ b/addons/product_margin/tests/test_product_margin.py @@ -40,6 +40,7 @@ class TestProductMargin(AccountTestInvoicingCommon): 'invoice_line_ids': [(0, 0, {'product_id': ipad.id, 'quantity': 10.0, 'price_unit': 550.0})], }, ]) + invoices.invoice_date = invoices[0].date invoices.action_post() result = ipad._compute_product_margin_fields_values() diff --git a/addons/purchase/tests/test_purchase_order_report.py b/addons/purchase/tests/test_purchase_order_report.py index e3df301e813..8b38611373a 100644 --- a/addons/purchase/tests/test_purchase_order_report.py +++ b/addons/purchase/tests/test_purchase_order_report.py @@ -39,6 +39,7 @@ class TestPurchaseOrderReport(AccountTestInvoicingCommon): po.button_confirm() f = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + f.invoice_date = f.date f.partner_id = po.partner_id f.purchase_id = po invoice = f.save() diff --git a/addons/purchase_stock/tests/test_purchase_order.py b/addons/purchase_stock/tests/test_purchase_order.py index ddb5dd80ceb..7d98d24792e 100644 --- a/addons/purchase_stock/tests/test_purchase_order.py +++ b/addons/purchase_stock/tests/test_purchase_order.py @@ -106,6 +106,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon): #After Receiving all products create vendor bill. move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form.invoice_date = move_form.date move_form.partner_id = self.partner_a move_form.purchase_id = self.po self.invoice = move_form.save() @@ -136,6 +137,7 @@ class TestPurchaseOrder(ValuationReconciliationTestCommon): self.assertEqual(self.po.order_line[0].qty_received, 3.0, 'Purchase: delivered quantity should be 3.0 instead of "%s" after picking return' % self.po.order_line[0].qty_received) #Create vendor bill for refund qty move_form = Form(self.env['account.move'].with_context(default_move_type='in_refund')) + move_form.invoice_date = move_form.date move_form.partner_id = self.partner_a move_form.purchase_id = self.po self.invoice = move_form.save() diff --git a/addons/purchase_stock/tests/test_stockvaluation.py b/addons/purchase_stock/tests/test_stockvaluation.py index 24f01a2ccb1..fba2382c435 100644 --- a/addons/purchase_stock/tests/test_stockvaluation.py +++ b/addons/purchase_stock/tests/test_stockvaluation.py @@ -379,6 +379,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): receipt_po1.button_validate() move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form.invoice_date = move_form.date move_form.partner_id = self.partner_id move_form.purchase_id = po1 invoice_po1 = move_form.save() @@ -404,6 +405,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): receipt_po2.button_validate() move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form.invoice_date = move_form.date move_form.partner_id = self.partner_id move_form.purchase_id = po2 invoice_po2 = move_form.save() @@ -428,6 +430,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): # create a credit note for po2 move_form = Form(self.env['account.move'].with_context(default_move_type='in_refund')) + move_form.invoice_date = move_form.date move_form.partner_id = self.partner_id move_form.purchase_id = po2 with move_form.invoice_line_ids.edit(0) as line_form: @@ -462,6 +465,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): # Create an invoice with a different price move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form.invoice_date = move_form.date move_form.partner_id = order.partner_id move_form.purchase_id = order with move_form.invoice_line_ids.edit(0) as line_form: @@ -1211,6 +1215,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): # Create an invoice with a different price and a discount invoice_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + invoice_form.invoice_date = invoice_form.date invoice_form.purchase_id = order with invoice_form.invoice_line_ids.edit(0) as line_form: line_form.price_unit = 100.0 @@ -1257,6 +1262,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): # Create an invoice with a different price and a discount invoice_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + invoice_form.invoice_date = invoice_form.date invoice_form.purchase_id = order with invoice_form.invoice_line_ids.edit(0) as line_form: line_form.tax_ids.clear() @@ -1303,6 +1309,7 @@ class TestStockValuationWithCOA(AccountTestInvoicingCommon): # Create an invoice with a different price and a discount invoice_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + invoice_form.invoice_date = invoice_form.date invoice_form.purchase_id = order with invoice_form.invoice_line_ids.edit(0) as line_form: line_form.price_unit = 100.0 diff --git a/addons/sale/tests/test_reinvoice.py b/addons/sale/tests/test_reinvoice.py index 477004a22c4..0ecb15ed54d 100644 --- a/addons/sale/tests/test_reinvoice.py +++ b/addons/sale/tests/test_reinvoice.py @@ -26,7 +26,12 @@ class TestReInvoice(TestSaleCommon): 'pricelist_id': cls.company_data['default_pricelist'].id, }) - cls.AccountMove = cls.env['account.move'].with_context(default_move_type='in_invoice', mail_notrack=True, mail_create_nolog=True) + cls.AccountMove = cls.env['account.move'].with_context( + default_move_type='in_invoice', + default_invoice_date=cls.sale_order.date_order, + mail_notrack=True, + mail_create_nolog=True, + ) def test_at_cost(self): """ Test vendor bill at cost for product based on ordered and delivered quantities. """ diff --git a/addons/sale/tests/test_sale_order.py b/addons/sale/tests/test_sale_order.py index 77055cb9939..70be53ea68b 100644 --- a/addons/sale/tests/test_sale_order.py +++ b/addons/sale/tests/test_sale_order.py @@ -240,6 +240,7 @@ class TestSaleOrder(TestSaleCommon): inv = self.env['account.move'].with_context(default_move_type='in_invoice').create({ 'partner_id': self.partner_a.id, + 'invoice_date': so.date_order, 'invoice_line_ids': [ (0, 0, { 'name': serv_cost.name, diff --git a/addons/sale_timesheet/tests/test_reinvoice.py b/addons/sale_timesheet/tests/test_reinvoice.py index 0ea1087d926..0b85f45093e 100644 --- a/addons/sale_timesheet/tests/test_reinvoice.py +++ b/addons/sale_timesheet/tests/test_reinvoice.py @@ -40,7 +40,12 @@ class TestReInvoice(TestCommonSaleTimesheet): 'pricelist_id': cls.company_data['default_pricelist'].id, }) - cls.Invoice = cls.env['account.move'].with_context(mail_notrack=True, mail_create_nolog=True) + cls.Invoice = cls.env['account.move'].with_context( + default_move_type='in_invoice', + default_invoice_date=cls.sale_order.date_order, + mail_notrack=True, + mail_create_nolog=True, + ) def test_at_cost(self): """ Test vendor bill at cost for product based on ordered and delivered quantities. """ @@ -82,7 +87,7 @@ class TestReInvoice(TestCommonSaleTimesheet): 'company_id': self.company_data['company'].id, }) - move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form = Form(self.Invoice) move_form.partner_id = self.partner_a with move_form.line_ids.new() as line_form: line_form.product_id = self.company_data['product_order_cost'] @@ -117,7 +122,7 @@ class TestReInvoice(TestCommonSaleTimesheet): self.assertEqual(sale_order_line4.qty_delivered_method, 'analytic', "Delivered quantity of 'expense' SO line should be computed by analytic amount") # create second invoice lines and validate it - move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form = Form(self.Invoice) move_form.partner_id = self.partner_a with move_form.line_ids.new() as line_form: line_form.product_id = self.company_data['product_order_cost'] @@ -181,7 +186,7 @@ class TestReInvoice(TestCommonSaleTimesheet): }) # create invoice lines and validate it - move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form = Form(self.Invoice) move_form.partner_id = self.partner_a with move_form.line_ids.new() as line_form: line_form.product_id = self.company_data['product_delivery_sales_price'] @@ -216,7 +221,7 @@ class TestReInvoice(TestCommonSaleTimesheet): self.assertEqual(sale_order_line4.qty_delivered_method, 'analytic', "Delivered quantity of 'expense' SO line 4 should be computed by analytic amount") # create second invoice lines and validate it - move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form = Form(self.Invoice) move_form.partner_id = self.partner_a with move_form.line_ids.new() as line_form: line_form.product_id = self.company_data['product_delivery_sales_price'] @@ -256,7 +261,7 @@ class TestReInvoice(TestCommonSaleTimesheet): self.sale_order.action_confirm() # create invoice lines and validate it - move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form = Form(self.Invoice) move_form.partner_id = self.partner_a with move_form.line_ids.new() as line_form: line_form.product_id = self.company_data['product_order_no'] diff --git a/addons/stock_dropshipping/tests/test_stockvaluation.py b/addons/stock_dropshipping/tests/test_stockvaluation.py index f4709c03829..b1ac78d2003 100644 --- a/addons/stock_dropshipping/tests/test_stockvaluation.py +++ b/addons/stock_dropshipping/tests/test_stockvaluation.py @@ -69,6 +69,7 @@ class TestStockValuation(ValuationReconciliationTestCommon): move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) move_form.partner_id = vendor1 move_form.purchase_id = self.purchase_order1 + move_form.invoice_date = move_form.date for i in range(len(self.purchase_order1.order_line)): with move_form.invoice_line_ids.edit(i) as line_form: line_form.tax_ids.clear() diff --git a/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py b/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py index 2c879fae12b..f18ec214707 100644 --- a/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py +++ b/addons/stock_landed_costs/tests/test_stock_landed_costs_purchase.py @@ -355,6 +355,7 @@ class TestLandedCostsWithPurchaseAndInv(TestStockValuationLCCommon): # Create an invoice with the same price move_form = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + move_form.invoice_date = move_form.date move_form.partner_id = order.partner_id move_form.purchase_id = order move = move_form.save() diff --git a/addons/stock_landed_costs/tests/test_stockvaluationlayer.py b/addons/stock_landed_costs/tests/test_stockvaluationlayer.py index c2cb5354282..30ea438f49d 100644 --- a/addons/stock_landed_costs/tests/test_stockvaluationlayer.py +++ b/addons/stock_landed_costs/tests/test_stockvaluationlayer.py @@ -65,7 +65,7 @@ class TestStockValuationLCCommon(TestStockLandedCostsCommon): lc.compute_landed_cost() lc.button_validate() return lc - + def _make_in_move(self, product, quantity, unit_cost=None, create_picking=False): """ Helper to create and validate a receipt move. """ @@ -341,6 +341,7 @@ class TestStockValuationLCFIFOVB(TestStockValuationLCCommon): # Create a vendor bill for the RFQ action = rfq.action_create_invoice() vb = self.env['account.move'].browse(action['res_id']) + vb.invoice_date = vb.date vb.action_post() input_aml = self._get_stock_input_move_lines()[-1] @@ -353,6 +354,7 @@ class TestStockValuationLCFIFOVB(TestStockValuationLCCommon): # Create a vendor bill for a landed cost product, post it and validate a landed cost # linked to this vendor bill. LC; 1@50 lcvb = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) + lcvb.invoice_date = lcvb.date lcvb.partner_id = self.vendor2 with lcvb.invoice_line_ids.new() as inv_line: inv_line.product_id = self.productlc1 @@ -429,6 +431,7 @@ class TestStockValuationLCFIFOVB(TestStockValuationLCCommon): # Create a vendor bill for the RFQ and add to it the landed cost vb = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) vb.partner_id = self.vendor1 + vb.invoice_date = vb.date with vb.invoice_line_ids.new() as inv_line: inv_line.product_id = self.productlc1 inv_line.price_unit = 50 @@ -481,6 +484,7 @@ class TestStockValuationLCFIFOVB(TestStockValuationLCCommon): # Create a vebdor bill for the RFQ action = rfq.action_create_invoice() vb = self.env['account.move'].browse(action['res_id']) + vb.invoice_date = vb.date vb.action_post() expense_aml = self._get_expense_move_lines()[-1] @@ -495,6 +499,7 @@ class TestStockValuationLCFIFOVB(TestStockValuationLCCommon): # linked to this vendor bill. LC; 1@50 lcvb = Form(self.env['account.move'].with_context(default_move_type='in_invoice')) lcvb.partner_id = self.vendor2 + lcvb.invoice_date = lcvb.date with lcvb.invoice_line_ids.new() as inv_line: inv_line.product_id = self.productlc1 inv_line.price_unit = 50 diff --git a/odoo/addons/test_main_flows/static/tests/tours/main_flow.js b/odoo/addons/test_main_flows/static/tests/tours/main_flow.js index 544128c0dee..6eff349cbe4 100644 --- a/odoo/addons/test_main_flows/static/tests/tours/main_flow.js +++ b/odoo/addons/test_main_flows/static/tests/tours/main_flow.js @@ -775,6 +775,15 @@ tour.stepUtils.openBuggerMenu("li.breadcrumb-item.active:contains('OP/')"), position: 'bottom', }, ...tour.stepUtils.statusbarButtonsSteps('Create Bill', _t('go to Vendor Bills'), ".o_statusbar_status .btn.dropdown-toggle:contains('Purchase Order')"), +{ + trigger: '.o_form_button_edit', + content: _t('Edit the vendor bill'), + extra_trigger: 'body.o_web_client:not(.oe_wait)', +}, { + trigger:".o_field_widget[name=invoice_date] input", + content: _t('Set the invoice date'), + run: "text 01/01/2020", +}, ...tour.stepUtils.statusbarButtonsSteps('Confirm', _t("Try to send it to email"), ".o_statusbar_status .btn.dropdown-toggle:contains('Draft')"), ...tour.stepUtils.statusbarButtonsSteps('Register Payment', _t("Register Payment"), ".o_statusbar_status .btn.dropdown-toggle:contains('Posted')"), {