Newer
Older
# © 2022 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import tools
from odoo import models, fields, api
class ScopContributionReport(models.Model):
_name = "scop.contribution.report"
_description = "Vue cotisations"
_auto = False
_order = 'year desc, partner_id'
name = fields.Char(compute='_compute_name')
year = fields.Char('Année de cotisation')
source = fields.Selection(
string='Source',
selection=[('odoo', 'Odoo')],
required=True,)
type_contribution_id = fields.Many2one(
comodel_name="scop.contribution.type",
string="Type de cotisation",
readonly=True)
partner_id = fields.Many2one('res.partner', string='Partner', readonly=True)
amount_called = fields.Float('Montant Appelé')
amount_paid = fields.Float('Montant Payé')
amount_due = fields.Float('Montant Restant')
is_loss = fields.Boolean('Exonération/Perte', compute="_compute_is_loss")
payments = fields.Html('Paiements', compute="_compute_payments")
_depends = {
'account.invoice': [
'year', 'type_contribution_id', 'partner_id',
'amount_total_signed', 'residual_company_signed',
'state', 'type', 'is_contribution', 'refund_invoice_id'
],
}
# ------------------------------------------------------
# Sub Query
# ------------------------------------------------------
def _select_invoice(self):
select_str = """
SELECT
'odoo' as source,
CAST(i.year AS VARCHAR),
i.type_contribution_id,
i.partner_id,
SUM(i.amount_total_signed) AS amount_called,
SUM(i.amount_total_signed - i.residual_company_signed) AS amount_paid,
SUM(i.residual_company_signed) AS amount_due
"""
return select_str
def _from_invoice(self):
from_str = """
FROM
account_invoice i
"""
return from_str
def _where_invoice(self):
where_str = """
WHERE
i.state in ('open', 'paid', 'in_payment') AND
i.is_contribution = true
"""
return where_str
def _groupby_invoice(self):
groupby_str = """
GROUP BY
i.year,
i.type_contribution_id,
i.partner_id
"""
return groupby_str
def _query_invoice(self):
query = "(%s %s %s %s)" % (
self._select_invoice(), self._from_invoice(),
self._where_invoice(), self._groupby_invoice())
return query
def _subquery(self):
return self._query_invoice()
# ------------------------------------------------------
# Main Query
# ------------------------------------------------------
def _select(self):
select_str = """
SELECT
ROW_NUMBER() OVER(ORDER BY c.year, c.partner_id) AS id,
c.source,
c.year,
c.type_contribution_id,
c.partner_id,
SUM(c.amount_called) AS amount_called,
SUM(c.amount_paid) AS amount_paid,
SUM(c.amount_due) AS amount_due
FROM (
"""
return select_str
def _query_groupby(self):
return """
GROUP BY
c.year,
c.type_contribution_id,
c.partner_id,
c.source
"""
def _query_order(self):
return "ORDER BY c.year DESC"
def _query(self):
query = (
self._select() + self._subquery() + ') c ' +
self._query_groupby() + self._query_order()
)
return query
@api.model_cr
def init(self):
tools.drop_view_if_exists(self.env.cr, self._table)
self.env.cr.execute("""CREATE or REPLACE VIEW %s as (
%s
)""" % (
self._table, self._query()))
# ------------------------------------------------------
# Computed fields
# ------------------------------------------------------
@api.multi
def _compute_is_loss(self):
for contribution in self:
contribution.is_loss = contribution._get_is_loss()
@api.multi
def _compute_name(self):
for contribution in self:
contribution.name = (contribution.year + ' - ' +
contribution.type_contribution_id.name +
' - ' + contribution.partner_id.name)
@api.multi
def _compute_payments(self):
for contribution in self:
contribution.payments = contribution._get_payment()
# ------------------------------------------------------
# Business functions
# ------------------------------------------------------
invoice_ids = self.env['account.invoice'].sudo().search([
('year', '=', int(self.year)),
('partner_id', '=', self.partner_id.id),
('type_contribution_id', '=', self.type_contribution_id.id),
])
refund_ids = invoice_ids.filtered(lambda i: i.type == 'out_refund')
if refund_ids:
return True
else:
return False
def _get_payment(self):
self.ensure_one()
payments_html = False
if self.source == 'odoo':
invoice_ids = self.get_invoice_contribution()
payment_ids = invoice_ids.mapped('payment_move_line_ids')
if payment_ids:
payments = payment_ids.mapped(lambda p: {
'date': p.date,
'name': p.name,
'ref': p.ref,
'credit': p.credit,
'class': ''
} if not p.invoice_id else {
'date': p.date,
'name': p.name,
'ref': '',
'credit': p.credit,
'class': 'text-danger'
})
payments_html = self._get_html_table(payments)
if not payments_html:
payments_html = "<p>Il n'y a pas de paiements associés à cette cotisation</p>"
return payments_html
def get_invoice_contribution(self):
invoice_ids = self.env['account.invoice'].sudo().search([
('year', '=', int(self.year)),
('partner_id', '=', self.partner_id.id),
('type_contribution_id', '=', self.type_contribution_id.id),
('type', '=', 'out_invoice'),
'|',
('bordereau_id.state', 'not in', ('cancel',)),
('bordereau_id', '=', False)
return invoice_ids
def _get_html_table(self, payments):
"""
:param payments: list of dict {date, name, ref, amount}
@return: HTML table with payments
"""
start_html = """
<table class='table table-sm table-striped table-hover table-bordered'>
<thead><tr>
<th>Date</th>
<th>Libellé</th>
<th>Référence</th>
<th>Montant</th>
</tr></thead>
<tbody>
"""
content_html = ""
for payment in payments:
content_html += """
<td>%s</td>
<td>%s</td>
<td>%s</td>
<td class='text-right'>%.2f €</td>
</tr>
""" % (payment.get('class', ''),
payment.get('date', '').strftime('%d/%m/%Y'),
payment.get('name', ''), payment.get('ref', ''),
payment.get('credit', 0.0),)
end_html = "</tbody></table>"
return start_html + content_html + end_html