You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

433 lines
16 KiB

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 opendons_recurring_donation(models.Model):
_name = 'opendons.recurring_donation_configuration'
_description = 'recurring donation management'
generation_day=fields.Integer('Generation day in the month')
limite_days_before=fields.Integer('Limite_days before generation day')
class DonationDonation(models.Model):
_inherit = 'donation.donation'
donor_id=fields.Char(related='partner_id.donor_id')
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'
)
@api.model
def create(self, vals):
vals['tax_receipt_option']='annual'
res = super(DonationDonation, self).create(vals)
#res.tax_receipt_option='annual'
# sepa_payment_method=self.env['account.payment.method'].search([('code','=','sepa_direct_debit')])
# if sepa_payment_method:
# sepa_payment_mode=self.env['account.payment.mode'].search([('payment_method_id','=',int( sepa_payment_method))])
# if sepa_payment_mode:
# res.payment_mode_id=sepa_payment_mode.id
# else:
# raise Warning('Please configure mode sepa payment')
# else:
# raise Warning('Please configure method sepa payment')
return res
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)
#mise à jour de la date de dernière génération
donation.lastexecution_date=datetime.now().date()
payment_mode_id=donation.payment_mode_id.id
if not new_donation_ids : raise Warning ("aucun don n'a été généré")
#on teste l'existence d'un ordre de paiement en status brouillon
#si plusieurs, c'est le dernier créé qui sera alimenté
#payorder=self.env['account.payment.order'].search([('state','=','draft')],order='create_date desc', limit=2)
#if payorder[0]:
# payorder_id=self.update_direct_debit_payment_order(new_donation_ids,payment_mode_id,payorder[0])
#sinon création de l'ordre de paiement SEPA avec tous les dons générés
#else:
payorder_id=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,
# }
# )
action = self.env.ref("account_payment_order.account_payment_order_inbound_action").sudo().read([])[0]
action.update(
{
"view_mode": "form",
"view_type":"list",
"res_id": payorder_id if payorder_id else False
}
)
#affichage de l'ordre de prélèvement
#action = self.env.ref("account_payment_order.account_payment_order_inbound_action").sudo().read([])[0]
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()
vals={}
vals['payment_mode_id']=payment_mode_id
payorder = apoo.create(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 int(payorder.id)
def update_direct_debit_payment_order(self,donation_ids,payment_mode_id,payorder):
payorder_vals = {"payment_mode_id": payment_mode_id}
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 int(payorder.id)
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
def recurring_donation_action(self):
sepa_payment_method=self.env['account.payment.method'].search([('code','=','sepa_direct_debit')])
if sepa_payment_method:
sepa_payment_mode=self.env['account.payment.mode'].search([('payment_method_id','=',int( sepa_payment_method))])
if sepa_payment_mode:
payment_mode_id=sepa_payment_mode.id
else:
raise Warning('Please configure mode sepa payment')
else:
raise Warning('Please configure method sepa payment')
action = self.env.ref("opendons.donation_recurring_action").sudo().read([])[0]
action.update(
{
"res_model": 'donation.donation',
"view_mode": 'tree,form,pivot,graph',
"context": {'default_recurring_template': 'active', 'recurring_view': True,'default_payment_mode_id':payment_mode_id,
'default_tax_receipt_option':'annual'},
"domain": [('recurring_template', '!=', False)]
}
)
return action
def payment_order_action(self):
#payorder=self.env['account.payment.order'].search([('state','=','draft')],order='create_date desc', limit=2)
action = self.env.ref("account_payment_order.account_payment_order_inbound_action").sudo().read([])[0]
# action.update(
# {
# "view_mode": "tree",
# "view_type":"list",
# #"res_id": payorder[0].id if payorder[0].id else False
# }
# )
return action