diff --git a/CHANGELOG b/CHANGELOG
index 68df9a59d6..5a4ebc30fc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,4 @@
+* New reports design: General Ledger, Trial Balance and Aged Balance
* Add Python3 support
* Merge Third Party Balance into Aged Balance
* Add date to Aged Balance
diff --git a/__init__.py b/__init__.py
index 2a77933b59..4a3f377dd6 100644
--- a/__init__.py
+++ b/__init__.py
@@ -24,16 +24,19 @@ def register():
Account,
AccountDeferral,
OpenChartAccountStart,
- PrintGeneralLedgerStart,
- PrintTrialBalanceStart,
- OpenBalanceSheetStart,
- OpenIncomeStatementStart,
+ GeneralLedgerAccount,
+ GeneralLedgerAccountContext,
+ GeneralLedgerLine,
+ GeneralLedgerLineContext,
+ BalanceSheetContext,
+ IncomeStatementContext,
CreateChartStart,
CreateChartAccount,
CreateChartProperties,
UpdateChartStart,
UpdateChartSucceed,
- OpenAgedBalanceStart,
+ AgedBalanceContext,
+ AgedBalance,
Configuration,
Period,
JournalType,
@@ -80,13 +83,8 @@ def register():
BalanceNonDeferral,
CloseFiscalYear,
OpenChartAccount,
- PrintGeneralLedger,
- PrintTrialBalance,
- OpenBalanceSheet,
- OpenIncomeStatement,
CreateChart,
UpdateChart,
- OpenAgedBalance,
ClosePeriod,
ReOpenPeriod,
OpenJournalCash,
@@ -106,6 +104,6 @@ def register():
Pool.register(
GeneralLedger,
TrialBalance,
- AgedBalance,
+ AgedBalanceReport,
GeneralJournal,
module='account', type_='report')
diff --git a/account.py b/account.py
index e9d0bc40de..347762fc0f 100644
--- a/account.py
+++ b/account.py
@@ -2,33 +2,31 @@
# this repository contains the full copyright notices and license terms.
from decimal import Decimal
import datetime
-import operator
-from itertools import izip, groupby
from functools import wraps
-from sql import Column, Null
-from sql.aggregate import Sum
+from sql import Column, Null, Window, Literal
+from sql.aggregate import Sum, Max
from sql.conditionals import Coalesce, Case
from trytond.model import ModelView, ModelSQL, fields, Unique
from trytond.wizard import Wizard, StateView, StateAction, StateTransition, \
- StateReport, Button
+ Button
from trytond.report import Report
from trytond.tools import reduce_ids, grouped_slice
-from trytond.pyson import Eval, PYSONEncoder, Date
+from trytond.pyson import Eval, PYSONEncoder
from trytond.transaction import Transaction
from trytond.pool import Pool
from trytond import backend
__all__ = ['TypeTemplate', 'Type', 'OpenType', 'AccountTemplate', 'Account',
'AccountDeferral', 'OpenChartAccountStart', 'OpenChartAccount',
- 'PrintGeneralLedgerStart', 'PrintGeneralLedger', 'GeneralLedger',
- 'PrintTrialBalanceStart', 'PrintTrialBalance', 'TrialBalance',
- 'OpenBalanceSheetStart', 'OpenBalanceSheet',
- 'OpenIncomeStatementStart', 'OpenIncomeStatement',
+ 'GeneralLedgerAccount', 'GeneralLedgerAccountContext',
+ 'GeneralLedgerLine', 'GeneralLedgerLineContext',
+ 'GeneralLedger', 'TrialBalance',
+ 'BalanceSheetContext', 'IncomeStatementContext',
+ 'AgedBalanceContext', 'AgedBalance', 'AgedBalanceReport',
'CreateChartStart', 'CreateChartAccount', 'CreateChartProperties',
- 'CreateChart', 'UpdateChartStart', 'UpdateChartSucceed', 'UpdateChart',
- 'OpenAgedBalanceStart', 'OpenAgedBalance', 'AgedBalance']
+ 'CreateChart', 'UpdateChartStart', 'UpdateChartSucceed', 'UpdateChart']
def inactive_records(func):
@@ -1000,9 +998,129 @@ class OpenChartAccount(Wizard):
return 'end'
-class PrintGeneralLedgerStart(ModelView):
- 'Print General Ledger'
- __name__ = 'account.print_general_ledger.start'
+class GeneralLedgerAccount(ModelSQL, ModelView):
+ 'General Ledger Account'
+ __name__ = 'account.general_ledger.account'
+
+ # TODO reuse rec_name of Account
+ name = fields.Char('Name')
+ code = fields.Char('Code')
+ active = fields.Boolean('Active')
+ company = fields.Many2One('company.company', 'Company')
+ start_debit = fields.Function(fields.Numeric('Start Debit',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'get_account')
+ debit = fields.Function(fields.Numeric('Debit',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'get_debit_credit')
+ end_debit = fields.Function(fields.Numeric('End Debit',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'get_account')
+ start_credit = fields.Function(fields.Numeric('Start Credit',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'get_account')
+ credit = fields.Function(fields.Numeric('Credit',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'get_debit_credit')
+ end_credit = fields.Function(fields.Numeric('End Credit',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'get_account')
+ start_balance = fields.Function(fields.Numeric('Start Balance',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'get_account')
+ end_balance = fields.Function(fields.Numeric('End Balance',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits']), 'get_account')
+ lines = fields.One2Many('account.general_ledger.line', 'account', 'Lines',
+ readonly=True)
+ general_ledger_balance = fields.Boolean('General Ledger Balance')
+ currency_digits = fields.Function(fields.Integer('Currency Digits'),
+ 'get_currency_digits')
+
+ @classmethod
+ def __setup__(cls):
+ super(GeneralLedgerAccount, cls).__setup__()
+ cls._order.insert(0, ('code', 'ASC'))
+ cls._order.insert(1, ('name', 'ASC'))
+
+ @classmethod
+ def table_query(cls):
+ pool = Pool()
+ context = Transaction().context
+ Account = pool.get('account.account')
+ account = Account.__table__()
+ columns = []
+ for fname, field in cls._fields.iteritems():
+ if not hasattr(field, 'set'):
+ columns.append(Column(account, fname).as_(fname))
+ return account.select(*columns,
+ where=(account.company == context.get('company'))
+ & (account.kind != 'view'))
+
+ @classmethod
+ def get_period_ids(cls, name):
+ pool = Pool()
+ Period = pool.get('account.period')
+ context = Transaction().context
+
+ period = None
+ if name.startswith('start_'):
+ period_ids = [0]
+ if context.get('start_period'):
+ period = Period(context['start_period'])
+ elif name.startswith('end_'):
+ period_ids = []
+ if context.get('end_period'):
+ period = Period(context['end_period'])
+
+ if period:
+ periods = Period.search([
+ ('fiscalyear', '=', context.get('fiscalyear')),
+ ('end_date', '<=', period.start_date),
+ ])
+ if periods:
+ period_ids = [p.id for p in periods]
+ return period_ids
+
+ @classmethod
+ def get_account(cls, records, name):
+ pool = Pool()
+ Account = pool.get('account.account')
+
+ period_ids = cls.get_period_ids(name)
+ with Transaction().set_context(periods=period_ids):
+ accounts = Account.browse(records)
+ fname = name
+ for test in ['start_', 'end_']:
+ if name.startswith(test):
+ fname = name[len(test):]
+ break
+ return {a.id: getattr(a, fname) for a in accounts}
+
+ @classmethod
+ def get_debit_credit(cls, records, name):
+ pool = Pool()
+ Account = pool.get('account.account')
+
+ start_period_ids = cls.get_period_ids('start_%s' % name)
+ end_period_ids = cls.get_period_ids('end_%s' % name)
+ periods_ids = list(
+ set(end_period_ids).difference(set(start_period_ids)))
+ with Transaction().set_context(periods=periods_ids):
+ accounts = Account.browse(records)
+ return {a.id: getattr(a, name) for a in accounts}
+
+ def get_currency_digits(self, name):
+ return self.company.currency.digits
+
+ def get_rec_name(self, name):
+ # TODO add start/end balance
+ return self.name
+
+
+class GeneralLedgerAccountContext(ModelView):
+ 'General Ledger Account Context'
+ __name__ = 'account.general_ledger.account.context'
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
required=True)
start_period = fields.Many2One('account.period', 'Start Period',
@@ -1018,64 +1136,145 @@ class PrintGeneralLedgerStart(ModelView):
depends=['fiscalyear', 'start_period'])
company = fields.Many2One('company.company', 'Company', required=True)
posted = fields.Boolean('Posted Move', help='Show only posted move')
- empty_account = fields.Boolean('Empty Account',
- help='With account without move')
- @staticmethod
- def default_fiscalyear():
- FiscalYear = Pool().get('account.fiscalyear')
- return FiscalYear.find(
- Transaction().context.get('company'), exception=False)
+ @classmethod
+ def default_fiscalyear(cls):
+ pool = Pool()
+ FiscalYear = pool.get('account.fiscalyear')
+ context = Transaction().context
+ return context.get(
+ 'fiscalyear',
+ FiscalYear.find(context.get('company'), exception=False))
- @staticmethod
- def default_company():
+ @classmethod
+ def default_start_period(cls):
+ return Transaction().context.get('start_period')
+
+ @classmethod
+ def default_end_period(cls):
+ return Transaction().context.get('end_period')
+
+ @classmethod
+ def default_company(cls):
return Transaction().context.get('company')
- @staticmethod
- def default_posted():
- return False
+ @classmethod
+ def default_posted(cls):
+ return Transaction().context.get('posted', False)
- @staticmethod
- def default_empty_account():
- return False
-
- @fields.depends('fiscalyear')
+ @fields.depends('fiscalyear', 'start_period', 'end_period')
def on_change_fiscalyear(self):
- self.start_period = None
- self.end_period = None
+ if (self.start_period
+ and self.start_period.fiscalyear != self.fiscalyear):
+ self.start_period = None
+ if (self.end_period
+ and self.end_period.fiscalyear != self.fiscalyear):
+ self.end_period = None
-class PrintGeneralLedger(Wizard):
- 'Print General Ledger'
- __name__ = 'account.print_general_ledger'
- start = StateView('account.print_general_ledger.start',
- 'account.print_general_ledger_start_view_form', [
- Button('Cancel', 'end', 'tryton-cancel'),
- Button('Print', 'print_', 'tryton-print', default=True),
- ])
- print_ = StateReport('account.general_ledger')
+class GeneralLedgerLine(ModelSQL, ModelView):
+ 'General Ledger Line'
+ __name__ = 'account.general_ledger.line'
- def do_print_(self, action):
- if self.start.start_period:
- start_period = self.start.start_period.id
- else:
- start_period = None
- if self.start.end_period:
- end_period = self.start.end_period.id
- else:
- end_period = None
- data = {
- 'company': self.start.company.id,
- 'fiscalyear': self.start.fiscalyear.id,
- 'start_period': start_period,
- 'end_period': end_period,
- 'posted': self.start.posted,
- 'empty_account': self.start.empty_account,
- }
- return action, data
+ move = fields.Many2One('account.move', 'Move')
+ date = fields.Date('Date')
+ account = fields.Many2One('account.general_ledger.account', 'Account')
+ party = fields.Many2One('party.party', 'Party',
+ states={
+ 'invisible': ~Eval('party_required', False),
+ },
+ depends=['party_required'])
+ party_required = fields.Function(fields.Boolean('Party Required'),
+ 'get_party_required')
+ company = fields.Many2One('company.company', 'Company')
+ debit = fields.Numeric('Debit',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits'])
+ credit = fields.Numeric('Credit',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits'])
+ balance = fields.Numeric('Balance',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits'])
+ origin = fields.Reference('Origin', selection='get_origin')
+ description = fields.Char('Description')
+ move_description = fields.Char('Move Description')
+ state = fields.Selection([
+ ('draft', 'Draft'),
+ ('posted', 'Posted'),
+ ], 'State')
+ state_string = state.translated('state')
+ currency_digits = fields.Function(fields.Integer('Currency Digits'),
+ 'get_currency_digits')
- def transition_print_(self):
- return 'end'
+ @classmethod
+ def __setup__(cls):
+ super(GeneralLedgerLine, cls).__setup__()
+ cls._order.insert(0, ('date', 'ASC'))
+
+ @classmethod
+ def table_query(cls):
+ pool = Pool()
+ Line = pool.get('account.move.line')
+ Move = pool.get('account.move')
+ Account = pool.get('account.general_ledger.account')
+ context = Transaction().context
+ line = Line.__table__()
+ move = Move.__table__()
+ columns = []
+ for fname, field in cls._fields.iteritems():
+ if hasattr(field, 'set'):
+ continue
+ field_line = getattr(Line, fname, None)
+ if fname == 'balance':
+ # TODO replace the test by a generic one on backend
+ if backend.name() == 'postgresql':
+ w_columns = [line.account]
+ if context.get('party_cumulate', False):
+ w_columns.append(line.party)
+ column = Sum(line.debit - line.credit,
+ window=Window(w_columns,
+ order_by=[move.date.asc, line.id])).as_('balance')
+ else:
+ column = (line.debit - line.credit).as_('balance')
+ elif fname == 'move_description':
+ column = Column(move, 'description').as_(fname)
+ elif (not field_line
+ or fname == 'state'
+ or isinstance(field_line, fields.Function)):
+ column = Column(move, fname).as_(fname)
+ else:
+ column = Column(line, fname).as_(fname)
+ columns.append(column)
+ start_period_ids = set(Account.get_period_ids('start_balance'))
+ end_period_ids = set(Account.get_period_ids('end_balance'))
+ period_ids = list(end_period_ids.difference(start_period_ids))
+ with Transaction().set_context(periods=period_ids):
+ line_query, fiscalyear_ids = Line.query_get(line)
+ return line.join(move, condition=line.move == move.id
+ ).select(*columns, where=line_query)
+
+ def get_party_required(self, name):
+ return self.account.party_required
+
+ def get_currency_digits(self, name):
+ return self.company.currency.digits
+
+ @classmethod
+ def get_origin(cls):
+ Line = Pool().get('account.move.line')
+ return Line.get_origin()
+
+
+class GeneralLedgerLineContext(GeneralLedgerAccountContext):
+ 'General Ledger Line Context'
+ __name__ = 'account.general_ledger.line.context'
+
+ party_cumulate = fields.Boolean('Cumulate per Party')
+
+ @classmethod
+ def default_party_cumulate(cls):
+ return False
class GeneralLedger(Report):
@@ -1083,326 +1282,61 @@ class GeneralLedger(Report):
@classmethod
def get_context(cls, records, data):
+ pool = Pool()
+ Company = pool.get('company.company')
+ Fiscalyear = pool.get('account.fiscalyear')
+ Period = pool.get('account.period')
+ context = Transaction().context
+
report_context = super(GeneralLedger, cls).get_context(records, data)
- pool = Pool()
- Account = pool.get('account.account')
- Period = pool.get('account.period')
- Company = pool.get('company.company')
+ report_context['company'] = Company(context['company'])
+ report_context['fiscalyear'] = Fiscalyear(context['fiscalyear'])
- company = Company(data['company'])
-
- accounts = Account.search([
- ('company', '=', data['company']),
- ('kind', '!=', 'view'),
- ], order=[('code', 'ASC'), ('id', 'ASC')])
-
- start_period_ids = [0]
- start_periods = []
- if data['start_period']:
- start_period = Period(data['start_period'])
- start_periods = Period.search([
- ('fiscalyear', '=', data['fiscalyear']),
- ('end_date', '<=', start_period.start_date),
- ])
- start_period_ids += [p.id for p in start_periods]
- else:
- start_period = None
-
- with Transaction().set_context(
- fiscalyear=data['fiscalyear'],
- periods=start_period_ids,
- posted=data['posted']):
- start_accounts = Account.browse(accounts)
- id2start_account = {}
- for account in start_accounts:
- id2start_account[account.id] = account
-
- end_period_ids = []
- if data['end_period']:
- end_period = Period(data['end_period'])
- end_periods = Period.search([
- ('fiscalyear', '=', data['fiscalyear']),
- ('end_date', '<=', end_period.start_date),
- ])
- if end_period not in end_periods:
- end_periods.append(end_period)
- else:
- end_periods = Period.search([
- ('fiscalyear', '=', data['fiscalyear']),
- ])
- end_period = None
- end_period_ids = [p.id for p in end_periods]
-
- with Transaction().set_context(
- fiscalyear=data['fiscalyear'],
- periods=end_period_ids,
- posted=data['posted']):
- end_accounts = Account.browse(accounts)
- id2end_account = {}
- for account in end_accounts:
- id2end_account[account.id] = account
-
- if not data['empty_account']:
- account2lines = dict(cls.get_lines(accounts,
- end_periods, data['posted']))
- accounts = Account.browse([a.id for a in accounts
- if a in account2lines])
-
- account_id2lines = cls.lines(
- [a for a in accounts if not a.general_ledger_balance],
- list(set(end_periods).difference(set(start_periods))),
- data['posted'])
-
- report_context['accounts'] = accounts
- report_context['id2start_account'] = id2start_account
- report_context['id2end_account'] = id2end_account
- report_context['digits'] = company.currency.digits
- report_context['lines'] = \
- lambda account_id: account_id2lines[account_id]
- report_context['company'] = company
- report_context['start_period'] = start_period
- report_context['end_period'] = end_period
+ for period in ['start_period', 'end_period']:
+ if context.get(period):
+ report_context[period] = Period(context[period])
+ else:
+ report_context[period] = None
+ report_context['accounts'] = records
return report_context
- @classmethod
- def get_lines(cls, accounts, periods, posted):
- MoveLine = Pool().get('account.move.line')
- clause = [
- ('account', 'in', [a.id for a in accounts]),
- ('period', 'in', [p.id for p in periods]),
- ('state', '!=', 'draft'),
- ]
- if posted:
- clause.append(('move.state', '=', 'posted'))
- lines = MoveLine.search(clause,
- order=[
- ('account.id', 'ASC'),
- ('date', 'ASC'),
- ])
- return groupby(lines, operator.attrgetter('account'))
-
- @classmethod
- def lines(cls, accounts, periods, posted):
- Move = Pool().get('account.move')
- res = dict((a.id, []) for a in accounts)
- account2lines = cls.get_lines(accounts, periods, posted)
-
- state_selections = dict(Move.fields_get(
- fields_names=['state'])['state']['selection'])
-
- for account, lines in account2lines:
- balance = Decimal('0.0')
- for line in lines:
- balance += line.debit - line.credit
- res[account.id].append({
- 'date': line.date,
- 'move': line.move.rec_name,
- 'debit': line.debit,
- 'credit': line.credit,
- 'balance': balance,
- 'description': '\n'.join(
- (line.move.description or '',
- line.description or '')).strip(),
- 'origin': (line.move.origin.rec_name
- if line.move.origin else ''),
- 'state': state_selections.get(line.move.state,
- line.move.state),
- })
- return res
-
-
-class PrintTrialBalanceStart(ModelView):
- 'Print Trial Balance'
- __name__ = 'account.print_trial_balance.start'
- fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
- required=True)
- start_period = fields.Many2One('account.period', 'Start Period',
- domain=[
- ('fiscalyear', '=', Eval('fiscalyear')),
- ('start_date', '<=', (Eval('end_period'), 'start_date'))
- ],
- depends=['end_period', 'fiscalyear'])
- end_period = fields.Many2One('account.period', 'End Period',
- domain=[
- ('fiscalyear', '=', Eval('fiscalyear')),
- ('start_date', '>=', (Eval('start_period'), 'start_date'))
- ],
- depends=['start_period', 'fiscalyear'])
- company = fields.Many2One('company.company', 'Company', required=True)
- posted = fields.Boolean('Posted Move', help='Show only posted move')
- empty_account = fields.Boolean('Empty Account',
- help='With account without move')
-
- @staticmethod
- def default_fiscalyear():
- FiscalYear = Pool().get('account.fiscalyear')
- return FiscalYear.find(
- Transaction().context.get('company'), exception=False)
-
- @staticmethod
- def default_company():
- return Transaction().context.get('company')
-
- @staticmethod
- def default_posted():
- return False
-
- @staticmethod
- def default_empty_account():
- return False
-
- @fields.depends('fiscalyear')
- def on_change_fiscalyear(self):
- self.start_period = None
- self.end_period = None
-
-
-class PrintTrialBalance(Wizard):
- 'Print Trial Balance'
- __name__ = 'account.print_trial_balance'
- start = StateView('account.print_trial_balance.start',
- 'account.print_trial_balance_start_view_form', [
- Button('Cancel', 'end', 'tryton-cancel'),
- Button('Print', 'print_', 'tryton-print', default=True),
- ])
- print_ = StateReport('account.trial_balance')
-
- def do_print_(self, action):
- if self.start.start_period:
- start_period = self.start.start_period.id
- else:
- start_period = None
- if self.start.end_period:
- end_period = self.start.end_period.id
- else:
- end_period = None
- data = {
- 'company': self.start.company.id,
- 'fiscalyear': self.start.fiscalyear.id,
- 'start_period': start_period,
- 'end_period': end_period,
- 'posted': self.start.posted,
- 'empty_account': self.start.empty_account,
- }
- return action, data
-
- def transition_print_(self):
- return 'end'
-
class TrialBalance(Report):
__name__ = 'account.trial_balance'
@classmethod
def get_context(cls, records, data):
+ pool = Pool()
+ Company = pool.get('company.company')
+ Fiscalyear = pool.get('account.fiscalyear')
+ Period = pool.get('account.period')
+ context = Transaction().context
+
report_context = super(TrialBalance, cls).get_context(records, data)
- pool = Pool()
- Account = pool.get('account.account')
- Period = pool.get('account.period')
- Company = pool.get('company.company')
+ report_context['company'] = Company(context['company'])
+ report_context['fiscalyear'] = Fiscalyear(context['fiscalyear'])
- company = Company(data['company'])
-
- accounts = Account.search([
- ('company', '=', data['company']),
- ('kind', '!=', 'view'),
- ])
-
- start_periods = []
- if data['start_period']:
- start_period = Period(data['start_period'])
- start_periods = Period.search([
- ('fiscalyear', '=', data['fiscalyear']),
- ('end_date', '<=', start_period.start_date),
- ])
-
- if data['end_period']:
- end_period = Period(data['end_period'])
- end_periods = Period.search([
- ('fiscalyear', '=', data['fiscalyear']),
- ('end_date', '<=', end_period.start_date),
- ])
- end_periods = list(set(end_periods).difference(
- set(start_periods)))
- if end_period not in end_periods:
- end_periods.append(end_period)
- else:
- end_periods = Period.search([
- ('fiscalyear', '=', data['fiscalyear']),
- ])
- end_periods = list(set(end_periods).difference(
- set(start_periods)))
-
- start_period_ids = [p.id for p in start_periods] or [0]
- end_period_ids = [p.id for p in end_periods]
-
- with Transaction().set_context(
- fiscalyear=data['fiscalyear'],
- periods=start_period_ids,
- posted=data['posted']):
- start_accounts = Account.browse(accounts)
-
- with Transaction().set_context(
- fiscalyear=None,
- periods=end_period_ids,
- posted=data['posted']):
- in_accounts = Account.browse(accounts)
-
- with Transaction().set_context(
- fiscalyear=data['fiscalyear'],
- periods=start_period_ids + end_period_ids,
- posted=data['posted']):
- end_accounts = Account.browse(accounts)
-
- to_remove = set()
- if not data['empty_account']:
- for account in in_accounts:
- if account.debit == Decimal('0.0') \
- and account.credit == Decimal('0.0'):
- to_remove.add(account)
-
- accounts = []
- for start_account, in_account, end_account in izip(
- start_accounts, in_accounts, end_accounts):
- if in_account in to_remove:
- continue
- accounts.append({
- 'code': start_account.code,
- 'name': start_account.name,
- 'start_balance': start_account.balance,
- 'debit': in_account.debit,
- 'credit': in_account.credit,
- 'end_balance': end_account.balance,
- })
-
- periods = end_periods
-
- report_context['accounts'] = accounts
- periods.sort(key=operator.attrgetter('start_date'))
- report_context['start_period'] = periods[0]
- periods.sort(key=operator.attrgetter('end_date'))
- report_context['end_period'] = periods[-1]
- report_context['company'] = company
- report_context['digits'] = company.currency.digits
- report_context['sum'] = \
- lambda accounts, field: cls.sum(accounts, field)
+ for period in ['start_period', 'end_period']:
+ if context.get(period):
+ report_context[period] = Period(context[period])
+ else:
+ report_context[period] = None
+ report_context['accounts'] = records
+ report_context['sum'] = cls.sum
return report_context
@classmethod
def sum(cls, accounts, field):
- amount = Decimal('0.0')
- for account in accounts:
- amount += account[field]
- return amount
+ return sum((getattr(a, field) for a in accounts), Decimal('0'))
-class OpenBalanceSheetStart(ModelView):
- 'Open Balance Sheet'
- __name__ = 'account.open_balance_sheet.start'
+class BalanceSheetContext(ModelView):
+ 'Balance Sheet Context'
+ __name__ = 'account.balance_sheet.context'
date = fields.Date('Date', required=True)
company = fields.Many2One('company.company', 'Company', required=True)
posted = fields.Boolean('Posted Move', help='Show only posted move')
@@ -1421,45 +1355,9 @@ class OpenBalanceSheetStart(ModelView):
return False
-class OpenBalanceSheet(Wizard):
- 'Open Balance Sheet'
- __name__ = 'account.open_balance_sheet'
- start = StateView('account.open_balance_sheet.start',
- 'account.open_balance_sheet_start_view_form', [
- Button('Cancel', 'end', 'tryton-cancel'),
- Button('Open', 'open_', 'tryton-ok', default=True),
- ])
- open_ = StateAction('account.act_account_balance_sheet_tree')
-
- def do_open_(self, action):
- pool = Pool()
- Lang = pool.get('ir.lang')
-
- company = self.start.company
- lang, = Lang.search([
- ('code', '=', Transaction().language),
- ])
-
- date = Lang.strftime(self.start.date, lang.code, lang.date)
-
- action['pyson_context'] = PYSONEncoder().encode({
- 'date': Date(self.start.date.year,
- self.start.date.month,
- self.start.date.day),
- 'posted': self.start.posted,
- 'company': company.id,
- 'cumulate': True,
- })
- action['name'] += ' %s - %s' % (date, company.rec_name)
- return action, {}
-
- def transition_open_(self):
- return 'end'
-
-
-class OpenIncomeStatementStart(ModelView):
- 'Open Income Statement'
- __name__ = 'account.open_income_statement.start'
+class IncomeStatementContext(ModelView):
+ 'Income Statement Context'
+ __name__ = 'account.income_statement.context'
fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
required=True)
start_period = fields.Many2One('account.period', 'Start Period',
@@ -1497,50 +1395,224 @@ class OpenIncomeStatementStart(ModelView):
self.end_period = None
-class OpenIncomeStatement(Wizard):
- 'Open Income Statement'
- __name__ = 'account.open_income_statement'
- start = StateView('account.open_income_statement.start',
- 'account.open_income_statement_start_view_form', [
- Button('Cancel', 'end', 'tryton-cancel'),
- Button('Open', 'open_', 'tryton-ok', default=True),
- ])
- open_ = StateAction('account.act_account_income_statement_tree')
+class AgedBalanceContext(ModelView):
+ 'Aged Balance Context'
+ __name__ = 'account.aged_balance.context'
+ type = fields.Selection([
+ ('customer', 'Customers'),
+ ('supplier', 'Suppliers'),
+ ('customer_supplier', 'Customers and Suppliers'),
+ ],
+ "Type", required=True)
+ date = fields.Date('Date', required=True)
+ term1 = fields.Integer("First Term", required=True)
+ term2 = fields.Integer("Second Term", required=True,
+ domain=[
+ ('term2', '>', Eval('term1', 0)),
+ ],
+ depends=['term1'])
+ term3 = fields.Integer("Third Term", required=True,
+ domain=[
+ ('term3', '>', Eval('term2', 0)),
+ ],
+ depends=['term2'])
+ unit = fields.Selection([
+ ('day', 'Days'),
+ ('month', 'Months'),
+ ], "Unit", required=True)
+ company = fields.Many2One('company.company', 'Company', required=True)
+ posted = fields.Boolean('Posted Move', help='Show only posted move')
- def do_open_(self, action):
+ @classmethod
+ def default_type(cls):
+ return 'customer'
+
+ @classmethod
+ def default_posted(cls):
+ return False
+
+ @classmethod
+ def default_date(cls):
+ return Pool().get('ir.date').today()
+
+ @staticmethod
+ def default_term1():
+ return 30
+
+ @staticmethod
+ def default_term2():
+ return 60
+
+ @staticmethod
+ def default_term3():
+ return 90
+
+ @staticmethod
+ def default_unit():
+ return 'day'
+
+ @staticmethod
+ def default_company():
+ return Transaction().context.get('company')
+
+
+class AgedBalance(ModelSQL, ModelView):
+ 'Aged Balance'
+ __name__ = 'account.aged_balance'
+
+ party = fields.Many2One('party.party', 'Party')
+ company = fields.Many2One('company.company', 'Company')
+ term0 = fields.Numeric('Now',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits'])
+ term1 = fields.Numeric('First Term',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits'])
+ term2 = fields.Numeric('Second Term',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits'])
+ term3 = fields.Numeric('Third Term',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits'])
+ balance = fields.Numeric('Balance',
+ digits=(16, Eval('currency_digits', 2)),
+ depends=['currency_digits'])
+ currency_digits = fields.Function(fields.Integer('Currency Digits'),
+ 'get_currency_digits')
+
+ @classmethod
+ def __setup__(cls):
+ super(AgedBalance, cls).__setup__()
+ cls._order.insert(0, ('party', 'ASC'))
+
+ @classmethod
+ def table_query(cls):
pool = Pool()
- Period = pool.get('account.period')
+ context = Transaction().context
+ MoveLine = pool.get('account.move.line')
+ Move = pool.get('account.move')
+ Reconciliation = pool.get('account.move.reconciliation')
+ Account = pool.get('account.account')
- start_periods = []
- if self.start.start_period:
- start_periods = Period.search([
- ('fiscalyear', '=', self.start.fiscalyear.id),
- ('end_date', '<=', self.start.start_period.start_date),
- ])
+ line = MoveLine.__table__()
+ move = Move.__table__()
+ reconciliation = Reconciliation.__table__()
+ account = Account.__table__()
- end_periods = []
- if self.start.end_period:
- end_periods = Period.search([
- ('fiscalyear', '=', self.start.fiscalyear.id),
- ('end_date', '<=', self.start.end_period.start_date),
- ])
- end_periods = list(set(end_periods).difference(
- set(start_periods)))
- if self.start.end_period not in end_periods:
- end_periods.append(self.start.end_period)
+ company_id = context.get('company')
+ date = context.get('date')
+ with Transaction().set_context(date=None):
+ line_query, _ = MoveLine.query_get(line)
+ kind = cls.get_kind()
+ columns = [
+ line.party.as_('id'),
+ Literal(0).as_('create_uid'),
+ Max(line.create_date).as_('create_date'),
+ Literal(0).as_('write_uid'),
+ Max(line.write_date).as_('write_date'),
+ line.party.as_('party'),
+ move.company.as_('company'),
+ (Sum(line.debit) - Sum(line.credit)).as_('balance'),
+ ]
+
+ terms = cls.get_terms()
+ factor = cls.get_unit_factor()
+ term_values = sorted(terms.values())
+
+ for name, value in terms.iteritems():
+ if value is None or factor is None or date is None:
+ columns.append(Literal(None).as_(name))
+ continue
+ cond = line.maturity_date <= (date - value * factor)
+ idx = term_values.index(value)
+ if idx + 1 < len(terms):
+ cond &= line.maturity_date > (
+ date - term_values[idx + 1] * factor)
+ else:
+ cond |= line.maturity_date == Null
+ columns.append(
+ Sum(Case((cond, line.debit - line.credit), else_=0)).as_(name))
+
+ return line.join(move, condition=line.move == move.id
+ ).join(account, condition=line.account == account.id
+ ).join(reconciliation, 'LEFT',
+ condition=reconciliation.id == line.reconciliation
+ ).select(*columns,
+ where=(line.party != Null)
+ & (account.active == True)
+ & account.kind.in_(kind)
+ & ((line.reconciliation == Null)
+ | (reconciliation.date > date))
+ & (move.date <= date)
+ & (account.company == company_id)
+ & line_query,
+ group_by=(line.party, move.company))
+
+ @classmethod
+ def get_terms(cls):
+ context = Transaction().context
+ return {
+ 'term0': 0,
+ 'term1': context.get('term1'),
+ 'term2': context.get('term2'),
+ 'term3': context.get('term3'),
+ }
+
+ @classmethod
+ def get_unit_factor(cls):
+ context = Transaction().context
+ unit = context.get('unit', 'day')
+ if unit == 'month':
+ return datetime.timedelta(days=30)
+ elif unit == 'day':
+ return datetime.timedelta(days=1)
+
+ @classmethod
+ def get_kind(cls):
+ context = Transaction().context
+ type_ = context.get('type', 'customer')
+ if type_ == 'customer_supplier':
+ return ['payable', 'receivable']
+ elif type_ == 'supplier':
+ return ['payable']
+ elif type_ == 'customer':
+ return ['receivable']
else:
- end_periods = Period.search([
- ('fiscalyear', '=', self.start.fiscalyear.id),
- ])
- end_periods = list(set(end_periods).difference(
- set(start_periods)))
+ return []
- action['pyson_context'] = PYSONEncoder().encode({
- 'periods': [p.id for p in end_periods],
- 'posted': self.start.posted,
- 'company': self.start.company.id,
- })
- return action, {}
+ def get_currency_digits(self, name):
+ return self.company.currency.digits
+
+
+class AgedBalanceReport(Report):
+ __name__ = 'account.aged_balance'
+
+ @classmethod
+ def get_context(cls, records, data):
+ pool = Pool()
+ Company = pool.get('company.company')
+ Context = pool.get('account.aged_balance.context')
+ AgedBalance = pool.get('account.aged_balance')
+ context = Transaction().context
+
+ report_context = super(AgedBalanceReport, cls).get_context(
+ records, data)
+
+ context_fields = Context.fields_get(['type', 'unit'])
+
+ report_context['company'] = Company(context['company'])
+ report_context['date'] = context['date']
+ report_context['type'] = dict(
+ context_fields['type']['selection'])[context['type']]
+ report_context['unit'] = dict(
+ context_fields['unit']['selection'])[context['unit']]
+ report_context.update(AgedBalance.get_terms())
+ report_context['sum'] = cls.sum
+ return report_context
+
+ @classmethod
+ def sum(cls, records, field):
+ return sum((getattr(r, field) for r in records), Decimal('0'))
class CreateChartStart(ModelView):
@@ -1851,194 +1923,3 @@ class UpdateChart(Wizard):
tax_rule_line_template.create_rule_line(template2tax,
template2rule, template2rule_line=template2rule_line)
return 'succeed'
-
-
-class OpenAgedBalanceStart(ModelView):
- 'Open Aged Balance'
- __name__ = 'account.open_aged_balance.start'
- company = fields.Many2One('company.company', 'Company', required=True)
- balance_type = fields.Selection(
- [('customer', 'Customer'), ('supplier', 'Supplier'), ('both', 'Both')],
- "Type", required=True)
- date = fields.Date('Date', required=True)
- term1 = fields.Integer("First Term", required=True)
- term2 = fields.Integer("Second Term", required=True,
- domain=[
- ('term2', '>', Eval('term1', 0)),
- ],
- depends=['term1'])
- term3 = fields.Integer("Third Term", required=True,
- domain=[
- ('term3', '>', Eval('term2', 0)),
- ],
- depends=['term2'])
- unit = fields.Selection(
- [('day', 'Day'), ('month', 'Month')], "Unit", required=True)
- posted = fields.Boolean('Posted Move', help='Show only posted move')
-
- @staticmethod
- def default_balance_type():
- return "customer"
-
- @staticmethod
- def default_posted():
- return False
-
- @classmethod
- def default_date(cls):
- return Pool().get('ir.date').today()
-
- @staticmethod
- def default_term1():
- return 30
-
- @staticmethod
- def default_term2():
- return 60
-
- @staticmethod
- def default_term3():
- return 90
-
- @staticmethod
- def default_unit():
- return 'day'
-
- @staticmethod
- def default_company():
- return Transaction().context.get('company')
-
-
-class OpenAgedBalance(Wizard):
- 'Open Aged Party Balance'
- __name__ = 'account.open_aged_balance'
- start = StateView('account.open_aged_balance.start',
- 'account.open_aged_balance_start_view_form', [
- Button('Cancel', 'end', 'tryton-cancel'),
- Button('Print', 'print_', 'tryton-print', default=True),
- ])
- print_ = StateReport('account.aged_balance')
-
- @classmethod
- def __setup__(cls):
- super(OpenAgedBalance, cls).__setup__()
- cls._error_messages.update({
- 'warning': 'Warning',
- 'term_overlap_desc': 'You cannot define overlapping terms',
- })
-
- def do_print_(self, action):
- if not (self.start.term1 < self.start.term2 < self.start.term3):
- self.raise_user_error(error="warning",
- error_description="term_overlap_desc")
- data = {
- 'company': self.start.company.id,
- 'date': self.start.date,
- 'term1': self.start.term1,
- 'term2': self.start.term2,
- 'term3': self.start.term3,
- 'unit': self.start.unit,
- 'posted': self.start.posted,
- 'balance_type': self.start.balance_type,
- }
- return action, data
-
- def transition_print_(self):
- return 'end'
-
-
-class AgedBalance(Report):
- __name__ = 'account.aged_balance'
-
- @classmethod
- def get_context(cls, records, data):
- report_context = super(AgedBalance, cls).get_context(records, data)
-
- pool = Pool()
- Party = pool.get('party.party')
- MoveLine = pool.get('account.move.line')
- Move = pool.get('account.move')
- Reconciliation = pool.get('account.move.reconciliation')
- Account = pool.get('account.account')
- Company = pool.get('company.company')
- cursor = Transaction().connection.cursor()
-
- line = MoveLine.__table__()
- move = Move.__table__()
- reconciliation = Reconciliation.__table__()
- account = Account.__table__()
-
- company = Company(data['company'])
- report_context['digits'] = company.currency.digits
- report_context['posted'] = data['posted']
- with Transaction().set_context(context=report_context):
- line_query, _ = MoveLine.query_get(line)
-
- terms = (0, data['term1'], data['term2'], data['term3'])
- if data['unit'] == 'month':
- coef = datetime.timedelta(days=30)
- else:
- coef = datetime.timedelta(days=1)
-
- kind = {
- 'both': ('payable', 'receivable'),
- 'supplier': ('payable',),
- 'customer': ('receivable',),
- }[data['balance_type']]
-
- report_context['date'] = date = data['date']
- res = {}
- for position, term in enumerate(terms):
- term_query = line.maturity_date <= (date - term * coef)
- if position + 1 < len(terms):
- term_query &= line.maturity_date > (
- date - terms[position + 1] * coef)
- else:
- term_query |= line.maturity_date == Null
-
- cursor.execute(*line.join(move, condition=line.move == move.id
- ).join(account, condition=line.account == account.id
- ).join(reconciliation, 'LEFT',
- condition=reconciliation.id == line.reconciliation
- ).select(line.party, Sum(line.debit) - Sum(line.credit),
- where=(line.party != Null)
- & (account.active == True)
- & account.kind.in_(kind)
- & ((line.reconciliation == Null)
- | (reconciliation.date > date))
- & (move.date <= date)
- & (account.company == data['company'])
- & term_query & line_query,
- group_by=line.party,
- having=(Sum(line.debit) - Sum(line.credit)) != 0))
- for party, solde in cursor.fetchall():
- if party in res:
- res[party][position] = solde
- else:
- res[party] = [(i[0] == position) and solde
- or Decimal("0.0") for i in enumerate(terms)]
- parties = Party.search([
- ('id', 'in', [k for k in res.iterkeys()]),
- ])
-
- report_context['main_title'] = data['balance_type']
- report_context['unit'] = data['unit']
- total = 0
- for i in range(len(terms)):
- report_context['total' + str(i)] = sum(
- (v[i] for v in res.itervalues()))
- total += report_context['total' + str(i)]
- report_context['term' + str(i)] = terms[i]
- report_context['total'] = total
-
- report_context['company'] = company
- report_context['parties'] = [{
- 'name': p.rec_name,
- 'balance': sum(res[p.id]),
- 'amount0': res[p.id][0],
- 'amount1': res[p.id][1],
- 'amount2': res[p.id][2],
- 'amount3': res[p.id][3],
- } for p in parties]
-
- return report_context
diff --git a/account.xml b/account.xml
index dff06932d4..d838e22d35 100644
--- a/account.xml
+++ b/account.xml
@@ -417,50 +417,118 @@ this repository contains the full copyright notices and license terms. -->
open_chart_start_form
-
- account.print_general_ledger.start
- form
- print_general_legder_start_form
-
-
-
- Print General Legder
- account.print_general_ledger
-
-
-
General Ledger
-
+ account.general_ledger.account
account.general_ledger
account/general_ledger.odt
-
-
- account.print_trial_balance.start
- form
- print_trial_balance_start_form
+
+ form_print
+ account.general_ledger.account,-1
+
-
- Print Trial Balance
- account.print_trial_balance
-
-
-
Trial Balance
-
+ account.general_ledger.account
account.trial_balance
account/trial_balance.odt
+
+ form_print
+ account.general_ledger.account,-1
+
+
-
- account.open_balance_sheet.start
+
+ account.general_ledger.account
+ tree
+ general_ledger_account_list
+
+
+
+ General Ledger - Accounts
+ account.general_ledger.account
+ account.general_ledger.account.context
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ account.general_ledger.line
+ tree
+ general_ledger_line_list
+
+
+
+ General Ledger - Lines
+ account.general_ledger.line
+ account.general_ledger.line.context
+
+
+
+
+
+
+
+
+ tree_open
+ account.general_ledger.account,-1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ account.general_ledger.account.context
form
- open_balance_sheet_start_form
+ general_ledger_account_context_form
+
+
+
+ account.general_ledger.line.context
+
+ general_ledger_line_context_form
@@ -472,9 +540,11 @@ this repository contains the full copyright notices and license terms. -->
Balance Sheet
account.account.type
+ account.balance_sheet.context
+
@@ -482,18 +552,13 @@ this repository contains the full copyright notices and license terms. -->
-
- Open Balance Sheet
- account.open_balance_sheet
-
-
+
-
- account.open_income_statement.start
+
+ account.balance_sheet.context
form
- open_income_statement_start_form
+ balance_sheet_context_form
@@ -505,6 +570,7 @@ this repository contains the full copyright notices and license terms. -->
Income Statement
account.account.type
+ account.income_statement.context
@@ -515,31 +581,49 @@ this repository contains the full copyright notices and license terms. -->
-
- Open Income Statement
- account.open_income_statement
-
-
+
-
- account.open_aged_balance.start
+
+ account.income_statement.context
form
- open_aged_balance_start_form
+ income_statement_context_form
+
+
+
+ account.aged_balance
+ tree
+ aged_balance_list
+
+
+ Aged Balance
+ account.aged_balance
+ account.aged_balance.context
+
+
+
+
+
+
+
+
+
+
+ account.aged_balance.context
+ form
+ aged_balance_context_form
Aged Balance
-
+ account.aged_balance
account.aged_balance
account/aged_balance.odt
-
- Open Aged Balance
- account.open_aged_balance
+
+ form_print
+ account.aged_balance,-1
+
-
diff --git a/aged_balance.odt b/aged_balance.odt
index c0ca768e1d..82b91286a6 100644
Binary files a/aged_balance.odt and b/aged_balance.odt differ
diff --git a/general_ledger.odt b/general_ledger.odt
index de55c2f403..8b85b84d6d 100644
Binary files a/general_ledger.odt and b/general_ledger.odt differ
diff --git a/move.xml b/move.xml
index 86283cafb9..8110b94f20 100644
--- a/move.xml
+++ b/move.xml
@@ -300,6 +300,7 @@ this repository contains the full copyright notices and license terms. -->
account.move.line,-1
+
Unreconcile Lines
diff --git a/tests/scenario_reports.rst b/tests/scenario_reports.rst
index 01ee57ec9f..5deff0f5c6 100644
--- a/tests/scenario_reports.rst
+++ b/tests/scenario_reports.rst
@@ -79,18 +79,36 @@ Create a moves::
Print some reports::
- >>> print_general_ledger = Wizard('account.print_general_ledger')
- >>> print_general_ledger.form.start_period = None
- >>> print_general_ledger.form.end_period = None
- >>> print_general_ledger.execute('print_')
+ >>> GeneralLedgerAccount = Model.get('account.general_ledger.account')
+ >>> gl_accounts = GeneralLedgerAccount.find([])
- >>> print_trial_balance = Wizard('account.print_trial_balance')
- >>> print_trial_balance.form.start_period = None
- >>> print_trial_balance.form.end_period = None
- >>> print_trial_balance.execute('print_')
+ >>> general_ledger = Report('account.general_ledger', context={
+ ... 'company': company.id,
+ ... 'fiscalyear': fiscalyear.id,
+ ... })
+ >>> _ = general_ledger.execute(gl_accounts)
- >>> aged_balance = Wizard('account.open_aged_balance')
- >>> aged_balance.execute('print_')
+ >>> trial_balance = Report('account.trial_balance', context={
+ ... 'company': company.id,
+ ... 'fiscalyear': fiscalyear.id,
+ ... })
+ >>> _ = trial_balance.execute(gl_accounts)
+
+ >>> AgedBalance = Model.get('account.aged_balance')
+ >>> context = {
+ ... 'company': company.id,
+ ... 'type': 'customer',
+ ... 'date': today,
+ ... 'term1': 30,
+ ... 'term2': 60,
+ ... 'term3': 90,
+ ... 'unit': 'day',
+ ... }
+ >>> with config.set_context(context):
+ ... aged_balances = AgedBalance.find([])
+
+ >>> aged_balance = Report('account.aged_balance', context=context)
+ >>> _ = aged_balance.execute(aged_balances)
>>> print_general_journal = Wizard('account.move.print_general_journal')
>>> print_general_journal.execute('print_')
diff --git a/trial_balance.odt b/trial_balance.odt
index dfc0bc7993..7c7b38f4f4 100644
Binary files a/trial_balance.odt and b/trial_balance.odt differ
diff --git a/view/open_aged_balance_start_form.xml b/view/aged_balance_context_form.xml
similarity index 72%
rename from view/open_aged_balance_start_form.xml
rename to view/aged_balance_context_form.xml
index 2fd86af7e5..e60b91fa67 100644
--- a/view/open_aged_balance_start_form.xml
+++ b/view/aged_balance_context_form.xml
@@ -1,25 +1,22 @@
-
diff --git a/view/aged_balance_list.xml b/view/aged_balance_list.xml
new file mode 100644
index 0000000000..088d9b28cb
--- /dev/null
+++ b/view/aged_balance_list.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/view/open_balance_sheet_start_form.xml b/view/balance_sheet_context_form.xml
similarity index 88%
rename from view/open_balance_sheet_start_form.xml
rename to view/balance_sheet_context_form.xml
index b7db0b7a5e..85e04b19c2 100644
--- a/view/open_balance_sheet_start_form.xml
+++ b/view/balance_sheet_context_form.xml
@@ -1,7 +1,7 @@
-
diff --git a/view/general_ledger_account_list.xml b/view/general_ledger_account_list.xml
new file mode 100644
index 0000000000..06109ff169
--- /dev/null
+++ b/view/general_ledger_account_list.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/view/general_ledger_line_context_form.xml b/view/general_ledger_line_context_form.xml
new file mode 100644
index 0000000000..c790348477
--- /dev/null
+++ b/view/general_ledger_line_context_form.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/view/general_ledger_line_list.xml b/view/general_ledger_line_list.xml
new file mode 100644
index 0000000000..e48cfe6a55
--- /dev/null
+++ b/view/general_ledger_line_list.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/view/open_income_statement_start_form.xml b/view/income_statement_context_form.xml
similarity index 92%
rename from view/open_income_statement_start_form.xml
rename to view/income_statement_context_form.xml
index 65cfc3b83e..c8ae0b8c5d 100644
--- a/view/open_income_statement_start_form.xml
+++ b/view/income_statement_context_form.xml
@@ -1,7 +1,7 @@
-