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', domain=[('state', '=', 'exported')] ) # operation_state= fields.Char(related='operation_id.state') segment_id = fields.Many2one( 'opendons.segment', string='Segment', track_visibility='onchange', 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.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 " "%s 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