[MIG] account_usability_akretion to v18
Move code from account_usability_akretion to base_usability_akretion
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
@@ -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',
|
||||
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
70
account_usability_akretion/models/account_move_line.py
Normal file
70
account_usability_akretion/models/account_move_line.py
Normal 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()
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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_'
|
||||
|
||||
@@ -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).
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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>
|
||||
|
||||
|
||||
@@ -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).
|
||||
-->
|
||||
|
||||
@@ -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).
|
||||
-->
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
-->
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
52
account_usability_akretion/views/account_move_line.xml
Normal file
52
account_usability_akretion/views/account_move_line.xml
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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).
|
||||
-->
|
||||
|
||||
@@ -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).
|
||||
-->
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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).
|
||||
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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"
|
||||
/>
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user