Merge pull request #232 from akretion/18-mig-account_invoice_update_wizard

[18][MIG] account_invoice_update_wizard
This commit is contained in:
Florian
2025-10-15 14:05:50 +02:00
committed by GitHub
7 changed files with 586 additions and 176 deletions

View File

@@ -4,7 +4,7 @@
{ {
'name': 'Account Invoice Update Wizard', 'name': 'Account Invoice Update Wizard',
'version': '14.0.1.0.0', 'version': '18.0.1.0.0',
'category': 'Accounting & Finance', 'category': 'Accounting & Finance',
'license': 'AGPL-3', 'license': 'AGPL-3',
'summary': 'Wizard to update non-legal fields of an open/paid invoice', 'summary': 'Wizard to update non-legal fields of an open/paid invoice',
@@ -18,5 +18,5 @@
'wizard/account_move_update_view.xml', 'wizard/account_move_update_view.xml',
'views/account_move.xml', 'views/account_move.xml',
], ],
'installable': False, 'installable': True,
} }

View File

@@ -0,0 +1,243 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_invoice_update_wizard
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__price_subtotal
msgid "Amount"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__analytic_account_id
msgid "Analytic Account"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__analytic_tag_ids
msgid "Analytic Tags"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__partner_bank_id
msgid "Bank Account"
msgstr ""
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
msgid "Bill Reference"
msgstr ""
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
msgid "Cancel"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__company_id
msgid "Company"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__create_uid
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__create_uid
msgid "Created by"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__create_date
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__create_date
msgid "Created on"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__currency_id
msgid "Currency"
msgstr ""
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
msgid "Customer Reference"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__name
msgid "Description"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move__display_name
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__display_name
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__display_name
msgid "Display Name"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__display_type
msgid "Display Type"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move__id
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__id
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__id
msgid "ID"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_id
msgid "Invoice"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__invoice_line_id
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__line_ids
msgid "Invoice Lines"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.actions.act_window,name:account_invoice_update_wizard.account_invoice_update_action
msgid "Invoice Update Wizard"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model,name:account_invoice_update_wizard.model_account_move
msgid "Journal Entry"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move____last_update
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update____last_update
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update____last_update
msgid "Last Modified on"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__write_uid
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__write_uid
msgid "Last Updated by"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__write_date
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__write_date
msgid "Last Updated on"
msgstr ""
#. module: account_invoice_update_wizard
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
#, python-format
msgid "Non-legal fields of invoice updated via the Invoice Update wizard."
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields.selection,name:account_invoice_update_wizard.selection__account_move_line_update__display_type__line_note
msgid "Note"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__partner_id
msgid "Partner"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_payment_term_id
msgid "Payment Term"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__quantity
msgid "Quantity"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__ref
msgid "Reference"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__user_id
msgid "Salesperson"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields.selection,name:account_invoice_update_wizard.selection__account_move_line_update__display_type__line_section
msgid "Section"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__sequence
msgid "Sequence"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_origin
msgid "Source Document"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,help:account_invoice_update_wizard.field_account_move_line_update__display_type
msgid "Technical field for UX purpose."
msgstr ""
#. module: account_invoice_update_wizard
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
#, python-format
msgid ""
"The original payment term '%s' doesn't have the same terms (number of terms "
"and/or amount) as the new payment term '%s'. You can only switch to a "
"payment term that has the same number of terms with the same amount."
msgstr ""
#. module: account_invoice_update_wizard
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
#, python-format
msgid ""
"This wizard doesn't support the update of payment terms on an invoice which "
"is partially or fully paid."
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__move_type
msgid "Type"
msgstr ""
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
msgid "Update"
msgstr ""
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.view_move_form_inherit
msgid "Update Invoice"
msgstr ""
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
msgid "Update Invoice Wizard"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model,name:account_invoice_update_wizard.model_account_move_line_update
msgid "Update non-legal fields of invoice lines"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__parent_id
msgid "Wizard"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model,name:account_invoice_update_wizard.model_account_move_update
msgid "Wizard to update non-legal fields of invoice"
msgstr ""

View File

@@ -0,0 +1,250 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_invoice_update_wizard
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__price_subtotal
msgid "Amount"
msgstr "Montant"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__analytic_account_id
msgid "Analytic Account"
msgstr "Compte Analytique"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__analytic_tag_ids
msgid "Analytic Tags"
msgstr "Tag Analytique"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__partner_bank_id
msgid "Bank Account"
msgstr "Compte Bancaire"
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
#, fuzzy
msgid "Bill Reference"
msgstr "Reference Client"
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
msgid "Cancel"
msgstr "Annuler"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__company_id
msgid "Company"
msgstr "Société"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__create_uid
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__create_uid
msgid "Created by"
msgstr "Créé par"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__create_date
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__create_date
msgid "Created on"
msgstr "Créé le"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__currency_id
msgid "Currency"
msgstr "Devise"
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
#, fuzzy
msgid "Customer Reference"
msgstr "Reference Client"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__name
msgid "Description"
msgstr "Description"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move__display_name
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__display_name
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__display_name
msgid "Display Name"
msgstr "Nom"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__display_type
msgid "Display Type"
msgstr "Type Affichage"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move__id
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__id
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__id
msgid "ID"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_id
msgid "Invoice"
msgstr "Facture"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__invoice_line_id
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__line_ids
msgid "Invoice Lines"
msgstr "Ligne de factures"
#. module: account_invoice_update_wizard
#: model:ir.actions.act_window,name:account_invoice_update_wizard.account_invoice_update_action
msgid "Invoice Update Wizard"
msgstr "Assistance de mise à jour de la facture"
#. module: account_invoice_update_wizard
#: model:ir.model,name:account_invoice_update_wizard.model_account_move
msgid "Journal Entry"
msgstr "Entrée comptable"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move____last_update
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update____last_update
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update____last_update
msgid "Last Modified on"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__write_uid
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__write_uid
msgid "Last Updated by"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__write_date
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__write_date
msgid "Last Updated on"
msgstr ""
#. module: account_invoice_update_wizard
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
#, python-format
msgid "Non-legal fields of invoice updated via the Invoice Update wizard."
msgstr "Champs non légaux mis à jour via l'assistant"
#. module: account_invoice_update_wizard
#: model:ir.model.fields.selection,name:account_invoice_update_wizard.selection__account_move_line_update__display_type__line_note
msgid "Note"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__partner_id
msgid "Partner"
msgstr "Client"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_payment_term_id
msgid "Payment Term"
msgstr "Condition de paiement"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__quantity
msgid "Quantity"
msgstr "Quantité"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__ref
#, fuzzy
msgid "Reference"
msgstr "Reference Client"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__user_id
msgid "Salesperson"
msgstr "Vendeur"
#. module: account_invoice_update_wizard
#: model:ir.model.fields.selection,name:account_invoice_update_wizard.selection__account_move_line_update__display_type__line_section
msgid "Section"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__sequence
msgid "Sequence"
msgstr "Sequence"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__invoice_origin
msgid "Source Document"
msgstr "Origine du document"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,help:account_invoice_update_wizard.field_account_move_line_update__display_type
msgid "Technical field for UX purpose."
msgstr ""
#. module: account_invoice_update_wizard
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
#, python-format
msgid ""
"The original payment term '%s' doesn't have the same terms (number of terms "
"and/or amount) as the new payment term '%s'. You can only switch to a "
"payment term that has the same number of terms with the same amount."
msgstr ""
#. module: account_invoice_update_wizard
#: code:addons/account_invoice_update_wizard/wizard/account_move_update.py:0
#, python-format
msgid ""
"This wizard doesn't support the update of payment terms on an invoice which "
"is partially or fully paid."
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_update__move_type
msgid "Type"
msgstr ""
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
msgid "Update"
msgstr "Mettre à jour"
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.view_move_form_inherit
msgid "Update Invoice"
msgstr "Mettre à jour"
#. module: account_invoice_update_wizard
#: model_terms:ir.ui.view,arch_db:account_invoice_update_wizard.account_invoice_update_form
msgid "Update Invoice Wizard"
msgstr "Assistant de mise à jour"
#. module: account_invoice_update_wizard
#: model:ir.model,name:account_invoice_update_wizard.model_account_move_line_update
msgid "Update non-legal fields of invoice lines"
msgstr "Mettre à jour les champs non légaux des lignes de facture"
#. module: account_invoice_update_wizard
#: model:ir.model.fields,field_description:account_invoice_update_wizard.field_account_move_line_update__parent_id
msgid "Wizard"
msgstr ""
#. module: account_invoice_update_wizard
#: model:ir.model,name:account_invoice_update_wizard.model_account_move_update
msgid "Wizard to update non-legal fields of invoice"
msgstr "Assistant pour mettre à jours les champs non légaux"
#~ msgid "Account"
#~ msgstr "Compte"

View File

@@ -1,10 +1,10 @@
# Copyright 2018-2022 Camptocamp # Copyright 2018-2022 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import SavepointCase from odoo.tests.common import TransactionCase
class TestAccountInvoiceUpdateWizard(SavepointCase): class TestAccountInvoiceUpdateWizard(TransactionCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
@@ -13,6 +13,17 @@ class TestAccountInvoiceUpdateWizard(SavepointCase):
cls.product16 = cls.env.ref('product.product_product_16') cls.product16 = cls.env.ref('product.product_product_16')
uom_unit = cls.env.ref('uom.product_uom_categ_unit') uom_unit = cls.env.ref('uom.product_uom_categ_unit')
cls.plan = cls.env['account.analytic.plan'].create({'name': 'Test Plan'})
cls.analytic_account_1 = cls.env['account.analytic.account'].create({
'name': 'analytic 1 test plan',
'plan_id': cls.plan.id,
'company_id': False,
})
cls.analytic_account_2 = cls.env['account.analytic.account'].create({
'name': 'analytic 2 test plan',
'plan_id': cls.plan.id,
'company_id': False,
})
cls.move1 = cls.env['account.move'].create({ cls.move1 = cls.env['account.move'].create({
'name': 'Test invoice', 'name': 'Test invoice',
'partner_id': cls.customer12.id, 'partner_id': cls.customer12.id,
@@ -30,13 +41,6 @@ class TestAccountInvoiceUpdateWizard(SavepointCase):
], ],
}) })
cls.aa1 = cls.env.ref('analytic.analytic_partners_camp_to_camp')
cls.aa2 = cls.env.ref('analytic.analytic_nebula')
cls.atag1 = cls.env.ref('analytic.tag_contract')
cls.atag2 = cls.env['account.analytic.tag'].create({
'name': '',
})
def create_wizard(self, move): def create_wizard(self, move):
res = move.prepare_update_wizard() res = move.prepare_update_wizard()
self.wiz = self.env['account.move.update'].browse(res['res_id']) self.wiz = self.env['account.move.update'].browse(res['res_id'])
@@ -54,13 +58,14 @@ class TestAccountInvoiceUpdateWizard(SavepointCase):
wiz_line = self.wiz.line_ids.filtered( wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id.product_id.id == self.product16.id) lambda rec: rec.invoice_line_id.product_id.id == self.product16.id)
wiz_line.analytic_account_id = self.aa1 wiz_line.analytic_distribution = {self.analytic_account_1.id: 50, self.analytic_account_2.id: 50}
self.wiz.run() self.wiz.run()
related_ml = self.move1.invoice_line_ids.filtered( related_ml = self.move1.invoice_line_ids.filtered(
lambda rec: rec.product_id == self.product16) lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_account_id, self.aa1) self.assertEqual(related_ml.analytic_distribution, {str(self.analytic_account_1.id): 50.0, str(self.analytic_account_2.id): 50.0})
self.assertEqual(related_ml.analytic_line_ids.account_id, self.aa1) self.assertEqual(len(related_ml.analytic_line_ids), 2)
self.assertEqual(related_ml.analytic_line_ids[0].amount, 21.0)
def test_change_analytic_account_line1(self): def test_change_analytic_account_line1(self):
""" Change analytic account on a move line """ Change analytic account on a move line
@@ -70,86 +75,21 @@ class TestAccountInvoiceUpdateWizard(SavepointCase):
- update the move line - update the move line
- update the existing analytic line.""" - update the existing analytic line."""
move_line1 = self.move1.invoice_line_ids.filtered(lambda rec: rec.product_id == self.product16) move_line1 = self.move1.invoice_line_ids.filtered(lambda rec: rec.product_id == self.product16)
move_line1.analytic_account_id = self.aa2 move_line1.analytic_distribution = {self.analytic_account_1.id: 100}
self.move1._post() self.move1._post()
self.create_wizard(self.move1) self.create_wizard(self.move1)
wiz_line = self.wiz.line_ids.filtered( wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id.product_id.id == self.product16.id) lambda rec: rec.invoice_line_id.product_id.id == self.product16.id)
wiz_line.analytic_account_id = self.aa1 wiz_line.analytic_distribution = {self.analytic_account_1.id: 50, self.analytic_account_2.id: 50}
self.wiz.run() self.wiz.run()
related_ml = self.move1.invoice_line_ids.filtered( related_ml = self.move1.invoice_line_ids.filtered(
lambda rec: rec.product_id == self.product16) lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_account_id, self.aa1) self.assertEqual(related_ml.analytic_distribution, {str(self.analytic_account_1.id): 50.0, str(self.analytic_account_2.id): 50.0})
self.assertEqual(related_ml.analytic_line_ids.account_id, self.aa1) self.assertEqual(len(related_ml.analytic_line_ids), 2)
self.assertEqual(related_ml.analytic_line_ids[0].amount, 21.0)
def test_add_analytic_tags_line1(self):
""" Add analytic tags on a move line
after the move has been approved.
This will update move line.
"""
self.move1._post()
self.create_wizard(self.move1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id.product_id.id == self.product16.id)
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.move1.invoice_line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_tag_ids, self.atag2)
self.assertFalse(related_ml.analytic_line_ids)
def test_change_analytic_tags_line1(self):
""" Change analytic tags on a move line
after the move has been approved.
It will update move line and analytic line
"""
move_line1 = self.move1.invoice_line_ids.filtered(lambda rec: rec.product_id == self.product16)
move_line1.analytic_account_id = self.aa2
move_line1.analytic_tag_ids = self.atag1
self.move1._post()
self.create_wizard(self.move1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id.product_id.id == self.product16.id)
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.move1.invoice_line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_tag_ids, self.atag2)
self.assertEqual(related_ml.analytic_line_ids.tag_ids, self.atag2)
def test_add_analytic_info_line1(self):
""" Add analytic account and tags on a move line
after the move has been approved.
This will:
- update move line
- create an analytic line
"""
self.move1._post()
self.create_wizard(self.move1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id.product_id.id == self.product16.id)
wiz_line.analytic_account_id = self.aa1
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.move1.invoice_line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_account_id, self.aa1)
self.assertEqual(related_ml.analytic_tag_ids, self.atag2)
self.assertEqual(related_ml.analytic_line_ids.account_id, self.aa1)
self.assertEqual(related_ml.analytic_line_ids.tag_ids, self.atag2)
def test_empty_analytic_account_line1(self): def test_empty_analytic_account_line1(self):
""" Remove analytic account """ Remove analytic account
@@ -158,16 +98,16 @@ class TestAccountInvoiceUpdateWizard(SavepointCase):
This will raise an error as it is not implemented. This will raise an error as it is not implemented.
""" """
move_line1 = self.move1.invoice_line_ids.filtered(lambda rec: rec.product_id == self.product16) move_line1 = self.move1.invoice_line_ids.filtered(lambda rec: rec.product_id == self.product16)
move_line1.analytic_account_id = self.aa2 move_line1.analytic_distribution = {self.analytic_account_1.id: 100}
self.move1._post() self.move1._post()
self.create_wizard(self.move1) self.create_wizard(self.move1)
wiz_line = self.wiz.line_ids.filtered( wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id.product_id.id == self.product16.id) lambda rec: rec.invoice_line_id.product_id.id == self.product16.id)
wiz_line.analytic_account_id = False wiz_line.analytic_distribution = False
self.wiz.run() self.wiz.run()
related_ml = self.move1.invoice_line_ids.filtered( related_ml = self.move1.invoice_line_ids.filtered(
lambda rec: rec.product_id == self.product16) lambda rec: rec.product_id == self.product16)
self.assertFalse(related_ml.analytic_account_id) self.assertFalse(related_ml.analytic_distribution)
self.assertFalse(related_ml.analytic_line_ids) self.assertFalse(related_ml.analytic_line_ids)

View File

@@ -11,7 +11,8 @@
<field name="inherit_id" ref="account.view_move_form"/> <field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<button name="button_draft" position="before"> <button name="button_draft" position="before">
<button name="prepare_update_wizard" type="object" string="Update Invoice" states="posted" groups="account.group_account_invoice"/> <button name="prepare_update_wizard" type="object" string="Update Invoice" invisible="state != 'posted' or move_type == 'entry'" groups="account.group_account_invoice"/>
<button name="prepare_update_wizard" type="object" string="Update Entry" invisible="state != 'posted' or move_type != 'entry'" groups="account.group_account_invoice"/>
</button> </button>
</field> </field>
</record> </record>

View File

@@ -2,7 +2,7 @@
# Copyright 2018-2022 Camptocamp # Copyright 2018-2022 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _ from odoo import Command, models, fields, api
from odoo.exceptions import UserError from odoo.exceptions import UserError
import odoo.addons.decimal_precision as dp import odoo.addons.decimal_precision as dp
@@ -17,10 +17,11 @@ class AccountMoveUpdate(models.TransientModel):
move_type = fields.Selection(related='invoice_id.move_type') move_type = fields.Selection(related='invoice_id.move_type')
company_id = fields.Many2one(related='invoice_id.company_id') company_id = fields.Many2one(related='invoice_id.company_id')
partner_id = fields.Many2one(related='invoice_id.partner_id') partner_id = fields.Many2one(related='invoice_id.partner_id')
user_id = fields.Many2one('res.users', string='Salesperson') invoice_user_id = fields.Many2one('res.users', string='Salesperson')
invoice_payment_term_id = fields.Many2one( invoice_payment_term_id = fields.Many2one(
'account.payment.term', string='Payment Term') 'account.payment.term', string='Payment Term')
ref = fields.Char(string='Reference') # field label is customized in the view ref = fields.Char(string='Reference') # field label is customized in the view
invoice_date = fields.Date()
invoice_origin = fields.Char(string='Source Document') invoice_origin = fields.Char(string='Source Document')
partner_bank_id = fields.Many2one( partner_bank_id = fields.Many2one(
'res.partner.bank', string='Bank Account') 'res.partner.bank', string='Bank Account')
@@ -30,11 +31,11 @@ class AccountMoveUpdate(models.TransientModel):
@api.model @api.model
def _simple_fields2update(self): def _simple_fields2update(self):
'''List boolean, date, datetime, char, text fields''' '''List boolean, date, datetime, char, text fields'''
return ['ref', 'invoice_origin'] return ['ref', 'invoice_origin', 'invoice_date']
@api.model @api.model
def _m2o_fields2update(self): def _m2o_fields2update(self):
return ['invoice_payment_term_id', 'user_id', 'partner_bank_id'] return ['invoice_payment_term_id', 'invoice_user_id', 'partner_bank_id']
@api.model @api.model
def _prepare_default_get(self, invoice): def _prepare_default_get(self, invoice):
@@ -44,17 +45,14 @@ class AccountMoveUpdate(models.TransientModel):
for m2ofield in self._m2o_fields2update(): for m2ofield in self._m2o_fields2update():
res[m2ofield] = invoice[m2ofield].id or False res[m2ofield] = invoice[m2ofield].id or False
for line in invoice.invoice_line_ids: for line in invoice.invoice_line_ids:
aa_tags = line.analytic_tag_ids
aa_tags = [(6, 0, aa_tags.ids)] if aa_tags else False
res['line_ids'].append([0, 0, { res['line_ids'].append([0, 0, {
'invoice_line_id': line.id, 'invoice_line_id': line.id,
'sequence': line.sequence,
'name': line.name, 'name': line.name,
'quantity': line.quantity, 'quantity': line.quantity,
'price_subtotal': line.price_subtotal, 'price_subtotal': line.price_subtotal,
'analytic_account_id': line.analytic_account_id.id, 'analytic_distribution': line.analytic_distribution,
'currency_id': line.currency_id.id, 'currency_id': line.currency_id.id,
'analytic_tag_ids': aa_tags,
'display_type': line.display_type,
}]) }])
return res return res
@@ -87,15 +85,15 @@ class AccountMoveUpdate(models.TransientModel):
@api.model @api.model
def _line_simple_fields2update(self): def _line_simple_fields2update(self):
return ["name"] return ["name", "analytic_distribution"]
@api.model @api.model
def _line_m2o_fields2update(self): def _line_m2o_fields2update(self):
return ["analytic_account_id"] return []
@api.model @api.model
def _line_m2m_fields2update(self): def _line_m2m_fields2update(self):
return ["analytic_tag_ids"] return []
@api.model @api.model
def _prepare_invoice_line(self, line): def _prepare_invoice_line(self, line):
@@ -108,30 +106,9 @@ class AccountMoveUpdate(models.TransientModel):
vals[field] = line[field].id vals[field] = line[field].id
for field in self._line_m2m_fields2update(): for field in self._line_m2m_fields2update():
if line[field] != line.invoice_line_id[field]: if line[field] != line.invoice_line_id[field]:
vals[field] = [(6, 0, line[field].ids)] vals[field] = [Command.set(line[field].ids)]
return vals return vals
def _prepare_move_line_and_analytic_line(self, inv_line):
mlvals = {}
alvals = {}
inv_line_upd = self.line_ids.filtered(
lambda rec: rec.invoice_line_id == inv_line)
ini_aa = inv_line.analytic_account_id
new_aa = inv_line_upd.analytic_account_id
if ini_aa != new_aa:
mlvals['analytic_account_id'] = new_aa.id
alvals['account_id'] = new_aa.id
ini_aa_tags = inv_line.analytic_tag_ids
new_aa_tags = inv_line_upd.analytic_tag_ids
if ini_aa_tags != new_aa_tags:
mlvals['analytic_tag_ids'] = [(6, None, new_aa_tags.ids)]
alvals['tag_ids'] = [(6, None, new_aa_tags.ids)]
return mlvals, alvals
def _update_payment_term_move(self): def _update_payment_term_move(self):
self.ensure_one() self.ensure_one()
inv = self.invoice_id inv = self.invoice_id
@@ -144,7 +121,7 @@ class AccountMoveUpdate(models.TransientModel):
# the reconcile marks to put the new maturity date on the right # the reconcile marks to put the new maturity date on the right
# lines # lines
if inv.payment_id: if inv.payment_id:
raise UserError(_( raise UserError(self.env._(
"This wizard doesn't support the update of payment " "This wizard doesn't support the update of payment "
"terms on an invoice which is partially or fully " "terms on an invoice which is partially or fully "
"paid.")) "paid."))
@@ -168,7 +145,7 @@ class AccountMoveUpdate(models.TransientModel):
mlines[amount] = [line] mlines[amount] = [line]
for iamount, lines in mlines.items(): for iamount, lines in mlines.items():
if len(lines) != len(new_pterm.get(iamount, [])): if len(lines) != len(new_pterm.get(iamount, [])):
raise UserError(_( raise UserError(self.env._(
"The original payment term '%s' doesn't have the " "The original payment term '%s' doesn't have the "
"same terms (number of terms and/or amount) as the " "same terms (number of terms and/or amount) as the "
"new payment term '%s'. You can only switch to a " "new payment term '%s'. You can only switch to a "
@@ -188,64 +165,55 @@ class AccountMoveUpdate(models.TransientModel):
if ivals: if ivals:
updated = True updated = True
inv.write(ivals) inv.write(ivals)
if inv:
for ml in inv.line_ids.filtered(
# we are only interested in invoice lines, not tax lines
lambda rec: bool(rec.product_id)
):
if ml.credit == 0.0:
continue
analytic_account = ml.analytic_account_id
mlvals, alvals = self._prepare_move_line_and_analytic_line(ml)
if mlvals:
updated = True
ml.write(mlvals)
aalines = ml.analytic_line_ids
if aalines and alvals:
updated = True
if ('account_id' in alvals and
alvals['account_id'] is False):
former_aa = analytic_account
to_remove_aalines = aalines.filtered(
lambda rec: rec.account_id == former_aa)
# remove existing analytic line
to_remove_aalines.unlink()
else:
aalines.write(alvals)
elif 'account_id' in alvals:
# Create analytic lines if analytic account
# is added later
ml.create_analytic_lines()
for line in self.line_ids: for line in self.line_ids:
ilvals = self._prepare_invoice_line(line) ilvals = self._prepare_invoice_line(line)
if ilvals: if ilvals:
updated = True updated = True
# note that updating analytic_distribution will delete/re-create
# the analytic line with inverse method, we do not need additional
# logic about that.
line.invoice_line_id.write(ilvals) line.invoice_line_id.write(ilvals)
if updated: if updated:
inv.message_post(body=_( inv.message_post(body=self.env._(
'Non-legal fields of invoice updated via the Invoice Update ' 'Non-legal fields of invoice updated via the Invoice Update '
'wizard.')) 'wizard.'))
# Purge existing PDF
report = self.env.ref("account.account_invoices")
attachment = report.retrieve_attachment(inv)
# attachment may be None
if attachment:
attachment.unlink()
return True return True
class AccountMoveLineUpdate(models.TransientModel): class AccountMoveLineUpdate(models.TransientModel):
_name = 'account.move.line.update' _name = 'account.move.line.update'
_description = 'Update non-legal fields of invoice lines' _description = 'Update non-legal fields of invoice lines'
_order = "sequence, name"
sequence = fields.Integer()
parent_id = fields.Many2one( parent_id = fields.Many2one(
'account.move.update', string='Wizard', ondelete='cascade') 'account.move.update', string='Wizard', ondelete='cascade')
invoice_line_id = fields.Many2one( invoice_line_id = fields.Many2one(
'account.move.line', string='Invoice Line', readonly=True) 'account.move.line', string='Invoice Line', readonly=True)
name = fields.Text(string='Description', required=True) name = fields.Text(string='Description', required=True)
display_type = fields.Selection([ display_type = fields.Selection(
('line_section', "Section"), related="invoice_line_id.display_type",
('line_note', "Note")], default=False, help="Technical field for UX purpose.") help="Technical field for UX purpose.")
quantity = fields.Float( quantity = fields.Float(
string='Quantity', digits='Product Unit of Measure', readonly=True) string='Quantity', digits='Product Unit of Measure', readonly=True)
price_subtotal = fields.Monetary( price_subtotal = fields.Monetary(
string='Amount', readonly=True) string='Amount', readonly=True)
analytic_account_id = fields.Many2one(
'account.analytic.account', string='Analytic Account')
analytic_tag_ids = fields.Many2many(
'account.analytic.tag', string='Analytic Tags')
currency_id = fields.Many2one('res.currency', readonly=True) currency_id = fields.Many2one('res.currency', readonly=True)
analytic_distribution = fields.Json(
string="Analytic",
# compute="_compute_writeoff_analytic_distribution",
# readonly=False,
# store=True,
# precompute=True,
)
analytic_precision = fields.Integer(
default=lambda self: self.env["decimal.precision"].precision_get(
"Percentage Analytic"
),
)

View File

@@ -15,25 +15,33 @@
<field name="move_type" invisible="1"/> <field name="move_type" invisible="1"/>
<field name="company_id" invisible="1"/> <field name="company_id" invisible="1"/>
<field name="partner_id" invisible="1"/> <field name="partner_id" invisible="1"/>
<field string="Bill Reference" attrs="{'invisible': [('move_type', 'not in', ('in_invoice', 'in_refund'))]}" name="ref"/> <field string="Bill Date" invisible="move_type not in ('in_invoice', 'in_refund')" name="invoice_date"/>
<field string="Customer Reference" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}" name="ref"/> <field string="Bill Reference" invisible="move_type not in ('in_invoice', 'in_refund')" name="ref"/>
<field name="invoice_origin"/> <field string="Customer Reference" invisible="move_type not in ('out_invoice', 'out_refund')" name="ref"/>
<field name="invoice_payment_term_id" widget="selection"/> <field string="Ref" invisible="move_type != 'entry'" name="ref"/>
<field name="partner_bank_id"/> <field name="invoice_origin" invisible="move_type == 'entry'"/>
<field name="user_id" options="{'no_open': True, 'no_create': True, 'no_create_edit': True}"/> <!-- update of payment term is broken -->
<!-- <field name="invoice_payment_term_id" widget="selection"/>-->
<field name="partner_bank_id" invisible="move_type == 'entry'"/>
<field name="invoice_user_id" options="{'no_open': True, 'no_create': True, 'no_create_edit': True}" invisible="move_type == 'entry'"/>
</group> </group>
<group name="lines"> <group name="lines">
<field name="line_ids" nolabel="1"> <field name="line_ids" nolabel="1" widget="section_and_note_one2many">
<tree editable="bottom" create="false" delete="false" edit="true"> <list editable="bottom" create="false" delete="false" edit="true">
<field name="invoice_line_id" invisible="1"/> <field name="invoice_line_id" column_invisible="1"/>
<field name="display_type" invisible="1"/> <field name="display_type" column_invisible="1"/>
<field name="currency_id" invisible="1"/> <field name="currency_id" column_invisible="1"/>
<field name="name"/> <field name="name"/>
<field name="quantity" attrs="{'invisible': [('display_type', '!=', False)]}"/> <field name="quantity" invisible="display_type != 'product'" column_invisible="parent.move_type == 'entry'"/>
<field name="price_subtotal" attrs="{'invisible': [('display_type', '!=', False)]}"/> <field name="price_subtotal" invisible="display_type != 'product'" column_invisible="parent.move_type == 'entry'"/>
<field name="analytic_account_id" attrs="{'invisible': [('display_type', '!=', False)]}" groups="analytic.group_analytic_accounting"/> <field
<field name="analytic_tag_ids" attrs="{'invisible': [('display_type', '!=', False)]}" groups="analytic.group_analytic_tags" widget="many2many_tags"/> name="analytic_distribution"
</tree> widget="analytic_distribution"
groups="analytic.group_analytic_accounting"
options="{'account_field': 'account_id', 'business_domain': 'general'}"
invisible="display_type != 'product'"
/>
</list>
</field> </field>
</group> </group>
<footer> <footer>