trytond-account_reports/common.py

182 lines
6.8 KiB
Python
Raw Permalink Normal View History

2020-06-05 12:43:20 +02:00
# This file is part of account_reports for tryton. The COPYRIGHT file
# at the top level of this repository contains the full copyright notices and
# license terms.
from decimal import Decimal
from sql.aggregate import Sum
from sql.conditionals import Coalesce
from sql.operators import In
from trytond.pool import Pool, PoolMeta
from trytond.tools import reduce_ids
from trytond.transaction import Transaction
__all__ = ['FiscalYear', 'Account', 'Party']
class FiscalYear(metaclass=PoolMeta):
__name__ = 'account.fiscalyear'
def get_periods(self, start_period, end_period):
pool = Pool()
Period = pool.get('account.period')
domain = [('fiscalyear', '=', self)]
if start_period:
domain += [('start_date', '>=', start_period.start_date)]
domain += [('end_date', '>=', start_period.end_date)]
if end_period:
domain += [('start_date', '<=', end_period.start_date)]
domain += [('end_date', '<=', end_period.end_date)]
periods = Period.search(domain)
return periods
class AccountTemplate(metaclass=PoolMeta):
__name__ = 'account.account.template'
@classmethod
def __setup__(cls):
super(AccountTemplate, cls).__setup__()
# hide because used in odt report
cls.general_ledger_balance.states['invisible'] = True
class Account(metaclass=PoolMeta):
__name__ = 'account.account'
@classmethod
def __setup__(cls):
super(Account, cls).__setup__()
# hide because used in odt report
cls.general_ledger_balance.states['invisible'] = True
@classmethod
def read_account_vals(cls, accounts, with_moves=False,
exclude_party_moves=False):
pool = Pool()
Account = pool.get('account.account')
Move = pool.get('account.move')
MoveLine = pool.get('account.move.line')
line = MoveLine.__table__()
move = Move.__table__()
table_a = Account.__table__()
table_c = Account.__table__()
in_max = 3000
values = {}
transaction = Transaction()
cursor = transaction.connection.cursor()
move_join = 'INNER' if with_moves else 'LEFT'
if not accounts:
accounts = Account.search([
('company', '=', transaction.context.get('company')),
])
account_ids = [a.id for a in accounts]
group_by = (table_a.id,)
columns = (group_by + (Sum(Coalesce(line.debit, 0)).as_('debit'),
Sum(Coalesce(line.credit, 0)).as_('credit'),
(Sum(Coalesce(line.debit, 0)) -
Sum(Coalesce(line.credit, 0))).as_('balance')))
for i in range(0, len(account_ids), in_max):
sub_ids = account_ids[i:i + in_max]
red_sql = reduce_ids(table_a.id, sub_ids)
where = red_sql
periods = transaction.context.get('periods', False)
if periods:
periods.append(0)
where = (where & In(Coalesce(move.period, 0), periods))
date = transaction.context.get('date')
if date:
where &= (move.date <= date)
if exclude_party_moves:
# This "where" not use account kind (before a change use it)
# because there are some companies that the accounts kind and
# party_required use in a different way that "standard".
# For example if you check the prty_required an account with
# the kind equal to 'other'
where = (where & (line.party == None))
cursor.execute(*table_a.join(table_c,
condition=(table_c.left >= table_a.left)
& (table_c.right <= table_a.right)
).join(line, move_join,
condition=line.account == table_c.id
).join(move, move_join,
condition=move.id == line.move
).select(*columns, where=where, group_by=group_by))
for account, debit, credit, balance in cursor.fetchall():
# SQLite uses float for SUM
if not isinstance(credit, Decimal):
credit = Decimal(str(credit))
if not isinstance(debit, Decimal):
debit = Decimal(str(debit))
if not isinstance(balance, Decimal):
balance = Decimal(str(balance))
values[account] = {
'credit': credit,
'debit': debit,
'balance': balance,
}
return values
class Party(metaclass=PoolMeta):
__name__ = 'party.party'
@classmethod
def get_account_values_by_party(cls, parties, accounts, company):
'''
Function to compute credit,debit and balance for party ids.
'''
res = {}
pool = Pool()
Move = pool.get('account.move')
MoveLine = pool.get('account.move.line')
Account = pool.get('account.account')
transaction = Transaction()
context = transaction.context
cursor = transaction.connection.cursor()
move = Move.__table__()
line = MoveLine.__table__()
account = Account.__table__()
group_by = (line.party, line.account,)
columns = (group_by + (Sum(Coalesce(line.debit, 0)).as_('debit'),
Sum(Coalesce(line.credit, 0)).as_('credit'),
(Sum(Coalesce(line.debit, 0)) -
Sum(Coalesce(line.credit, 0))).as_('balance')))
line_query, _ = MoveLine.query_get(line)
if context.get('date'):
# Cumulate data from previous fiscalyears
line_query = line.move.in_(move.select(move.id,
where=move.date <= context.get('date')))
where = (line_query &
(account.company == company.id))
if accounts:
where = where & line.account.in_([a.id for a in accounts])
if parties:
where = where & line.party.in_([p.id for p in parties])
cursor.execute(*line.join(account,
condition=(line.account == account.id)
).select(*columns, where=where, group_by=group_by))
for party, account, debit, credit, balance in cursor.fetchall():
# SQLite uses float for SUM
if not isinstance(credit, Decimal):
credit = Decimal(str(credit))
if not isinstance(debit, Decimal):
debit = Decimal(str(debit))
if not isinstance(balance, Decimal):
balance = Decimal(str(balance))
if account not in res:
res[account] = {}
res[account][party] = {
'credit': credit,
'debit': debit,
'balance': balance,
}
return res