|
|
@ -4,7 +4,6 @@ |
|
|
|
|
|
|
|
from odoo import models, api |
|
|
|
from odoo.tools import float_is_zero |
|
|
|
from odoo.osv import expression |
|
|
|
from datetime import date, datetime |
|
|
|
import operator |
|
|
|
|
|
|
@ -29,100 +28,91 @@ class OpenItemsReport(models.AbstractModel): |
|
|
|
'account_financial_report.report_open_items').render(rcontext) |
|
|
|
return result |
|
|
|
|
|
|
|
def _get_account_partial_reconciled(self, move_lines_data, date_at_object): |
|
|
|
reconciled_ids = [] |
|
|
|
for move_line in move_lines_data: |
|
|
|
if move_line['reconciled']: |
|
|
|
reconciled_ids += [move_line['id']] |
|
|
|
domain = [('max_date', '>=', date_at_object)] |
|
|
|
domain += expression.OR( |
|
|
|
[[('debit_move_id', 'in', reconciled_ids)], |
|
|
|
[('credit_move_id', 'in', reconciled_ids)]]) |
|
|
|
def _get_account_partial_reconciled(self, company_id, date_at_object): |
|
|
|
domain = [('max_date', '>', date_at_object), |
|
|
|
('company_id', '=', company_id)] |
|
|
|
fields = ['debit_move_id', 'credit_move_id', 'amount'] |
|
|
|
accounts_partial_reconcile = \ |
|
|
|
self.env['account.partial.reconcile'].search_read( |
|
|
|
domain=domain, |
|
|
|
fields=fields |
|
|
|
) |
|
|
|
debit_accounts_partial_amount = {} |
|
|
|
credit_accounts_partial_amount = {} |
|
|
|
debit_amount = {} |
|
|
|
credit_amount = {} |
|
|
|
for account_partial_reconcile_data in accounts_partial_reconcile: |
|
|
|
debit_move_id = account_partial_reconcile_data['debit_move_id'][0] |
|
|
|
credit_move_id = account_partial_reconcile_data['credit_move_id'][0] |
|
|
|
if debit_move_id not in debit_accounts_partial_amount.keys(): |
|
|
|
debit_accounts_partial_amount[debit_move_id] = 0.0 |
|
|
|
debit_accounts_partial_amount[debit_move_id] += \ |
|
|
|
if debit_move_id not in debit_amount.keys(): |
|
|
|
debit_amount[debit_move_id] = 0.0 |
|
|
|
debit_amount[debit_move_id] += \ |
|
|
|
account_partial_reconcile_data['amount'] |
|
|
|
if credit_move_id not in credit_accounts_partial_amount.keys(): |
|
|
|
credit_accounts_partial_amount[credit_move_id] = 0.0 |
|
|
|
credit_accounts_partial_amount[credit_move_id] += \ |
|
|
|
if credit_move_id not in credit_amount.keys(): |
|
|
|
credit_amount[credit_move_id] = 0.0 |
|
|
|
credit_amount[credit_move_id] += \ |
|
|
|
account_partial_reconcile_data['amount'] |
|
|
|
account_partial_reconcile_data.update({ |
|
|
|
'debit_move_id': debit_move_id, |
|
|
|
'credit_move_id': credit_move_id, |
|
|
|
}) |
|
|
|
return accounts_partial_reconcile, debit_accounts_partial_amount, \ |
|
|
|
credit_accounts_partial_amount |
|
|
|
return accounts_partial_reconcile, debit_amount, credit_amount |
|
|
|
|
|
|
|
@api.model |
|
|
|
def _get_query_domain(self, account_ids, partner_ids, date_at_object, |
|
|
|
target_move, company_id, date_from): |
|
|
|
query = """ |
|
|
|
WHERE aml.account_id in %s and aml.company_id = %s |
|
|
|
""" % (tuple(account_ids) if len(account_ids) > 1 else "(%s)" % |
|
|
|
account_ids[0], company_id) |
|
|
|
if date_from: |
|
|
|
query += " and aml.date >= '%s'" % date_from |
|
|
|
def _get_new_move_lines_domain(self, new_ml_ids, account_ids, company_id, |
|
|
|
partner_ids, target_moves): |
|
|
|
domain = [('account_id', 'in', account_ids), |
|
|
|
('company_id', '=', company_id), |
|
|
|
('id', 'in', new_ml_ids)] |
|
|
|
if partner_ids: |
|
|
|
query += " and aml.partner_id in %s" % (tuple(partner_ids),) |
|
|
|
if target_move == 'posted': |
|
|
|
query += " and am.state = 'posted'" |
|
|
|
if date_at_object >= date.today(): |
|
|
|
query += " and aml.reconciled IS FALSE" |
|
|
|
else: |
|
|
|
query += """ and ((aml.reconciled IS FALSE OR aml.date >= '%s') |
|
|
|
OR aml.full_reconcile_id IS NOT NULL)""" % date_at_object |
|
|
|
return query |
|
|
|
|
|
|
|
@api.model |
|
|
|
def _get_query(self, account_ids, partner_ids, date_at_object, |
|
|
|
target_move, company_id, date_from): |
|
|
|
aml_fields = [ |
|
|
|
'id', 'date', 'move_id', 'journal_id', 'account_id', 'partner_id', |
|
|
|
'ref', 'date_maturity', 'amount_residual', 'amount_currency', |
|
|
|
'amount_residual_currency', 'debit', 'credit', 'currency_id', |
|
|
|
'reconciled', 'full_reconcile_id'] |
|
|
|
query = "" |
|
|
|
|
|
|
|
# SELECT |
|
|
|
for field in aml_fields: |
|
|
|
if not query: |
|
|
|
query = "SELECT aml.%s" % field |
|
|
|
else: |
|
|
|
query += ", aml.%s" % field |
|
|
|
# name from res_partner |
|
|
|
query += ", rp.name as partner_name" |
|
|
|
# name from res_currency |
|
|
|
query += ", rc.name as currency_name" |
|
|
|
# state and name from account_move |
|
|
|
query += ", am.state, am.name as move_name" |
|
|
|
domain += [('partner_id', 'in', partner_ids)] |
|
|
|
if target_moves == 'posted': |
|
|
|
domain += [('move_id.state', '=', 'posted')] |
|
|
|
return domain |
|
|
|
|
|
|
|
# FROM |
|
|
|
query += """ |
|
|
|
FROM account_move_line as aml |
|
|
|
LEFT JOIN res_partner as rp |
|
|
|
ON aml.partner_id = rp.id |
|
|
|
LEFT JOIN res_currency as rc |
|
|
|
ON aml.currency_id = rc.id |
|
|
|
LEFT JOIN account_move as am |
|
|
|
ON am.id = aml.move_id |
|
|
|
""" |
|
|
|
def _recalculate_move_lines(self, move_lines, debit_ids, credit_ids, |
|
|
|
debit_amount, credit_amount, ml_ids, |
|
|
|
account_ids, company_id, partner_ids, |
|
|
|
target_moves): |
|
|
|
debit_ids = set(debit_ids) |
|
|
|
credit_ids = set(credit_ids) |
|
|
|
in_credit_but_not_in_debit = credit_ids - debit_ids |
|
|
|
reconciled_ids = list(debit_ids) + list(in_credit_but_not_in_debit) |
|
|
|
reconciled_ids = set(reconciled_ids) |
|
|
|
ml_ids = set(ml_ids) |
|
|
|
new_ml_ids = reconciled_ids - ml_ids |
|
|
|
new_ml_ids = list(new_ml_ids) |
|
|
|
new_domain = self._get_new_move_lines_domain(new_ml_ids, account_ids, |
|
|
|
company_id, partner_ids, |
|
|
|
target_moves) |
|
|
|
ml_fields = [ |
|
|
|
'id', 'name', 'date', 'move_id', 'journal_id', 'account_id', |
|
|
|
'partner_id', 'amount_residual', 'date_maturity', 'ref', |
|
|
|
'debit', 'credit', 'reconciled', 'currency_id', 'amount_currency', |
|
|
|
'amount_residual_currency'] |
|
|
|
new_move_lines = self.env['account.move.line'].search_read( |
|
|
|
domain=new_domain, fields=ml_fields |
|
|
|
) |
|
|
|
move_lines = move_lines + new_move_lines |
|
|
|
for move_line in move_lines: |
|
|
|
ml_id = move_line['id'] |
|
|
|
if ml_id in debit_ids: |
|
|
|
move_line['amount_residual'] += debit_amount[ml_id] |
|
|
|
if ml_id in credit_ids: |
|
|
|
move_line['amount_residual'] -= credit_amount[ml_id] |
|
|
|
return move_lines |
|
|
|
|
|
|
|
# WHERE |
|
|
|
query += self._get_query_domain(account_ids, partner_ids, |
|
|
|
date_at_object, target_move, |
|
|
|
company_id, date_from) |
|
|
|
return query |
|
|
|
@api.model |
|
|
|
def _get_move_lines_domain(self, company_id, account_ids, partner_ids, |
|
|
|
target_move, date_from): |
|
|
|
domain = [('account_id', 'in', account_ids), |
|
|
|
('company_id', '=', company_id), |
|
|
|
('reconciled', '=', False)] |
|
|
|
if partner_ids: |
|
|
|
domain += [('partner_id', 'in', partner_ids)] |
|
|
|
if target_move == 'posted': |
|
|
|
domain += [('move_id.state', '=', 'posted')] |
|
|
|
if date_from: |
|
|
|
domain += [('date', '>', date_from)] |
|
|
|
return domain |
|
|
|
|
|
|
|
def _get_accounts_data(self, accounts_ids): |
|
|
|
accounts = self.env['account.account'].browse(accounts_ids) |
|
|
@ -146,65 +136,59 @@ class OpenItemsReport(models.AbstractModel): |
|
|
|
'code': journal.code}}) |
|
|
|
return journals_data |
|
|
|
|
|
|
|
def _get_data(self, account_ids, partner_ids, date_at_object, target_move, |
|
|
|
company_id, date_from): |
|
|
|
query = self._get_query(account_ids, partner_ids, date_at_object, |
|
|
|
target_move, company_id, date_from) |
|
|
|
self._cr.execute(query) |
|
|
|
move_lines_data = self._cr.dictfetchall() |
|
|
|
account_ids = map(operator.itemgetter('account_id'), move_lines_data) |
|
|
|
accounts_data = self._get_accounts_data(list(account_ids)) |
|
|
|
journal_ids = map(operator.itemgetter('journal_id'), move_lines_data) |
|
|
|
journals_data = self._get_journals_data(list(journal_ids)) |
|
|
|
|
|
|
|
def _get_data( |
|
|
|
self, account_ids, partner_ids, date_at_object, |
|
|
|
target_move, company_id, date_from): |
|
|
|
domain = self._get_move_lines_domain(company_id, account_ids, |
|
|
|
partner_ids, target_move, |
|
|
|
date_from) |
|
|
|
ml_fields = [ |
|
|
|
'id', 'name', 'date', 'move_id', 'journal_id', 'account_id', |
|
|
|
'partner_id', 'amount_residual', 'date_maturity', 'ref', |
|
|
|
'debit', 'credit', 'reconciled', 'currency_id', 'amount_currency', |
|
|
|
'amount_residual_currency'] |
|
|
|
move_lines = self.env['account.move.line'].search_read( |
|
|
|
domain=domain, fields=ml_fields |
|
|
|
) |
|
|
|
journals_ids = set() |
|
|
|
partners_ids = set() |
|
|
|
partners_data = {} |
|
|
|
if date_at_object < date.today(): |
|
|
|
accounts_partial_reconcile, debit_accounts_partial_amount, \ |
|
|
|
credit_accounts_partial_amount = \ |
|
|
|
self._get_account_partial_reconciled(move_lines_data, |
|
|
|
acc_partial_rec, debit_amount, credit_amount = \ |
|
|
|
self._get_account_partial_reconciled(company_id, |
|
|
|
date_at_object) |
|
|
|
if accounts_partial_reconcile: |
|
|
|
debit_ids = map(operator.itemgetter('debit_move_id'), |
|
|
|
accounts_partial_reconcile) |
|
|
|
credit_ids = map(operator.itemgetter('credit_move_id'), |
|
|
|
accounts_partial_reconcile) |
|
|
|
for move_line in move_lines_data: |
|
|
|
if move_line['id'] in debit_ids: |
|
|
|
move_line['amount_residual'] += \ |
|
|
|
debit_accounts_partial_amount[move_line['id']] |
|
|
|
if move_line['id'] in credit_ids: |
|
|
|
move_line['amount_residual'] -= \ |
|
|
|
credit_accounts_partial_amount[move_line['id']] |
|
|
|
moves_lines_to_remove = [] |
|
|
|
for move_line in move_lines_data: |
|
|
|
if move_line['date'] > date_at_object or float_is_zero( |
|
|
|
move_line['amount_residual'], precision_digits=2): |
|
|
|
moves_lines_to_remove.append(move_line) |
|
|
|
if len(moves_lines_to_remove) > 0: |
|
|
|
for move_line_to_remove in moves_lines_to_remove: |
|
|
|
move_lines_data.remove(move_line_to_remove) |
|
|
|
partners_data = { |
|
|
|
0: { |
|
|
|
'id': 0, |
|
|
|
'name': 'Missing Partner' |
|
|
|
} |
|
|
|
} |
|
|
|
if acc_partial_rec: |
|
|
|
ml_ids = list(map(operator.itemgetter('id'), move_lines)) |
|
|
|
debit_ids = list(map(operator.itemgetter('debit_move_id'), |
|
|
|
acc_partial_rec)) |
|
|
|
credit_ids = list(map(operator.itemgetter('credit_move_id'), |
|
|
|
acc_partial_rec)) |
|
|
|
move_lines = self._recalculate_move_lines( |
|
|
|
move_lines, debit_ids, credit_ids, |
|
|
|
debit_amount, credit_amount, ml_ids, account_ids, |
|
|
|
company_id, partner_ids, target_move |
|
|
|
) |
|
|
|
move_lines = [move_line for move_line in move_lines if |
|
|
|
move_line['date'] <= date_at_object and not |
|
|
|
float_is_zero(move_line['amount_residual'], |
|
|
|
precision_digits=2)] |
|
|
|
|
|
|
|
open_items_move_lines_data = {} |
|
|
|
for move_line in move_lines_data: |
|
|
|
no_partner = True |
|
|
|
for move_line in move_lines: |
|
|
|
journals_ids.add(move_line['journal_id'][0]) |
|
|
|
acc_id = move_line['account_id'][0] |
|
|
|
# Partners data |
|
|
|
if move_line['partner_id']: |
|
|
|
no_partner = False |
|
|
|
prt_id = move_line['partner_id'][0] |
|
|
|
prt_name = move_line['partner_id'][1] |
|
|
|
else: |
|
|
|
prt_id = 0 |
|
|
|
prt_name = "Missing Partner" |
|
|
|
if prt_id not in partners_ids: |
|
|
|
partners_data.update({ |
|
|
|
move_line['partner_id']: { |
|
|
|
'id': move_line['partner_id'], |
|
|
|
'name': move_line['partner_name'], |
|
|
|
'currency_id': accounts_data[move_line[ |
|
|
|
'account_id']]['currency_id'], |
|
|
|
} |
|
|
|
prt_id: {'id': prt_id, 'name': prt_name} |
|
|
|
}) |
|
|
|
else: |
|
|
|
partners_data[0]['currency_id'] = accounts_data[move_line[ |
|
|
|
'account_id']]['currency_id'] |
|
|
|
partners_ids.add(prt_id) |
|
|
|
|
|
|
|
# Move line update |
|
|
|
original = 0 |
|
|
@ -214,32 +198,46 @@ class OpenItemsReport(models.AbstractModel): |
|
|
|
if not float_is_zero(move_line['debit'], precision_digits=2): |
|
|
|
original = move_line['debit'] |
|
|
|
|
|
|
|
if move_line['ref'] == move_line['name']: |
|
|
|
if move_line['ref']: |
|
|
|
ref_label = move_line['ref'] |
|
|
|
else: |
|
|
|
ref_label = '' |
|
|
|
elif not move_line['ref']: |
|
|
|
ref_label = move_line['name'] |
|
|
|
elif not move_line['name']: |
|
|
|
ref_label = move_line['ref'] |
|
|
|
else: |
|
|
|
ref_label = move_line['ref'] + str(' - ') + move_line['name'] |
|
|
|
|
|
|
|
move_line.update({ |
|
|
|
'date': move_line['date'].strftime("%d/%m/%Y"), |
|
|
|
'date': move_line['date'], |
|
|
|
'date_maturity': move_line["date_maturity"] |
|
|
|
and move_line["date_maturity"].strftime("%d/%m/%Y"), |
|
|
|
'original': original, |
|
|
|
'partner_id': 0 if no_partner else move_line['partner_id'], |
|
|
|
'partner_name': '' if no_partner else move_line['partner_name'], |
|
|
|
'ref': '' if not move_line['ref'] else move_line['ref'], |
|
|
|
'account': accounts_data[move_line['account_id']]['code'], |
|
|
|
'journal': journals_data[move_line['journal_id']]['code'], |
|
|
|
'partner_id': prt_id, |
|
|
|
'partner_name': prt_name, |
|
|
|
'ref_label': ref_label, |
|
|
|
'journal_id': move_line['journal_id'][0], |
|
|
|
'move_name': move_line['move_id'][1], |
|
|
|
'currency_id': move_line['currency_id'][0] |
|
|
|
if move_line['currency_id'] else False, |
|
|
|
'currency_name': move_line['currency_id'][1] |
|
|
|
if move_line['currency_id'] else False, |
|
|
|
}) |
|
|
|
|
|
|
|
# Open Items Move Lines Data |
|
|
|
if move_line['account_id'] not in open_items_move_lines_data.keys(): |
|
|
|
open_items_move_lines_data[move_line['account_id']] = { |
|
|
|
move_line['partner_id']: [move_line]} |
|
|
|
if acc_id not in open_items_move_lines_data.keys(): |
|
|
|
open_items_move_lines_data[acc_id] = {prt_id: [move_line]} |
|
|
|
else: |
|
|
|
if move_line['partner_id'] not in \ |
|
|
|
open_items_move_lines_data[move_line[ |
|
|
|
'account_id']].keys(): |
|
|
|
open_items_move_lines_data[move_line['account_id']][ |
|
|
|
move_line['partner_id']] = [move_line] |
|
|
|
if prt_id not in open_items_move_lines_data[acc_id].keys(): |
|
|
|
open_items_move_lines_data[acc_id][prt_id] = [move_line] |
|
|
|
else: |
|
|
|
open_items_move_lines_data[move_line['account_id']][ |
|
|
|
move_line['partner_id']].append(move_line) |
|
|
|
return move_lines_data, partners_data, journals_data, accounts_data, \ |
|
|
|
open_items_move_lines_data[acc_id][prt_id].append(move_line) |
|
|
|
journals_data = self._get_journals_data(list(journals_ids)) |
|
|
|
accounts_data = self._get_accounts_data( |
|
|
|
open_items_move_lines_data.keys()) |
|
|
|
return move_lines, partners_data, journals_data, accounts_data, \ |
|
|
|
open_items_move_lines_data |
|
|
|
|
|
|
|
@api.model |
|
|
@ -260,16 +258,28 @@ class OpenItemsReport(models.AbstractModel): |
|
|
|
return total_amount |
|
|
|
|
|
|
|
@api.model |
|
|
|
def _get_open_items_no_partners(self, open_items_move_lines_data): |
|
|
|
def _order_open_items_by_date( |
|
|
|
self, open_items_move_lines_data, show_partner_details): |
|
|
|
new_open_items = {} |
|
|
|
for acc_id in open_items_move_lines_data.keys(): |
|
|
|
new_open_items[acc_id] = {} |
|
|
|
move_lines = [] |
|
|
|
for prt_id in open_items_move_lines_data[acc_id]: |
|
|
|
for move_line in open_items_move_lines_data[acc_id][prt_id]: |
|
|
|
move_lines += [move_line] |
|
|
|
move_lines = sorted(move_lines, key=lambda k: (k['date'])) |
|
|
|
new_open_items[acc_id] = move_lines |
|
|
|
if not show_partner_details: |
|
|
|
for acc_id in open_items_move_lines_data.keys(): |
|
|
|
new_open_items[acc_id] = {} |
|
|
|
move_lines = [] |
|
|
|
for prt_id in open_items_move_lines_data[acc_id]: |
|
|
|
for move_line in open_items_move_lines_data[acc_id][prt_id]: |
|
|
|
move_lines += [move_line] |
|
|
|
move_lines = sorted(move_lines, key=lambda k: (k['date'])) |
|
|
|
new_open_items[acc_id] = move_lines |
|
|
|
else: |
|
|
|
for acc_id in open_items_move_lines_data.keys(): |
|
|
|
new_open_items[acc_id] = {} |
|
|
|
for prt_id in open_items_move_lines_data[acc_id]: |
|
|
|
new_open_items[acc_id][prt_id] = {} |
|
|
|
move_lines = [] |
|
|
|
for move_line in open_items_move_lines_data[acc_id][prt_id]: |
|
|
|
move_lines += [move_line] |
|
|
|
move_lines = sorted(move_lines, key=lambda k: (k['date'])) |
|
|
|
new_open_items[acc_id][prt_id] = move_lines |
|
|
|
return new_open_items |
|
|
|
|
|
|
|
@api.multi |
|
|
@ -291,10 +301,9 @@ class OpenItemsReport(models.AbstractModel): |
|
|
|
target_move, company_id, date_from) |
|
|
|
|
|
|
|
total_amount = self._calculate_amounts(open_items_move_lines_data) |
|
|
|
if not show_partner_details: |
|
|
|
open_items_move_lines_data = self._get_open_items_no_partners( |
|
|
|
open_items_move_lines_data |
|
|
|
) |
|
|
|
open_items_move_lines_data = self._order_open_items_by_date( |
|
|
|
open_items_move_lines_data, show_partner_details |
|
|
|
) |
|
|
|
return{ |
|
|
|
'doc_ids': [wizard_id], |
|
|
|
'doc_model': 'open.items.report.wizard', |
|
|
@ -306,6 +315,7 @@ class OpenItemsReport(models.AbstractModel): |
|
|
|
'date_at': date_at_object.strftime("%d/%m/%Y"), |
|
|
|
'hide_account_at_0': data['hide_account_at_0'], |
|
|
|
'target_move': data['target_move'], |
|
|
|
'journals_data': journals_data, |
|
|
|
'partners_data': partners_data, |
|
|
|
'accounts_data': accounts_data, |
|
|
|
'total_amount': total_amount, |
|
|
|