OCA/l10n-italy

View on GitHub
l10n_it_ricevute_bancarie/models/riba.py

Summary

Maintainability
D
2 days
Test Coverage
# -*- coding: utf-8 -*-
##############################################################################
#
#    Copyright (C) 2012 Andrea Cometa.
#    Email: info@andreacometa.it
#    Web site: http://www.andreacometa.it
#    Copyright (C) 2012-2015 Lorenzo Battistini - Agile Business Group
#    Copyright (C) 2012 Domsense srl (<http://www.domsense.com>)
#    Copyright (C) 2014 Associazione Odoo Italia
#    (<http://www.odoo-italia.org>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as published
#    by the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp import fields, models, api, workflow, _
from openerp.exceptions import Warning as UserError
import openerp.addons.decimal_precision as dp


class RibaList(models.Model):

    @api.one
    def _get_acceptance_move_ids(self):
        move_ids = self.env['account.move']
        for line in self.line_ids:
            move_ids |= line.acceptance_move_id
        self.acceptance_move_ids = move_ids

    @api.one
    def _get_unsolved_move_ids(self):
        move_ids = self.env['account.move']
        for line in self.line_ids:
            move_ids |= line.unsolved_move_id
        self.unsolved_move_ids = move_ids

    @api.one
    def _get_payment_ids(self):
        move_lines = self.env['account.move.line']
        for line in self.line_ids:
            move_lines |= line.payment_ids
        self.payment_ids = move_lines

    _name = 'riba.distinta'
    _description = 'Riba list'

    name = fields.Char(
        'Reference', required=True, readonly=True,
        states={'draft': [('readonly', False)]},
        default=(lambda self: self.env['ir.sequence'].get('riba.distinta')))
    config_id = fields.Many2one(
        'riba.configuration', string='Configuration', select=True,
        required=True, readonly=True, states={'draft': [('readonly', False)]},
        help='Riba configuration to be used')
    state = fields.Selection([
        ('draft', 'Draft'),
        ('accepted', 'Accepted'),
        ('accredited', 'Accredited'),
        ('paid', 'Paid'),
        ('unsolved', 'Unsolved'),
        ('cancel', 'Canceled')], 'State', select=True, readonly=True,
        default='draft')
    line_ids = fields.One2many(
        'riba.distinta.line', 'distinta_id', 'Riba deadlines', readonly=True,
        states={'draft': [('readonly', False)]})
    user_id = fields.Many2one(
        'res.users', 'User', required=True, readonly=True,
        states={'draft': [('readonly', False)]},
        default=lambda self: self.env.user,)
    date_created = fields.Date(
        'Creation date', readonly=True,
        default=lambda self: fields.Date.context_today(self))
    date_accepted = fields.Date('Acceptance date')
    date_accreditation = fields.Date('Accreditation date')
    date_paid = fields.Date('Paid date', readonly=True)
    date_unsolved = fields.Date('Unsolved date', readonly=True)
    company_id = fields.Many2one(
        'res.company', 'Company', required=True, readonly=True,
        states={'draft': [('readonly', False)]},
        default=lambda self: self.env['res.company']._company_default_get(
            'riba.distinta'))
    acceptance_move_ids = fields.Many2many(
        'account.move',
        compute='_get_acceptance_move_ids',
        string="Acceptance Entries")
    accreditation_move_id = fields.Many2one(
        'account.move', 'Accreditation Entry', readonly=True)
    payment_ids = fields.Many2many(
        'account.move.line', compute='_get_payment_ids', string='Payments')
    unsolved_move_ids = fields.Many2many(
        'account.move',
        compute='_get_unsolved_move_ids',
        string="Unsolved Entries")
    type = fields.Selection(
        string="Type", related='config_id.type', readonly=True)
    registration_date = fields.Date(
        'Registration Date',
        states={'draft': [('readonly', False)],
                'cancel': [('readonly', False)], },
        select=True, readonly=True,
        required=True,
        default=lambda self: fields.Date.context_today(self),
        help="Keep empty to use the current date")

    @api.multi
    def unlink(self):
        for riba_list in self:
            if riba_list.state not in ('draft',  'cancel'):
                raise UserError(
                    'List %s is in state %s. You can only delete documents'
                    ' in state draft or canceled'
                    % (riba_list.name, riba_list.state))
        super(RibaList, self).unlink()

    @api.multi
    def confirm(self):
        for list in self:
            for line in list.line_ids:
                line.confirm()

    @api.multi
    def riba_new(self):
        self.state = 'draft'

    @api.multi
    def riba_cancel(self):
        for riba_list in self:
            for line in riba_list.line_ids:
                line.state = 'cancel'
                if line.acceptance_move_id:
                    line.acceptance_move_id.unlink()
                if line.unsolved_move_id:
                    line.unsolved_move_id.unlink()
            if riba_list.accreditation_move_id:
                riba_list.accreditation_move_id.unlink()
            riba_list.state = 'cancel'

    @api.onchange('date_accepted', 'date_accreditation')
    def _onchange_date(self):
        if self.date_accepted and self.date_accreditation:
            if self.date_accepted > self.date_accreditation:
                raise UserError(_(
                    "Date accreditation must be greater or equal to"
                    " date acceptance"))

    @api.multi
    def riba_accepted(self):
        self.state = 'accepted'
        if not self.date_accepted:
            self.date_accepted = fields.Date.context_today(self)

    @api.multi
    def riba_accredited(self):
        self.state = 'accredited'
        if not self.date_accreditation:
            self.date_accreditation = fields.Date.context_today(self)
        for riba_list in self:
            for line in riba_list.line_ids:
                line.state = 'accredited'

    @api.multi
    def riba_paid(self):
        self.state = 'paid'
        self.date_paid = fields.Date.context_today(self)

    @api.multi
    def riba_unsolved(self):
        self.state = 'unsolved'
        self.date_unsolved = fields.Date.context_today(self)

    @api.multi
    def test_state(self, state):
        for riba_list in self:
            for line in riba_list.line_ids:
                if line.state != state:
                    return False
        return True

    @api.multi
    def test_accepted(self):
        return self.test_state('confirmed')

    @api.multi
    def test_unsolved(self):
        return self.test_state('unsolved')

    @api.multi
    def test_paid(self):
        return self.test_state('paid')

    @api.multi
    def action_cancel_draft(self):
        for riba_list in self:
            workflow.trg_delete(
                self.env.user.id, 'riba.distinta', riba_list.id, self._cr)
            workflow.trg_create(
                self.env.user.id, 'riba.distinta', riba_list.id, self._cr)
            riba_list.state = 'draft'
            for line in riba_list.line_ids:
                line.state = 'draft'


class RibaListLine(models.Model):
    # TODO estendere la account_due_list per visualizzare e filtrare
    # in base alle riba ?
    _name = 'riba.distinta.line'
    _description = 'Riba details'
    _rec_name = 'sequence'

    @api.one
    def _get_line_values(self):
        self.amount = 0.0
        self.invoice_date = ""
        self.invoice_number = ""
        for move_line in self.move_line_ids:
            self.amount += move_line.amount
            if not self.invoice_date:
                self.invoice_date = str(fields.Date.from_string(
                    move_line.move_line_id.invoice.date_invoice
                ).strftime('%d/%m/%Y'))
            else:
                self.invoice_date = "%s, %s" % (
                    self.invoice_date, str(fields.Date.from_string(
                        move_line.move_line_id.invoice.date_invoice
                    ).strftime('%d/%m/%Y')))
            if not self.invoice_number:
                self.invoice_number = str(
                    move_line.move_line_id.invoice.internal_number)
            else:
                self.invoice_number = "%s, %s" % (self.invoice_number, str(
                    move_line.move_line_id.invoice.internal_number))

    amount = fields.Float(
        compute='_get_line_values', string="Amount")
    invoice_date = fields.Char(
        compute='_get_line_values', string="Invoice Date", size=256)
    invoice_number = fields.Char(
        compute='_get_line_values', string="Invoice Number", size=256)

    @api.multi
    def move_line_id_payment_get(self):
        # return the move line ids with the same account as the distinta line
        if not self.id:
            return []
        query = """ SELECT l.id
                    FROM account_move_line l, riba_distinta_line rdl
                    WHERE rdl.id = %s AND l.move_id = rdl.acceptance_move_id
                    AND l.account_id = rdl.acceptance_account_id
                """
        self._cr.execute(query, (self.id,))
        return [row[0] for row in self._cr.fetchall()]

    @api.multi
    def test_reconcilied(self):
        # check whether all corresponding account move lines are reconciled
        line_ids = self.move_line_id_payment_get()
        if not line_ids:
            return False
        query = "SELECT reconcile_id FROM account_move_line WHERE id IN %s"
        self._cr.execute(query, (tuple(line_ids),))
        reconcilied = all(row[0] for row in self._cr.fetchall())
        return reconcilied

    @api.multi
    def _compute_lines(self):
        for line in self:
            src = []
            lines = []
            if line.acceptance_move_id and not line.state == 'unsolved':
                for m in line.acceptance_move_id.line_id:
                    temp_lines = []
                    if m.reconcile_id and m.credit == 0.0:
                        temp_lines = map(
                            lambda x: x.id, m.reconcile_id.line_id)
                    elif m.reconcile_partial_id and m.credit == 0.0:
                        temp_lines = map(
                            lambda x: x.id,
                            m.reconcile_partial_id.line_partial_ids)
                    lines += [x for x in temp_lines if x not in lines]
                    src.append(m.id)

            lines = filter(lambda x: x not in src, lines)
            line.payment_ids = self.env['account.move.line'].browse(lines)

    sequence = fields.Integer('Number')
    move_line_ids = fields.One2many(
        'riba.distinta.move.line', 'riba_line_id', string='Credit move lines')
    acceptance_move_id = fields.Many2one(
        'account.move', string='Acceptance Entry', readonly=True)
    unsolved_move_id = fields.Many2one(
        'account.move', string='Unsolved Entry', readonly=True)
    acceptance_account_id = fields.Many2one(
        'account.account', string='Acceptance Account')
    bank_id = fields.Many2one('res.partner.bank', string='Debitor Bank')
    iban = fields.Char(
        related='bank_id.iban', string='IBAN', store=False,
        readonly=True)
    distinta_id = fields.Many2one(
        'riba.distinta', string='List', required=True, ondelete='cascade')
    partner_id = fields.Many2one(
        'res.partner', string="Cliente", readonly=True)
    due_date = fields.Date("Due date", readonly=True)
    state = fields.Selection([
        ('draft', 'Draft'),
        ('confirmed', 'Confirmed'),
        ('accredited', 'Accredited'),
        ('paid', 'Paid'),
        ('unsolved', 'Unsolved'),
        ('cancel', 'Canceled'),
    ], 'State', select=True, readonly=True, track_visibility='onchange')
    payment_ids = fields.Many2many(
        'account.move.line', compute='_compute_lines', string='Payments')
    type = fields.Selection(
        string="Type", related='distinta_id.config_id.type', readonly=True)
    config_id = fields.Many2one(
        string="Configuration", related='distinta_id.config_id',
        readonly=True, store=True)

    @api.multi
    def confirm(self):
        move_pool = self.pool['account.move']
        move_line_pool = self.pool['account.move.line']
        for line in self:
            journal = line.distinta_id.config_id.acceptance_journal_id
            total_credit = 0.0
            period_id = self.pool['account.period'].find(
                self._cr, self.env.user.id,
                line.distinta_id.registration_date)
            move_id = move_pool.create(self._cr, self.env.user.id, {
                'ref': 'Ri.Ba. %s - line %s' % (line.distinta_id.name,
                                                line.sequence),
                'journal_id': journal.id,
                'date': line.distinta_id.registration_date,
                'period_id': period_id and period_id[0] or False,
            }, self._context)
            to_be_reconciled = []
            for riba_move_line in line.move_line_ids:
                total_credit += riba_move_line.amount
                move_line_id = move_line_pool.create(
                    self._cr, self.env.user.id, {
                        'name': (
                            riba_move_line.move_line_id.invoice and
                            riba_move_line.move_line_id.invoice.number or
                            riba_move_line.move_line_id.name),
                        'partner_id': line.partner_id.id,
                        'account_id': (
                            riba_move_line.move_line_id.account_id.id),
                        'credit': riba_move_line.amount,
                        'debit': 0.0,
                        'move_id': move_id,
                    }, self._context)
                to_be_reconciled.append([move_line_id,
                                         riba_move_line.move_line_id.id])
            move_line_pool.create(self._cr, self.env.user.id, {
                'name': 'Ri.Ba. %s - line %s' % (line.distinta_id.name,
                                                 line.sequence),
                'account_id': (
                    line.acceptance_account_id.id or
                    line.distinta_id.config_id.acceptance_account_id.id
                    # in questo modo se la riga non ha conto accettazione
                    # viene prelevato il conto in configuration riba
                ),
                'partner_id': line.partner_id.id,
                'date_maturity': line.due_date,
                'credit': 0.0,
                'debit': total_credit,
                'move_id': move_id,
            }, self._context)
            move_pool.post(
                self._cr, self.env.user.id, [move_id], self._context)
            for reconcile_ids in to_be_reconciled:
                move_line_pool.reconcile_partial(self._cr, self.env.user.id,
                                                 reconcile_ids,
                                                 self._context)
            line.write({
                'acceptance_move_id': move_id,
                'state': 'confirmed',
            })
            line.distinta_id.signal_workflow('accepted')


class RibaListMoveLine(models.Model):

    _name = 'riba.distinta.move.line'
    _description = 'Riba details'
    _rec_name = 'amount'

    amount = fields.Float(
        'Amount', digits_compute=dp.get_precision('Account'))
    move_line_id = fields.Many2one(
        'account.move.line', string='Credit move line')
    riba_line_id = fields.Many2one(
        'riba.distinta.line', string='List line', ondelete='cascade')