116 lines
4.7 KiB
Python
116 lines
4.7 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
# (c) 2015 Pedro M. Baeza
|
||
|
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
||
|
|
||
|
from openerp import models, fields, api, exceptions, _
|
||
|
|
||
|
|
||
|
class AccountMoveMakeNetting(models.TransientModel):
|
||
|
_name = "account.move.make.netting"
|
||
|
|
||
|
journal = fields.Many2one(
|
||
|
comodel_name="account.journal", required=True,
|
||
|
domain="[('type', '=', 'general')]")
|
||
|
move_lines = fields.Many2many(comodel_name="account.move.line")
|
||
|
balance = fields.Float(readonly=True)
|
||
|
balance_type = fields.Selection(
|
||
|
selection=[('pay', 'To pay'), ('receive', 'To receive')],
|
||
|
readonly=True)
|
||
|
|
||
|
@api.model
|
||
|
def default_get(self, fields):
|
||
|
if len(self.env.context.get('active_ids', [])) < 2:
|
||
|
raise exceptions.ValidationError(
|
||
|
_("You should compensate at least 2 journal entries."))
|
||
|
move_lines = self.env['account.move.line'].browse(
|
||
|
self.env.context['active_ids'])
|
||
|
if (any(x not in ('payable', 'receivable') for
|
||
|
x in move_lines.mapped('account_id.type'))):
|
||
|
raise exceptions.ValidationError(
|
||
|
_("All entries must have a receivable or payable account"))
|
||
|
if any(move_lines.mapped('reconcile_id')):
|
||
|
raise exceptions.ValidationError(
|
||
|
_("All entries mustn't been reconciled"))
|
||
|
partner_id = None
|
||
|
for move in move_lines:
|
||
|
if (not move.partner_id or (
|
||
|
move.partner_id != partner_id and partner_id is not None)):
|
||
|
raise exceptions.ValidationError(
|
||
|
_("All entries should have a partner and the partner must "
|
||
|
"be the same for all."))
|
||
|
partner_id = move.partner_id
|
||
|
res = super(AccountMoveMakeNetting, self).default_get(fields)
|
||
|
res['move_lines'] = [(6, 0, move_lines.ids)]
|
||
|
balance = (sum(move_lines.mapped('debit')) -
|
||
|
sum(move_lines.mapped('credit')))
|
||
|
res['balance'] = abs(balance)
|
||
|
res['balance_type'] = 'pay' if balance < 0 else 'receive'
|
||
|
return res
|
||
|
|
||
|
@api.multi
|
||
|
def button_compensate(self):
|
||
|
self.ensure_one()
|
||
|
# Create account move
|
||
|
move = self.env['account.move'].create(
|
||
|
{
|
||
|
'ref': _('AR/AP netting'),
|
||
|
'journal_id': self.journal.id,
|
||
|
})
|
||
|
# Group amounts by account
|
||
|
account_groups = self.move_lines.read_group(
|
||
|
[('id', 'in', self.move_lines.ids)],
|
||
|
['account_id', 'debit', 'credit'], ['account_id'])
|
||
|
debtors = []
|
||
|
creditors = []
|
||
|
total_debtors = 0
|
||
|
total_creditors = 0
|
||
|
for account_group in account_groups:
|
||
|
balance = account_group['debit'] - account_group['credit']
|
||
|
group_vals = {
|
||
|
'account_id': account_group['account_id'][0],
|
||
|
'balance': abs(balance),
|
||
|
}
|
||
|
if balance > 0:
|
||
|
debtors.append(group_vals)
|
||
|
total_debtors += balance
|
||
|
else:
|
||
|
creditors.append(group_vals)
|
||
|
total_creditors += abs(balance)
|
||
|
# Create move lines
|
||
|
move_line_model = self.env['account.move.line']
|
||
|
netting_amount = min(total_creditors, total_debtors)
|
||
|
field_map = {1: 'debit', 0: 'credit'}
|
||
|
for i, group in enumerate([debtors, creditors]):
|
||
|
available_amount = netting_amount
|
||
|
for account_group in group:
|
||
|
if account_group['balance'] > available_amount:
|
||
|
amount = available_amount
|
||
|
else:
|
||
|
amount = account_group['balance']
|
||
|
move_line_vals = {
|
||
|
field_map[i]: amount,
|
||
|
'move_id': move.id,
|
||
|
'partner_id': self.move_lines[0].partner_id.id,
|
||
|
'date': move.date,
|
||
|
'period_id': move.period_id.id,
|
||
|
'journal_id': move.journal_id.id,
|
||
|
'name': move.ref,
|
||
|
'account_id': account_group['account_id'],
|
||
|
}
|
||
|
move_line_model.create(move_line_vals)
|
||
|
available_amount -= account_group['balance']
|
||
|
if available_amount <= 0:
|
||
|
break
|
||
|
# Make reconciliation
|
||
|
for move_line in move.line_id:
|
||
|
to_reconcile = move_line + self.move_lines.filtered(
|
||
|
lambda x: x.account_id == move_line.account_id)
|
||
|
to_reconcile.reconcile_partial()
|
||
|
# Open created move
|
||
|
action = self.env.ref('account.action_move_journal_line').read()[0]
|
||
|
action['view_mode'] = 'form'
|
||
|
del action['views']
|
||
|
del action['view_id']
|
||
|
action['res_id'] = move.id
|
||
|
return action
|