#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 trytond.model import ModelView, ModelSQL, fields from decimal import Decimal class Party(ModelSQL, ModelView): _name = 'party.party' account_payable = fields.Property(type='many2one', relation='account.account', string='Account Payable', domain=[('kind', '=', 'payable'), "('company', '=', company)"], states={ 'required': "globals().get('company') and bool(company)", 'invisible': "not globals().get('company') or not bool(company)", }) account_receivable = fields.Property(type='many2one', relation='account.account', string='Account Receivable', domain=[('kind', '=', 'receivable'), "('company', '=', company)"], states={ 'required': "globals().get('company') and bool(company)", 'invisible': "not globals().get('company') or not bool(company)", }) customer_tax_rule = fields.Property(type='many2one', relation='account.tax.rule', string='Customer Tax Rule', domain=["('company', '=', company)"], states={ 'invisible': "not globals().get('company') or not bool(company)", }, help='Apply this rule on taxes when party is customer.') supplier_tax_rule = fields.Property(type='many2one', relation='account.tax.rule', string='Supplier Tax Rule', domain=["('company', '=', company)"], states={ 'invisible': "not globals().get('company') or not bool(company)", }, help='Apply this rule on taxes when party is supplier.') receivable = fields.Function('get_receivable_payable', fnct_search='search_receivable_payable', string='Receivable') payable = fields.Function('get_receivable_payable', fnct_search='search_receivable_payable', string='Payable') receivable_today = fields.Function('get_receivable_payable', fnct_search='search_receivable_payable', string='Receivable Today') payable_today = fields.Function('get_receivable_payable', fnct_search='search_receivable_payable', string='Payable Today') def get_receivable_payable(self, cursor, user_id, ids, names, arg, context=None): ''' Function to compute receivable, payable (today or not) for party ids. :param cursor: the database cursor :param user: the user id :param ids: the ids of the party :param names: the list of field name to compute :param arg: optional argument :param context: the context :return: a dictionary with all field names as key and a dictionary as value with id as key ''' res = {} move_line_obj = self.pool.get('account.move.line') company_obj = self.pool.get('company.company') user_obj = self.pool.get('res.user') date_obj = self.pool.get('ir.date') if context is None: context = {} for name in names: if name not in ('receivable', 'payable', 'receivable_today', 'payable_today'): raise Exception('Bad argument') res[name] = dict((x, Decimal('0.0')) for x in ids) if not ids: return {} company_id = None user = user_obj.browse(cursor, user_id, user_id, context=context) if context.get('company'): child_company_ids = company_obj.search(cursor, user_id, [ ('parent', 'child_of', [user.main_company.id]), ], order=[], context=context) if context['company'] in child_company_ids: company_id = context['company'] if not company_id: company_id = user.company.id or user.main_company.id if not company_id: return res line_query, _ = move_line_obj.query_get(cursor, user_id, context=context) for name in names: code = name today_query = '' today_value = [] if name in ('receivable_today', 'payable_today'): code = name[:-6] today_query = 'AND (l.maturity_date <= %s ' \ 'OR l.maturity_date IS NULL) ' today_value = [date_obj.today(cursor, user, context=context)] cursor.execute('SELECT l.party, ' \ 'SUM((COALESCE(l.debit, 0) - COALESCE(l.credit, 0))) ' \ 'FROM account_move_line AS l, ' \ 'account_account AS a ' \ 'WHERE a.id = l.account ' \ 'AND a.active ' \ 'AND a.kind = %s ' \ 'AND l.party IN ' \ '(' + ','.join(('%s',) * len(ids)) + ') ' \ 'AND l.reconciliation IS NULL ' \ 'AND ' + line_query + ' ' \ + today_query + \ 'AND a.company = %s ' \ 'GROUP BY l.party', [code,] + ids + today_value + [company_id]) for party_id, sum in cursor.fetchall(): res[name][party_id] = sum return res def search_receivable_payable(self, cursor, user_id, name, args, context=None): if not len(args): return [] move_line_obj = self.pool.get('account.move.line') company_obj = self.pool.get('company.company') user_obj = self.pool.get('res.user') date_obj = self.pool.get('ir.date') if context is None: context = {} if name not in ('receivable', 'payable', 'receivable_today', 'payable_today'): raise Exception('Bad argument') company_id = None user = user_obj.browse(cursor, user_id, user_id, context=context) if context.get('company'): child_company_ids = company_obj.search(cursor, user_id, [ ('parent', 'child_of', [user.main_company.id]), ], context=context) if context['company'] in child_company_ids: company_id = context['company'] if not company_id: company_id = user.company.id or user.main_company.id if not company_id: return [] code = name today_query = '' today_value = [] if name in ('receivable_today', 'payable_today'): code = name[:-6] today_query = 'AND (l.maturity_date <= %s ' \ 'OR l.maturity_date IS NULL) ' today_value = [date_obj.today(cursor, user, context=context)] line_query, _ = move_line_obj.query_get(cursor, user_id, context=context) cursor.execute('SELECT l.party ' \ 'FROM account_move_line AS l, ' \ 'account_account AS a ' \ 'WHERE a.id = l.account ' \ 'AND a.active ' \ 'AND a.kind = %s ' \ 'AND l.party IS NOT NULL ' \ 'AND l.reconciliation IS NULL ' \ 'AND ' + line_query + ' ' \ + today_query + \ 'AND a.company = %s ' \ 'GROUP BY l.party ' \ 'HAVING ' + \ 'AND'.join('(SUM((COALESCE(l.debit, 0) - COALESCE(l.credit, 0))) ' \ + ' ' + x[1] + ' %s) ' for x in args), [code] + today_value + [company_id] + [x[2] for x in args]) return [('id', 'in', [x[0] for x in cursor.fetchall()])] Party()