[MIG] account_usability_akretion to v18

Move code from account_usability_akretion to base_usability_akretion
This commit is contained in:
Alexis de Lattre
2024-12-31 01:02:50 +01:00
parent 8e5d3b8a74
commit bdf4a527de
40 changed files with 298 additions and 567 deletions

View File

@@ -1,3 +1,3 @@
from . import models
from . import wizard
from .hooks import post_init_hook
from . import wizards
# from .hooks import post_init_hook

View File

@@ -1,10 +1,10 @@
# Copyright 2015-2022 Akretion (http://www.akretion.com)
# Copyright 2015-2024 Akretion France (https://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': '16.0.1.0.0',
'version': '18.0.1.0.0',
'category': 'Accounting & Finance',
'license': 'AGPL-3',
'summary': 'Small usability enhancements in account module',
@@ -12,7 +12,7 @@
'website': 'https://github.com/akretion/odoo-usability',
'depends': [
'account',
'base_usability', # needed only to access base_usability.group_nobody
'base_usability_akretion', # needed only to access base_usability.group_nobody
],
'data': [
'views/account_account.xml',
@@ -21,21 +21,21 @@
'views/account_invoice_report.xml',
'views/account_journal.xml',
'views/account_move.xml',
'views/account_move_line.xml',
'views/account_analytic_line.xml',
'views/account_menu.xml',
'views/account_tax.xml',
# 'views/product.xml', # TODO
'views/res_company.xml',
'views/account_report.xml',
'wizard/account_invoice_mark_sent_view.xml',
'wizard/account_group_generate_view.xml',
'wizard/account_payment_register_views.xml',
'wizard/account_move_reversal.xml',
# 'views/account_report.xml',
'wizards/account_invoice_mark_sent_view.xml',
# 'wizards/account_group_generate_view.xml',
'wizards/account_move_reversal.xml',
'security/ir.model.access.csv',
# 'report/invoice_report.xml', # TODO
"views/res_partner.xml",
],
# 'qweb': ['static/src/xml/account_payment.xml'],
'installable': False,
'installable': True,
# "post_init_hook": "post_init_hook",
}

View File

@@ -2,8 +2,8 @@
# @author Sébastien BEAU <sebastien.beau@akretion.com>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import SUPERUSER_ID, api
# from odoo import SUPERUSER_ID, api
def post_init_hook(cr, registry):
env = api.Environment(cr, SUPERUSER_ID, {})
env["account.move.line"].update_matching_number()
# def post_init_hook(cr, registry):
# env = api.Environment(cr, SUPERUSER_ID, {})
# env["account.move.line"].update_matching_number()

View File

@@ -1,9 +0,0 @@
# Copyright 2020 ACSONE SA/NV
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import SUPERUSER_ID, api
def migrate(cr, version):
env = api.Environment(cr, SUPERUSER_ID, {})
env["account.move.line"].update_matching_number()

View File

@@ -1,12 +1,10 @@
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_move_line
from . import account_partial_reconcile
from . import res_partner
from . import res_company
#from . import product
from . import account_invoice_report
from . import res_partner_bank

View File

@@ -1,19 +0,0 @@
# Copyright 2015-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, models
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()

View File

@@ -1,21 +1,20 @@
# Copyright 2015-2022 Akretion (http://www.akretion.com)
# Copyright 2015-2024 Akretion France (https://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 import api, models
class AccountAnalyticAccount(models.Model):
_inherit = 'account.analytic.account'
def name_get(self):
@api.depends_context('analytic_account_show_code_only')
def _compute_display_name(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
for rec in self:
rec.display_name = rec.code or rec.name
else:
return super().name_get()
return super()._compute_display_name()
_sql_constraints = [(
'code_company_unique',

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,31 +1,15 @@
# Copyright 2015-2022 Akretion (http://www.akretion.com)
# Copyright 2015-2024 Akretion France (https://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
from odoo import models
class AccountIncoterms(models.Model):
_inherit = 'account.incoterms'
_rec_names_search = ["name", "code"]
_sql_constraints = [(
'code_unique',
'unique(code)',
'This incoterm 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=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,8 +1,9 @@
# Copyright 2022 Akretion (http://www.akretion.com)
# Copyright 2022-2024 Akretion France (https://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 SQL
class AccountInvoiceReport(models.Model):
@@ -12,6 +13,6 @@ class AccountInvoiceReport(models.Model):
@api.model
def _select(self):
res = super()._select()
res += ", COALESCE(partner.industry_id, commercial_partner.industry_id) AS industry_id"
return res
return SQL(
"%s, COALESCE(partner.industry_id, commercial_partner.industry_id) AS industry_id",
super()._select())

View File

@@ -1,4 +1,4 @@
# Copyright 2015-2022 Akretion (http://www.akretion.com)
# Copyright 2015-2024 Akretion France (https://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -17,41 +17,34 @@ class AccountJournal(models.Model):
"the start/end balance and you regularly check the accounting balance "
"of the bank account vs the amount of your bank account."
)
# 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)
@api.depends(
'name', 'currency_id', 'company_id', 'company_id.currency_id', 'code')
def name_get(self):
res = []
@api.depends('name', 'currency_id', 'company_id', 'code')
@api.depends_context('journal_show_code_only')
def _compute_display_name(self):
if self._context.get('journal_show_code_only'):
for journal in self:
res.append((journal.id, journal.code))
return res
journal.display_name = journal.code
else:
for journal in self:
name = "[%s] %s" % (journal.code, journal.name)
name = f"[{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
name = f"{name} ({journal.currency_id.name})"
journal.display_name = name
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
# 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

View File

@@ -1,17 +1,14 @@
# Copyright 2015-2022 Akretion (http://www.akretion.com)
# Copyright 2015-2024 Akretion France (https://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import timedelta
from collections import defaultdict
import logging
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.osv import expression
from odoo.tools import float_is_zero
from odoo.tools.misc import format_date
from odoo.tools.safe_eval import safe_eval, time
_logger = logging.getLogger(__name__)
@@ -19,9 +16,6 @@ _logger = logging.getLogger(__name__)
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)]})
invoice_date_due = fields.Date(tracking=True)
invoice_payment_term_id = fields.Many2one(tracking=True)
journal_id = fields.Many2one(tracking=True)
@@ -38,36 +32,34 @@ class AccountMove(models.Model):
compute="_compute_sales_dates",
help="This information appear on invoice qweb report "
"(you may use it for your own report)")
# There is a native "blocked" field (bool) on account.move.line
# We want to have that field on invoices to improve usability
# while keeping compatibility with the standard Odoo datamodel
blocked = fields.Boolean(
compute="_compute_blocked",
inverse="_inverse_blocked",
store=True,
string="Dispute",
tracking=True,
)
# The native "blocked" field (bool) on account.move.line has been removed in v18
# blocked = fields.Boolean(
# compute="_compute_blocked",
# inverse="_inverse_blocked",
# store=True,
# string="Dispute",
# tracking=True,
# )
# Field search_account_id is just for search view
search_account_id = fields.Many2one(related='line_ids.account_id')
@api.depends("line_ids", "line_ids.blocked")
def _compute_blocked(self):
for move in self:
move.blocked = any(
[
l.blocked
for l in move.line_ids
if l.account_id.account_type in ("liability_payable", "asset_receivable")
]
)
# @api.depends("line_ids", "line_ids.blocked")
# def _compute_blocked(self):
# for move in self:
# move.blocked = any(
# [
# l.blocked
# for l in move.line_ids
# if l.account_id.account_type in ("liability_payable", "asset_receivable")
# ]
# )
def _inverse_blocked(self):
for move in self:
for line in move.line_ids.filtered(
lambda l: l.account_id.account_type in ("liability_payable", "asset_receivable")
):
line.blocked = move.blocked
# def _inverse_blocked(self):
# for move in self:
# for line in move.line_ids.filtered(
# lambda l: l.account_id.account_type in ("liability_payable", "asset_receivable")
# ):
# line.blocked = move.blocked
def _compute_has_discount(self):
prec = self.env['decimal.precision'].precision_get('Discount')
@@ -103,35 +95,6 @@ class AccountMove(models.Model):
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
def _reverse_moves(self, default_values_list=None, cancel=False):
reverse_moves = super()._reverse_moves(
default_values_list=default_values_list, cancel=cancel)
# In the simple scenario 1 invoice -> 1 refund, we add a message in the chatter
# of the invoice and in the chatter of the refund
if len(self) == 1 and len(reverse_moves) == 1:
self.message_post(body=_("A reverse journal entry <a href=# data-oe-model=account.move data-oe-id=%d>%s</a> has been generated.") % (reverse_moves.id, reverse_moves.display_name))
reverse_moves.message_post(body=_("This journal entry has been generated as the reverse of <a href=# data-oe-model=account.move data-oe-id=%d>%s</a>.") % (self.id, self.display_name))
return reverse_moves
def delete_lines_qty_zero(self):
lines = self.env['account.move.line'].search([
('display_type', '=', 'product'),
@@ -204,94 +167,27 @@ class AccountMove(models.Model):
])
move.suitable_journal_ids = self.env['account.journal'].search(domain)
def button_draft(self):
# There is no more attachment by default on invoice reports...
# TODO check what's the editor strategy on this
# def button_draft(self):
# Delete attached pdf invoice
for move in self.filtered(lambda x: x.move_type in ('out_invoice', 'out_refund')):
for report_xmlid in ('account.account_invoices', 'account.account_invoices_without_payment'):
report = self.env.ref(report_xmlid)
attach = report.retrieve_attachment(move)
if attach:
attach.unlink()
super().button_draft()
# for move in self.filtered(lambda x: x.move_type in ('out_invoice', 'out_refund')):
# for report_xmlid in ('account.account_invoices', 'account.account_invoices_without_payment'):
# report = self.env.ref(report_xmlid)
# attach = report.retrieve_attachment(move)
# if attach:
# attach.unlink()
# super().button_draft()
def _get_accounting_date(self, invoice_date, has_tax):
def _get_accounting_date(self, invoice_date, has_tax, lock_dates=None):
# 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 = super()._get_accounting_date(invoice_date, has_tax, lock_dates=lock_dates)
lock_dates = lock_dates or self._get_violated_lock_dates(invoice_date, has_tax)
if self.is_purchase_document(include_receipts=True) and invoice_date:
if lock_dates:
date = max([entry[0] for entry in lock_dates]) + timedelta(1)
else:
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')
# 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
def update_matching_number(self):
records = self.search([("matching_number", "=", "P")])
_logger.info(f"Update partial reconcile number for {len(records)} lines")
records._compute_matching_number()
# def _compute_matching_number(self):
# TODO maybe it will be better to have the same maching_number for
# all partial so it will be easier to group by
# super()._compute_matching_number()
# for record in self:
# if record.matching_number == "P":
# record.matching_number = ", ".join([
# "a%d" % pr.id
# for pr in record.matched_debit_ids + record.matched_credit_ids
# ])
def _compute_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()._compute_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

@@ -0,0 +1,70 @@
# Copyright 2015-2024 Akretion France (https://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
import logging
_logger = logging.getLogger(__name__)
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"
# for optional display in list 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,list',
})
return action
# def update_matching_number(self):
# records = self.search([("matching_number", "=", "P")])
# _logger.info(f"Update partial reconcile number for {len(records)} lines")
# records._compute_matching_number()
# def _compute_matching_number(self):
# TODO maybe it will be better to have the same maching_number for
# all partial so it will be easier to group by
# super()._compute_matching_number()
# for record in self:
# if record.matching_number == "P":
# record.matching_number = ", ".join([
# "a%d" % pr.id
# for pr in record.matched_debit_ids + record.matched_credit_ids
# ])
def _compute_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()._compute_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

@@ -3,21 +3,21 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
from odoo.tools.misc import formatLang
# from odoo.tools.misc import formatLang
class AccountPartialReconcile(models.Model):
_inherit = "account.partial.reconcile"
_rec_name = "id"
# _rec_name = "id"
def name_get(self):
res = []
for rec in self:
# 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
# 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

@@ -4,6 +4,9 @@
from odoo import api, fields, models, _
# CODE DISABLED FOR THE MOMENT. I need to decide if I want to drop it
# because native code is enough and if I want to re-enable it
class ProductTemplate(models.Model):
_inherit = 'product.template'

View File

@@ -13,7 +13,7 @@ class ResCompany(models.Model):
# 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"
# So I decided to have our own field "static_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_'

View File

@@ -1,4 +1,4 @@
# Copyright 2017-2022 Akretion France (https://akretion.com/)
# Copyright 2017-2024 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).

View File

@@ -1,21 +0,0 @@
# Copyright 2015-2022 Akretion France (http://www.akretion.com/)
# @author: Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models
class ResPartnerBank(models.Model):
_inherit = 'res.partner.bank'
def name_get(self):
res = []
for acc in self:
name = acc.acc_number
if acc.currency_id:
name = "%s (%s)" % (name, acc.currency_id.name)
if acc.bank_id.name:
name = "%s - %s" % (name, acc.bank_id.name)
res += [(acc.id, name)]
return res

View File

@@ -1,3 +1,2 @@
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
access_account_group_generate_full Full access on account.group.generate model_account_group_generate account.group_account_manager 1 1 1 1
2 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,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2022 Akretion France (http://www.akretion.com/)
Copyright 2015-2024 Akretion France (https://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -14,7 +14,7 @@
<field name="inherit_id" ref="account.view_account_form"/>
<field name="arch" type="xml">
<field name="deprecated" position="before">
<field name="reconcile" attrs="{'invisible': ['|', ('account_type', 'in', ('asset_cash', 'liability_credit_card')), ('internal_group', '=', 'off_balance')]}" widget="boolean_toggle"/>
<field name="reconcile" invisible="account_type in ('asset_cash', 'liability_credit_card', 'off_balance')" widget="boolean_toggle"/>
</field>
</field>
</record>
@@ -28,9 +28,6 @@
<field name="name" position="after">
<field name="code" filter_domain="[('code', '=like', self + '%')]" string="Code"/>
</field>
<filter name="accounttype" position="after">
<filter name="group_groupby" string="Group" context="{'group_by': 'group_id'}"/>
</filter>
</field>
</record>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2024 Akretion France (http://www.akretion.com/)
Copyright 2024 Akretion France (https://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,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021-2022 Akretion France (http://www.akretion.com/)
Copyright 2021-2024 Akretion France (https://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,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2018-2024 Akretion (http://www.akretion.com/)
Copyright 2018-2024 Akretion (https://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -15,7 +15,6 @@
<field name="arch" type="xml">
<field name="partner_id" position="after">
<field name="commercial_partner_id" optional="hide"/>
<field name="country_id" optional="hide"/>
<field name="industry_id" optional="hide"/>
<field name="fiscal_position_id" optional="hide"/>
</field>
@@ -41,6 +40,7 @@
</field>
</record>
<!-- pivot in first position instead of graph -->
<record id="account.action_account_invoice_report_all_supp" model="ir.actions.act_window">
<field name="view_mode">pivot,graph</field>
</record>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2022 Akretion France (http://www.akretion.com/)
Copyright 2015-2024 Akretion France (https://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -13,30 +13,13 @@
<field name="inherit_id" ref="account.view_account_journal_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='account_control_ids']/.." position="after">
<group name="usability" string="Misc" attrs="{'invisible': [('type', '!=', 'bank')]}">
<group name="usability" string="Misc" invisible="type != 'bank'">
<field name="hide_bank_statement_balance" groups="account.group_account_readonly"/>
</group>
</xpath>
<xpath expr="//field[@name='inbound_payment_method_line_ids']/tree/field[@name='payment_account_id']" position="attributes">
<attribute name="optional">show</attribute>
</xpath>
<xpath expr="//field[@name='outbound_payment_method_line_ids']/tree/field[@name='payment_account_id']" position="attributes">
<attribute name="optional">show</attribute>
</xpath>
<!--
<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>
<!-- TODO
<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>
@@ -48,9 +31,10 @@
<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>
</t> -->
</field>
</record>
-->

View File

@@ -1,13 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2022 Akretion France (http://www.akretion.com/)
Copyright 2015-2024 Akretion France (https://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"
<!-- Duplicate the menu "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"/>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2022 Akretion France (http://www.akretion.com/)
Copyright 2015-2024 Akretion France (https://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -12,37 +12,30 @@
<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 id="account_invoice_payment_btn" 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 name="%(account.account_invoices)d" type="action" string="Print" invisible="move_type not in ('out_invoice', 'out_refund')"/>
</button>
<button name="preview_invoice" position="attributes">
<attribute name="attrs">{}</attribute>
<attribute name="invisible">1</attribute>
</button>
<!-- move sent field and make it visible -->
<!-- move field is_move_sent 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 name="is_move_sent" invisible="move_type not in ('out_invoice', 'out_refund')"/>
</field>
<xpath expr="//field[@name='line_ids']/tree/field[@name='tax_tag_ids']" position="after">
<xpath expr="//field[@name='line_ids']/list/field[@name='tax_tag_ids']" position="after">
<field name="matching_number" optional="show"/>
</xpath>
<xpath expr="//field[@name='invoice_line_ids']/tree/field[@name='product_id']" position="after">
<xpath expr="//field[@name='invoice_line_ids']/list/field[@name='product_id']" position="after">
<field name="product_barcode" optional="hide"/>
</xpath>
<!--
<field name="invoice_source_email" position="after">
<field name="blocked"/>
</field>
@@ -52,15 +45,15 @@
attrs="{'invisible': ['|', ('move_type', 'not in', ('in_invoice', 'in_refund', 'out_invoice', 'out_refund')), ('blocked', '=', False)]}">
This <field name="move_type"/> is marked as <b>disputed</b>.
</div>
</div>
<xpath expr="//button[@name='open_duplicated_ref_bill_view']/.." position="attributes">
</div> -->
<xpath expr="//field[@name='duplicated_ref_ids']/.." position="attributes">
<!-- show duplicate warning not only in draft state, but also in posted state -->
<attribute name="attrs">{'invisible': ['|', ('state', '=', 'cancel'), ('duplicated_ref_ids', '=', [])]}</attribute>
<attribute name="invisible">not duplicated_ref_ids</attribute>
</xpath>
<button name="button_cancel" attrs="{'invisible' : ['|', '|', ('id', '=', False), ('state', '!=', 'draft'),('move_type', '!=', 'entry')]}" position="attributes">
<button name="button_cancel" invisible="not id or state != 'draft' or move_type != 'entry'" position="attributes">
<attribute name="confirm">Are you sure you want to cancel this journal entry?</attribute>
</button>
<button name="button_cancel" attrs="{'invisible' : ['|', '|', ('id', '=', False), ('state', '!=', 'draft'),('move_type', '==', 'entry')]}" position="attributes">
<button name="button_cancel" invisible="not id or state != 'draft' or move_type == 'entry'" position="attributes">
<attribute name="confirm">Are you sure you want to cancel this invoice?</attribute>
</button>
</field>
@@ -71,6 +64,7 @@
<field name="inherit_id" ref="account.view_invoice_tree"/>
<field name="arch" type="xml">
<field name="amount_residual_signed" position="attributes">
<!-- switch from hide to show -->
<attribute name="optional">show</attribute>
</field>
</field>
@@ -82,15 +76,11 @@
<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)]"/>
<separator/>
<filter name="dispute" string="Dispute" domain="[('blocked', '=', True)]"/>
<!-- <filter name="dispute" string="Dispute" domain="[('blocked', '=', True)]"/> -->
</filter>
<filter name="salesperson" position="before">
<filter name="partner" position="before">
<filter name="commercial_partner_groupby" string="Commercial Partner" context="{'group_by': 'commercial_partner_id'}"/>
</filter>
<filter name="status" position="after">
@@ -109,70 +99,5 @@
</field>
</record>
<record id="view_move_line_form" model="ir.ui.view">
<field name="model">account.move.line</field>
<field name="inherit_id" ref="account.view_move_line_form"/>
<field name="arch" type="xml">
<!-- The field 'blocked' is alone in it's block
We don't want to display an empty block, so we put the attrs on the group
The drawback of this is that, if someone added a field in that group,
he won't see the field when internal_type is not payable/receivable -->
<xpath expr="//field[@name='blocked']/.." position="attributes">
<attribute name="attrs">{'invisible': [('account_type', 'not in', ('liability_payable', 'asset_receivable'))]}</attribute>
</xpath>
<field name="account_id" position="after">
<field name="account_type" invisible="1"/>
</field>
</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="analytic_distribution" position="after">
<button title="View Journal Entry Form" type="object" name="show_account_move_form" icon="fa-arrow-right"/>
</field>
<!-- balance is already present
<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">
<field name="partner_id" position="after">
<field name="matching_number" />
<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="[('account_id.reconcile', '=', True), ('full_reconcile_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">Label, Reference, Account or Partner</attribute>
</field>
<field name="name" position="before">
<field name="move_id" position="move"/>
</field>
<field name="partner_id" position="attributes">
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
</field>
</field>
</record>
<!-- Inherit action called from button of account.account form view
Make it similar to standard "Journal Items" menu account.action_account_moves_all_a -->
<record id="account.action_move_line_select" model="ir.actions.act_window">
<field name="domain">[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="account.view_move_line_tree"/>
<field name="view_mode">tree,pivot,graph,kanban</field>
</record>
</odoo>

View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2024 Akretion France (https://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_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">
<list position="inside">
<button title="View Journal Entry Form" type="object" name="show_account_move_form" icon="fa-arrow-right"/>
</list>
</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="matching_number" />
<field name="debit" filter_domain="['|', ('debit', '=', self), ('credit', '=', self)]" string="Debit or Credit"/>
</field>
<filter name="reconcilable_account" position="before">
<filter name="reconciled" string="Fully Reconciled" domain="[('account_id.reconcile', '=', True), ('full_reconcile_id', '!=', False)]"/>
</filter>
<filter name="reconcilable_account" position="attributes">
<attribute name="string">Unreconciled or Partially Reconciled</attribute>
</filter>
<field name="name" position="attributes">
<attribute name="string">Label, Reference, Account or Partner</attribute>
</field>
<field name="partner_id" position="attributes">
<attribute name="domain">['|', ('parent_id', '=', False), ('is_company', '=', True)]</attribute>
</field>
</field>
</record>
<!-- Inherit action called from button of account.account form view
Make it similar to standard "Journal Items" menu account.action_account_moves_all_a -->
<record id="account.action_move_line_select" model="ir.actions.act_window">
<field name="domain">[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="account.view_move_line_tree"/>
<field name="view_mode">list,pivot,graph,kanban</field>
</record>
</odoo>

View File

@@ -7,6 +7,10 @@
<odoo>
<!-- in v18, attachments are disabled by default
TODO see what's the editor idea about it
in the meantime, this field is disabled in manifest -->
<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>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2015-2022 Akretion France (http://www.akretion.com/)
Copyright 2015-2024 Akretion France (https://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,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021-2022 Akretion (http://www.akretion.com/)
Copyright 2021-2024 Akretion (https://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,18 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2014-2024 Akretion (http://www.akretion.com/)
Copyright 2014-2024 Akretion (https://www.akretion.com/)
@author: Mourad EL HADJ MIMOUNE <mourad.elhadj.mimoune@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
<odoo>
<record id="view_partner_simple_form" model="ir.ui.view">
<field name="name">base_usability.title.on.partner.simplified.form</field>
<record id="view_partner_property_form" model="ir.ui.view">
<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']//field[@name='acc_number']" position="after">
<xpath expr="//field[@name='bank_ids']/list/field[@name='acc_number']" position="after">
<field name="currency_id" optional="hide"/>
</xpath>
</field>

View File

@@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2021-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>
<!-- 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,3 +1,3 @@
from . import account_invoice_mark_sent
from . import account_move_reversal
from . import account_group_generate
#from . import account_group_generate

View File

@@ -1,4 +1,4 @@
# Copyright 2015-2022 Akretion (http://www.akretion.com)
# Copyright 2015-2024 Akretion (https://www.akretion.com)
# @author Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -56,7 +56,7 @@ class AccountGroupGenerate(models.TransientModel):
action = {
'type': 'ir.actions.act_window',
'name': _('Account Groups'),
'view_mode': 'tree,form',
'view_mode': 'list,form',
'res_model': 'account.group',
}
return action

View File

@@ -1,4 +1,4 @@
# Copyright 2017-2022 Akretion France (https://akretion.com/en)
# Copyright 2017-2024 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).

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2017-2022 Akretion France
Copyright 2017-2024 Akretion France (https://www.akretion.com/)
@author: Alexis de Lattre <alexis.delattre@akretion.com>
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-->
@@ -11,7 +11,7 @@
<field name="name">account.invoice.mark.sent.form</field>
<field name="model">account.invoice.mark.sent</field>
<field name="arch" type="xml">
<form string="Mark invoices as sent">
<form>
<p>
This wizard will mark as <i>sent</i> all the selected posted invoices.
</p>

View File

@@ -1,10 +1,9 @@
# Copyright 2018-2022 Akretion France (https://akretion.com/)
# Copyright 2018-2024 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, fields, models, _
from dateutil.relativedelta import relativedelta
from odoo.exceptions import UserError
from datetime import timedelta
class AccountMoveReversal(models.TransientModel):
@@ -17,15 +16,9 @@ class AccountMoveReversal(models.TransientModel):
for wizard in self:
moves = wizard.move_ids or self.env["account.move"].browse(self._context['active_ids'])
reversed_moves = self.env["account.move"].search([('reversed_entry_id', 'in', moves.ids)])
warning = ""
for already_reversed_move in reversed_moves.reversed_entry_id:
if warning:
warning += "\n"
reversed_by = " ; ".join(already_reversed_move.reversal_move_id.mapped("display_name"))
move_detail = _("%s reversed by %s") % (already_reversed_move.display_name, reversed_by)
warning += move_detail
wizard.already_reversed_warning = warning or False
# in v18, display_name contains "MISC/2024/0008 (Reversal of: MISC/2024/0007)"
warning = "\n".join([m.display_name for m in reversed_moves])
wizard.already_reversed_warning = warning
# Set default reversal date to original move + 1 day
# and raise error if original move has already been reversed
@@ -36,5 +29,5 @@ class AccountMoveReversal(models.TransientModel):
amo = self.env['account.move']
moves = amo.browse(self._context['active_ids'])
if len(moves) == 1:
res['date'] = moves.date + relativedelta(days=1)
res['date'] = moves.date + timedelta(1)
return res

View File

@@ -9,10 +9,9 @@
<div
class="alert alert-warning"
role="alert"
attrs="{'invisible': [('already_reversed_warning', '=', False)]}"
invisible="not already_reversed_warning"
>
You are about to reverse entries that have already been reversed or partially reversed (refund). Make sure it is intented.
Already reversed entries are the following :
You are about to reverse entries that have already been reversed:
<field
name="already_reversed_warning"
/>

View File

@@ -2,7 +2,7 @@
# @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 import api, fields, models
class ResPartnerBank(models.Model):
@@ -12,3 +12,13 @@ class ResPartnerBank(models.Model):
# displayed as 'Name', which the string of the related field it
# points to
bank_name = fields.Char(string='Bank Name')
@api.depends('currency_id')
def _compute_display_name(self):
for acc in self:
name = acc.acc_number
if acc.currency_id:
name = f"{name} ({acc.currency_id.name})"
if acc.bank_id:
name = f"{name} - {acc.bank_id.name}"
acc.display_name = name