You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
322 lines
11 KiB
322 lines
11 KiB
# -*- coding: utf-8 -*-
|
|
###############################################################################
|
|
#
|
|
# OpenERP, Open Source Management Solution
|
|
# This module copyright (C) 2010 - 2014 Savoir-faire Linux
|
|
# (<http://www.savoirfairelinux.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/>.
|
|
#
|
|
###############################################################################
|
|
|
|
import time
|
|
import pytz
|
|
from datetime import datetime
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
import itertools
|
|
|
|
from openerp import pooler
|
|
from openerp.addons.report_webkit.webkit_report import WebKitParser
|
|
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
|
|
|
|
from openerp.addons.account.report.account_aged_partner_balance import (
|
|
aged_trial_report
|
|
)
|
|
|
|
|
|
class PartnerAgedTrialReport(aged_trial_report):
|
|
_partners = None
|
|
|
|
def __init__(self, cr, uid, name, context):
|
|
super(PartnerAgedTrialReport, self).__init__(cr, uid, name, context)
|
|
current_user = self.localcontext["user"]
|
|
self._company = current_user.company_id
|
|
if self.localcontext.get("active_model", "") == "res.partner":
|
|
self._partners = self.localcontext["active_ids"]
|
|
self.ttype = 'receipt'
|
|
self.localcontext.update({
|
|
'message': self._message,
|
|
'getLinesCurrent': self._lines_get_current,
|
|
'getLines3160': self._lines_get_31_60,
|
|
'getLines61': self._lines_get_61,
|
|
'getLinesRefunds': self._lines_get_refunds,
|
|
'show_message': True,
|
|
'get_current_invoice_lines': self._get_current_invoice_lines,
|
|
'get_balance': self._get_balance,
|
|
'get_refunds_total': self._refunds_total,
|
|
'ttype': self.ttype,
|
|
})
|
|
self.partner_invoices_dict = {}
|
|
tz = self.localcontext.get('tz', False)
|
|
tz = tz and pytz.timezone(tz) or pytz.utc
|
|
self.today = datetime.now(tz)
|
|
|
|
def _get_balance(self, partner, company):
|
|
"""
|
|
Get the lines of balance to display in the report
|
|
"""
|
|
today = self.today
|
|
date_30 = today - relativedelta(days=30)
|
|
date_60 = today - relativedelta(days=60)
|
|
date_90 = today - relativedelta(days=90)
|
|
date_120 = today - relativedelta(days=120)
|
|
|
|
today = today.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
date_30 = date_30.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
date_60 = date_60.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
date_90 = date_90.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
date_120 = date_120.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
|
|
movelines = [
|
|
line for line in
|
|
self._get_current_invoice_lines(partner, company, today)
|
|
if line['type'] in ['in_invoice', 'out_invoice']
|
|
]
|
|
movelines = sorted(movelines, key=lambda x: x['currency_name'])
|
|
|
|
grouped_movelines = [
|
|
(key, list(group)) for key, group in itertools.groupby(
|
|
movelines, key=lambda x: x['currency_name'])
|
|
]
|
|
|
|
res = {}
|
|
for currency_name, lines in grouped_movelines:
|
|
res[currency_name] = {
|
|
'current': 0,
|
|
'30': 0,
|
|
'3160': 0,
|
|
'6190': 0,
|
|
'91120': 0,
|
|
'121': 0,
|
|
'total': 0,
|
|
'currency_name': currency_name,
|
|
}
|
|
current_dict = res[currency_name]
|
|
|
|
for line in lines:
|
|
amount = line['amount_unreconciled']
|
|
|
|
if (
|
|
not line['date_original'] or
|
|
line['date_original'] >= date_30
|
|
):
|
|
current_dict['current'] += amount
|
|
|
|
elif line['date_original'] >= date_60:
|
|
current_dict['3160'] += amount
|
|
|
|
elif line['date_original'] >= date_90:
|
|
current_dict['6190'] += amount
|
|
|
|
elif line['date_original'] >= date_120:
|
|
current_dict['91120'] += amount
|
|
|
|
else:
|
|
current_dict['121'] += amount
|
|
|
|
current_dict['total'] += amount
|
|
|
|
return res.values()
|
|
|
|
def _get_current_invoice_lines(self, partner, company, date):
|
|
"""
|
|
Get all invoices with unpaid amounts for the given supplier
|
|
: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 invoice
|
|
'currency_name': the name of the currency
|
|
'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]
|
|
|
|
pool = pooler.get_pool(self.cr.dbname)
|
|
cr, uid, context = self.cr, self.uid, self.localcontext
|
|
|
|
inv_obj = pool['account.invoice']
|
|
|
|
invoice_types = (
|
|
['out_invoice', 'out_refund'] if self.ttype == 'receipt'
|
|
else ['in_invoice', 'in_refund'])
|
|
|
|
invoice_ids = inv_obj.search(cr, uid, [
|
|
('state', '=', 'open'),
|
|
('company_id', '=', company.id),
|
|
('partner_id', '=', partner.id),
|
|
('type', 'in', invoice_types),
|
|
], context=context)
|
|
|
|
invoices = inv_obj.browse(cr, uid, invoice_ids, context=context)
|
|
|
|
res = sorted([
|
|
{
|
|
'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,
|
|
'type': inv.type,
|
|
} for inv in invoices
|
|
], key=lambda inv: inv['date_original'])
|
|
|
|
res.reverse()
|
|
|
|
return res
|
|
|
|
def _lines_get_current(self, partner, company):
|
|
today = self.today
|
|
stop = today - relativedelta(days=30)
|
|
stop = stop.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
|
|
movelines = self._get_current_invoice_lines(partner, company, today)
|
|
movelines = [
|
|
line for line in movelines
|
|
if ((
|
|
not line['date_original'] or
|
|
line['date_original'] >= stop
|
|
) and line['type'] in ['in_invoice', 'out_invoice'])
|
|
]
|
|
return movelines
|
|
|
|
def _lines_get_31_60(self, partner, company):
|
|
today = self.today
|
|
start = today - relativedelta(days=31)
|
|
stop = today - relativedelta(days=60)
|
|
|
|
today = today.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
start = start.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
stop = stop.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
|
|
movelines = self._get_current_invoice_lines(partner, company, today)
|
|
movelines = [
|
|
line for line in movelines
|
|
if ((
|
|
line['date_original'] and
|
|
stop <= line['date_original'] <= start
|
|
) and line['type'] in ['in_invoice', 'out_invoice'])
|
|
]
|
|
return movelines
|
|
|
|
def _lines_get_61(self, partner, company):
|
|
today = self.today
|
|
start = today - relativedelta(days=61)
|
|
|
|
today = today.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
start = start.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
|
|
|
movelines = self._get_current_invoice_lines(partner, company, today)
|
|
movelines = [
|
|
line for line in movelines
|
|
if ((
|
|
line['date_original'] and
|
|
line['date_original'] <= start
|
|
) and line['type'] in ['in_invoice', 'out_invoice'])
|
|
]
|
|
return movelines
|
|
|
|
def _refunds_total(self, partner, company):
|
|
today = self.today
|
|
movelines = self._get_current_invoice_lines(partner, company, today)
|
|
return sum(
|
|
line['amount_unreconciled'] for line in movelines
|
|
if line['type'] in ['in_refund', 'out_refund']
|
|
)
|
|
|
|
def _lines_get_refunds(self, partner, company):
|
|
today = self.today
|
|
movelines = self._get_current_invoice_lines(partner, company, today)
|
|
movelines = [
|
|
line for line in movelines
|
|
if line['type'] in ['in_refund', 'out_refund']
|
|
]
|
|
return movelines
|
|
|
|
def _message(self, obj, company):
|
|
company_pool = pooler.get_pool(self.cr.dbname)['res.company']
|
|
message = company_pool.browse(
|
|
self.cr, self.uid, company.id, {'lang': obj.lang}).overdue_msg
|
|
return message and message.split('\n') or ''
|
|
|
|
def _get_company(self, data):
|
|
return self._company.name
|
|
|
|
def _get_currency(self, data):
|
|
return self._company.currency_id.symbol
|
|
|
|
def set_context(self, objects, data, ids, report_type=None):
|
|
period_length = 30
|
|
form = {
|
|
"direction_selection": "past",
|
|
"period_length": period_length,
|
|
"result_selection": "customer",
|
|
"date_from": time.strftime("%Y-%m-%d"),
|
|
}
|
|
# Taken from 'account/wizard/account_report_aged_partner_balance.py
|
|
# which sets data from the form
|
|
start = datetime.now()
|
|
for i in range(4, -1, -1):
|
|
stop = start - relativedelta(days=period_length)
|
|
form[str(i)] = {
|
|
'name': (i != 0 and "{0}-{1}".format(
|
|
5 - (i + 1), (5 - i) * period_length,
|
|
) or '+{0}'.format(4 * period_length)),
|
|
'stop': start.strftime('%Y-%m-%d'),
|
|
'start': (i != 0 and stop.strftime('%Y-%m-%d') or False),
|
|
}
|
|
start = stop - relativedelta(days=1)
|
|
|
|
data["form"] = form
|
|
res = super(PartnerAgedTrialReport, self).set_context(
|
|
objects, data, ids, report_type=report_type)
|
|
self.orig_query = self.query
|
|
if self._partners is not None:
|
|
self.query = "{0} AND l.partner_id = {1}".format(
|
|
self.query,
|
|
", ".join(str(int(i)) for i in self._partners),
|
|
)
|
|
|
|
self.ACCOUNT_TYPE = ['receivable']
|
|
return res
|
|
|
|
def _get_lines(self, form, partner):
|
|
# self.query is used to get the lines in super()._get_lines
|
|
self.query = "{0} AND l.partner_id = {1}".format(
|
|
self.orig_query,
|
|
partner.id,)
|
|
res = super(PartnerAgedTrialReport, self)._get_lines(form)
|
|
self.query = self.orig_query
|
|
return res
|
|
|
|
|
|
WebKitParser(
|
|
'report.webkit.partner_aged_statement_report',
|
|
'res.partner',
|
|
('addons/'
|
|
'account_partner_aged_statement_webkit/'
|
|
'report/'
|
|
'partner_aged_statement.mako'),
|
|
parser=PartnerAgedTrialReport,
|
|
)
|