Sélectionner une révision Git
scop_invoice_idf.py 7,56 Kio
# © 2021 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api
class ScopInvoiceIDF(models.Model):
_name = "scop.invoice.idf"
_description = "Paiements IDF"
# ------------------------------------------------------
# Fields declaration
# ------------------------------------------------------
name = fields.Char('Libellé')
company_id = fields.Many2one(
comodel_name='res.company',
string='Société',
)
partner_id = fields.Many2one(
comodel_name='res.partner',
string='Adhérent',
required=True,
domain=[('is_company', '=', True)])
journal = fields.Char('Journal')
writing_date = fields.Date('Date écriture')
acc_doc = fields.Char('Numéro de pièce comptable')
year = fields.Char('Année')
type = fields.Selection([
('inv', 'Facture'),
('refund', 'Avoir'),
('reject', 'Rejet'),
('pay', 'Paiement')],
string='Type', required=True)
lettrage = fields.Char('Référence de lettrage')
currency_id = fields.Many2one(
comodel_name='res.currency',
string='Monnaie',
related='company_id.currency_id')
debit = fields.Monetary(string='Débit', currency_field='currency_id')
credit = fields.Monetary(string='Crédit', currency_field='currency_id')
amount_residual = fields.Float(
string='Reste à payer',
compute='_compute_amount_residual',
store=True, currency_field='currency_id'
)
state = fields.Selection(
string='Etat',
selection=[('no_invoice', 'Pas de facture associée'),
('awaiting_payments', 'En attente de paiements'),
('overpaid', 'La somme des paiements est supérieure au '
'montant de la facture'),
('paid', 'La facture a bien été réglée !')],
required=False,
search='_search_state',
compute='_compute_state')
invoice_id = fields.Many2one(
comodel_name='scop.invoice.idf',
string='Facture',
)
payments_ids = fields.One2many(
comodel_name='scop.invoice.idf',
inverse_name='invoice_id',
string='Paiements / Avoirs',
required=False, readonly=True)
# ------------------------------------------------------
# Computed fields
# ------------------------------------------------------
@api.depends('payments_ids', 'debit',
'payments_ids.debit', 'payments_ids.debit')
@api.multi
def _compute_amount_residual(self):
for r in self:
if r.type == 'inv':
if r.payments_ids:
amount_paid = sum(
r.payments_ids.mapped('credit'))
r.amount_residual = r.debit - amount_paid
else:
r.amount_residual = r.debit
@api.multi
def _compute_state(self):
"""
A line can be in different states :
- No invoice related to a payment / refund
- Too many payments related to one invoice
- Some payments are missing
- The invoice has been paid
"""
def which_state(amount_residual):
if amount_residual > 0:
return 'awaiting_payments'
elif amount_residual < 0:
return 'overpaid'
else:
return 'paid'
for r in self:
if r.type != 'inv':
if not r.invoice_id:
r.state = 'no_invoice'
else:
r.state = which_state(r.invoice_id.amount_residual)
else:
r.state = which_state(r.amount_residual)
@api.multi
def _search_state(self, operator, value):
recs = None
if operator == '=':
recs = self.search([]).filtered(lambda x: x.state == value)
elif operator == 'in':
recs = self.search([]).filtered(lambda x: x.state in value)
elif operator == '!=':
recs = self.search([]).filtered(lambda x: x.state != value)
elif operator == 'not in':
recs = self.search([]).filtered(lambda x: x.state not in value)
if recs:
return [('id', 'in', [x.id for x in recs])]
# ------------------------------------------------------
# Actions
# ------------------------------------------------------
def reconcile(self):
"""
Link payments and invoices if same letter for a given year
:return:
"""
years = set(self.mapped('year'))
partners = self.mapped('partner_id')
for year in years:
for partner in partners:
invoice_lines = self.search([
['year', '=', year],
['partner_id', '=', partner.id],
['type', '=', 'inv']])
letters = set(invoice_lines.mapped('lettrage'))
lines_to_lettre = self.search([
['year', '=', year],
['partner_id', '=', partner.id],
['type', '!=', 'inv']])
for line in lines_to_lettre:
if line.lettrage in letters:
line.invoice_id = invoice_lines.filtered(
lambda l: l.lettrage == line.lettrage)[0]
def action_open_payment(self):
return {
'type': 'ir.actions.act_window',
'name': 'Paiement / Avoir',
'views': [
[self.env.ref(
'cgscop_invoice_idf.view_scop_invoice_idf_form').id,
"form"]
],
'view_mode': 'form',
'res_model': 'scop.invoice.idf',
'target': 'current',
'res_id': self.id
}
def action_free_payment(self):
self.invoice_id = None
def action_show_payments(self):
form_view = self.env.ref(
'cgscop_invoice_idf.view_scop_invoice_idf_form').id
tree_view = self.env.ref(
'cgscop_invoice_idf.view_scop_invoice_idf_tree').id
return {
'type': 'ir.actions.act_window',
'name': 'Paiement / Avoir',
'views': [
[tree_view, "tree"], [form_view, "form"]
],
'view_mode': 'form',
'res_model': 'scop.invoice.idf',
'target': 'current',
'domain': [('id', 'in', self.payments_ids.ids)]
}
def action_show_invoice(self):
form_view = self.env.ref(
'cgscop_invoice_idf.view_scop_invoice_idf_form').id
return {
'type': 'ir.actions.act_window',
'name': 'Facture',
'views': [
[form_view, "form"]
],
'view_mode': 'form',
'res_model': 'scop.invoice.idf',
'target': 'current',
'res_id': self.invoice_id.id
}
def action_show_partner_invoice_idf(self):
form_view = self.env.ref(
'cgscop_invoice_idf.view_scop_invoice_idf_form').id
tree_view = self.env.ref(
'cgscop_invoice_idf.view_scop_invoice_idf_tree').id
return {
'type': 'ir.actions.act_window',
'name': 'Factures IDF - ' + self.partner_id.name,
'views': [
[tree_view, "tree"], [form_view, "form"]
],
'view_mode': 'form',
'res_model': 'scop.invoice.idf',
'target': 'current',
'domain': [('partner_id', '=', self.partner_id.id)]
}