[MODULE] +v1.1.0 from https://www.odoo.com/apps/7.0/account_financial_report_webkit/
[burette/account_financial_report_webkit.git] / report / general_ledger.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 # Author: Nicolas Bessi, Guewen Baconnier
5 # Copyright Camptocamp SA 2011
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as
9 # published by the Free Software Foundation, either version 3 of the
10 # License, or (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU Affero General Public License for more details.
16 #
17 # You should have received a copy of the GNU Affero General Public License
18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 from operator import itemgetter
23 from itertools import groupby
24 from datetime import datetime
25
26 from openerp.report import report_sxw
27 from openerp import pooler
28 from openerp.tools.translate import _
29 from .common_reports import CommonReportHeaderWebkit
30 from .webkit_parser_header_fix import HeaderFooterTextWebKitParser
31
32
33 class GeneralLedgerWebkit(report_sxw.rml_parse, CommonReportHeaderWebkit):
34
35 def __init__(self, cursor, uid, name, context):
36 super(GeneralLedgerWebkit, self).__init__(cursor, uid, name, context=context)
37 self.pool = pooler.get_pool(self.cr.dbname)
38 self.cursor = self.cr
39
40 company = self.pool.get('res.users').browse(self.cr, uid, uid, context=context).company_id
41 header_report_name = ' - '.join((_('GENERAL LEDGER'), company.name, company.currency_id.name))
42
43 footer_date_time = self.formatLang(str(datetime.today()), date_time=True)
44
45 self.localcontext.update({
46 'cr': cursor,
47 'uid': uid,
48 'report_name': _('General Ledger'),
49 'display_account': self._get_display_account,
50 'display_account_raw': self._get_display_account_raw,
51 'filter_form': self._get_filter,
52 'target_move': self._get_target_move,
53 'initial_balance': self._get_initial_balance,
54 'amount_currency': self._get_amount_currency,
55 'display_target_move': self._get_display_target_move,
56 'accounts': self._get_accounts_br,
57 'additional_args': [
58 ('--header-font-name', 'Helvetica'),
59 ('--footer-font-name', 'Helvetica'),
60 ('--header-font-size', '10'),
61 ('--footer-font-size', '6'),
62 ('--header-left', header_report_name),
63 ('--header-spacing', '2'),
64 ('--footer-left', footer_date_time),
65 ('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))),
66 ('--footer-line',),
67 ],
68 })
69
70 def set_context(self, objects, data, ids, report_type=None):
71 """Populate a ledger_lines attribute on each browse record that will be used
72 by mako template"""
73 new_ids = data['form']['account_ids'] or data['form']['chart_account_id']
74
75 # Account initial balance memoizer
76 init_balance_memoizer = {}
77
78 # Reading form
79 main_filter = self._get_form_param('filter', data, default='filter_no')
80 target_move = self._get_form_param('target_move', data, default='all')
81 start_date = self._get_form_param('date_from', data)
82 stop_date = self._get_form_param('date_to', data)
83 do_centralize = self._get_form_param('centralize', data)
84 start_period = self.get_start_period_br(data)
85 stop_period = self.get_end_period_br(data)
86 fiscalyear = self.get_fiscalyear_br(data)
87 chart_account = self._get_chart_account_id_br(data)
88
89 if main_filter == 'filter_no':
90 start_period = self.get_first_fiscalyear_period(fiscalyear)
91 stop_period = self.get_last_fiscalyear_period(fiscalyear)
92
93 # computation of ledger lines
94 if main_filter == 'filter_date':
95 start = start_date
96 stop = stop_date
97 else:
98 start = start_period
99 stop = stop_period
100
101 initial_balance = self.is_initial_balance_enabled(main_filter)
102 initial_balance_mode = initial_balance and self._get_initial_balance_mode(start) or False
103
104 # Retrieving accounts
105 accounts = self.get_all_accounts(new_ids, exclude_type=['view'])
106 if initial_balance_mode == 'initial_balance':
107 init_balance_memoizer = self._compute_initial_balances(accounts, start, fiscalyear)
108 elif initial_balance_mode == 'opening_balance':
109 init_balance_memoizer = self._read_opening_balance(accounts, start)
110
111 ledger_lines_memoizer = self._compute_account_ledger_lines(accounts, init_balance_memoizer,
112 main_filter, target_move, start, stop)
113 objects = []
114 for account in self.pool.get('account.account').browse(self.cursor, self.uid, accounts):
115 if do_centralize and account.centralized and ledger_lines_memoizer.get(account.id):
116 account.ledger_lines = self._centralize_lines(main_filter, ledger_lines_memoizer.get(account.id, []))
117 else:
118 account.ledger_lines = ledger_lines_memoizer.get(account.id, [])
119 account.init_balance = init_balance_memoizer.get(account.id, {})
120
121 objects.append(account)
122
123 self.localcontext.update({
124 'fiscalyear': fiscalyear,
125 'start_date': start_date,
126 'stop_date': stop_date,
127 'start_period': start_period,
128 'stop_period': stop_period,
129 'chart_account': chart_account,
130 'initial_balance_mode': initial_balance_mode,
131 })
132
133 return super(GeneralLedgerWebkit, self).set_context(objects, data, new_ids,
134 report_type=report_type)
135
136 def _centralize_lines(self, filter, ledger_lines, context=None):
137 """ Group by period in filter mode 'period' or on one line in filter mode 'date'
138 ledger_lines parameter is a list of dict built by _get_ledger_lines"""
139 def group_lines(lines):
140 if not lines:
141 return {}
142 sums = reduce(lambda line, memo: dict((key, value + memo[key]) for key, value
143 in line.iteritems() if key in ('balance', 'debit', 'credit')), lines)
144
145 res_lines = {
146 'balance': sums['balance'],
147 'debit': sums['debit'],
148 'credit': sums['credit'],
149 'lname': _('Centralized Entries'),
150 'account_id': lines[0]['account_id'],
151 }
152 return res_lines
153
154 centralized_lines = []
155 if filter == 'filter_date':
156 # by date we centralize all entries in only one line
157 centralized_lines.append(group_lines(ledger_lines))
158
159 else: # by period
160 # by period we centralize all entries in one line per period
161 period_obj = self.pool.get('account.period')
162 # we need to sort the lines per period in order to use groupby
163 # unique ids of each used period id in lines
164 period_ids = list(set([line['lperiod_id'] for line in ledger_lines]))
165 # search on account.period in order to sort them by date_start
166 sorted_period_ids = period_obj.search(self.cr, self.uid,
167 [('id', 'in', period_ids)],
168 order='special desc, date_start',
169 context=context)
170 sorted_ledger_lines = sorted(ledger_lines, key=lambda x: sorted_period_ids.index(x['lperiod_id']))
171
172 for period_id, lines_per_period_iterator in groupby(sorted_ledger_lines, itemgetter('lperiod_id')):
173 lines_per_period = list(lines_per_period_iterator)
174 if not lines_per_period:
175 continue
176 group_per_period = group_lines(lines_per_period)
177 group_per_period.update({
178 'lperiod_id': period_id,
179 'period_code': lines_per_period[0]['period_code'], # period code is anyway the same on each line per period
180 })
181 centralized_lines.append(group_per_period)
182
183 return centralized_lines
184
185 def _compute_account_ledger_lines(self, accounts_ids, init_balance_memoizer, main_filter,
186 target_move, start, stop):
187 res = {}
188 for acc_id in accounts_ids:
189 move_line_ids = self.get_move_lines_ids(acc_id, main_filter, start, stop, target_move)
190 if not move_line_ids:
191 res[acc_id] = []
192 continue
193
194 lines = self._get_ledger_lines(move_line_ids, acc_id)
195 res[acc_id] = lines
196 return res
197
198 def _get_ledger_lines(self, move_line_ids, account_id):
199 if not move_line_ids:
200 return []
201 res = self._get_move_line_datas(move_line_ids)
202 ## computing counter part is really heavy in term of ressouces consuption
203 ## looking for a king of SQL to help me improve it
204 move_ids = [x.get('move_id') for x in res]
205 counter_parts = self._get_moves_counterparts(move_ids, account_id)
206 for line in res:
207 line['counterparts'] = counter_parts.get(line.get('move_id'), '')
208 return res
209
210
211 HeaderFooterTextWebKitParser('report.account.account_report_general_ledger_webkit',
212 'account.account',
213 'addons/account_financial_report_webkit/report/templates/account_report_general_ledger.mako',
214 parser=GeneralLedgerWebkit)