← Back to team overview

openerp-community-reviewer team mailing list archive

[Merge] lp:~camptocamp/account-financial-report/add_aged_partner_ledger-nbi into lp:account-financial-report

 

Nicolas Bessi - Camptocamp has proposed merging lp:~camptocamp/account-financial-report/add_aged_partner_ledger-nbi into lp:account-financial-report.

Commit message:
[ADD] Aged Partner Balance webkit report. Report inherit Open Invoice Report and uses previously computed ledger lines to determin aged lines

Requested reviews:
  Account Report Core Editors (account-report-core-editor)

For more details, see:
https://code.launchpad.net/~camptocamp/account-financial-report/add_aged_partner_ledger-nbi/+merge/211040

[ADD] Aged Partner Balance webkit report. Report inherit Open Invoice Report and uses previously computed ledger lines to determin aged linesAdd aged partner balance webkit report. 
-- 
https://code.launchpad.net/~camptocamp/account-financial-report/add_aged_partner_ledger-nbi/+merge/211040
Your team Account Report Core Editors is requested to review the proposed merge of lp:~camptocamp/account-financial-report/add_aged_partner_ledger-nbi into lp:account-financial-report.
=== modified file 'account_financial_report_webkit/__openerp__.py'
--- account_financial_report_webkit/__openerp__.py	2014-03-13 10:49:47 +0000
+++ account_financial_report_webkit/__openerp__.py	2014-03-17 12:10:18 +0000
@@ -30,7 +30,7 @@
  - Partner ledger
  - Partner balance
  - Open invoices report
-
+ - Aged Partner Balance
 
 Main improvements per report:
 -----------------------------
@@ -100,6 +100,47 @@
 * Subtotal by account and partner
 * Alphabetical sorting (same as in partner balance)
 
+
+Aged Partner Balance: Summary of aged open amount per partner
+
+This report is an accounting tool helping in various tasks.
+You can credit control or partner balance provisions computation for instance.
+
+The aged balance report allows you to print balances per partner
+like the trial balance but add an extra information :
+
+* It will split balances into due amounts
+  (due date not reached à the end date of the report) and overdue amounts
+  Overdue data are also split by period.
+* For each partner following columns will be displayed:
+
+  * Total balance (all figures must match with same date partner balance report).
+     This column equals the sum of all following columns)
+
+   * Due
+   * Overdue <= 30 days
+   * Overdue <= 60 days
+   * Overdue <= 90 days
+   * Overdue <= 120 days
+   * Older
+
+Hypothesis / Contraints of aged partner balance
+
+* Overdues columns will be by default  be based on 30 days range fix number of days.
+  This can be changed by changes the RANGES constraint
+* All data will be displayed in company currency
+* When partial payments, the payment must appear in the same colums than the invoice
+  (Except if multiple payment terms)
+* Data granularity: partner (will not display figures at invoices level)
+* The report aggregate data per account with sub-totals
+* Initial balance must be calculated the same way that
+  the partner balance / Ignoring the opening entry
+  in special period (idem open invoice report)
+* Only accounts with internal type payable or receivable are considered
+  (idem open invoice report)
+* If maturity date is null then use move line date
+
+
 Limitations:
 ------------
 
@@ -147,6 +188,7 @@
                    'wizard/trial_balance_wizard_view.xml',
                    'wizard/partner_balance_wizard_view.xml',
                    'wizard/open_invoices_wizard_view.xml',
+                   'wizard/aged_partner_balance_wizard.xml',
                    'wizard/print_journal_view.xml',
                    'report_menus.xml',
                    ],

=== modified file 'account_financial_report_webkit/report/__init__.py'
--- account_financial_report_webkit/report/__init__.py	2013-09-12 20:53:27 +0000
+++ account_financial_report_webkit/report/__init__.py	2014-03-17 12:10:18 +0000
@@ -9,3 +9,4 @@
 from . import partner_balance
 from . import open_invoices
 from . import print_journal
+from . import aged_partner_balance

=== added file 'account_financial_report_webkit/report/aged_partner_balance.py'
--- account_financial_report_webkit/report/aged_partner_balance.py	1970-01-01 00:00:00 +0000
+++ account_financial_report_webkit/report/aged_partner_balance.py	2014-03-17 12:10:18 +0000
@@ -0,0 +1,405 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Author: Nicolas Bessi
+#    Copyright 2014 Camptocamp SA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+from datetime import datetime
+
+from openerp import pooler
+from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
+from openerp.tools.translate import _
+from .open_invoices import PartnersOpenInvoicesWebkit
+from .webkit_parser_header_fix import HeaderFooterTextWebKitParser
+
+
+def make_ranges(top, offset):
+    """Return sorted days ranges
+
+    :param top: maximum overdue day
+    :param offset: offset for ranges
+
+    :returns: list of sorted ranges tuples in days
+              eg. [(-100000, 0), (0, offset), (offset, n*offset), ... (top, 100000)]
+    """
+    ranges = [(n, min(n + offset, top)) for n in xrange(0, top, offset)]
+    ranges.insert(0, (-100000000000, 0))
+    ranges.append((top, 100000000000))
+    return ranges
+
+#list of overdue ranges
+RANGES = make_ranges(120, 30)
+
+
+def make_ranges_titles():
+    """Generates title to be used by mako"""
+    titles = [_('Due')]
+    titles += [_(u'Overdue ≤ %s d.') % x[1] for x in RANGES[1:-1]]
+    titles.append(_('Older'))
+    return titles
+
+#list of overdue ranges title
+RANGES_TITLES = make_ranges_titles()
+#list of payable journal types
+REC_PAY_TYPE = ('purchase', 'sale')
+#list of refund payable type
+REFUND_TYPE = ('purchase_refund', 'sale_refund')
+INV_TYPE = REC_PAY_TYPE + REFUND_TYPE
+
+
+class AccountAgedTrialBalanceWebkit(PartnersOpenInvoicesWebkit):
+    """Compute Aged Partner Balance based on result of Open Invoices"""
+
+    def __init__(self, cursor, uid, name, context=None):
+        """Constructor, refer to :class:`openerp.report.report_sxw.rml_parse`"""
+        super(AccountAgedTrialBalanceWebkit, self).__init__(cursor, uid, name,
+                                                            context=context)
+        self.pool = pooler.get_pool(self.cr.dbname)
+        self.cursor = self.cr
+        company = self.pool.get('res.users').browse(self.cr, uid, uid,
+                                                    context=context).company_id
+
+        header_report_name = ' - '.join((_('Aged Partner Balance'),
+                                         company.currency_id.name))
+
+        footer_date_time = self.formatLang(str(datetime.today()),
+                                           date_time=True)
+
+        self.localcontext.update({
+            'cr': cursor,
+            'uid': uid,
+            'company': company,
+            'ranges': self._get_ranges(),
+            'ranges_titles': self._get_ranges_titles(),
+            'report_name': _('Aged Partner Balance'),
+            'additional_args': [
+                ('--header-font-name', 'Helvetica'),
+                ('--footer-font-name', 'Helvetica'),
+                ('--header-font-size', '10'),
+                ('--footer-font-size', '6'),
+                ('--header-left', header_report_name),
+                ('--header-spacing', '2'),
+                ('--footer-left', footer_date_time),
+                ('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
+                ('--footer-line',),
+            ],
+        })
+
+    def _get_ranges(self):
+        """:returns: :cons:`RANGES`"""
+        return RANGES
+
+    def _get_ranges_titles(self):
+        """:returns: :cons: `RANGES_TITLES`"""
+        return RANGES_TITLES
+
+    def set_context(self, objects, data, ids, report_type=None):
+        """Populate aged_lines, aged_balance, aged_percents attributes
+
+        on each account browse record that will be used by mako template
+        The browse record are store in :attr:`objects`
+
+        The computation are based on the ledger_lines attribute set on account
+        contained by :attr:`objects`
+
+        :attr:`objects` values were previously set by parent class
+        :class: `.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :returns: parent :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+                  call to set_context
+
+        """
+        res = super(AccountAgedTrialBalanceWebkit, self).set_context(
+            objects,
+            data,
+            ids,
+            report_type=report_type
+        )
+
+        for acc in self.objects:
+            acc.aged_lines = {}
+            acc.agged_totals = {}
+            acc.agged_percents = {}
+            for part_id, partner_lines in acc.ledger_lines.items():
+                aged_lines = self.compute_aged_lines(part_id,
+                                                     partner_lines,
+                                                     data)
+                if aged_lines:
+                    acc.aged_lines[part_id] = aged_lines
+            acc.aged_totals = totals = self.compute_totals(acc.aged_lines.values())
+            acc.aged_percents = self.compute_percents(totals)
+        #Free some memory
+        del(acc.ledger_lines)
+        return res
+
+    def compute_aged_lines(self, partner_id, ledger_lines, data):
+        """Add property aged_lines to accounts browse records
+
+        contained in :attr:`objects` for a given partner
+
+        :params: partner_id current partner
+        :params: ledger_lines generated by parent
+                 :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :returns: dict of computed aged lines
+                  eg {'balance': 1000.0,
+                       'aged_lines': {(90, 120): 0.0, ...}
+
+        """
+        lines_to_age = self.filter_lines(partner_id, ledger_lines)
+        res = {}
+        end_date = self._get_end_date(data)
+        aged_lines = dict.fromkeys(RANGES, 0.0)
+        reconcile_lookup = self.get_reconcile_count_lookup(lines_to_age)
+        res['aged_lines'] = aged_lines
+        for line in lines_to_age:
+            compute_method = self.get_compute_method(reconcile_lookup,
+                                                     partner_id,
+                                                     line)
+            delay = compute_method(line, end_date, ledger_lines)
+            classification = self.classify_line(partner_id, delay)
+            aged_lines[classification] += line['debit'] - line['credit']
+        self.compute_balance(res, aged_lines)
+        return res
+
+    def _get_end_date(self, data):
+        """Retrieve end date to be used to compute delay.
+
+        :param data: data dict send to report contains form dict
+
+        :returns: end date to be used to compute overdue delay
+
+        """
+        end_date = None
+        date_to = data['form']['date_to']
+        period_to_id = data['form']['period_to']
+        fiscal_to_id = data['form']['fiscalyear_id']
+        if date_to:
+            end_date = date_to
+        elif period_to_id:
+            period_to = self.pool['account.period'].browse(self.cr,
+                                                           self.uid,
+                                                           period_to_id)
+            end_date = period_to.date_stop
+        elif fiscal_to_id:
+            fiscal_to = self.pool['account.fiscalyear'].browse(self.cr,
+                                                               self.uid,
+                                                               fiscal_to_id)
+            end_date = fiscal_to.date_stop
+        else:
+            raise ValueError('End date and end period not available')
+        return end_date
+
+    def _compute_delay_from_key(self, key, line, end_date):
+        """Compute overdue delay delta in days for line using attribute in key
+
+        delta = end_date - date of key
+
+        :param line: current ledger line
+        :param key: date key to be used to compute delta
+        :param end_date: end_date computed for wizard data
+
+        :returns: delta in days
+        """
+        from_date = datetime.strptime(line[key], DEFAULT_SERVER_DATE_FORMAT)
+        end_date = datetime.strptime(end_date, DEFAULT_SERVER_DATE_FORMAT)
+        delta = end_date - from_date
+        return delta.days
+
+    def compute_delay_from_maturity(self, line, end_date, ledger_lines):
+        """Compute overdue delay delta in days for line using attribute in key
+
+        delta = end_date - maturity date
+
+        :param line: current ledger line
+        :param end_date: end_date computed for wizard data
+        :params: ledger_lines generated by parent
+                 :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :returns: delta in days
+        """
+        return self._compute_delay_from_key('date_maturity',
+                                            line,
+                                            end_date)
+
+    def compute_delay_from_date(self, line, end_date, ledger_lines):
+        """Compute overdue delay delta in days for line using attribute in key
+
+        delta = end_date - date
+
+        :param line: current ledger line
+        :param end_date: end_date computed for wizard data
+        :params: ledger_lines generated by parent
+                 :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :returns: delta in days
+        """
+        return self._compute_delay_from_key('ldate',
+                                            line,
+                                            end_date)
+
+    def compute_delay_from_partial_rec(self, line, end_date, ledger_lines):
+        """Compute overdue delay delta in days for the case where move line
+
+        is related to a partial reconcile with more than one reconcile line
+
+        :param line: current ledger line
+        :param end_date: end_date computed for wizard data
+        :params: ledger_lines generated by parent
+                 :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :returns: delta in days
+        """
+        sale_lines = [x for x in ledger_lines if x['jtype'] in REC_PAY_TYPE and
+                      line['rec_id'] == x['rec_id']]
+        refund_lines = [x for x in ledger_lines if x['jtype'] in REFUND_TYPE and
+                        line['rec_id'] == x['rec_id']]
+        reference_line = line
+        if len(sale_lines) == 1:
+            reference_line = sale_lines[0]
+        elif len(refund_lines) == 1:
+            reference_line = refund_lines[0]
+        key = 'date_maturity' if reference_line.get('date_maturity') else 'ldate'
+        return self._compute_delay_from_key(key,
+                                            reference_line,
+                                            end_date)
+
+    def get_compute_method(self, reconcile_lookup, partner_id, line):
+        """Get the function that should compute the delay for a given line
+
+        :param reconcile_lookup: dict of reconcile group by id and count
+                                 {rec_id: count of line related to reconcile}
+        :param partner_id: current partner_id
+        :param line: current ledger line generated by parent
+                     :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :returns: function bounded to :class:`.AccountAgedTrialBalanceWebkit`
+
+        """
+        if reconcile_lookup.get(line['rec_id'], 0.0) > 1:
+            return self.compute_delay_from_partial_rec
+        if line['jtype'] in INV_TYPE:
+            if line.get('date_maturity'):
+                return self.compute_delay_from_maturity
+            return self.compute_delay_from_date
+        else:
+            return self.compute_delay_from_date
+
+    def line_is_valid(self, partner_id, line):
+        """Predicate hook that allows to filter line to be treated
+
+        :param partner_id: current partner_id
+        :param line: current ledger line generated by parent
+                     :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :returns: boolean True if line is allowed
+        """
+        return True
+
+    def filter_lines(self, partner_id, lines):
+        """Filter ledger lines that have to be treated
+
+        :param partner_id: current partner_id
+        :param lines: ledger_lines related to current partner
+                      and generated by parent
+                      :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :returns: list of allowed lines
+
+        """
+        return [x for x in lines if self.line_is_valid(partner_id, x)]
+
+    def classify_line(self, partner_id, overdue_days):
+        """Return the overdue range for a given delay
+
+        We loop from smaller range to higher
+        This should be the most effective solution as generaly
+        customer tend to have one or two month of delay
+
+        :param overdue_days: delay in days
+        :param partner_id: current partner_id
+
+        :returns: the correct range in :const:`RANGES`
+
+        """
+        for drange in RANGES:
+            if overdue_days <= drange[1]:
+                return drange
+        return drange
+
+    def compute_balance(self, res, aged_lines):
+        """Compute the total balance of aged line
+        for given account"""
+        res['balance'] = sum(aged_lines.values())
+
+    def compute_totals(self, aged_lines):
+        """Compute the totals for an account
+
+        :param aged_lines: dict of aged line taken from the
+                           property added to account record
+
+        :returns: dict of total {'balance':1000.00, (30, 60): 3000,...}
+
+        """
+        totals = {}
+        totals['balance'] = sum(x.get('balance', 0.0) for
+                                x in aged_lines)
+        aged_ranges = [x.get('aged_lines', {}) for x in aged_lines]
+        for drange in RANGES:
+            totals[drange] = sum(x.get(drange, 0.0) for x in aged_ranges)
+        return totals
+
+    def compute_percents(self, totals):
+        percents = {}
+        base = float(totals['balance']) or 1.0
+        for drange in RANGES:
+            percents[drange] = (float(totals[drange]) / base) * 100.0
+        return percents
+
+    def get_reconcile_count_lookup(self, lines):
+        """Compute an lookup dict
+
+        It contains has partial reconcile id as key and the count of lines
+        related to the reconcile id
+
+        :param: a list of ledger lines generated by parent
+                :class:`.open_invoices.PartnersOpenInvoicesWebkit`
+
+        :retuns: lookup dict {ṛec_id: count}
+
+        """
+        # possible bang if l_ids is really long.
+        # We have the same weakness in common_report ...
+        # but it seems not really possible for a partner
+        # So I'll keep that option.
+        l_ids = tuple(x['id'] for x in lines)
+        sql = ("SELECT reconcile_partial_id, COUNT(*) FROM account_move_line \n"
+               "   WHERE reconcile_partial_id IS NOT NULL \n"
+               "   AND id in %s \n"
+               "   GROUP BY reconcile_partial_id")
+        self.cr.execute(sql, (l_ids,))
+        res = self.cr.fetchall()
+        if res:
+            return dict((x[0], x[1]) for x in res)
+        return {}
+
+HeaderFooterTextWebKitParser(
+    'report.account.account_aged_trial_balance_webkit',
+    'account.account',
+    'addons/account_financial_report_webkit/report/templates/aged_trial_webkit.mako',
+    parser=AccountAgedTrialBalanceWebkit,
+)

=== modified file 'account_financial_report_webkit/report/common_reports.py'
--- account_financial_report_webkit/report/common_reports.py	2013-12-17 16:16:37 +0000
+++ account_financial_report_webkit/report/common_reports.py	2014-03-17 12:10:18 +0000
@@ -30,7 +30,7 @@
 
 _logger = logging.getLogger('financial.reports.webkit')
 
-
+MAX_MONSTER_SLICE = 50000
 class CommonReportHeaderWebkit(common_report_header):
     """Define common helper for financial report"""
 
@@ -433,6 +433,14 @@
             raise osv.except_osv(_('No valid filter'), _('Please set a valid time filter'))
 
     def _get_move_line_datas(self, move_line_ids, order='per.special DESC, l.date ASC, per.date_start ASC, m.name ASC'):
+        # Possible bang if move_line_ids is too long
+        # We can not slice here as we have to do the sort.
+        # If slice has to be done it means that we have to reorder in python
+        # after all is finished. That quite crapy...
+        # We have a defective desing here (mea culpa) that should be fixed
+        #
+        # TODO improve that by making a better domain or if not possible
+        # by using python sort
         if not move_line_ids:
             return []
         if not isinstance(move_line_ids, list):
@@ -441,6 +449,7 @@
 SELECT l.id AS id,
             l.date AS ldate,
             j.code AS jcode ,
+            j.type AS jtype,
             l.currency_id,
             l.account_id,
             l.amount_currency,
@@ -455,7 +464,8 @@
             l.partner_id AS lpartner_id,
             p.name AS partner_name,
             m.name AS move_name,
-             COALESCE(partialrec.name, fullrec.name, '') AS rec_name,
+            COALESCE(partialrec.name, fullrec.name, '') AS rec_name,
+            COALESCE(partialrec.id, fullrec.id, NULL) AS rec_id,
             m.id AS move_id,
             c.name AS currency_code,
             i.id AS invoice_id,

=== modified file 'account_financial_report_webkit/report/open_invoices.py'
--- account_financial_report_webkit/report/open_invoices.py	2013-11-03 12:55:27 +0000
+++ account_financial_report_webkit/report/open_invoices.py	2014-03-17 12:10:18 +0000
@@ -93,7 +93,6 @@
         """Populate a ledger_lines attribute on each browse record that will be used
         by mako template"""
         new_ids = data['form']['chart_account_id']
-
         # Account initial balance memoizer
         init_balance_memoizer = {}
         # Reading form

=== modified file 'account_financial_report_webkit/report/report.xml'
--- account_financial_report_webkit/report/report.xml	2013-12-16 09:37:19 +0000
+++ account_financial_report_webkit/report/report.xml	2014-03-17 12:10:18 +0000
@@ -14,23 +14,16 @@
             <field name="name">General Ledger Webkit</field>
             <field name="report_rml">account_financial_report_webkit/report/templates/account_report_general_ledger.mako</field>
             <field name="report_file">account_financial_report_webkit/report/templates/account_report_general_ledger.mako</field>
-        </record> 
+        </record>
+
         <record id="property_account_report_general_ledger_webkit" model="ir.property">
             <field name="name">account_report_general_ledger_webkit</field>
             <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/>
             <field eval="'ir.header_webkit,'+str(ref('account_financial_report_webkit.financial_landscape_header'))" model="ir.header_webkit" name="value"/>
             <field eval="'ir.actions.report.xml,'+str(ref('account_financial_report_webkit.account_report_general_ledger_webkit'))" model="ir.actions.report.xml" name="res_id"/>
         </record>
-        <!-- waiting the fix 
-        <report auto="False" 
-            id="account_report_partner_ledger_webkit" 
-            model="account.account" 
-            name="account.account_report_partner_ledger_webkit"  
-            file="account_financial_report_webkit/report/templates/account_report_partner_ledger.mako" 
-            string="General Ledger Webkit"
-            report_type="webkit"/>  -->
-            
-                <!-- we do not use report tag has we can not set header ref -->
+
+        <!-- we do not use report tag has we can not set header ref -->
        <record id="account_report_partners_ledger_webkit" model="ir.actions.report.xml">
             <field name="report_type">webkit</field>
             <field name="report_name">account.account_report_partners_ledger_webkit</field>
@@ -44,6 +37,7 @@
             <field name="report_rml">account_financial_report_webkit/report/templates/account_report_partners_ledger.mako</field>
             <field name="report_file">account_financial_report_webkit/report/templates/account_report_partners_ledger.mako</field>
         </record>
+
         <record id="property_account_report_partners_ledger_webkit" model="ir.property">
             <field name="name">account_report_partners_ledger_webkit</field>
             <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/>
@@ -64,6 +58,7 @@
              <field name="report_rml">account_financial_report_webkit/report/templates/account_report_trial_balance.mako</field>
              <field name="report_file">account_financial_report_webkit/report/templates/account_report_trial_balance.mako</field>
          </record>
+
         <record id="property_account_report_trial_balance_webkit" model="ir.property">
             <field name="name">account_report_trial_balance_webkit</field>
             <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/>
@@ -84,6 +79,7 @@
              <field name="report_rml">account_financial_report_webkit/report/templates/account_report_partner_balance.mako</field>
              <field name="report_file">account_financial_report_webkit/report/templates/account_report_partner_balance.mako</field>
          </record>
+
         <record id="property_account_report_partner_balance_webkit" model="ir.property">
             <field name="name">account_report_partner_balance_webkit</field>
             <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/>
@@ -104,6 +100,7 @@
              <field name="report_rml">account_financial_report_webkit/report/templates/account_report_open_invoices.mako</field>
              <field name="report_file">account_financial_report_webkit/report/templates/account_report_open_invoices.mako</field>
          </record>
+
         <record id="property_account_report_open_invoices_webkit" model="ir.property">
             <field name="name">account_report_open_invoices_webkit</field>
             <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/>
@@ -111,6 +108,31 @@
             <field eval="'ir.actions.report.xml,'+str(ref('account_financial_report_webkit.account_report_open_invoices_webkit'))" model="ir.actions.report.xml" name="res_id"/>
         </record>
 
+        <record id="account_report_aged_trial_blanance_webkit" model="ir.actions.report.xml">
+             <field name="report_type">webkit</field>
+             <field name="report_name">account.account_aged_trial_balance_webkit</field>
+             <field eval="[(6,0,[])]" name="groups_id"/>
+             <field eval="0" name="multi"/>
+             <field eval="0" name="auto"/>
+             <field eval="1" name="header"/>
+             <field name="model">account.account</field>
+             <field name="type">ir.actions.report.xml</field>
+             <field name="name">Aged Partner Balance</field>
+             <field name="report_rml">account_financial_report_webkit/report/templates/aged_trial_webkit.mako</field>
+             <field name="report_file">account_financial_report_webkit/report/templates/aged_trial_webkit.mako</field>
+         </record>
+
+        <record id="property_account_report_aged_trial_balance_webkit" model="ir.property">
+            <field name="name">account_aged_trial_balance_webkit</field>
+            <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/>
+            <field eval="'ir.header_webkit,'+str(ref('account_financial_report_webkit.financial_landscape_header'))"
+                   model="ir.header_webkit"
+                   name="value"/>
+            <field eval="'ir.actions.report.xml,'+str(ref('account_financial_report_webkit.account_report_aged_trial_blanance_webkit'))"
+                   model="ir.actions.report.xml"
+                   name="res_id"/>
+        </record>
+
         <record id="account_report_print_journal_webkit" model="ir.actions.report.xml">
              <field name="report_type">webkit</field>
              <field name="report_name">account.account_report_print_journal_webkit</field>
@@ -124,6 +146,7 @@
              <field name="report_rml">account_financial_report_webkit/report/templates/account_report_print_journal.mako</field>
              <field name="report_file">account_financial_report_webkit/report/templates/account_report_print_journal.mako</field>
          </record>
+
         <record id="property_account_report_print_journal_webkit" model="ir.property">
             <field name="name">account_report_print_journal_webkit</field>
             <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/>

=== added file 'account_financial_report_webkit/report/templates/aged_trial_webkit.mako'
--- account_financial_report_webkit/report/templates/aged_trial_webkit.mako	1970-01-01 00:00:00 +0000
+++ account_financial_report_webkit/report/templates/aged_trial_webkit.mako	2014-03-17 12:10:18 +0000
@@ -0,0 +1,155 @@
+## -*- coding: utf-8 -*-
+<!DOCTYPE html SYSTEM
+"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";>
+<html xmlns="http://www.w3.org/1999/xhtml";>
+    <head>
+        <style type="text/css">
+            .overflow_ellipsis {
+                text-overflow: ellipsis;
+                overflow: hidden;
+                white-space: nowrap;
+            }
+
+            .open_invoice_previous_line {
+                font-style: italic;
+            }
+
+            .percent_line {
+                font-style: italic;
+            }
+
+            .amount {
+                text-align:right;
+            }
+
+            .classif_title {
+                text-align:right;
+            }
+
+            .classif{
+              width: ${700/len(ranges)}px;
+            }
+            .total{
+               font-weight:bold;
+            }
+            ${css}
+        </style>
+    </head>
+
+    <%!
+    def amount(text):
+        # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers)
+        return text.replace('-', '&#8209;')
+    %>
+    <body>
+        <%setLang(user.lang)%>
+
+        <div class="act_as_table data_table">
+            <div class="act_as_row labels">
+                <div class="act_as_cell">${_('Chart of Account')}</div>
+                <div class="act_as_cell">${_('Fiscal Year')}</div>
+                <div class="act_as_cell">
+                    %if filter_form(data) == 'filter_date':
+                        ${_('Dates Filter')}
+                    %else:
+                        ${_('Periods Filter')}
+                    %endif
+                </div>
+                <div class="act_as_cell">${_('Clearance Date')}</div>
+                <div class="act_as_cell">${_('Accounts Filter')}</div>
+                <div class="act_as_cell">${_('Target Moves')}</div>
+
+            </div>
+            <div class="act_as_row">
+                <div class="act_as_cell">${ chart_account.name }</div>
+                <div class="act_as_cell">${ fiscalyear.name if fiscalyear else '-' }</div>
+                <div class="act_as_cell">
+                    ${_('From:')}
+                    %if filter_form(data) == 'filter_date':
+                        ${formatLang(start_date, date=True) if start_date else u'' }
+                    %else:
+                        ${start_period.name if start_period else u''}
+                    %endif
+                    ${_('To:')}
+                    %if filter_form(data) == 'filter_date':
+                        ${ formatLang(stop_date, date=True) if stop_date else u'' }
+                    %else:
+                        ${stop_period.name if stop_period else u'' }
+                    %endif
+                </div>
+                <div class="act_as_cell">${ formatLang(date_until, date=True) }</div>
+                <div class="act_as_cell">
+                    %if partner_ids:
+                        ${_('Custom Filter')}
+                    %else:
+                        ${ display_partner_account(data) }
+                    %endif
+                </div>
+                <div class="act_as_cell">${ display_target_move(data) }</div>
+            </div>
+        </div>
+        %for acc in objects:
+          %if acc.aged_lines:
+          <div class="account_title bg" style="width: 1080px; margin-top: 20px; font-size: 12px;">${acc.code} - ${acc.name}</div>
+
+
+
+                <div class="act_as_table list_table" style="margin-top: 5px;">
+                  <div class="act_as_thead">
+                    <div class="act_as_row labels">
+                      ## partner
+                      <div class="act_as_cell first_column" style="width: 60px;">${_('Partner')}</div>
+                      ## code
+                      <div class="act_as_cell" style="width: 70px;">${_('code')}</div>
+                      ## balance
+                      <div class="act_as_cell classif_title" style="width: 70px;">${_('balance')}</div>
+                      ## Classifications
+                      %for title in ranges_titles:
+                        <div class="act_as_cell classif classif_title">${title}</div>
+                      %endfor
+                    </div>
+                  </div>
+                  <div class="act_as_tbody">
+                    %for partner_name, p_id, p_ref, p_name in acc.partners_order:
+                       %if acc.aged_lines.get(p_id):
+                       <div class="act_as_row lines">
+                         <%line = acc.aged_lines[p_id]%>
+                         <%percents = acc.aged_percents%>
+                         <%totals = acc.aged_totals%>
+                           <div class="act_as_cell first_column">${partner_name}</div>
+                           <div class="act_as_cell">${p_ref or ''}</div>
+
+                           <div class="act_as_cell amount">${formatLang(line.get('balance') or 0.0) | amount}</div>
+                            %for classif in ranges:
+                              <div class="act_as_cell classif amount">
+                                ${formatLang(line['aged_lines'][classif] or 0.0) | amount}
+                              </div>
+                            %endfor
+                       </div>
+                       %endif
+                    %endfor
+                    <div class="act_as_row labels">
+                      <div class="act_as_cell total">${_('Total')}</div>
+                      <div class="act_as_cell"></div>
+                      <div class="act_as_cell amount classif total">${formatLang(totals['balance']) | amount}</div>
+                      %for classif in ranges:
+                        <div class="act_as_cell amount classif total">${formatLang(totals[classif]) | amount}</div>
+                      %endfor
+                    </div>
+
+                    <div class="act_as_row">
+                      <div class="act_as_cell"><b>${_('Percents')}</b></div>
+                      <div class="act_as_cell"></div>
+                      <div class="act_as_cell"></div>
+                      %for classif in ranges:
+                        <div class="act_as_cell amount percent_line  classif">${formatLang(percents[classif]) | amount}%</div>
+                      %endfor
+                    </div>
+                  </div>
+                  <br/>
+
+                 %endif
+              %endfor
+        </div>
+    </body>
+</html>

=== modified file 'account_financial_report_webkit/report/templates/open_invoices_inclusion.mako.html'
--- account_financial_report_webkit/report/templates/open_invoices_inclusion.mako.html	2013-11-21 15:55:29 +0000
+++ account_financial_report_webkit/report/templates/open_invoices_inclusion.mako.html	2014-03-17 12:10:18 +0000
@@ -9,7 +9,7 @@
     %>
 
     <div class="account_title bg" style="width: 1080px; margin-top: 20px; font-size: 12px;">${account.code} - ${account.name}</div>
-    
+
     %for partner_name, p_id, p_ref, p_name in account.partners_order:
     <%
       total_debit = 0.0
@@ -18,7 +18,7 @@
       cumul_balance_curr = 0.0
 
       part_cumul_balance = 0.0
-      part_cumul_balance_curr = 0.0 
+      part_cumul_balance_curr = 0.0
     %>
     <div class="act_as_table list_table" style="margin-top: 5px;">
         <div class="act_as_caption account_title">

=== modified file 'account_financial_report_webkit/report/webkit_parser_header_fix.py'
--- account_financial_report_webkit/report/webkit_parser_header_fix.py	2014-01-14 09:37:20 +0000
+++ account_financial_report_webkit/report/webkit_parser_header_fix.py	2014-03-17 12:10:18 +0000
@@ -160,7 +160,6 @@
     # override needed to keep the attachments' storing procedure
     def create_single_pdf(self, cursor, uid, ids, data, report_xml, context=None):
         """generate the PDF"""
-
         if context is None:
             context={}
         htmls = []

=== modified file 'account_financial_report_webkit/report_menus.xml'
--- account_financial_report_webkit/report_menus.xml	2014-01-13 09:33:02 +0000
+++ account_financial_report_webkit/report_menus.xml	2014-03-17 12:10:18 +0000
@@ -18,6 +18,10 @@
             parent="account.next_id_22" action="action_account_partner_balance_menu_webkit"
             groups="account.group_account_manager,account.group_account_user" id="account.menu_account_partner_balance_report"/>
 
+        <menuitem icon="STOCK_PRINT" name="Aged Partner Balance"
+            parent="account.next_id_22" action="action_account_aged_trial_balance_menu_webkit"
+            groups="account.group_account_manager,account.group_account_user" id="account.menu_aged_trial_balance"/>
+
         <menuitem icon="STOCK_PRINT" name="Open Invoices"
             parent="account.next_id_22" action="action_account_open_invoices_menu_webkit"
             groups="account.group_account_manager,account.group_account_user" id="menu_account_open_invoices"/>

=== modified file 'account_financial_report_webkit/wizard/__init__.py'
--- account_financial_report_webkit/wizard/__init__.py	2013-09-12 20:53:27 +0000
+++ account_financial_report_webkit/wizard/__init__.py	2014-03-17 12:10:18 +0000
@@ -27,3 +27,4 @@
 from . import partner_balance_wizard
 from . import open_invoices_wizard
 from . import print_journal
+from . import aged_partner_balance_wizard

=== added file 'account_financial_report_webkit/wizard/aged_partner_balance_wizard.py'
--- account_financial_report_webkit/wizard/aged_partner_balance_wizard.py	1970-01-01 00:00:00 +0000
+++ account_financial_report_webkit/wizard/aged_partner_balance_wizard.py	2014-03-17 12:10:18 +0000
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+#    Author: Nicolas Bessi
+#    Copyright 2014 Camptocamp SA
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU Affero General Public License as
+#    published by the Free Software Foundation, either version 3 of the
+#    License, or (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+from openerp.osv import orm
+
+
+class AccountAgedTrialBalance(orm.TransientModel):
+    """Will launch age partner balance report.
+    This report is based on Open Invoice Report
+    and share a lot of knowledge with him
+    """
+
+    _inherit = "open.invoices.webkit"
+    _name = "account.aged.trial.balance.webkit"
+    _description = "Aged partner balanced"
+
+    def _print_report(self, cr, uid, ids, data, context=None):
+        # we update form with display account value
+        data = self.pre_print_report(cr, uid, ids, data, context=context)
+        return {'type': 'ir.actions.report.xml',
+                'report_name': 'account.account_aged_trial_balance_webkit',
+                'datas': data}

=== added file 'account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml'
--- account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml	1970-01-01 00:00:00 +0000
+++ account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml	2014-03-17 12:10:18 +0000
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+  <data>
+
+    <record id="account_aged_trial_balance_webkit" model="ir.ui.view">
+      <field name="name">Aged Partner Balance Report</field>
+      <field name="model">account.aged.trial.balance.webkit</field>
+      <field name="inherit_id" ref="account.account_common_report_view"/>
+      <field name="arch" type="xml">
+        <data>
+
+          <xpath expr="/form/label[@string='']" position="replace">
+            <separator string="Aged Partner Balance" colspan="4"/>
+            <label nolabel="1"
+                   colspan="4"
+                   string="This report list partner open balances and indicate when payment is (or was) supposed to be completed"/>
+          </xpath>
+          <field name="chart_account_id" position='attributes'>
+            <attribute name="colspan">4</attribute>
+          </field>
+          <xpath expr="//field[@name='target_move']" position="after">
+            <newline/>
+            <field name="result_selection" colspan="4"/>
+          </xpath>
+          <xpath expr="/form/notebook[1]" position="after">
+            <separator string="Clearance Analysis Options" colspan="4"/>
+            <newline/>
+            <field name="until_date"/>
+          </xpath>
+          <page name="filters" position="after">
+            <page string="Partners Filters" name="partners">
+              <separator string="Print only" colspan="4"/>
+              <field name="partner_ids" colspan="4" nolabel="1"/>
+            </page>
+          </page>
+          <page name="filters" position="attributes">
+            <attribute name="string">Time Filters</attribute>
+          </page>
+          <page name="journal_ids" position="attributes">
+            <attribute name="invisible">True</attribute>
+          </page>
+          <field name="fiscalyear_id" position="attributes">
+            <attribute name="on_change">onchange_fiscalyear(fiscalyear_id, period_to, date_to, until_date)</attribute>
+          </field>
+          <field name="date_to" position="attributes">
+            <attribute name="on_change">onchange_date_to(fiscalyear_id, period_to, date_to, until_date)</attribute>
+          </field>
+          <field name="period_to" position="attributes">
+            <attribute name="on_change">onchange_period_to(fiscalyear_id, period_to, date_to, until_date)</attribute>
+          </field>
+          <field name="period_from" position="attributes">
+            <attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
+          </field>
+          <field name="period_to" position="attributes">
+            <attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute>
+          </field>
+        </data>
+      </field>
+    </record>
+
+    <record id="action_account_aged_trial_balance_menu_webkit"
+            model="ir.actions.act_window">
+      <field name="name">Aged partner balance</field>
+      <field name="type">ir.actions.act_window</field>
+      <field name="res_model">account.aged.trial.balance.webkit</field>
+      <field name="view_type">form</field>
+      <field name="view_mode">form</field>
+      <field name="view_id" ref="account_aged_trial_balance_webkit"/>
+      <field name="target">new</field>
+    </record>
+  </data>
+</openerp>


Follow ups