[MIG] account_invoice_update_wizard to 18
This commit is contained in:
@@ -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,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -11,8 +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" groups="account.group_account_invoice" attrs="{'invisible': ['|', ('state', '!=', 'posted'), ('move_type', '=', 'entry')]}"/>
|
<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" groups="account.group_account_invoice" attrs="{'invisible': ['|', ('state', '!=', 'posted'), ('move_type', '!=', 'entry')]}"/>
|
<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>
|
||||||
|
|||||||
@@ -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,7 +17,7 @@ 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
|
||||||
@@ -35,7 +35,7 @@ class AccountMoveUpdate(models.TransientModel):
|
|||||||
|
|
||||||
@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):
|
||||||
@@ -45,18 +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,
|
'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
|
||||||
|
|
||||||
@@ -89,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):
|
||||||
@@ -110,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
|
||||||
@@ -146,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."))
|
||||||
@@ -170,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 "
|
||||||
@@ -190,41 +165,16 @@ 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
|
# Purge existing PDF
|
||||||
@@ -247,15 +197,23 @@ class AccountMoveLineUpdate(models.TransientModel):
|
|||||||
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"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|||||||
@@ -15,28 +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 Date" attrs="{'invisible': [('move_type', 'not in', ('in_invoice', 'in_refund'))]}" name="invoice_date"/>
|
<field string="Bill Date" invisible="move_type not in ('in_invoice', 'in_refund')" name="invoice_date"/>
|
||||||
<field string="Supplier Bill Reference" attrs="{'invisible': [('move_type', 'not in', ('in_invoice', 'in_refund'))]}" name="ref"/>
|
<field string="Bill Reference" invisible="move_type not in ('in_invoice', 'in_refund')" name="ref"/>
|
||||||
<field string="Customer Reference" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}" name="ref"/>
|
<field string="Customer Reference" invisible="move_type not in ('out_invoice', 'out_refund')" name="ref"/>
|
||||||
<field string="Ref" attrs="{'invisible': [('move_type', '!=', 'entry')]}" name="ref"/>
|
<field string="Ref" invisible="move_type != 'entry'" name="ref"/>
|
||||||
<field name="invoice_origin" attrs="{'invisible': [('move_type', '=', 'entry')]}"/>
|
<field name="invoice_origin" invisible="move_type == 'entry'"/>
|
||||||
<!-- update of payment term is broken -->
|
<!-- update of payment term is broken -->
|
||||||
<!-- <field name="invoice_payment_term_id" widget="selection"/>-->
|
<!-- <field name="invoice_payment_term_id" widget="selection"/>-->
|
||||||
<field name="partner_bank_id" attrs="{'invisible': [('move_type', '=', 'entry')]}"/>
|
<field name="partner_bank_id" invisible="move_type == 'entry'"/>
|
||||||
<field name="user_id" options="{'no_open': True, 'no_create': True, 'no_create_edit': True}" attrs="{'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" widget="section_and_note_one2many">
|
<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)], 'column_invisible': [('parent.move_type', '=', 'entry')]}"/>
|
<field name="quantity" invisible="display_type != 'product'" column_invisible="parent.move_type == 'entry'"/>
|
||||||
<field name="price_subtotal" attrs="{'invisible': [('display_type', '!=', False)], 'column_invisible': [('parent.move_type', '=', 'entry')]}"/>
|
<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>
|
||||||
|
|||||||
Reference in New Issue
Block a user