Skip to content
Extraits de code Groupes Projets
Valider ab38d2a3 rédigé par Benjamin - Le Filament's avatar Benjamin - Le Filament
Parcourir les fichiers

[add] payment schedule functionality

parent ff9efa1d
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
"security/security_rules.xml", "security/security_rules.xml",
"security/ir.model.access.csv", "security/ir.model.access.csv",
"views/account_invoice.xml", "views/account_invoice.xml",
"views/account_payment_term.xml",
"views/res_config_settings.xml", "views/res_config_settings.xml",
"views/scop_cotisation_task.xml", "views/scop_cotisation_task.xml",
], ],
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from . import account_invoice from . import account_invoice
from . import account_payment_term
from . import chart_template from . import chart_template
from . import res_company from . import res_company
from . import res_config_settings from . import res_config_settings
......
# © 2020 Le Filament (<http://www.le-filament.com>) # © 2020 Le Filament (<http://www.le-filament.com>)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
from odoo import models, fields, api from odoo import models, fields, api, _
from odoo.exceptions import UserError
class ScopAccountInvoice(models.Model): class ScopAccountInvoice(models.Model):
...@@ -44,11 +45,11 @@ class ScopAccountInvoice(models.Model): ...@@ -44,11 +45,11 @@ class ScopAccountInvoice(models.Model):
) )
nb_quarter = fields.Selection( nb_quarter = fields.Selection(
string='Nombre de trimestres de cotisation', string='Nombre de trimestres de cotisation',
selection=[('1', '1'), selection=[(1, '1'),
('2', '2'), (2, '2'),
('3', '3'), (3, '3'),
('4', '4')], (4, '4')],
default='4', default=4,
required=True) required=True)
is_sdd = fields.Boolean( is_sdd = fields.Boolean(
'Au prélèvement', 'Au prélèvement',
...@@ -77,6 +78,18 @@ class ScopAccountInvoice(models.Model): ...@@ -77,6 +78,18 @@ class ScopAccountInvoice(models.Model):
# ------------------------------------------------------ # ------------------------------------------------------
# Override Parent # Override Parent
# ------------------------------------------------------ # ------------------------------------------------------
def get_last_maturity_date(self, months, account_move_line_ids):
"""
Get the last maturity date from account_move_line
for a certain period (months = [])
:param months:
:param account_move_line_ids:
:return: last date_maturity
"""
line_ids = account_move_line_ids.filtered(
lambda l: l.date_maturity.month in months)
return line_ids[-1].date_maturity if line_ids else None
@api.multi @api.multi
def action_invoice_open(self): def action_invoice_open(self):
""" """
...@@ -84,6 +97,125 @@ class ScopAccountInvoice(models.Model): ...@@ -84,6 +97,125 @@ class ScopAccountInvoice(models.Model):
quand une facture cotisation devient valide quand une facture cotisation devient valide
""" """
results = super(ScopAccountInvoice, self).action_invoice_open() results = super(ScopAccountInvoice, self).action_invoice_open()
for inv in self:
if inv.is_contribution:
inv.set_scop_contribution()
return results
@api.multi
def action_move_create(self):
"""
Complete override parent
Pass invoice in payment_term.compute function to generate payment
schedule
:return: True
"""
account_move = self.env['account.move']
for inv in self:
if not inv.journal_id.sequence_id:
raise UserError(_('Please define sequence on the journal related to this invoice.'))
if not inv.invoice_line_ids.filtered(lambda line: line.account_id):
raise UserError(_('Please add at least one invoice line.'))
if inv.move_id:
continue
if not inv.date_invoice:
inv.write({'date_invoice': fields.Date.context_today(self)})
if not inv.date_due:
inv.write({'date_due': inv.date_invoice})
company_currency = inv.company_id.currency_id
# create move lines
# (one per invoice line + eventual taxes and analytic lines)
iml = inv.invoice_line_move_line_get()
iml += inv.tax_line_move_line_get()
diff_currency = inv.currency_id != company_currency
# create one move line for the total and possibly adjust
# the other lines amount
total, total_currency, iml = inv.compute_invoice_totals(
company_currency, iml)
name = inv.name or ''
if inv.payment_term_id:
totlines = inv.payment_term_id.with_context(
currency_id=company_currency.id).compute(total, inv.date_invoice, inv)[0]
res_amount_currency = total_currency
print(totlines)
for i, t in enumerate(totlines):
if inv.currency_id != company_currency:
amount_currency = company_currency._convert(
t[1],
inv.currency_id,
inv.company_id,
inv._get_currency_rate_date() or fields.Date.today())
else:
amount_currency = False
# last line: add the diff
res_amount_currency -= amount_currency or 0
if i + 1 == len(totlines):
amount_currency += res_amount_currency
iml.append({
'type': 'dest',
'name': name,
'price': t[1],
'account_id': inv.account_id.id,
'date_maturity': t[0],
'amount_currency': diff_currency and amount_currency,
'currency_id': diff_currency and inv.currency_id.id,
'invoice_id': inv.id
})
else:
iml.append({
'type': 'dest',
'name': name,
'price': total,
'account_id': inv.account_id.id,
'date_maturity': inv.date_due,
'amount_currency': diff_currency and total_currency,
'currency_id': diff_currency and inv.currency_id.id,
'invoice_id': inv.id
})
part = self.env['res.partner']._find_accounting_partner(
inv.partner_id)
line = [(0, 0, self.line_get_convert(l, part.id)) for l in iml]
line = inv.group_lines(iml, line)
line = inv.finalize_invoice_move_lines(line)
date = inv.date or inv.date_invoice
move_vals = {
'ref': inv.reference,
'line_ids': line,
'journal_id': inv.journal_id.id,
'date': date,
'narration': inv.comment,
}
move = account_move.create(move_vals)
# Pass invoice in method post: used if you want to get the same
# account move reference when creating the same invoice
# after a cancelled one:
move.post(invoice = inv)
# make the invoice point to that move
vals = {
'move_id': move.id,
'date': date,
'move_name': move.name,
}
inv.write(vals)
return True
# ------------------------------------------------------
# Common Function
# ------------------------------------------------------
@api.multi
def set_scop_contribution(self):
"""
Création d'une ligne dans scop.contribution
"""
for inv in self: for inv in self:
if inv.is_contribution: if inv.is_contribution:
year = inv.year year = inv.year
...@@ -116,16 +248,4 @@ class ScopAccountInvoice(models.Model): ...@@ -116,16 +248,4 @@ class ScopAccountInvoice(models.Model):
[10, 11, 12], account_move_line_ids), [10, 11, 12], account_move_line_ids),
'invoice_id': inv.id, 'invoice_id': inv.id,
}) })
return results return True
def get_last_maturity_date(self, months, account_move_line_ids):
"""
Get the last maturity date from account_move_line
for a certain period (months = [])
:param months:
:param account_move_line_ids:
:return: last date_maturity
"""
line_ids = account_move_line_ids.filtered(
lambda l: l.date_maturity.month in months)
return line_ids[-1].date_maturity if line_ids else None
# Copyright 2020 Le Filament
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
from odoo import fields, models, api
class AccountPaymentTerm(models.Model):
_inherit = 'account.payment.term'
is_contribution = fields.Boolean('Conditions de paiement des cotisations')
def compute(self, value, date_ref=False, invoice=False):
"""
Override la fonction compute du modèle account.payment.term
La fonction initiale checke les conditions de paiement et crée
les lignes de paiement associées
L'héritage permet de créer un échéancier en fonction de celui
défini sur la base de cotisations
"""
date_ref = date_ref or fields.Date.today()
amount = value
sign = value < 0 and -1 or 1
if self.env.context.get('currency_id'):
currency = self.env['res.currency'].browse(
self.env.context['currency_id'])
else:
currency = self.env.user.company_id.currency_id
# si base de cotisation
if self.is_contribution and invoice and (invoice.cotisation_cg_id or invoice.cotisation_aura_id):
result = []
if invoice.cotisation_cg_id:
base_contrib_field = 'cotisation_cg_id'
elif invoice.cotisation_aura_id:
base_contrib_field = 'cotisation_aura_id'
trimesters = {
4: invoice[base_contrib_field].trimester_1,
3: invoice[base_contrib_field].trimester_2,
2: invoice[base_contrib_field].trimester_3,
1: invoice[base_contrib_field].trimester_4,
}
for i in range(invoice.nb_quarter, 0, -1):
# Gestion de l'arrondi de la division
if i == 1:
amt = currency.round(amount)
else:
amt = currency.round(value / invoice.nb_quarter)
result.append((fields.Date.to_string(trimesters.get(i)), amt))
amount -= amt
return [result]
else:
return super(AccountPaymentTerm, self).compute(value, date_ref)
...@@ -16,7 +16,6 @@ class ScopCotisation(models.AbstractModel): ...@@ -16,7 +16,6 @@ class ScopCotisation(models.AbstractModel):
fields.Datetime.now().year - 1, fields.Datetime.now().year + 2)], fields.Datetime.now().year - 1, fields.Datetime.now().year + 2)],
string='Année de cotisation', string='Année de cotisation',
required=True) required=True)
company_id = fields.Many2one( company_id = fields.Many2one(
comodel_name='res.company', comodel_name='res.company',
string='Company', change_default=True, string='Company', change_default=True,
...@@ -29,7 +28,8 @@ class ScopCotisation(models.AbstractModel): ...@@ -29,7 +28,8 @@ class ScopCotisation(models.AbstractModel):
payment_term_id = fields.Many2one( payment_term_id = fields.Many2one(
comodel_name='account.payment.term', comodel_name='account.payment.term',
string="Conditions de paiement", string="Conditions de paiement",
required=True domain=[('is_contribution', '=', True)],
required=True,
) )
date_cotisation = fields.Date("Date de cotisation", required=True) date_cotisation = fields.Date("Date de cotisation", required=True)
...@@ -42,6 +42,10 @@ class ScopCotisation(models.AbstractModel): ...@@ -42,6 +42,10 @@ class ScopCotisation(models.AbstractModel):
invoiced_member_count = fields.Integer( invoiced_member_count = fields.Integer(
"Cotisations créées", "Cotisations créées",
compute='_compute_invoiced_member_count') compute='_compute_invoiced_member_count')
trimester_1 = fields.Date('1er Trimestre')
trimester_2 = fields.Date('2ème Trimestre')
trimester_3 = fields.Date('3ème Trimestre')
trimester_4 = fields.Date('4ème Trimestre')
# ------------------------------------------------------ # ------------------------------------------------------
# Compute fields # Compute fields
...@@ -66,7 +70,7 @@ class ScopCotisation(models.AbstractModel): ...@@ -66,7 +70,7 @@ class ScopCotisation(models.AbstractModel):
# Global functions # Global functions
# ------------------------------------------------------ # ------------------------------------------------------
def create_contribution(self, product, partner, type_contribution, def create_contribution(self, product, partner, type_contribution,
liasse=None, amount=0): liasse=None, amount=0, date=False):
Invoice = self.env['account.invoice'] Invoice = self.env['account.invoice']
InvoiceLine = self.env['account.invoice.line'] InvoiceLine = self.env['account.invoice.line']
...@@ -75,6 +79,7 @@ class ScopCotisation(models.AbstractModel): ...@@ -75,6 +79,7 @@ class ScopCotisation(models.AbstractModel):
('year', '=', self.year), ('year', '=', self.year),
('type_contribution_id', '=', type_contribution) ('type_contribution_id', '=', type_contribution)
]) ])
date_invoice = date if date else self.date_cotisation
if not exisiting_invoice: if not exisiting_invoice:
member_invoice = Invoice.create({ member_invoice = Invoice.create({
'partner_id': partner.id, 'partner_id': partner.id,
...@@ -88,7 +93,7 @@ class ScopCotisation(models.AbstractModel): ...@@ -88,7 +93,7 @@ class ScopCotisation(models.AbstractModel):
'account_id': partner.property_account_receivable_id.id, 'account_id': partner.property_account_receivable_id.id,
'payment_term_id': self.payment_term_id.id, 'payment_term_id': self.payment_term_id.id,
'payment_mode_id': partner.customer_payment_mode_id.id, 'payment_mode_id': partner.customer_payment_mode_id.id,
'date_invoice': self.date_cotisation, 'date_invoice': date_invoice,
}) })
else: else:
member_invoice = exisiting_invoice member_invoice = exisiting_invoice
......
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Copyright 2020 Le Filament
License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -->
<data>
<record id="view_payment_term_form_inherited" model="ir.ui.view">
<field name="name">account.payment.term.form</field>
<field name="model">account.payment.term</field>
<field name="inherit_id" ref="account.view_payment_term_form"/>
<field name="arch" type="xml">
<xpath expr="//group" position="after">
<group name="schedule">
<field name="is_contribution" widget="boolean_toggle"/>
</group>
</xpath>
</field>
</record>
</data>
</odoo>
\ No newline at end of file
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter