Show debit / credit columns in ledgers when they contain lines

issue11072
review372881002
This commit is contained in:
Nicolas Évrard
2022-02-04 15:39:41 +01:00
parent b6e7792572
commit 030963812f
6 changed files with 221 additions and 23 deletions
+2
View File
@@ -1,3 +1,5 @@
* Show debit / credit columns in ledgers when they contain lines
* Count number of lines in Account and General Ledger
* Handle errors in move template expression
* Rename split lines into reschedule lines
* Add optional credit type on account
+111 -18
View File
@@ -9,9 +9,10 @@ from itertools import zip_longest
from dateutil.relativedelta import relativedelta
from sql import Column, Literal, Null, Window
from sql.aggregate import Max, Min, Sum
from sql.aggregate import Count, Max, Min, Sum
from sql.conditionals import Case, Coalesce
from trytond import backend
from trytond.i18n import gettext
from trytond.model import (
Check, ModelSQL, ModelView, Unique, fields, sequence_ordered, tree)
@@ -876,10 +877,18 @@ class Account(AccountMixin(), ActivePeriodMixin, tree(), ModelSQL, ModelView):
"Balance", currency='currency', digits='currency'),
'get_balance')
credit = fields.Function(Monetary(
"Credit", currency='currency', digits='currency'),
"Credit", currency='currency', digits='currency',
states={
'invisible': ~Eval('line_count', -1),
},
depends=['line_count']),
'get_credit_debit')
debit = fields.Function(Monetary(
"Debit", currency='currency', digits='currency'),
"Debit", currency='currency', digits='currency',
states={
'invisible': ~Eval('line_count', -1),
},
depends=['line_count']),
'get_credit_debit')
amount_second_currency = fields.Function(Monetary(
"Amount Second Currency",
@@ -889,6 +898,8 @@ class Account(AccountMixin(), ActivePeriodMixin, tree(), ModelSQL, ModelView):
},
depends=['second_currency']),
'get_credit_debit')
line_count = fields.Function(
fields.Integer("Line Count"), 'get_credit_debit')
note = fields.Text('Note')
deferrals = fields.One2Many(
'account.account.deferral', 'account', "Deferrals", readonly=True,
@@ -1026,16 +1037,21 @@ class Account(AccountMixin(), ActivePeriodMixin, tree(), ModelSQL, ModelView):
result = {}
ids = [a.id for a in accounts]
for name in names:
if name not in {'credit', 'debit', 'amount_second_currency'}:
if name not in {
'credit', 'debit', 'amount_second_currency', 'line_count'}:
raise ValueError('Unknown name: %s' % name)
result[name] = dict((i, Decimal(0)) for i in ids)
col_type = int if name == 'line_count' else Decimal
result[name] = defaultdict(col_type)
table = cls.__table__()
line = MoveLine.__table__()
line_query, fiscalyear_ids = MoveLine.query_get(line)
columns = [table.id]
for name in names:
columns.append(Sum(Coalesce(Column(line, name), 0)))
if name == 'line_count':
columns.append(Count(Literal('*')))
else:
columns.append(Sum(Coalesce(Column(line, name), 0)))
for sub_ids in grouped_slice(ids):
red_sql = reduce_ids(table.id, sub_ids)
cursor.execute(*table.join(line, 'LEFT',
@@ -1047,12 +1063,15 @@ class Account(AccountMixin(), ActivePeriodMixin, tree(), ModelSQL, ModelView):
account_id = row[0]
for i, name in enumerate(names, 1):
# SQLite uses float for SUM
if not isinstance(row[i], Decimal):
if (name != 'line_count'
and not isinstance(row[i], Decimal)):
result[name][account_id] = Decimal(str(row[i]))
else:
result[name][account_id] = row[i]
for account in accounts:
for name in names:
if name == 'line_count':
continue
if (name == 'amount_second_currency'
and account.second_currency):
currency = account.second_currency
@@ -1397,6 +1416,8 @@ class AccountParty(ActivePeriodMixin, ModelSQL):
},
depends=['second_currency']),
'get_credit_debit')
line_count = fields.Function(
fields.Integer("Line Count"), 'get_credit_debit')
second_currency = fields.Many2One(
'currency.currency', "Secondary Currency")
@@ -1496,11 +1517,12 @@ class AccountParty(ActivePeriodMixin, ModelSQL):
cursor = Transaction().connection.cursor()
result = {}
ids = [a.id for a in records]
for name in names:
if name not in {'credit', 'debit', 'amount_second_currency'}:
if name not in {
'credit', 'debit', 'amount_second_currency', 'line_count'}:
raise ValueError('Unknown name: %s' % name)
result[name] = dict((i, Decimal(0)) for i in ids)
column_type = int if name == 'line_count' else Decimal
result[name] = defaultdict(column_type)
account_ids = {a.account.id for a in records}
party_ids = {a.party.id for a in records}
@@ -1510,7 +1532,10 @@ class AccountParty(ActivePeriodMixin, ModelSQL):
line_query, fiscalyear_ids = MoveLine.query_get(line)
columns = [table.id, line.party]
for name in names:
columns.append(Sum(Coalesce(Column(line, name), 0)))
if name == 'line_count':
columns.append(Count(Literal('*')))
else:
columns.append(Sum(Coalesce(Column(line, name), 0)))
for sub_account_ids in grouped_slice(account_ids):
account_sql = reduce_ids(table.id, sub_account_ids)
for sub_party_ids in grouped_slice(party_ids):
@@ -1529,12 +1554,15 @@ class AccountParty(ActivePeriodMixin, ModelSQL):
continue
for i, name in enumerate(names, 2):
# SQLite uses float for SUM
if not isinstance(row[i], Decimal):
if (name != 'line_count'
and not isinstance(row[i], Decimal)):
result[name][id_] = Decimal(str(row[i]))
else:
result[name][id_] = row[i]
for record in records:
for name in names:
if name == 'line_count':
continue
if name == 'amount_second_currency' and record.second_currency:
currency = record.second_currency
else:
@@ -1586,6 +1614,7 @@ class AccountDeferral(ModelSQL, ModelView):
'invisible': ~Eval('second_currency'),
},
depends=['second_currency'])
line_count = fields.Integer("Line Count", required=True)
second_currency = fields.Function(fields.Many2One(
'currency.currency', "Second Currency"), 'get_second_currency')
@@ -1598,10 +1627,47 @@ class AccountDeferral(ModelSQL, ModelView):
'account.msg_deferral_unique'),
]
@classmethod
def __register__(cls, module_name):
pool = Pool()
MoveLine = pool.get('account.move.line')
Move = pool.get('account.move')
Period = pool.get('account.period')
cursor = Transaction().connection.cursor()
deferral = cls.__table__()
move_line = MoveLine.__table__()
move = Move.__table__()
period = Period.__table__()
exist = backend.TableHandler.table_exist(cls._table)
table_h = cls.__table_handler__(module_name)
created_line_count = exist and not table_h.column_exist('line_count')
super().__register__(module_name)
# Migration from 6.2: add line_count on deferrals
if created_line_count:
counting_query = (move_line
.join(move, condition=move_line.move == move.id)
.join(period, condition=move.period == period.id)
.select(
move_line.account, period.fiscalyear, Count(Literal('*')),
group_by=[move_line.account, period.fiscalyear]))
cursor.execute(*deferral.update(
[deferral.line_count], [counting_query.line_count],
from_=[counting_query],
where=((deferral.account == counting_query.account)
& (deferral.fiscalyear == counting_query.fiscalyear))))
@classmethod
def default_amount_second_currency(cls):
return Decimal(0)
@classmethod
def default_line_count(cls):
return 0
@classmethod
def get_balance(cls, deferrals, name):
pool = Pool()
@@ -1715,23 +1781,50 @@ class _GeneralLedgerAccount(ActivePeriodMixin, ModelSQL, ModelView):
account = fields.Many2One('account.account', "Account")
company = fields.Many2One('company.company', 'Company')
start_debit = fields.Function(Monetary(
"Start Debit", currency='currency', digits='currency'),
"Start Debit", currency='currency', digits='currency',
states={
'invisible': ~Eval('line_count', -1),
},
depends=['line_count']),
'get_account', searcher='search_account')
debit = fields.Function(Monetary(
"Debit", currency='currency', digits='currency'),
"Debit", currency='currency', digits='currency',
states={
'invisible': ~Eval('line_count', -1),
},
depends=['line_count']),
'get_debit_credit', searcher='search_debit_credit')
end_debit = fields.Function(Monetary(
"End Debit", currency='currency', digits='currency'),
"End Debit", currency='currency', digits='currency',
states={
'invisible': ~Eval('line_count', -1),
},
depends=['line_count']),
'get_account', searcher='search_account')
start_credit = fields.Function(Monetary(
"Start Credit", currency='currency', digits='currency'),
"Start Credit", currency='currency', digits='currency',
states={
'invisible': ~Eval('line_count', -1),
},
depends=['line_count']),
'get_account', searcher='search_account')
credit = fields.Function(Monetary(
"Credit", currency='currency', digits='currency'),
"Credit", currency='currency', digits='currency',
states={
'invisible': ~Eval('line_count', -1),
},
depends=['line_count']),
'get_debit_credit', searcher='search_debit_credit')
end_credit = fields.Function(Monetary(
"End Credit", currency='currency', digits='currency'),
"End Credit", currency='currency', digits='currency',
states={
'invisible': ~Eval('line_count', -1),
},
depends=['line_count']),
'get_account', searcher='search_account')
line_count = fields.Function(
fields.Integer("Line Count"),
'get_debit_credit', searcher='search_debit_credit')
start_balance = fields.Function(Monetary(
"Start Balance", currency='currency', digits='currency'),
'get_account', searcher='search_account')
+1
View File
@@ -550,6 +550,7 @@ this repository contains the full copyright notices and license terms. -->
<field name="name">General Ledger - Accounts</field>
<field name="res_model">account.general_ledger.account</field>
<field name="context_model">account.general_ledger.account.context</field>
<field name="search_value" eval="[('line_count', '!=', 0)]" pyson="1"/>
</record>
<record model="ir.action.act_window.view"
id="act_general_ledger_account_form_view1">
+1
View File
@@ -257,6 +257,7 @@ class FiscalYear(Workflow, ModelSQL, ModelView):
deferral.fiscalyear = self
deferral.debit = account.debit
deferral.credit = account.credit
deferral.line_count = account.line_count
deferral.amount_second_currency = account.amount_second_currency
return deferral
+105 -5
View File
@@ -40,6 +40,12 @@ Create chart of accounts::
>>> expense = accounts['expense']
>>> cash = accounts['cash']
Create a child account::
>>> _ = revenue.childs.new()
>>> revenue.save()
>>> child_revenue, = revenue.childs
Create parties::
>>> Party = Model.get('party.party')
@@ -61,7 +67,7 @@ Create a moves::
>>> move.journal = journal_revenue
>>> move.date = period_3.start_date
>>> line = move.lines.new()
>>> line.account = revenue
>>> line.account = child_revenue
>>> line.credit = Decimal(10)
>>> line = move.lines.new()
>>> line.account = receivable
@@ -102,6 +108,9 @@ Print some reports::
... 'fiscalyear': fiscalyear.id,
... }
>>> with config.set_context(context):
... gl_child_revenue, = GeneralLedgerAccount.find([
... ('account', '=', child_revenue.id),
... ])
... gl_revenue, = GeneralLedgerAccount.find([
... ('account', '=', revenue.id),
... ])
@@ -109,14 +118,26 @@ Print some reports::
... ('account', '=', receivable.id),
... ('party', '=', party.id),
... ])
>>> gl_child_revenue.start_balance
Decimal('0.00')
>>> gl_child_revenue.credit
Decimal('10.00')
>>> gl_child_revenue.debit
Decimal('0.00')
>>> gl_child_revenue.end_balance
Decimal('-10.00')
>>> gl_child_revenue.line_count
1
>>> gl_revenue.start_balance
Decimal('0.00')
>>> gl_revenue.credit
Decimal('10.00')
Decimal('0.00')
>>> gl_revenue.debit
Decimal('0.00')
>>> gl_revenue.end_balance
Decimal('-10.00')
>>> gl_revenue.line_count
0
>>> glp_receivable.start_balance
Decimal('0.00')
>>> glp_receivable.credit
@@ -125,6 +146,8 @@ Print some reports::
Decimal('10.00')
>>> glp_receivable.end_balance
Decimal('0.00')
>>> glp_receivable.line_count
2
>>> context = {
... 'company': company.id,
@@ -133,6 +156,9 @@ Print some reports::
... 'to_date': period_3.end_date,
... }
>>> with config.set_context(context):
... gl_child_revenue, = GeneralLedgerAccount.find([
... ('account', '=', child_revenue.id),
... ])
... gl_revenue, = GeneralLedgerAccount.find([
... ('account', '=', revenue.id),
... ])
@@ -140,14 +166,26 @@ Print some reports::
... ('account', '=', receivable.id),
... ('party', '=', party.id),
... ])
>>> gl_child_revenue.start_balance
Decimal('0.00')
>>> gl_child_revenue.credit
Decimal('10.00')
>>> gl_child_revenue.debit
Decimal('0.00')
>>> gl_child_revenue.end_balance
Decimal('-10.00')
>>> gl_child_revenue.line_count
1
>>> gl_revenue.start_balance
Decimal('0.00')
>>> gl_revenue.credit
Decimal('10.00')
Decimal('0.00')
>>> gl_revenue.debit
Decimal('0.00')
>>> gl_revenue.end_balance
Decimal('-10.00')
>>> gl_revenue.line_count
0
>>> glp_receivable.start_balance
Decimal('0.00')
>>> glp_receivable.credit
@@ -156,6 +194,8 @@ Print some reports::
Decimal('10.00')
>>> glp_receivable.end_balance
Decimal('10.00')
>>> glp_receivable.line_count
1
>>> context = {
... 'company': company.id,
@@ -163,17 +203,32 @@ Print some reports::
... 'start_period': period_3.id,
... }
>>> with config.set_context(context):
... gl_child_revenue, = GeneralLedgerAccount.find([
... ('account', '=', child_revenue.id),
... ])
... gl_revenue, = GeneralLedgerAccount.find([
... ('account', '=', revenue.id),
... ])
>>> gl_child_revenue.start_balance
Decimal('0.00')
>>> gl_child_revenue.credit
Decimal('10.00')
>>> gl_child_revenue.debit
Decimal('0.00')
>>> gl_child_revenue.end_balance
Decimal('-10.00')
>>> gl_child_revenue.line_count
1
>>> gl_revenue.start_balance
Decimal('0.00')
>>> gl_revenue.credit
Decimal('10.00')
Decimal('0.00')
>>> gl_revenue.debit
Decimal('0.00')
>>> gl_revenue.end_balance
Decimal('-10.00')
>>> gl_revenue.line_count
0
>>> context = {
... 'company': company.id,
@@ -181,9 +236,22 @@ Print some reports::
... 'start_period': period_5.id,
... }
>>> with config.set_context(context):
... gl_child_revenue, = GeneralLedgerAccount.find([
... ('account', '=', child_revenue.id),
... ])
... gl_revenue, = GeneralLedgerAccount.find([
... ('account', '=', revenue.id),
... ])
>>> gl_child_revenue.start_balance
Decimal('-10.00')
>>> gl_child_revenue.credit
Decimal('0.00')
>>> gl_child_revenue.debit
Decimal('0.00')
>>> gl_child_revenue.end_balance
Decimal('-10.00')
>>> gl_child_revenue.line_count
0
>>> gl_revenue.start_balance
Decimal('-10.00')
>>> gl_revenue.credit
@@ -192,6 +260,8 @@ Print some reports::
Decimal('0.00')
>>> gl_revenue.end_balance
Decimal('-10.00')
>>> gl_revenue.line_count
0
>>> context = {
... 'company': company.id,
@@ -199,17 +269,32 @@ Print some reports::
... 'from_date': period_3.start_date,
... }
>>> with config.set_context(context):
... gl_child_revenue, = GeneralLedgerAccount.find([
... ('account', '=', child_revenue.id),
... ])
... gl_revenue, = GeneralLedgerAccount.find([
... ('account', '=', revenue.id),
... ])
>>> gl_child_revenue.start_balance
Decimal('0.00')
>>> gl_child_revenue.credit
Decimal('10.00')
>>> gl_child_revenue.debit
Decimal('0.00')
>>> gl_child_revenue.end_balance
Decimal('-10.00')
>>> gl_child_revenue.line_count
1
>>> gl_revenue.start_balance
Decimal('0.00')
>>> gl_revenue.credit
Decimal('10.00')
Decimal('0.00')
>>> gl_revenue.debit
Decimal('0.00')
>>> gl_revenue.end_balance
Decimal('-10.00')
>>> gl_revenue.line_count
0
>>> context = {
... 'company': company.id,
@@ -217,9 +302,22 @@ Print some reports::
... 'from_date': period_5.start_date,
... }
>>> with config.set_context(context):
... gl_child_revenue, = GeneralLedgerAccount.find([
... ('account', '=', child_revenue.id),
... ])
... gl_revenue, = GeneralLedgerAccount.find([
... ('account', '=', revenue.id),
... ])
>>> gl_child_revenue.start_balance
Decimal('-10.00')
>>> gl_child_revenue.credit
Decimal('0.00')
>>> gl_child_revenue.debit
Decimal('0.00')
>>> gl_child_revenue.end_balance
Decimal('-10.00')
>>> gl_child_revenue.line_count
0
>>> gl_revenue.start_balance
Decimal('-10.00')
>>> gl_revenue.credit
@@ -228,6 +326,8 @@ Print some reports::
Decimal('0.00')
>>> gl_revenue.end_balance
Decimal('-10.00')
>>> gl_revenue.line_count
0
>>> trial_balance = Report('account.trial_balance', context={
... 'company': company.id,
+1
View File
@@ -4,6 +4,7 @@ this repository contains the full copyright notices and license terms. -->
<tree keyword_open="1">
<field name="account" expand="1"/>
<field name="start_balance" sum="Start Balance" optional="0"/>
<field name="line_count" optional="1"/>
<field name="debit" sum="Debit" optional="0"/>
<field name="credit" sum="Credit" optional="0"/>
<field name="end_balance" sum="End Balance" optional="0"/>