from odoo import models, fields, api,_
|
|
from odoo.exceptions import UserError, ValidationError,Warning
|
|
from psycopg2 import sql, DatabaseError
|
|
from datetime import datetime
|
|
|
|
from werkzeug import utils
|
|
import base64
|
|
|
|
|
|
class DonationDonation(models.Model):
|
|
_inherit = 'donation.donation'
|
|
|
|
operation_id = fields.Many2one(
|
|
'opendons.operation',
|
|
string='Operation',
|
|
track_visibility='onchange',
|
|
ondelete='restrict',
|
|
required=True,
|
|
domain=[('state', '=', 'exported')]
|
|
|
|
)
|
|
# operation_state= fields.Char(related='operation_id.state')
|
|
|
|
segment_id = fields.Many2one(
|
|
'opendons.segment',
|
|
string='Segment',
|
|
track_visibility='onchange',
|
|
required=True,
|
|
ondelete='restrict'
|
|
|
|
)
|
|
|
|
end_date = fields.Date(
|
|
string='End Date',
|
|
index=True,
|
|
readonly=True,
|
|
track_visibility='onchange'
|
|
)
|
|
suspended_date = fields.Date(
|
|
string='Suspended Date',
|
|
index=True,
|
|
readonly=True,
|
|
track_visibility='onchange'
|
|
)
|
|
lastexecution_date = fields.Date(
|
|
string='Last execution Date',
|
|
index=True,
|
|
readonly=True,
|
|
track_visibility='onchange'
|
|
)
|
|
frequency =fields.Selection(
|
|
[('monthly','Monthly'), ('bimonthly','Bimonthly'),('quarterly','Quarterly'),('half-yearly','Half-yearly'),('annually','Annually')],
|
|
default='monthly'
|
|
)
|
|
|
|
payment_batch_id = fields.Many2one(
|
|
'opendons_payment_batch',
|
|
string='Payment Batch',
|
|
ondelete='set null'
|
|
)
|
|
|
|
def _default_payment_mode_id(self):
|
|
|
|
#if self.recurring_template=='active':
|
|
|
|
sepa_payment_method=self.env['account.payment.method'].search([('code','=','sepa_direct_debit')])
|
|
|
|
if sepa_payment_method:
|
|
|
|
id=int(sepa_payment_method.id)
|
|
return 4
|
|
else:
|
|
raise Warning('veuillez configurer la méthode de paiment SEPA')
|
|
|
|
payment_mode_id = fields.Many2one(
|
|
"account.payment.mode",
|
|
string="Payment Mode",
|
|
domain="[('company_id', '=', company_id), ('donation', '=', True)]",
|
|
copy=False,
|
|
tracking=True,
|
|
check_company=True,
|
|
states={"done": [("readonly", True)]}
|
|
|
|
)
|
|
|
|
|
|
|
|
@api.onchange('operation_id')
|
|
def _onchange_operation_id(self):
|
|
res = {}
|
|
res['domain']={'segment_id':[('operation_id', '=', self.operation_id.id)]}
|
|
return res
|
|
|
|
|
|
def generate_recurring_payment(self):
|
|
#self.ensure_one()
|
|
|
|
doo = self.env["donation.donation"]
|
|
#chercher les templates de dons récurrents actifs
|
|
donations = doo.search(
|
|
[
|
|
("recurring_template", "=", "active")
|
|
|
|
]
|
|
)
|
|
new_donation_ids = []
|
|
|
|
|
|
#pour chaque template de don récurrent
|
|
#création d'un don si les dates sont bonnes
|
|
for donation in donations:
|
|
generate=True
|
|
existing_recur_donations = doo.search([("source_recurring_id", "=",int(donation.id))])
|
|
|
|
if donation.donation_date>fields.Date.context_today(self):
|
|
generate=False
|
|
|
|
delta=0
|
|
if donation.frequency=='annually':delta=365
|
|
if donation.frequency=='half-yearly':delta=365/2
|
|
if donation.frequency=='quarterly':delta=365/4
|
|
if donation.frequency=='bimonthly':delta=365/6
|
|
if donation.frequency=='monthly':delta=365/12
|
|
|
|
if existing_recur_donations:
|
|
for d in existing_recur_donations:
|
|
days_diff=(d.donation_date-fields.Date.context_today(self)).days
|
|
if days_diff<=delta:
|
|
generate=False
|
|
break
|
|
|
|
#si tout est ok pour la date, génération du don
|
|
if generate==True:
|
|
default = {
|
|
"recurring_template":'',
|
|
"donation_date": fields.Date.context_today(self),
|
|
"source_recurring_id": donation.id,
|
|
"payment_ref": '',
|
|
"payment_mode_id":donation.payment_mode_id.id,
|
|
"mandate_required":'True',
|
|
"mandate_id":donation.mandate_id.id,
|
|
"state":"draft"
|
|
}
|
|
#creation du don à partir du template de don récurrent
|
|
new_donation = donation.copy(default=default)
|
|
#ajout du don à la collection des dons générés pour affichage
|
|
new_donation_ids.append(new_donation.id)
|
|
payment_mode_id=donation.payment_mode_id.id
|
|
|
|
#création de l'ordre de paiement SEPA avec tous les dons générés
|
|
self.create_direct_debit_payment_order(new_donation_ids,payment_mode_id)
|
|
#affichage des dons générés
|
|
action = self.env.ref("donation.donation_action").sudo().read([])[0]
|
|
action.update(
|
|
{
|
|
"domain": [("id", "in", new_donation_ids)],
|
|
"limit": 500,
|
|
}
|
|
)
|
|
|
|
return action
|
|
|
|
def create_direct_debit_payment_order(self,donation_ids,payment_mode_id):
|
|
"""Create Direct debit payment order on donation validation or update
|
|
an existing draft Direct Debit pay order"""
|
|
|
|
apoo = self.env["account.payment.order"].sudo()
|
|
|
|
payorder_vals = {"payment_mode_id": payment_mode_id}
|
|
payorder = apoo.create(payorder_vals)
|
|
|
|
|
|
msg = _(
|
|
"A new draft direct debit order "
|
|
"<a href=# data-oe-model=account.payment.order "
|
|
"data-oe-id=%d>%s</a> has been automatically created"
|
|
) % (payorder.id, payorder.name)
|
|
|
|
|
|
# add payment lines
|
|
|
|
donations=self.env["donation.donation"].search([("id", "in",donation_ids)])
|
|
|
|
for donation in donations:
|
|
#validation du don et génération des écritures comptables
|
|
|
|
self.validate_donation(donation)
|
|
|
|
|
|
|
|
|
|
if donation.payment_mode_id.payment_type == "inbound":
|
|
|
|
|
|
#génération de la ligne de paiement dans l'ordre de prélèvement
|
|
payment_account_id = (
|
|
donation.payment_mode_id.fixed_journal_id.payment_debit_account_id.id
|
|
)
|
|
|
|
for mline in donation.move_id.line_ids:
|
|
if mline.account_id.id == payment_account_id:
|
|
mline.sudo().create_payment_line_from_move_line(payorder)
|
|
break
|
|
|
|
if donations:donation.message_post(body=msg)
|
|
return True
|
|
|
|
|
|
def validate_donation(self,donations):
|
|
check_total = self.env["res.users"].has_group(
|
|
"donation.group_donation_check_total"
|
|
)
|
|
for donation in donations:
|
|
if donation.donation_date > fields.Date.context_today(self):
|
|
raise UserError(
|
|
_(
|
|
"The date of donation %s should be today "
|
|
"or in the past, not in the future!"
|
|
)
|
|
% donation.number
|
|
)
|
|
if not donation.line_ids:
|
|
raise UserError(
|
|
_(
|
|
"Cannot validate donation %s because it doesn't "
|
|
"have any lines!"
|
|
)
|
|
% donation.number
|
|
)
|
|
|
|
if donation.currency_id.is_zero(donation.amount_total):
|
|
raise UserError(
|
|
_("Cannot validate donation %s because the " "total amount is 0!")
|
|
% donation.number
|
|
)
|
|
|
|
if donation.state != "draft":
|
|
raise UserError(
|
|
_(
|
|
"Cannot validate donation %s because it is not "
|
|
"in draft state."
|
|
)
|
|
% donation.number
|
|
)
|
|
|
|
if check_total and donation.currency_id.compare_amounts(
|
|
donation.check_total, donation.amount_total
|
|
):
|
|
raise UserError(
|
|
_(
|
|
"The amount of donation %s (%s) is different "
|
|
"from the sum of the donation lines (%s)."
|
|
)
|
|
% (
|
|
donation.number,
|
|
format_amount(
|
|
self.env, donation.check_total, donation.currency_id
|
|
),
|
|
format_amount(
|
|
self.env, donation.amount_total, donation.currency_id
|
|
),
|
|
)
|
|
)
|
|
full_in_kind = all([line.in_kind for line in donation.line_ids])
|
|
if not donation.payment_mode_id and not full_in_kind:
|
|
raise UserError(
|
|
_(
|
|
"Payment Mode is not set on donation %s (only fully "
|
|
"in-kind donations don't require a payment mode)."
|
|
)
|
|
% donation.number
|
|
)
|
|
|
|
vals = {"state": "done"}
|
|
if full_in_kind and donation.payment_mode_id:
|
|
vals["payment_mode_id"] = False
|
|
|
|
if not full_in_kind:
|
|
move_vals = donation._prepare_donation_move()
|
|
# when we have a full in-kind donation: no account move
|
|
if move_vals:
|
|
move = self.env["account.move"].create(move_vals)
|
|
move.action_post()
|
|
vals["move_id"] = move.id
|
|
else:
|
|
donation.message_post(
|
|
body=_("Full in-kind donation: no account move generated")
|
|
)
|
|
|
|
receipt = donation.generate_each_tax_receipt()
|
|
if receipt:
|
|
vals["tax_receipt_id"] = receipt.id
|
|
|
|
donation.write(vals)
|
|
if donation.bank_statement_line_id:
|
|
donation._reconcile_donation_from_bank_statement()
|
|
donation.partner_id._update_donor_rank()
|
|
return
|