diff --git a/CHANGELOG b/CHANGELOG
index abbd3b59f8..81a4ba59f2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -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
diff --git a/account.py b/account.py
index b8b800a975..bd5c7a8756 100644
--- a/account.py
+++ b/account.py
@@ -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')
diff --git a/account.xml b/account.xml
index 778f3c67e3..af1ce91e7e 100644
--- a/account.xml
+++ b/account.xml
@@ -550,6 +550,7 @@ this repository contains the full copyright notices and license terms. -->
General Ledger - Accounts
account.general_ledger.account
account.general_ledger.account.context
+
diff --git a/fiscalyear.py b/fiscalyear.py
index 89c34799d8..1ffc9dcff4 100644
--- a/fiscalyear.py
+++ b/fiscalyear.py
@@ -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
diff --git a/tests/scenario_reports.rst b/tests/scenario_reports.rst
index 98baef7118..217d421049 100644
--- a/tests/scenario_reports.rst
+++ b/tests/scenario_reports.rst
@@ -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,
diff --git a/view/general_ledger_account_list.xml b/view/general_ledger_account_list.xml
index 4b4b18904a..79ce6b37ea 100644
--- a/view/general_ledger_account_list.xml
+++ b/view/general_ledger_account_list.xml
@@ -4,6 +4,7 @@ this repository contains the full copyright notices and license terms. -->
+