# -*- coding: utf-8 -*-
# © 2014 Compassion CH - Cyril Sester <csester@compassion.ch>
# © 2014 Serv. Tecnol. Avanzados - Pedro M. Baeza
# © 2015-2016 Akretion - Alexis de Lattre <alexis.delattre@akretion.com>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from openerp import models, fields, api, _
from openerp.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'

    format = fields.Selection(
        [('basic', 'Basic Mandate')], default='basic', required=True,
        string='Mandate Format', track_visibility='onchange')
    partner_bank_id = fields.Many2one(
        comodel_name='res.partner.bank', string='Bank Account',
        track_visibility='onchange')
    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')
    signature_date = fields.Date(string='Date of Signature of the Mandate',
                                 track_visibility='onchange')
    scan = fields.Binary(string='Scan of the Mandate')
    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.multi
    @api.constrains('state', 'partner_bank_id')
    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.multi
    @api.onchange('partner_bank_id')
    def mandate_partner_bank_change(self):
        for mandate in self:
            mandate.partner_id = mandate.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