diff --git a/account_partner_aged_statement_webkit/report/partner_aged_statement_report.py b/account_partner_aged_statement_webkit/report/partner_aged_statement_report.py index 3d6eb68f..44058bc3 100644 --- a/account_partner_aged_statement_webkit/report/partner_aged_statement_report.py +++ b/account_partner_aged_statement_webkit/report/partner_aged_statement_report.py @@ -49,7 +49,7 @@ class PartnerAgedTrialReport(aged_trial_report): 'message': self._message, 'getLines30': self._lines_get_30, 'getLines3060': self._lines_get_30_60, - 'getLines60': self._lines_get60, + 'getLines60': self._lines_get_60, 'show_message': True, 'get_current_invoice_lines': self._get_current_invoice_lines, 'get_balance': self._get_balance, @@ -129,136 +129,48 @@ class PartnerAgedTrialReport(aged_trial_report): :return: a list of dict containing invoice data { 'date_due': the date of maturity + 'date_original': the date of the invoice + 'ref': the partner reference on the invoice 'amount_original': the original date 'amount_unreconciled': the amount left to pay - 'currency_id': the currency of the move line + 'currency_id': the currency of the invoice 'currency_name': the name of the currency - 'name': the name of the move line + 'name': the number of the invoice } """ # Only compute this method one time per partner if partner.id in self.partner_invoices_dict: return self.partner_invoices_dict[partner.id] - voucher_obj = pooler.get_pool(self.cr.dbname)['account.voucher'] - journal_obj = pooler.get_pool(self.cr.dbname)['account.journal'] - move_line_obj = pooler.get_pool(self.cr.dbname)['account.move.line'] - currency_obj = pooler.get_pool(self.cr.dbname)['res.currency'] - - currency = company.currency_id - - # Get the journal with the correct currency - journal_ids = journal_obj.search( - self.cr, self.uid, [ - ('type', 'in', ['bank', 'cash']), - ('currency', '=', currency.id), - ], context=self.localcontext) - - if not journal_ids: - journal_ids = journal_obj.search( - self.cr, self.uid, [('type', 'in', ['bank', 'cash'])], - context=self.localcontext) - - journal_id = journal_ids[0] - - # Retreive every invoice in a first time - voucher_lines = voucher_obj.recompute_voucher_lines( - self.cr, self.uid, ids=False, partner_id=partner.id, - journal_id=journal_id, price=0, currency_id=currency.id, - ttype=self.ttype, date=date, context=self.localcontext)['value'] - - # Map the result by move line - line_dict = { - line['move_line_id']: line for line in - voucher_lines['line_cr_ids'] + voucher_lines['line_dr_ids'] - } - - # If some of the invoices have different currency than the currency - # of the company, need to get the lines in these currencies - other_currencies = {} - for move_line in move_line_obj.browse( - self.cr, self.uid, line_dict.keys(), context=self.localcontext - ): - invoice = move_line.invoice - if invoice and invoice.currency_id.id != currency.id: - if invoice.currency_id.id in other_currencies: - other_currencies[invoice.currency_id.id]['move_line_ids'].\ - append(move_line.id) - else: - # Get the journal with the correct currency - journal_ids = journal_obj.search( - self.cr, self.uid, [ - ('type', 'in', ['bank', 'cash']), - ('currency', '=', invoice.currency_id.id), - ], context=self.localcontext) - - if not journal_ids: - journal_ids = journal_obj.search( - self.cr, self.uid, - [('type', 'in', ['bank', 'cash'])], - context=self.localcontext) - - journal_id = journal_ids[0] - - lines_in_currency = voucher_obj.recompute_voucher_lines( - self.cr, self.uid, ids=False, partner_id=partner.id, - journal_id=journal_id, price=0, - currency_id=invoice.currency_id.id, - ttype=self.ttype, date=date, - context=self.localcontext)['value'] - - other_currencies[invoice.currency_id.id] = { - 'lines_in_currency': { - line['move_line_id']: line for line in - lines_in_currency['line_cr_ids'] - + lines_in_currency['line_dr_ids'] - }, - 'move_line_ids': [move_line.id], - } - - for currency_id in other_currencies: - for move_line_id in other_currencies[currency_id]['move_line_ids']: - line_dict[move_line_id] = other_currencies[currency_id][ - 'lines_in_currency'][move_line_id] - - for line in line_dict: - move_line = move_line_obj.browse( - self.cr, self.uid, line_dict[line]['move_line_id'], - context=self.localcontext) - line_dict[line]['ref'] = move_line.ref - - currency = currency_obj.browse( - self.cr, self.uid, line_dict[line]['currency_id'], - context=self.localcontext) - line_dict[line]['currency_name'] = currency.name - - # Adjust the amount signs depending on the report type - if self.ttype == 'receipt': - for line in line_dict: - if line_dict[line]['type'] == 'dr': - line_dict[line]['amount_original'] *= -1 - line_dict[line]['amount_unreconciled'] *= -1 - - elif self.ttype == 'payment': - for line in line_dict: - if line_dict[line]['type'] == 'cr': - line_dict[line]['amount_original'] *= -1 - line_dict[line]['amount_unreconciled'] *= -1 - - # Order the invoices by date and check for lines with no amount - invoice_list = [ - inv for inv in - sorted(line_dict.values(), key=lambda x: x['date_original']) - if inv['amount_original'] or inv['amount_unreconciled'] + pool = pooler.get_pool(self.cr.dbname) + cr, uid, context = self.cr, self.uid, self.localcontext + + inv_obj = pool['account.invoice'] + + invoice_ids = inv_obj.search(cr, uid, [ + ('state', '=', 'open'), + ('company_id', '=', company.id), + ('partner_id', '=', partner.id), + ('type', '=', 'out_invoice' + if self.ttype == 'receipt' else 'in_invoice'), + ], context=context) + + invoices = inv_obj.browse(cr, uid, invoice_ids, context=context) + + return [ + { + 'date_due': inv.date_due or '', + 'date_original': inv.date_invoice or '', + 'amount_original': inv.amount_total, + 'amount_unreconciled': inv.residual, + 'currency_id': inv.currency_id.id, + 'currency_name': inv.currency_id.name, + 'name': inv.number, + 'ref': inv.reference or '', + 'id': inv.id, + } for inv in invoices ] - # Order from the most recent to the older invoice. - invoice_list.reverse() - - self.partner_invoices_dict[partner.id] = invoice_list - - return self.partner_invoices_dict[partner.id] - def _lines_get_30(self, partner, company): today = self.today stop = today - relativedelta(days=30) @@ -289,7 +201,7 @@ class PartnerAgedTrialReport(aged_trial_report): ] return movelines - def _lines_get60(self, partner, company): + def _lines_get_60(self, partner, company): today = self.today start = today - relativedelta(days=60) diff --git a/account_partner_aged_statement_webkit/tests/__init__.py b/account_partner_aged_statement_webkit/tests/__init__.py new file mode 100644 index 00000000..4e709b0a --- /dev/null +++ b/account_partner_aged_statement_webkit/tests/__init__.py @@ -0,0 +1,28 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# 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 . +# +############################################################################## + +from . import ( + test_aged_statement, +) + +checks = [ + test_aged_statement, +] diff --git a/account_partner_aged_statement_webkit/tests/test_aged_statement.py b/account_partner_aged_statement_webkit/tests/test_aged_statement.py new file mode 100644 index 00000000..b9bd4cf6 --- /dev/null +++ b/account_partner_aged_statement_webkit/tests/test_aged_statement.py @@ -0,0 +1,200 @@ +# -*- coding:utf-8 -*- +############################################################################## +# +# Copyright (C) 2015 Savoir-faire Linux. All Rights Reserved. +# +# 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 . +# +############################################################################## + + +from openerp import netsvc +from datetime import datetime +from openerp.tests import common +from ..report.partner_aged_statement_report import PartnerAgedTrialReport +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT + +from dateutil.relativedelta import relativedelta + + +class test_aged_statement(common.TransactionCase): + + def create_fiscal_year(self, year): + cr, uid, context = self.cr, self.uid, self.context + + fy_id = self.fiscal_year_model.create(cr, uid, { + 'name': 'Test %s' % year, + 'code': 'FY%s' % year, + 'company_id': self.company_id, + 'date_start': datetime(year, 1, 1), + 'date_stop': datetime(year, 12, 31), + }, context=context) + + fy = self.fiscal_year_model.browse(cr, uid, fy_id, context=context) + fy.create_period() + + def setUp(self): + super(test_aged_statement, self).setUp() + self.user_model = self.registry("res.users") + self.partner_model = self.registry("res.partner") + self.invoice_model = self.registry("account.invoice") + self.account_model = self.registry("account.account") + self.journal_model = self.registry("account.journal") + self.company_model = self.registry("res.company") + self.fiscal_year_model = self.registry("account.fiscalyear") + + self.context = self.user_model.context_get(self.cr, self.uid) + + cr, uid, context = self.cr, self.uid, self.context + + self.company_id = self.user_model.browse( + cr, uid, uid, context=context).company_id.id + + self.partner_id = self.partner_model.create( + cr, uid, {'name': 'Test', 'customer': True}, context=context) + + self.account_id = self.account_model.search( + cr, uid, [ + ('type', '=', 'receivable'), + ('currency_id', '=', False), + ], context=context)[0] + + self.account_2_id = self.account_model.search( + cr, uid, [ + ('type', '=', 'other'), + ('currency_id', '=', False), + ], context=context)[0] + + self.journal_id = self.journal_model.search( + cr, uid, [('type', '=', 'sale')], context=context)[0] + + self.today = datetime.now() + + self.create_fiscal_year(self.today.year - 1) + + self.date1 = self.today - relativedelta(weeks=2) + self.date2 = self.today - relativedelta(months=1, weeks=1) + self.date3 = self.today - relativedelta(months=2, weeks=1) + self.date4 = self.today - relativedelta(months=3, weeks=1) + self.date5 = self.today - relativedelta(months=4, weeks=1) + + self.invoice_ids = [ + self.invoice_model.create( + cr, uid, { + 'journal_id': self.journal_id, + 'account_id': self.account_id, + 'partner_id': self.partner_id, + 'date_invoice': invoice[0], + 'invoice_line': [(0, 0, { + 'name': 'Test', + 'account_id': self.account_2_id, + 'price_unit': invoice[1], + 'quantity': 1, + })], + }, context=context) + for invoice in [ + (self.today, 300), + (self.date1, 100), + (self.date2, 150), + (self.date3, 200), + (self.date4, 250), + (self.date5, 500), + ] + ] + + wf_service = netsvc.LocalService("workflow") + for inv_id in self.invoice_ids: + wf_service.trg_validate( + uid, 'account.invoice', inv_id, 'invoice_open', cr) + + self.report = PartnerAgedTrialReport( + cr, uid, 'webkit.partner_aged_statement_report', + context=context) + + self.partner = self.partner_model.browse( + cr, uid, self.partner_id, context=context) + + self.company = self.company_model.browse( + cr, uid, self.company_id, context=context) + + def test_get_balance(self): + balance = self.report._get_balance(self.partner, self.company) + + self.assertEqual(len(balance), 1) + self.assertEqual(balance[0]['30'], 400) + self.assertEqual(balance[0]['3060'], 150) + self.assertEqual(balance[0]['6090'], 200) + self.assertEqual(balance[0]['90120'], 250) + self.assertEqual(balance[0]['120'], 500) + self.assertEqual(balance[0]['total'], 400 + 150 + 200 + 250 + 500) + + def compare_vals(self, line, vals): + self.assertEqual( + line['date_original'], vals['date_original'].strftime( + DEFAULT_SERVER_DATE_FORMAT)) + self.assertEqual(line['amount_original'], vals['amount_original']) + self.assertEqual( + line['amount_unreconciled'], vals['amount_unreconciled']) + + def test_line_get_30(self): + lines = sorted( + self.report._lines_get_30(self.partner, self.company), + key=lambda l: l['date_original']) + + self.compare_vals(lines[0], { + 'date_original': self.date1, + 'amount_original': 100, + 'amount_unreconciled': 100, + }) + + self.compare_vals(lines[1], { + 'date_original': self.today, + 'amount_original': 300, + 'amount_unreconciled': 300, + }) + + def test_line_get_30_60(self): + lines = sorted( + self.report._lines_get_30_60(self.partner, self.company), + key=lambda l: l['date_original']) + + self.compare_vals(lines[0], { + 'date_original': self.date2, + 'amount_original': 150, + 'amount_unreconciled': 150, + }) + + def test_line_get_60(self): + lines = sorted( + self.report._lines_get_60(self.partner, self.company), + key=lambda l: l['date_original']) + + self.compare_vals(lines[0], { + 'date_original': self.date5, + 'amount_original': 500, + 'amount_unreconciled': 500, + }) + + self.compare_vals(lines[1], { + 'date_original': self.date4, + 'amount_original': 250, + 'amount_unreconciled': 250, + }) + + self.compare_vals(lines[2], { + 'date_original': self.date3, + 'amount_original': 200, + 'amount_unreconciled': 200, + })