diff --git a/__manifest__.py b/__manifest__.py index 5fb2936..fba33a8 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -32,6 +32,7 @@ 'views/phone.xml', 'views/partner.xml', 'views/donation.xml', + 'data/recurring_donation_configuration.xml', 'views/relationship.xml', 'views/operation.xml', 'views/templates.xml', diff --git a/models/__init__.py b/models/__init__.py index bd27d8b..f5ad92c 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -16,4 +16,5 @@ from . import aggregate from . import duplicate from . import template_rf from . import donation_tax_receipt -from . import laposte_ref \ No newline at end of file +from . import laposte_ref +from . import res_partner_bank \ No newline at end of file diff --git a/models/donation.py b/models/donation.py index 0af4c2e..deb7a5e 100644 --- a/models/donation.py +++ b/models/donation.py @@ -6,6 +6,12 @@ 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' @@ -61,6 +67,26 @@ class DonationDonation(models.Model): 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': @@ -96,6 +122,8 @@ class DonationDonation(models.Model): def generate_recurring_payment(self): #self.ensure_one() + + doo = self.env["donation.donation"] #chercher les templates de dons récurrents actifs @@ -110,6 +138,7 @@ class DonationDonation(models.Model): #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))]) @@ -147,19 +176,39 @@ class DonationDonation(models.Model): 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é") - #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) + #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 = 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( { - "domain": [("id", "in", new_donation_ids)], - "limit": 500, + "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): @@ -167,9 +216,10 @@ class DonationDonation(models.Model): 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) + vals={} + vals['payment_mode_id']=payment_mode_id + vals['sepa']=True + payorder = apoo.create(vals) msg = _( @@ -205,8 +255,48 @@ class DonationDonation(models.Model): break if donations:donation.message_post(body=msg) - return True + 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 " + "%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 int(payorder.id) + def validate_donation(self,donations): check_total = self.env["res.users"].has_group( @@ -297,4 +387,35 @@ class DonationDonation(models.Model): if donation.bank_statement_line_id: donation._reconcile_donation_from_bank_statement() donation.partner_id._update_donor_rank() - return \ No newline at end of file + return + def recurring_donation_action(self): + + action = self.env.ref("opendons.donation_recurring_action").sudo().read([])[0] + + action.update( + { + "res_model": 'donation.donation', + "name": 'Prélèvements automatiques : mai 2022', + "view_mode": 'tree,form,pivot,graph', + "context": {'default_recurring_template': 'active', 'recurring_view': True,'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": "form", + "view_type":"list", + "res_id": payorder[0].id if payorder[0].id else False + } + ) + + return action \ No newline at end of file diff --git a/models/partner.py b/models/partner.py index 95b3dd9..5c11504 100644 --- a/models/partner.py +++ b/models/partner.py @@ -286,29 +286,4 @@ class partner(models.Model): raise ValidationError('Invalid mobile') - - class ResPartnerBank(models.Model): - _inherit = 'res.partner.bank' - - @api.onchange('acc_number') - def _onchange_acc_number(self): - #validation IBAN - #https://www.regextester.com/115565 - if self.acc_number: - - regex = re.compile(r'(^(?:(?:IT|SM)\d{2}[A-Z]\d{22}|CY\d{2}[A-Z]\d{23}|NL\d{2}[A-Z]{4}\d{10}|LV\d{2}[A-Z]{4}\d{13}|(?:BG|BH|GB|IE)\d{2}[A-Z]{4}\d{14}|GI\d{2}[A-Z]{4}\d{15}|RO\d{2}[A-Z]{4}\d{16}|KW\d{2}[A-Z]{4}\d{22}|MT\d{2}[A-Z]{4}\d{23}|NO\d{13}|(?:DK|FI|GL|FO)\d{16}|MK\d{17}|(?:AT|EE|KZ|LU|XK)\d{18}|(?:BA|HR|LI|CH|CR)\d{19}|(?:GE|DE|LT|ME|RS)\d{20}|IL\d{21}|(?:AD|CZ|ES|MD|SA)\d{22}|PT\d{23}|(?:BE|IS)\d{24}|(?:FR|MR|MC)\d{25}|(?:AL|DO|LB|PL)\d{26}|(?:AZ|HU)\d{27}|(?:GR|MU)\d{28})$)+') - - if not re.fullmatch(regex, self.acc_number): - raise Warning('Invalid IBAN') - - @api.constrains('acc_number') - def _onchange_acc_number(self): - #validation IBAN - #https://www.regextester.com/115565 - if self.acc_number: - - regex = re.compile(r'(^(?:(?:IT|SM)\d{2}[A-Z]\d{22}|CY\d{2}[A-Z]\d{23}|NL\d{2}[A-Z]{4}\d{10}|LV\d{2}[A-Z]{4}\d{13}|(?:BG|BH|GB|IE)\d{2}[A-Z]{4}\d{14}|GI\d{2}[A-Z]{4}\d{15}|RO\d{2}[A-Z]{4}\d{16}|KW\d{2}[A-Z]{4}\d{22}|MT\d{2}[A-Z]{4}\d{23}|NO\d{13}|(?:DK|FI|GL|FO)\d{16}|MK\d{17}|(?:AT|EE|KZ|LU|XK)\d{18}|(?:BA|HR|LI|CH|CR)\d{19}|(?:GE|DE|LT|ME|RS)\d{20}|IL\d{21}|(?:AD|CZ|ES|MD|SA)\d{22}|PT\d{23}|(?:BE|IS)\d{24}|(?:FR|MR|MC)\d{25}|(?:AL|DO|LB|PL)\d{26}|(?:AZ|HU)\d{27}|(?:GR|MU)\d{28})$)+') - - if not re.fullmatch(regex, self.acc_number): - - raise Warning('Invalid IBAN') \ No newline at end of file + \ No newline at end of file diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv index e44956b..3f8b98a 100644 --- a/security/ir.model.access.csv +++ b/security/ir.model.access.csv @@ -34,3 +34,5 @@ access_opendons_duplicate_partner,opendons_duplicate_partner,model_opendons_dupl access_opendons_template_rf,opendons_template_rf,model_opendons_template_rf,donation.group_donation_manager,1,1,1,1 access_opendons_laposte_ref,opendons_laposte_ref,model_opendons_laposte_ref,donation.group_donation_manager,1,1,1,1 + +access_opendons_recurring_donation_configuration,opendons_recurring_donation_configuration,model_opendons_recurring_donation_configuration,donation.group_donation_manager,1,1,1,1 diff --git a/views/address.xml b/views/address.xml index 6050a22..5902442 100644 --- a/views/address.xml +++ b/views/address.xml @@ -75,7 +75,7 @@ - + diff --git a/views/donation.xml b/views/donation.xml index 8392baf..04b56ae 100644 --- a/views/donation.xml +++ b/views/donation.xml @@ -21,35 +21,49 @@ + + + + context.get('recurring_view') + + + + + + + + + + - - opendons.donation.recurring.tree - donation.donation - - - - - - - - + opendons.donation.recurring.tree donation.donation - - - + + + + + + + + + + + + + + + + @@ -106,16 +120,79 @@ code action=model.generate_recurring_payment() + + + resume res_id action + + code + + action = model.sudo().recurring_donation_action() + + + + + Payment order + + code + + action = model.sudo().payment_order_action() + + + + + name="Recurring donations" action="recurring_action_tmp" web_icon="opendons,static/description/recurring_donation.png"/> - + + + + + + + + + + + opendons.recurring_donation_configuration list + opendons.recurring_donation_configuration + + + + + + + + + + opendons.recurring_donation_configuration form + opendons.recurring_donation_configuration + +
+ + + + +
+
+
+ + + + configuration + opendons.recurring_donation_configuration + tree,form + + + + \ No newline at end of file