# Copyright 2014 Compassion CH - Cyril Sester # Copyright 2014 Tecnativa - Pedro M. Baeza # Copyright 2015-16 Akretion - Alexis de Lattre # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from flectra import models, fields, api, _ from flectra.exceptions import UserError, ValidationError class AccountBankingMandate(models.Model): """The banking mandate is attached to a bank account and represents an authorization that the bank account owner gives to a company for a specific operation (such as direct debit) """ _name = 'account.banking.mandate' _description = "A generic banking mandate" _rec_name = 'unique_mandate_reference' _inherit = ['mail.thread'] _order = 'signature_date desc' def _get_default_partner_bank_id_domain(self): if 'default_partner_id' in self.env.context: return [('partner_id', '=', self.env.context.get( 'default_partner_id'))] else: return [] format = fields.Selection( [('basic', 'Basic Mandate')], default='basic', required=True, string='Mandate Format', track_visibility='onchange') type = fields.Selection( [('generic', 'Generic Mandate')], string='Type of Mandate', track_visibility='onchange' ) partner_bank_id = fields.Many2one( comodel_name='res.partner.bank', string='Bank Account', track_visibility='onchange', domain=lambda self: self._get_default_partner_bank_id_domain(),) partner_id = fields.Many2one( comodel_name='res.partner', related='partner_bank_id.partner_id', string='Partner', store=True) company_id = fields.Many2one( comodel_name='res.company', string='Company', required=True, default=lambda self: self.env['res.company']._company_default_get( 'account.banking.mandate')) unique_mandate_reference = fields.Char( string='Unique Mandate Reference', track_visibility='onchange', copy=False, ) signature_date = fields.Date(string='Date of Signature of the Mandate', track_visibility='onchange') scan = fields.Binary( string='Scan of the Mandate', attachment=True, ) last_debit_date = fields.Date(string='Date of the Last Debit', readonly=True) state = fields.Selection([ ('draft', 'Draft'), ('valid', 'Valid'), ('expired', 'Expired'), ('cancel', 'Cancelled'), ], string='Status', default='draft', track_visibility='onchange', help="Only valid mandates can be used in a payment line. A cancelled " "mandate is a mandate that has been cancelled by the customer.") payment_line_ids = fields.One2many( comodel_name='account.payment.line', inverse_name='mandate_id', string="Related Payment Lines") _sql_constraints = [( 'mandate_ref_company_uniq', 'unique(unique_mandate_reference, company_id)', 'A Mandate with the same reference already exists for this company!')] @api.multi @api.constrains('signature_date', 'last_debit_date') def _check_dates(self): for mandate in self: if (mandate.signature_date and mandate.signature_date > fields.Date.context_today( mandate)): raise ValidationError( _("The date of signature of mandate '%s' " "is in the future!") % mandate.unique_mandate_reference) if (mandate.signature_date and mandate.last_debit_date and mandate.signature_date > mandate.last_debit_date): raise ValidationError( _("The mandate '%s' can't have a date of last debit " "before the date of signature." ) % mandate.unique_mandate_reference) @api.constrains('company_id', 'payment_line_ids', 'partner_bank_id') def _company_constrains(self): for mandate in self: if mandate.partner_bank_id.company_id and \ mandate.partner_bank_id.company_id != mandate.company_id: raise ValidationError( _("The company of the mandate %s differs from the " "company of partner %s.") % (mandate.display_name, mandate.partner_id.name)) if self.env['account.payment.line'].search( [('mandate_id', '=', mandate.id), ('company_id', '!=', mandate.company_id.id)], limit=1): raise ValidationError( _("You cannot change the company of mandate %s, " "as there exists payment lines referencing it that " "belong to another company.") % (mandate.display_name, )) if self.env['account.invoice'].search( [('mandate_id', '=', mandate.id), ('company_id', '!=', mandate.company_id.id)], limit=1): raise ValidationError( _("You cannot change the company of mandate %s, " "as there exists invoices referencing it that belong to " "another company.") % (mandate.display_name, )) if self.env['account.move.line'].search( [('mandate_id', '=', mandate.id), ('company_id', '!=', mandate.company_id.id)], limit=1): raise ValidationError( _("You cannot change the company of mandate %s, " "as there exists journal items referencing it that " "belong to another company.") % (mandate.display_name, )) if self.env['bank.payment.line'].search( [('mandate_id', '=', mandate.id), ('company_id', '!=', mandate.company_id.id)], limit=1): raise ValidationError( _("You cannot change the company of mandate %s, " "as there exists bank payment lines referencing it that " "belong to another company.") % (mandate.display_name, )) @api.multi @api.constrains('state', 'partner_bank_id', 'signature_date') def _check_valid_state(self): for mandate in self: if mandate.state == 'valid': if not mandate.signature_date: raise ValidationError( _("Cannot validate the mandate '%s' without a date of " "signature.") % mandate.unique_mandate_reference) if not mandate.partner_bank_id: raise ValidationError( _("Cannot validate the mandate '%s' because it is not " "attached to a bank account.") % mandate.unique_mandate_reference) @api.model def create(self, vals=None): if vals.get('unique_mandate_reference', 'New') == 'New': vals['unique_mandate_reference'] = \ self.env['ir.sequence'].next_by_code( 'account.banking.mandate') or 'New' return super(AccountBankingMandate, self).create(vals) @api.onchange('company_id') def _onchange_company_id(self): res = {} partner_domain = self._get_default_partner_bank_id_domain() if self.company_id: if self.partner_bank_id and \ self.company_id and \ self.partner_bank_id.company_id and \ self.partner_bank_id.company_id != self.company_id: self.partner_bank_id = False partner_domain.append(('company_id', '=', self.company_id.id)) domain = {'partner_bank_id': partner_domain} else: domain = { 'partner_bank_id': partner_domain} res['domain'] = domain return res @api.onchange('partner_bank_id') def mandate_partner_bank_change(self): self.partner_id = self.partner_bank_id.partner_id @api.multi def validate(self): for mandate in self: if mandate.state != 'draft': raise UserError( _('Mandate should be in draft state.')) self.write({'state': 'valid'}) return True @api.multi def cancel(self): for mandate in self: if mandate.state not in ('draft', 'valid'): raise UserError( _('Mandate should be in draft or valid state.')) self.write({'state': 'cancel'}) return True @api.multi def back2draft(self): """Allows to set the mandate back to the draft state. This is for mandates cancelled by mistake. """ for mandate in self: if mandate.state != 'cancel': raise UserError( _('Mandate should be in cancel state.')) self.write({'state': 'draft'}) return True