# -*- coding: utf-8 -*-
##############################################################################
#
#    OpenERP, Open Source Management Solution
#    Copyright (C) 2012 Domsense s.r.l. (<http://www.domsense.com>).
#    Copyright (C) 2012-2014 Agile Business Group sagl
#    (<http://www.agilebg.com>)
#
#    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.osv import fields, orm
from openerp.tools.translate import _
import openerp.addons.decimal_precision as dp


class AccountVoucher(orm.Model):
    _inherit = "account.voucher"

    _columns = {
        'line_total': fields.float(
            'Lines Total', digits_compute=dp.get_precision('Account'),
            readonly=True),
        # exclude_write_off field will be used by modules like
        # account_vat_on_payment and l10n_it_withholding_tax
        'exclude_write_off': fields.boolean(
            'Exclude write-off from tax on payment',
            help="""Select this if you want, when closing the invoice, the
            tax to be computed
            based on the invoice's totals instead of the paid amount"""),
    }

    def balance_move(self, cr, uid, move_id, context=None):
        currency_obj = self.pool.get('res.currency')
        move = self.pool.get('account.move').browse(cr, uid, move_id, context)
        amount = 0.0
        for line in move.line_id:
            amount += line.debit - line.credit
        amount = currency_obj.round(
            cr, uid, move.company_id.currency_id, amount)
        # check if balance differs for more than 1 decimal according to account
        # decimal precision
        if abs(amount * 10 ** dp.get_precision('Account')(cr)[1]) > 1:
            raise orm.except_orm(
                _('Error'),
                _('The generated payment entry is unbalanced for more than 1 '
                  'decimal'))
        if not currency_obj.is_zero(
            cr, uid, move.company_id.currency_id, amount
        ):
            for line in move.line_id:
                # adjust the first move line that's not receivable, payable or
                # liquidity
                if (
                    line.account_id.type != 'receivable' and
                    line.account_id.type != 'payable' and
                    line.account_id.type != 'liquidity'
                ):
                    if line.credit:
                        line.write({
                            'credit': line.credit + amount,
                        }, update_check=False)
                    elif line.debit:
                        line.write({
                            'debit': line.debit - amount,
                        }, update_check=False)
                    if line.tax_amount:
                        line.write({
                            'tax_amount': line.tax_amount + amount,
                        }, update_check=False)
                    break
        return amount

    def voucher_move_line_create(
        self, cr, uid, voucher_id, line_total,
        move_id, company_currency, current_currency, context=None
    ):
        res = super(AccountVoucher, self).voucher_move_line_create(
            cr, uid, voucher_id, line_total, move_id, company_currency,
            current_currency, context)
        self.write(cr, uid, voucher_id, {'line_total': res[0]}, context)
        return res

    def get_invoice_total(self, invoice):
        res = 0.0
        for inv_move_line in invoice.move_id.line_id:
            if inv_move_line.account_id.type in ('receivable', 'payable'):
                res += inv_move_line.debit or inv_move_line.credit
        return res

    def get_invoice_total_currency(self, invoice):
        res = 0.0
        for inv_move_line in invoice.move_id.line_id:
            if inv_move_line.account_id.type in ('receivable', 'payable'):
                res += abs(inv_move_line.amount_currency)
        return res

    def allocated_amounts_grouped_by_invoice(
        self, cr, uid, voucher, context=None
    ):
        '''

        this method builds a dictionary in the following form

        {
            first_invoice_id: {
                'allocated': 120.0,
                'total': 120.0,
                'total_currency': 0.0,
                'write-off': 20.0,
                'allocated_currency': 0.0,
                'foreign_currency_id': False, # int
                'currency-write-off': 0.0,
                }
            second_invoice_id: {
                'allocated': 50.0,
                'total': 100.0,
                'total_currency': 0.0,
                'write-off': 0.0,
                'allocated_currency': 0.0,
                'foreign_currency_id': False,
                'currency-write-off': 0.0,
                }
        }

        every amout is expressed in company currency.

        In order to compute cashed amount correctly, write-off will be
        subtract to reconciled amount.
        If more than one invoice is paid with this voucher, we distribute
        write-off equally (if allowed)

        '''
        res = {}
        ctx = dict(context) or {}
        company_currency = super(AccountVoucher, self)._get_company_currency(
            cr, uid, voucher.id, context=ctx)
        current_currency = super(AccountVoucher, self)._get_current_currency(
            cr, uid, voucher.id, context=ctx)
        for line in voucher.line_ids:
            if line.amount and line.move_line_id and line.move_line_id.invoice:
                if line.move_line_id.invoice.id not in res:
                    res[line.move_line_id.invoice.id] = {
                        'allocated': 0.0,
                        'total': 0.0,
                        'total_currency': 0.0,
                        'write-off': 0.0,
                        'allocated_currency': 0.0,
                        'foreign_currency_id': False,
                        'currency-write-off': 0.0,
                    }
                current_amount = line.amount
                if company_currency != current_currency:
                    ctx['date'] = voucher.date
                    current_amount = super(
                        AccountVoucher, self)._convert_amount(
                            cr, uid, line.amount, voucher.id, context=ctx)
                    res[line.move_line_id.invoice.id][
                        'allocated_currency'
                    ] += line.amount
                    res[line.move_line_id.invoice.id][
                        'foreign_currency_id'
                    ] = current_currency
                    res[line.move_line_id.invoice.id][
                        'total_currency'
                    ] = self.get_invoice_total_currency(
                        line.move_line_id.invoice)
                res[line.move_line_id.invoice.id][
                    'allocated'
                ] += current_amount
                res[line.move_line_id.invoice.id][
                    'total'
                ] = self.get_invoice_total(line.move_line_id.invoice)
        if res:
            # we use line_total as it can be != writeoff_amount in case of
            # multi currency
            write_off_per_invoice = voucher.line_total / len(res)
            if not voucher.company_id.allow_distributing_write_off and len(
                res
            ) > 1 and write_off_per_invoice:
                raise orm.except_orm(_('Error'), _(
                    'You are trying to pay with write-off more than one '
                    'invoice and distributing write-off is not allowed. '
                    'See company settings.'))
            if voucher.type == 'payment' or voucher.type == 'purchase':
                write_off_per_invoice = - write_off_per_invoice
            for inv_id in res:
                res[inv_id]['write-off'] = write_off_per_invoice
            if company_currency != current_currency:
                curr_write_off_per_invoice = voucher.writeoff_amount / len(res)
                if voucher.type == 'payment' or voucher.type == 'purchase':
                    curr_write_off_per_invoice = - curr_write_off_per_invoice
                for inv_id in res:
                    res[inv_id][
                        'currency-write-off'] = curr_write_off_per_invoice
        return res