diff --git a/account.py b/account.py
index f6e87a301d..539e495dc1 100644
--- a/account.py
+++ b/account.py
@@ -1405,3 +1405,194 @@ class ThirdPartyBalance(Report):
return objects
ThirdPartyBalance()
+
+
+class OpenAgedBalanceInit(WizardOSV):
+ _name = 'account.account.open_aged_balance.init'
+ company = fields.Many2One('company.company', 'Company', required=True)
+ fiscalyear = fields.Many2One('account.fiscalyear', 'Fiscal Year',
+ required=True)
+ balance_type = fields.Selection(
+ [('customer', 'Customer'), ('supplier', 'Supplier'), ('both', 'Both')],
+ "Type", required=True)
+ term1 = fields.Integer("First Term", required=True)
+ term2 = fields.Integer("Second Term", required=True)
+ term3 = fields.Integer("Third Term", required=True)
+ unit = fields.selection(
+ [('day', 'Day'), ('month', 'Month')], "Unit", required=True)
+ posted = fields.Boolean('Posted Move', help='Only posted move')
+
+ def default_fiscalyear(self, cursor, user, context=None):
+ fiscalyear_obj = self.pool.get('account.fiscalyear')
+ if context is None:
+ context = {}
+ fiscalyear_id = fiscalyear_obj.find(cursor, user,
+ context.get('company', False), exception=False, context=context)
+ if fiscalyear_id:
+ return fiscalyear_obj.name_get(cursor, user, fiscalyear_id,
+ context=context)[0]
+ return False
+
+ def default_balance_type(self, cursor, user, context=None):
+ return "customer"
+
+ def default_posted(self, cursor, user, context=None):
+ return False
+
+ def default_term1(self, cursor, user, context=None):
+ return 30
+
+ def default_term2(self, cursor, user, context=None):
+ return 60
+
+ def default_term3(self, cursor, user, context=None):
+ return 90
+
+ def default_unit(self, cursor, user, context=None):
+ return 'day'
+
+ def default_company(self, cursor, user, context=None):
+ if context is None:
+ context = {}
+ company_obj = self.pool.get('company.company')
+ if context.get('company'):
+ return company_obj.name_get(cursor, user, context['company'],
+ context=context)[0]
+ return False
+
+OpenAgedBalanceInit()
+
+
+class OpenAgedBalance(Wizard):
+ 'Open Aged Party Balance'
+ _name = 'account.account.open_aged_balance'
+
+ def __init__(self):
+ super(OpenAgedBalance, self).__init__()
+ self._error_messages.update({
+ 'warning': 'Warning',
+ 'term_overlap_desc': 'You cannot define overlapping terms'})
+ states = {
+ 'init': {
+ 'result': {
+ 'type': 'form',
+ 'object': 'account.account.open_aged_balance.init',
+ 'state': [
+ ('end', 'Cancel', 'tryton-cancel'),
+ ('print', 'Print', 'tryton-ok', True),
+ ],
+ },
+ },
+ 'print': {
+ 'actions': ['check',],
+ 'result': {
+ 'type': 'print',
+ 'report': 'account.account.aged_balance',
+ 'state': 'end',
+ },
+ },
+ }
+
+ def check(self, cursor, user, datas, context=None):
+ if not (datas['form']['term1'] < datas['form']['term2'] \
+ < datas['form']['term3']):
+ self.raise_user_error(cursor, error="warning",
+ error_description="term_overlap_desc")
+ return {}
+
+OpenAgedBalance()
+
+
+class AgedBalance(Report):
+ _name = 'account.account.aged_balance'
+
+ def _get_objects(self, cursor, user, ids, model, datas, context):
+ import traceback
+ traceback.print_stack()
+ party_obj = self.pool.get('relationship.party')
+ move_line_obj = self.pool.get('account.move.line')
+ company_obj = self.pool.get('company.company')
+ company = company_obj.browse(cursor, user,
+ datas['form']['company'], context=context)
+ context['company'] = company
+ context['digits'] = company.currency.digits
+ context['fiscalyear'] = datas['form']['fiscalyear']
+ line_query = move_line_obj.query_get(cursor, user, context=context)
+ if datas['form']['posted']:
+ posted_clause = "and m.state = 'posted' "
+ else:
+ posted_clause = ""
+
+ terms = (datas['form']['term1'],
+ datas['form']['term2'],
+ datas['form']['term3'])
+ if datas['form']['unit'] == 'month':
+ coef = 30
+ else:
+ coef = 1
+
+ kind = {'both': ('payable','receivable'),
+ 'supplier': ('payable',),
+ 'customer': ('receivable',),
+ }[datas['form']['balance_type']]
+
+ res = {}
+ for position in range(len(terms)):
+ if position == 0:
+ term_query = '(l.maturity_date <= %s '\
+ 'OR l.maturity_date IS NULL) '
+ term_args = (datetime.date.today() + \
+ datetime.timedelta(days=terms[position]*coef),)
+ else:
+ term_query = '(l.maturity_date <= %s '\
+ 'AND l.maturity_date >= %s) '
+ term_args = (
+ datetime.date.today() + \
+ datetime.timedelta(days=terms[position]*coef),
+ datetime.date.today() + \
+ datetime.timedelta(days=terms[position-1]*coef),
+ )
+
+ cursor.execute(
+ 'SELECT l.party, SUM(l.debit) - SUM(l.credit) ' \
+ 'FROM account_move_line l ' \
+ 'JOIN account_move m on (l.move = m.id) '
+ 'JOIN account_account a on (l.account = a.id) '
+ 'WHERE l.party is not null '\
+ 'AND a.active ' \
+ 'AND a.kind in ('+ ','.join('%s' for i in kind) + ") "\
+ 'AND l.reconciliation IS NULL ' \
+ 'AND a.company = %s ' \
+ 'AND '+ term_query+\
+ 'AND ' + line_query + ' ' \
+ + posted_clause + \
+ 'GROUP BY l.party',
+ kind + (datas['form']['company'],) + term_args)
+ for party, solde in cursor.fetchall():
+ if party in res:
+ res[party][position] = solde
+ else:
+ res[party] = [i == position and solde or Decimal("0.0")\
+ for i in range(len(terms))]
+
+ context['main_title'] = {
+ 'both': u'Suppliers and Customers',
+ 'supplier': u'Suppliers',
+ 'customer': u'Customers',
+ }[datas['form']['balance_type']]
+ unit = {'day': u'Days', 'month': u'Months'}[datas['form']['unit']] #FIXME: translation !
+ for i in range(3):
+ context['total' + str(i)] = sum((v[i] for v in res.itervalues()))
+ context['title' + str(i)] = str(terms[i]) + " " + unit
+
+ parties = party_obj.name_get(
+ cursor, user, [k for k in res.iterkeys()], context=context)
+ parties.sort(lambda x,y: cmp(x[1],y[1]))
+
+ return ({'name': p[1],
+ 'amount0': res[p[0]][0],
+ 'amount1': res[p[0]][1],
+ 'amount2': res[p[0]][2],
+ } for p in parties)
+
+AgedBalance()
diff --git a/account.xml b/account.xml
index 282083f413..2148a78ced 100644
--- a/account.xml
+++ b/account.xml
@@ -713,5 +713,49 @@
id="menu_third_party_balance" icon="tryton-print"
name="Third Party Balance"/>
+
+ account.account.open_aged_balance.init
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ]]>
+
+
+
+ Aged Balance
+ relationship.partner
+ account.account.aged_balance
+ account/aged_balance.odt
+
+
+ Open Aged Balance
+ account.account.open_aged_balance
+
+
+
diff --git a/aged_balance.odt b/aged_balance.odt
new file mode 100644
index 0000000000..6c1883c16c
Binary files /dev/null and b/aged_balance.odt differ