Browse Source

[IMP] Extend customer_activity_statement to display also payables

pull/537/head
Jordi Ballester Alomar 7 years ago
committed by ahenriquez
parent
commit
20733f427f
  1. 16
      customer_activity_statement/README.rst
  2. 4
      customer_activity_statement/__manifest__.py
  3. 42
      customer_activity_statement/report/customer_activity_statement.py
  4. 10
      customer_activity_statement/static/description/index.html
  5. 7
      customer_activity_statement/views/statement.xml
  6. 4
      customer_activity_statement/wizard/customer_activity_statement_wizard.py
  7. 11
      customer_activity_statement/wizard/customer_activity_statement_wizard.xml

16
customer_activity_statement/README.rst

@ -2,18 +2,18 @@
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3 :alt: License: AGPL-3
=================================
Print Customer Activity Statement
=================================
================================
Print Partner Activity Statement
================================
The activity statement provides details of all activity on the customer receivables
The activity statement provides details of all activity on the partner receivables or payables
between two selected dates. This includes all invoices, refunds and payments. between two selected dates. This includes all invoices, refunds and payments.
Any outstanding balance dated prior to the chosen statement period will appear Any outstanding balance dated prior to the chosen statement period will appear
as a forward balance at the top of the statement. The list is displayed in chronological as a forward balance at the top of the statement. The list is displayed in chronological
order and is split by currencies. order and is split by currencies.
Aging details can be shown in the report, expressed in aging buckets (30 days Aging details can be shown in the report, expressed in aging buckets (30 days
due, ...), so the customer can review how much is open, due or overdue.
due, ...), so the customer or vendor can review how much is open, due or overdue.
Configuration Configuration
============= =============
@ -28,9 +28,9 @@ Usage
To use this module, you need to: To use this module, you need to:
#. Go to Customers and select one or more
#. Press 'Action > Customer Activity Statement'
#. Indicate if you want to display aging buckets
#. Go to Customers or Vendors and select one or more
#. Press 'Action > Partner Activity Statement'
#. Indicate if you want to display receivables or payables, and if you want to display aging buckets
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas .. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas

4
customer_activity_statement/__manifest__.py

@ -4,8 +4,8 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{ {
'name': 'Customer Activity Statement',
'version': '10.0.1.1.0',
'name': 'Partner Activity Statement',
'version': '10.0.2.0.0',
'category': 'Accounting & Finance', 'category': 'Accounting & Finance',
'summary': 'OCA Financial Reports', 'summary': 'OCA Financial Reports',
'author': "Eficent, Odoo Community Association (OCA)", 'author': "Eficent, Odoo Community Association (OCA)",

42
customer_activity_statement/report/customer_activity_statement.py

@ -19,7 +19,7 @@ class CustomerActivityStatement(models.AbstractModel):
date = datetime.strptime(str_date, DEFAULT_SERVER_DATE_FORMAT).date() date = datetime.strptime(str_date, DEFAULT_SERVER_DATE_FORMAT).date()
return date.strftime(lang.date_format) return date.strftime(lang.date_format)
def _initial_balance_sql_q1(self, partners, date_start):
def _initial_balance_sql_q1(self, partners, date_start, account_type):
return """ return """
SELECT l.partner_id, l.currency_id, l.company_id, SELECT l.partner_id, l.currency_id, l.company_id,
CASE WHEN l.currency_id is not null AND l.amount_currency > 0.0 CASE WHEN l.currency_id is not null AND l.amount_currency > 0.0
@ -33,11 +33,11 @@ class CustomerActivityStatement(models.AbstractModel):
FROM account_move_line l FROM account_move_line l
JOIN account_account_type at ON (at.id = l.user_type_id) JOIN account_account_type at ON (at.id = l.user_type_id)
JOIN account_move m ON (l.move_id = m.id) JOIN account_move m ON (l.move_id = m.id)
WHERE l.partner_id IN (%s) AND at.type = 'receivable'
WHERE l.partner_id IN (%s) AND at.type = '%s'
AND l.date < '%s' AND not l.blocked AND l.date < '%s' AND not l.blocked
GROUP BY l.partner_id, l.currency_id, l.amount_currency, GROUP BY l.partner_id, l.currency_id, l.amount_currency,
l.company_id l.company_id
""" % (partners, date_start)
""" % (partners, account_type, date_start)
def _initial_balance_sql_q2(self, company_id): def _initial_balance_sql_q2(self, company_id):
return """ return """
@ -49,7 +49,7 @@ class CustomerActivityStatement(models.AbstractModel):
""" % company_id """ % company_id
def _get_account_initial_balance(self, company_id, partner_ids, def _get_account_initial_balance(self, company_id, partner_ids,
date_start):
date_start, account_type):
res = dict(map(lambda x: (x, []), partner_ids)) res = dict(map(lambda x: (x, []), partner_ids))
partners = ', '.join([str(i) for i in partner_ids]) partners = ', '.join([str(i) for i in partner_ids])
date_start = datetime.strptime( date_start = datetime.strptime(
@ -57,13 +57,15 @@ class CustomerActivityStatement(models.AbstractModel):
# pylint: disable=E8103 # pylint: disable=E8103
self.env.cr.execute("""WITH Q1 AS (%s), Q2 AS (%s) self.env.cr.execute("""WITH Q1 AS (%s), Q2 AS (%s)
SELECT partner_id, currency_id, balance SELECT partner_id, currency_id, balance
FROM Q2""" % (self._initial_balance_sql_q1(partners, date_start),
FROM Q2""" % (self._initial_balance_sql_q1(partners, date_start,
account_type),
self._initial_balance_sql_q2(company_id))) self._initial_balance_sql_q2(company_id)))
for row in self.env.cr.dictfetchall(): for row in self.env.cr.dictfetchall():
res[row.pop('partner_id')].append(row) res[row.pop('partner_id')].append(row)
return res return res
def _display_lines_sql_q1(self, partners, date_start, date_end):
def _display_lines_sql_q1(self, partners, date_start, date_end,
account_type):
return """ return """
SELECT m.name AS move_id, l.partner_id, l.date, l.name, SELECT m.name AS move_id, l.partner_id, l.date, l.name,
l.ref, l.blocked, l.currency_id, l.company_id, l.ref, l.blocked, l.currency_id, l.company_id,
@ -82,12 +84,12 @@ class CustomerActivityStatement(models.AbstractModel):
FROM account_move_line l FROM account_move_line l
JOIN account_account_type at ON (at.id = l.user_type_id) JOIN account_account_type at ON (at.id = l.user_type_id)
JOIN account_move m ON (l.move_id = m.id) JOIN account_move m ON (l.move_id = m.id)
WHERE l.partner_id IN (%s) AND at.type = 'receivable'
WHERE l.partner_id IN (%s) AND at.type = '%s'
AND '%s' <= l.date AND l.date <= '%s' AND '%s' <= l.date AND l.date <= '%s'
GROUP BY l.partner_id, m.name, l.date, l.date_maturity, l.name, GROUP BY l.partner_id, m.name, l.date, l.date_maturity, l.name,
l.ref, l.blocked, l.currency_id, l.ref, l.blocked, l.currency_id,
l.amount_currency, l.company_id l.amount_currency, l.company_id
""" % (partners, date_start, date_end)
""" % (partners, account_type, date_start, date_end)
def _display_lines_sql_q2(self, company_id): def _display_lines_sql_q2(self, company_id):
return """ return """
@ -100,7 +102,7 @@ class CustomerActivityStatement(models.AbstractModel):
""" % company_id """ % company_id
def _get_account_display_lines(self, company_id, partner_ids, date_start, def _get_account_display_lines(self, company_id, partner_ids, date_start,
date_end):
date_end, account_type):
# pylint: disable=sql-injection # pylint: disable=sql-injection
res = dict(map(lambda x: (x, []), partner_ids)) res = dict(map(lambda x: (x, []), partner_ids))
partners = ', '.join([str(i) for i in partner_ids]) partners = ', '.join([str(i) for i in partner_ids])
@ -113,7 +115,8 @@ class CustomerActivityStatement(models.AbstractModel):
credit, amount, blocked, currency_id credit, amount, blocked, currency_id
FROM Q2 FROM Q2
ORDER BY date, date_maturity, move_id""" % ( ORDER BY date, date_maturity, move_id""" % (
self._display_lines_sql_q1(partners, date_start, date_end),
self._display_lines_sql_q1(partners, date_start, date_end,
account_type),
self._display_lines_sql_q2(company_id))) self._display_lines_sql_q2(company_id)))
for row in self.env.cr.dictfetchall(): for row in self.env.cr.dictfetchall():
res[row.pop('partner_id')].append(row) res[row.pop('partner_id')].append(row)
@ -176,7 +179,7 @@ class CustomerActivityStatement(models.AbstractModel):
""" % (self._get_reconcile_date(), date_end, """ % (self._get_reconcile_date(), date_end,
self._get_reconcile_date(), date_end) self._get_reconcile_date(), date_end)
def _show_buckets_sql_q1(self, partners, date_end):
def _show_buckets_sql_q1(self, partners, date_end, account_type):
return """ return """
SELECT l.partner_id, l.currency_id, l.company_id, l.move_id, SELECT l.partner_id, l.currency_id, l.company_id, l.move_id,
CASE WHEN l.balance > 0.0 CASE WHEN l.balance > 0.0
@ -207,14 +210,14 @@ class CustomerActivityStatement(models.AbstractModel):
ON pr.debit_move_id = l2.id ON pr.debit_move_id = l2.id
WHERE l2.date <= '%s' WHERE l2.date <= '%s'
) as pc ON pc.credit_move_id = l.id ) as pc ON pc.credit_move_id = l.id
WHERE l.partner_id IN (%s) AND at.type = 'receivable'
WHERE l.partner_id IN (%s) AND at.type = '%s'
AND (Q0.reconciled_date is null or AND (Q0.reconciled_date is null or
Q0.reconciled_date > '%s') Q0.reconciled_date > '%s')
AND l.date <= '%s' AND not l.blocked AND l.date <= '%s' AND not l.blocked
GROUP BY l.partner_id, l.currency_id, l.date, l.date_maturity, GROUP BY l.partner_id, l.currency_id, l.date, l.date_maturity,
l.amount_currency, l.balance, l.move_id, l.amount_currency, l.balance, l.move_id,
l.company_id l.company_id
""" % (date_end, date_end, partners, date_end, date_end)
""" % (date_end, date_end, partners, account_type, date_end, date_end)
def _show_buckets_sql_q2(self, date_end, minus_30, minus_60, minus_90, def _show_buckets_sql_q2(self, date_end, minus_30, minus_60, minus_90,
minus_120): minus_120):
@ -306,7 +309,8 @@ class CustomerActivityStatement(models.AbstractModel):
'minus_120': date_end - timedelta(days=120), 'minus_120': date_end - timedelta(days=120),
} }
def _get_account_show_buckets(self, company_id, partner_ids, date_end):
def _get_account_show_buckets(self, company_id, partner_ids, date_end,
account_type):
res = dict(map(lambda x: (x, []), partner_ids)) res = dict(map(lambda x: (x, []), partner_ids))
partners = ', '.join([str(i) for i in partner_ids]) partners = ', '.join([str(i) for i in partner_ids])
date_end = datetime.strptime( date_end = datetime.strptime(
@ -323,7 +327,7 @@ class CustomerActivityStatement(models.AbstractModel):
GROUP BY partner_id, currency_id, current, b_1_30, b_30_60, b_60_90, GROUP BY partner_id, currency_id, current, b_1_30, b_30_60, b_60_90,
b_90_120, b_over_120""" % ( b_90_120, b_over_120""" % (
self._show_buckets_sql_q0(date_end), self._show_buckets_sql_q0(date_end),
self._show_buckets_sql_q1(partners, date_end),
self._show_buckets_sql_q1(partners, date_end, account_type),
self._show_buckets_sql_q2( self._show_buckets_sql_q2(
full_dates['date_end'], full_dates['date_end'],
full_dates['minus_30'], full_dates['minus_30'],
@ -342,6 +346,7 @@ class CustomerActivityStatement(models.AbstractModel):
partner_ids = data['partner_ids'] partner_ids = data['partner_ids']
date_start = data['date_start'] date_start = data['date_start']
date_end = data['date_end'] date_end = data['date_end']
account_type = data['account_type']
today = fields.Date.today() today = fields.Date.today()
balance_start_to_display, buckets_to_display = {}, {} balance_start_to_display, buckets_to_display = {}, {}
@ -350,7 +355,7 @@ class CustomerActivityStatement(models.AbstractModel):
today_display, date_start_display, date_end_display = {}, {}, {} today_display, date_start_display, date_end_display = {}, {}, {}
balance_start = self._get_account_initial_balance( balance_start = self._get_account_initial_balance(
company_id, partner_ids, date_start)
company_id, partner_ids, date_start, account_type)
for partner_id in partner_ids: for partner_id in partner_ids:
balance_start_to_display[partner_id] = {} balance_start_to_display[partner_id] = {}
@ -362,7 +367,7 @@ class CustomerActivityStatement(models.AbstractModel):
line['balance'] line['balance']
lines = self._get_account_display_lines( lines = self._get_account_display_lines(
company_id, partner_ids, date_start, date_end)
company_id, partner_ids, date_start, date_end, account_type)
for partner_id in partner_ids: for partner_id in partner_ids:
lines_to_display[partner_id], amount_due[partner_id] = {}, {} lines_to_display[partner_id], amount_due[partner_id] = {}, {}
@ -394,7 +399,7 @@ class CustomerActivityStatement(models.AbstractModel):
if data['show_aging_buckets']: if data['show_aging_buckets']:
buckets = self._get_account_show_buckets( buckets = self._get_account_show_buckets(
company_id, partner_ids, date_end)
company_id, partner_ids, date_end, account_type)
for partner_id in partner_ids: for partner_id in partner_ids:
buckets_to_display[partner_id] = {} buckets_to_display[partner_id] = {}
for line in buckets[partner_id]: for line in buckets[partner_id]:
@ -418,6 +423,7 @@ class CustomerActivityStatement(models.AbstractModel):
'Date_start': date_start_display, 'Date_start': date_start_display,
'Date_end': date_end_display, 'Date_end': date_end_display,
'Date': today_display, 'Date': today_display,
'account_type': account_type,
} }
return self.env['report'].render( return self.env['report'].render(
'customer_activity_statement.statement', values=docargs) 'customer_activity_statement.statement', values=docargs)

10
customer_activity_statement/static/description/index.html

@ -1,7 +1,7 @@
<section class="oe_container"> <section class="oe_container">
<div class="oe_row oe_spaced"> <div class="oe_row oe_spaced">
<div class="oe_span12"> <div class="oe_span12">
<h2 class="oe_slogan">Customer Activity Statement</h2>
<h2 class="oe_slogan">Partner Activity Statement</h2>
</div> </div>
<div class="oe_span6"> <div class="oe_span6">
<div class="oe_demo oe_picture oe_screenshot"> <div class="oe_demo oe_picture oe_screenshot">
@ -10,12 +10,12 @@
</div> </div>
<div class="oe_span4"> <div class="oe_span4">
<p class="oe_mt32"><div style="text-align:justify">The activity statement provides <p class="oe_mt32"><div style="text-align:justify">The activity statement provides
details of all activity on the customer receivables between two selected dates. This
details of all activity on the receivables or payables of a partner between two selected dates. This
includes all invoices, refunds and payments. Any outstanding balance dated prior to includes all invoices, refunds and payments. Any outstanding balance dated prior to
the chosen statement period will appear as a forward balance at the top of the statement. the chosen statement period will appear as a forward balance at the top of the statement.
The list is displayed in chronological order and is split by currencies.<br><br>Aging The list is displayed in chronological order and is split by currencies.<br><br>Aging
details can be shown in the report, expressed in aging buckets (30 days due, ...), details can be shown in the report, expressed in aging buckets (30 days due, ...),
so the customer can review how much is open, due or overdue.</div></p>
so the customer or vendor can review how much is open, due or overdue.</div></p>
</div> </div>
</div> </div>
</section> </section>
@ -44,8 +44,8 @@ so the customer can review how much is open, due or overdue.</div></p>
<div class="oe_span12"> <div class="oe_span12">
<p class="oe_mt32">To use this module, you need to: <p class="oe_mt32">To use this module, you need to:
<ul> <ul>
<li>Go to <code>Customers</code> and select one or more</li>
<li>Press '<code>Action > Customer Activity Statement</code>'</li>
<li>Go to <code>Customers</code> or <code>Vendors</code> and select one or more</li>
<li>Press '<code>Action > Partner Activity Statement</code>'</li>
<li>Indicate if you want to display aging buckets</li> <li>Indicate if you want to display aging buckets</li>
</ul> </ul>
</p> </p>

7
customer_activity_statement/views/statement.xml

@ -21,8 +21,11 @@
<br/> <br/>
<t t-foreach="Lines[o.id]" t-as="currency"> <t t-foreach="Lines[o.id]" t-as="currency">
<br t-if="not currency_first" /> <br t-if="not currency_first" />
<p>
Activity Statement between <span t-esc="Date_start[o.id]" /> and <span t-esc="Date_end[o.id]" /> in <span t-esc="Currencies[o.id][currency].name"/>:
<p t-if="account_type == 'receivable'">
Customer Activity Statement between <span t-esc="Date_start[o.id]" /> and <span t-esc="Date_end[o.id]" /> in <span t-esc="Currencies[o.id][currency].name"/>:
</p>
<p t-if="account_type == 'payable'">
Supplier Activity Statement between <span t-esc="Date_start[o.id]" /> and <span t-esc="Date_end[o.id]" /> in <span t-esc="Currencies[o.id][currency].name"/>:
</p> </p>
<table class="table table-condensed" style="border: 1px solid black; border-collapse: collapse;"> <table class="table table-condensed" style="border: 1px solid black; border-collapse: collapse;">
<thead> <thead>

4
customer_activity_statement/wizard/customer_activity_statement_wizard.py

@ -31,6 +31,9 @@ class CustomerActivityStatementWizard(models.TransientModel):
) )
filter_partners_non_due = fields.Boolean( filter_partners_non_due = fields.Boolean(
string='Don\'t show partners with no due entries', default=True) string='Don\'t show partners with no due entries', default=True)
account_type = fields.Selection(
[('receivable', 'Receivable'),
('payable', 'Payable')], string='Account type', default='receivable')
@api.multi @api.multi
def button_export_pdf(self): def button_export_pdf(self):
@ -46,6 +49,7 @@ class CustomerActivityStatementWizard(models.TransientModel):
'partner_ids': self._context['active_ids'], 'partner_ids': self._context['active_ids'],
'show_aging_buckets': self.show_aging_buckets, 'show_aging_buckets': self.show_aging_buckets,
'filter_non_due_partners': self.filter_partners_non_due, 'filter_non_due_partners': self.filter_partners_non_due,
'account_type': self.account_type,
} }
def _export(self): def _export(self):

11
customer_activity_statement/wizard/customer_activity_statement_wizard.xml

@ -2,7 +2,7 @@
<odoo> <odoo>
<!-- wizard action on res.partner --> <!-- wizard action on res.partner -->
<act_window id="customer_activity_statement_wizard_action" <act_window id="customer_activity_statement_wizard_action"
name="Customer Activity Statement"
name="Partner Activity Statement"
src_model="res.partner" src_model="res.partner"
res_model="customer.activity.statement.wizard" res_model="customer.activity.statement.wizard"
view_type="form" view_mode="form" view_type="form" view_mode="form"
@ -17,16 +17,21 @@
<form name="Report Options"> <form name="Report Options">
<div style="text-align:justify"> <div style="text-align:justify">
<label string="The activity statement provides details of all activity on <label string="The activity statement provides details of all activity on
the customer receivables between two selected dates. This includes all invoices,
a partner's receivables and payables between two selected dates. This includes all invoices,
refunds and payments. Any outstanding balance dated prior to the chosen statement refunds and payments. Any outstanding balance dated prior to the chosen statement
period will appear as a forward balance at the top of the statement. The list is period will appear as a forward balance at the top of the statement. The list is
displayed in chronological order and is split by currencies."/><br/><br/> displayed in chronological order and is split by currencies."/><br/><br/>
<label string="Aging details can be shown in the report, expressed in aging <label string="Aging details can be shown in the report, expressed in aging
buckets (30 days due, ...), so the customer can review how much is open, due or overdue."/>
buckets (30 days due, ...), so the customer or vendor can review how much is open, due or overdue."/>
</div><hr/> </div><hr/>
<group name="main_info"> <group name="main_info">
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/> <field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group> </group>
<group name="account_type">
<label for="account_type"/>
<field name="account_type" nolabel="1" widget="radio"/>
</group>
<group name="dates"> <group name="dates">
<field name="date_start"/> <field name="date_start"/>
<field name="date_end"/> <field name="date_end"/>

Loading…
Cancel
Save