Compare commits

..

1 Commits

Author SHA1 Message Date
clementmbr
16424a6897 [12.0][MIG] product_unit_manager_group + rename
Basic module migration and :

- rename module's name product_unit_manager_group into uom_manager_group
in order to follow the new separation between product and uom modules
in Odoo 12.0
- light refactor adding a group category "Units of Measure" with two
levels :
    - nothing : neither UoM fields nor menus are displayed
    - User : UoM fields are displayed but not Uom menus (Users are not
    allowed to create or modify UoM)
    - Manager : display both fields and UoM menus

The rest of the module philosophy is maintained. All the Sales
Manager, Stock Manager, MRP Manager have no more rights to create or
modify UoMs. Only "UoM Managers" can.
2020-05-13 18:02:04 -03:00
518 changed files with 4296 additions and 15504 deletions

View File

@@ -1 +0,0 @@
from . import models

View File

@@ -1,23 +0,0 @@
# © 2016-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Account Fiscal Position Payable Receivable",
"version": "12.0.1.0.0",
"category": "Accounting & Finance",
"license": "AGPL-3",
"summary": "Configure payable/receivable accounts on fiscal positions",
"description": """
Account Fiscal Position Payable Receivable
==========================================
This module allows to configure a special *Partner Receivable Account* and a special *Partner Payable Account* on fiscal positions. This is used in the onchange of the fiscal position of partners.
This module has been written by Alexis de Lattre from Akretion <alexis.delattre@akretion.com>.
""",
"author": "Akretion",
"website": "http://www.akretion.com",
"depends": ["account"],
"data": ["views/account_fiscal_position_view.xml"],
"installable": False,
}

View File

@@ -1,2 +0,0 @@
from . import account_fiscal_position
from . import res_partner

View File

@@ -1,21 +0,0 @@
# © 2016-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
class AccountFiscalPosition(models.Model):
_inherit = "account.fiscal.position"
receivable_account_id = fields.Many2one(
"account.account",
string="Partner Receivable Account",
company_dependent=True,
domain=[("internal_type", "=", "receivable")],
)
payable_account_id = fields.Many2one(
"account.account",
string="Partner Payable Account",
company_dependent=True,
domain=[("internal_type", "=", "payable")],
)

View File

@@ -1,25 +0,0 @@
# © 2016-2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, api
class ResPartner(models.Model):
_inherit = "res.partner"
@api.onchange("property_account_position_id")
def fiscal_position_receivable_payable_change(self):
fp = self.property_account_position_id
ipo = self.env["ir.property"]
if fp.receivable_account_id:
self.property_account_receivable_id = fp.receivable_account_id
else:
self.property_account_receivable_id = ipo.get(
"property_account_receivable_id", "res.partner"
)
if fp.payable_account_id:
self.property_account_payable_id = fp.payable_account_id
else:
self.property_account_payable_id = ipo.get(
"property_account_payable_id", "res.partner"
)

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
© 2016 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_position_form" model="ir.ui.view">
<field name="name">receivable_payable.fiscal_position_form</field>
<field name="model">account.fiscal.position</field>
<field name="inherit_id" ref="account.view_account_position_form" />
<field name="arch" type="xml">
<field name="company_id" position="after">
<field name="receivable_account_id"/>
<field name="payable_account_id"/>
</field>
</field>
</record>
</odoo>

View File

@@ -20,5 +20,5 @@ This module has been written by Alexis de Lattre from Akretion
'data': [
'account_invoice_view.xml',
],
'installable': False,
'installable': True,
}

View File

@@ -4,7 +4,7 @@
{
'name': 'Account Invoice Update Wizard',
'version': '14.0.1.0.0',
'version': '12.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Wizard to update non-legal fields of an open/paid invoice',
@@ -14,9 +14,8 @@
'account',
],
'data': [
'security/ir.model.access.csv',
'wizard/account_move_update_view.xml',
'views/account_move.xml',
],
'wizard/account_invoice_update_view.xml',
'views/account_invoice.xml',
],
'installable': True,
}

View File

@@ -1 +1 @@
from . import account_move
from . import account_invoice

View File

@@ -1,15 +1,17 @@
# Copyright 2019-2022 Camptocamp
# Copyright 2019 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
from odoo import models, fields, api, _
from odoo.exceptions import UserError
import odoo.addons.decimal_precision as dp
class AccountMove(models.Model):
_inherit = 'account.move'
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
def prepare_update_wizard(self):
self.ensure_one()
wizard = self.env['account.move.update']
wizard = self.env['account.invoice.update']
res = wizard._prepare_default_get(self)
action = self.env.ref(
'account_invoice_update_wizard.account_invoice_update_action'
@@ -17,3 +19,4 @@ class AccountMove(models.Model):
action['name'] = "Update Wizard"
action['res_id'] = wizard.create(res).id
return action

View File

@@ -1,3 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_move_update,account.move.update.user,model_account_move_update,account.group_account_invoice,1,1,1,1
access_account_move_line_update,account.move.line.update.user,model_account_move_line_update,account.group_account_invoice,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_account_move_update account.move.update.user model_account_move_update account.group_account_invoice 1 1 1 1
3 access_account_move_line_update account.move.line.update.user model_account_move_line_update account.group_account_invoice 1 1 1 1

View File

@@ -1 +1 @@
from . import test_account_move_update_wizard
from . import test_account_invoice_update_wizard

View File

@@ -0,0 +1,196 @@
# Copyright 2018-2019 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import SavepointCase
from odoo.exceptions import UserError
class TestAccountInvoiceUpdateWizard(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.customer12 = cls.env.ref('base.res_partner_12')
cls.product16 = cls.env.ref('product.product_product_16')
cls.product24 = cls.env.ref('product.product_product_24')
uom_unit = cls.env.ref('uom.product_uom_categ_unit')
cls.invoice1 = cls.env['account.invoice'].create({
'name': 'Test invoice',
'partner_id': cls.customer12.id,
})
cls.inv_line1 = cls.env['account.invoice.line'].create({
'invoice_id': cls.invoice1.id,
'name': "Line1",
'product_id': cls.product16.id,
'product_uom_id': uom_unit.id,
'account_id': cls.invoice1.account_id.id,
'price_unit': 42.0,
})
cls.inv_line2 = cls.env['account.invoice.line'].create({
'invoice_id': cls.invoice1.id,
'name': "Line2",
'product_id': cls.product24.id,
'product_uom_id': uom_unit.id,
'account_id': cls.invoice1.account_id.id,
'price_unit': 1111.1,
})
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, invoice):
res = self.invoice1.prepare_update_wizard()
self.wiz = self.env['account.invoice.update'].browse(res['res_id'])
def test_add_analytic_account_line1(self):
""" Add analytic account on an invoice line
after the invoice has been approved.
This will:
- update the move line
- create a new analytic line.
"""
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = self.aa1
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_account_id, self.aa1)
self.assertEqual(related_ml.analytic_line_ids.account_id, self.aa1)
def test_change_analytic_account_line1(self):
""" Change analytic account on an invoice line
after the invoice has been approved.
This will:
- update the move line
- update the existing analytic line."""
self.inv_line1.account_analytic_id = self.aa2
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = self.aa1
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertEqual(related_ml.analytic_account_id, self.aa1)
self.assertEqual(related_ml.analytic_line_ids.account_id, self.aa1)
def test_error_grouped_move_lines(self):
""" Change analytic account on an invoice line
after the invoice has been approved where both
lines were grouped in the same move line.
This will raise an error.
"""
self.invoice1.journal_id.group_invoice_lines = True
self.inv_line2.product_id = self.product16
self.inv_line2.unit_price = 42.0
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
line1 = self.wiz.line_ids[0]
line1.account_analytic_id = self.aa1
with self.assertRaises(UserError):
self.wiz.run()
def test_add_analytic_tags_line1(self):
""" Add analytic tags on an invoice line
after the invoice has been approved.
This will update move line.
"""
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.invoice1.move_id.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 an invoice line
after the invoice has been approved.
It will update move line and analytic line
"""
self.inv_line1.account_analytic_id = self.aa2
self.inv_line1.analytic_tag_ids = self.atag1
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.invoice1.move_id.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 an invoice line
after the invoice has been approved.
This will:
- update move line
- create an analytic line
"""
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = self.aa1
wiz_line.analytic_tag_ids = self.atag2
self.wiz.run()
related_ml = self.invoice1.move_id.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):
""" Remove analytic account
after the invoice has been approved.
This will raise an error as it is not implemented.
"""
self.inv_line1.account_analytic_id = self.aa2
self.invoice1.action_invoice_open()
self.create_wizard(self.invoice1)
wiz_line = self.wiz.line_ids.filtered(
lambda rec: rec.invoice_line_id == self.inv_line1)
wiz_line.account_analytic_id = False
self.wiz.run()
related_ml = self.invoice1.move_id.line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertFalse(related_ml.analytic_account_id)
self.assertFalse(related_ml.analytic_line_ids)

View File

@@ -1,173 +0,0 @@
# Copyright 2018-2022 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo.tests.common import SavepointCase
class TestAccountInvoiceUpdateWizard(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.customer12 = cls.env.ref('base.res_partner_12')
cls.product16 = cls.env.ref('product.product_product_16')
uom_unit = cls.env.ref('uom.product_uom_categ_unit')
cls.move1 = cls.env['account.move'].create({
'name': 'Test invoice',
'partner_id': cls.customer12.id,
'move_type': 'out_invoice',
'invoice_line_ids': [
[0, None, {
'name': 'Line1',
'product_id': cls.product16.id,
'product_uom_id': uom_unit.id,
'quantity': 1,
'price_unit': 42.0,
'credit': 42.0,
'debit': 0
}],
],
})
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):
res = move.prepare_update_wizard()
self.wiz = self.env['account.move.update'].browse(res['res_id'])
def test_add_analytic_account_line1(self):
""" Add analytic account on a move line
after the move has been approved.
This will:
- update the move line
- create a new 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
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_line_ids.account_id, self.aa1)
def test_change_analytic_account_line1(self):
""" Change analytic account on a move line
after the move has been approved.
This will:
- update the move line
- update the existing analytic line."""
move_line1 = self.move1.invoice_line_ids.filtered(lambda rec: rec.product_id == self.product16)
move_line1.analytic_account_id = self.aa2
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
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_line_ids.account_id, self.aa1)
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):
""" Remove analytic account
after the move has been approved.
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.analytic_account_id = self.aa2
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 = False
self.wiz.run()
related_ml = self.move1.invoice_line_ids.filtered(
lambda rec: rec.product_id == self.product16)
self.assertFalse(related_ml.analytic_account_id)
self.assertFalse(related_ml.analytic_line_ids)

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="invoice_supplier_form" model="ir.ui.view">
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<button name="action_invoice_draft" position="before">
<button name="prepare_update_wizard" type="object" string="Update Invoice" states="open,paid" groups="account.group_account_invoice"/>
</button>
</field>
</record>
<record id="invoice_form" model="ir.ui.view">
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<button name="action_invoice_draft" position="before">
<button name="prepare_update_wizard" type="object" string="Update Invoice" states="open,paid" groups="account.group_account_invoice"/>
</button>
</field>
</record>
</odoo>

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_move_form_inherit" model="ir.ui.view">
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<button name="button_draft" position="before">
<button name="prepare_update_wizard" type="object" string="Update Invoice" states="posted" groups="account.group_account_invoice"/>
</button>
</field>
</record>
</odoo>

View File

@@ -1 +1 @@
from . import account_move_update
from . import account_invoice_update

View File

@@ -1,5 +1,5 @@
# Copyright 2017 Akretion (Alexis de Lattre <alexis.delattre@akretion.com>)
# Copyright 2018-2022 Camptocamp
# Copyright 2018-2019 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
@@ -7,37 +7,38 @@ from odoo.exceptions import UserError
import odoo.addons.decimal_precision as dp
class AccountMoveUpdate(models.TransientModel):
_name = 'account.move.update'
class AccountInvoiceUpdate(models.TransientModel):
_name = 'account.invoice.update'
_description = 'Wizard to update non-legal fields of invoice'
invoice_id = fields.Many2one(
'account.move', string='Invoice', required=True,
'account.invoice', string='Invoice', required=True,
readonly=True)
type = fields.Selection(related='invoice_id.move_type', readonly=True)
type = fields.Selection(related='invoice_id.type', readonly=True)
company_id = fields.Many2one(
related='invoice_id.company_id', readonly=True)
partner_id = fields.Many2one(
related='invoice_id.partner_id', readonly=True)
user_id = fields.Many2one('res.users', string='Salesperson')
invoice_payment_term_id = fields.Many2one(
payment_term_id = fields.Many2one(
'account.payment.term', string='Payment Term')
ref = fields.Char(string='Invoice Reference')
reference = fields.Char(string='Invoice Reference')
name = fields.Char(string='Reference/Description')
invoice_origin = fields.Char(string='Source Document')
origin = fields.Char(string='Source Document')
comment = fields.Text('Additional Information')
partner_bank_id = fields.Many2one(
'res.partner.bank', string='Bank Account')
line_ids = fields.One2many(
'account.move.line.update', 'parent_id', string='Invoice Lines')
'account.invoice.line.update', 'parent_id', string='Invoice Lines')
@api.model
def _simple_fields2update(self):
'''List boolean, date, datetime, char, text fields'''
return ['ref', 'name', 'invoice_origin']
return ['reference', 'name', 'origin', 'comment']
@api.model
def _m2o_fields2update(self):
return ['invoice_payment_term_id', 'user_id', 'partner_bank_id']
return ['payment_term_id', 'user_id', 'partner_bank_id']
@api.model
def _prepare_default_get(self, invoice):
@@ -54,7 +55,7 @@ class AccountMoveUpdate(models.TransientModel):
'name': line.name,
'quantity': line.quantity,
'price_subtotal': line.price_subtotal,
'analytic_account_id': line.analytic_account_id.id,
'account_analytic_id': line.account_analytic_id.id,
'analytic_tag_ids': aa_tags,
'display_type': line.display_type,
}])
@@ -71,6 +72,7 @@ class AccountMoveUpdate(models.TransientModel):
"[('partner_id', '=', partner_id)]"
return res
@api.multi
def _prepare_invoice(self):
vals = {}
inv = self.invoice_id
@@ -80,8 +82,8 @@ class AccountMoveUpdate(models.TransientModel):
for m2ofield in self._m2o_fields2update():
if self[m2ofield] != inv[m2ofield]:
vals[m2ofield] = self[m2ofield].id or False
if 'invoice_payment_term_id' in vals:
pterm_list = self.invoice_payment_term_id.compute(
if 'payment_term_id' in vals:
pterm_list = self.payment_term_id.compute(
value=1, date_ref=inv.date_invoice)[0]
if pterm_list:
vals['date_due'] = max(line[0] for line in pterm_list)
@@ -89,15 +91,15 @@ class AccountMoveUpdate(models.TransientModel):
@api.model
def _line_simple_fields2update(self):
return ["name"]
return ["name",]
@api.model
def _line_m2o_fields2update(self):
return ["analytic_account_id"]
return ["account_analytic_id",]
@api.model
def _line_m2m_fields2update(self):
return ["analytic_tag_ids"]
return ["analytic_tag_ids",]
@api.model
def _prepare_invoice_line(self, line):
@@ -113,45 +115,87 @@ class AccountMoveUpdate(models.TransientModel):
vals[field] = [(6, 0, line[field].ids)]
return vals
def _prepare_move_line_and_analytic_line(self, inv_line):
@api.multi
def _prepare_move(self):
mvals = {}
inv = self.invoice_id
ini_ref = inv.move_id.ref
ref = inv.reference or inv.name
if ini_ref != ref:
mvals['ref'] = ref
return mvals
@api.multi
def _get_matching_inv_line(self, move_line):
""" Find matching invoice line by product """
# TODO make it accept more case as lines won't
# be grouped unless journal.group_invoice_line is True
inv_line = self.invoice_id.invoice_line_ids.filtered(
lambda rec: rec.product_id == move_line.product_id)
if len(inv_line) != 1:
raise UserError(
"Cannot match a single invoice line to move line %s" %
move_line.name)
return inv_line
@api.multi
def _prepare_move_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
ini_aa = inv_line.account_analytic_id
new_aa = inv_line_upd.account_analytic_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
return mlvals
@api.multi
def _prepare_analytic_line(self, inv_line):
alvals = {}
inv_line_upd = self.line_ids.filtered(
lambda rec: rec.invoice_line_id == inv_line)
ini_aa = inv_line.account_analytic_id
new_aa = inv_line_upd.account_analytic_id
if ini_aa != new_aa:
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:
alvals['tag_ids'] = [(6, None, new_aa_tags.ids)]
return alvals
@api.multi
def _update_payment_term_move(self):
self.ensure_one()
inv = self.invoice_id
if (
self.invoice_payment_term_id and
self.invoice_payment_term_id != inv.invoice_payment_term_id):
self.payment_term_id and
self.payment_term_id != inv.payment_term_id and
inv.move_id):
# I don't update pay term when the invoice is partially (or fully)
# paid because if you have a payment term with several lines
# of the same amount, you would also have to take into account
# the reconcile marks to put the new maturity date on the right
# lines
if inv.payment_id:
if inv.payment_ids:
raise UserError(_(
"This wizard doesn't support the update of payment "
"terms on an invoice which is partially or fully "
"paid."))
prec = self.env['decimal.precision'].precision_get('Account')
term_res = self.invoice_payment_term_id.compute(
term_res = self.payment_term_id.compute(
inv.amount_total, inv.date_invoice)[0]
new_pterm = {} # key = int(amount * 100), value = [date1, date2]
for entry in term_res:
@@ -176,10 +220,11 @@ class AccountMoveUpdate(models.TransientModel):
"new payment term '%s'. You can only switch to a "
"payment term that has the same number of terms "
"with the same amount.") % (
inv.invoice_payment_term_id.name, self.invoice_payment_term_id.name))
inv.payment_term_id.name, self.payment_term_id.name))
for line in lines:
line.date_maturity = new_pterm[iamount].pop()
@api.multi
def run(self):
self.ensure_one()
inv = self.invoice_id
@@ -190,24 +235,28 @@ class AccountMoveUpdate(models.TransientModel):
if ivals:
updated = True
inv.write(ivals)
if inv:
for ml in inv.line_ids.filtered(
if inv.move_id:
mvals = self._prepare_move()
if mvals:
inv.move_id.write(mvals)
for ml in inv.move_id.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)
inv_line = self._get_matching_inv_line(ml)
mlvals = self._prepare_move_line(inv_line)
if mlvals:
updated = True
ml.write(mlvals)
aalines = ml.analytic_line_ids
alvals = self._prepare_analytic_line(inv_line)
if aalines and alvals:
updated = True
if ('account_id' in alvals and
alvals['account_id'] is False):
former_aa = analytic_account
former_aa = inv_line.account_analytic_id
to_remove_aalines = aalines.filtered(
lambda rec: rec.account_id == former_aa)
# remove existing analytic line
@@ -230,14 +279,14 @@ class AccountMoveUpdate(models.TransientModel):
return True
class AccountMoveLineUpdate(models.TransientModel):
_name = 'account.move.line.update'
class AccountInvoiceLineUpdate(models.TransientModel):
_name = 'account.invoice.line.update'
_description = 'Update non-legal fields of invoice lines'
parent_id = fields.Many2one(
'account.move.update', string='Wizard', ondelete='cascade')
'account.invoice.update', string='Wizard', ondelete='cascade')
invoice_line_id = fields.Many2one(
'account.move.line', string='Invoice Line', readonly=True)
'account.invoice.line', string='Invoice Line', readonly=True)
name = fields.Text(string='Description', required=True)
display_type = fields.Selection([
('line_section', "Section"),
@@ -247,7 +296,7 @@ class AccountMoveLineUpdate(models.TransientModel):
readonly=True)
price_subtotal = fields.Float(
string='Amount', readonly=True, digits=dp.get_precision('Account'))
analytic_account_id = fields.Many2one(
account_analytic_id = fields.Many2one(
'account.analytic.account', string='Analytic Account')
analytic_tag_ids = fields.Many2many(
'account.analytic.tag', string='Analytic Tags')

View File

@@ -7,7 +7,7 @@
<odoo>
<record id="account_invoice_update_form" model="ir.ui.view">
<field name="model">account.move.update</field>
<field name="model">account.invoice.update</field>
<field name="arch" type="xml">
<form string="Update Invoice Wizard">
<group name="main">
@@ -15,12 +15,13 @@
<field name="type" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="partner_id" invisible="1"/>
<field name="ref" attrs="{'invisible': [('type', 'not in', ('in_invoice', 'in_refund'))]}"/>
<field name="invoice_origin"/>
<field name="reference" attrs="{'invisible': [('type', 'not in', ('in_invoice', 'in_refund'))]}"/>
<field name="origin"/>
<field name="name"/>
<field name="invoice_payment_term_id" widget="selection"/>
<field name="payment_term_id" widget="selection"/>
<field name="partner_bank_id"/>
<field name="user_id"/>
<field name="comment"/>
</group>
<group name="lines">
<field name="line_ids" nolabel="1">
@@ -30,7 +31,7 @@
<field name="name"/>
<field name="quantity" attrs="{'invisible': [('display_type', '!=', False)]}"/>
<field name="price_subtotal" attrs="{'invisible': [('display_type', '!=', False)]}"/>
<field name="analytic_account_id" attrs="{'invisible': [('display_type', '!=', False)]}" groups="analytic.group_analytic_accounting"/>
<field name="account_analytic_id" attrs="{'invisible': [('display_type', '!=', False)]}" groups="analytic.group_analytic_accounting"/>
<field name="analytic_tag_ids" attrs="{'invisible': [('display_type', '!=', False)]}" groups="analytic.group_analytic_accounting" widget="many2many_tags"/>
</tree>
</field>
@@ -45,7 +46,7 @@
<record id="account_invoice_update_action" model="ir.actions.act_window">
<field name="name">Invoice Update Wizard</field>
<field name="res_model">account.move.update</field>
<field name="res_model">account.invoice.update</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>

View File

@@ -1,18 +0,0 @@
# Copyright 2022 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Menu Usability',
'version': '14.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Small usability enhancements in account_menu module',
'author': 'Akretion',
'website': 'https://github.com/akretion/odoo-usability',
'depends': ['account_menu'],
'data': [
'views/account_menu.xml',
],
'installable': True,
}

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- Accounting Templates are useful only when creating a new company/loading
a chart of accounts, so we put it under 'Settings > Technical' and not
under 'Invoicing > Configuration' which already has a lot of menu entries -->
<record id="account_menu.menu_account_coa_settings" model="ir.ui.menu">
<field name="name">Accounting Templates</field>
<field name="parent_id" ref="base.menu_custom"/>
</record>
</odoo>

View File

@@ -1 +0,0 @@
from . import models

View File

@@ -1,29 +0,0 @@
# Copyright 2022 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Move Label Copy',
'version': '14.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'When creating a Journal Entry manually, copy label from line to line',
'description': """
Account Move Label Copy
=======================
This module is ONLY for users who don't accept to use the 'Reference' (ref) to store the description of the journal entry (the recommended method), but want to use the label on the lines for that purpose (name field of account.move.line). With this module, the label of the first line will be copied by default to the other lines upon creation of each line.
I don't recommend the use of this module.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': [
'account',
'base_view_inheritance_extension',
],
'data': [
'views/account_move.xml',
],
'installable': True,
}

View File

@@ -1 +0,0 @@
from . import account_move

View File

@@ -1,13 +0,0 @@
# Copyright 2022 Akretion France (http://www.akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models
class AccountMove(models.Model):
_inherit = "account.move"
default_move_line_name = fields.Char(
related='line_ids.name',
string='Default Journal Item Label')

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_move_form" model="ir.ui.view">
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<field name="narration" position="after">
<field name="default_move_line_name" invisible="1"/>
</field>
<xpath expr="//page[@id='aml_tab']/field[@name='line_ids']" position="attributes">
<attribute name="context" operation="python_dict" key="default_name">default_move_line_name</attribute>
</xpath>
</field>
</record>
</odoo>

View File

@@ -52,7 +52,6 @@ This modules adds the following functions:
* don't attach PDF upon invoice report generation on supplier invoices/refunds
* Add filter on debit and credit amount for Move Lines
* Add supplier invoice number in invoice tree view
* Add date in outstanding payment widget on invoice form view (requires `odoo PR 84180 <https://github.com/odoo/odoo/pull/84180>`_)
Together with this module, I recommend the use of the following modules:

View File

@@ -1,2 +1,4 @@
from . import models
from . import account
#from . import account_invoice_report
from . import partner
from . import wizard

View File

@@ -1,10 +1,10 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# Copyright 2015-2019 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Account Usability',
'version': '14.0.1.0.0',
'version': '12.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Small usability enhancements in account module',
@@ -12,33 +12,17 @@
'website': 'http://www.akretion.com',
'depends': [
'account',
'base_view_inheritance_extension',
'base_usability', # needed only to access base_usability.group_nobody
# in v12, I may create a module only for group_nobody
],
'data': [
'views/account_account_type.xml',
'views/account_account.xml',
'views/account_group.xml',
'views/account_analytic_account.xml',
'views/account_analytic_group.xml',
'views/account_bank_statement.xml',
'views/account_invoice_report.xml',
'views/account_journal.xml',
'views/account_move.xml',
'views/account_menu.xml',
'views/account_tax.xml',
'views/product.xml',
'views/res_config_settings.xml',
'views/res_partner.xml',
'views/res_company.xml',
'views/account_report.xml',
'views/account_reconcile_model.xml',
'account_view.xml',
'account_report.xml',
'account_invoice_report_view.xml',
'partner_view.xml',
'wizard/account_invoice_mark_sent_view.xml',
'wizard/account_group_generate_view.xml',
'wizard/account_payment_register_views.xml',
'security/ir.model.access.csv',
'report/invoice_report.xml',
],
'qweb': ['static/src/xml/account_payment.xml'],
'installable': True,
}

View File

@@ -0,0 +1,695 @@
# Copyright 2015-2019 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields, api, _
from odoo.tools import float_compare, float_is_zero
from odoo.tools.misc import formatLang
from odoo.exceptions import UserError, ValidationError
from odoo.osv import expression
from odoo import SUPERUSER_ID
import logging
logger = logging.getLogger(__name__)
class AccountInvoice(models.Model):
_inherit = 'account.invoice'
origin = fields.Char(track_visibility='onchange')
reference = fields.Char(track_visibility='onchange')
sent = fields.Boolean(track_visibility='onchange')
date_invoice = fields.Date(track_visibility='onchange')
date_due = fields.Date(track_visibility='onchange')
payment_term_id = fields.Many2one(track_visibility='onchange')
account_id = fields.Many2one(track_visibility='onchange')
journal_id = fields.Many2one(track_visibility='onchange')
partner_bank_id = fields.Many2one(track_visibility='onchange')
fiscal_position_id = fields.Many2one(track_visibility='onchange')
amount_total = fields.Monetary(track_visibility='onchange')
# I want to see the number of cancelled invoice in chatter
move_id = fields.Many2one(track_visibility='onchange')
# for invoice report
has_discount = fields.Boolean(
compute='_compute_has_discount', readonly=True)
# has_attachment is useful for those who use attachment to archive
# supplier invoices. It allows them to find supplier invoices
# that don't have any attachment
has_attachment = fields.Boolean(
compute='_compute_has_attachment',
search='_search_has_attachment', readonly=True)
sale_dates = fields.Char(
compute="_compute_sales_dates", readonly=True,
help="This information appears on invoice qweb report "
"(you may use it for your own report)")
def _compute_has_discount(self):
prec = self.env['decimal.precision'].precision_get('Discount')
for inv in self:
has_discount = False
for line in inv.invoice_line_ids:
if not float_is_zero(line.discount, precision_digits=prec):
has_discount = True
break
inv.has_discount = has_discount
def _compute_has_attachment(self):
iao = self.env['ir.attachment']
for inv in self:
if iao.search([
('res_model', '=', 'account.invoice'),
('res_id', '=', inv.id),
('type', '=', 'binary'),
('company_id', '=', inv.company_id.id)], limit=1):
inv.has_attachment = True
else:
inv.has_attachment = False
def _search_has_attachment(self, operator, value):
att_inv_ids = {}
if operator == '=':
search_res = self.env['ir.attachment'].search_read([
('res_model', '=', 'account.invoice'),
('type', '=', 'binary'),
('res_id', '!=', False)], ['res_id'])
for att in search_res:
att_inv_ids[att['res_id']] = True
res = [('id', value and 'in' or 'not in', list(att_inv_ids))]
return res
# when you have an invoice created from a lot of sale orders, the 'name'
# field is very large, which makes the name_get() of that invoice very big
# which screws-up the form view of that invoice because of the link at the
# top of the screen
# That's why we have to cut the name_get() when it's too long
def name_get(self):
old_res = super(AccountInvoice, self).name_get()
res = []
for old_re in old_res:
name = old_re[1]
if name and len(name) > 100:
# nice cut
name = u'%s ...' % ', '.join(name.split(', ')[:3])
# if not enough, hard cut
if len(name) > 120:
name = u'%s ...' % old_re[1][:120]
res.append((old_re[0], name))
return res
# I really hate to see a "/" in the 'name' field of the account.move.line
# generated from customer invoices linked to the partners' account because:
# 1) the label of an account move line is an important field, we can't
# write a rubbish '/' in it !
# 2) the 'name' field of the account.move.line is used in the overdue
# letter, and '/' is not meaningful for our customer !
# TODO mig to v12
# @api.multi
# def action_move_create(self):
# res = super(AccountInvoice, self).action_move_create()
# for inv in self:
# self._cr.execute(
# "UPDATE account_move_line SET name= "
# "CASE WHEN name='/' THEN %s "
# "ELSE %s||' - '||name END "
# "WHERE move_id=%s", (inv.number, inv.number, inv.move_id.id))
# self.invalidate_cache()
# return res
def delete_lines_qty_zero(self):
lines = self.env['account.invoice.line'].search([
('invoice_id', 'in', self.ids), ('quantity', '=', 0)])
lines.unlink()
return True
def fix_invoice_attachment_filename(self):
# This script is designed to fix attachment of invoices
# badly generated by Odoo v8. I found this problem in Nov 2018 at
# Encres Dubuit when investigating a bug where Odoo would create a
# new attachment when printing an old invoice that already had the
# PDF of the invoice as attachment
logger.info('START fix customer invoice attachment filename')
# Run this script as admin to fix problem in all companies
self = self.sudo()
attachs = self.env['ir.attachment'].search([
('res_model', '=', 'account.invoice'),
('res_id', '!=', False),
('type', '=', 'binary'),
('name', '=like', 'INV%.pdf'),
('datas_fname', '=like', 'INV%.pdf.pdf')])
for attach in attachs:
inv = self.browse(attach.res_id)
if inv.type in ('out_invoice', 'out_refund'):
attach.datas_fname = attach.name
logger.info(
'Fixed field datas_fname of attachment ID %s name %s',
attach.id, attach.name)
logger.info('END fix customer invoice attachment filename')
# for report
def py3o_lines_layout(self):
self.ensure_one()
res = []
has_sections = False
subtotal = 0.0
sign = self.type == 'out_refund' and -1 or 1
for line in self.invoice_line_ids:
if line.display_type == 'line_section':
# insert line
if has_sections:
res.append({'subtotal': subtotal})
subtotal = 0.0 # reset counter
has_sections = True
else:
if not line.display_type:
subtotal += line.price_subtotal * sign
res.append({'line': line})
if has_sections: # insert last subtotal line
res.append({'subtotal': subtotal})
# res:
# [
# {'line': account_invoice_line(1) with display_type=='line_section'},
# {'line': account_invoice_line(2) without display_type},
# {'line': account_invoice_line(3) without display_type},
# {'line': account_invoice_line(4) with display_type=='line_note'},
# {'subtotal': 8932.23},
# ]
return res
def _compute_sales_dates(self):
""" French law requires to set sale order dates into invoice
returned string: "sale1 (date1), sale2 (date2) ..."
"""
for inv in self:
sales = inv.invoice_line_ids.mapped(
'sale_line_ids').mapped('order_id')
lang = inv.partner_id.commercial_partner_id.lang
date_format = self.env["res.lang"]._lang_get(
lang or "").date_format
dates = ["%s%s" % (
x.name,
x.confirmation_date and " (%s)" %
# only when confirmation_date display it
x.confirmation_date.strftime(date_format) or "")
for x in sales]
inv.sale_dates = ", ".join(dates)
class AccountInvoiceLine(models.Model):
_inherit = 'account.invoice.line'
# In the 'account' module, we have related stored field for:
# company_id, partner_id, currency_id
invoice_type = fields.Selection(store=True)
date_invoice = fields.Date(
related='invoice_id.date_invoice', store=True, readonly=True)
commercial_partner_id = fields.Many2one(
related='invoice_id.partner_id.commercial_partner_id',
store=True, readonly=True, compute_sudo=True)
state = fields.Selection(
related='invoice_id.state', store=True, readonly=True,
string='Invoice State')
invoice_number = fields.Char(
related='invoice_id.move_id.name', store=True, readonly=True,
string='Invoice Number')
class AccountJournal(models.Model):
_inherit = 'account.journal'
@api.multi
@api.depends(
'name', 'currency_id', 'company_id', 'company_id.currency_id', 'code')
def name_get(self):
res = []
if self._context.get('journal_show_code_only'):
for journal in self:
res.append((journal.id, journal.code))
return res
else:
for journal in self:
currency = journal.currency_id or\
journal.company_id.currency_id
name = "[%s] %s (%s)" % (
journal.code, journal.name, currency.name)
res.append((journal.id, name))
return res
@api.constrains('default_credit_account_id', 'default_debit_account_id')
def _check_account_type_on_bank_journal(self):
bank_acc_type = self.env.ref('account.data_account_type_liquidity')
for jrl in self:
if jrl.type in ('bank', 'cash'):
if (
jrl.default_debit_account_id and
jrl.default_debit_account_id.user_type_id !=
bank_acc_type):
raise ValidationError(_(
"On journal '%s', the default debit account '%s' "
"should be configured with Type = 'Bank and Cash'.")
% (jrl.display_name,
jrl.default_debit_account_id.display_name))
if (
jrl.default_credit_account_id and
jrl.default_credit_account_id.user_type_id !=
bank_acc_type):
raise ValidationError(_(
"On journal '%s', the default credit account '%s' "
"should be configured with Type = 'Bank and Cash'.")
% (jrl.display_name,
jrl.default_credit_account_id.display_name))
class AccountAccount(models.Model):
_inherit = 'account.account'
@api.multi
@api.depends('name', 'code')
def name_get(self):
if self._context.get('account_account_show_code_only'):
res = []
for record in self:
res.append((record.id, record.code))
return res
else:
return super(AccountAccount, self).name_get()
# https://github.com/odoo/odoo/issues/23040
# TODO mig to v12
def fix_bank_account_types(self):
aao = self.env['account.account']
companies = self.env['res.company'].search([])
if len(companies) > 1 and self.env.user.id != SUPERUSER_ID:
raise UserError(
"In multi-company setups, you should run this "
"script as admin user")
logger.info("START the script 'fix bank and cash account types'")
bank_type = self.env.ref('account.data_account_type_liquidity')
asset_type = self.env.ref('account.data_account_type_current_assets')
journals = self.env['account.journal'].search(
[('type', 'in', ('bank', 'cash'))], order='company_id')
journal_accounts_bank_type = aao
for journal in journals:
for account in [
journal.default_credit_account_id,
journal.default_debit_account_id]:
if account:
if account.user_type_id != bank_type:
account.user_type_id = bank_type.id
logger.info(
'Company %s: Account %s updated to Bank '
'and Cash type',
account.company_id.display_name, account.code)
if account not in journal_accounts_bank_type:
journal_accounts_bank_type += account
accounts = aao.search([
('user_type_id', '=', bank_type.id)], order='company_id, code')
for account in accounts:
if account not in journal_accounts_bank_type:
account.user_type_id = asset_type.id
logger.info(
'Company %s: Account %s updated to Current Asset type',
account.company_id.display_name, account.code)
logger.info("END of the script 'fix bank and cash account types'")
return True
# TODO mig to v12
@api.model
def create_account_groups(self, level=2, name_prefix=u'Comptes '):
'''Should be launched by a script. Make sure the account_group module is installed
(the account_usability module doesn't depend on it currently'''
assert level >= 1
assert isinstance(level, int)
companies = self.env['res.company'].search([])
if len(companies) > 1:
logger.info(
'Multi-company detected: running script create_account_groups '
'as admin')
self = self.sudo()
ago = self.env['account.group']
groups = ago.search([])
if groups:
raise UserError(_("Some account groups already exists"))
accounts = self.search([])
struct = {'childs': {}}
for account in accounts:
assert len(account.code) > level
n = 1
parent = struct
gparent = False
while n <= level:
group_code = account.code[:n]
if group_code not in parent['childs']:
new_group = ago.create({
'name': u'%s%s' % (name_prefix or '', group_code),
'code_prefix': group_code,
'parent_id': gparent and gparent.id or False,
})
parent['childs'][group_code] = {'obj': new_group, 'childs': {}}
parent = parent['childs'][group_code]
gparent = parent['obj']
n += 1
account.group_id = gparent.id
class AccountAnalyticAccount(models.Model):
_inherit = 'account.analytic.account'
@api.multi
def name_get(self):
if self._context.get('analytic_account_show_code_only'):
res = []
for record in self:
res.append((record.id, record.code or record.name))
return res
else:
return super(AccountAnalyticAccount, self).name_get()
_sql_constraints = [(
'code_company_unique',
'unique(code, company_id)',
'An analytic account with the same code already '
'exists in the same company!')]
class AccountMove(models.Model):
_inherit = 'account.move'
default_move_line_name = fields.Char(
string='Default Label', states={'posted': [('readonly', True)]})
# By default, we can still modify "ref" when account move is posted
# which seems a bit lazy for me...
ref = fields.Char(states={'posted': [('readonly', True)]})
date = fields.Date(copy=False)
default_account_id = fields.Many2one(
related='journal_id.default_debit_account_id', readonly=True)
default_credit = fields.Float(
compute='_compute_default_credit_debit', readonly=True)
default_debit = fields.Float(
compute='_compute_default_credit_debit', readonly=True)
@api.depends('line_ids.credit', 'line_ids.debit')
def _compute_default_credit_debit(self):
for move in self:
total_debit = total_credit = default_debit = default_credit = 0.0
for l in move.line_ids:
total_debit += l.debit
total_credit += l.credit
# I could use float_compare, but I don't think it's really needed
# in this context
if total_debit > total_credit:
default_credit = total_debit - total_credit
else:
default_debit = total_credit - total_debit
move.default_credit = default_credit
move.default_debit = default_debit
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
# Native order:
# _order = "date desc, id desc"
# Problem: when you manually create a journal entry, the
# order of the lines is inverted when you save ! It is quite annoying for
# the user...
_order = "date desc, id asc"
# Update field only to add a string (there is no string in account module)
invoice_id = fields.Many2one(string='Invoice')
account_reconcile = fields.Boolean(
related='account_id.reconcile', readonly=True)
full_reconcile_id = fields.Many2one(string='Full Reconcile')
matched_debit_ids = fields.One2many(string='Partial Reconcile Debit')
matched_credit_ids = fields.One2many(string='Partial Reconcile Credit')
reconcile_string = fields.Char(
compute='_compute_reconcile_string', string='Reconcile', store=True)
@api.onchange('credit')
def _credit_onchange(self):
prec = self.env['decimal.precision'].precision_get('Account')
if (
not float_is_zero(self.credit, precision_digits=prec) and
not float_is_zero(self.debit, precision_digits=prec)):
self.debit = 0
@api.onchange('debit')
def _debit_onchange(self):
prec = self.env['decimal.precision'].precision_get('Account')
if (
not float_is_zero(self.debit, precision_digits=prec) and
not float_is_zero(self.credit, precision_digits=prec)):
self.credit = 0
@api.onchange('currency_id', 'amount_currency')
def _amount_currency_change(self):
prec = self.env['decimal.precision'].precision_get('Account')
if (
self.currency_id and
self.amount_currency and
float_is_zero(self.credit, precision_digits=prec) and
float_is_zero(self.debit, precision_digits=prec)):
date = self.date or None
amount_company_currency = self.currency_id.with_context(
date=date).compute(
self.amount_currency, self.env.user.company_id.currency_id)
precision = self.env['decimal.precision'].precision_get('Account')
if float_compare(
amount_company_currency, 0,
precision_digits=precision) == -1:
self.debit = amount_company_currency * -1
else:
self.credit = amount_company_currency
def show_account_move_form(self):
self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id(
'account', 'action_move_line_form')
action.update({
'res_id': self.move_id.id,
'view_id': False,
'views': False,
'view_mode': 'form,tree',
})
return action
@api.depends(
'full_reconcile_id', 'matched_debit_ids', 'matched_credit_ids')
def _compute_reconcile_string(self):
for line in self:
rec_str = False
if line.full_reconcile_id:
rec_str = line.full_reconcile_id.name
else:
rec_str = ', '.join([
'a%d' % pr.id for pr in line.matched_debit_ids + line.matched_credit_ids])
line.reconcile_string = rec_str
class AccountPartialReconcile(models.Model):
_inherit = "account.partial.reconcile"
_rec_name = "id"
def name_get(self):
res = []
for rec in self:
# There is no seq for partial rec, so I simulate one with the ID
# Prefix for full rec: 'A' (upper case)
# Prefix for partial rec: 'a' (lower case)
amount_fmt = formatLang(self.env, rec.amount, currency_obj=rec.company_currency_id)
name = 'a%d (%s)' % (rec.id, amount_fmt)
res.append((rec.id, name))
return res
class AccountBankStatement(models.Model):
_inherit = 'account.bank.statement'
start_date = fields.Date(
compute='_compute_dates', string='Start Date', readonly=True,
store=True)
end_date = fields.Date(
compute='_compute_dates', string='End Date', readonly=True,
store=True)
@api.multi
@api.depends('line_ids.date')
def _compute_dates(self):
for st in self:
dates = [line.date for line in st.line_ids]
st.start_date = dates and min(dates) or False
st.end_date = dates and max(dates) or False
@api.multi
@api.depends('name', 'start_date', 'end_date')
def name_get(self):
res = []
for statement in self:
name = "%s (%s => %s)" % (
statement.name, statement.start_date, statement.end_date)
res.append((statement.id, name))
return res
class AccountBankStatementLine(models.Model):
_inherit = 'account.bank.statement.line'
# Native order is:
# _order = 'statement_id desc, sequence, id desc'
_order = 'statement_id desc, date desc, sequence, id desc'
# Disable guessing for reconciliation
# because my experience with several customers shows that it is a problem
# in the following scenario : move line 'x' has been "guessed" by OpenERP
# to be reconciled with a statement line 'Y' at the end of the bank
# statement, but it is a mistake because it should be reconciled with
# statement line 'B' at the beginning of the bank statement
# When the user is on statement line 'B', he tries to select
# move line 'x', but it can't find it... because it is already "reserved"
# by the guess of OpenERP for statement line 'Y' ! To solve this problem,
# the user must go to statement line 'Y' and unselect move line 'x'
# and then come back on statement line 'B' and select move line 'A'...
# but non super-expert users can't do that because it is impossible to
# figure out that the fact that the user can't find move line 'x'
# is caused by this.
# Set search_reconciliation_proposition to False by default
# TODO: re-write in v10
# def get_data_for_reconciliations(
# self, cr, uid, ids, excluded_ids=None,
# search_reconciliation_proposition=False, context=None):
# # Make variable name shorted for PEP8 !
# search_rec_prop = search_reconciliation_proposition
# return super(AccountBankStatementLine, self).\
# get_data_for_reconciliations(
# cr, uid, ids, excluded_ids=excluded_ids,
# search_reconciliation_proposition=search_rec_prop,
# context=context)
def _prepare_reconciliation_move(self, move_ref):
vals = super(AccountBankStatementLine, self).\
_prepare_reconciliation_move(move_ref)
# By default, ref contains the name of the statement + name of the
# statement line. It causes 2 problems:
# 1) The 'ref' field is too big
# 2) The name of the statement line is already written in the name of
# the move line -> not useful to have the info 2 times
# In the end, I think it's better to just put nothing (we could write
# the name of the statement which has the account number, but it
# doesn't bring any useful info to the accountant)
# The only "good" thing to do would be to have a sequence per
# statement line and write it in this 'ref' field
# But that would required an additionnal field on statement lines
vals['ref'] = False
return vals
def show_account_move(self):
self.ensure_one()
action = self.env['ir.actions.act_window'].for_xml_id(
'account', 'action_move_line_form')
if self.journal_entry_ids:
action.update({
'views': False,
'view_id': False,
'view_mode': 'form,tree',
'res_id': self.journal_entry_ids[0].move_id.id,
})
return action
else:
raise UserError(_(
'No journal entry linked to this bank statement line.'))
class AccountFiscalPosition(models.Model):
_inherit = 'account.fiscal.position'
# TODO mig to v12 ?
@api.model
def get_fiscal_position_no_partner(
self, company_id=None, vat_subjected=False, country_id=None):
'''This method is inspired by the method get_fiscal_position()
in odoo/addons/account/partner.py : it uses the same algo
but without a real partner.
Returns a recordset of fiscal position, or False'''
domains = [[
('auto_apply', '=', True),
('vat_required', '=', vat_subjected),
('company_id', '=', company_id)]]
if vat_subjected:
domains += [[
('auto_apply', '=', True),
('vat_required', '=', False),
('company_id', '=', company_id)]]
for domain in domains:
if country_id:
fps = self.search(
domain + [('country_id', '=', country_id)], limit=1)
if fps:
return fps[0]
fps = self.search(
domain +
[('country_group_id.country_ids', '=', country_id)],
limit=1)
if fps:
return fps[0]
fps = self.search(
domain +
[('country_id', '=', None), ('country_group_id', '=', None)],
limit=1)
if fps:
return fps[0]
return False
class AccountReconcileModel(models.Model):
_inherit = 'account.reconcile.model'
@api.onchange('name')
def onchange_name(self):
# Do NOT copy by default name on label
# Because it's much better to have the bank statement line label as
# label of the counter-part move line, then the label of the button
assert True # Stupid line of code just to have something...
class AccountIncoterms(models.Model):
_inherit = 'account.incoterms'
@api.depends('code', 'name')
def name_get(self):
res = []
for rec in self:
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
return res
class AccountReconciliation(models.AbstractModel):
_inherit = 'account.reconciliation.widget'
# Add ability to filter by account code in the work interface of the
# bank statement
@api.model
def _domain_move_lines(self, search_str):
str_domain = super(AccountReconciliation, self)._domain_move_lines(
search_str)
account_code_domain = [('account_id.code', '=ilike', search_str + '%')]
str_domain = expression.OR([str_domain, account_code_domain])
return str_domain
@api.model
def _domain_move_lines_for_reconciliation(
self, st_line, aml_accounts, partner_id,
excluded_ids=None, search_str=False):
domain = super()._domain_move_lines_for_reconciliation(
st_line, aml_accounts, partner_id,
excluded_ids=excluded_ids, search_str=search_str)
# We want to replace a domain item by another one
position = domain.index(('payment_id', '<>', False))
domain[position] = ['journal_id', '=', st_line.journal_id.id]
return domain
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
transfer_account_id = fields.Many2one(
related='company_id.transfer_account_id', readonly=False)

View File

@@ -0,0 +1,26 @@
# Copyright 2018-2019 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
class AccountInvoiceReport(models.Model):
_inherit = 'account.invoice.report'
number = fields.Char(string="Number", readonly=True)
def _sub_select(self):
select_str = super(AccountInvoiceReport, self)._sub_select()
select_str += ", ai.number"
return select_str
def _select(self):
select_str = super(AccountInvoiceReport, self)._select()
select_str += ", sub.number"
return select_str
def _group_by(self):
group_by_str = super(AccountInvoiceReport, self)._group_by()
group_by_str += ", ai.number"
return group_by_str

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account_invoice_report_tree" model="ir.ui.view">
<field name="name">usability.account.invoice.report.tree</field>
<field name="model">account.invoice.report</field>
<field name="arch" type="xml">
<tree string="Invoices Analysis">
<field name="number"/>
<field name="date"/>
<field name="date_due"/>
<field name="type"/>
<field name="commercial_partner_id"/>
<field name="user_id"/>
<field name="product_id"/>
<field name="product_qty" sum="1"/>
<field name="uom_name" groups="uom.group_uom"/>
<field name="price_total" sum="1"/>
<field name="state"/>
</tree>
</field>
</record>
<record id="account.action_account_invoice_report_all_supp" model="ir.actions.act_window">
<field name="context">{'search_default_current': 1, 'search_default_supplier': 1, 'search_default_year': 1}</field> <!-- Remove group_by_no_leaf, which breaks tree view -->
</record>
<record id="account.action_account_invoice_report_all" model="ir.actions.act_window">
<field name="context">{'search_default_current': 1, 'search_default_customer': 1, 'search_default_year': 1}</field> <!-- Remove group_by_no_leaf, which breaks tree view -->
</record>
<record id="view_account_invoice_report_pivot" model="ir.ui.view">
<field name="name">usability.account.invoice.report</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_pivot"/>
<field name="arch" type="xml">
<pivot position="attributes">
<attribute name="disable_linking"></attribute>
</pivot>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018-2019 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account.account_invoices" model="ir.actions.report">
<!-- Don't attach on supplier invoices/refunds ! -->
<field name="attachment">(object.type in ('out_invoice', 'out_refund')) and (object.state in ('open','in_payment','paid')) and ('INV'+(object.number or '').replace('/','')+'.pdf')</field>
</record>
</odoo>

View File

@@ -0,0 +1,13 @@
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
index 53f28e0c620..1721d01edf9 100644
--- a/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
+++ b/addons/account/static/src/js/reconciliation/reconciliation_renderer.js
@@ -514,7 +514,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
}
return this.model.makeRecord('account.bank.statement.line', [field], {
partner_id: {
- domain: ["|", ["is_company", "=", true], ["parent_id", "=", false], "|", ["customer", "=", true], ["supplier", "=", true]],
+ domain: ["|", ["is_company", "=", true], ["parent_id", "=", false]],
options: {
no_open: true
}

View File

@@ -0,0 +1,578 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2019 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- INVOICE -->
<record id="invoice_supplier_form" model="ir.ui.view">
<field name="name">account_usability.supplier.invoice.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_supplier_form"/>
<field name="arch" type="xml">
<field name="fiscal_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<field name="incoterm_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<field name="invoice_line_ids" position="before">
<button name="delete_lines_qty_zero" states="draft" string="⇒ Delete lines qty=0" type="object" class="oe_link oe_right" groups="account.group_account_invoice"/>
</field>
<xpath expr="//field[@name='tax_line_ids']/tree/field[@name='amount']" position="before">
<field name="base" readonly="1"/>
</xpath>
</field>
</record>
<record id="invoice_form" model="ir.ui.view">
<field name="name">account_usability.invoice.form</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_form"/>
<field name="arch" type="xml">
<field name="fiscal_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<field name="incoterm_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<!-- move sent field and make it visible -->
<field name="sent" position="replace"/>
<field name="move_id" position="before">
<field name="sent"/>
</field>
<xpath expr="//field[@name='tax_line_ids']/tree/field[@name='amount']" position="before">
<field name="base" readonly="1"/>
</xpath>
<!-- Warning: there are 2 invoice_print buttons in the native view... probably a bug -->
<!--
<xpath expr="//button[@name='invoice_print']" position="attributes">
<attribute name="attrs">{'invisible': [('state', 'not in', ('open', 'paid'))]}</attribute>
</xpath>
<xpath expr="//button[@name='invoice_print'][2]" position="attributes">
<attribute name="attrs">{'invisible': True}</attribute>
</xpath> -->
</field>
</record>
<record id="invoice_tree" model="ir.ui.view">
<field name="name">account_usability.invoice_tree</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.invoice_tree"/>
<field name="arch" type="xml">
<field name="reference" position="attributes">
<attribute name="invisible">not context.get('type') in ('in_invoice', 'in_refund')</attribute>
</field>
</field>
</record>
<record id="view_account_invoice_filter" model="ir.ui.view">
<field name="name">account_usability.invoice.search</field>
<field name="model">account.invoice</field>
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
<field name="arch" type="xml">
<filter name="late" position="after">
<separator/>
<filter name="to_send" string="To Send" domain="[('sent', '=', False), ('state', 'in', ('open', 'paid'))]"/>
<filter name="sent" string="Sent" domain="[('sent', '=', True)]"/>
<separator/>
<filter name="no_attachment" string="Missing Attachment" domain="[('has_attachment', '=', False)]"/>
</filter>
</field>
</record>
<!-- Having a menu entry on invoice lines is often very usefull for odoo user:
they can search in their lines, etc...
So I enhance the generic views and add actions, but I don't add menu entries here ;
the creation of the corresponding menu entry should be done in the customer-specifc
module -->
<record id="view_invoice_line_tree" model="ir.ui.view">
<field name="name">account_usability.invoice_line_tree</field>
<field name="model">account.invoice.line</field>
<field name="inherit_id" ref="account.view_invoice_line_tree"/>
<field name="arch" type="xml">
<field name="name" position="before">
<field name="partner_id" invisible="not context.get('show_invoice_fields')"/>
<field name="date_invoice" invisible="not context.get('show_invoice_fields')"/>
<field name="invoice_number" invisible="not context.get('show_invoice_fields')"/>
</field>
<field name="currency_id" position="after">
<field name="state" invisible="not context.get('show_invoice_fields')"/>
<field name="invoice_type" invisible="1"/>
</field>
<field name="quantity" position="attributes">
<attribute name="sum">1</attribute>
</field>
<xpath expr="/tree" position="attributes">
<attribute name="decoration-info">state == 'draft'</attribute>
<attribute name="decoration-muted">state == 'cancel'</attribute>
<attribute name="edit">0</attribute>
<attribute name="create">0</attribute>
</xpath>
</field>
</record>
<record id="account_invoice_line_search" model="ir.ui.view">
<field name="name">account_usability.invoice_line_search</field>
<field name="model">account.invoice.line</field>
<field name="arch" type="xml">
<search string="Search Invoice Lines">
<field name="partner_id"/>
<field name="product_id"/>
<field name="account_id"/>
<field name="invoice_number"/>
<field name="name"/>
<filter name="out_invoice" string="Customer Invoices"
domain="[('invoice_type', '=', 'out_invoice')]"/>
<filter name="out_refund" string="Customer Refunds"
domain="[('invoice_type', '=', 'out_refund')]"/>
<filter name="in_invoice" string="Supplier Invoices"
domain="[('invoice_type', '=', 'in_invoice')]"/>
<filter name="in_refund" string="Supplier Refunds"
domain="[('invoice_type', '=', 'in_refund')]"/>
<separator/>
<filter name="draft" string="Draft" domain="[('state', '=', 'draft')]"/>
<filter name="unpaid" string="Not Paid" domain="[('state', '=', 'open')]"/>
<filter name="paid" string="Paid" domain="[('state', '=', 'paid')]"/>
<group string="Group By" name="groupby">
<filter name="partner_groupby" string="Partner"
context="{'group_by': 'partner_id'}"/>
<filter name="date_groupby" string="Invoice Date"
context="{'group_by': 'date_invoice'}"/>
<filter name="product_groupby" string="Product"
context="{'group_by': 'product_id'}"/>
<filter name="account_groupby" string="Account"
context="{'group_by': 'account_id'}"/>
</group>
</search>
</field>
</record>
<record id="out_invoice_line_action" model="ir.actions.act_window">
<field name="name">Customer Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'out_invoice')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="out_refund_line_action" model="ir.actions.act_window">
<field name="name">Customer Refund Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'out_refund')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="out_invoice_refund_line_action" model="ir.actions.act_window">
<field name="name">Customer Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', 'in', ('out_invoice', 'out_refund'))]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="in_invoice_line_action" model="ir.actions.act_window">
<field name="name">Supplier Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'in_invoice')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="in_refund_line_action" model="ir.actions.act_window">
<field name="name">Supplier Refund Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', '=', 'in_refund')]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="in_invoice_refund_line_action" model="ir.actions.act_window">
<field name="name">Supplier Invoice Lines</field>
<field name="res_model">account.invoice.line</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('invoice_type', 'in', ('in_invoice', 'in_refund'))]</field>
<field name="context">{'show_invoice_fields': True}</field>
</record>
<record id="account_invoice_report_tree" model="ir.ui.view">
<field name="name">usability.account.invoice.report.tree</field>
<field name="model">account.invoice.report</field>
<field name="arch" type="xml">
<tree string="Invoices Analysis">
<field name="date"/>
<field name="commercial_partner_id"/>
<field name="type"/>
<field name="product_id"/>
<field name="product_qty" sum="1"/>
<field name="price_total" sum="1"/>
<field name="state"/>
<field name="currency_id" invisible="1"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<record id="account.action_account_invoice_report_all_supp" model="ir.actions.act_window">
<field name="view_mode">pivot,graph,tree</field>
<field name="context">{'search_default_current':1, 'search_default_supplier':1, 'search_default_year': 1}</field>
</record>
<record id="account.action_account_invoice_report_all" model="ir.actions.act_window">
<field name="view_mode">pivot,graph,tree</field>
<field name="context">{'search_default_current':1, 'search_default_customer':1, 'search_default_year': 1}</field>
</record>
<record id="view_account_invoice_report_pivot" model="ir.ui.view">
<field name="name">usability.account.invoice.report.pivot</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_pivot"/>
<field name="arch" type="xml">
<xpath expr="/pivot" position="attributes">
<attribute name="disable_linking"></attribute>
</xpath>
</field>
</record>
<record id="view_invoice_tax_form" model="ir.ui.view">
<field name="name">usability.account.invoice.tax.form</field>
<field name="model">account.invoice.tax</field>
<field name="inherit_id" ref="account.view_invoice_tax_form"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="tax_id"/>
</field>
</field>
</record>
<record id="view_account_payment_form" model="ir.ui.view">
<field name="name">usability.account.payment.form</field>
<field name="model">account.payment</field>
<field name="inherit_id" ref="account.view_account_payment_form"/>
<field name="arch" type="xml">
<field name="communication" position="after">
<field name="payment_reference"/>
</field>
</field>
</record>
<!-- model account.move.line / Journal Items -->
<record id="account.action_account_moves_all_a" model="ir.actions.act_window">
<field name="limit">200</field>
<!-- Win space, because there are already many columns -->
<field name="context">{'journal_show_code_only': True}</field>
</record>
<!-- replace group_account_manager on Journal Items-->
<record id="account.menu_action_account_moves_all" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('account.group_account_user')])]"/>
</record>
<!-- model account.move / Journal Entries -->
<record id="account.action_move_journal_line" model="ir.actions.act_window">
<field name="limit">200</field>
<field name="context">{'view_no_maturity': True}</field> <!-- Don't filter by default on misc journal -->
</record>
<record id="view_move_form" model="ir.ui.view">
<field name="name">account_usability.account_move_form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<field name="journal_id" position="after">
<field name="default_move_line_name"/>
<field name="default_account_id" invisible="1"/>
<field name="default_credit" invisible="1"/>
<field name="default_debit" invisible="1"/>
</field>
<xpath expr="//field[@name='line_ids']" position="attributes">
<attribute name="context" operation="python_dict" key="default_name">default_move_line_name</attribute>
<attribute name="context" operation="python_dict" key="default_account_id">default_account_id</attribute>
<attribute name="context" operation="python_dict" key="default_credit">default_credit</attribute>
<attribute name="context" operation="python_dict" key="default_debit">default_debit</attribute>
</xpath>
<xpath expr="//field[@name='line_ids']/tree/field[@name='credit']" position="after">
<field name="reconcile_string"/>
</xpath>
</field>
</record>
<record id="view_account_move_line_filter" model="ir.ui.view">
<field name="name">account_usability.account_move_line_search</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_account_move_line_filter"/>
<field name="arch" type="xml">
<field name="partner_id" position="after">
<field name="reconcile_string" />
<field name="debit" filter_domain="['|', ('debit', '=', self), ('credit', '=', self)]" string="Debit or Credit"/>
</field>
<filter name="unreconciled" position="before">
<filter name="reconciled" string="Fully Reconciled" domain="[('full_reconcile_id', '!=', False)]"/>
<!-- <filter name="partial_reconciled" string="Partially Reconciled" domain="[('reconcile_partial_id', '!=', False)]"/> -->
</filter>
<filter name="unreconciled" position="attributes">
<attribute name="string">Unreconciled or Partially Reconciled</attribute>
</filter>
<field name="name" position="attributes">
<attribute name="string">Name or Reference</attribute>
</field>
<field name="partner_id" position="attributes">
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
</field>
</field>
</record>
<record id="view_move_line_form" model="ir.ui.view">
<field name="name">account_usability.account_move_line_form</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_form"/>
<field name="arch" type="xml">
<field name="quantity" position="after">
<field name="product_id" />
</field>
<field name="move_id" position="after">
<field name="invoice_id"/>
<field name="account_reconcile" invisible="1"/>
</field>
<xpath expr="//field[@name='full_reconcile_id']/.." position="replace">
<field name="full_reconcile_id" nolabel="1"/> <!-- label is already in view -->
<field name="matched_debit_ids" readonly="1" widget="many2many_tags" attrs="{'invisible': ['|', ('full_reconcile_id', '!=', False), ('matched_debit_ids', '=', [])]}"/>
<field name="matched_credit_ids" readonly="1" widget="many2many_tags" attrs="{'invisible': ['|', ('full_reconcile_id', '!=', False), ('matched_credit_ids', '=', [])]}"/>
<field name="reconciled" invisible="1"/>
<button name="open_reconcile_view" class="oe_link" type="object"
string="-> View partially reconciled entries" colspan="2"
attrs="{'invisible': ['|', ('full_reconcile_id', '!=', False), '&amp;', ('matched_debit_ids', '=', []), ('matched_credit_ids', '=', [])]}"/>
<span colspan="2" attrs="{'invisible': ['|', '|', ('full_reconcile_id', '!=', False), ('matched_debit_ids', '!=', []), ('matched_credit_ids', '!=', [])]}" class="o_form_field">No Partial Reconcile</span>
</xpath>
<xpath expr="//label[@for='full_reconcile_id']/.." position="attributes">
<attribute name="attrs">{'invisible': [('account_reconcile', '=', False)]}</attribute>
</xpath>
</field>
</record>
<record id="view_move_line_tree" model="ir.ui.view">
<field name="name">account_usability.account_move_line_tree</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_tree"/>
<field name="arch" type="xml">
<field name="full_reconcile_id" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="credit" position="after">
<field name="balance" sum="Total Balance"/>
<field name="reconcile_string"/>
</field>
<field name="date_maturity" position="after">
<button name="show_account_move_form" type="object" icon="fa-arrows-h" string="Show Journal Entry"/>
</field>
</field>
</record>
<record id="view_account_move_filter" model="ir.ui.view">
<field name="name">account_usability.account_move_search</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_account_move_filter"/>
<field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
</field>
</field>
</record>
<record id="view_account_search" model="ir.ui.view">
<field name="name">account.account.search</field>
<field name="model">account.account</field>
<field name="inherit_id" ref="account.view_account_search"/>
<field name="arch" type="xml">
<!-- The native "name" filter uses a domain ['|', ('name','ilike',self), ('code','=like',str(self)+'%')]
This is good because it uses '=like' on 'code', but sometimes there are digits in account names,
so you get additionnal unexpected accounts in the result of the search -->
<field name="name" position="after">
<field name="code" filter_domain="[('code', '=like', str(self)+'%')]" string="Code"/>
</field>
</field>
</record>
<record id="view_account_type_tree" model="ir.ui.view">
<field name="name">account_usability.account_type_tree</field>
<field name="model">account.account.type</field>
<field name="inherit_id" ref="account.view_account_type_tree" />
<field name="arch" type="xml">
<field name="type" position="after">
<field name="include_initial_balance" />
</field>
</field>
</record>
<record id="view_account_journal_tree" model="ir.ui.view">
<field name="name">usability.account.journal.tree</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_tree"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="code"/>
</field>
</field>
</record>
<record id="view_account_journal_search" model="ir.ui.view">
<field name="name">usability.account.journal.search</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_search"/>
<field name="arch" type="xml">
<filter name="dashboard" position="after">
<group name="groupby" string="Group By">
<filter name="type_groupby" string="Type" context="{'group_by': 'type'}"/>
</group>
</filter>
</field>
</record>
<record id="view_bank_statement_form" model="ir.ui.view">
<field name="name">usability.account.bank.statement.form</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='line_ids']/tree/field[@name='bank_account_id']" position="after">
<!-- The cancel button is provided by the account_cancel module, but we don't want to depend on it -->
<button name="show_account_move" type="object"
string="View Account Move" icon="fa-arrow-right"
attrs="{'invisible': [('journal_entry_ids', '=', [])]}"/>
</xpath>
<field name="date" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record id="view_bank_statement_tree" model="ir.ui.view">
<field name="name">usability.account.bank.statement.tree</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_tree"/>
<field name="arch" type="xml">
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="journal_id" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
</field>
</record>
<record id="view_bank_statement_search" model="ir.ui.view">
<field name="name">usability.account.bank.statement.search</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_search"/>
<field name="arch" type="xml">
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="date" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
<filter name="date" position="attributes">
<attribute name="invisible">1</attribute>
</filter>
<filter name="date" position="after">
<filter name="start_date_groupby" string="Start Date"
context="{'group_by': 'start_date'}"/>
<filter name="end_date_groupby" string="End Date"
context="{'group_by': 'end_date'}"/>
</filter>
</field>
</record>
<!-- ACCOUNT TAX -->
<record id="view_tax_tree" model="ir.ui.view">
<field name="model">account.tax</field>
<field name="inherit_id" ref="account.view_tax_tree"/>
<field name="arch" type="xml">
<field name="company_id" position="before">
<field name="price_include" string="Include"/>
</field>
</field>
</record>
<!-- ACCOUNT TAX GROUP -->
<!-- in the account module, there is nothing for account.tax.group : no form/tree view, no menu... -->
<record id="account_tax_group_form" model="ir.ui.view">
<field name="name">usability.account.tax.group.form</field>
<field name="model">account.tax.group</field>
<field name="arch" type="xml">
<form string="Tax Group">
<group name="main">
<field name="name"/>
<field name="sequence" invisible="1"/>
</group>
</form>
</field>
</record>
<record id="account_tax_group_tree" model="ir.ui.view">
<field name="name">usability.account.tax.group.tree</field>
<field name="model">account.tax.group</field>
<field name="arch" type="xml">
<tree string="Tax Groups">
<field name="sequence" widget="handle"/>
<field name="name"/>
</tree>
</field>
</record>
<record id="account_tax_group_action" model="ir.actions.act_window">
<field name="name">Tax Groups</field>
<field name="res_model">account.tax.group</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="account_tax_group_menu" action="account_tax_group_action" parent="account.account_account_menu" sequence="2"/>
<!-- Account config page -->
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">account_usability account config page</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='account_bank_reconciliation_start']/../.." position="after">
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<label for="transfer_account_id"/>
<div class="text-muted">
Transit account when you transfer money from a bank account of your company to another bank account of your company.
</div>
<field name="transfer_account_id"/>
</div>
</div>
</xpath>
</field>
</record>
<!-- Remove menu entry "Accounting > Configuration > Accounting > Bank Accounts"
(account.journal filtered on type = 'bank' with special tree and form view)
because it is useless and confusing -->
<record id="account.menu_action_account_bank_journal_form" model="ir.ui.menu">
<field name="groups_id" eval="[(6, 0, [ref('base_usability.group_nobody')])]"/>
</record>
<!-- Duplicate the menu "Sales > Configuration > Contacts > Bank Accounts"
under "Accounting > Configuration", because most users will try to find it there -->
<menuitem id="bank_account_account_config_menu" name="Bank Accounts" parent="account.menu_finance_configuration" sequence="9"/>
<menuitem id="res_bank_account_config_menu" action="base.action_res_bank_form" parent="bank_account_account_config_menu" sequence="10"/>
<menuitem id="res_partner_bank_account_config_menu" action="base.action_res_partner_bank_account_form" parent="bank_account_account_config_menu" sequence="20"/>
</odoo>

View File

@@ -1,32 +0,0 @@
diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py
index 49e166e5823..5e352c03d7a 100644
--- a/addons/account/models/account_journal_dashboard.py
+++ b/addons/account/models/account_journal_dashboard.py
@@ -309,6 +309,7 @@ class account_journal(models.Model):
'has_at_least_one_statement': has_at_least_one_statement,
'nb_lines_bank_account_balance': nb_lines_bank_account_balance,
'outstanding_pay_account_balance': formatLang(self.env, currency.round(outstanding_pay_account_balance), currency_obj=currency),
+ 'account_balance_plus_outstanding': formatLang(self.env, currency.round(bank_account_balance + outstanding_pay_account_balance), currency_obj=currency),
'nb_lines_outstanding_pay_account_balance': nb_lines_outstanding_pay_account_balance,
'last_balance': formatLang(self.env, currency.round(last_balance) + 0.0, currency_obj=currency),
'number_draft': number_draft,
diff --git a/addons/account/views/account_journal_dashboard_view.xml b/addons/account/views/account_journal_dashboard_view.xml
index 347a36c265e..fd7fb7b67ca 100644
--- a/addons/account/views/account_journal_dashboard_view.xml
+++ b/addons/account/views/account_journal_dashboard_view.xml
@@ -278,6 +278,15 @@
<span><t t-esc="dashboard.outstanding_pay_account_balance"/></span>
</div>
</div>
+ <div class="row" t-if="dashboard.nb_lines_outstanding_pay_account_balance > 0">
+ <div id="dashboard_account_balance_plus_outstanding" class="col overflow-hidden text-left">
+ <span title="Balance + Outstanding">Balance + Outstanding</span>
+ </div>
+ <div class="col-auto text-right">
+ <span><t t-esc="dashboard.account_balance_plus_outstanding"/></span>
+ </div>
+ </div>
+
<t t-if="dashboard.has_at_least_one_statement and dashboard.account_balance != dashboard.last_balance">
<div class="row" name="latest_statement">
<div class="col overflow-hidden text-left">

View File

@@ -1,696 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_usability
#
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_usability
#: code:addons/account_usability/wizard/account_group_generate.py:0
#, python-format
msgid ""
"%d account groups already exists in company '%s'. This wizard is designed to"
" generate account groups from scratch."
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_account
msgid "Account"
msgstr ""
#. module: account_usability
#: code:addons/account_usability/wizard/account_group_generate.py:0
#, python-format
msgid "Account Groups"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_move_reversal
msgid "Account Move Reversal"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_reconciliation_widget
msgid "Account Reconciliation widget"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_journal__account_type_current_assets_id
msgid "Account Type Current Assets"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_journal__account_type_current_liabilities_id
msgid "Account Type Current Liabilities"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__account_reconcile
msgid "Allow Reconciliation"
msgstr ""
#. module: account_usability
#: model:ir.model.constraint,message:account_usability.constraint_account_analytic_account_code_company_unique
msgid ""
"An analytic account with the same code already exists in the same company!"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_analytic_account
msgid "Analytic Account"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_form
msgid "Are you sure to unreconcile all the entrie of the bank statement?"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_bank_statement_line__partner_bank_id
#: model:ir.model.fields,help:account_usability.field_account_move__partner_bank_id
msgid ""
"Bank Account Number to which the invoice will be paid. A Company bank "
"account if this is a Customer Invoice or Vendor Credit Note, otherwise a "
"Partner bank account number."
msgstr ""
#. module: account_usability
#: model:ir.ui.menu,name:account_usability.res_partner_bank_account_config_menu
msgid "Bank Accounts"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_bank_statement
msgid "Bank Statement"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_bank_statement_line
msgid "Bank Statement Line"
msgstr ""
#. module: account_usability
#: model:ir.ui.menu,name:account_usability.res_bank_account_config_menu
msgid "Banks"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_group_generate_form
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_mark_sent_form
msgid "Cancel"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__account_reconcile
msgid ""
"Check this box if this account allows invoices & payments matching of "
"journal items."
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_search
msgid "Code"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_res_company
msgid "Companies"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_res_config_settings
msgid "Config Settings"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_res_partner
msgid "Contact"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__create_uid
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__create_uid
msgid "Created by"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__create_date
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__create_date
msgid "Created on"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__matched_credit_ids
msgid "Credit journal items that are matched with this journal item."
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Current Year"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__date
#: model:ir.model.fields,field_description:account_usability.field_account_move__date
#: model:ir.model.fields,field_description:account_usability.field_account_payment__date
msgid "Date"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__matched_debit_ids
msgid "Debit journal items that are matched with this journal item."
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Debit or Credit"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_account__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_analytic_account__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_incoterms__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_report__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_journal__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_move__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_move_reversal__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_partial_reconcile__display_name
#: model:ir.model.fields,field_description:account_usability.field_product_supplierinfo__display_name
#: model:ir.model.fields,field_description:account_usability.field_product_template__display_name
#: model:ir.model.fields,field_description:account_usability.field_res_company__display_name
#: model:ir.model.fields,field_description:account_usability.field_res_config_settings__display_name
#: model:ir.model.fields,field_description:account_usability.field_res_partner__display_name
msgid "Display Name"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__invoice_date_due
#: model:ir.model.fields,field_description:account_usability.field_account_move__invoice_date_due
#: model:ir.model.fields,field_description:account_usability.field_account_payment__invoice_date_due
msgid "Due Date"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__end_date
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_search
msgid "End Date"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_fiscal_position
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__fiscal_position_id
#: model:ir.model.fields,field_description:account_usability.field_account_move__fiscal_position_id
#: model:ir.model.fields,field_description:account_usability.field_account_payment__fiscal_position_id
#: model:ir.model.fields,field_description:account_usability.field_res_partner__property_account_position_id
#: model:ir.model.fields,field_description:account_usability.field_res_users__property_account_position_id
msgid "Fiscal Position"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_fiscalyear
msgid "Fiscal Year"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_bank_statement_line__fiscal_position_id
#: model:ir.model.fields,help:account_usability.field_account_move__fiscal_position_id
#: model:ir.model.fields,help:account_usability.field_account_payment__fiscal_position_id
msgid ""
"Fiscal positions are used to adapt taxes and accounts for particular "
"customers or sales orders/invoices. The default value comes from the "
"customer."
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__full_reconcile_id
msgid "Full Reconcile"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Fully Reconciled"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_group_generate_form
msgid "Generate"
msgstr ""
#. module: account_usability
#: model:ir.actions.act_window,name:account_usability.account_group_generate_action
#: model:ir.model,name:account_usability.model_account_group_generate
#: model:ir.ui.menu,name:account_usability.account_group_generate_menu
msgid "Generate Account Groups"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_group_generate_form
msgid "Generate account groups"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_analytic_account_search
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_search
msgid "Group"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_journal_search
msgid "Group By"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__has_attachment
#: model:ir.model.fields,field_description:account_usability.field_account_move__has_attachment
#: model:ir.model.fields,field_description:account_usability.field_account_payment__has_attachment
msgid "Has Attachment"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__has_discount
#: model:ir.model.fields,field_description:account_usability.field_account_move__has_discount
#: model:ir.model.fields,field_description:account_usability.field_account_payment__has_discount
msgid "Has Discount"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__hide_bank_statement_balance
#: model:ir.model.fields,field_description:account_usability.field_account_journal__hide_bank_statement_balance
msgid "Hide Bank Statement Balance"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_account__id
#: model:ir.model.fields,field_description:account_usability.field_account_analytic_account__id
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__id
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__id
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__id
#: model:ir.model.fields,field_description:account_usability.field_account_incoterms__id
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__id
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_report__id
#: model:ir.model.fields,field_description:account_usability.field_account_journal__id
#: model:ir.model.fields,field_description:account_usability.field_account_move__id
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__id
#: model:ir.model.fields,field_description:account_usability.field_account_move_reversal__id
#: model:ir.model.fields,field_description:account_usability.field_account_partial_reconcile__id
#: model:ir.model.fields,field_description:account_usability.field_product_supplierinfo__id
#: model:ir.model.fields,field_description:account_usability.field_product_template__id
#: model:ir.model.fields,field_description:account_usability.field_res_company__id
#: model:ir.model.fields,field_description:account_usability.field_res_config_settings__id
#: model:ir.model.fields,field_description:account_usability.field_res_partner__id
msgid "ID"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_incoterms
msgid "Incoterms"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_res_config_settings__transfer_account_id
msgid "Inter-Banks Transfer Account"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_res_config_settings__transfer_account_id
msgid ""
"Intermediary account used when moving money from a liquidity account to "
"another"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__product_barcode
msgid "International Article Number used for product identification."
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_invoice
#: model:ir.model.fields,field_description:account_usability.field_res_partner__invoice_warn
#: model:ir.model.fields,field_description:account_usability.field_res_users__invoice_warn
msgid "Invoice"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_company_form
msgid "Invoice Legal Terms"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_invoice_line
msgid "Invoice Line"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_report_tree
msgid "Invoices Analysis"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_invoice_report
msgid "Invoices Statistics"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_journal
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__journal_id
#: model:ir.model.fields,field_description:account_usability.field_account_move__journal_id
#: model:ir.model.fields,field_description:account_usability.field_account_payment__journal_id
msgid "Journal"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_move
msgid "Journal Entry"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_move_line
msgid "Journal Item"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_account____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_analytic_account____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_incoterms____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_report____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_journal____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_move____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_move_line____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_move_reversal____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_partial_reconcile____last_update
#: model:ir.model.fields,field_description:account_usability.field_product_supplierinfo____last_update
#: model:ir.model.fields,field_description:account_usability.field_product_template____last_update
#: model:ir.model.fields,field_description:account_usability.field_res_company____last_update
#: model:ir.model.fields,field_description:account_usability.field_res_config_settings____last_update
#: model:ir.model.fields,field_description:account_usability.field_res_partner____last_update
msgid "Last Modified on"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__write_uid
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__write_uid
msgid "Last Updated by"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__write_date
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__write_date
msgid "Last Updated on"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_company_form
msgid "Legal Terms"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_res_company__static_invoice_terms
msgid "Legal Terms on Invoice"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__level
msgid "Level"
msgstr ""
#. module: account_usability
#: model:ir.actions.act_window,name:account_usability.account_invoice_mark_sent_action
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_mark_sent_form
msgid "Mark as Sent"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_invoice_mark_sent
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_mark_sent_form
msgid "Mark invoices as sent"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_invoice_filter
msgid "Missing Attachment"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_partial_reconcile
msgid "Partial Reconcile"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__matched_credit_ids
msgid "Partial Reconcile Credit"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__matched_debit_ids
msgid "Partial Reconcile Debit"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_report__industry_id
msgid "Partner Industry"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__invoice_payment_term_id
#: model:ir.model.fields,field_description:account_usability.field_account_move__invoice_payment_term_id
#: model:ir.model.fields,field_description:account_usability.field_account_payment__invoice_payment_term_id
msgid "Payment Terms"
msgstr ""
#. module: account_usability
#: code:addons/account_usability/models/account_move.py:0
#, python-format
msgid "Please post the following entries before reconciliation :"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__name_prefix
msgid "Prefix"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_reconcile_model
msgid ""
"Preset to create journal entries during a invoices and payments matching"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Previous Year"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_move_form
msgid "Print"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__product_barcode
msgid "Product Barcode"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_product_template
msgid "Product Template"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_product_product__purchase_price_type
#: model:ir.model.fields,field_description:account_usability.field_product_supplierinfo__purchase_price_type
#: model:ir.model.fields,field_description:account_usability.field_product_template__purchase_price_type
msgid "Purchase Price Type"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__partner_bank_id
#: model:ir.model.fields,field_description:account_usability.field_account_move__partner_bank_id
msgid "Recipient Bank"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__reconcile_string
msgid "Reconcile"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__ref
#: model:ir.model.fields,field_description:account_usability.field_account_move__ref
#: model:ir.model.fields,field_description:account_usability.field_account_payment__ref
msgid "Reference"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_reversal__date
msgid "Reversal date"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__sale_dates
#: model:ir.model.fields,field_description:account_usability.field_account_move__sale_dates
#: model:ir.model.fields,field_description:account_usability.field_account_payment__sale_dates
msgid "Sale Dates"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_product_product__sale_price_type
#: model:ir.model.fields,field_description:account_usability.field_product_template__sale_price_type
msgid "Sale Price Type"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_res_partner__invoice_warn
#: model:ir.model.fields,help:account_usability.field_res_users__invoice_warn
msgid ""
"Selecting the \"Warning\" option will notify user with the message, "
"Selecting \"Blocking Message\" will throw an exception with the message and "
"block the flow. The Message has to be written in the next field."
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_invoice_filter
msgid "Sent"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__start_date
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_search
msgid "Start Date"
msgstr ""
#. module: account_usability
#: model:ir.model,name:account_usability.model_product_supplierinfo
msgid "Supplier Pricelist"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.product_supplierinfo_tree_view
msgid "Tax"
msgstr ""
#. module: account_usability
#: code:addons/account_usability/models/product.py:0
#, python-format
msgid "Tax excl."
msgstr ""
#. module: account_usability
#: code:addons/account_usability/models/product.py:0
#, python-format
msgid "Tax incl."
msgstr ""
#. module: account_usability
#: code:addons/account_usability/wizard/account_group_generate.py:0
#, python-format
msgid ""
"The code of account '%s' is %d caracters. It cannot be inferior to level "
"(%d)."
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_res_partner__property_account_position_id
#: model:ir.model.fields,help:account_usability.field_res_users__property_account_position_id
msgid ""
"The fiscal position determines the taxes/accounts used for this contact."
msgstr ""
#. module: account_usability
#: code:addons/account_usability/wizard/account_group_generate.py:0
#, python-format
msgid "The level must be >= 1."
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_bank_statement_line__sale_dates
#: model:ir.model.fields,help:account_usability.field_account_move__sale_dates
#: model:ir.model.fields,help:account_usability.field_account_payment__sale_dates
msgid ""
"This information appears on invoice qweb report (you may use it for your own"
" report)"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_group_generate_form
msgid ""
"This wizard is designed to auto-generate account groups from the chart of "
"account."
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_mark_sent_form
msgid ""
"This wizard will mark as <i>sent</i> all the selected invoices in open or "
"paid state."
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_invoice_filter
msgid "To Send"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__amount_total
#: model:ir.model.fields,field_description:account_usability.field_account_move__amount_total
#: model:ir.model.fields,field_description:account_usability.field_account_payment__amount_total
msgid "Total"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.res_config_settings_view_form
msgid ""
"Transit account when you transfer money from a bank account of your company "
"to another bank account of your company."
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_journal_search
msgid "Type"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_form
msgid "Unreconcile All"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Unreconciled or Partially Reconciled"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_form
msgid "View Journal Entry"
msgstr ""
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_move_line_tree
msgid "View Journal Entry Form"
msgstr ""
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_bank_statement__hide_bank_statement_balance
#: model:ir.model.fields,help:account_usability.field_account_journal__hide_bank_statement_balance
msgid ""
"You may want to enable this option when your bank journal is generated from "
"a bank statement file that doesn't handle start/end balance (QIF for "
"instance) and you don't want to enter the start/end balance manually: it "
"will prevent the display of wrong information in the accounting dashboard "
"and on bank statements."
msgstr ""

View File

@@ -1,744 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_usability
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-06-01 14:17+0000\n"
"PO-Revision-Date: 2022-09-18 18:55+0200\n"
"Last-Translator: \n"
"Language-Team: Alpis Traduction et Interprétation <info@alpis.fr>\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.0.4\n"
#. module: account_usability
#: code:addons/account_usability/wizard/account_group_generate.py:0
#, python-format
msgid ""
"%d account groups already exists in company '%s'. This wizard is designed "
"to generate account groups from scratch."
msgstr ""
"%d des groupes de comptes existent déjà dans la société '%s'. Cet "
"assistant est conçu pour créer des groupes de comptes à partir de zéro."
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_account
msgid "Account"
msgstr "Compte"
#. module: account_usability
#: code:addons/account_usability/wizard/account_group_generate.py:0
#, python-format
msgid "Account Groups"
msgstr "Groupes de comptes"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_move_reversal
msgid "Account Move Reversal"
msgstr "Extourne d'écritures"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_reconciliation_widget
msgid "Account Reconciliation widget"
msgstr "Outils de lettrage de compte"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_journal__account_type_current_assets_id
msgid "Account Type Current Assets"
msgstr "Type de compte actif circulant"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_journal__account_type_current_liabilities_id
msgid "Account Type Current Liabilities"
msgstr "Type de compte Dettes à court terme"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__account_reconcile
msgid "Allow Reconciliation"
msgstr "Autoriser le lettrage"
#. module: account_usability
#: model:ir.model.constraint,message:account_usability.constraint_account_analytic_account_code_company_unique
msgid ""
"An analytic account with the same code already exists in the same company!"
msgstr ""
"Un compte analytique avec le même code existe déjà dans la même société !"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_analytic_account
msgid "Analytic Account"
msgstr "Compte analytique"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_form
msgid "Are you sure to unreconcile all the entries of the bank statement?"
msgstr "Êtes-vous sûr de vouloir délettrer toutes les écritures du relevé ?"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__balance
#: model_terms:ir.ui.view,arch_db:account_usability.view_move_line_tree
msgid "Balance"
msgstr "Solde"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_bank_statement_line__partner_bank_id
#: model:ir.model.fields,help:account_usability.field_account_move__partner_bank_id
msgid ""
"Bank Account Number to which the invoice will be paid. A Company bank "
"account if this is a Customer Invoice or Vendor Credit Note, otherwise a "
"Partner bank account number."
msgstr ""
"Numéro du compte bancaire sur lequel la facture sera payée. Un compte "
"bancaire de la société s'il s'agit d'une facture client ou d'un avoir du "
"fournisseur, sinon un numéro de compte bancaire du tiers."
#. module: account_usability
#: model:ir.ui.menu,name:account_usability.res_partner_bank_account_config_menu
msgid "Bank Accounts"
msgstr "Comptes bancaires"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_bank_statement
msgid "Bank Statement"
msgstr "Relevé de compte"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_bank_statement_line
msgid "Bank Statement Line"
msgstr "Ligne de relevé de compte"
#. module: account_usability
#: model:ir.ui.menu,name:account_usability.res_bank_account_config_menu
msgid "Banks"
msgstr "Banques"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_group_generate_form
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_mark_sent_form
msgid "Cancel"
msgstr "Annuler"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__account_reconcile
msgid ""
"Check this box if this account allows invoices & payments matching of "
"journal items."
msgstr ""
"Cochez cette case si ce compte permet de faire du rapprochement entre "
"factures et paiements."
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_search
msgid "Code"
msgstr "Code"
#. module: account_usability
#: model:ir.model,name:account_usability.model_res_company
msgid "Companies"
msgstr "Sociétés"
#. module: account_usability
#: model:ir.model,name:account_usability.model_res_config_settings
msgid "Config Settings"
msgstr "Paramètres de configuration"
#. module: account_usability
#: model:ir.model,name:account_usability.model_res_partner
msgid "Contact"
msgstr "Contact"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__create_uid
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__create_uid
msgid "Created by"
msgstr "Créé par"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__create_date
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__create_date
msgid "Created on"
msgstr "Créé le"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__matched_credit_ids
msgid "Credit journal items that are matched with this journal item."
msgstr "Écritures comptables au crédit qui correspondent à cette écriture comptable."
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Current Year"
msgstr "Année en cours"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__date
#: model:ir.model.fields,field_description:account_usability.field_account_move__date
#: model:ir.model.fields,field_description:account_usability.field_account_payment__date
msgid "Date"
msgstr "Date"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__matched_debit_ids
msgid "Debit journal items that are matched with this journal item."
msgstr "Écritures comptables au débit qui correspondent avec cette écriture comptable."
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Debit or Credit"
msgstr "Débit ou crédit"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_account__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_analytic_account__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_incoterms__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_report__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_journal__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_move__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_move_reversal__display_name
#: model:ir.model.fields,field_description:account_usability.field_account_partial_reconcile__display_name
#: model:ir.model.fields,field_description:account_usability.field_product_supplierinfo__display_name
#: model:ir.model.fields,field_description:account_usability.field_product_template__display_name
#: model:ir.model.fields,field_description:account_usability.field_res_company__display_name
#: model:ir.model.fields,field_description:account_usability.field_res_config_settings__display_name
#: model:ir.model.fields,field_description:account_usability.field_res_partner__display_name
msgid "Display Name"
msgstr "Nom affiché"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__invoice_date_due
#: model:ir.model.fields,field_description:account_usability.field_account_move__invoice_date_due
#: model:ir.model.fields,field_description:account_usability.field_account_payment__invoice_date_due
msgid "Due Date"
msgstr "Date d'échéance"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__end_date
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_search
msgid "End Date"
msgstr "Date de Fin"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_fiscal_position
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__fiscal_position_id
#: model:ir.model.fields,field_description:account_usability.field_account_move__fiscal_position_id
#: model:ir.model.fields,field_description:account_usability.field_account_payment__fiscal_position_id
#: model:ir.model.fields,field_description:account_usability.field_res_partner__property_account_position_id
#: model:ir.model.fields,field_description:account_usability.field_res_users__property_account_position_id
msgid "Fiscal Position"
msgstr "Position fiscale"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_fiscalyear
msgid "Fiscal Year"
msgstr "Exercice"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_bank_statement_line__fiscal_position_id
#: model:ir.model.fields,help:account_usability.field_account_move__fiscal_position_id
#: model:ir.model.fields,help:account_usability.field_account_payment__fiscal_position_id
msgid ""
"Fiscal positions are used to adapt taxes and accounts for particular "
"customers or sales orders/invoices. The default value comes from the "
"customer."
msgstr ""
"Les positions fiscales sont utilisées pour adapter les taxes et les comptes "
"à des clients particuliers ou à des bons de commande/factures. La valeur "
"par défaut provient du client."
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__full_reconcile_id
msgid "Full Reconcile"
msgstr "Marque de lettrage"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Fully Reconciled"
msgstr "Lettré totalement"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_group_generate_form
msgid "Generate"
msgstr "Générer"
#. module: account_usability
#: model:ir.actions.act_window,name:account_usability.account_group_generate_action
#: model:ir.model,name:account_usability.model_account_group_generate
#: model:ir.ui.menu,name:account_usability.account_group_generate_menu
msgid "Generate Account Groups"
msgstr "Générer les groupes de comptes"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_analytic_account_search
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_search
msgid "Group"
msgstr "Groupe"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_journal_search
msgid "Group By"
msgstr "Regrouper par"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__has_attachment
#: model:ir.model.fields,field_description:account_usability.field_account_move__has_attachment
#: model:ir.model.fields,field_description:account_usability.field_account_payment__has_attachment
msgid "Has Attachment"
msgstr "Possède une pièce jointe"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__has_discount
#: model:ir.model.fields,field_description:account_usability.field_account_move__has_discount
#: model:ir.model.fields,field_description:account_usability.field_account_payment__has_discount
msgid "Has Discount"
msgstr "A une réduction"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__hide_bank_statement_balance
#: model:ir.model.fields,field_description:account_usability.field_account_journal__hide_bank_statement_balance
msgid "Hide Bank Statement Balance"
msgstr "Masquer le solde du relevé bancaire"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_account__id
#: model:ir.model.fields,field_description:account_usability.field_account_analytic_account__id
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__id
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__id
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__id
#: model:ir.model.fields,field_description:account_usability.field_account_incoterms__id
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__id
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_report__id
#: model:ir.model.fields,field_description:account_usability.field_account_journal__id
#: model:ir.model.fields,field_description:account_usability.field_account_move__id
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__id
#: model:ir.model.fields,field_description:account_usability.field_account_move_reversal__id
#: model:ir.model.fields,field_description:account_usability.field_account_partial_reconcile__id
#: model:ir.model.fields,field_description:account_usability.field_product_supplierinfo__id
#: model:ir.model.fields,field_description:account_usability.field_product_template__id
#: model:ir.model.fields,field_description:account_usability.field_res_company__id
#: model:ir.model.fields,field_description:account_usability.field_res_config_settings__id
#: model:ir.model.fields,field_description:account_usability.field_res_partner__id
msgid "ID"
msgstr "ID"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_incoterms
msgid "Incoterms"
msgstr "Incoterms"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_res_config_settings__transfer_account_id
msgid "Inter-Banks Transfer Account"
msgstr "Compte de transfert inter-bancaire"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_res_config_settings__transfer_account_id
msgid ""
"Intermediary account used when moving money from a liquidity account to "
"another"
msgstr ""
"Compte intermédiaire utilisé pour déplacer de l'argent d'un compte de "
"trésorerie vers un autre"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__product_barcode
msgid "International Article Number used for product identification."
msgstr ""
"Numéro d'article international (IAN) utilisé pour identifier cet article."
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_invoice
#: model:ir.model.fields,field_description:account_usability.field_res_partner__invoice_warn
#: model:ir.model.fields,field_description:account_usability.field_res_users__invoice_warn
msgid "Invoice"
msgstr "Facture"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_company_form
msgid "Invoice Legal Terms"
msgstr "Mentions légales sur les factures"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_invoice_line
msgid "Invoice Line"
msgstr "Lignes de facture"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_report_tree
msgid "Invoices Analysis"
msgstr "Analyse des factures"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_invoice_report
msgid "Invoices Statistics"
msgstr "Statistiques des factures"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_journal
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__journal_id
#: model:ir.model.fields,field_description:account_usability.field_account_move__journal_id
#: model:ir.model.fields,field_description:account_usability.field_account_payment__journal_id
msgid "Journal"
msgstr "Journal"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_move
msgid "Journal Entry"
msgstr "Pièce comptable"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_move_line
msgid "Journal Item"
msgstr "Écriture comptable"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_account____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_analytic_account____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_incoterms____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_report____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_journal____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_move____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_move_line____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_move_reversal____last_update
#: model:ir.model.fields,field_description:account_usability.field_account_partial_reconcile____last_update
#: model:ir.model.fields,field_description:account_usability.field_product_supplierinfo____last_update
#: model:ir.model.fields,field_description:account_usability.field_product_template____last_update
#: model:ir.model.fields,field_description:account_usability.field_res_company____last_update
#: model:ir.model.fields,field_description:account_usability.field_res_config_settings____last_update
#: model:ir.model.fields,field_description:account_usability.field_res_partner____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__write_uid
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__write_uid
msgid "Last Updated by"
msgstr "Mis à jour par"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__write_date
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_mark_sent__write_date
msgid "Last Updated on"
msgstr "Mis à jour le"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_company_form
msgid "Legal Terms"
msgstr "Mentions légales"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_res_company__static_invoice_terms
msgid "Legal Terms on Invoice"
msgstr "Mentions légales sur les factures"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__level
msgid "Level"
msgstr "Niveau"
#. module: account_usability
#: model:ir.actions.act_window,name:account_usability.account_invoice_mark_sent_action
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_mark_sent_form
msgid "Mark as Sent"
msgstr "Marquer comme envoyé"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_invoice_mark_sent
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_mark_sent_form
msgid "Mark invoices as sent"
msgstr "Marquer les factures comme envoyées"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_invoice_filter
msgid "Missing Attachment"
msgstr "Pièce jointe manquante"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_partial_reconcile
msgid "Partial Reconcile"
msgstr "Lettrage partiel"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__matched_credit_ids
msgid "Partial Reconcile Credit"
msgstr "Crédit de lettrage partiel"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__matched_debit_ids
msgid "Partial Reconcile Debit"
msgstr "Débit de lettrage partiel"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_invoice_report__industry_id
msgid "Partner Industry"
msgstr "Secteur dactivité du partenaire"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__invoice_payment_term_id
#: model:ir.model.fields,field_description:account_usability.field_account_move__invoice_payment_term_id
#: model:ir.model.fields,field_description:account_usability.field_account_payment__invoice_payment_term_id
msgid "Payment Terms"
msgstr "Conditions de paiement"
#. module: account_usability
#: code:addons/account_usability/models/account_move.py:0
#, python-format
msgid "Please post the following entries before reconciliation :"
msgstr "Veuillez comptabiliser les pièces suivantes avant le lettrage :"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_group_generate__name_prefix
msgid "Prefix"
msgstr "Préfixe"
#. module: account_usability
#: model:ir.model,name:account_usability.model_account_reconcile_model
msgid ""
"Preset to create journal entries during a invoices and payments matching"
msgstr ""
"Préconfigurer pour créer une écriture pendant la correspondance entre des "
"factures et des paiements"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Previous Year"
msgstr "Année précédente"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_move_form
msgid "Print"
msgstr "Imprimer"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__product_barcode
msgid "Product Barcode"
msgstr "Code barre du produit"
#. module: account_usability
#: model:ir.model,name:account_usability.model_product_template
msgid "Product Template"
msgstr "Modèle de produit"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_product_product__purchase_price_type
#: model:ir.model.fields,field_description:account_usability.field_product_supplierinfo__purchase_price_type
#: model:ir.model.fields,field_description:account_usability.field_product_template__purchase_price_type
msgid "Purchase Price Type"
msgstr "Type de prix dachat"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__partner_bank_id
#: model:ir.model.fields,field_description:account_usability.field_account_move__partner_bank_id
msgid "Recipient Bank"
msgstr "Compte bancaire destinataire"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_line__reconcile_string
msgid "Reconcile"
msgstr "Lettrer"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__ref
#: model:ir.model.fields,field_description:account_usability.field_account_move__ref
#: model:ir.model.fields,field_description:account_usability.field_account_payment__ref
msgid "Reference"
msgstr "Référence"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_move_reversal__date
msgid "Reversal date"
msgstr "Date d'extourne"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__sale_dates
#: model:ir.model.fields,field_description:account_usability.field_account_move__sale_dates
#: model:ir.model.fields,field_description:account_usability.field_account_payment__sale_dates
msgid "Sale Dates"
msgstr "Dates de vente"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_product_product__sale_price_type
#: model:ir.model.fields,field_description:account_usability.field_product_template__sale_price_type
msgid "Sale Price Type"
msgstr "Type de prix de vente"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_res_partner__invoice_warn
#: model:ir.model.fields,help:account_usability.field_res_users__invoice_warn
msgid ""
"Selecting the \"Warning\" option will notify user with the message, "
"Selecting \"Blocking Message\" will throw an exception with the message and "
"block the flow. The Message has to be written in the next field."
msgstr ""
"Sélectionner l'option 'Avertissement' notifiera l'utilisateur avec le "
"Message. Sélectionner 'Message Bloquant' lancera une exception avec le "
"message et bloquera le flux. Le Message doit être encodé dans le champ "
"suivant."
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_invoice_filter
msgid "Sent"
msgstr "Envoyé"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement__start_date
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_search
msgid "Start Date"
msgstr "Date de Début"
#. module: account_usability
#: model:ir.model,name:account_usability.model_product_supplierinfo
msgid "Supplier Pricelist"
msgstr "Liste prix fournisseur"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.product_supplierinfo_tree_view
msgid "Tax"
msgstr "Taxe"
#. module: account_usability
#: code:addons/account_usability/models/product.py:0
#, python-format
msgid "Tax excl."
msgstr "HT"
#. module: account_usability
#: code:addons/account_usability/models/product.py:0
#, python-format
msgid "Tax incl."
msgstr "TTC"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_move_line__balance
msgid ""
"Technical field holding the debit - credit in order to open meaningful "
"graph views from reports"
msgstr ""
"Champ technique égal à 'débit - crédit', utilisé pour les vues graphes dans "
"les rapports"
#. module: account_usability
#: code:addons/account_usability/wizard/account_group_generate.py:0
#, python-format
msgid ""
"The code of account '%s' is %d caracters. It cannot be inferior to level "
"(%d)."
msgstr ""
"Le code du compte '%s' fait %d caractères. Il ne peut pas être de niveau "
"inférieur à (%d)."
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_res_partner__property_account_position_id
#: model:ir.model.fields,help:account_usability.field_res_users__property_account_position_id
msgid ""
"The fiscal position determines the taxes/accounts used for this contact."
msgstr ""
"La position fiscale détermine les taxes / comptes utilisés pour ce contact."
#. module: account_usability
#: code:addons/account_usability/wizard/account_group_generate.py:0
#, python-format
msgid "The level must be >= 1."
msgstr "Le niveau doit être >= 1."
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_bank_statement_line__sale_dates
#: model:ir.model.fields,help:account_usability.field_account_move__sale_dates
#: model:ir.model.fields,help:account_usability.field_account_payment__sale_dates
msgid ""
"This information appear on invoice qweb report (you may use it for your "
"own report)"
msgstr ""
"Cette information apparait sur le rapport qweb de la facture (vous "
"pouvez les utiliser pour votre propre rapport)"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_group_generate_form
msgid ""
"This wizard is designed to auto-generate account groups from the chart of "
"account."
msgstr ""
"Cet assistant est conçu pour générer automatiquement les groupes de comptes "
"à partir du plan comptable."
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.account_invoice_mark_sent_form
msgid ""
"This wizard will mark as <i>sent</i> all the selected posted invoices."
msgstr ""
"Cet assistant marquera comme <i>envoyées</i> toutes les factures "
"sélectionnées et comptabilisées."
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_invoice_filter
msgid "To Send"
msgstr "À envoyer"
#. module: account_usability
#: model:ir.model.fields,field_description:account_usability.field_account_bank_statement_line__amount_total
#: model:ir.model.fields,field_description:account_usability.field_account_move__amount_total
#: model:ir.model.fields,field_description:account_usability.field_account_payment__amount_total
msgid "Total"
msgstr "Total"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.res_config_settings_view_form
msgid ""
"Transit account when you transfer money from a bank account of your company "
"to another bank account of your company."
msgstr ""
"Compte de transit lorsque vous transférez de l'argent d'un compte bancaire "
"de votre entreprise vers un autre compte bancaire de votre entreprise."
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_journal_search
msgid "Type"
msgstr "Type"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_form
msgid "Unreconcile All"
msgstr "Tout délettrer"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_account_move_line_filter
msgid "Unreconciled or Partially Reconciled"
msgstr "Non lettré ou partiellement lettré"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_bank_statement_form
msgid "View Journal Entry"
msgstr "Voir la pièce comptable"
#. module: account_usability
#: model_terms:ir.ui.view,arch_db:account_usability.view_move_line_tree
msgid "View Journal Entry Form"
msgstr "Voir la pièce comptable en vue formulaire"
#. module: account_usability
#: model:ir.model.fields,help:account_usability.field_account_bank_statement__hide_bank_statement_balance
#: model:ir.model.fields,help:account_usability.field_account_journal__hide_bank_statement_balance
msgid ""
"You may want to enable this option when your bank journal is generated from "
"a bank statement file that doesn't handle start/end balance (QIF for "
"instance) and you don't want to enter the start/end balance manually: it "
"will prevent the display of wrong information in the accounting dashboard "
"and on bank statements."
msgstr ""
"Vous pouvez activer cette option lorsque votre journal bancaire est généré "
"à partir d'un fichier de relevés bancaires qui ne gère pas le solde de "
"début/fin (par exemple QIF) et que vous ne souhaitez pas saisir le solde de "
"début/fin manuellement : cela empêchera l'affichage d'informations erronées "
"dans le tableau de bord comptable et sur les relevés bancaires."

View File

@@ -1,55 +1,33 @@
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py
index 2dd1f9cef83..62275fca65e 100644
index f38f459c533..a475d6a82c7 100644
--- a/addons/account/models/account_payment.py
+++ b/addons/account/models/account_payment.py
@@ -262,6 +262,7 @@ class AccountPayment(models.Model):
'credit': write_off_balance > 0.0 and write_off_balance or 0.0,
'partner_id': self.partner_id.id,
'account_id': write_off_line_vals.get('account_id'),
+ 'analytic_account_id': write_off_line_vals.get('analytic_account_id'),
})
return line_vals_list
@@ -699,6 +700,7 @@ class AccountPayment(models.Model):
'name': writeoff_lines[0].name,
'amount': writeoff_amount * sign,
'account_id': writeoff_lines[0].account_id.id,
+ 'analytic_account_id': writeoff_lines[0].analytic_account_id.id,
}
else:
write_off_line_vals = {}
diff --git a/addons/account/wizard/account_payment_register.py b/addons/account/wizard/account_payment_register.py
index 3fc91f716ad..35636774c7e 100644
--- a/addons/account/wizard/account_payment_register.py
+++ b/addons/account/wizard/account_payment_register.py
@@ -93,6 +93,7 @@ class AccountPaymentRegister(models.TransientModel):
], default='open', string="Payment Difference Handling")
writeoff_account_id = fields.Many2one('account.account', string="Difference Account", copy=False,
domain="[('deprecated', '=', False), ('company_id', '=', company_id)]")
+ writeoff_analytic_account_id = fields.Many2one('account.analytic.account', string="Difference Analytic Account", copy=False, domain="[('company_id', '=', company_id)]")
writeoff_label = fields.Char(string='Journal Item Label', default='Write-Off',
help='Change label of the counterpart that will hold the payment difference')
@@ -422,6 +423,7 @@ class AccountPaymentRegister(models.TransientModel):
'name': self.writeoff_label,
'amount': self.payment_difference,
'account_id': self.writeoff_account_id.id,
+ 'analytic_account_id': self.writeoff_analytic_account_id.id or False,
}
return payment_vals
diff --git a/addons/account/wizard/account_payment_register_views.xml b/addons/account/wizard/account_payment_register_views.xml
index 16eec30e265..b9386567baa 100644
--- a/addons/account/wizard/account_payment_register_views.xml
+++ b/addons/account/wizard/account_payment_register_views.xml
@@ -65,6 +65,10 @@
string="Post Difference In"
options="{'no_create': True}"
attrs="{'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
+ <label for="writeoff_analytic_account_id" class="oe_edit_only" string="Analytic Account" groups="analytic.group_analytic_accounting"/>
+ <field name="writeoff_analytic_account_id"
+ groups="analytic.group_analytic_accounting"
+ options="{'no_create': True}" />
<label for="writeoff_label" class="oe_edit_only" string="Label"/>
<field name="writeoff_label" attrs="{'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
</div>
@@ -62,6 +62,7 @@ class account_abstract_payment(models.AbstractModel):
payment_difference = fields.Monetary(compute='_compute_payment_difference', readonly=True)
payment_difference_handling = fields.Selection([('open', 'Keep open'), ('reconcile', 'Mark invoice as fully paid')], default='open', string="Payment Difference Handling", copy=False)
writeoff_account_id = fields.Many2one('account.account', string="Difference Account", domain=[('deprecated', '=', False)], copy=False)
+ writeoff_analytic_account_id = fields.Many2one('account.analytic.account', string="Difference Analytic Account", copy=False)
writeoff_label = fields.Char(
string='Journal Item Label',
help='Change label of the counterpart that will hold the payment difference',
@@ -717,6 +718,7 @@ class account_payment(models.Model):
debit_wo, credit_wo, amount_currency_wo, currency_id = aml_obj.with_context(date=self.payment_date)._compute_amount_fields(self.payment_difference, self.currency_id, self.company_id.currency_id)
writeoff_line['name'] = self.writeoff_label
writeoff_line['account_id'] = self.writeoff_account_id.id
+ writeoff_line['analytic_account_id'] = self.writeoff_analytic_account_id.id or False
writeoff_line['debit'] = debit_wo
writeoff_line['credit'] = credit_wo
writeoff_line['amount_currency'] = amount_currency_wo
diff --git a/addons/account/views/account_payment_view.xml b/addons/account/views/account_payment_view.xml
index 07230902ee8..1359009bf23 100644
--- a/addons/account/views/account_payment_view.xml
+++ b/addons/account/views/account_payment_view.xml
@@ -277,6 +277,8 @@
<div attrs="{'invisible': [('payment_difference_handling','=','open')]}">
<label for="writeoff_account_id" class="oe_edit_only" string="Post Difference In"/>
<field name="writeoff_account_id" string="Post Difference In" attrs="{'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
+ <label for="writeoff_analytic_account_id" class="oe_edit_only" string="Analytic Account" groups="analytic.group_analytic_accounting"/>
+ <field name="writeoff_analytic_account_id" groups="analytic.group_analytic_accounting"/>
<label for="journal_id" string="Journal" attrs="{'invisible': [('amount', '!=', 0)]}"/>
<field name="journal_id" string="Journal" widget="selection" attrs="{'invisible': [('amount', '!=', 0)]}"/>
<label for="writeoff_label" class="oe_edit_only" string="Label"/>

View File

@@ -1,11 +0,0 @@
from . import account_account
from . import account_analytic_account
from . import account_bank_statement
from . import account_incoterms
from . import account_journal
from . import account_move
from . import account_partial_reconcile
from . import res_partner
from . import res_company
from . import product
from . import account_invoice_report

View File

@@ -1,59 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models
import logging
logger = logging.getLogger(__name__)
class AccountAccount(models.Model):
_inherit = 'account.account'
@api.depends('name', 'code')
def name_get(self):
if self._context.get('account_account_show_code_only'):
res = []
for record in self:
res.append((record.id, record.code))
return res
else:
return super().name_get()
# https://github.com/odoo/odoo/issues/23040
# TODO mig to v14 ?
def fix_bank_account_types(self):
aao = self.env['account.account']
companies = self.env['res.company'].search([])
if len(companies) > 1:
self = self.sudo()
logger.info("START the script 'fix bank and cash account types'")
bank_type = self.env.ref('account.data_account_type_liquidity')
asset_type = self.env.ref('account.data_account_type_current_assets')
journals = self.env['account.journal'].search(
[('type', 'in', ('bank', 'cash'))], order='company_id')
journal_accounts_bank_type = aao
for journal in journals:
for account in [
journal.default_credit_account_id,
journal.default_debit_account_id]:
if account:
if account.user_type_id != bank_type:
account.user_type_id = bank_type.id
logger.info(
'Company %s: Account %s updated to Bank '
'and Cash type',
account.company_id.display_name, account.code)
if account not in journal_accounts_bank_type:
journal_accounts_bank_type += account
accounts = aao.search([
('user_type_id', '=', bank_type.id)], order='company_id, code')
for account in accounts:
if account not in journal_accounts_bank_type:
account.user_type_id = asset_type.id
logger.info(
'Company %s: Account %s updated to Current Asset type',
account.company_id.display_name, account.code)
logger.info("END of the script 'fix bank and cash account types'")
return True

View File

@@ -1,24 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class AccountAnalyticAccount(models.Model):
_inherit = 'account.analytic.account'
def name_get(self):
if self._context.get('analytic_account_show_code_only'):
res = []
for record in self:
res.append((record.id, record.code or record.name))
return res
else:
return super().name_get()
_sql_constraints = [(
'code_company_unique',
'unique(code, company_id)',
'An analytic account with the same code already '
'exists in the same company!')]

View File

@@ -1,104 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
from odoo.tools.misc import format_date
class AccountBankStatement(models.Model):
_inherit = 'account.bank.statement'
start_date = fields.Date(
compute='_compute_dates', string='Start Date', store=True)
end_date = fields.Date(
compute='_compute_dates', string='End Date', store=True)
line_count = fields.Integer(
compute='_compute_dates', string='# of Lines', store=True)
hide_bank_statement_balance = fields.Boolean(
related='journal_id.hide_bank_statement_balance', readonly=True)
@api.depends('line_ids.date')
def _compute_dates(self):
for st in self:
dates = [line.date for line in st.line_ids]
st.start_date = dates and min(dates) or False
st.end_date = dates and max(dates) or False
st.line_count = len(dates)
def _check_balance_end_real_same_as_computed(self):
for stmt in self:
if not stmt.hide_bank_statement_balance:
super(AccountBankStatement, stmt)._check_balance_end_real_same_as_computed()
return True
@api.depends('name', 'start_date', 'end_date')
def name_get(self):
res = []
for statement in self:
name = "%s (%s => %s)" % (
statement.name,
statement.start_date and format_date(self.env, statement.start_date) or '',
statement.end_date and format_date(self.env, statement.end_date) or '')
res.append((statement.id, name))
return res
def button_reopen(self):
self = self.with_context(skip_undo_reconciliation=True)
return super().button_reopen()
def button_undo_reconciliation(self):
self.line_ids.button_undo_reconciliation()
class AccountBankStatementLine(models.Model):
_inherit = 'account.bank.statement.line'
# Native order is:
# _order = 'statement_id desc, sequence, id desc'
_order = 'statement_id desc, date desc, sequence, id desc'
# Disable guessing for reconciliation
# because my experience with several customers shows that it is a problem
# in the following scenario : move line 'x' has been "guessed" by OpenERP
# to be reconciled with a statement line 'Y' at the end of the bank
# statement, but it is a mistake because it should be reconciled with
# statement line 'B' at the beginning of the bank statement
# When the user is on statement line 'B', he tries to select
# move line 'x', but it can't find it... because it is already "reserved"
# by the guess of OpenERP for statement line 'Y' ! To solve this problem,
# the user must go to statement line 'Y' and unselect move line 'x'
# and then come back on statement line 'B' and select move line 'A'...
# but non super-expert users can't do that because it is impossible to
# figure out that the fact that the user can't find move line 'x'
# is caused by this.
# Set search_reconciliation_proposition to False by default
# TODO: re-write in v10
# def get_data_for_reconciliations(
# self, cr, uid, ids, excluded_ids=None,
# search_reconciliation_proposition=False, context=None):
# # Make variable name shorted for PEP8 !
# search_rec_prop = search_reconciliation_proposition
# return super().\
# get_data_for_reconciliations(
# cr, uid, ids, excluded_ids=excluded_ids,
# search_reconciliation_proposition=search_rec_prop,
# context=context)
def show_account_move(self):
self.ensure_one()
action = self.env["ir.actions.actions"]._for_xml_id(
'account.action_move_line_form')
# Note: this action is on account.move, not account.move.line !
action.update({
'views': False,
'view_id': False,
'view_mode': 'form,tree',
'res_id': self.move_id.id,
})
return action
def button_undo_reconciliation(self):
if self._context.get("skip_undo_reconciliation"):
return
else:
return super().button_undo_reconciliation()

View File

@@ -1,26 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models
class AccountIncoterms(models.Model):
_inherit = 'account.incoterms'
@api.depends('code', 'name')
def name_get(self):
res = []
for rec in self:
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
return res
@api.model
def name_search(self, name='', args=None, operator='ilike', limit=100):
if args is None:
args = []
if name and operator == 'ilike':
recs = self.search([('code', '=ilike', name + '%')] + args, limit=limit)
if recs:
return recs.name_get()
return super().name_search(name=name, args=args, operator=operator, limit=limit)

View File

@@ -1,17 +0,0 @@
# Copyright 2022 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class AccountInvoiceReport(models.Model):
_inherit = 'account.invoice.report'
industry_id = fields.Many2one('res.partner.industry', string='Partner Industry', readonly=True)
@api.model
def _select(self):
res = super()._select()
res += ", COALESCE(partner.industry_id, commercial_partner.industry_id) AS industry_id"
return res

View File

@@ -1,87 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class AccountJournal(models.Model):
_inherit = 'account.journal'
hide_bank_statement_balance = fields.Boolean(
string='Hide and Disable Bank Statement Balance',
help="When this option is enabled, the start and end balance is "
"not displayed on the bank statement form view, and the check of "
"the end balance vs the real end balance is disabled. When you enable "
"this option, you process the statement lines without considering "
"the start/end balance and you regularly check the accounting balance "
"of the bank account vs the amount of your bank account "
"(the 2 processes are managed separately)."
)
# Used to set default user_type_id on account fields via context
account_type_current_assets_id = fields.Many2one(
'account.account.type',
default=lambda self: self.env.ref('account.data_account_type_current_assets').id)
# SQL constraint in the 'account' module: unique(code, name, company_id) !!!
_sql_constraints = [(
'code_unique', 'unique(code, company_id)',
'Another journal already has this code in this company!')]
@api.depends(
'name', 'currency_id', 'company_id', 'company_id.currency_id', 'code')
def name_get(self):
res = []
if self._context.get('journal_show_code_only'):
for journal in self:
res.append((journal.id, journal.code))
return res
else:
for journal in self:
name = "[%s] %s" % (journal.code, journal.name)
if (
journal.currency_id and
journal.currency_id != journal.company_id.currency_id):
name = "%s (%s)" % (name, journal.currency_id.name)
res.append((journal.id, name))
return res
def open_outstanding_payments(self):
self.ensure_one()
action = self.env["ir.actions.actions"]._for_xml_id(
"account.action_account_moves_all")
action['domain'] = [
('account_id', 'in', (self.payment_debit_account_id.id, self.payment_credit_account_id.id)),
('journal_id', '=', self.id),
('display_type', 'not in', ('line_section', 'line_note')),
('parent_state', '!=', 'cancel'),
]
action['context'] = {
'search_default_unreconciled': True,
'search_default_posted': True,
}
return action
# @api.constrains('default_credit_account_id', 'default_debit_account_id')
# def _check_account_type_on_bank_journal(self):
# bank_acc_type = self.env.ref('account.data_account_type_liquidity')
# for jrl in self:
# if jrl.type in ('bank', 'cash'):
# if (
# jrl.default_debit_account_id and
# jrl.default_debit_account_id.user_type_id !=
# bank_acc_type):
# raise ValidationError(_(
# "On journal '%s', the default debit account '%s' "
# "should be configured with Type = 'Bank and Cash'.")
# % (jrl.display_name,
# jrl.default_debit_account_id.display_name))
# if (
# jrl.default_credit_account_id and
# jrl.default_credit_account_id.user_type_id !=
# bank_acc_type):
# raise ValidationError(_(
# "On journal '%s', the default credit account '%s' "
# "should be configured with Type = 'Bank and Cash'.")
# % (jrl.display_name,
# jrl.default_credit_account_id.display_name))

View File

@@ -1,290 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
from odoo.tools import float_is_zero
from odoo.tools.misc import format_date
from odoo.osv import expression
from datetime import timedelta
from odoo.exceptions import UserError
class AccountMove(models.Model):
_inherit = 'account.move'
# By default, we can still modify "ref" when account move is posted
# which seems a bit lazy for me...
ref = fields.Char(states={'posted': [('readonly', True)]})
date = fields.Date(tracking=True)
invoice_date_due = fields.Date(tracking=True)
invoice_payment_term_id = fields.Many2one(tracking=True)
journal_id = fields.Many2one(tracking=True)
partner_bank_id = fields.Many2one(tracking=True)
fiscal_position_id = fields.Many2one(tracking=True)
amount_total = fields.Monetary(tracking=True)
# for invoice report
has_discount = fields.Boolean(
compute='_compute_has_discount', readonly=True)
# has_attachment is useful for those who use attachment to archive
# supplier invoices. It allows them to find supplier invoices
# that don't have any attachment
has_attachment = fields.Boolean(
compute='_compute_has_attachment',
search='_search_has_attachment', readonly=True)
sale_dates = fields.Char(
compute="_compute_sales_dates", readonly=True,
help="This information appear on invoice qweb report "
"(you may use it for your own report)")
def _compute_has_discount(self):
prec = self.env['decimal.precision'].precision_get('Discount')
for inv in self:
has_discount = False
for line in inv.invoice_line_ids:
if not line.display_type and not float_is_zero(line.discount, precision_digits=prec):
has_discount = True
break
inv.has_discount = has_discount
def _compute_has_attachment(self):
iao = self.env['ir.attachment']
for move in self:
if iao.search_count([
('res_model', '=', 'account.move'),
('res_id', '=', move.id),
('type', '=', 'binary'),
('company_id', '=', move.company_id.id)]):
move.has_attachment = True
else:
move.has_attachment = False
def _search_has_attachment(self, operator, value):
att_inv_ids = {}
if operator == '=':
search_res = self.env['ir.attachment'].search_read([
('res_model', '=', 'account.move'),
('type', '=', 'binary'),
('res_id', '!=', False)], ['res_id'])
for att in search_res:
att_inv_ids[att['res_id']] = True
res = [('id', value and 'in' or 'not in', list(att_inv_ids))]
return res
# when you have an invoice created from a lot of sale orders, the 'name'
# field is very large, which makes the name_get() of that invoice very big
# which screws-up the form view of that invoice because of the link at the
# top of the screen
# That's why we have to cut the name_get() when it's too long
def name_get(self):
old_res = super().name_get()
res = []
for old_re in old_res:
name = old_re[1]
if name and len(name) > 100:
# nice cut
name = '%s ...' % ', '.join(name.split(', ')[:3])
# if not enough, hard cut
if len(name) > 120:
name = '%s ...' % old_re[1][:120]
res.append((old_re[0], name))
return res
# I really hate to see a "/" in the 'name' field of the account.move.line
# generated from customer invoices linked to the partners' account because:
# 1) the label of an account move line is an important field, we can't
# write a rubbish '/' in it !
# 2) the 'name' field of the account.move.line is used in the overdue
# letter, and '/' is not meaningful for our customer !
# TODO mig to v12
# def action_move_create(self):
# res = super().action_move_create()
# for inv in self:
# self._cr.execute(
# "UPDATE account_move_line SET name= "
# "CASE WHEN name='/' THEN %s "
# "ELSE %s||' - '||name END "
# "WHERE move_id=%s", (inv.number, inv.number, inv.move_id.id))
# self.invalidate_cache()
# return res
def delete_lines_qty_zero(self):
lines = self.env['account.move.line'].search([
('display_type', '=', False),
('move_id', 'in', self.ids),
('quantity', '=', 0)])
lines.unlink()
return True
# for report
def py3o_lines_layout(self):
self.ensure_one()
res = []
has_sections = False
subtotal = 0.0
sign = self.move_type == 'out_refund' and -1 or 1
# Warning: the order of invoice line is forced in the view
# <tree editable="bottom" default_order="sequence, date desc, move_name desc, id"
# it's not the same as the _order in the class AccountMoveLine
lines = self.env['account.move.line'].search([('exclude_from_invoice_tab', '=', False), ('move_id', '=', self.id)], order="sequence, date desc, move_name desc, id")
for line in lines:
if line.display_type == 'line_section':
# insert line
if has_sections:
res.append({'subtotal': subtotal})
subtotal = 0.0 # reset counter
has_sections = True
else:
if not line.display_type:
subtotal += line.price_subtotal * sign
res.append({'line': line})
if has_sections: # insert last subtotal line
res.append({'subtotal': subtotal})
# res:
# [
# {'line': account_invoice_line(1) with display_type=='line_section'},
# {'line': account_invoice_line(2) without display_type},
# {'line': account_invoice_line(3) without display_type},
# {'line': account_invoice_line(4) with display_type=='line_note'},
# {'subtotal': 8932.23},
# ]
return res
def _compute_sales_dates(self):
""" French law requires to set sale order dates into invoice
returned string: "sale1 (date1), sale2 (date2) ..."
"""
for move in self:
sales = move.invoice_line_ids.mapped(
'sale_line_ids').mapped('order_id')
dates = ["%s (%s)" % (
x.name, format_date(move.env, x.date_order))
for x in sales]
move.sale_dates = ", ".join(dates)
# allow to manually create moves not only in general journals,
# but also in cash journal and check journals (= bank journals not linked to a bank account)
@api.depends('company_id', 'invoice_filter_type_domain')
def _compute_suitable_journal_ids(self):
for move in self:
if move.invoice_filter_type_domain:
super(AccountMove, move)._compute_suitable_journal_ids()
else:
company_id = move.company_id.id or self.env.company.id
domain = expression.AND([
[('company_id', '=', company_id)],
expression.OR([
[('type', 'in', ('general', 'cash'))],
[('type', '=', 'bank'), ('bank_account_id', '=', False)]
])
])
move.suitable_journal_ids = self.env['account.journal'].search(domain)
def button_draft(self):
super().button_draft()
# Delete attached pdf invoice
try:
report_invoice = self.env['ir.actions.report']._get_report_from_name('account.report_invoice')
except IndexError:
report_invoice = False
if report_invoice and report_invoice.attachment:
for move in self.filtered(lambda x: x.move_type in ('out_invoice', 'out_refund')):
# The pb is that the filename is dynamic and related to move.state
# in v12, the feature was native and they used that kind of code:
# with invoice.env.do_in_draft():
# invoice.number, invoice.state = invoice.move_name, 'open'
# attachment = self.env.ref('account.account_invoices').retrieve_attachment(invoice)
# But do_in_draft() doesn't exists in v14
# If you know how we could do that, please update the code below
attachment = self.env['ir.attachment'].search([
('name', '=', self._get_invoice_attachment_name()),
('res_id', '=', move.id),
('res_model', '=', self._name),
('type', '=', 'binary'),
], limit=1)
if attachment:
attachment.unlink()
def _get_invoice_attachment_name(self):
self.ensure_one()
return '%s.pdf' % (self.name and self.name.replace('/', '_') or 'INV')
def _get_accounting_date(self, invoice_date, has_tax):
# On vendor bills/refunds, we want date = invoice_date unless
# we have a company tax_lock_date and the invoice has taxes
# and invoice_date <= tax_lock_date
date = super()._get_accounting_date(invoice_date, has_tax)
if self.is_purchase_document(include_receipts=True):
tax_lock_date = self.company_id.tax_lock_date
if invoice_date and tax_lock_date and has_tax and invoice_date <= tax_lock_date:
invoice_date = tax_lock_date + timedelta(days=1)
date = invoice_date
return date
class AccountMoveLine(models.Model):
_inherit = 'account.move.line'
# Native order:
# _order = "date desc, move_name desc, id"
# Problem: when you manually create a journal entry, the
# order of the lines is inverted when you save ! It is quite annoying for
# the user...
_order = "date desc, id asc"
# In the 'account' module, we have related stored field for:
# name (move_name), date, ref, state (parent_state),
# journal_id, company_id, payment_id, statement_line_id,
account_reconcile = fields.Boolean(related='account_id.reconcile')
full_reconcile_id = fields.Many2one(string='Full Reconcile')
matched_debit_ids = fields.One2many(string='Partial Reconcile Debit')
matched_credit_ids = fields.One2many(string='Partial Reconcile Credit')
reconcile_string = fields.Char(
compute='_compute_reconcile_string', string='Reconcile', store=True)
# for optional display in tree view
product_barcode = fields.Char(related='product_id.barcode', string="Product Barcode")
def show_account_move_form(self):
self.ensure_one()
action = self.env["ir.actions.actions"]._for_xml_id(
'account.action_move_line_form')
action.update({
'res_id': self.move_id.id,
'view_id': False,
'views': False,
'view_mode': 'form,tree',
})
return action
@api.depends(
'full_reconcile_id', 'matched_debit_ids', 'matched_credit_ids')
def _compute_reconcile_string(self):
for line in self:
rec_str = False
if line.full_reconcile_id:
rec_str = line.full_reconcile_id.name
else:
rec_str = ', '.join([
'a%d' % pr.id for pr in line.matched_debit_ids + line.matched_credit_ids])
line.reconcile_string = rec_str
def _get_computed_name(self):
# This is useful when you want to have the product code in a dedicated
# column in your customer invoice report
# The same ir.config_parameter is used in sale_usability,
# purchase_usability and account_usability
no_product_code_param = self.env['ir.config_parameter'].sudo().get_param(
'usability.line_name_no_product_code')
if no_product_code_param and no_product_code_param == 'True':
self = self.with_context(display_default_code=False)
return super()._get_computed_name()
def reconcile(self):
"""Explicit error message if unposted lines"""
unposted_ids = self.filtered(lambda l: l.move_id.state != "posted")
if unposted_ids:
m = _("Please post the following entries before reconciliation :")
sep = "\n - "
unpost = sep.join([am.display_name for am in unposted_ids.move_id])
raise UserError(m + sep + unpost)
return super().reconcile()

View File

@@ -1,23 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
from odoo.tools.misc import formatLang
class AccountPartialReconcile(models.Model):
_inherit = "account.partial.reconcile"
_rec_name = "id"
def name_get(self):
res = []
for rec in self:
# There is no seq for partial rec, so I simulate one with the ID
# Prefix for full rec: 'A' (upper case)
# Prefix for partial rec: 'a' (lower case)
amount_fmt = formatLang(
self.env, rec.amount, currency_obj=rec.company_currency_id)
name = 'a%d (%s)' % (rec.id, amount_fmt)
res.append((rec.id, name))
return res

View File

@@ -1,45 +0,0 @@
# Copyright 2015-2021 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
class ProductTemplate(models.Model):
_inherit = 'product.template'
# DON'T put store=True on those fields, because they are company dependent
sale_price_type = fields.Selection(
'_sale_purchase_price_type_sel', compute='_compute_sale_price_type',
string='Sale Price Type', compute_sudo=False, readonly=True)
purchase_price_type = fields.Selection(
'_sale_purchase_price_type_sel', compute='_compute_purchase_price_type',
string='Purchase Price Type', compute_sudo=False, readonly=True)
@api.model
def _sale_purchase_price_type_sel(self):
return [('incl', _('Tax incl.')), ('excl', _('Tax excl.'))]
@api.depends('taxes_id')
def _compute_sale_price_type(self):
for pt in self:
sale_price_type = 'incl'
if pt.taxes_id and all([not t.price_include for t in pt.taxes_id if t.amount_type == 'percent']):
sale_price_type = 'excl'
pt.sale_price_type = sale_price_type
@api.depends('supplier_taxes_id')
def _compute_purchase_price_type(self):
for pt in self:
purchase_price_type = 'incl'
if pt.supplier_taxes_id and all([not t.price_include for t in pt.supplier_taxes_id if t.amount_type == 'percent']):
purchase_price_type = 'excl'
pt.purchase_price_type = purchase_price_type
class ProductSupplierinfo(models.Model):
_inherit = 'product.supplierinfo'
# DON'T put store=True on those fields, because they are company dependent
purchase_price_type = fields.Selection(
related='product_tmpl_id.purchase_price_type', related_sudo=False)

View File

@@ -1,21 +0,0 @@
# Copyright 2021 Akretion France (https://akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ResCompany(models.Model):
_inherit = 'res.company'
# There is a native field invoice_terms which is displayed on res.config.settings
# when the ir.config_parameter account.use_invoice_terms is True
# But there are several problems with this native field:
# - it is copied on the 'narration' field of account.move => we don't want that
# - the text block is very small on the form view of res.config.settings
# So I decided to have our own field "fixed_invoice_terms"
# The native field can still be used when you need to customise some
# terms and conditions on each invoice (not very common, but...)
# To underline this different with the native field, I prefix it with 'static_'
static_invoice_terms = fields.Text(
translate=True, string="Legal Terms on Invoice")

View File

@@ -1,12 +0,0 @@
# Copyright 2017-2020 Akretion France (https://akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ResPartner(models.Model):
_inherit = 'res.partner'
invoice_warn = fields.Selection(tracking=True)
property_account_position_id = fields.Many2one(tracking=True)

View File

@@ -0,0 +1,13 @@
# Copyright 2017-2019 Akretion France (https://akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
class ResPartner(models.Model):
_inherit = 'res.partner'
invoice_warn = fields.Selection(track_visibility='onchange')
property_account_position_id = fields.Many2one(
track_visibility='onchange')

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2020 Akretion (http://www.akretion.com/)
Copyright 2017-2019 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -13,9 +13,9 @@
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='bank_ids']/tree/field[@name='acc_number']" position="after">
<field name="acc_type"/>
</xpath>
<field name="property_account_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
</field>
</record>

View File

@@ -1,3 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_account_group_generate_full,Full access on account.group.generate,model_account_group_generate,account.group_account_manager,1,1,1,1
access_account_invoice_mark_sent_full,Full access on account.invoice.mark.sent,model_account_invoice_mark_sent,account.group_account_invoice,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_account_group_generate_full Full access on account.group.generate model_account_group_generate account.group_account_manager 1 1 1 1
3 access_account_invoice_mark_sent_full Full access on account.invoice.mark.sent model_account_invoice_mark_sent account.group_account_invoice 1 1 1 1

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<templates id="template" xml:space="preserve">
<!-- Requires https://github.com/odoo/odoo/pull/84180 -->
<t t-extend="ShowPaymentInfo" >
<t t-jquery="td:first" t-operation="after">
<td style="max-width: 25em;" id="outstanding-date">
<div class="oe_form_field" style="margin-right: 5px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"><t t-esc="line.date"></t></div>
</td>
</t>
</t>
</templates>

View File

@@ -1,41 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_form" model="ir.ui.view">
<field name="name">account.account.form</field>
<field name="model">account.account</field>
<field name="inherit_id" ref="account.view_account_form"/>
<field name="arch" type="xml">
<field name="deprecated" position="before">
<field name="reconcile" attrs="{'invisible': ['|', ('internal_type','=','liquidity'), ('internal_group', '=', 'off_balance')]}"/>
</field>
</field>
</record>
<record id="view_account_search" model="ir.ui.view">
<field name="name">account.account.search</field>
<field name="model">account.account</field>
<field name="inherit_id" ref="account.view_account_search"/>
<field name="arch" type="xml">
<!-- The native "name" filter uses a domain ['|', ('name','ilike',self), ('code','=like',str(self)+'%')]
This is good because it uses '=like' on 'code', but sometimes there are digits in account names,
so you get additionnal unexpected accounts in the result of the search -->
<field name="name" position="after">
<field name="code" filter_domain="[('code', '=like', str(self)+'%')]" string="Code"/>
</field>
<filter name="accounttype" position="after">
<filter name="group_groupby" string="Group" context="{'group_by': 'group_id'}"/>
</filter>
</field>
</record>
</odoo>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2020 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_type_tree" model="ir.ui.view">
<field name="name">account_usability.account_type_tree</field>
<field name="model">account.account.type</field>
<field name="inherit_id" ref="account.view_account_type_tree" />
<field name="arch" type="xml">
<field name="type" position="after">
<field name="include_initial_balance" optional="show"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_analytic_account_list" model="ir.ui.view">
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_list"/>
<field name="arch" type="xml">
<field name="code" position="after">
<field name="group_id" optional="show"/>
</field>
</field>
</record>
<record id="view_account_analytic_account_search" model="ir.ui.view">
<field name="model">account.analytic.account</field>
<field name="inherit_id" ref="analytic.view_account_analytic_account_search"/>
<field name="arch" type="xml">
<filter name="associatedpartner" position="before">
<filter name="group_groupby" string="Group" context="{'group_by': 'group_id'}"/>
</filter>
</field>
</record>
</odoo>

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account_analytic_group_tree_view" model="ir.ui.view">
<field name="model">account.analytic.group</field>
<field name="inherit_id" ref="analytic.account_analytic_group_tree_view"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="parent_id" optional="show"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,123 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2020 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_bank_statement_form" model="ir.ui.view">
<field name="name">usability.account.bank.statement.form</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<button name="button_reopen" position="after">
<button
name="button_undo_reconciliation"
type="object"
confirm="Are you sure to unreconcile all the entries of the bank statement?"
states="open"
string="Unreconcile All"/>
</button>
<xpath expr="//field[@name='line_ids']/tree/button[@name='button_undo_reconciliation']" position="after">
<field name="move_id" invisible="1"/>
<button name="show_account_move" type="object"
title="View Journal Entry" icon="fa-arrow-right"/>
</xpath>
<xpath expr="//field[@name='balance_end_real']/.." position="after">
<field name="start_date"/>
<field name="end_date"/>
<field name="hide_bank_statement_balance" invisible="1"/>
<field name="line_count"/>
</xpath>
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="journal_id" position="attributes">
<attribute name="widget"></attribute>
</field>
<label for="balance_start" position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</label>
<label for="balance_end_real" position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</label>
<xpath expr="//field[@name='balance_start']/.." position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</xpath>
<xpath expr="//field[@name='balance_end_real']/.." position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</xpath>
<group name="sale_total" position="attributes">
<attribute name="attrs">{'invisible': [('hide_bank_statement_balance', '=', True)]}</attribute>
</group>
<div role="alert" position="attributes">
<attribute name="attrs">{'invisible': ['|', '|', ('hide_bank_statement_balance', '=', True), ('previous_statement_id', '=', False), ('is_valid_balance_start', '=', True)]}</attribute>
</div>
</field>
</record>
<record id="view_bank_statement_tree" model="ir.ui.view">
<field name="name">usability.account.bank.statement.tree</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_tree"/>
<field name="arch" type="xml">
<tree position="attributes">
<!-- Remove is_difference_zero condition for colors -->
<attribute name="decoration-danger"></attribute>
<attribute name="decoration-info">state == 'open'</attribute>
</tree>
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="journal_id" position="after">
<field name="start_date"/>
<field name="end_date"/>
<field name="line_count" optional="show"/>
</field>
<field name="balance_start" position="attributes">
<attribute name="optional">show</attribute>
</field>
<field name="balance_end_real" position="attributes">
<attribute name="optional">show</attribute>
</field>
<field name="state" position="attributes">
<attribute name="widget">badge</attribute>
<attribute name="decoration-info">state == 'open'</attribute>
<attribute name="decoration-warning">state == 'posted'</attribute>
<attribute name="decoration-success">state == 'confirm'</attribute>
</field>
</field>
</record>
<record id="view_bank_statement_search" model="ir.ui.view">
<field name="name">usability.account.bank.statement.search</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_search"/>
<field name="arch" type="xml">
<field name="date" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<filter name="filter_date" position="attributes">
<attribute name="invisible">1</attribute>
</filter>
<filter name="date" position="attributes">
<attribute name="invisible">1</attribute>
</filter>
<field name="date" position="after">
<field name="start_date"/>
<field name="end_date"/>
</field>
<filter name="date" position="after">
<filter name="start_date_groupby" string="Start Date"
context="{'group_by': 'start_date'}"/>
<filter name="end_date_groupby" string="End Date"
context="{'group_by': 'end_date'}"/>
</filter>
</field>
</record>
</odoo>

View File

@@ -1,32 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_group_form" model="ir.ui.view">
<field name="model">account.group</field>
<field name="inherit_id" ref="account.view_account_group_form"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="parent_id"/>
</field>
</field>
</record>
<record id="view_account_group_tree" model="ir.ui.view">
<field name="model">account.group</field>
<field name="inherit_id" ref="account.view_account_group_tree"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="parent_id" optional="show"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018-2020 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account_invoice_report_tree" model="ir.ui.view">
<field name="name">usability.account.invoice.report.tree</field>
<field name="model">account.invoice.report</field>
<field name="arch" type="xml">
<tree string="Invoices Analysis">
<field name="move_id"/>
<field name="journal_id" optional="hide"/>
<field name="company_id" optional="hide" groups="base.group_multi_company"/>
<field name="invoice_date"/>
<field name="invoice_date_due"/>
<field name="move_type"/>
<field name="commercial_partner_id"/>
<field name="partner_id" optional="hide"/>
<field name="country_id" optional="hide"/>
<field name="industry_id" optional="hide"/>
<field name="invoice_user_id"/>
<field name="fiscal_position_id" optional="hide"/>
<field name="product_id"/>
<field name="product_categ_id" optional="hide"/>
<field name="account_id" optional="hide"/>
<field name="analytic_account_id" optional="hide" groups="analytic.group_analytic_accounting"/>
<field name="quantity" sum="1"/>
<field name="product_uom_id" groups="uom.group_uom"/>
<field name="price_subtotal" sum="1"/>
<field name="state"/>
<field name="payment_state" optional="hide"/>
</tree>
</field>
</record>
<record id="account.action_account_invoice_report_all_supp" model="ir.actions.act_window">
<field name="context">{'search_default_current': 1, 'search_default_supplier': 1, 'group_by': ['invoice_date']}</field> <!-- Remove group_by_no_leaf, which breaks tree view -->
<field name="view_mode">pivot,graph</field>
</record>
<record id="account.action_account_invoice_report_all" model="ir.actions.act_window">
<field name="context">{'search_default_current': 1, 'search_default_customer': 1, 'group_by': ['invoice_date']}</field> <!-- Remove group_by_no_leaf, which breaks tree view -->
<field name="view_mode">pivot,graph</field>
</record>
<record id="view_account_invoice_report_pivot" model="ir.ui.view">
<field name="name">usability.account.invoice.report</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_pivot"/>
<field name="arch" type="xml">
<pivot position="attributes">
<attribute name="disable_linking"></attribute>
</pivot>
</field>
</record>
</odoo>

View File

@@ -1,72 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2020 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_journal_form" model="ir.ui.view">
<field name="name">usability.account.journal.form</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_form"/>
<field name="arch" type="xml">
<field name="bank_statements_source" position="after">
<field name="hide_bank_statement_balance" groups="account.group_account_readonly"/>
<field name="account_type_current_assets_id" invisible="1"/>
</field>
<field name="suspense_account_id" position="attributes">
<attribute name="context">{'default_user_type_id': account_type_current_assets_id, 'default_reconcile': False}</attribute>
</field>
<field name="payment_debit_account_id" position="attributes">
<attribute name="context">{'default_user_type_id': account_type_current_assets_id, 'default_reconcile': True}</attribute>
</field>
<field name="payment_credit_account_id" position="attributes">
<attribute name="context">{'default_user_type_id': account_type_current_assets_id, 'default_reconcile': True}</attribute>
</field>
</field>
</record>
<record id="account_journal_dashboard_kanban_view" model="ir.ui.view">
<field name="name">usability.account.journal.dashboard</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.account_journal_dashboard_kanban_view"/>
<field name="arch" type="xml">
<field name="kanban_dashboard" position="after">
<field name="hide_bank_statement_balance"/>
</field>
<xpath expr="//div[@name='latest_statement']/.." position="attributes">
<attribute name="t-if">dashboard.has_at_least_one_statement and dashboard.account_balance != dashboard.last_balance and !record.hide_bank_statement_balance.raw_value</attribute>
</xpath>
<t t-esc="dashboard.outstanding_pay_account_balance" position="replace">
<a name="open_outstanding_payments" type="object" title="Outstanding Payments/Receipts"><t t-esc="dashboard.outstanding_pay_account_balance"/></a>
</t>
</field>
</record>
<record id="view_account_journal_tree" model="ir.ui.view">
<field name="name">usability.account.journal.tree</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_tree"/>
<field name="arch" type="xml">
<field name="name" position="after">
<field name="code" optional="show"/>
</field>
</field>
</record>
<record id="view_account_journal_search" model="ir.ui.view">
<field name="name">usability.account.journal.search</field>
<field name="model">account.journal</field>
<field name="inherit_id" ref="account.view_account_journal_search"/>
<field name="arch" type="xml">
<filter name="inactive" position="after">
<group name="groupby" string="Group By">
<filter name="type_groupby" string="Type" context="{'group_by': 'type'}"/>
</group>
</filter>
</field>
</record>
</odoo>

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2020 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- Duplicate the menu "Sales > Configuration > Contacts > Bank Accounts"
under "Accounting > Configuration", because most users will try to find it there -->
<menuitem id="res_bank_account_config_menu" action="base.action_res_bank_form" parent="account.account_banks_menu" sequence="10"/>
<menuitem id="res_partner_bank_account_config_menu" action="base.action_res_partner_bank_account_form" parent="account.account_banks_menu" sequence="20"/>
</odoo>

View File

@@ -1,134 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2020 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_move_form" model="ir.ui.view">
<field name="name">account_usability.account.move.form</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<field name="fiscal_position_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<field name="invoice_incoterm_id" position="attributes">
<attribute name="widget">selection</attribute>
</field>
<button name="action_register_payment" position="attributes">
<attribute name="class">btn-default</attribute>
</button>
<button name="action_register_payment" position="before">
<button name="%(account.account_invoices)d" type="action" string="Print" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
</button>
<button name="preview_invoice" position="attributes">
<attribute name="attrs">{'invisible': 1}</attribute>
</button>
<!-- move sent field and make it visible -->
<field name="is_move_sent" position="replace"/>
<field name="invoice_origin" position="attributes">
<attribute name="invisible">0</attribute>
</field>
<field name="invoice_origin" position="after">
<field name="is_move_sent" attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund'))]}"/>
</field>
<xpath expr="//field[@name='line_ids']/tree/field[@name='analytic_account_id']" position="attributes">
<attribute name="optional">show</attribute>
</xpath>
<xpath expr="//field[@name='line_ids']/tree/field[@name='currency_id']" position="attributes">
<attribute name="optional">show</attribute>
</xpath>
<xpath expr="//field[@name='line_ids']/tree/field[@name='tax_tag_ids']" position="after">
<field name="matching_number" optional="hide"/>
<field name="reconcile_string" optional="show"/>
</xpath>
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='product_id']" position="after">
<field name="product_barcode" optional="hide"/>
</xpath>
</field>
</record>
<record id="view_invoice_tree" model="ir.ui.view">
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_invoice_tree"/>
<field name="arch" type="xml">
<field name="amount_residual_signed" position="attributes">
<attribute name="optional">show</attribute>
</field>
</field>
</record>
<record id="view_account_invoice_filter" model="ir.ui.view">
<field name="name">account_usability.account.move.search</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_account_invoice_filter"/>
<field name="arch" type="xml">
<filter name="due_date" position="after">
<separator/>
<filter name="to_send" string="To Send" domain="[('is_move_sent', '=', False), ('state', '=', 'posted'), ('move_type', 'in', ('out_invoice', 'out_refund'))]"/>
<filter name="sent" string="Sent" domain="[('is_move_sent', '=', True), ('move_type', 'in', ('out_invoice', 'out_refund'))]"/>
<separator/>
<filter name="no_attachment" string="Missing Attachment" domain="[('has_attachment', '=', False)]"/>
</filter>
<filter name="salesperson" position="before">
<filter name="commercial_partner_groupby" string="Commercial Partner" context="{'group_by': 'commercial_partner_id'}"/>
</filter>
<filter name="status" position="after">
<filter name="payment_state_groupby" string="Payment Status" context="{'group_by': 'payment_state'}"/>
</filter>
</field>
</record>
<record id="view_move_line_tree" model="ir.ui.view">
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_tree"/>
<field name="arch" type="xml">
<field name="matching_number" position="after">
<button title="View Journal Entry Form" type="object" name="show_account_move_form" icon="fa-arrow-right"/>
</field>
<field name="credit" position="after">
<field name="balance" sum="Balance" optional="show"/>
</field>
</field>
</record>
<record id="view_account_move_line_filter" model="ir.ui.view">
<field name="name">account_usability.account_move_line_search</field>
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_account_move_line_filter"/>
<field name="arch" type="xml">
<filter name="unposted" position="before">
<filter name="current_year" string="Current Year" domain="[('date', '&gt;=', (context_today().strftime('%Y-01-01'))), ('date', '&lt;=', (context_today().strftime('%Y-12-31')))]"/>
<filter name="previous_year" string="Previous Year" domain="[('date', '&gt;=', (context_today() + relativedelta(day=1, month=1, years=-1)).strftime('%Y-%m-%d')), ('date', '&lt;=', (context_today() + relativedelta(day=31, month=12, years=-1)).strftime('%Y-%m-%d'))]"/>
<separator/>
</filter>
<field name="partner_id" position="after">
<field name="reconcile_string" />
<field name="debit" filter_domain="['|', ('debit', '=', self), ('credit', '=', self)]" string="Debit or Credit"/>
</field>
<filter name="unreconciled" position="before">
<filter name="reconciled" string="Fully Reconciled" domain="[('reconciled', '=', True)]"/>
</filter>
<filter name="unreconciled" position="attributes">
<attribute name="string">Unreconciled or Partially Reconciled</attribute>
<attribute name="domain">[('reconciled', '=', False), ('balance', '!=', 0), ('account_id.reconcile', '=', True)]</attribute>
</filter>
<!--
<field name="name" position="attributes">
<attribute name="string">Name or Reference</attribute>
</field> -->
<field name="partner_id" position="attributes">
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
</field>
</field>
</record>
<record id="account.action_move_journal_line" model="ir.actions.act_window">
<field name="context">{'default_move_type': 'entry', 'view_no_maturity': True}</field>
<!-- Remove 'search_default_misc_filter': 1 -->
</record>
</odoo>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_account_reconcile_model_form" model="ir.ui.view">
<field name="model">account.reconcile.model</field>
<field name="inherit_id" ref="account.view_account_reconcile_model_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='line_ids']/tree/field[@name='analytic_account_id']" position="attributes">
<attribute name="optional">show</attribute> <!-- native value: hide -->
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018-2020 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account.account_invoices" model="ir.actions.report">
<!-- Attach only on customer invoices/refunds -->
<field name="attachment">(object.move_type in ('out_invoice', 'out_refund')) and (object.state == 'posted') and ((object.name or 'INV').replace('/','_')+'.pdf')</field>
</record>
<record id="account.account_invoices_without_payment" model="ir.actions.report">
<!-- Attach only on customer invoices/refunds -->
<field name="attachment">(object.move_type in ('out_invoice', 'out_refund')) and (object.state == 'posted') and ((object.name or 'INV').replace('/','_')+'.pdf')</field>
</record>
</odoo>

View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2020 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_tax_tree" model="ir.ui.view">
<field name="model">account.tax</field>
<field name="inherit_id" ref="account.view_tax_tree"/>
<field name="arch" type="xml">
<field name="description" position="after">
<field name="price_include" optional="show"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,72 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2020 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- In the official account module, on product category and product template,
some fields/groups are on account.group_account_invoice, some on
account.group_account_user and some on account.group_account_manager
Here, we set all those fields on account.group_account_invoice
-->
<record id="product_template_form_view" model="ir.ui.view">
<field name="name">account_usability.product.template.form</field>
<field name="model">product.template</field>
<field name="priority">100</field> <!-- when you replace a field, it's always better to inherit at the end -->
<field name="inherit_id" ref="account.product_template_form_view"/>
<field name="arch" type="xml">
<field name="property_account_income_id" position="attributes">
<attribute name="groups">account.group_account_invoice</attribute>
</field>
<field name="property_account_expense_id" position="attributes">
<attribute name="groups">account.group_account_invoice</attribute>
</field>
<field name="list_price" position="replace">
<div name="list_price">
<field name="list_price" widget='monetary' options="{'currency_field': 'currency_id', 'field_digits': True}" class="oe_inline"/>
<label for="sale_price_type" string=" "/>
<field name="sale_price_type"/>
</div>
</field>
</field>
</record>
<record id="view_category_property_form" model="ir.ui.view">
<field name="name">account_usability.product.category.form</field>
<field name="model">product.category</field>
<field name="inherit_id" ref="account.view_category_property_form"/>
<field name="arch" type="xml">
<group name="account_property" position="attributes">
<attribute name="groups">account.group_account_invoice</attribute>
</group>
</field>
</record>
<record id="product_supplierinfo_form_view" model="ir.ui.view">
<field name="name">account_usability.product.supplierinfo.form</field>
<field name="model">product.supplierinfo</field>
<field name="inherit_id" ref="product.product_supplierinfo_form_view"/>
<field name="arch" type="xml">
<field name="currency_id" position="after">
<field name="purchase_price_type"/>
</field>
</field>
</record>
<record id="product_supplierinfo_tree_view" model="ir.ui.view">
<field name="name">account_usability.product.supplierinfo.tree</field>
<field name="model">product.supplierinfo</field>
<field name="inherit_id" ref="product.product_supplierinfo_tree_view"/>
<field name="arch" type="xml">
<field name="price" position="after">
<field name="purchase_price_type" string="Tax"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 Akretion (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_company_form" model="ir.ui.view">
<field name="name">account_usability.res.company.form</field>
<field name="model">res.company</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Legal Terms" name="legal_terms">
<group string="Invoice Legal Terms" name="static_invoice_terms">
<field name="static_invoice_terms" nolabel="1"/>
</group>
</page>
</notebook>
</field>
</record>
</odoo>

View File

@@ -1,31 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2020 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">account_usability account config page</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="account.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='bank_cash']" position="inside">
<div class="col-xs-12 col-md-6 o_setting_box" id="transfer_account">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<label for="transfer_account_id"/>
<div class="text-muted">
Transit account when you transfer money from a bank account of your company to another bank account of your company.
</div>
<field name="transfer_account_id"/>
</div>
</div>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,4 +1,2 @@
from . import account_invoice_mark_sent
from . import account_move_reversal
from . import res_config_settings
from . import account_group_generate

View File

@@ -1,62 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models, _
from odoo.exceptions import UserError
class AccountGroupGenerate(models.TransientModel):
_name = 'account.group.generate'
_description = 'Generate Account Groups'
company_id = fields.Many2one(
'res.company', string='Company', required=True,
default=lambda self: self.env.company)
name_prefix = fields.Char(string='Prefix', required=True, default='Comptes')
level = fields.Integer(default=2, required=True)
def run(self):
if self.level < 1:
raise UserError(_("The level must be >= 1."))
ago = self.env['account.group']
aao = self.env['account.account']
company = self.company_id
groups = ago.search([('company_id', '=', company.id)])
if groups:
raise UserError(_(
"%d account groups already exists in company '%s'. This wizard is "
"designed to generate account groups from scratch.")
% (len(groups), company.display_name))
accounts = aao.search([('company_id', '=', company.id)])
struct = {'childs': {}}
for account in accounts:
if len(account.code) <= self.level:
raise UserError(_(
"The code of account '%s' is %d caracters. "
"It cannot be inferior to level (%d).")
% (account.display_name, len(account.code), self.level))
n = 1
parent = struct
gparent = False
while n <= self.level:
group_code = account.code[:n]
if group_code not in parent['childs']:
new_group = ago.create({
'name': '%s %s' % (self.name_prefix or '', group_code),
'code_prefix_start': group_code,
'parent_id': gparent and gparent.id or False,
'company_id': company.id,
})
parent['childs'][group_code] = {'obj': new_group, 'childs': {}}
parent = parent['childs'][group_code]
gparent = parent['obj']
n += 1
account.write({'group_id': gparent.id})
action = {
'type': 'ir.actions.act_window',
'name': _('Account Groups'),
'view_mode': 'tree,form',
'res_model': 'account.group',
}
return action

View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="account_group_generate_form" model="ir.ui.view">
<field name="name">account.group.generate.form</field>
<field name="model">account.group.generate</field>
<field name="arch" type="xml">
<form>
<p>
This wizard is designed to auto-generate account groups from the chart of account.
</p>
<group name="main">
<field name="company_id" groups="base.group_multi_company"/>
<field name="name_prefix"/>
<field name="level"/>
</group>
<footer>
<button type="object" name="run" string="Generate" class="btn-primary"/>
<button special="cancel" string="Cancel"/>
</footer>
</form>
</field>
</record>
<record id="account_group_generate_action" model="ir.actions.act_window">
<field name="name">Generate Account Groups</field>
<field name="res_model">account.group.generate</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<menuitem id="account_group_generate_menu"
action="account_group_generate_action"
parent="account.account_account_menu"
sequence="51"/>
</odoo>

View File

@@ -1,4 +1,4 @@
# Copyright 2017-2020 Akretion France (https://akretion.com/en)
# Copyright 2017-2019 Akretion France (https://akretion.com/en)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -12,13 +12,12 @@ class AccountInvoiceMarkSent(models.TransientModel):
_description = 'Mark invoices as sent'
def run(self):
assert self.env.context.get('active_model') == 'account.move',\
assert self.env.context.get('active_model') == 'account.invoice',\
'Source model must be invoices'
assert self.env.context.get('active_ids'), 'No invoices selected'
invoices = self.env['account.move'].search([
invoices = self.env['account.invoice'].search([
('id', 'in', self.env.context.get('active_ids')),
('move_type', 'in', ('out_invoice', 'out_refund')),
('state', '=', 'posted')])
invoices.write({'is_move_sent': True})
('state', 'in', ('open', 'paid'))])
invoices.write({'sent': True})
logger.info('Marking invoices with ID %s as sent', invoices.ids)
return

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2020 Akretion France
Copyright 2017-2019 Akretion France
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -13,7 +13,7 @@
<field name="arch" type="xml">
<form string="Mark invoices as sent">
<p>
This wizard will mark as <i>sent</i> all the selected posted invoices.
This wizard will mark as <i>sent</i> all the selected invoices in open or paid state.
</p>
<footer>
<button type="object" name="run" string="Mark as Sent" class="btn-primary"/>
@@ -23,13 +23,14 @@
</field>
</record>
<record id="account_invoice_mark_sent_action" model="ir.actions.act_window">
<field name="name">Mark as Sent</field>
<field name="res_model">account.invoice.mark.sent</field>
<field name="view_mode">form</field>
<field name="target">new</field>
<field name="binding_model_id" ref="account.model_account_move" />
<field name="binding_view_types">list</field>
</record>
<act_window id="account_invoice_mark_sent_action"
multi="True"
key2="client_action_multi"
name="Mark as Sent"
res_model="account.invoice.mark.sent"
src_model="account.invoice"
view_mode="form"
target="new"
groups="account.group_account_invoice" />
</odoo>

View File

@@ -1,29 +1,24 @@
# Copyright 2018-2020 Akretion France (https://akretion.com/)
# Copyright 2018-2019 Akretion France (https://akretion.com/)
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models, _
from odoo import api, fields, models
from dateutil.relativedelta import relativedelta
from odoo.exceptions import UserError
class AccountMoveReversal(models.TransientModel):
_inherit = 'account.move.reversal'
# Set default reversal date to original move + 1 day
# and raise error if original move has already been reversed
@api.model
def default_get(self, fields_list):
res = super().default_get(fields_list)
assert self._context.get('active_model') == 'account.move'
amo = self.env['account.move']
moves = amo.browse(self._context['active_ids'])
if len(moves) == 1:
res['date'] = moves.date + relativedelta(days=1)
reversed_move = amo.search([('reversed_entry_id', 'in', moves.ids)], limit=1)
if reversed_move:
raise UserError(_(
"Move '%s' has already been reversed by move '%s'.") % (
reversed_move.reversed_entry_id.display_name,
reversed_move.display_name))
return res
def _default_date(self):
date = None
if (
self._context.get('active_model') == 'account.move' and
self._context.get('active_id')):
move = self.env['account.move'].browse(self._context['active_id'])
date_dt = fields.Date.from_string(move.date) +\
relativedelta(days=1)
date = fields.Date.to_string(date_dt)
return date
date = fields.Date(default=_default_date)

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- When you change the date, it resets the amount via the onchange
So, in the view, the date should be BEFORE the amount -->
<record id="view_account_payment_register_form" model="ir.ui.view">
<field name="model">account.payment.register</field>
<field name="inherit_id" ref="account.view_account_payment_register_form"/>
<field name="arch" type="xml">
<label for="amount" position="before">
<field name="payment_date" position="move"/>
</label>
</field>
</record>
</odoo>

View File

@@ -1,12 +0,0 @@
# Copyright 2015-2020 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
transfer_account_id = fields.Many2one(
related='company_id.transfer_account_id', readonly=False)

View File

@@ -19,12 +19,16 @@ Base Company Extension
|badge1| |badge2| |badge3|
This module adds the following fields on the company:
This module adds the following fields to the ResCompany model:
* Capital Amount
* Legal Type
This is useful to display the legal name of the company in reports.
This is useful to display the legal name of the company in reports
**Table of contents**
.. contents::
:local:
Bug Tracker
===========
@@ -32,7 +36,7 @@ Bug Tracker
Bugs are tracked on `GitHub Issues <https://github.com/akretion/odoo-usability/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/akretion/odoo-usability/issues/new?body=module:%20base_company_extension%0Aversion:%2014.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
`feedback <https://github.com/akretion/odoo-usability/issues/new?body=module:%20base_company_extension%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Do not contact contributors directly about support or help with technical issues.

View File

@@ -1,10 +1,11 @@
# Copyright 2014-2020 Akretion (http://www.akretion.com)
# -*- coding: utf-8 -*-
# Copyright 2014-2019 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Base Company Extension',
'version': '14.0.1.0.0',
'version': '12.0.1.0.0',
'category': 'Partner',
'license': 'AGPL-3',
'summary': 'Adds capital and title on company',

View File

@@ -1,4 +1,4 @@
# Copyright 2014-2020 Akretion (http://www.akretion.com)
# Copyright 2014-2019 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -16,7 +16,7 @@ class ResCompany(models.Model):
def _report_company_legal_name(self):
self.ensure_one()
if self.legal_type:
name = '%s %s' % (self.name, self.legal_type)
name = u'%s %s' % (self.name, self.legal_type)
else:
name = self.name
return name

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2014-2020 Akretion (http://www.akretion.com/)
Copyright 2014-2019 Akretion (http://www.akretion.com/)
@author Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->

View File

@@ -1 +0,0 @@
from . import models

View File

@@ -1,62 +0,0 @@
# Copyright 2020-2021 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Base Dynamic List',
'version': '14.0.1.0.0',
'category': 'Tools',
'license': 'AGPL-3',
'summary': 'Dynamic lists',
'description': """
Base Dynamic List
=================
Very often during an Odoo implementation, we need to add selection fields on a native objet, and we don't want to have a hard-coded selection list (fields.Selection), but a selection list that can be changed by users (Many2one field). For that, the developper needs to add a new object (with just a 'name' and 'sequence' field) with a form/tree view. The goal of this module is to speed-up this process by defining a dynamic list object that already has all the required views.
This module provides several ready-to-go objects:
* simple list : fields *name*, *sequence* and *active*
* translatable list : fields *name* with translate=True, *sequence* and *active*
* code list : fields *code* (unique), *name*, *sequence* and *active*
* translatable code list : fields *code* (unique), *name* with translate=True, *sequence* and *active*
These objects are readable by the employee group. The system group has full rights on it.
To use it, you need to do 2 or 3 things :
1) Add an entry in the domain field and the object you selected:
domain = fields.Selection(selection_add=[('risk.type', "Risk Type")], ondelete={"risk.type": "cascade"})
2) Add the many2one field on your object:
risk_type_id = fields.Many2one(
'dynamic.list', string="Risk Type",
ondelete='restrict', domain=[('domain', '=', 'risk.type')])
3) Optionally, you can add a dedicated action and a menu entry (otherwize, you can use the generic menu entry under *Settings > Technical > Dynamic Lists*:
<record id="dynamic_list_risk_type_action" model="ir.actions.act_window">
<field name="name">Risk Type</field>
<field name="res_model">dynamic.list</field>
<field name="view_mode">tree,form</field>
<field name="domain">[('domain', '=', 'risk.type')]</field>
<field name="context">{'default_domain': 'risk.type'}</field>
</record>
<menuitem id="dynamic_list_risk_type_menu" action="dynamic_list_risk_type_action"
parent="parent_menu_xmlid"/>
Limitation: when you want to have different access rights on these lists depending on the source object, you should prefer to use dedicated objects.
""",
'author': 'Akretion',
'website': 'http://www.akretion.com',
'depends': ['base'],
'data': [
'security/ir.model.access.csv',
'views/dynamic_list.xml',
],
'installable': True,
}

View File

@@ -1 +0,0 @@
from . import dynamic_list

View File

@@ -1,115 +0,0 @@
# Copyright 2020-2021 Akretion France (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models
class DynamicList(models.Model):
_name = 'dynamic.list'
_description = 'Dynamic List (non translatable)'
_order = 'sequence, id'
name = fields.Char(required=True)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
domain = fields.Selection([], string='Domain', required=True, index=True)
_sql_constraint = [(
'domain_name_uniq',
'unique(domain, name)',
'This entry already exists!'
)]
class DynamicListTranslate(models.Model):
_name = 'dynamic.list.translate'
_description = 'Translatable Dynamic List'
_order = 'sequence, id'
name = fields.Char(translate=True, required=True)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
domain = fields.Selection([], string='Domain', required=True, index=True)
_sql_constraint = [(
'domain_name_uniq',
'unique(domain, name)',
'This entry already exists!'
)]
class DynamicListCode(models.Model):
_name = 'dynamic.list.code'
_description = 'Dynamic list with code'
_order = 'sequence, id'
code = fields.Char(required=True)
name = fields.Char(translate=True, required=True)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
domain = fields.Selection([], string='Domain', required=True, index=True)
_sql_constraint = [(
'domain_code_uniq',
'unique(domain, code)',
'This code already exists!'
)]
@api.depends('code', 'name')
def name_get(self):
res = []
for rec in self:
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
return res
@api.model
def name_search(
self, name='', args=None, operator='ilike', limit=80):
if args is None:
args = []
if name and operator == 'ilike':
recs = self.search(
[('code', '=', name)] + args, limit=limit)
if recs:
return recs.name_get()
return super().name_search(
name=name, args=args, operator=operator, limit=limit)
class DynamicListCodeTranslate(models.Model):
_name = 'dynamic.list.code.translate'
_description = 'Translatable dynamic list with code'
_order = 'sequence, id'
code = fields.Char(required=True)
name = fields.Char(translate=True, required=True)
sequence = fields.Integer(default=10)
active = fields.Boolean(default=True)
domain = fields.Selection([], string='Domain', required=True, index=True)
_sql_constraint = [(
'domain_code_uniq',
'unique(domain, code)',
'This code already exists!'
)]
@api.depends('code', 'name')
def name_get(self):
res = []
for rec in self:
res.append((rec.id, '[%s] %s' % (rec.code, rec.name)))
return res
@api.model
def name_search(
self, name='', args=None, operator='ilike', limit=80):
if args is None:
args = []
if name and operator == 'ilike':
recs = self.search(
[('code', '=', name)] + args, limit=limit)
if recs:
return recs.name_get()
return super().name_search(
name=name, args=args, operator=operator, limit=limit)

View File

@@ -1,9 +0,0 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_dynamic_list_read,Read access on dynamic.list to employees,model_dynamic_list,base.group_user,1,0,0,0
access_dynamic_list_full,Full access to dynamic.list to System group,model_dynamic_list,base.group_system,1,1,1,1
access_dynamic_list_translate_read,Read access on dynamic.list.translate to employees,model_dynamic_list_translate,base.group_user,1,0,0,0
access_dynamic_list_translate_full,Full access to dynamic.list.translate to System group,model_dynamic_list_translate,base.group_system,1,1,1,1
access_dynamic_list_code_read,Read access on dynamic.list.code to employees,model_dynamic_list_code,base.group_user,1,0,0,0
access_dynamic_list_code_full,Full access to dynamic.list.code to System group,model_dynamic_list_code,base.group_system,1,1,1,1
access_dynamic_list_code_translate_read,Read access on dynamic.list.code.translate to employees,model_dynamic_list_code_translate,base.group_user,1,0,0,0
access_dynamic_list_code_translate_full,Full access to dynamic.list.code.translate to System group,model_dynamic_list_code_translate,base.group_system,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_dynamic_list_read Read access on dynamic.list to employees model_dynamic_list base.group_user 1 0 0 0
3 access_dynamic_list_full Full access to dynamic.list to System group model_dynamic_list base.group_system 1 1 1 1
4 access_dynamic_list_translate_read Read access on dynamic.list.translate to employees model_dynamic_list_translate base.group_user 1 0 0 0
5 access_dynamic_list_translate_full Full access to dynamic.list.translate to System group model_dynamic_list_translate base.group_system 1 1 1 1
6 access_dynamic_list_code_read Read access on dynamic.list.code to employees model_dynamic_list_code base.group_user 1 0 0 0
7 access_dynamic_list_code_full Full access to dynamic.list.code to System group model_dynamic_list_code base.group_system 1 1 1 1
8 access_dynamic_list_code_translate_read Read access on dynamic.list.code.translate to employees model_dynamic_list_code_translate base.group_user 1 0 0 0
9 access_dynamic_list_code_translate_full Full access to dynamic.list.code.translate to System group model_dynamic_list_code_translate base.group_system 1 1 1 1

View File

@@ -1,220 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2020-2021 Akretion France (http://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<menuitem id="dynamic_list_root_menu" name="Dynamic Lists" parent="base.menu_custom" sequence="100"/>
<record id="dynamic_list_form" model="ir.ui.view">
<field name="model">dynamic.list</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_main_view')"/>
<field name="active" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dynamic_list_tree" model="ir.ui.view">
<field name="model">dynamic.list</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_main_view')"/>
</tree>
</field>
</record>
<record id="dynamic_list_search" model="ir.ui.view">
<field name="model">dynamic.list</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group string="Group By" name="groupby">
<filter name="domain_groupby" string="Domain" context="{'group_by': 'domain'}"/>
</group>
</search>
</field>
</record>
<record id="dynamic_list_action" model="ir.actions.act_window">
<field name="name">Simple List</field>
<field name="res_model">dynamic.list</field>
<field name="view_mode">tree,form</field>
<field name="context">{'dynamic_list_main_view': True, 'search_default_domain_groupby': True}</field>
</record>
<menuitem id="dynamic_list_menu" action="dynamic_list_action" parent="dynamic_list_root_menu" sequence="10"/>
<record id="dynamic_list_translate_form" model="ir.ui.view">
<field name="model">dynamic.list.translate</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_translate_main_view')"/>
<field name="active" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dynamic_list_translate_tree" model="ir.ui.view">
<field name="model">dynamic.list.translate</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_translate_main_view')"/>
</tree>
</field>
</record>
<record id="dynamic_list_translate_search" model="ir.ui.view">
<field name="model">dynamic.list.translate</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group string="Group By" name="groupby">
<filter name="domain_groupby" string="Domain" context="{'group_by': 'domain'}"/>
</group>
</search>
</field>
</record>
<record id="dynamic_list_translate_action" model="ir.actions.act_window">
<field name="name">Translatable Simple List</field>
<field name="res_model">dynamic.list.translate</field>
<field name="view_mode">tree,form</field>
<field name="context">{'dynamic_list_translate_main_view': True, 'search_default_domain_groupby': True}</field>
</record>
<menuitem id="dynamic_list_translate_menu" action="dynamic_list_translate_action" parent="dynamic_list_root_menu" sequence="20"/>
<record id="dynamic_list_code_form" model="ir.ui.view">
<field name="model">dynamic.list.code</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="code"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_code_main_view')"/>
<field name="active" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dynamic_list_code_tree" model="ir.ui.view">
<field name="model">dynamic.list.code</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="code"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_code_main_view')"/>
</tree>
</field>
</record>
<record id="dynamic_list_code_search" model="ir.ui.view">
<field name="model">dynamic.list.code</field>
<field name="arch" type="xml">
<search>
<field name="name" string="Name or Code" filter_domain="['|', ('name', 'ilike', self), ('code', 'ilike', self)]"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<field name="code"/>
<group string="Group By" name="groupby">
<filter name="domain_groupby" string="Domain" context="{'group_by': 'domain'}"/>
</group>
</search>
</field>
</record>
<record id="dynamic_list_code_action" model="ir.actions.act_window">
<field name="name">Code List</field>
<field name="res_model">dynamic.list.code</field>
<field name="view_mode">tree,form</field>
<field name="context">{'dynamic_list_code_main_view': True, 'search_default_domain_groupby': True}</field>
</record>
<menuitem id="dynamic_list_code_menu" action="dynamic_list_code_action" parent="dynamic_list_root_menu" sequence="30"/>
<record id="dynamic_list_code_translate_form" model="ir.ui.view">
<field name="model">dynamic.list.code.translate</field>
<field name="arch" type="xml">
<form>
<sheet>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<group name="main">
<field name="code"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_code_translate_main_view')"/>
<field name="active" invisible="1"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="dynamic_list_code_translate_tree" model="ir.ui.view">
<field name="model">dynamic.list.code.translate</field>
<field name="arch" type="xml">
<tree>
<field name="sequence" widget="handle"/>
<field name="code"/>
<field name="name"/>
<field name="domain" invisible="not context.get('dynamic_list_code_translate_main_view')"/>
</tree>
</field>
</record>
<record id="dynamic_list_code_translate_search" model="ir.ui.view">
<field name="model">dynamic.list.code.translate</field>
<field name="arch" type="xml">
<search>
<field name="name" string="Name or Code" filter_domain="['|', ('name', 'ilike', self), ('code', 'ilike', self)]"/>
<field name="code"/>
<separator/>
<filter string="Archived" name="inactive" domain="[('active', '=', False)]"/>
<group string="Group By" name="groupby">
<filter name="domain_groupby" string="Domain" context="{'group_by': 'domain'}"/>
</group>
</search>
</field>
</record>
<record id="dynamic_list_code_translate_action" model="ir.actions.act_window">
<field name="name">Translatable Code List</field>
<field name="res_model">dynamic.list.code.translate</field>
<field name="view_mode">tree,form</field>
<field name="context">{'dynamic_list_code_translate_main_view': True, 'search_default_domain_groupby': True}</field>
</record>
<menuitem id="dynamic_list_code_translate_menu" action="dynamic_list_code_translate_action" parent="dynamic_list_root_menu" sequence="40"/>
</odoo>

View File

@@ -1 +0,0 @@
from . import models

View File

@@ -1,21 +0,0 @@
# Copyright 2017-2022 Akretion (http://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Mail Sender Bcc',
'version': '14.0.1.0.0',
'category': 'Mail',
'license': 'AGPL-3',
'summary': "Always send a copy of the mail to the sender",
'description': """
Mail Sender Bcc
===============
With this module, when Odoo sends an outgoing email, it adds the sender as Bcc (blind copy) of the email.
""",
'author': 'Akretion',
'website': 'https://github.com/akretion/odoo-usability',
'depends': ['base'],
'installable': True,
}

View File

@@ -1 +0,0 @@
from . import ir_mail_server

View File

@@ -1,27 +0,0 @@
# Copyright 2017-2022 Akretion France
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class IrMailServer(models.Model):
_inherit = 'ir.mail_server'
def build_email(
self, email_from, email_to, subject, body, email_cc=None,
email_bcc=None, reply_to=False, attachments=None,
message_id=None, references=None, object_id=False,
subtype='plain', headers=None,
body_alternative=None, subtype_alternative='plain'):
if email_from:
if email_bcc is None:
email_bcc = [email_from]
elif isinstance(email_bcc, list) and email_from not in email_bcc:
email_bcc.append(email_from)
return super().build_email(
email_from, email_to, subject, body, email_cc=email_cc,
email_bcc=email_bcc, reply_to=reply_to, attachments=attachments,
message_id=message_id, references=references, object_id=object_id,
subtype=subtype, headers=headers,
body_alternative=body_alternative, subtype_alternative=subtype_alternative)

View File

@@ -1,2 +0,0 @@
from . import partner_phone
from .post_install import migrate_to_partner_phone

View File

@@ -1,31 +0,0 @@
# Copyright 2014-2020 Abbaye du Barroux (http://www.barroux.org)
# Copyright 2014-2020 Akretion (http://www.akretion.com>)
# @author: Frère Bernard <informatique@barroux.org>
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
'name': 'Base Partner One2many Phone',
'version': '14.0.1.0.0',
'category': 'Phone',
'license': 'AGPL-3',
'summary': 'One2many link between partners and phone numbers/emails',
'description': """
Base Partner One2many Phone
===========================
With this module, one partner can have several phone numbers and several emails. It adds a new table dedicated to phone numbers and emails and a one2many link between partners and phone numbers. This module keeps compatibility with the native behavior of Odoo on phone numbers and emails.
It has been developped by brother Bernard from Barroux Abbey and Alexis de Lattre from Akretion.
""",
'author': 'Akretion',
'website': 'https://akretion.com/',
'depends': ['contacts', 'base_usability', 'phone_validation'],
'excludes': ['sms'], # because sms introduces big changes in partner form view
'data': [
'partner_phone_view.xml',
'security/ir.model.access.csv',
],
'installable': True,
'post_init_hook': 'migrate_to_partner_phone',
}

View File

@@ -1,202 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partner_one2many_phone
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-29 21:12+0000\n"
"PO-Revision-Date: 2021-10-29 21:12+0000\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: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner
msgid "Contact"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__create_uid
msgid "Created by"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__create_date
msgid "Created on"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__display_name
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__display_name
msgid "Display Name"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__email
msgid "E-Mail"
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid ""
"E-mail field must be empty when type is Primary/Secondary Phone, "
"Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid ""
"E-mail field must have a value when type is Primary E-mail or Secondary "
"E-mail."
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__email
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__email
msgid "Email"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__id
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__id
msgid "ID"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner____last_update
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone____last_update
msgid "Last Modified on"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__write_uid
msgid "Last Updated by"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__write_date
msgid "Last Updated on"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__mobile
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__mobile
msgid "Mobile"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner_phone
msgid "Multiple emails and phones for partners"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__note
msgid "Note"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__phone
msgid "Phone"
msgstr ""
#. module: base_partner_one2many_phone
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_form
msgid "Phone and E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid ""
"Phone field must be empty when type is Primary E-mail or Secondary E-mail."
msgstr ""
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid ""
"Phone field must have a value when type is Primary/Secondary Phone, "
"Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr ""
#. module: base_partner_one2many_phone
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_tree
msgid "Phones and E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.actions.act_window,name:base_partner_one2many_phone.res_partner_phone_action
#: model:ir.ui.menu,name:base_partner_one2many_phone.res_partner_phone_menu
msgid "Phones/E-mails"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__phone_ids
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__phone_ids
msgid "Phones/Emails"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__1_email_primary
msgid "Primary E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__7_fax_primary
msgid "Primary Fax"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__5_mobile_primary
msgid "Primary Mobile"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__3_phone_primary
msgid "Primary Phone"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__partner_id
msgid "Related Partner"
msgstr ""
#. module: base_partner_one2many_phone
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
msgid "Search Phones/E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__2_email_secondary
msgid "Secondary E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__8_fax_secondary
msgid "Secondary Fax"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__6_mobile_secondary
msgid "Secondary Mobile"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__4_phone_secondary
msgid "Secondary Phone"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__type
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
msgid "Type"
msgstr ""

View File

@@ -1,202 +0,0 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * base_partner_one2many_phone
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-29 21:12+0000\n"
"PO-Revision-Date: 2021-10-29 21:12+0000\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: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner
msgid "Contact"
msgstr "Contact"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__create_uid
msgid "Created by"
msgstr "Créé par"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__create_date
msgid "Created on"
msgstr "Créé le"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__display_name
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__display_name
msgid "Display Name"
msgstr "Nom affiché"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__email
msgid "E-Mail"
msgstr "E-Mail"
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid ""
"E-mail field must be empty when type is Primary/Secondary Phone, "
"Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr "Le champ E-mail doit être vide quand le type est Tél. principal/secondaire, Portable principal/secondaire ou Fax principal/secondaire."
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid ""
"E-mail field must have a value when type is Primary E-mail or Secondary "
"E-mail."
msgstr "Le champ E-mail doit avoir une valeur quand le type est E-mail principal ou secondaire."
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__email
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__email
msgid "Email"
msgstr "E-mail"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__id
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__id
msgid "ID"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner____last_update
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone____last_update
msgid "Last Modified on"
msgstr "Dernière modification le"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__write_uid
msgid "Last Updated by"
msgstr "Dernière modification par"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__write_date
msgid "Last Updated on"
msgstr "Dernière modification le"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__mobile
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__mobile
msgid "Mobile"
msgstr "Portable"
#. module: base_partner_one2many_phone
#: model:ir.model,name:base_partner_one2many_phone.model_res_partner_phone
msgid "Multiple emails and phones for partners"
msgstr "Multiples e-mails et téléphones pour les partenaires"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__note
msgid "Note"
msgstr "Note"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__phone
msgid "Phone"
msgstr "Tél."
#. module: base_partner_one2many_phone
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_form
msgid "Phone and E-mail"
msgstr "Tél. et E-mail"
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid ""
"Phone field must be empty when type is Primary E-mail or Secondary E-mail."
msgstr "Le champ Tél. doit être vide quand le type est E-mail principal ou E-mail secondaire."
#. module: base_partner_one2many_phone
#: code:addons/base_partner_one2many_phone/partner_phone.py:0
#, python-format
msgid ""
"Phone field must have a value when type is Primary/Secondary Phone, "
"Primary/Secondary Mobile or Primary/Secondary Fax."
msgstr "Le champ Tél. doit avoir une valeur quand le type est Tél. principal/secondaire, Portable principal/secondaire ou Fax principal/secondaire."
#. module: base_partner_one2many_phone
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_tree
msgid "Phones and E-mail"
msgstr "Téls et E-mail"
#. module: base_partner_one2many_phone
#: model:ir.actions.act_window,name:base_partner_one2many_phone.res_partner_phone_action
#: model:ir.ui.menu,name:base_partner_one2many_phone.res_partner_phone_menu
msgid "Phones/E-mails"
msgstr "Téls/E-mails"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner__phone_ids
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_users__phone_ids
msgid "Phones/Emails"
msgstr "Téls/E-mails"
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__1_email_primary
msgid "Primary E-mail"
msgstr "E-mail principal"
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__7_fax_primary
msgid "Primary Fax"
msgstr "Fax principal"
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__5_mobile_primary
msgid "Primary Mobile"
msgstr "Portable principal"
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__3_phone_primary
msgid "Primary Phone"
msgstr "Tél. principal"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__partner_id
msgid "Related Partner"
msgstr "Partenaire associé"
#. module: base_partner_one2many_phone
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
msgid "Search Phones/E-mail"
msgstr ""
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__2_email_secondary
msgid "Secondary E-mail"
msgstr "E-mail secondaire"
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__8_fax_secondary
msgid "Secondary Fax"
msgstr "Fax secondaire"
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__6_mobile_secondary
msgid "Secondary Mobile"
msgstr "Portable secondaire"
#. module: base_partner_one2many_phone
#: model:ir.model.fields.selection,name:base_partner_one2many_phone.selection__res_partner_phone__type__4_phone_secondary
msgid "Secondary Phone"
msgstr "Tél. secondaire"
#. module: base_partner_one2many_phone
#: model:ir.model.fields,field_description:base_partner_one2many_phone.field_res_partner_phone__type
#: model_terms:ir.ui.view,arch_db:base_partner_one2many_phone.res_partner_phone_search
msgid "Type"
msgstr "Type"

View File

@@ -1,193 +0,0 @@
# Copyright 2014-2020 Abbaye du Barroux (http://www.barroux.org)
# Copyright 2016-2020 Akretion (http://www.akretion.com>)
# @author: Frère Bernard <informatique@barroux.org>
# @author: Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
EMAIL_TYPES = ('1_email_primary', '2_email_secondary')
PHONE_TYPES = ('3_phone_primary', '4_phone_secondary', '5_mobile_primary', '6_mobile_secondary', '7_fax_primary', '8_fax_secondary')
class ResPartnerPhone(models.Model):
_name = 'res.partner.phone'
_order = 'partner_id, type'
_phone_name_sequence = 8
_inherit = ['phone.validation.mixin']
_description = 'Multiple emails and phones for partners'
partner_id = fields.Many2one(
'res.partner', string='Related Partner', index=True, ondelete='cascade')
type = fields.Selection([
('1_email_primary', 'Primary E-mail'),
('2_email_secondary', 'Secondary E-mail'),
('3_phone_primary', 'Primary Phone'),
('4_phone_secondary', 'Secondary Phone'),
('5_mobile_primary', 'Primary Mobile'),
('6_mobile_secondary', 'Secondary Mobile'),
('7_fax_primary', 'Primary Fax'),
('8_fax_secondary', 'Secondary Fax'),
],
string='Type', required=True, index=True)
phone = fields.Char(string='Phone')
email = fields.Char(string='E-Mail')
note = fields.Char('Note')
@api.onchange('type')
def type_change(self):
if self.type:
if self.type in EMAIL_TYPES:
self.phone = False
elif self.type in PHONE_TYPES:
self.email = False
@api.onchange('phone', 'partner_id')
def _onchange_phone_validation(self):
if self.phone:
self.phone = self.phone_format(self.phone, country=self.partner_id.country_id)
@api.constrains('type', 'phone', 'email')
def _check_partner_phone(self):
for rec in self:
if rec.type in EMAIL_TYPES:
if not rec.email:
raise ValidationError(_(
"E-mail field must have a value when type is Primary E-mail or Secondary E-mail."))
if rec.phone:
raise ValidationError(_(
"Phone field must be empty when type is Primary E-mail or Secondary E-mail."))
elif rec.type in PHONE_TYPES:
if not rec.phone:
raise ValidationError(_(
"Phone field must have a value when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."))
if rec.email:
raise ValidationError(_(
"E-mail field must be empty when type is Primary/Secondary Phone, Primary/Secondary Mobile or Primary/Secondary Fax."))
def name_get(self):
res = []
for pphone in self:
if pphone.partner_id:
if self._context.get('callerid'):
name = pphone.partner_id.display_name
else:
name = u'%s (%s)' % (pphone.phone, pphone.partner_id.name)
else:
name = pphone.phone
res.append((pphone.id, name))
return res
def init(self):
self._cr.execute('''
CREATE UNIQUE INDEX IF NOT EXISTS single_email_primary
ON res_partner_phone (partner_id, type)
WHERE (type='1_email_primary')
''')
self._cr.execute('''
CREATE UNIQUE INDEX IF NOT EXISTS single_phone_primary
ON res_partner_phone (partner_id, type)
WHERE (type='3_phone_primary')
''')
self._cr.execute('''
CREATE UNIQUE INDEX IF NOT EXISTS single_mobile_primary
ON res_partner_phone (partner_id, type)
WHERE (type='5_mobile_primary')
''')
self._cr.execute('''
CREATE UNIQUE INDEX IF NOT EXISTS single_fax_primary
ON res_partner_phone (partner_id, type)
WHERE (type='7_fax_primary')
''')
class ResPartner(models.Model):
_inherit = 'res.partner'
# in v10, we are supposed to have in DB E.164 format
# with the current implementation, we have:
# in res.partner : PhoneNumberFormat.INTERNATIONAL
# in res.partner.phone : E.164
# It is not good, but it is not a big bug and it's complex to fix
# so let's let it like that. In v12, we store in
# PhoneNumberFormat.INTERNATIONAL, so this bug is kind of an anticipation
# for the future :)
phone_ids = fields.One2many(
'res.partner.phone', 'partner_id', string='Phones/Emails')
phone = fields.Char(
compute='_compute_partner_phone',
store=True, readonly=True, compute_sudo=True)
mobile = fields.Char(
compute='_compute_partner_phone',
store=True, readonly=True, compute_sudo=True)
email = fields.Char(
compute='_compute_partner_phone',
store=True, readonly=True, compute_sudo=True)
@api.depends('phone_ids.phone', 'phone_ids.type', 'phone_ids.email')
def _compute_partner_phone(self):
for partner in self:
phone = mobile = email = False
for pphone in partner.phone_ids:
if pphone.type == '1_email_primary' and pphone.email:
email = pphone.email
elif pphone.phone:
if pphone.type == '5_mobile_primary':
mobile = pphone.phone
elif pphone.type == '3_phone_primary':
phone = pphone.phone
partner.phone = phone
partner.mobile = mobile
partner.email = email
def _update_create_vals(
self, vals, type, partner_field, partner_phone_field):
if vals.get(partner_field):
vals['phone_ids'].append(
(0, 0, {'type': type, partner_phone_field: vals[partner_field]}))
@api.model
def create(self, vals):
if 'phone_ids' not in vals:
vals['phone_ids'] = []
self._update_create_vals(vals, '1_email_primary', 'email', 'email')
self._update_create_vals(vals, '3_phone_primary', 'phone', 'phone')
self._update_create_vals(vals, '5_mobile_primary', 'mobile', 'phone')
# self._update_create_vals(vals, '7_fax_primary', 'fax', 'phone')
return super().create(vals)
def _update_write_vals(
self, vals, type, partner_field, partner_phone_field):
self.ensure_one()
rppo = self.env['res.partner.phone']
if partner_field in vals:
pphone = rppo.search([
('partner_id', '=', self.id),
('type', '=', type)], limit=1)
if vals[partner_field]:
if pphone:
vals['phone_ids'].append((1, pphone.id, {
partner_phone_field: vals[partner_field]}))
else:
vals['phone_ids'].append((0, 0, {
'type': type,
partner_phone_field: vals[partner_field],
}))
else:
if pphone:
vals['phone_ids'].append((2, pphone.id))
def write(self, vals):
if 'phone_ids' not in vals:
for rec in self:
vals['phone_ids'] = []
rec._update_write_vals(vals, '1_email_primary', 'email', 'email')
rec._update_write_vals(vals, '3_phone_primary', 'phone', 'phone')
rec._update_write_vals(vals, '5_mobile_primary', 'mobile', 'phone')
rec._update_write_vals(vals, '7_fax_primary', 'fax', 'phone')
super(ResPartner, rec).write(vals)
return True
else:
return super().write(vals)

View File

@@ -1,167 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2014-2020 Abbaye du Barroux (http://www.barroux.org)
Copyright 2016-2020 Akretion (http://www.akretion.com>)
@author: Frère Bernard <informatique@barroux.org>
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<!-- Partner phones -->
<record id="res_partner_phone_tree" model="ir.ui.view">
<field name="name">res.partner.phone.tree</field>
<field name="model">res.partner.phone</field>
<field name="arch" type="xml">
<tree editable="bottom">
<field name="partner_id" invisible="not context.get('partner_phone_main_view')"/>
<field name="type"/>
<field name="phone" widget="phone" options="{'enable_sms': false}" attrs="{'required': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'readonly': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
<field name="email" widget="email" attrs="{'readonly': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'required': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
<field name="note"/>
</tree>
</field>
</record>
<record id="res_partner_phone_form" model="ir.ui.view">
<field name="name">res.partner.phone.form</field>
<field name="model">res.partner.phone</field>
<field name="arch" type="xml">
<form>
<group name="main">
<field name="partner_id" invisible="not context.get('partner_phone_main_view')"/>
<field name="type"/>
<field name="phone" widget="phone" options="{'enable_sms': false}" attrs="{'required': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'invisible': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
<field name="email" widget="email" attrs="{'invisible': [('type', 'not in', ('1_email_primary', '2_email_secondary'))], 'required': [('type', 'in', ('1_email_primary', '2_email_secondary'))]}"/>
<field name="note"/>
</group>
</form>
</field>
</record>
<record id="res_partner_phone_search" model="ir.ui.view">
<field name="name">res.partner.phone.search</field>
<field name="model">res.partner.phone</field>
<field name="arch" type="xml">
<search>
<field name="phone" />
<field name="email" />
<group name="groupby">
<filter name="type_groupby" string="Type" context="{'group_by': 'type'}"/>
</group>
</search>
</field>
</record>
<record id="res_partner_phone_action" model="ir.actions.act_window">
<field name="name">Phones/E-mails</field>
<field name="res_model">res.partner.phone</field>
<field name="view_mode">tree</field>
<field name="context">{'partner_phone_main_view': True}</field>
</record>
<menuitem id="res_partner_phone_menu" action="res_partner_phone_action"
parent="contacts.menu_contacts" sequence="10"/>
<record id="contacts.res_partner_menu_config" model="ir.ui.menu">
<field name="sequence">20</field>
</record>
<!-- PARTNER views -->
<record id="view_partner_form" model="ir.ui.view">
<field name="name">add.phone_ids.on.partner.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="mail.res_partner_view_form_inherit_mail"/>
<!-- This module depends on contacts which depends on mail
and the mail module replaces the email field -->
<field name="arch" type="xml">
<field name="phone" position="after">
<field name="phone_ids" nolabel="1" colspan="2"/>
</field>
<field name="phone" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="mobile" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<label for="email" position="attributes">
<attribute name="invisible">1</attribute>
</label>
<xpath expr="//field[@name='email']/.." position="attributes">
<attribute name="invisible">1</attribute>
</xpath>
<!-- I can't display phone_ids in the Contacts
because there is a very strange thing in the web client: if
you have a res.partner.phone on one of the fields,
it will send to write {'child_ids': [1, ID_child, {'phone_ids': [[5], [4, id_phone_child]]}]}
=> it will delete res.partner.phone and then try to re-create it,
which triggers the message 'Record does not exist or has been deleted.'
<xpath expr="//field[@name='child_ids']/form//field[@name='phone']" position="after">
<field name="phone_ids" nolabel="1" colspan="2" widget="many2many_tags"/>
</xpath>
-->
<xpath expr="//field[@name='child_ids']/form//field[@name='phone']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='child_ids']/form//field[@name='mobile']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
<xpath expr="//field[@name='child_ids']/form//field[@name='email']" position="attributes">
<attribute name="readonly">1</attribute>
</xpath>
</field>
</record>
<record id="view_partner_simple_form" model="ir.ui.view">
<field name="name">add.phone_ids.on.res.partner.simplified.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_simple_form"/>
<field name="arch" type="xml">
<field name="phone" position="after">
<field name="phone_ids" nolabel="1" colspan="2"/>
</field>
<field name="phone" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="mobile" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="email" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record id="res_partner_view_form_private" model="ir.ui.view">
<field name="name">add.phone_ids.on.res.partner.private.form</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.res_partner_view_form_private"/>
<field name="arch" type="xml">
<field name="phone" position="after">
<field name="phone_ids" nolabel="1" colspan="2"/>
</field>
<field name="phone" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="mobile" position="attributes">
<attribute name="invisible">1</attribute>
</field>
<field name="email" position="attributes">
<attribute name="invisible">1</attribute>
</field>
</field>
</record>
<record id="view_res_partner_filter" model="ir.ui.view">
<field name="name">phone.one2many.res.partner.search</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base_usability.view_res_partner_filter"/>
<field name="arch" type="xml">
<field name="name" position="attributes">
<attribute name="filter_domain">['|', '|', ('display_name', 'ilike', self), ('ref', '=ilike', self + '%'), ('phone_ids.email', 'ilike', self)]</attribute>
</field>
</field>
</record>
</odoo>

View File

@@ -1,49 +0,0 @@
# Copyright 2017-2020 Akretion France (http://www.akretion.com/)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, SUPERUSER_ID
import logging
logger = logging.getLogger(__name__)
def create_partner_phone(cr, phone_field, phone_type):
cr.execute(
'SELECT id, ' + phone_field + ' FROM res_partner WHERE ' +
phone_field + ' IS NOT null AND ' + phone_field + "!= ''")
to_create = []
for partner in cr.fetchall():
to_create.append({
'partner_id': partner[0],
'type': phone_type,
'phone': partner[1],
})
return to_create
def create_partner_email(cr):
cr.execute(
"SELECT id, email FROM res_partner WHERE email IS NOT null AND email != ''")
to_create = []
for partner in cr.fetchall():
to_create.append({
'partner_id': partner[0],
'type': '1_email_primary',
'email': partner[1],
})
return to_create
def migrate_to_partner_phone(cr, registry):
logger.info('start data migration for one2many_phone')
with api.Environment.manage():
env = api.Environment(cr, SUPERUSER_ID, {})
rppo = env['res.partner.phone']
to_create = []
to_create += create_partner_phone(cr, 'phone', '3_phone_primary')
to_create += create_partner_phone(cr, 'mobile', '5_mobile_primary')
to_create += create_partner_email(cr)
# I need to create all at the end for invalidation purposes
rppo.create(to_create)
logger.info('end data migration for one2many_phone')
return

Some files were not shown because too many files have changed in this diff Show More