[IMP] account: statement automatically set starting and ending balance
To prevent having holes between statements and for better usability using import and synchronization we try to automatically set the starting and ending balance based on the previous existing statement. To do that, we added a new field previous_statement_id so that whenever we change the ending_balance of the previous statement, we recompute the starting balance and ending balance of the current statement. Also creating a new statement in between 2 others statements will automatically set the correct value to the starting and ending balance of that statement and all the statements afterwards. Exception: creating a statement by hand won't automatically set the balance_end_real, however if you create one between 2 statements, the balance_end_real of next statements will be recomputed Was Task #1880409 closes odoo/odoo#38696 Signed-off-by: Quentin De Paoli (qdp) <qdp@openerp.com>
This commit is contained in:
@@ -111,6 +111,34 @@ class AccountBankStmtCloseCheck(models.TransientModel):
|
||||
|
||||
class AccountBankStatement(models.Model):
|
||||
|
||||
# Note: the reason why we did 2 separate function with the same dependencies (one for balance_start and one for balance_end_real)
|
||||
# is because if we create a bank statement with a default value for one of the field but not the other, the compute method
|
||||
# won't be called and therefore the other field will have a value of 0 and we don't want that.
|
||||
@api.depends('previous_statement_id', 'previous_statement_id.balance_end_real')
|
||||
def _compute_starting_balance(self):
|
||||
for statement in self:
|
||||
if statement.previous_statement_id.balance_end_real != statement.balance_start:
|
||||
statement.balance_start = statement.previous_statement_id.balance_end_real
|
||||
else:
|
||||
# Need default value
|
||||
statement.balance_start = statement.balance_start or 0.0
|
||||
|
||||
@api.depends('previous_statement_id', 'previous_statement_id.balance_end_real')
|
||||
def _compute_ending_balance(self):
|
||||
for statement in self:
|
||||
# recompute balance_end_real in case we are in a bank journal and if we change the
|
||||
# balance_end_real of previous statement as we don't want
|
||||
# holes in case we add a statement in between 2 others statements.
|
||||
# We only do this for the bank journal as we use the balance_end_real in cash
|
||||
# journal for verification and creating cash difference entries so we don't want
|
||||
# to recompute the value in that case
|
||||
if statement.journal_type == 'bank':
|
||||
total_entry_encoding = sum([line.amount for line in statement.line_ids])
|
||||
statement.balance_end_real = statement.previous_statement_id.balance_end_real + total_entry_encoding
|
||||
else:
|
||||
# Need default value
|
||||
statement.balance_end_real = statement.balance_end_real or 0.0
|
||||
|
||||
@api.depends('line_ids', 'balance_start', 'line_ids.amount', 'balance_end_real')
|
||||
def _end_balance(self):
|
||||
for statement in self:
|
||||
@@ -168,6 +196,63 @@ class AccountBankStatement(models.Model):
|
||||
return self._get_opening_balance(journal_id)
|
||||
return 0
|
||||
|
||||
@api.depends('balance_start', 'previous_statement_id')
|
||||
def _compute_is_valid_balance_start(self):
|
||||
for bnk in self:
|
||||
bnk.is_valid_balance_start = bnk.balance_start == bnk.previous_statement_id.balance_end_real
|
||||
|
||||
@api.depends('date', 'journal_id')
|
||||
def _get_previous_statement(self):
|
||||
# We have to sort self by date otherwise we may encounter some errors
|
||||
# Let's assume the following case
|
||||
# Self contains 3 record (1,2,3) with the following order on date (2019-01-13, 2019-01-12, 2019-01-15)
|
||||
# On first iteration, record 1 will correctly set previous_Statement_id = 2
|
||||
# On second iteration, before record 2 can set its previous_statement_id, it will look for someone
|
||||
# pointing to him in order to change that to its self.previous_statement_id (because we could change the date of
|
||||
# record 2 and move it to the end and we don't want the previously statement that was pointing towards him to
|
||||
# continue doing so). However in the case of a creating in batch like in our example, this will cause the following
|
||||
# issue: record 3 that was done just before in the first loop iteration will have its previous_statement_id set
|
||||
# to False and its starting and ending balance won't be computed correctly.
|
||||
# The solution to avoid that is to sort self by date in ascending order that way we are sure that no record
|
||||
# set their values too soon.
|
||||
for st in sorted(self, key=lambda l: l['date']):
|
||||
# Search for the previous statement
|
||||
domain = [('date', '<=', st.date), ('journal_id', '=', st.journal_id.id)]
|
||||
# The reason why we have to perform this test is because we have two use case here:
|
||||
# First one is in case we are creating a new record, in that case that new record does
|
||||
# not have any id yet. However if we are updating an existing record, the domain date <= st.date
|
||||
# will find the record itself, so we have to add a condition in the search to ignore self.id
|
||||
if not isinstance(st.id, models.NewId):
|
||||
domain.append(('id', '!=', st.id))
|
||||
previous_statement = self.search(domain, limit=1)
|
||||
|
||||
# Exist early if no change
|
||||
if previous_statement == st.previous_statement_id:
|
||||
st.previous_statement_id = previous_statement.id
|
||||
continue
|
||||
|
||||
# Search for statement pointing to myself to change it's previous_statement_id to my previous_statement_id
|
||||
# This does not need to be compute when we are creating a record (newId)
|
||||
if not isinstance(st.id, models.NewId):
|
||||
point_to_me_statement = self.search([('previous_statement_id', '=', st.id)], limit=1)
|
||||
if point_to_me_statement:
|
||||
point_to_me_statement.previous_statement_id = st.previous_statement_id.id
|
||||
|
||||
# two cases here:
|
||||
# 1- If we have a previous statement, it is possible that we are creating a statement between 2 others stmt
|
||||
# so we have to change the link of the stmt that was already pointing to the previous statement to ourself
|
||||
# We only do this if the record already exists in db, because we can't
|
||||
# assign a newId to an existing next_statement
|
||||
# 2- We have found no more previous statement, however it is possible that we have been moved first of the list
|
||||
# so we have to search for any other existing statement and link that one to us (this again also make sense
|
||||
# only if we already have an actual id)
|
||||
st.previous_statement_id = previous_statement.id
|
||||
if not isinstance(st.id, models.NewId):
|
||||
next_statement = self.search([('previous_statement_id', '=', previous_statement.id), ('id', '!=', st.id), ('journal_id', '=', st.journal_id.id)], limit=1)
|
||||
if next_statement:
|
||||
next_statement.previous_statement_id = st.id
|
||||
|
||||
|
||||
_name = "account.bank.statement"
|
||||
_description = "Bank Statement"
|
||||
_order = "date desc, id desc"
|
||||
@@ -177,8 +262,8 @@ class AccountBankStatement(models.Model):
|
||||
reference = fields.Char(string='External Reference', states={'open': [('readonly', False)]}, copy=False, readonly=True, help="Used to hold the reference of the external mean that created this statement (name of imported file, reference of online synchronization...)")
|
||||
date = fields.Date(required=True, states={'confirm': [('readonly', True)]}, index=True, copy=False, default=fields.Date.context_today)
|
||||
date_done = fields.Datetime(string="Closed On")
|
||||
balance_start = fields.Monetary(string='Starting Balance', states={'confirm': [('readonly', True)]}, default=_default_opening_balance)
|
||||
balance_end_real = fields.Monetary('Ending Balance', states={'confirm': [('readonly', True)]})
|
||||
balance_start = fields.Monetary(string='Starting Balance', states={'confirm': [('readonly', True)]}, compute='_compute_starting_balance', readonly=False, store=True)
|
||||
balance_end_real = fields.Monetary('Ending Balance', states={'confirm': [('readonly', True)]}, compute='_compute_ending_balance', readonly=False, store=True)
|
||||
accounting_date = fields.Date(string="Accounting Date", help="If set, the accounting entries created during the bank statement reconciliation process will be created at this date.\n"
|
||||
"This is useful if the accounting period in which the entries should normally be booked is already closed.")
|
||||
state = fields.Selection([('open', 'New'), ('confirm', 'Validated')], string='Status', required=True, readonly=True, copy=False, default='open')
|
||||
@@ -201,10 +286,8 @@ class AccountBankStatement(models.Model):
|
||||
cashbox_start_id = fields.Many2one('account.bank.statement.cashbox', string="Starting Cashbox")
|
||||
cashbox_end_id = fields.Many2one('account.bank.statement.cashbox', string="Ending Cashbox")
|
||||
is_difference_zero = fields.Boolean(compute='_is_difference_zero', string='Is zero', help="Check if difference is zero.")
|
||||
|
||||
@api.onchange('journal_id')
|
||||
def onchange_journal_id(self):
|
||||
self._set_opening_balance(self.journal_id.id)
|
||||
previous_statement_id = fields.Many2one('account.bank.statement', help='technical field to compute starting balance correctly', compute='_get_previous_statement', store=True)
|
||||
is_valid_balance_start = fields.Boolean(string="Is Valid Balance Start", compute="_compute_is_valid_balance_start", help="technical field to display a warning message in case starting balance is different than previous ending balance")
|
||||
|
||||
def _balance_check(self):
|
||||
for stmt in self:
|
||||
@@ -240,6 +323,11 @@ class AccountBankStatement(models.Model):
|
||||
raise UserError(_('In order to delete a bank statement, you must first cancel it to delete related journal items.'))
|
||||
# Explicitly unlink bank statement lines so it will check that the related journal entries have been deleted first
|
||||
statement.line_ids.unlink()
|
||||
# Some other bank statements might be link to this one, so in that case we have to switch the previous_statement_id
|
||||
# from that statement to the one linked to this statement
|
||||
next_statement = self.search([('previous_statement_id', '=', statement.id)])
|
||||
if next_statement:
|
||||
next_statement.previous_statement_id = statement.previous_statement_id
|
||||
return super(AccountBankStatement, self).unlink()
|
||||
|
||||
def open_cashbox_id(self):
|
||||
|
||||
@@ -9,6 +9,7 @@ from . import test_account_move_partner_count
|
||||
from . import test_account_move_rounding
|
||||
from . import test_account_invoice_report
|
||||
from . import test_account_journal_dashboard
|
||||
from . import test_account_bank_statement
|
||||
from . import test_bank_statement_reconciliation
|
||||
from . import test_control_journal_account
|
||||
from . import test_fiscal_position
|
||||
|
||||
@@ -0,0 +1,230 @@
|
||||
from odoo.addons.account.tests.account_test_classes import AccountingTestCase
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('post_install', '-at_install')
|
||||
class TestBankStatementReconciliation(AccountingTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestBankStatementReconciliation, self).setUp()
|
||||
self.bs_model = self.env['account.bank.statement']
|
||||
self.bsl_model = self.env['account.bank.statement.line']
|
||||
self.partner = self.env['res.partner'].create({'name': 'test'})
|
||||
self.journal = self.env['account.journal'].create({
|
||||
'name': 'BnkJournal',
|
||||
'type': 'bank'
|
||||
})
|
||||
self.journal2 = self.env['account.journal'].create({
|
||||
'name': 'BnkJournal2',
|
||||
'type': 'bank'
|
||||
})
|
||||
self.cashjournal = self.env['account.journal'].create({
|
||||
'name': 'CashJournal',
|
||||
'type': 'cash'
|
||||
})
|
||||
self.number = 1
|
||||
|
||||
def create_bank_statement(self, date, line_amount, balance_end_real=False, journal=False):
|
||||
vals = {
|
||||
'name': 'BNK' + str(self.number),
|
||||
'date': date,
|
||||
'line_ids': [(0, 0, {
|
||||
'name': '_',
|
||||
'amount': line_amount,
|
||||
})],
|
||||
'journal_id': journal or self.journal.id
|
||||
}
|
||||
if balance_end_real:
|
||||
vals['balance_end_real'] = balance_end_real
|
||||
self.number += 1
|
||||
return self.bs_model.create(vals)
|
||||
|
||||
def test_compute_balance_end_real_with_lines(self):
|
||||
bnk1 = self.create_bank_statement('2019-01-02', 100)
|
||||
self.assertEqual(bnk1.balance_start, 0)
|
||||
# Balance is automatically computed when creating statement with the lines
|
||||
self.assertEqual(bnk1.balance_end_real, 100)
|
||||
self.assertEqual(bnk1.balance_end, 100)
|
||||
|
||||
def test_compute_balance_end_real_without_lines(self):
|
||||
vals = {
|
||||
'name': 'BNK' + str(self.number),
|
||||
'date': '2019-01-01',
|
||||
'journal_id': self.journal.id
|
||||
}
|
||||
bnk1 = self.bs_model.create(vals)
|
||||
self.assertEqual(bnk1.balance_start, 0)
|
||||
self.assertEqual(bnk1.balance_end_real, 0)
|
||||
self.assertEqual(bnk1.balance_end, 0)
|
||||
# Add a line
|
||||
self.bsl_model.create({
|
||||
'name': '_',
|
||||
'amount': 10,
|
||||
'statement_id': bnk1.id
|
||||
})
|
||||
self.assertEqual(bnk1.balance_start, 0)
|
||||
# balance_end_real should not have changed
|
||||
self.assertEqual(bnk1.balance_end_real, 0)
|
||||
# Compute balance should have been computed
|
||||
self.assertEqual(bnk1.balance_end, 10)
|
||||
|
||||
def test_create_new_statement(self):
|
||||
# Create first statement on 1/1/2019
|
||||
bnk1 = self.create_bank_statement('2019-01-02', 100)
|
||||
# import pdb;pdb.set_trace()
|
||||
self.assertEqual(bnk1.balance_start, 0)
|
||||
# Balance is automatically computed when creating statement with the lines
|
||||
self.assertEqual(bnk1.balance_end_real, 100)
|
||||
self.assertEqual(bnk1.balance_end, 100)
|
||||
self.assertEqual(bnk1.previous_statement_id.id, False)
|
||||
|
||||
# Create a new statement after that one
|
||||
bnk2 = self.create_bank_statement('2019-01-10', 50)
|
||||
self.assertEqual(bnk2.balance_start, 100)
|
||||
self.assertEqual(bnk2.balance_end_real, 150)
|
||||
self.assertEqual(bnk2.balance_end, 150)
|
||||
self.assertEqual(bnk2.previous_statement_id.id, bnk1.id)
|
||||
|
||||
# Create new statement with given ending balance
|
||||
bnk3 = self.create_bank_statement('2019-01-15', 25, 200)
|
||||
self.assertEqual(bnk3.balance_end_real, 200)
|
||||
self.assertEqual(bnk3.balance_start, 150)
|
||||
self.assertEqual(bnk3.balance_end, 175)
|
||||
self.assertEqual(bnk3.previous_statement_id.id, bnk2.id)
|
||||
|
||||
bnk4 = self.create_bank_statement('2019-01-03', 100)
|
||||
self.assertEqual(bnk4.balance_start, 100)
|
||||
self.assertEqual(bnk4.balance_end_real, 200)
|
||||
self.assertEqual(bnk4.balance_end, 200)
|
||||
self.assertEqual(bnk4.previous_statement_id.id, bnk1.id)
|
||||
# Bnk2 should have changed its previous statement
|
||||
self.assertEqual(bnk2.previous_statement_id.id, bnk4.id)
|
||||
# The starting balance and balance_end_real should have been recomputed
|
||||
self.assertEqual(bnk2.balance_start, 200)
|
||||
self.assertEqual(bnk2.balance_end_real, 250)
|
||||
self.assertEqual(bnk2.balance_end, 250)
|
||||
# The starting balance and balance_end_real of next entries should also have been recomputed
|
||||
# and since we are propagating an update, the balance_end_real should have been recomputed to
|
||||
# the correct value
|
||||
self.assertEqual(bnk3.balance_start, 250)
|
||||
self.assertEqual(bnk3.balance_end_real, 275)
|
||||
self.assertEqual(bnk3.balance_end, 275)
|
||||
|
||||
# Change date of bank stmt4 to be the last
|
||||
bnk4.date = '2019-01-20'
|
||||
self.assertEqual(bnk1.previous_statement_id.id, False)
|
||||
self.assertEqual(bnk2.previous_statement_id.id, bnk1.id)
|
||||
self.assertEqual(bnk3.previous_statement_id.id, bnk2.id)
|
||||
self.assertEqual(bnk4.previous_statement_id.id, bnk3.id)
|
||||
self.assertEqual(bnk1.balance_start, 0)
|
||||
self.assertEqual(bnk2.balance_start, 100)
|
||||
self.assertEqual(bnk3.balance_start, 150)
|
||||
self.assertEqual(bnk4.balance_start, 175)
|
||||
self.assertEqual(bnk1.balance_end_real, 100)
|
||||
self.assertEqual(bnk2.balance_end_real, 150)
|
||||
self.assertEqual(bnk3.balance_end_real, 175)
|
||||
self.assertEqual(bnk4.balance_end_real, 275)
|
||||
|
||||
# Move bnk3 to first position
|
||||
bnk3.date = '2019-01-01'
|
||||
self.assertEqual(bnk3.previous_statement_id.id, False)
|
||||
self.assertEqual(bnk1.previous_statement_id.id, bnk3.id)
|
||||
self.assertEqual(bnk2.previous_statement_id.id, bnk1.id)
|
||||
self.assertEqual(bnk4.previous_statement_id.id, bnk2.id)
|
||||
self.assertEqual(bnk3.balance_start, 0)
|
||||
self.assertEqual(bnk1.balance_start, 25)
|
||||
self.assertEqual(bnk2.balance_start, 125)
|
||||
self.assertEqual(bnk4.balance_start, 175)
|
||||
self.assertEqual(bnk3.balance_end_real, 25)
|
||||
self.assertEqual(bnk1.balance_end_real, 125)
|
||||
self.assertEqual(bnk2.balance_end_real, 175)
|
||||
self.assertEqual(bnk4.balance_end_real, 275)
|
||||
|
||||
# Change bnk1 and bnk2
|
||||
bnk1.date = '2019-01-11'
|
||||
self.assertEqual(bnk3.previous_statement_id.id, False)
|
||||
self.assertEqual(bnk2.previous_statement_id.id, bnk3.id)
|
||||
self.assertEqual(bnk1.previous_statement_id.id, bnk2.id)
|
||||
self.assertEqual(bnk4.previous_statement_id.id, bnk1.id)
|
||||
self.assertEqual(bnk3.balance_start, 0)
|
||||
self.assertEqual(bnk2.balance_start, 25)
|
||||
self.assertEqual(bnk1.balance_start, 75)
|
||||
self.assertEqual(bnk4.balance_start, 175)
|
||||
self.assertEqual(bnk3.balance_end_real, 25)
|
||||
self.assertEqual(bnk2.balance_end_real, 75)
|
||||
self.assertEqual(bnk1.balance_end_real, 175)
|
||||
self.assertEqual(bnk4.balance_end_real, 275)
|
||||
|
||||
def test_create_statements_in_different_journal(self):
|
||||
# Bank statement create in two different journal should not link with each other
|
||||
bnk1 = self.create_bank_statement('2019-01-01', 100, 100)
|
||||
bnk2 = self.create_bank_statement('2019-01-10', 50)
|
||||
|
||||
bnk1other = self.create_bank_statement('2019-01-02', 20, 20, self.journal2.id)
|
||||
bnk2other = self.create_bank_statement('2019-01-12', 10, False, self.journal2.id)
|
||||
|
||||
self.assertEqual(bnk1.previous_statement_id.id, False)
|
||||
self.assertEqual(bnk2.previous_statement_id.id, bnk1.id)
|
||||
self.assertEqual(bnk1.balance_start, 0)
|
||||
self.assertEqual(bnk2.balance_start, 100)
|
||||
self.assertEqual(bnk2.balance_end_real, 150)
|
||||
|
||||
self.assertEqual(bnk1other.previous_statement_id.id, False)
|
||||
self.assertEqual(bnk2other.previous_statement_id.id, bnk1other.id)
|
||||
self.assertEqual(bnk1other.balance_start, 0)
|
||||
self.assertEqual(bnk2other.balance_start, 20)
|
||||
self.assertEqual(bnk2other.balance_end_real, 30)
|
||||
|
||||
def test_statement_cash_journal(self):
|
||||
# Entry in cash journal should not recompute the balance_end_real
|
||||
cash1 = self.create_bank_statement('2019-01-01', 100, 100, self.cashjournal.id)
|
||||
cash2 = self.create_bank_statement('2019-01-03', 100, False, self.cashjournal.id)
|
||||
self.assertEqual(cash1.balance_start, 0)
|
||||
self.assertEqual(cash1.balance_end_real, 100)
|
||||
self.assertEqual(cash2.balance_start, 100)
|
||||
self.assertEqual(cash2.balance_end_real, 0)
|
||||
cash2.balance_end_real = 1000
|
||||
self.assertEqual(cash2.balance_end_real, 1000)
|
||||
# add cash entry in between, should recompute starting balance of cash2 entry but not ending balance
|
||||
cash3 = self.create_bank_statement('2019-01-02', 100, 200, self.cashjournal.id)
|
||||
self.assertEqual(cash3.balance_start, 100)
|
||||
self.assertEqual(cash3.balance_end_real, 200)
|
||||
self.assertEqual(cash2.balance_start, 200)
|
||||
self.assertEqual(cash2.balance_end_real, 1000)
|
||||
|
||||
def test_unlink_bank_statement(self):
|
||||
bnk1 = self.create_bank_statement('2019-01-02', 100)
|
||||
bnk2 = self.create_bank_statement('2019-01-10', 50)
|
||||
bnk3 = self.create_bank_statement('2019-01-15', 25)
|
||||
bnk4 = self.create_bank_statement('2019-01-21', 100)
|
||||
bnk5 = self.create_bank_statement('2019-01-22', 100)
|
||||
self.assertEqual(bnk1.previous_statement_id.id, False)
|
||||
self.assertEqual(bnk2.previous_statement_id.id, bnk1.id)
|
||||
self.assertEqual(bnk3.previous_statement_id.id, bnk2.id)
|
||||
self.assertEqual(bnk4.previous_statement_id.id, bnk3.id)
|
||||
self.assertEqual(bnk5.previous_statement_id.id, bnk4.id)
|
||||
self.assertEqual(bnk3.balance_start, 150)
|
||||
self.assertEqual(bnk3.balance_end_real, 175)
|
||||
self.assertEqual(bnk4.balance_start, 175)
|
||||
self.assertEqual(bnk4.balance_end_real, 275)
|
||||
self.assertEqual(bnk5.balance_start, 275)
|
||||
self.assertEqual(bnk5.balance_end_real, 375)
|
||||
|
||||
# Delete bnk2 and check that previous_statement_id and balance are correct
|
||||
bnk2.unlink()
|
||||
self.assertEqual(bnk1.previous_statement_id.id, False)
|
||||
self.assertEqual(bnk3.previous_statement_id.id, bnk1.id)
|
||||
self.assertEqual(bnk4.previous_statement_id.id, bnk3.id)
|
||||
self.assertEqual(bnk5.previous_statement_id.id, bnk4.id)
|
||||
self.assertEqual(bnk3.balance_start, 100)
|
||||
self.assertEqual(bnk3.balance_end_real, 125)
|
||||
self.assertEqual(bnk4.balance_start, 125)
|
||||
self.assertEqual(bnk4.balance_end_real, 225)
|
||||
self.assertEqual(bnk5.balance_start, 225)
|
||||
self.assertEqual(bnk5.balance_end_real, 325)
|
||||
|
||||
# Delete bnk1 bnk3 and bnk4 at the same time and check that balance are correct
|
||||
(bnk1 + bnk3 + bnk4).unlink()
|
||||
self.assertEqual(bnk5.previous_statement_id.id, False)
|
||||
self.assertEqual(bnk5.balance_start, 0)
|
||||
self.assertEqual(bnk5.balance_end_real, 100)
|
||||
@@ -640,6 +640,9 @@ action = model.setting_init_bank_account_action()
|
||||
<button name="%(action_cash_box_out)d" string="Take Money In/Out" type="action" class="oe_highlight" attrs="{'invisible': [('journal_type','!=','cash')]}"/>
|
||||
<field name="state" widget="statusbar" statusbar_visible="open,confirm"/>
|
||||
</header>
|
||||
<div class="alert alert-warning" role="alert" attrs="{'invisible': ['|', ('previous_statement_id', '=', False), ('is_valid_balance_start', '=', True)]}">
|
||||
The starting balance <b>doesn't match</b> with the ending balance of the previous bank statement.
|
||||
</div>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button" name="button_journal_entries"
|
||||
@@ -654,6 +657,8 @@ action = model.setting_init_bank_account_action()
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="previous_statement_id" invisible="1"/>
|
||||
<field name="is_valid_balance_start" invisible="1"/>
|
||||
<field name="journal_type" invisible="1"/>
|
||||
<field name="cashbox_start_id" invisible="1"/>
|
||||
<field name="cashbox_end_id" invisible="1"/>
|
||||
|
||||
Reference in New Issue
Block a user