trytond-account_reports/common.py

211 lines
7.6 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 datetime import datetime
2020-06-05 12:43:20 +02:00
from sql.aggregate import Sum
from sql.conditionals import Coalesce
from sql.operators import In
from trytond.model import fields
2020-06-05 12:43:20 +02:00
from trytond.pool import Pool, PoolMeta
from trytond.tools import reduce_ids
from trytond.transaction import Transaction
class TimeoutException(Exception):
pass
class TimeoutChecker:
def __init__(self, timeout, callback):
self._timeout = timeout
self._callback = callback
self._start = datetime.now()
@property
def elapsed(self):
return (datetime.now() - self._start).seconds
def check(self):
if self.elapsed > self._timeout:
self._callback()
class Configuration(metaclass=PoolMeta):
__name__ = 'account.configuration'
default_timeout = fields.Integer('Timeout (s)')
2020-06-05 12:43:20 +02:00
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 html_read_account_vals(cls, accounts, company, with_moves=False,
exclude_party_moves=False, final_accounts=False):
2020-06-05 12:43:20 +02:00
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', '=', company),
])
if final_accounts:
account_ids = [a.id for a in accounts if not a.childs]
else:
account_ids = [a.id for a in accounts]
2020-06-05 12:43:20 +02:00
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)
where &= (move.date <= date)
where &= (move.company == company.id)
2020-06-05 12:43:20 +02:00
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 html_get_account_values_by_party(cls, parties, accounts, company):
2020-06-05 12:43:20 +02:00
'''
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