Browse Source

Merge pull request #118 from savoirfairelinux/7.0_aged_partner_balance_by_invoice

[7.0] Improve Aged Partner Balance report
pull/139/head
Maxime Chambreuil - http://www.savoirfairelinux.com 9 years ago
parent
commit
96f048ed04
  1. 1767
      account_financial_report_webkit/i18n/account_financial_report_webkit.pot
  2. 1132
      account_financial_report_webkit/i18n/fr.po
  3. 83
      account_financial_report_webkit/report/aged_partner_balance.py
  4. 100
      account_financial_report_webkit/report/templates/aged_trial_webkit.mako
  5. 32
      account_financial_report_webkit/wizard/aged_partner_balance_wizard.py
  6. 4
      account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml

1767
account_financial_report_webkit/i18n/account_financial_report_webkit.pot
File diff suppressed because it is too large
View File

1132
account_financial_report_webkit/i18n/fr.po
File diff suppressed because it is too large
View File

83
account_financial_report_webkit/report/aged_partner_balance.py

@ -49,8 +49,8 @@ RANGES = make_ranges(120, 30)
def make_ranges_titles(): def make_ranges_titles():
"""Generates title to be used by mako""" """Generates title to be used by mako"""
titles = [_('Due')]
titles += [_(u'Overdue ≤ %s d.') % x[1] for x in RANGES[1:-1]]
titles = [_('Current')]
titles += [_(u'Age ≤ %s d.') % x[1] for x in RANGES[1:-1]]
titles.append(_('Older')) titles.append(_('Older'))
return titles return titles
@ -113,7 +113,8 @@ class AccountAgedTrialBalanceWebkit(PartnersOpenInvoicesWebkit):
return RANGES_TITLES return RANGES_TITLES
def set_context(self, objects, data, ids, report_type=None): def set_context(self, objects, data, ids, report_type=None):
"""Populate aged_lines, aged_balance, aged_percents attributes
"""Populate aged_lines, aged_lines_by_invoice, aged_balance,
aged_percents attributes
on each account browse record that will be used by mako template on each account browse record that will be used by mako template
The browse record are store in :attr:`objects` The browse record are store in :attr:`objects`
@ -134,17 +135,23 @@ class AccountAgedTrialBalanceWebkit(PartnersOpenInvoicesWebkit):
ids, ids,
report_type=report_type report_type=report_type
) )
self.localcontext.update({
'aging_method': data['form']['aging_method']
})
for acc in self.objects: for acc in self.objects:
acc.aged_lines = {} acc.aged_lines = {}
acc.aged_lines_by_invoice = {}
acc.agged_totals = {} acc.agged_totals = {}
acc.agged_percents = {} acc.agged_percents = {}
for part_id, partner_lines in acc.ledger_lines.items(): 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
partner_aged_lines, invoice_aged_lines = \
self.compute_aged_lines(part_id,
partner_lines,
data)
if partner_aged_lines:
acc.aged_lines[part_id] = partner_aged_lines
if data['form']['detailed_by_invoice']:
acc.aged_lines_by_invoice[part_id] = invoice_aged_lines
acc.aged_totals = totals = self.compute_totals( acc.aged_totals = totals = self.compute_totals(
acc.aged_lines.values()) acc.aged_lines.values())
acc.aged_percents = self.compute_percents(totals) acc.aged_percents = self.compute_percents(totals)
@ -161,26 +168,58 @@ class AccountAgedTrialBalanceWebkit(PartnersOpenInvoicesWebkit):
:param ledger_lines: generated by parent :param ledger_lines: generated by parent
:class:`.open_invoices.PartnersOpenInvoicesWebkit` :class:`.open_invoices.PartnersOpenInvoicesWebkit`
:returns: dict of computed aged lines
:returns:
- dict of computed aged lines
eg {'balance': 1000.0, eg {'balance': 1000.0,
'aged_lines': {(90, 120): 0.0, ...}
'aged_lines': {(90, 120): 0.0, ...}
}
- dict of computed aged lines by invoice
eg {'SAJ/2015/003': {'balance: 700.0
'aged_lines': {(90, 120): 0.0, ...},
'SAJ/2015/004': {'balance: 300.0
'aged_lines': {(90, 120): 300.0, ...},
}
""" """
detailed_by_invoice = data['form']['detailed_by_invoice']
aging_method = data['form']['aging_method']
lines_to_age = self.filter_lines(partner_id, ledger_lines) lines_to_age = self.filter_lines(partner_id, ledger_lines)
res = {}
res_by_partner = {}
res_by_invoice = {}
end_date = self._get_end_date(data) end_date = self._get_end_date(data)
aged_lines = dict.fromkeys(RANGES, 0.0)
partner_aged_lines = dict.fromkeys(RANGES, 0.0)
reconcile_lookup = self.get_reconcile_count_lookup(lines_to_age) reconcile_lookup = self.get_reconcile_count_lookup(lines_to_age)
res['aged_lines'] = aged_lines
res_by_partner['aged_lines'] = partner_aged_lines
for line in lines_to_age: for line in lines_to_age:
compute_method = self.get_compute_method(reconcile_lookup, compute_method = self.get_compute_method(reconcile_lookup,
partner_id, partner_id,
line)
line,
aging_method)
delay = compute_method(line, end_date, ledger_lines) delay = compute_method(line, end_date, ledger_lines)
classification = self.classify_line(partner_id, delay) classification = self.classify_line(partner_id, delay)
aged_lines[classification] += line['debit'] - line['credit']
self.compute_balance(res, aged_lines)
return res
amount = line['debit'] - line['credit']
partner_aged_lines[classification] += amount
# Populate the aged_lines_by_invoice dictionary if the option has
# been chosen in the wizard
if detailed_by_invoice:
invoice = line['invoice_number']
if invoice not in res_by_invoice:
res_by_invoice[invoice] = {
'aged_lines': dict.fromkeys(RANGES, 0.0),
}
res_by_invoice[invoice][
'aged_lines'][classification] += amount
if detailed_by_invoice:
for invoice in res_by_invoice:
self.compute_balance(
res_by_invoice[invoice],
res_by_invoice[invoice]['aged_lines']
)
self.compute_balance(res_by_partner, partner_aged_lines)
return res_by_partner, res_by_invoice
def _get_end_date(self, data): def _get_end_date(self, data):
"""Retrieve end date to be used to compute delay. """Retrieve end date to be used to compute delay.
@ -286,7 +325,8 @@ class AccountAgedTrialBalanceWebkit(PartnersOpenInvoicesWebkit):
reference_line, reference_line,
end_date) end_date)
def get_compute_method(self, reconcile_lookup, partner_id, line):
def get_compute_method(self, reconcile_lookup, partner_id, line,
aging_method):
"""Get the function that should compute the delay for a given line """Get the function that should compute the delay for a given line
:param reconcile_lookup: dict of reconcile group by id and count :param reconcile_lookup: dict of reconcile group by id and count
@ -300,7 +340,8 @@ class AccountAgedTrialBalanceWebkit(PartnersOpenInvoicesWebkit):
""" """
if reconcile_lookup.get(line['rec_id'], 0.0) > 1: if reconcile_lookup.get(line['rec_id'], 0.0) > 1:
return self.compute_delay_from_partial_rec return self.compute_delay_from_partial_rec
elif line['jtype'] in INV_TYPE and line.get('date_maturity'):
elif line['jtype'] in INV_TYPE and line.get('date_maturity') \
and aging_method == 'due_date':
return self.compute_delay_from_maturity return self.compute_delay_from_maturity
else: else:
return self.compute_delay_from_date return self.compute_delay_from_date

100
account_financial_report_webkit/report/templates/aged_trial_webkit.mako

@ -48,6 +48,7 @@
<div class="act_as_row labels" style="page-break-inside: avoid"> <div class="act_as_row labels" style="page-break-inside: avoid">
<div class="act_as_cell">${_('Chart of Account')}</div> <div class="act_as_cell">${_('Chart of Account')}</div>
<div class="act_as_cell">${_('Fiscal Year')}</div> <div class="act_as_cell">${_('Fiscal Year')}</div>
<div class="act_as_cell">${_('Aged From')}</div>
<div class="act_as_cell"> <div class="act_as_cell">
%if filter_form(data) == 'filter_date': %if filter_form(data) == 'filter_date':
${_('Dates Filter')} ${_('Dates Filter')}
@ -63,6 +64,13 @@
<div class="act_as_row" style="page-break-inside: avoid"> <div class="act_as_row" style="page-break-inside: avoid">
<div class="act_as_cell">${ chart_account.name }</div> <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">${ fiscalyear.name if fiscalyear else '-' }</div>
<div class="act_as_cell">
%if aging_method == 'due_date':
${_('Due Date')}
%else:
${_('Invoice Date')}
%endif
</div>
<div class="act_as_cell"> <div class="act_as_cell">
${_('From:')} ${_('From:')}
%if filter_form(data) == 'filter_date': %if filter_form(data) == 'filter_date':
@ -100,9 +108,13 @@
## partner ## partner
<div class="act_as_cell first_column" style="width: 60px;">${_('Partner')}</div> <div class="act_as_cell first_column" style="width: 60px;">${_('Partner')}</div>
## code ## code
<div class="act_as_cell" style="width: 70px;">${_('code')}</div>
<div class="act_as_cell" style="width: 70px;">${_('Code')}</div>
## invoice for detailed reports
%if acc.aged_lines_by_invoice:
<div class="act_as_cell" style="width: 70px;">${_('Invoice')}</div>
%endif
## balance ## balance
<div class="act_as_cell classif_title" style="width: 70px;">${_('balance')}</div>
<div class="act_as_cell classif_title" style="width: 70px;">${_('Balance')}</div>
## Classifications ## Classifications
%for title in ranges_titles: %for title in ranges_titles:
<div class="act_as_cell classif classif_title">${title}</div> <div class="act_as_cell classif classif_title">${title}</div>
@ -110,27 +122,74 @@
</div> </div>
</div> </div>
<div class="act_as_tbody"> <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" style="page-break-inside: avoid">
<%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>
%if not acc.aged_lines_by_invoice:
%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" style="page-break-inside: avoid">
<%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_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
%else:
%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" style="page-break-inside: avoid">
<%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"></div>
<div class="act_as_cell amount"></div>
%for classif in ranges:
<div class="act_as_cell classif amount"></div>
%endfor
</div>
%for invoice in acc.aged_lines_by_invoice[p_id]:
<%invoice_line = acc.aged_lines_by_invoice[p_id][invoice]%>
<div class="act_as_row lines" style="page-break-inside: avoid">
<div class="act_as_cell first_column"></div>
<div class="act_as_cell"></div>
<div class="act_as_cell">${invoice}</div>
<div class="act_as_cell amount">${formatLang(invoice_line.get('balance') or 0.0) | amount}</div>
%for classif in ranges:
<div class="act_as_cell classif amount">
${formatLang(invoice_line['aged_lines'][classif] or 0.0) | amount}
</div>
%endfor
</div>
%endfor
<div class="act_as_row lines" style="page-break-inside: avoid">
<div class="act_as_cell first_column"></div>
<div class="act_as_cell"></div>
<div class="act_as_cell total">Total</div>
<div class="act_as_cell amount total">${formatLang(line.get('balance') or 0.0) | amount}</div>
%for classif in ranges:
<div class="act_as_cell classif amount total">
${formatLang(line['aged_lines'][classif] or 0.0) | amount}
</div>
%endfor
</div>
%endif
%endfor
%endif
<div class="act_as_row labels" style="page-break-inside: avoid"> <div class="act_as_row labels" style="page-break-inside: avoid">
<div class="act_as_cell total">${_('Total')}</div> <div class="act_as_cell total">${_('Total')}</div>
<div class="act_as_cell"></div> <div class="act_as_cell"></div>
%if acc.aged_lines_by_invoice:
<div class="act_as_cell"></div>
%endif
<div class="act_as_cell amount classif total">${formatLang(totals['balance']) | amount}</div> <div class="act_as_cell amount classif total">${formatLang(totals['balance']) | amount}</div>
%for classif in ranges: %for classif in ranges:
<div class="act_as_cell amount classif total">${formatLang(totals[classif]) | amount}</div> <div class="act_as_cell amount classif total">${formatLang(totals[classif]) | amount}</div>
@ -140,6 +199,9 @@
<div class="act_as_row" style="page-break-inside: avoid"> <div class="act_as_row" style="page-break-inside: avoid">
<div class="act_as_cell"><b>${_('Percents')}</b></div> <div class="act_as_cell"><b>${_('Percents')}</b></div>
<div class="act_as_cell"></div> <div class="act_as_cell"></div>
%if acc.aged_lines_by_invoice:
<div class="act_as_cell"></div>
%endif
<div class="act_as_cell"></div> <div class="act_as_cell"></div>
%for classif in ranges: %for classif in ranges:
<div class="act_as_cell amount percent_line classif">${formatLang(percents[classif]) | amount}%</div> <div class="act_as_cell amount percent_line classif">${formatLang(percents[classif]) | amount}%</div>

32
account_financial_report_webkit/wizard/aged_partner_balance_wizard.py

@ -18,7 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
############################################################################## ##############################################################################
from openerp.osv import orm
from openerp.osv import orm, fields
class AccountAgedTrialBalance(orm.TransientModel): class AccountAgedTrialBalance(orm.TransientModel):
@ -31,6 +31,36 @@ class AccountAgedTrialBalance(orm.TransientModel):
_name = "account.aged.trial.balance.webkit" _name = "account.aged.trial.balance.webkit"
_description = "Aged partner balanced" _description = "Aged partner balanced"
_columns = {
'detailed_by_invoice': fields.boolean(
"Detailed by Invoice",
help="Provide an aged partner balance report with invoice "
"details"
),
'aging_method': fields.selection(
[('due_date', 'Due Date'),
('invoice_date', 'Invoice Date')],
'Aged from',
required=True
),
}
_defaults = {
'aging_method': 'due_date',
}
def pre_print_report(self, cr, uid, ids, data, context=None):
data = super(AccountAgedTrialBalance, self).pre_print_report(
cr, uid, ids, data, context)
# will be used to attach the report on the main account
data['ids'] = [data['form']['chart_account_id']]
vals = self.read(cr, uid, ids,
['detailed_by_invoice',
'aging_method'],
context=context)[0]
data['form'].update(vals)
return data
def _print_report(self, cr, uid, ids, data, context=None): def _print_report(self, cr, uid, ids, data, context=None):
# we update form with display account value # we update form with display account value
data = self.pre_print_report(cr, uid, ids, data, context=context) data = self.pre_print_report(cr, uid, ids, data, context=context)

4
account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml

@ -18,9 +18,13 @@
<field name="chart_account_id" position='attributes'> <field name="chart_account_id" position='attributes'>
<attribute name="colspan">4</attribute> <attribute name="colspan">4</attribute>
</field> </field>
<field name="chart_account_id" position='after'>
<field name="detailed_by_invoice" colspan="4"/>
</field>
<xpath expr="//field[@name='target_move']" position="after"> <xpath expr="//field[@name='target_move']" position="after">
<newline/> <newline/>
<field name="result_selection" colspan="4"/> <field name="result_selection" colspan="4"/>
<field name="aging_method" colspan="4"/>
</xpath> </xpath>
<xpath expr="/form/notebook[1]" position="after"> <xpath expr="/form/notebook[1]" position="after">
<separator string="Clearance Analysis Options" colspan="4"/> <separator string="Clearance Analysis Options" colspan="4"/>

Loading…
Cancel
Save