Merge lp:~camptocamp/account-financial-report/add_aged_partner_ledger-nbi into lp:~account-report-core-editor/account-financial-report/7.0
- add_aged_partner_ledger-nbi
- Merge into 7.0
Status: | Merged |
---|---|
Approved by: | Yannick Vaucher @ Camptocamp |
Approved revision: | 102 |
Merged at revision: | 86 |
Proposed branch: | lp:~camptocamp/account-financial-report/add_aged_partner_ledger-nbi |
Merge into: | lp:~account-report-core-editor/account-financial-report/7.0 |
Diff against target: |
1070 lines (+829/-20) 14 files modified
account_financial_report_webkit/__openerp__.py (+46/-3) account_financial_report_webkit/report/__init__.py (+1/-0) account_financial_report_webkit/report/aged_partner_balance.py (+403/-0) account_financial_report_webkit/report/common_reports.py (+12/-2) account_financial_report_webkit/report/open_invoices.py (+0/-1) account_financial_report_webkit/report/report.xml (+34/-11) account_financial_report_webkit/report/templates/aged_trial_webkit.mako (+155/-0) account_financial_report_webkit/report/templates/open_invoices_inclusion.mako.html (+2/-2) account_financial_report_webkit/report/webkit_parser_header_fix.py (+0/-1) account_financial_report_webkit/report_menus.xml (+4/-0) account_financial_report_webkit/tests/aged_trial_balance.yml (+60/-0) account_financial_report_webkit/wizard/__init__.py (+1/-0) account_financial_report_webkit/wizard/aged_partner_balance_wizard.py (+39/-0) account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml (+72/-0) |
To merge this branch: | bzr merge lp:~camptocamp/account-financial-report/add_aged_partner_ledger-nbi |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Stéphane Bidoul (Acsone) (community) | test | Approve | |
Frederic Clementi - Camptocamp | functional | Approve | |
Alexandre Fayolle - camptocamp | lgtm | Approve | |
Luc De Meyer (Noviat) | Pending | ||
Review via email: mp+211040@code.launchpad.net |
Commit message
[ADD] Aged Partner Balance webkit report. Report inherit Open Invoice Report and uses previously computed ledger lines to determin aged lines
Description of the change
[ADD] Aged Partner Balance webkit report. Report inherit Open Invoice Report and uses previously computed ledger lines to determin aged linesAdd aged partner balance webkit report.
- 97. By Nicolas Bessi - Camptocamp
-
[FIX] docstring syntax
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
- 98. By Nicolas Bessi - Camptocamp
-
[IMP] module revision number
- 99. By Nicolas Bessi - Camptocamp
-
[MRG] from head
- 100. By Nicolas Bessi - Camptocamp
-
[FIX] coding style
- 101. By Nicolas Bessi - Camptocamp
-
[FIX] use from __future__ import division instead of float casting
- 102. By Nicolas Bessi - Camptocamp
-
[FIX] add YML test on aged partner balance
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote : | # |
Hello,
Fixes done and basic tests added
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
the tests are red here
TEST test_70 openerp.
ERROR test_70 openerp.
2014-03-18 16:14:12,556 23281 ERROR test_70 openerp.
Traceback (most recent call last):
File "/home/
_load_data(cr, module_name, idref, mode, 'test')
File "/home/
tools.
File "/home/
yaml_
File "/home/
self.
File "/home/
self.
File "/home/
unsafe_
File "/home/
ctx={}
File "/home/
result = _exec_action(
File "/home/
res = try_report(cr, uid, 'report.
File "/home/
res = netsvc.
File "/home/
result = self.create_
File "/home/
return self.create_
File "/home/
self.
File "/home/
start_period = self.get_
File "/home/
return self._get_
Stéphane Bidoul (Acsone) (sbi) wrote : | # |
Alexandre, I think the fix for this one is in addons demo data (lp:1281579). Merged on OCB already.
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote : | # |
Hello,
Stéphan is right,
Test runs perfectly on OCB, that is the branches I used to developp communitiy addons.
Regards
Nicolas
2014-03-18 15:53:58,357 27853 INFO test_aged_partner openerp.
2014-03-18 15:53:58,364 27853 TEST test_aged_partner openerp.
lt setting
2014-03-18 15:53:58,815 27853 TEST test_aged_partner openerp.
rs and currency
2014-03-18 15:53:59,269 27853 TEST test_aged_partner openerp.
rs on partners
2014-03-18 15:53:59,706 27853 TEST test_aged_partner openerp.
rs on periods
2014-03-18 15:54:00,145 27853 TEST test_aged_partner openerp.
rs on dates
2014-03-18 15:54:00,597 27853 INFO test_aged_partner openerp.
en_US
2014-03-18 15:54:00,597 27853 INFO test_aged_partner openerp.
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
ok my bad. I generally run the OCA tests on the official branch...
Still with the OCB branch, the test requires some specific setup:
here: http://
Traceback (most recent call last):
File "/home/
self.
File "/home/
self.
File "/home/
unsafe_
File "/home/
ctx={}
File "/home/
result = _exec_action(
File "/home/
res = try_report(cr, uid, 'report.
File "/home/
res = netsvc.
File "/home/
result = self.create_
File "/home/
return self.create_
File "/home/
bin = self.get_
File "/home/
_('Please install executable on your system' \
except_osv: (u'Wkhtmltopdf library path is not set', u'Please install executable on your system (sudo apt-get install wkhtmltopdf) or download it from here: http://
2014-03-19 07:51:04,798 10999 ERROR test_ocb70 openerp.
Traceback (most recent call last):
File "/home/
_load_data(cr, module_name, idref, mode, 'test')
File "/home/
tools.
File "/home/
Frederic Clementi - Camptocamp (frederic-clementi) wrote : | # |
I do not get what is the issue excactly however this report MUST work with the addons branch as well...
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote : | # |
Alexandre,
As for all webkit report if you do not set explicitly path to wkhtml2pdf in an ir.config.parameter you have to have a wkhtml2pdf command in your executable path.
Nicolas
Nicolas Bessi - Camptocamp (nbessi-c2c-deactivatedaccount) wrote : | # |
Frederic
The reports are functional on addons branch, only the tests failed because on official addons in demo data all periods are special.
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
ok setup problem on my test instance.
Frederic Clementi - Camptocamp (frederic-clementi) wrote : | # |
All my uses cases works perfectely.
Ok for me
Stéphane Bidoul (Acsone) (sbi) wrote : | # |
Hi Nicolas,
I did a quick test and found significant differences from the standard report which I need to investigate, so if you don't mind I'll put it Need Information so it does not get merged accidentally.
It is probably an issue in my test data, I'll get back to you as soon as possible.
Another question, is there a particular reason you did not implement the "period length" and leave it to 30 days?
Christelle De Coninck (Acsone) (cde) wrote : | # |
Hi Nicolas,
I'm working as a business analyst for Acsone and Stéphane Bidoul asked me to make a functional test regarding the new "Aged Partner Balance" report .
I noticed that the amounts are classified in the different columns (<30, <60, etc.) based on the clearance Date. By default, this clearance date is the end of the fiscal year (31/12/2014 in this case).
I tried to change this date but it is forbidden and I obtained the following error message:
ValidateError
Error occurred while validating the field(s) until_date: Clearance date must be the very last date of the last period or later.
In my opinion, it is interesting to let the user choose the clearance date he wants for his report. Furthermore, I think that current date is again more interesting as it permits to have a good representation of the actual situation.
An improvement to this report could thus be that the current date is used as default date and the user have the possibility to change it.
What do you think?
Thanks in advance for your answer
Frederic Clementi - Camptocamp (frederic-clementi) wrote : | # |
Hi Christelle,
Very happy that you can test this new report.
FYI, I wrote a google doc here : http://
Do not hesitate to ask information if needed.
Frederic Clementi
Frederic Clementi - Camptocamp (frederic-clementi) wrote : | # |
Just did a new tests (with clearance date) on production environement -> works fine. Result match with all other reports.
Christelle De Coninck (Acsone) (cde) wrote : | # |
Hi Frederic,
Thanks a lot for your answer and for the google doc. It's more clear now.
So I redid my tests and for me, this report works fine.
Best regards,
Christelle
Stéphane Bidoul (Acsone) (sbi) wrote : | # |
Report works fine provided the clearance date is set correctly.
My only remark is a usability issue as the most common use case (aged balance as of current date) requires fiddling with the date filters. As another MP resolving the usability issue is on its way, I approve this one.
Thanks!
Preview Diff
1 | === modified file 'account_financial_report_webkit/__openerp__.py' |
2 | --- account_financial_report_webkit/__openerp__.py 2014-03-13 10:49:47 +0000 |
3 | +++ account_financial_report_webkit/__openerp__.py 2014-03-18 15:55:27 +0000 |
4 | @@ -30,7 +30,7 @@ |
5 | - Partner ledger |
6 | - Partner balance |
7 | - Open invoices report |
8 | - |
9 | + - Aged Partner Balance |
10 | |
11 | Main improvements per report: |
12 | ----------------------------- |
13 | @@ -100,6 +100,47 @@ |
14 | * Subtotal by account and partner |
15 | * Alphabetical sorting (same as in partner balance) |
16 | |
17 | + |
18 | +Aged Partner Balance: Summary of aged open amount per partner |
19 | + |
20 | +This report is an accounting tool helping in various tasks. |
21 | +You can credit control or partner balance provisions computation for instance. |
22 | + |
23 | +The aged balance report allows you to print balances per partner |
24 | +like the trial balance but add an extra information : |
25 | + |
26 | +* It will split balances into due amounts |
27 | + (due date not reached à the end date of the report) and overdue amounts |
28 | + Overdue data are also split by period. |
29 | +* For each partner following columns will be displayed: |
30 | + |
31 | + * Total balance (all figures must match with same date partner balance report). |
32 | + This column equals the sum of all following columns) |
33 | + |
34 | + * Due |
35 | + * Overdue <= 30 days |
36 | + * Overdue <= 60 days |
37 | + * Overdue <= 90 days |
38 | + * Overdue <= 120 days |
39 | + * Older |
40 | + |
41 | +Hypothesis / Contraints of aged partner balance |
42 | + |
43 | +* Overdues columns will be by default be based on 30 days range fix number of days. |
44 | + This can be changed by changes the RANGES constraint |
45 | +* All data will be displayed in company currency |
46 | +* When partial payments, the payment must appear in the same colums than the invoice |
47 | + (Except if multiple payment terms) |
48 | +* Data granularity: partner (will not display figures at invoices level) |
49 | +* The report aggregate data per account with sub-totals |
50 | +* Initial balance must be calculated the same way that |
51 | + the partner balance / Ignoring the opening entry |
52 | + in special period (idem open invoice report) |
53 | +* Only accounts with internal type payable or receivable are considered |
54 | + (idem open invoice report) |
55 | +* If maturity date is null then use move line date |
56 | + |
57 | + |
58 | Limitations: |
59 | ------------ |
60 | |
61 | @@ -126,7 +167,7 @@ |
62 | the header and footer are created as text with arguments passed to |
63 | wkhtmltopdf. The texts are defined inside the report classes. |
64 | """, |
65 | - 'version': '1.0.2', |
66 | + 'version': '1.1.0', |
67 | 'author': 'Camptocamp', |
68 | 'license': 'AGPL-3', |
69 | 'category': 'Finance', |
70 | @@ -147,6 +188,7 @@ |
71 | 'wizard/trial_balance_wizard_view.xml', |
72 | 'wizard/partner_balance_wizard_view.xml', |
73 | 'wizard/open_invoices_wizard_view.xml', |
74 | + 'wizard/aged_partner_balance_wizard.xml', |
75 | 'wizard/print_journal_view.xml', |
76 | 'report_menus.xml', |
77 | ], |
78 | @@ -155,7 +197,8 @@ |
79 | 'tests/partner_ledger.yml', |
80 | 'tests/trial_balance.yml', |
81 | 'tests/partner_balance.yml', |
82 | - 'tests/open_invoices.yml',], |
83 | + 'tests/open_invoices.yml', |
84 | + 'tests/aged_trial_balance.yml'], |
85 | #'tests/account_move_line.yml' |
86 | 'active': False, |
87 | 'installable': True, |
88 | |
89 | === modified file 'account_financial_report_webkit/report/__init__.py' |
90 | --- account_financial_report_webkit/report/__init__.py 2013-09-12 20:53:27 +0000 |
91 | +++ account_financial_report_webkit/report/__init__.py 2014-03-18 15:55:27 +0000 |
92 | @@ -9,3 +9,4 @@ |
93 | from . import partner_balance |
94 | from . import open_invoices |
95 | from . import print_journal |
96 | +from . import aged_partner_balance |
97 | |
98 | === added file 'account_financial_report_webkit/report/aged_partner_balance.py' |
99 | --- account_financial_report_webkit/report/aged_partner_balance.py 1970-01-01 00:00:00 +0000 |
100 | +++ account_financial_report_webkit/report/aged_partner_balance.py 2014-03-18 15:55:27 +0000 |
101 | @@ -0,0 +1,403 @@ |
102 | +# -*- coding: utf-8 -*- |
103 | +############################################################################## |
104 | +# |
105 | +# Author: Nicolas Bessi |
106 | +# Copyright 2014 Camptocamp SA |
107 | +# |
108 | +# This program is free software: you can redistribute it and/or modify |
109 | +# it under the terms of the GNU Affero General Public License as |
110 | +# published by the Free Software Foundation, either version 3 of the |
111 | +# License, or (at your option) any later version. |
112 | +# |
113 | +# This program is distributed in the hope that it will be useful, |
114 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
115 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
116 | +# GNU Affero General Public License for more details. |
117 | +# |
118 | +# You should have received a copy of the GNU Affero General Public License |
119 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
120 | +# |
121 | +############################################################################## |
122 | +from __future__ import division |
123 | +from datetime import datetime |
124 | + |
125 | +from openerp import pooler |
126 | +from openerp.tools import DEFAULT_SERVER_DATE_FORMAT |
127 | +from openerp.tools.translate import _ |
128 | +from .open_invoices import PartnersOpenInvoicesWebkit |
129 | +from .webkit_parser_header_fix import HeaderFooterTextWebKitParser |
130 | + |
131 | + |
132 | +def make_ranges(top, offset): |
133 | + """Return sorted days ranges |
134 | + |
135 | + :param top: maximum overdue day |
136 | + :param offset: offset for ranges |
137 | + |
138 | + :returns: list of sorted ranges tuples in days |
139 | + eg. [(-100000, 0), (0, offset), (offset, n*offset), ... (top, 100000)] |
140 | + """ |
141 | + ranges = [(n, min(n + offset, top)) for n in xrange(0, top, offset)] |
142 | + ranges.insert(0, (-100000000000, 0)) |
143 | + ranges.append((top, 100000000000)) |
144 | + return ranges |
145 | + |
146 | +#list of overdue ranges |
147 | +RANGES = make_ranges(120, 30) |
148 | + |
149 | + |
150 | +def make_ranges_titles(): |
151 | + """Generates title to be used by mako""" |
152 | + titles = [_('Due')] |
153 | + titles += [_(u'Overdue ≤ %s d.') % x[1] for x in RANGES[1:-1]] |
154 | + titles.append(_('Older')) |
155 | + return titles |
156 | + |
157 | +#list of overdue ranges title |
158 | +RANGES_TITLES = make_ranges_titles() |
159 | +#list of payable journal types |
160 | +REC_PAY_TYPE = ('purchase', 'sale') |
161 | +#list of refund payable type |
162 | +REFUND_TYPE = ('purchase_refund', 'sale_refund') |
163 | +INV_TYPE = REC_PAY_TYPE + REFUND_TYPE |
164 | + |
165 | + |
166 | +class AccountAgedTrialBalanceWebkit(PartnersOpenInvoicesWebkit): |
167 | + """Compute Aged Partner Balance based on result of Open Invoices""" |
168 | + |
169 | + def __init__(self, cursor, uid, name, context=None): |
170 | + """Constructor, refer to :class:`openerp.report.report_sxw.rml_parse`""" |
171 | + super(AccountAgedTrialBalanceWebkit, self).__init__(cursor, uid, name, |
172 | + context=context) |
173 | + self.pool = pooler.get_pool(self.cr.dbname) |
174 | + self.cursor = self.cr |
175 | + company = self.pool.get('res.users').browse(self.cr, uid, uid, |
176 | + context=context).company_id |
177 | + |
178 | + header_report_name = ' - '.join((_('Aged Partner Balance'), |
179 | + company.currency_id.name)) |
180 | + |
181 | + footer_date_time = self.formatLang(str(datetime.today()), |
182 | + date_time=True) |
183 | + |
184 | + self.localcontext.update({ |
185 | + 'cr': cursor, |
186 | + 'uid': uid, |
187 | + 'company': company, |
188 | + 'ranges': self._get_ranges(), |
189 | + 'ranges_titles': self._get_ranges_titles(), |
190 | + 'report_name': _('Aged Partner Balance'), |
191 | + 'additional_args': [ |
192 | + ('--header-font-name', 'Helvetica'), |
193 | + ('--footer-font-name', 'Helvetica'), |
194 | + ('--header-font-size', '10'), |
195 | + ('--footer-font-size', '6'), |
196 | + ('--header-left', header_report_name), |
197 | + ('--header-spacing', '2'), |
198 | + ('--footer-left', footer_date_time), |
199 | + ('--footer-right', ' '.join((_('Page'), '[page]', _('of'), '[topage]'))), |
200 | + ('--footer-line',), |
201 | + ], |
202 | + }) |
203 | + |
204 | + def _get_ranges(self): |
205 | + """:returns: :cons:`RANGES`""" |
206 | + return RANGES |
207 | + |
208 | + def _get_ranges_titles(self): |
209 | + """:returns: :cons: `RANGES_TITLES`""" |
210 | + return RANGES_TITLES |
211 | + |
212 | + def set_context(self, objects, data, ids, report_type=None): |
213 | + """Populate aged_lines, aged_balance, aged_percents attributes |
214 | + |
215 | + on each account browse record that will be used by mako template |
216 | + The browse record are store in :attr:`objects` |
217 | + |
218 | + The computation are based on the ledger_lines attribute set on account |
219 | + contained by :attr:`objects` |
220 | + |
221 | + :attr:`objects` values were previously set by parent class |
222 | + :class: `.open_invoices.PartnersOpenInvoicesWebkit` |
223 | + |
224 | + :returns: parent :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
225 | + call to set_context |
226 | + |
227 | + """ |
228 | + res = super(AccountAgedTrialBalanceWebkit, self).set_context( |
229 | + objects, |
230 | + data, |
231 | + ids, |
232 | + report_type=report_type |
233 | + ) |
234 | + |
235 | + for acc in self.objects: |
236 | + acc.aged_lines = {} |
237 | + acc.agged_totals = {} |
238 | + acc.agged_percents = {} |
239 | + for part_id, partner_lines in acc.ledger_lines.items(): |
240 | + aged_lines = self.compute_aged_lines(part_id, |
241 | + partner_lines, |
242 | + data) |
243 | + if aged_lines: |
244 | + acc.aged_lines[part_id] = aged_lines |
245 | + acc.aged_totals = totals = self.compute_totals(acc.aged_lines.values()) |
246 | + acc.aged_percents = self.compute_percents(totals) |
247 | + #Free some memory |
248 | + del(acc.ledger_lines) |
249 | + return res |
250 | + |
251 | + def compute_aged_lines(self, partner_id, ledger_lines, data): |
252 | + """Add property aged_lines to accounts browse records |
253 | + |
254 | + contained in :attr:`objects` for a given partner |
255 | + |
256 | + :param: partner_id: current partner |
257 | + :param ledger_lines: generated by parent |
258 | + :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
259 | + |
260 | + :returns: dict of computed aged lines |
261 | + eg {'balance': 1000.0, |
262 | + 'aged_lines': {(90, 120): 0.0, ...} |
263 | + |
264 | + """ |
265 | + lines_to_age = self.filter_lines(partner_id, ledger_lines) |
266 | + res = {} |
267 | + end_date = self._get_end_date(data) |
268 | + aged_lines = dict.fromkeys(RANGES, 0.0) |
269 | + reconcile_lookup = self.get_reconcile_count_lookup(lines_to_age) |
270 | + res['aged_lines'] = aged_lines |
271 | + for line in lines_to_age: |
272 | + compute_method = self.get_compute_method(reconcile_lookup, |
273 | + partner_id, |
274 | + line) |
275 | + delay = compute_method(line, end_date, ledger_lines) |
276 | + classification = self.classify_line(partner_id, delay) |
277 | + aged_lines[classification] += line['debit'] - line['credit'] |
278 | + self.compute_balance(res, aged_lines) |
279 | + return res |
280 | + |
281 | + def _get_end_date(self, data): |
282 | + """Retrieve end date to be used to compute delay. |
283 | + |
284 | + :param data: data dict send to report contains form dict |
285 | + |
286 | + :returns: end date to be used to compute overdue delay |
287 | + |
288 | + """ |
289 | + end_date = None |
290 | + date_to = data['form']['date_to'] |
291 | + period_to_id = data['form']['period_to'] |
292 | + fiscal_to_id = data['form']['fiscalyear_id'] |
293 | + if date_to: |
294 | + end_date = date_to |
295 | + elif period_to_id: |
296 | + period_to = self.pool['account.period'].browse(self.cr, |
297 | + self.uid, |
298 | + period_to_id) |
299 | + end_date = period_to.date_stop |
300 | + elif fiscal_to_id: |
301 | + fiscal_to = self.pool['account.fiscalyear'].browse(self.cr, |
302 | + self.uid, |
303 | + fiscal_to_id) |
304 | + end_date = fiscal_to.date_stop |
305 | + else: |
306 | + raise ValueError('End date and end period not available') |
307 | + return end_date |
308 | + |
309 | + def _compute_delay_from_key(self, key, line, end_date): |
310 | + """Compute overdue delay delta in days for line using attribute in key |
311 | + |
312 | + delta = end_date - date of key |
313 | + |
314 | + :param line: current ledger line |
315 | + :param key: date key to be used to compute delta |
316 | + :param end_date: end_date computed for wizard data |
317 | + |
318 | + :returns: delta in days |
319 | + """ |
320 | + from_date = datetime.strptime(line[key], DEFAULT_SERVER_DATE_FORMAT) |
321 | + end_date = datetime.strptime(end_date, DEFAULT_SERVER_DATE_FORMAT) |
322 | + delta = end_date - from_date |
323 | + return delta.days |
324 | + |
325 | + def compute_delay_from_maturity(self, line, end_date, ledger_lines): |
326 | + """Compute overdue delay delta in days for line using attribute in key |
327 | + |
328 | + delta = end_date - maturity date |
329 | + |
330 | + :param line: current ledger line |
331 | + :param end_date: end_date computed for wizard data |
332 | + :param ledger_lines: generated by parent |
333 | + :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
334 | + |
335 | + :returns: delta in days |
336 | + """ |
337 | + return self._compute_delay_from_key('date_maturity', |
338 | + line, |
339 | + end_date) |
340 | + |
341 | + def compute_delay_from_date(self, line, end_date, ledger_lines): |
342 | + """Compute overdue delay delta in days for line using attribute in key |
343 | + |
344 | + delta = end_date - date |
345 | + |
346 | + :param line: current ledger line |
347 | + :param end_date: end_date computed for wizard data |
348 | + :param ledger_lines: generated by parent |
349 | + :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
350 | + |
351 | + :returns: delta in days |
352 | + """ |
353 | + return self._compute_delay_from_key('ldate', |
354 | + line, |
355 | + end_date) |
356 | + |
357 | + def compute_delay_from_partial_rec(self, line, end_date, ledger_lines): |
358 | + """Compute overdue delay delta in days for the case where move line |
359 | + |
360 | + is related to a partial reconcile with more than one reconcile line |
361 | + |
362 | + :param line: current ledger line |
363 | + :param end_date: end_date computed for wizard data |
364 | + :param ledger_lines: generated by parent |
365 | + :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
366 | + |
367 | + :returns: delta in days |
368 | + """ |
369 | + sale_lines = [x for x in ledger_lines if x['jtype'] in REC_PAY_TYPE and |
370 | + line['rec_id'] == x['rec_id']] |
371 | + refund_lines = [x for x in ledger_lines if x['jtype'] in REFUND_TYPE and |
372 | + line['rec_id'] == x['rec_id']] |
373 | + if len(sale_lines) == 1: |
374 | + reference_line = sale_lines[0] |
375 | + elif len(refund_lines) == 1: |
376 | + reference_line = refund_lines[0] |
377 | + else: |
378 | + reference_line = line |
379 | + key = 'date_maturity' if reference_line.get('date_maturity') else 'ldate' |
380 | + return self._compute_delay_from_key(key, |
381 | + reference_line, |
382 | + end_date) |
383 | + |
384 | + def get_compute_method(self, reconcile_lookup, partner_id, line): |
385 | + """Get the function that should compute the delay for a given line |
386 | + |
387 | + :param reconcile_lookup: dict of reconcile group by id and count |
388 | + {rec_id: count of line related to reconcile} |
389 | + :param partner_id: current partner_id |
390 | + :param line: current ledger line generated by parent |
391 | + :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
392 | + |
393 | + :returns: function bounded to :class:`.AccountAgedTrialBalanceWebkit` |
394 | + |
395 | + """ |
396 | + if reconcile_lookup.get(line['rec_id'], 0.0) > 1: |
397 | + return self.compute_delay_from_partial_rec |
398 | + elif line['jtype'] in INV_TYPE and line.get('date_maturity'): |
399 | + return self.compute_delay_from_maturity |
400 | + else: |
401 | + return self.compute_delay_from_date |
402 | + |
403 | + def line_is_valid(self, partner_id, line): |
404 | + """Predicate hook that allows to filter line to be treated |
405 | + |
406 | + :param partner_id: current partner_id |
407 | + :param line: current ledger line generated by parent |
408 | + :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
409 | + |
410 | + :returns: boolean True if line is allowed |
411 | + """ |
412 | + return True |
413 | + |
414 | + def filter_lines(self, partner_id, lines): |
415 | + """Filter ledger lines that have to be treated |
416 | + |
417 | + :param partner_id: current partner_id |
418 | + :param lines: ledger_lines related to current partner |
419 | + and generated by parent |
420 | + :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
421 | + |
422 | + :returns: list of allowed lines |
423 | + |
424 | + """ |
425 | + return [x for x in lines if self.line_is_valid(partner_id, x)] |
426 | + |
427 | + def classify_line(self, partner_id, overdue_days): |
428 | + """Return the overdue range for a given delay |
429 | + |
430 | + We loop from smaller range to higher |
431 | + This should be the most effective solution as generaly |
432 | + customer tend to have one or two month of delay |
433 | + |
434 | + :param overdue_days: delay in days |
435 | + :param partner_id: current partner_id |
436 | + |
437 | + :returns: the correct range in :const:`RANGES` |
438 | + |
439 | + """ |
440 | + for drange in RANGES: |
441 | + if overdue_days <= drange[1]: |
442 | + return drange |
443 | + return drange |
444 | + |
445 | + def compute_balance(self, res, aged_lines): |
446 | + """Compute the total balance of aged line |
447 | + for given account""" |
448 | + res['balance'] = sum(aged_lines.values()) |
449 | + |
450 | + def compute_totals(self, aged_lines): |
451 | + """Compute the totals for an account |
452 | + |
453 | + :param aged_lines: dict of aged line taken from the |
454 | + property added to account record |
455 | + |
456 | + :returns: dict of total {'balance':1000.00, (30, 60): 3000,...} |
457 | + |
458 | + """ |
459 | + totals = {} |
460 | + totals['balance'] = sum(x.get('balance', 0.0) for |
461 | + x in aged_lines) |
462 | + aged_ranges = [x.get('aged_lines', {}) for x in aged_lines] |
463 | + for drange in RANGES: |
464 | + totals[drange] = sum(x.get(drange, 0.0) for x in aged_ranges) |
465 | + return totals |
466 | + |
467 | + def compute_percents(self, totals): |
468 | + percents = {} |
469 | + base = totals['balance'] or 1.0 |
470 | + for drange in RANGES: |
471 | + percents[drange] = (totals[drange] / base) * 100.0 |
472 | + return percents |
473 | + |
474 | + def get_reconcile_count_lookup(self, lines): |
475 | + """Compute an lookup dict |
476 | + |
477 | + It contains has partial reconcile id as key and the count of lines |
478 | + related to the reconcile id |
479 | + |
480 | + :param: a list of ledger lines generated by parent |
481 | + :class:`.open_invoices.PartnersOpenInvoicesWebkit` |
482 | + |
483 | + :retuns: lookup dict {ṛec_id: count} |
484 | + |
485 | + """ |
486 | + # possible bang if l_ids is really long. |
487 | + # We have the same weakness in common_report ... |
488 | + # but it seems not really possible for a partner |
489 | + # So I'll keep that option. |
490 | + l_ids = tuple(x['id'] for x in lines) |
491 | + sql = ("SELECT reconcile_partial_id, COUNT(*) FROM account_move_line" |
492 | + " WHERE reconcile_partial_id IS NOT NULL" |
493 | + " AND id in %s" |
494 | + " GROUP BY reconcile_partial_id") |
495 | + self.cr.execute(sql, (l_ids,)) |
496 | + res = self.cr.fetchall() |
497 | + return dict((x[0], x[1]) for x in res) |
498 | + |
499 | +HeaderFooterTextWebKitParser( |
500 | + 'report.account.account_aged_trial_balance_webkit', |
501 | + 'account.account', |
502 | + 'addons/account_financial_report_webkit/report/templates/aged_trial_webkit.mako', |
503 | + parser=AccountAgedTrialBalanceWebkit, |
504 | +) |
505 | |
506 | === modified file 'account_financial_report_webkit/report/common_reports.py' |
507 | --- account_financial_report_webkit/report/common_reports.py 2013-12-17 16:16:37 +0000 |
508 | +++ account_financial_report_webkit/report/common_reports.py 2014-03-18 15:55:27 +0000 |
509 | @@ -30,7 +30,7 @@ |
510 | |
511 | _logger = logging.getLogger('financial.reports.webkit') |
512 | |
513 | - |
514 | +MAX_MONSTER_SLICE = 50000 |
515 | class CommonReportHeaderWebkit(common_report_header): |
516 | """Define common helper for financial report""" |
517 | |
518 | @@ -433,6 +433,14 @@ |
519 | raise osv.except_osv(_('No valid filter'), _('Please set a valid time filter')) |
520 | |
521 | def _get_move_line_datas(self, move_line_ids, order='per.special DESC, l.date ASC, per.date_start ASC, m.name ASC'): |
522 | + # Possible bang if move_line_ids is too long |
523 | + # We can not slice here as we have to do the sort. |
524 | + # If slice has to be done it means that we have to reorder in python |
525 | + # after all is finished. That quite crapy... |
526 | + # We have a defective desing here (mea culpa) that should be fixed |
527 | + # |
528 | + # TODO improve that by making a better domain or if not possible |
529 | + # by using python sort |
530 | if not move_line_ids: |
531 | return [] |
532 | if not isinstance(move_line_ids, list): |
533 | @@ -441,6 +449,7 @@ |
534 | SELECT l.id AS id, |
535 | l.date AS ldate, |
536 | j.code AS jcode , |
537 | + j.type AS jtype, |
538 | l.currency_id, |
539 | l.account_id, |
540 | l.amount_currency, |
541 | @@ -455,7 +464,8 @@ |
542 | l.partner_id AS lpartner_id, |
543 | p.name AS partner_name, |
544 | m.name AS move_name, |
545 | - COALESCE(partialrec.name, fullrec.name, '') AS rec_name, |
546 | + COALESCE(partialrec.name, fullrec.name, '') AS rec_name, |
547 | + COALESCE(partialrec.id, fullrec.id, NULL) AS rec_id, |
548 | m.id AS move_id, |
549 | c.name AS currency_code, |
550 | i.id AS invoice_id, |
551 | |
552 | === modified file 'account_financial_report_webkit/report/open_invoices.py' |
553 | --- account_financial_report_webkit/report/open_invoices.py 2013-11-03 12:55:27 +0000 |
554 | +++ account_financial_report_webkit/report/open_invoices.py 2014-03-18 15:55:27 +0000 |
555 | @@ -93,7 +93,6 @@ |
556 | """Populate a ledger_lines attribute on each browse record that will be used |
557 | by mako template""" |
558 | new_ids = data['form']['chart_account_id'] |
559 | - |
560 | # Account initial balance memoizer |
561 | init_balance_memoizer = {} |
562 | # Reading form |
563 | |
564 | === modified file 'account_financial_report_webkit/report/report.xml' |
565 | --- account_financial_report_webkit/report/report.xml 2013-12-16 09:37:19 +0000 |
566 | +++ account_financial_report_webkit/report/report.xml 2014-03-18 15:55:27 +0000 |
567 | @@ -14,23 +14,16 @@ |
568 | <field name="name">General Ledger Webkit</field> |
569 | <field name="report_rml">account_financial_report_webkit/report/templates/account_report_general_ledger.mako</field> |
570 | <field name="report_file">account_financial_report_webkit/report/templates/account_report_general_ledger.mako</field> |
571 | - </record> |
572 | + </record> |
573 | + |
574 | <record id="property_account_report_general_ledger_webkit" model="ir.property"> |
575 | <field name="name">account_report_general_ledger_webkit</field> |
576 | <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/> |
577 | <field eval="'ir.header_webkit,'+str(ref('account_financial_report_webkit.financial_landscape_header'))" model="ir.header_webkit" name="value"/> |
578 | <field eval="'ir.actions.report.xml,'+str(ref('account_financial_report_webkit.account_report_general_ledger_webkit'))" model="ir.actions.report.xml" name="res_id"/> |
579 | </record> |
580 | - <!-- waiting the fix |
581 | - <report auto="False" |
582 | - id="account_report_partner_ledger_webkit" |
583 | - model="account.account" |
584 | - name="account.account_report_partner_ledger_webkit" |
585 | - file="account_financial_report_webkit/report/templates/account_report_partner_ledger.mako" |
586 | - string="General Ledger Webkit" |
587 | - report_type="webkit"/> --> |
588 | - |
589 | - <!-- we do not use report tag has we can not set header ref --> |
590 | + |
591 | + <!-- we do not use report tag has we can not set header ref --> |
592 | <record id="account_report_partners_ledger_webkit" model="ir.actions.report.xml"> |
593 | <field name="report_type">webkit</field> |
594 | <field name="report_name">account.account_report_partners_ledger_webkit</field> |
595 | @@ -44,6 +37,7 @@ |
596 | <field name="report_rml">account_financial_report_webkit/report/templates/account_report_partners_ledger.mako</field> |
597 | <field name="report_file">account_financial_report_webkit/report/templates/account_report_partners_ledger.mako</field> |
598 | </record> |
599 | + |
600 | <record id="property_account_report_partners_ledger_webkit" model="ir.property"> |
601 | <field name="name">account_report_partners_ledger_webkit</field> |
602 | <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/> |
603 | @@ -64,6 +58,7 @@ |
604 | <field name="report_rml">account_financial_report_webkit/report/templates/account_report_trial_balance.mako</field> |
605 | <field name="report_file">account_financial_report_webkit/report/templates/account_report_trial_balance.mako</field> |
606 | </record> |
607 | + |
608 | <record id="property_account_report_trial_balance_webkit" model="ir.property"> |
609 | <field name="name">account_report_trial_balance_webkit</field> |
610 | <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/> |
611 | @@ -84,6 +79,7 @@ |
612 | <field name="report_rml">account_financial_report_webkit/report/templates/account_report_partner_balance.mako</field> |
613 | <field name="report_file">account_financial_report_webkit/report/templates/account_report_partner_balance.mako</field> |
614 | </record> |
615 | + |
616 | <record id="property_account_report_partner_balance_webkit" model="ir.property"> |
617 | <field name="name">account_report_partner_balance_webkit</field> |
618 | <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/> |
619 | @@ -104,6 +100,7 @@ |
620 | <field name="report_rml">account_financial_report_webkit/report/templates/account_report_open_invoices.mako</field> |
621 | <field name="report_file">account_financial_report_webkit/report/templates/account_report_open_invoices.mako</field> |
622 | </record> |
623 | + |
624 | <record id="property_account_report_open_invoices_webkit" model="ir.property"> |
625 | <field name="name">account_report_open_invoices_webkit</field> |
626 | <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/> |
627 | @@ -111,6 +108,31 @@ |
628 | <field eval="'ir.actions.report.xml,'+str(ref('account_financial_report_webkit.account_report_open_invoices_webkit'))" model="ir.actions.report.xml" name="res_id"/> |
629 | </record> |
630 | |
631 | + <record id="account_report_aged_trial_blanance_webkit" model="ir.actions.report.xml"> |
632 | + <field name="report_type">webkit</field> |
633 | + <field name="report_name">account.account_aged_trial_balance_webkit</field> |
634 | + <field eval="[(6,0,[])]" name="groups_id"/> |
635 | + <field eval="0" name="multi"/> |
636 | + <field eval="0" name="auto"/> |
637 | + <field eval="1" name="header"/> |
638 | + <field name="model">account.account</field> |
639 | + <field name="type">ir.actions.report.xml</field> |
640 | + <field name="name">Aged Partner Balance</field> |
641 | + <field name="report_rml">account_financial_report_webkit/report/templates/aged_trial_webkit.mako</field> |
642 | + <field name="report_file">account_financial_report_webkit/report/templates/aged_trial_webkit.mako</field> |
643 | + </record> |
644 | + |
645 | + <record id="property_account_report_aged_trial_balance_webkit" model="ir.property"> |
646 | + <field name="name">account_aged_trial_balance_webkit</field> |
647 | + <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/> |
648 | + <field eval="'ir.header_webkit,'+str(ref('account_financial_report_webkit.financial_landscape_header'))" |
649 | + model="ir.header_webkit" |
650 | + name="value"/> |
651 | + <field eval="'ir.actions.report.xml,'+str(ref('account_financial_report_webkit.account_report_aged_trial_blanance_webkit'))" |
652 | + model="ir.actions.report.xml" |
653 | + name="res_id"/> |
654 | + </record> |
655 | + |
656 | <record id="account_report_print_journal_webkit" model="ir.actions.report.xml"> |
657 | <field name="report_type">webkit</field> |
658 | <field name="report_name">account.account_report_print_journal_webkit</field> |
659 | @@ -124,6 +146,7 @@ |
660 | <field name="report_rml">account_financial_report_webkit/report/templates/account_report_print_journal.mako</field> |
661 | <field name="report_file">account_financial_report_webkit/report/templates/account_report_print_journal.mako</field> |
662 | </record> |
663 | + |
664 | <record id="property_account_report_print_journal_webkit" model="ir.property"> |
665 | <field name="name">account_report_print_journal_webkit</field> |
666 | <field name="fields_id" ref="report_webkit.field_ir_act_report_xml_webkit_header"/> |
667 | |
668 | === added file 'account_financial_report_webkit/report/templates/aged_trial_webkit.mako' |
669 | --- account_financial_report_webkit/report/templates/aged_trial_webkit.mako 1970-01-01 00:00:00 +0000 |
670 | +++ account_financial_report_webkit/report/templates/aged_trial_webkit.mako 2014-03-18 15:55:27 +0000 |
671 | @@ -0,0 +1,155 @@ |
672 | +## -*- coding: utf-8 -*- |
673 | +<!DOCTYPE html SYSTEM |
674 | +"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
675 | +<html xmlns="http://www.w3.org/1999/xhtml"> |
676 | + <head> |
677 | + <style type="text/css"> |
678 | + .overflow_ellipsis { |
679 | + text-overflow: ellipsis; |
680 | + overflow: hidden; |
681 | + white-space: nowrap; |
682 | + } |
683 | + |
684 | + .open_invoice_previous_line { |
685 | + font-style: italic; |
686 | + } |
687 | + |
688 | + .percent_line { |
689 | + font-style: italic; |
690 | + } |
691 | + |
692 | + .amount { |
693 | + text-align:right; |
694 | + } |
695 | + |
696 | + .classif_title { |
697 | + text-align:right; |
698 | + } |
699 | + |
700 | + .classif{ |
701 | + width: ${700/len(ranges)}px; |
702 | + } |
703 | + .total{ |
704 | + font-weight:bold; |
705 | + } |
706 | + ${css} |
707 | + </style> |
708 | + </head> |
709 | + |
710 | + <%! |
711 | + def amount(text): |
712 | + # replace by a non-breaking hyphen (it will not word-wrap between hyphen and numbers) |
713 | + return text.replace('-', '‑') |
714 | + %> |
715 | + <body> |
716 | + <%setLang(user.lang)%> |
717 | + |
718 | + <div class="act_as_table data_table"> |
719 | + <div class="act_as_row labels"> |
720 | + <div class="act_as_cell">${_('Chart of Account')}</div> |
721 | + <div class="act_as_cell">${_('Fiscal Year')}</div> |
722 | + <div class="act_as_cell"> |
723 | + %if filter_form(data) == 'filter_date': |
724 | + ${_('Dates Filter')} |
725 | + %else: |
726 | + ${_('Periods Filter')} |
727 | + %endif |
728 | + </div> |
729 | + <div class="act_as_cell">${_('Clearance Date')}</div> |
730 | + <div class="act_as_cell">${_('Accounts Filter')}</div> |
731 | + <div class="act_as_cell">${_('Target Moves')}</div> |
732 | + |
733 | + </div> |
734 | + <div class="act_as_row"> |
735 | + <div class="act_as_cell">${ chart_account.name }</div> |
736 | + <div class="act_as_cell">${ fiscalyear.name if fiscalyear else '-' }</div> |
737 | + <div class="act_as_cell"> |
738 | + ${_('From:')} |
739 | + %if filter_form(data) == 'filter_date': |
740 | + ${formatLang(start_date, date=True) if start_date else u'' } |
741 | + %else: |
742 | + ${start_period.name if start_period else u''} |
743 | + %endif |
744 | + ${_('To:')} |
745 | + %if filter_form(data) == 'filter_date': |
746 | + ${ formatLang(stop_date, date=True) if stop_date else u'' } |
747 | + %else: |
748 | + ${stop_period.name if stop_period else u'' } |
749 | + %endif |
750 | + </div> |
751 | + <div class="act_as_cell">${ formatLang(date_until, date=True) }</div> |
752 | + <div class="act_as_cell"> |
753 | + %if partner_ids: |
754 | + ${_('Custom Filter')} |
755 | + %else: |
756 | + ${ display_partner_account(data) } |
757 | + %endif |
758 | + </div> |
759 | + <div class="act_as_cell">${ display_target_move(data) }</div> |
760 | + </div> |
761 | + </div> |
762 | + %for acc in objects: |
763 | + %if acc.aged_lines: |
764 | + <div class="account_title bg" style="width: 1080px; margin-top: 20px; font-size: 12px;">${acc.code} - ${acc.name}</div> |
765 | + |
766 | + |
767 | + |
768 | + <div class="act_as_table list_table" style="margin-top: 5px;"> |
769 | + <div class="act_as_thead"> |
770 | + <div class="act_as_row labels"> |
771 | + ## partner |
772 | + <div class="act_as_cell first_column" style="width: 60px;">${_('Partner')}</div> |
773 | + ## code |
774 | + <div class="act_as_cell" style="width: 70px;">${_('code')}</div> |
775 | + ## balance |
776 | + <div class="act_as_cell classif_title" style="width: 70px;">${_('balance')}</div> |
777 | + ## Classifications |
778 | + %for title in ranges_titles: |
779 | + <div class="act_as_cell classif classif_title">${title}</div> |
780 | + %endfor |
781 | + </div> |
782 | + </div> |
783 | + <div class="act_as_tbody"> |
784 | + %for partner_name, p_id, p_ref, p_name in acc.partners_order: |
785 | + %if acc.aged_lines.get(p_id): |
786 | + <div class="act_as_row lines"> |
787 | + <%line = acc.aged_lines[p_id]%> |
788 | + <%percents = acc.aged_percents%> |
789 | + <%totals = acc.aged_totals%> |
790 | + <div class="act_as_cell first_column">${partner_name}</div> |
791 | + <div class="act_as_cell">${p_ref or ''}</div> |
792 | + |
793 | + <div class="act_as_cell amount">${formatLang(line.get('balance') or 0.0) | amount}</div> |
794 | + %for classif in ranges: |
795 | + <div class="act_as_cell classif amount"> |
796 | + ${formatLang(line['aged_lines'][classif] or 0.0) | amount} |
797 | + </div> |
798 | + %endfor |
799 | + </div> |
800 | + %endif |
801 | + %endfor |
802 | + <div class="act_as_row labels"> |
803 | + <div class="act_as_cell total">${_('Total')}</div> |
804 | + <div class="act_as_cell"></div> |
805 | + <div class="act_as_cell amount classif total">${formatLang(totals['balance']) | amount}</div> |
806 | + %for classif in ranges: |
807 | + <div class="act_as_cell amount classif total">${formatLang(totals[classif]) | amount}</div> |
808 | + %endfor |
809 | + </div> |
810 | + |
811 | + <div class="act_as_row"> |
812 | + <div class="act_as_cell"><b>${_('Percents')}</b></div> |
813 | + <div class="act_as_cell"></div> |
814 | + <div class="act_as_cell"></div> |
815 | + %for classif in ranges: |
816 | + <div class="act_as_cell amount percent_line classif">${formatLang(percents[classif]) | amount}%</div> |
817 | + %endfor |
818 | + </div> |
819 | + </div> |
820 | + <br/> |
821 | + |
822 | + %endif |
823 | + %endfor |
824 | + </div> |
825 | + </body> |
826 | +</html> |
827 | |
828 | === modified file 'account_financial_report_webkit/report/templates/open_invoices_inclusion.mako.html' |
829 | --- account_financial_report_webkit/report/templates/open_invoices_inclusion.mako.html 2013-11-21 15:55:29 +0000 |
830 | +++ account_financial_report_webkit/report/templates/open_invoices_inclusion.mako.html 2014-03-18 15:55:27 +0000 |
831 | @@ -9,7 +9,7 @@ |
832 | %> |
833 | |
834 | <div class="account_title bg" style="width: 1080px; margin-top: 20px; font-size: 12px;">${account.code} - ${account.name}</div> |
835 | - |
836 | + |
837 | %for partner_name, p_id, p_ref, p_name in account.partners_order: |
838 | <% |
839 | total_debit = 0.0 |
840 | @@ -18,7 +18,7 @@ |
841 | cumul_balance_curr = 0.0 |
842 | |
843 | part_cumul_balance = 0.0 |
844 | - part_cumul_balance_curr = 0.0 |
845 | + part_cumul_balance_curr = 0.0 |
846 | %> |
847 | <div class="act_as_table list_table" style="margin-top: 5px;"> |
848 | <div class="act_as_caption account_title"> |
849 | |
850 | === modified file 'account_financial_report_webkit/report/webkit_parser_header_fix.py' |
851 | --- account_financial_report_webkit/report/webkit_parser_header_fix.py 2014-01-14 09:37:20 +0000 |
852 | +++ account_financial_report_webkit/report/webkit_parser_header_fix.py 2014-03-18 15:55:27 +0000 |
853 | @@ -160,7 +160,6 @@ |
854 | # override needed to keep the attachments' storing procedure |
855 | def create_single_pdf(self, cursor, uid, ids, data, report_xml, context=None): |
856 | """generate the PDF""" |
857 | - |
858 | if context is None: |
859 | context={} |
860 | htmls = [] |
861 | |
862 | === modified file 'account_financial_report_webkit/report_menus.xml' |
863 | --- account_financial_report_webkit/report_menus.xml 2014-01-13 09:33:02 +0000 |
864 | +++ account_financial_report_webkit/report_menus.xml 2014-03-18 15:55:27 +0000 |
865 | @@ -18,6 +18,10 @@ |
866 | parent="account.next_id_22" action="action_account_partner_balance_menu_webkit" |
867 | groups="account.group_account_manager,account.group_account_user" id="account.menu_account_partner_balance_report"/> |
868 | |
869 | + <menuitem icon="STOCK_PRINT" name="Aged Partner Balance" |
870 | + parent="account.next_id_22" action="action_account_aged_trial_balance_menu_webkit" |
871 | + groups="account.group_account_manager,account.group_account_user" id="account.menu_aged_trial_balance"/> |
872 | + |
873 | <menuitem icon="STOCK_PRINT" name="Open Invoices" |
874 | parent="account.next_id_22" action="action_account_open_invoices_menu_webkit" |
875 | groups="account.group_account_manager,account.group_account_user" id="menu_account_open_invoices"/> |
876 | |
877 | === added file 'account_financial_report_webkit/tests/aged_trial_balance.yml' |
878 | --- account_financial_report_webkit/tests/aged_trial_balance.yml 1970-01-01 00:00:00 +0000 |
879 | +++ account_financial_report_webkit/tests/aged_trial_balance.yml 2014-03-18 15:55:27 +0000 |
880 | @@ -0,0 +1,60 @@ |
881 | +- |
882 | + In order to test the PDF Aged Partner Balance Report webkit wizard I will print report with default setting |
883 | +- |
884 | + !python {model: account.account}: | |
885 | + from datetime import datetime |
886 | + ctx={} |
887 | + data_dict = {'chart_account_id':ref('account.chart0'), 'until_date': '%s-12-31' %(datetime.now().year)} |
888 | + from tools import test_reports |
889 | + test_reports.try_report_action(cr, uid, 'action_account_aged_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit') |
890 | + |
891 | +- |
892 | + In order to test the PDF Aged Partner Balance Report webkit wizard I will print report with filters and currency |
893 | +- |
894 | + !python {model: account.account}: | |
895 | + from datetime import datetime |
896 | + ctx={} |
897 | + data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'), |
898 | + 'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted', |
899 | + 'amount_currency': True, 'result_selection': 'customer_supplier'} |
900 | + from tools import test_reports |
901 | + test_reports.try_report_action(cr, uid, 'action_account_aged_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit') |
902 | + |
903 | +- |
904 | + In order to test the PDF Aged Partner Balance Report webkit wizard I will print report with filters on partners |
905 | +- |
906 | + !python {model: account.account}: | |
907 | + from datetime import datetime |
908 | + ctx={} |
909 | + data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'), |
910 | + 'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted', |
911 | + 'amount_currency': True, 'result_selection': 'customer_supplier', |
912 | + 'partner_ids': [ref('base.res_partner_2'), ref('base.res_partner_1')]} |
913 | + from tools import test_reports |
914 | + test_reports.try_report_action(cr, uid, 'action_account_aged_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit') |
915 | + |
916 | +- |
917 | + In order to test the PDF Aged Partner Balance Report webkit wizard I will print report with filters on periods |
918 | +- |
919 | + !python {model: account.account}: | |
920 | + from datetime import datetime |
921 | + ctx={} |
922 | + data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'), |
923 | + 'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted', |
924 | + 'amount_currency': True, 'result_selection': 'customer_supplier', |
925 | + 'filter': 'filter_period', 'period_from': ref('account.period_1'), 'period_to': ref('account.period_12')} |
926 | + from tools import test_reports |
927 | + test_reports.try_report_action(cr, uid, 'action_account_aged_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit') |
928 | + |
929 | +- |
930 | + In order to test the PDF Aged Partner Balance Report webkit wizard I will print report with filters on dates |
931 | +- |
932 | + !python {model: account.account}: | |
933 | + from datetime import datetime |
934 | + ctx={} |
935 | + data_dict = {'chart_account_id':ref('account.chart0'), 'fiscalyear_id': ref('account.data_fiscalyear'), |
936 | + 'until_date': '%s-12-31' %(datetime.now().year), 'target_move': 'posted', |
937 | + 'amount_currency': True, 'result_selection': 'customer_supplier', |
938 | + 'filter': 'filter_date', 'date_from': '%s-01-01' %(datetime.now().year), 'date_to': '%s-12-31' %(datetime.now().year)} |
939 | + from tools import test_reports |
940 | + test_reports.try_report_action(cr, uid, 'action_account_aged_trial_balance_menu_webkit',wiz_data=data_dict, context=ctx, our_module='account_financial_report_webkit') |
941 | |
942 | === modified file 'account_financial_report_webkit/wizard/__init__.py' |
943 | --- account_financial_report_webkit/wizard/__init__.py 2013-09-12 20:53:27 +0000 |
944 | +++ account_financial_report_webkit/wizard/__init__.py 2014-03-18 15:55:27 +0000 |
945 | @@ -27,3 +27,4 @@ |
946 | from . import partner_balance_wizard |
947 | from . import open_invoices_wizard |
948 | from . import print_journal |
949 | +from . import aged_partner_balance_wizard |
950 | |
951 | === added file 'account_financial_report_webkit/wizard/aged_partner_balance_wizard.py' |
952 | --- account_financial_report_webkit/wizard/aged_partner_balance_wizard.py 1970-01-01 00:00:00 +0000 |
953 | +++ account_financial_report_webkit/wizard/aged_partner_balance_wizard.py 2014-03-18 15:55:27 +0000 |
954 | @@ -0,0 +1,39 @@ |
955 | +# -*- coding: utf-8 -*- |
956 | +############################################################################## |
957 | +# |
958 | +# Author: Nicolas Bessi |
959 | +# Copyright 2014 Camptocamp SA |
960 | +# |
961 | +# This program is free software: you can redistribute it and/or modify |
962 | +# it under the terms of the GNU Affero General Public License as |
963 | +# published by the Free Software Foundation, either version 3 of the |
964 | +# License, or (at your option) any later version. |
965 | +# |
966 | +# This program is distributed in the hope that it will be useful, |
967 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
968 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
969 | +# GNU Affero General Public License for more details. |
970 | +# |
971 | +# You should have received a copy of the GNU Affero General Public License |
972 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
973 | +# |
974 | +############################################################################## |
975 | +from openerp.osv import orm |
976 | + |
977 | + |
978 | +class AccountAgedTrialBalance(orm.TransientModel): |
979 | + """Will launch age partner balance report. |
980 | + This report is based on Open Invoice Report |
981 | + and share a lot of knowledge with him |
982 | + """ |
983 | + |
984 | + _inherit = "open.invoices.webkit" |
985 | + _name = "account.aged.trial.balance.webkit" |
986 | + _description = "Aged partner balanced" |
987 | + |
988 | + def _print_report(self, cr, uid, ids, data, context=None): |
989 | + # we update form with display account value |
990 | + data = self.pre_print_report(cr, uid, ids, data, context=context) |
991 | + return {'type': 'ir.actions.report.xml', |
992 | + 'report_name': 'account.account_aged_trial_balance_webkit', |
993 | + 'datas': data} |
994 | |
995 | === added file 'account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml' |
996 | --- account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml 1970-01-01 00:00:00 +0000 |
997 | +++ account_financial_report_webkit/wizard/aged_partner_balance_wizard.xml 2014-03-18 15:55:27 +0000 |
998 | @@ -0,0 +1,72 @@ |
999 | +<?xml version="1.0" encoding="utf-8"?> |
1000 | +<openerp> |
1001 | + <data> |
1002 | + |
1003 | + <record id="account_aged_trial_balance_webkit" model="ir.ui.view"> |
1004 | + <field name="name">Aged Partner Balance Report</field> |
1005 | + <field name="model">account.aged.trial.balance.webkit</field> |
1006 | + <field name="inherit_id" ref="account.account_common_report_view"/> |
1007 | + <field name="arch" type="xml"> |
1008 | + <data> |
1009 | + |
1010 | + <xpath expr="/form/label[@string='']" position="replace"> |
1011 | + <separator string="Aged Partner Balance" colspan="4"/> |
1012 | + <label nolabel="1" |
1013 | + colspan="4" |
1014 | + string="This report list partner open balances and indicate when payment is (or was) supposed to be completed"/> |
1015 | + </xpath> |
1016 | + <field name="chart_account_id" position='attributes'> |
1017 | + <attribute name="colspan">4</attribute> |
1018 | + </field> |
1019 | + <xpath expr="//field[@name='target_move']" position="after"> |
1020 | + <newline/> |
1021 | + <field name="result_selection" colspan="4"/> |
1022 | + </xpath> |
1023 | + <xpath expr="/form/notebook[1]" position="after"> |
1024 | + <separator string="Clearance Analysis Options" colspan="4"/> |
1025 | + <newline/> |
1026 | + <field name="until_date"/> |
1027 | + </xpath> |
1028 | + <page name="filters" position="after"> |
1029 | + <page string="Partners Filters" name="partners"> |
1030 | + <separator string="Print only" colspan="4"/> |
1031 | + <field name="partner_ids" colspan="4" nolabel="1"/> |
1032 | + </page> |
1033 | + </page> |
1034 | + <page name="filters" position="attributes"> |
1035 | + <attribute name="string">Time Filters</attribute> |
1036 | + </page> |
1037 | + <page name="journal_ids" position="attributes"> |
1038 | + <attribute name="invisible">True</attribute> |
1039 | + </page> |
1040 | + <field name="fiscalyear_id" position="attributes"> |
1041 | + <attribute name="on_change">onchange_fiscalyear(fiscalyear_id, period_to, date_to, until_date)</attribute> |
1042 | + </field> |
1043 | + <field name="date_to" position="attributes"> |
1044 | + <attribute name="on_change">onchange_date_to(fiscalyear_id, period_to, date_to, until_date)</attribute> |
1045 | + </field> |
1046 | + <field name="period_to" position="attributes"> |
1047 | + <attribute name="on_change">onchange_period_to(fiscalyear_id, period_to, date_to, until_date)</attribute> |
1048 | + </field> |
1049 | + <field name="period_from" position="attributes"> |
1050 | + <attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute> |
1051 | + </field> |
1052 | + <field name="period_to" position="attributes"> |
1053 | + <attribute name="domain">[('fiscalyear_id', '=', fiscalyear_id), ('special', '=', False)]</attribute> |
1054 | + </field> |
1055 | + </data> |
1056 | + </field> |
1057 | + </record> |
1058 | + |
1059 | + <record id="action_account_aged_trial_balance_menu_webkit" |
1060 | + model="ir.actions.act_window"> |
1061 | + <field name="name">Aged partner balance</field> |
1062 | + <field name="type">ir.actions.act_window</field> |
1063 | + <field name="res_model">account.aged.trial.balance.webkit</field> |
1064 | + <field name="view_type">form</field> |
1065 | + <field name="view_mode">form</field> |
1066 | + <field name="view_id" ref="account_aged_trial_balance_webkit"/> |
1067 | + <field name="target">new</field> |
1068 | + </record> |
1069 | + </data> |
1070 | +</openerp> |
quite a lot a code, and no test... :-(
Remarks:
* line 353 (in compute_ delay_from_ partial_ rec): it would be nicer to move reference_line = line in the else clause of the if / elif statement (makes it clear that reference_line has avalue in all cases)
* line 381 and 383 (in get_compute_method) are the same. Can they be merged in the same branch?
* line 452: avoid the call to float() unless you have string in total[drange]. If you want to protect against int / int -> int, add from __future__ import division at the beginning of the module (and use // for integer division).
* line 472 and following (in get_reconcile_ count_lookup) : don't add \n in SQL statement.
* line 477 and following (in get_reconcile_ count_lookup) : the "if res" is useless, as well as the return {}.