first commit
This commit is contained in:
149
modules/account/company.py
Normal file
149
modules/account/company.py
Normal file
@@ -0,0 +1,149 @@
|
||||
# This file is part of 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 import Literal, Null
|
||||
from sql.aggregate import Sum
|
||||
from sql.conditionals import Coalesce
|
||||
|
||||
from trytond import backend
|
||||
from trytond.i18n import gettext
|
||||
from trytond.model import fields
|
||||
from trytond.model.exceptions import AccessError
|
||||
from trytond.modules.currency.fields import Monetary
|
||||
from trytond.pool import Pool, PoolMeta
|
||||
from trytond.tools import grouped_slice, reduce_ids, sqlite_apply_types
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class Company(metaclass=PoolMeta):
|
||||
__name__ = 'company.company'
|
||||
|
||||
receivable = fields.Function(Monetary(
|
||||
"Receivable", currency='currency', digits='currency'),
|
||||
'get_receivable_payable', searcher='search_receivable_payable')
|
||||
payable = fields.Function(Monetary(
|
||||
"Payable", currency='currency', digits='currency'),
|
||||
'get_receivable_payable', searcher='search_receivable_payable')
|
||||
receivable_today = fields.Function(Monetary(
|
||||
"Receivable Today", currency='currency', digits='currency'),
|
||||
'get_receivable_payable', searcher='search_receivable_payable')
|
||||
payable_today = fields.Function(Monetary(
|
||||
"Payable Today", currency='currency', digits='currency'),
|
||||
'get_receivable_payable', searcher='search_receivable_payable')
|
||||
|
||||
@classmethod
|
||||
def get_receivable_payable(cls, companies, names):
|
||||
amounts = {}
|
||||
pool = Pool()
|
||||
MoveLine = pool.get('account.move.line')
|
||||
Account = pool.get('account.account')
|
||||
AccountType = pool.get('account.account.type')
|
||||
Date = pool.get('ir.date')
|
||||
cursor = Transaction().connection.cursor()
|
||||
|
||||
line = MoveLine.__table__()
|
||||
account = Account.__table__()
|
||||
account_type = AccountType.__table__()
|
||||
|
||||
for name in names:
|
||||
assert name in {
|
||||
'receivable', 'payable', 'receivable_today', 'payable_today'}
|
||||
amounts[name] = dict.fromkeys(map(int, companies), Decimal(0))
|
||||
|
||||
exp = {
|
||||
c.id: Decimal(str(10.0 ** -c.currency.digits)) for c in companies}
|
||||
today = Date.today()
|
||||
|
||||
amount = Sum(Coalesce(line.debit, 0) - Coalesce(line.credit, 0))
|
||||
for name in names:
|
||||
if name.endswith('_today'):
|
||||
code = name[:-len('_today')]
|
||||
today_where = (
|
||||
(line.maturity_date <= today)
|
||||
| (line.maturity_date == Null))
|
||||
else:
|
||||
code = name
|
||||
today_where = Literal(True)
|
||||
for sub_companies in grouped_slice(companies):
|
||||
sub_ids = [p.id for p in sub_companies]
|
||||
company_where = reduce_ids(account.company, sub_ids)
|
||||
query = (line
|
||||
.join(account,
|
||||
condition=account.id == line.account)
|
||||
.join(account_type,
|
||||
condition=account.type == account_type.id)
|
||||
.select(account.company.as_('id'), amount.as_(name),
|
||||
where=(getattr(account_type, code)
|
||||
& (line.reconciliation == Null)
|
||||
& company_where
|
||||
& today_where),
|
||||
group_by=account.company))
|
||||
if backend.name == 'sqlite':
|
||||
sqlite_apply_types(query, [None, 'NUMERIC'])
|
||||
cursor.execute(*query)
|
||||
for company_id, value in cursor:
|
||||
amounts[name][company_id] = value.quantize(exp[company_id])
|
||||
return amounts
|
||||
|
||||
@classmethod
|
||||
def search_receivable_payable(cls, name, clause):
|
||||
pool = Pool()
|
||||
MoveLine = pool.get('account.move.line')
|
||||
Account = pool.get('account.account')
|
||||
AccountType = pool.get('account.account.type')
|
||||
Date = pool.get('ir.date')
|
||||
|
||||
line = MoveLine.__table__()
|
||||
account = Account.__table__()
|
||||
account_type = AccountType.__table__()
|
||||
|
||||
assert name in {
|
||||
'receivable', 'payable', 'receivable_today', 'payable_today'}
|
||||
_, operator, value = clause
|
||||
|
||||
today = Date.today()
|
||||
|
||||
if name.endswith('_today'):
|
||||
code = name[:-len('_today')]
|
||||
today_query = ((line.maturity_date <= today)
|
||||
| (line.maturity_date == Null))
|
||||
else:
|
||||
code = name
|
||||
today_query = Literal(True)
|
||||
|
||||
Operator = fields.SQL_OPERATORS[operator]
|
||||
|
||||
# Need to cast numeric for sqlite
|
||||
cast_ = MoveLine.debit.sql_cast
|
||||
amount = cast_(Sum(Coalesce(line.debit, 0) - Coalesce(line.credit, 0)))
|
||||
if operator in {'in', 'not in'}:
|
||||
value = [cast_(Literal(Decimal(v or 0))) for v in value]
|
||||
else:
|
||||
value = cast_(Literal(Decimal(value or 0)))
|
||||
query = (line
|
||||
.join(account, condition=account.id == line.account)
|
||||
.join(account_type, condition=account.type == account_type.id)
|
||||
.select(account.company,
|
||||
where=(getattr(account_type, code)
|
||||
& (line.reconciliation == Null)
|
||||
& today_query),
|
||||
group_by=account.company,
|
||||
having=Operator(amount, value)))
|
||||
return [('id', 'in', query)]
|
||||
|
||||
@classmethod
|
||||
def check_modification(cls, mode, companies, values=None, external=False):
|
||||
pool = Pool()
|
||||
Move = pool.get('account.move')
|
||||
super().check_modification(
|
||||
mode, companies, values=values, external=external)
|
||||
if mode == 'write':
|
||||
if 'currency' in values:
|
||||
moves = Move.search([
|
||||
('company', 'in', [c.id for c in companies]),
|
||||
],
|
||||
limit=1, order=[])
|
||||
if moves:
|
||||
raise AccessError(gettext(
|
||||
'account.msg_company_change_currency'))
|
||||
Reference in New Issue
Block a user