Merge lp:~camptocamp/account-financial-tools/add-credit-control-legal-claim-nbi into lp:~camptocamp/account-financial-tools/add-manual-line-and-fees-nbi

Proposed by Nicolas Bessi - Camptocamp
Status: Work in progress
Proposed branch: lp:~camptocamp/account-financial-tools/add-credit-control-legal-claim-nbi
Merge into: lp:~camptocamp/account-financial-tools/add-manual-line-and-fees-nbi
Diff against target: 1479 lines (+1377/-0)
19 files modified
account_credit_control_legal_claim/__init__.py (+23/-0)
account_credit_control_legal_claim/__openerp__.py (+59/-0)
account_credit_control_legal_claim/model/__init__.py (+24/-0)
account_credit_control_legal_claim/model/claim_fees_scheme.py (+131/-0)
account_credit_control_legal_claim/model/claim_office.py (+55/-0)
account_credit_control_legal_claim/model/partner.py (+55/-0)
account_credit_control_legal_claim/model/policy.py (+46/-0)
account_credit_control_legal_claim/report/__init__.py (+21/-0)
account_credit_control_legal_claim/report/claim_requisition_report.py (+80/-0)
account_credit_control_legal_claim/report/credit_control_legal_claim.html.mako (+259/-0)
account_credit_control_legal_claim/report/report.xml (+18/-0)
account_credit_control_legal_claim/tests/__init__.py (+23/-0)
account_credit_control_legal_claim/tests/test_claim_requisiton_print.py (+177/-0)
account_credit_control_legal_claim/view/claim_office_view.xml (+69/-0)
account_credit_control_legal_claim/view/claim_scheme_view.xml (+73/-0)
account_credit_control_legal_claim/view/credit_control_claim_printer_view.xml (+65/-0)
account_credit_control_legal_claim/view/policy_view.xml (+24/-0)
account_credit_control_legal_claim/wizard/__init__.py (+21/-0)
account_credit_control_legal_claim/wizard/credit_control_claim_printer.py (+154/-0)
To merge this branch: bzr merge lp:~camptocamp/account-financial-tools/add-credit-control-legal-claim-nbi
Reviewer Review Type Date Requested Status
Camptocamp Pending
Review via email: mp+220801@code.launchpad.net

Description of the change

Adds dunning/legal claim management based on credit control

To post a comment you must log in.
223. By Nicolas Bessi - Camptocamp on 2014-05-27

[MRG] from parent MP

224. By Nicolas Bessi - Camptocamp on 2014-05-27

[MRG] from parent MP

225. By Nicolas Bessi - Camptocamp on 2014-05-27

[TYPO] overriden -> overridden

Unmerged revisions

225. By Nicolas Bessi - Camptocamp on 2014-05-27

[TYPO] overriden -> overridden

224. By Nicolas Bessi - Camptocamp on 2014-05-27

[MRG] from parent MP

223. By Nicolas Bessi - Camptocamp on 2014-05-27

[MRG] from parent MP

222. By Nicolas Bessi - Camptocamp on 2014-05-23

[ADD] constraint to ensure that only highest level credit policy can trigger legal claim

221. By Nicolas Bessi - Camptocamp on 2014-05-23

[ADD] description in manifest

220. By Nicolas Bessi - Camptocamp on 2014-05-23

[ADD] test for account_credit_control_legal_claim

219. By Nicolas Bessi - Camptocamp on 2014-05-22

[ADD] docstring

218. By Nicolas Bessi - Camptocamp on 2014-05-22

[ADD] base of credit control legal claim

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'account_credit_control_legal_claim'
2=== added file 'account_credit_control_legal_claim/__init__.py'
3--- account_credit_control_legal_claim/__init__.py 1970-01-01 00:00:00 +0000
4+++ account_credit_control_legal_claim/__init__.py 2014-05-27 07:08:15 +0000
5@@ -0,0 +1,23 @@
6+# -*- coding: utf-8 -*-
7+##############################################################################
8+#
9+# Author: Nicolas Bessi
10+# Copyright 2014 Camptocamp SA
11+#
12+# This program is free software: you can redistribute it and/or modify
13+# it under the terms of the GNU Affero General Public License as
14+# published by the Free Software Foundation, either version 3 of the
15+# License, or (at your option) any later version.
16+#
17+# This program is distributed in the hope that it will be useful,
18+# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+# GNU Affero General Public License for more details.
21+#
22+# You should have received a copy of the GNU Affero General Public License
23+# along with this program. If not, see <http://www.gnu.org/licenses/>.
24+#
25+##############################################################################
26+from . import model
27+from . import wizard
28+from . import report
29
30=== added file 'account_credit_control_legal_claim/__openerp__.py'
31--- account_credit_control_legal_claim/__openerp__.py 1970-01-01 00:00:00 +0000
32+++ account_credit_control_legal_claim/__openerp__.py 2014-05-27 07:08:15 +0000
33@@ -0,0 +1,59 @@
34+# -*- coding: utf-8 -*-
35+##############################################################################
36+#
37+# Author: Nicolas Bessi
38+# Copyright 2014 Camptocamp SA
39+#
40+# This program is free software: you can redistribute it and/or modify
41+# it under the terms of the GNU Affero General Public License as
42+# published by the Free Software Foundation, either version 3 of the
43+# License, or (at your option) any later version.
44+#
45+# This program is distributed in the hope that it will be useful,
46+# but WITHOUT ANY WARRANTY; without even the implied warranty of
47+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48+# GNU Affero General Public License for more details.
49+#
50+# You should have received a copy of the GNU Affero General Public License
51+# along with this program. If not, see <http://www.gnu.org/licenses/>.
52+#
53+##############################################################################
54+{'name': 'Credit Control Legal Claim',
55+ 'version': '0.1',
56+ 'author': 'Camptocamp',
57+ 'maintainer': 'Camptocamp',
58+ 'category': 'Accounting',
59+ 'complexity': 'normal',
60+ 'depends': ['base_location',
61+ 'base_headers_webkit',
62+ 'account_credit_control'],
63+ 'description': """
64+Credit Control Legal Claim
65+--------------------------
66+
67+This addons allows to manage legal claim requisition
68+from credit controling.
69+
70+This is done by setting a boolean "Legal claim"
71+on credit control policy level.
72+
73+
74+From then you can print claim requisition letter from invoice
75+user the: ::
76+
77+ more -> Print Legal Claim Letter
78+
79+""",
80+ 'website': 'http://www.camptocamp.com',
81+ 'data': ['view/claim_office_view.xml',
82+ 'view/claim_scheme_view.xml',
83+ 'view/credit_control_claim_printer_view.xml',
84+ 'report/report.xml',
85+ 'view/policy_view.xml'],
86+ 'demo': [],
87+ 'test': [],
88+ 'installable': True,
89+ 'auto_install': False,
90+ 'license': 'AGPL-3',
91+ 'application': False,
92+ }
93
94=== added directory 'account_credit_control_legal_claim/i18n'
95=== added directory 'account_credit_control_legal_claim/model'
96=== added file 'account_credit_control_legal_claim/model/__init__.py'
97--- account_credit_control_legal_claim/model/__init__.py 1970-01-01 00:00:00 +0000
98+++ account_credit_control_legal_claim/model/__init__.py 2014-05-27 07:08:15 +0000
99@@ -0,0 +1,24 @@
100+# -*- coding: utf-8 -*-
101+##############################################################################
102+#
103+# Author: Nicolas Bessi
104+# Copyright 2014 Camptocamp SA
105+#
106+# This program is free software: you can redistribute it and/or modify
107+# it under the terms of the GNU Affero General Public License as
108+# published by the Free Software Foundation, either version 3 of the
109+# License, or (at your option) any later version.
110+#
111+# This program is distributed in the hope that it will be useful,
112+# but WITHOUT ANY WARRANTY; without even the implied warranty of
113+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
114+# GNU Affero General Public License for more details.
115+#
116+# You should have received a copy of the GNU Affero General Public License
117+# along with this program. If not, see <http://www.gnu.org/licenses/>.
118+#
119+##############################################################################
120+from . import claim_office
121+from . import claim_fees_scheme
122+from . import policy
123+from . import partner
124
125=== added file 'account_credit_control_legal_claim/model/claim_fees_scheme.py'
126--- account_credit_control_legal_claim/model/claim_fees_scheme.py 1970-01-01 00:00:00 +0000
127+++ account_credit_control_legal_claim/model/claim_fees_scheme.py 2014-05-27 07:08:15 +0000
128@@ -0,0 +1,131 @@
129+# -*- coding: utf-8 -*-
130+##############################################################################
131+#
132+# Author: Nicolas Bessi
133+# Copyright 2013 Camptocamp SA
134+#
135+# This program is free software: you can redistribute it and/or modify
136+# it under the terms of the GNU Affero General Public License as
137+# published by the Free Software Foundation, either version 3 of the
138+# License, or (at your option) any later version.
139+#
140+# This program is distributed in the hope that it will be useful,
141+# but WITHOUT ANY WARRANTY; without even the implied warranty of
142+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
143+# GNU Affero General Public License for more details.
144+#
145+# You should have received a copy of the GNU Affero General Public License
146+# along with this program. If not, see <http://www.gnu.org/licenses/>.
147+#
148+##############################################################################
149+from operator import attrgetter
150+from openerp.osv import orm, fields
151+
152+
153+class claim_fees_scheme(orm.Model):
154+ """Claim fees
155+
156+ Claim offices take fees based on open amount
157+ whan a legal action is taken.
158+
159+ The model represent the scheme open amount/fees
160+
161+ """
162+
163+ _name = 'legal.claim.fees.scheme'
164+
165+ _columns = {
166+ 'name': fields.char('Name',
167+ required=True),
168+ 'product_id': fields.many2one('product.product',
169+ 'Product',
170+ required=True),
171+ 'claim_scheme_line_ids': fields.one2many('legal.claim.fees.scheme.line',
172+ 'claim_scheme_id',
173+ 'Price lists'),
174+ 'company_id': fields.many2one('res.company',
175+ 'Company'),
176+ 'currency_id': fields.many2one('res.currency',
177+ 'Currency',
178+ required=True),
179+ }
180+
181+ def _company_get(self, cr, uid, context=None):
182+ """Return related company"""
183+ return self.pool['res.company']._company_default_get(cr, uid,
184+ 'claim.fees.scheme',
185+ context=context)
186+ _defaults = {'company_id': _company_get}
187+
188+ def _due_from_invoices(self, invoices_records, context=None):
189+ """Compute due amount form a list of invoice
190+
191+ :param invoices_record: list of invoice records
192+
193+ :returns: due amount (float)
194+
195+ """
196+ return sum(x.residual for x in invoices_records)
197+
198+ def get_fees_from_amount(self, cr, uid, ids, due_amount, context=None):
199+ """Get the fees from open amount
200+
201+ :param due_amount: float of the open (due) amount
202+
203+ :returns: fees amount (float)
204+
205+ """
206+ assert len(ids) == 1, 'Only on id expected'
207+ current = self.browse(cr, uid, ids[0], context=context)
208+ lines = current.claim_scheme_line_ids
209+ lines.sort(key=attrgetter('open_amount'), reverse=True)
210+ for line in lines:
211+ if due_amount >= line.open_amount:
212+ return line.fees
213+ return lines[-1].fees
214+
215+ def get_fees_from_invoices(self, cr, uid, ids, invoice_ids, context=None):
216+ """Get the fees form a list of invoice ids
217+
218+ :param invoice_ids: list of invoice_ids
219+
220+ :returns: fees amount (float)
221+
222+ """
223+ assert len(ids) == 1, 'Only on id expected'
224+ invoices = self.pool['account.invoice'].browse(cr, uid, invoice_ids,
225+ context=context)
226+ return self._get_fees_from_invoices(cr, uid, ids, invoices,
227+ context=context)
228+
229+ def _get_fees_from_invoices(self, cr, uid, ids, invoices, context=None):
230+ """Get the fees form a list of invoice record
231+
232+ :param invoice_ids: list of invoice record
233+
234+ :returns: fees amount (float)
235+
236+ """
237+ assert len(ids) == 1, 'Only on id expected'
238+ current = self.browse(cr, uid, ids[0], context=context)
239+ due = self._due_from_invoices(invoices, context=context)
240+ return current.get_fees_from_amount(due)
241+
242+
243+class claim_fees_scheme_line(orm.Model):
244+ """Price list line of scheme
245+ that contains price and qty"""
246+
247+ _name = 'legal.claim.fees.scheme.line'
248+ _rec_name = "open_amount"
249+ _order = "open_amount"
250+
251+ _columns = {
252+ 'claim_scheme_id': fields.many2one('legal.claim.fees.scheme',
253+ 'Price list',
254+ required=True),
255+ 'open_amount': fields.integer('Open Amount',
256+ required=True),
257+ 'fees': fields.float('Fees',
258+ required=True),
259+ }
260
261=== added file 'account_credit_control_legal_claim/model/claim_office.py'
262--- account_credit_control_legal_claim/model/claim_office.py 1970-01-01 00:00:00 +0000
263+++ account_credit_control_legal_claim/model/claim_office.py 2014-05-27 07:08:15 +0000
264@@ -0,0 +1,55 @@
265+# -*- coding: utf-8 -*-
266+##############################################################################
267+#
268+# Author: Nicolas Bessi
269+# Copyright 2014 Camptocamp SA
270+#
271+# This program is free software: you can redistribute it and/or modify
272+# it under the terms of the GNU Affero General Public License as
273+# published by the Free Software Foundation, either version 3 of the
274+# License, or (at your option) any later version.
275+#
276+# This program is distributed in the hope that it will be useful,
277+# but WITHOUT ANY WARRANTY; without even the implied warranty of
278+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
279+# GNU Affero General Public License for more details.
280+#
281+# You should have received a copy of the GNU Affero General Public License
282+# along with this program. If not, see <http://www.gnu.org/licenses/>.
283+#
284+##############################################################################
285+from openerp.osv import orm, fields
286+
287+
288+class claim_office(orm.Model):
289+ """Claim office"""
290+
291+ _name = "legal.claim.office"
292+ _columns = {
293+
294+ 'name': fields.char('Name',
295+ required=True),
296+
297+ 'locations_ids': fields.one2many('res.better.zip',
298+ 'claim_office_id',
299+ 'Related zip'),
300+
301+ 'fees_scheme_id': fields.many2one('legal.claim.fees.scheme',
302+ 'Fees Scheme',
303+ select=1,
304+ required=True),
305+ 'partner_id': fields.many2one('res.partner',
306+ 'Office Address',
307+ required=True),
308+ }
309+
310+
311+class better_zip(orm.Model):
312+ """Add relation to claim office"""
313+
314+ _inherit = "res.better.zip"
315+ _columns = {
316+ 'claim_office_id': fields.many2one('legal.claim.office',
317+ 'Claim office',
318+ select=True),
319+ }
320
321=== added file 'account_credit_control_legal_claim/model/partner.py'
322--- account_credit_control_legal_claim/model/partner.py 1970-01-01 00:00:00 +0000
323+++ account_credit_control_legal_claim/model/partner.py 2014-05-27 07:08:15 +0000
324@@ -0,0 +1,55 @@
325+# -*- coding: utf-8 -*-
326+##############################################################################
327+#
328+# Author: Nicolas Bessi
329+# Copyright 2014 Camptocamp SA
330+#
331+# This program is free software: you can redistribute it and/or modify
332+# it under the terms of the GNU Affero General Public License as
333+# published by the Free Software Foundation, either version 3 of the
334+# License, or (at your option) any later version.
335+#
336+# This program is distributed in the hope that it will be useful,
337+# but WITHOUT ANY WARRANTY; without even the implied warranty of
338+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
339+# GNU Affero General Public License for more details.
340+#
341+# You should have received a copy of the GNU Affero General Public License
342+# along with this program. If not, see <http://www.gnu.org/licenses/>.
343+#
344+##############################################################################
345+from openerp.osv import orm, fields
346+
347+
348+class res_partner(orm.Model):
349+ """Add related claim office"""
350+ def _get_claim_office(self, cr, uid, ids, field, args, context=None):
351+ res = {}
352+ location_model = self.pool['res.better.zip']
353+ for partner in self.browse(cr, uid, ids, context=context):
354+ res[partner.id] = False
355+ domain = [('name', '=', partner.zip),
356+ ('city', '=', partner.city),
357+ ('claim_office_id', '!=', False)]
358+ location_id = location_model.search(cr, uid, domain,
359+ order='priority',
360+ limit=1,
361+ context=context)
362+ if not location_id:
363+ continue
364+ loc = location_model.read(cr,
365+ uid,
366+ location_id,
367+ ['claim_office_id'],
368+ load='_classic_write',
369+ context=context)
370+ res[partner.id] = loc[0]['claim_office_id']
371+ return res
372+
373+ _inherit = "res.partner"
374+ _columns = {
375+ 'claim_office_id': fields.function(_get_claim_office,
376+ type='many2one',
377+ relation='legal.claim.office',
378+ string='Claim office')
379+ }
380
381=== added file 'account_credit_control_legal_claim/model/policy.py'
382--- account_credit_control_legal_claim/model/policy.py 1970-01-01 00:00:00 +0000
383+++ account_credit_control_legal_claim/model/policy.py 2014-05-27 07:08:15 +0000
384@@ -0,0 +1,46 @@
385+# -*- coding: utf-8 -*-
386+##############################################################################
387+#
388+# Author: Nicolas Bessi
389+# Copyright 2014 Camptocamp SA
390+#
391+# This program is free software: you can redistribute it and/or modify
392+# it under the terms of the GNU Affero General Public License as
393+# published by the Free Software Foundation, either version 3 of the
394+# License, or (at your option) any later version.
395+#
396+# This program is distributed in the hope that it will be useful,
397+# but WITHOUT ANY WARRANTY; without even the implied warranty of
398+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
399+# GNU Affero General Public License for more details.
400+#
401+# You should have received a copy of the GNU Affero General Public License
402+# along with this program. If not, see <http://www.gnu.org/licenses/>.
403+#
404+##############################################################################
405+from openerp.osv import orm, fields
406+from openerp.tools.translate import _
407+
408+class credit_control_policy_level(orm.Model):
409+ """Add claim type to policy level"""
410+
411+ _inherit = "credit.control.policy.level"
412+ _columns = {
413+ 'is_legal_claim': fields.boolean('Legal Claim Action')
414+ }
415+
416+ def _check_legal_claim_level(self, cr, uid, ids, context=None):
417+ for current_level in self.browse(cr, uid, ids, context=context):
418+ levels = current_level.policy_id.level_ids
419+ highest = max(levels, key= lambda x: x.level)
420+ for lvl in levels:
421+ if lvl.is_legal_claim and lvl != highest:
422+ raise orm.except_orm(
423+ _('Only highest level can be tickes as legal claim'),
424+ _('The current highest level is %s') % highest.name
425+ )
426+ return True
427+
428+ _constraints = [(_check_legal_claim_level,
429+ 'Only highest level can be legal claim',
430+ ['is_legal_claim'])]
431
432=== added directory 'account_credit_control_legal_claim/report'
433=== added file 'account_credit_control_legal_claim/report/__init__.py'
434--- account_credit_control_legal_claim/report/__init__.py 1970-01-01 00:00:00 +0000
435+++ account_credit_control_legal_claim/report/__init__.py 2014-05-27 07:08:15 +0000
436@@ -0,0 +1,21 @@
437+# -*- coding: utf-8 -*-
438+##############################################################################
439+#
440+# Author: Nicolas Bessi
441+# Copyright 2014 Camptocamp SA
442+#
443+# This program is free software: you can redistribute it and/or modify
444+# it under the terms of the GNU Affero General Public License as
445+# published by the Free Software Foundation, either version 3 of the
446+# License, or (at your option) any later version.
447+#
448+# This program is distributed in the hope that it will be useful,
449+# but WITHOUT ANY WARRANTY; without even the implied warranty of
450+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
451+# GNU Affero General Public License for more details.
452+#
453+# You should have received a copy of the GNU Affero General Public License
454+# along with this program. If not, see <http://www.gnu.org/licenses/>.
455+#
456+##############################################################################
457+from . import claim_requisition_report
458
459=== added file 'account_credit_control_legal_claim/report/claim_requisition_report.py'
460--- account_credit_control_legal_claim/report/claim_requisition_report.py 1970-01-01 00:00:00 +0000
461+++ account_credit_control_legal_claim/report/claim_requisition_report.py 2014-05-27 07:08:15 +0000
462@@ -0,0 +1,80 @@
463+ # -*- coding: utf-8 -*-
464+##############################################################################
465+#
466+# Author: Nicolas Bessi
467+# Copyright 2014 Camptocamp SA
468+#
469+# This program is free software: you can redistribute it and/or modify
470+# it under the terms of the GNU Affero General Public License as
471+# published by the Free Software Foundation, either version 3 of the
472+# License, or (at your option) any later version.
473+#
474+# This program is distributed in the hope that it will be useful,
475+# but WITHOUT ANY WARRANTY; without even the implied warranty of
476+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
477+# GNU Affero General Public License for more details.
478+#
479+# You should have received a copy of the GNU Affero General Public License
480+# along with this program. If not, see <http://www.gnu.org/licenses/>.
481+#
482+##############################################################################
483+import time
484+import operator
485+from itertools import groupby
486+from itertools import chain
487+from openerp.report import report_sxw
488+from openerp.osv import fields
489+
490+class CreditClaimRequisition(report_sxw.rml_parse):
491+ def __init__(self, cr, uid, name, context):
492+ super(CreditClaimRequisition, self).__init__(cr, uid, name,
493+ context=context)
494+ self.localcontext.update({
495+ 'time': time,
496+ 'cr': cr,
497+ 'uid': uid,
498+ 'today': fields.date.today(),
499+ 'compute_dunning_fees': self.compute_dunning_fees,
500+ 'compute_due_amount': self.compute_due_amount,
501+ 'get_legal_claim_fees': self.get_legal_claim_fees,
502+ 'compute_paid_amount': self.compute_paid_amount,
503+ })
504+
505+ def _active_line(self, cr, uid, line, context=None):
506+ return (line.state not in ('draft', 'ignored') and
507+ not line.manually_overridden)
508+
509+ def compute_dunning_fees(self, invoices):
510+ lines = chain.from_iterable([x.credit_control_line_ids for x in invoices])
511+ return sum(x.dunning_fees_amount for x in lines
512+ if self._active_line(self.cr, self. uid, x))
513+
514+ def get_legal_claim_fees(self, part, invoices):
515+ scheme = part.claim_office_id.fees_scheme_id
516+ return scheme.get_fees_from_invoices([x.id for x in invoices])
517+
518+ def compute_due_amount(self, invoices):
519+ return sum(x.residual for x in invoices)
520+
521+ def compute_paid_amount(self, invoices):
522+ return sum(x.amount_total - x.residual for x in invoices)
523+
524+ def set_context(self, objects, data, ids, report_type=None):
525+ """Group invoice by partner and currency and replace objects
526+ with partner
527+
528+ """
529+ new_objects = []
530+ for key, invoices in groupby(objects, lambda x: (x.partner_id, x.currency_id)):
531+ part = key[0]
532+ part.claim_invoices = list(invoices)
533+ part.claim_currency = key[1]
534+ new_objects.append(part)
535+ return super(CreditClaimRequisition, self).set_context(
536+ new_objects, data, id, report_type=report_type
537+ )
538+
539+report_sxw.report_sxw('report.credit_control_legal_claim_requisition',
540+ 'credit.control.communication',
541+ 'addons/account_credit_control_legal_claim/report/credit_control_legal_claim.html.mako',
542+ parser=CreditClaimRequisition)
543
544=== added file 'account_credit_control_legal_claim/report/credit_control_legal_claim.html.mako'
545--- account_credit_control_legal_claim/report/credit_control_legal_claim.html.mako 1970-01-01 00:00:00 +0000
546+++ account_credit_control_legal_claim/report/credit_control_legal_claim.html.mako 2014-05-27 07:08:15 +0000
547@@ -0,0 +1,259 @@
548+## -*- coding: utf-8 -*-
549+<html>
550+ <head>
551+ <style type="text/css">
552+ ${css}
553+body {
554+
555+ font-family: helvetica;
556+ font-size: 12px;
557+}
558+
559+.left_form_no{
560+ font-family: helvetica;
561+ font-size: 12px;
562+ text-align: left;
563+ border-bottom-style:solid;
564+ border-width:1px;
565+ width:30%;
566+}
567+
568+.right_form_no{
569+ font-family: helvetica;
570+ font-size: 12px;
571+ text-align: left;
572+ border-bottom-style:solid;
573+ border-width:1px;
574+ width:30%;
575+}
576+.custom_text {
577+ font-family: helvetica;
578+ font-size: 12px;
579+}
580+
581+.receive_date{
582+ font-family: helvetica;
583+ font-size: 12px;
584+ text-align: left;
585+ font-weight: bold;
586+}
587+
588+
589+.claim_office_address{
590+ font-family: helvetica;
591+ font-size: 12px;
592+ text-align: left;
593+ vertical-align:text-bottom;
594+}
595+
596+.stake_holder_table td{
597+ border-width:1px;
598+ border-bottom-style:solid;
599+ border-top-style:solid;
600+}
601+
602+.stake_holder_table{
603+ font-family: helvetica;
604+ font-size: 12px;
605+ border-collapse:collapse;
606+ width: 100%;
607+}
608+
609+.stake_holder_name{
610+ vertical-align:text-top;
611+ font-weight: bold;
612+ text-decoration:underline;
613+ width:30%;
614+}
615+
616+.stake_holder_reference{
617+ vertical-align:text-top;
618+ width:30%;
619+}
620+
621+.claim_reasons{
622+ font-family: helvetica;
623+ font-size: 12px;
624+ font-weight:bold;
625+
626+}
627+
628+.claim_table{
629+ font-family: helvetica;
630+ font-size: 12px;
631+ border-collapse:collapse;
632+ width:55%
633+}
634+
635+.summary_table{
636+ font-family: helvetica;
637+ font-size: 12px;
638+ border-collapse:collapse;
639+ width:55%
640+}
641+
642+.paid_amount_summary_table{
643+ font-family: helvetica;
644+ font-size: 12px;
645+ font-weight:bold;
646+ border-collapse:collapse;
647+}
648+
649+td.amount, th.amount {
650+ text-align: right;
651+ padding-right:2px;
652+}
653+
654+.signature{
655+ font-family: helvetica;
656+ font-size: 12px;
657+ border-collapse:collapse;
658+}
659+
660+.date_and_place{
661+ vertical-align:text-top;
662+ width:30%;
663+}
664+
665+.signature_address{
666+ vertical-align:text-top;
667+ width:30%;
668+}
669+
670+.title{
671+ text-align.center;
672+}
673+
674+ </style>
675+ </head>
676+ <body>
677+
678+ %for part in objects :
679+ <% setLang(part.lang) %>
680+ <br/>
681+ <h3 class="title" align="center">${_('Legal Claim Requisition')}</h3>
682+ <table width="100%">
683+ <tr>
684+ <td class="left_form_no">${_('From. No')}</td>
685+ <td></td>
686+ <td class="right_form_no">${_('Claim No')}</td>
687+ </tr>
688+ <tr height="50px">
689+ <td class="receive_date">${_('Claim receive by office, the:......')}</td>
690+ <td colspan="2"></td>
691+ <td></td>
692+ </tr>
693+ <tr>
694+ <td></td>
695+ <td></td>
696+ <td class="claim_office_address">${part.claim_office_id.partner_id.display_name}<br/>
697+ <% address_lines = part.claim_office_id.partner_id.contact_address.split("\n") %>
698+ %for add_part in address_lines:
699+ % if add_part:
700+ ${add_part}<br/>
701+ % endif
702+ %endfor
703+ </td>
704+ </tr>
705+ </table>
706+ <br/>
707+ <br/>
708+ <br/>
709+ <div class="state_style">${_('State:')} ${part.claim_office_id.partner_id.state_id.name}</div>
710+ <table class="stake_holder_table">
711+ <%
712+ debtor = part
713+ creditor = company.partner_id
714+ %>
715+ <tr class="stake_holder_line">
716+ <td class="stake_holder_name">${_('Debtor:')}</td>
717+ <td class="stake_holder_address">${part.display_name}<br/>
718+ <% address_lines = part.contact_address.split("\n") %>
719+ %for add_part in address_lines:
720+ % if add_part:
721+ ${add_part}<br/>
722+ % endif
723+ %endfor
724+
725+ </td>
726+ <td class="stake_holder_reference">${part.ref or _('N/A')}
727+ <br/>
728+ <br/>
729+ birthdate ${formatLang(part.birthday_date, date=True) or _('N/A')}
730+ </td>
731+ </tr>
732+ <tr class="stake_holder_line">
733+ <td class="stake_holder_name">${_('Creditor:')}</td>
734+ <td class="stake_holder_address">${creditor.display_name} <br/>
735+ <% address_lines = creditor.contact_address.split("\n") %>
736+ %for add_part in address_lines:
737+ % if add_part:
738+ ${add_part}<br/>
739+ % endif
740+ %endfor
741+ </td>
742+ <td class="stake_holder_reference">${creditor.phone or ''} </td>
743+ </tr>
744+ </table>
745+ <br/>
746+ <br/>
747+ <div class="claim_reasons">${_('Claim Reasons')}</div>
748+ <div>
749+
750+ <table class="claim_table">
751+ </tr>
752+%for inv in part.claim_invoices:
753+ <tr>
754+ <td class="date">${_('Invoice')} ${inv.number} of ${formatLang(inv.date_invoice, date=True)}, due at ${formatLang(inv.date_due, date=True)}</td>
755+ <td>${_('Due amount')}</td>
756+ <td class="amount">${formatLang(inv.residual)} ${part.claim_currency.name}</td>
757+ </tr>
758+%endfor
759+ </table>
760+ <br/>
761+ <br/>
762+ <table class="summary_table">
763+ <tr>
764+ <td>${_('Amount due')}</td>
765+ <td>${formatLang(compute_due_amount(part.claim_invoices))} ${part.claim_currency.name}</td>
766+ <td></td>
767+ </tr>
768+ <tr>
769+ <td>${_('Dunning Fees')}</td>
770+ <td>${formatLang(compute_dunning_fees(part.claim_invoices))} ${part.claim_currency.name}</td>
771+ <td></td>
772+ </tr>
773+ <tr>
774+ <td>${_('Legal Claim Fees')}</td>
775+ <td>${formatLang(get_legal_claim_fees(part, part.claim_invoices))} ${part.claim_currency.name}</td>
776+ <td></td>
777+ </tr>
778+ </table>
779+ <table class="paid_amount_summary_table">
780+ <tr>
781+ <td height="50px">${_('Debtor already paid amount')} ${formatLang(compute_paid_amount(part.claim_invoices))} ${part.claim_currency.name}</td>
782+ </tr>
783+ </table>
784+ <br/>
785+ <br/>
786+ <table class="signature">
787+ <tr>
788+ <td class="date_and_place"><b>${_('Date and place')}</b> <br/><br/><br/>
789+ ${creditor.city or ''}, ${formatLang(today, date=True)}
790+ </td>
791+ <td></td>
792+ <td class="signature_address">${creditor.display_name} <br/>
793+ <% address_lines = creditor.contact_address.split("\n") %>
794+ %for add_part in address_lines:
795+ % if add_part:
796+ ${add_part}<br/>
797+ % endif
798+ %endfor
799+ </td>
800+ </tr>
801+ </table>
802+ <p style="page-break-after:always"></p>
803+ %endfor
804+
805+ </body>
806+</html>
807
808=== added file 'account_credit_control_legal_claim/report/report.xml'
809--- account_credit_control_legal_claim/report/report.xml 1970-01-01 00:00:00 +0000
810+++ account_credit_control_legal_claim/report/report.xml 2014-05-27 07:08:15 +0000
811@@ -0,0 +1,18 @@
812+<openerp>
813+ <data>
814+ <report auto="False"
815+ id="legal_claim_report_webkit"
816+ model="account.invoice"
817+ name="credit_control_legal_claim_requisition"
818+ file="account_credit_control_legal_claim/report/credit_control_legal_claim.html.mako"
819+ string="Credit Summary Claim"
820+ report_type="webkit"
821+ webkit_header="base_headers_webkit.base_minimum_reports_portrait_header"/>
822+
823+ <record model="ir.actions.report.xml" id="legal_claim_report_webkit">
824+ <field name="precise_mode" eval="True"/>
825+ <field name="header" eval="False"/>
826+ </record>
827+
828+ </data>
829+</openerp>
830
831=== added directory 'account_credit_control_legal_claim/security'
832=== added directory 'account_credit_control_legal_claim/tests'
833=== added file 'account_credit_control_legal_claim/tests/__init__.py'
834--- account_credit_control_legal_claim/tests/__init__.py 1970-01-01 00:00:00 +0000
835+++ account_credit_control_legal_claim/tests/__init__.py 2014-05-27 07:08:15 +0000
836@@ -0,0 +1,23 @@
837+# -*- coding: utf-8 -*-
838+##############################################################################
839+#
840+# Author: Nicolas Bessi
841+# Copyright 2014 Camptocamp SA
842+#
843+# This program is free software: you can redistribute it and/or modify
844+# it under the terms of the GNU Affero General Public License as
845+# published by the Free Software Foundation, either version 3 of the
846+# License, or (at your option) any later version.
847+#
848+# This program is distributed in the hope that it will be useful,
849+# but WITHOUT ANY WARRANTY; without even the implied warranty of
850+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
851+# GNU Affero General Public License for more details.
852+#
853+# You should have received a copy of the GNU Affero General Public License
854+# along with this program. If not, see <http://www.gnu.org/licenses/>.
855+#
856+##############################################################################
857+from . import test_claim_requisiton_print
858+
859+checks = [test_claim_requisiton_print]
860
861=== added file 'account_credit_control_legal_claim/tests/test_claim_requisiton_print.py'
862--- account_credit_control_legal_claim/tests/test_claim_requisiton_print.py 1970-01-01 00:00:00 +0000
863+++ account_credit_control_legal_claim/tests/test_claim_requisiton_print.py 2014-05-27 07:08:15 +0000
864@@ -0,0 +1,177 @@
865+# -*- coding: utf-8 -*-
866+##############################################################################
867+#
868+# Author: Nicolas Bessi
869+# Copyright 2014 Camptocamp SA
870+#
871+# This program is free software: you can redistribute it and/or modify
872+# it under the terms of the GNU Affero General Public License as
873+# published by the Free Software Foundation, either version 3 of the
874+# License, or (at your option) any later version.
875+#
876+# This program is distributed in the hope that it will be useful,
877+# but WITHOUT ANY WARRANTY; without even the implied warranty of
878+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
879+# GNU Affero General Public License for more details.
880+#
881+# You should have received a copy of the GNU Affero General Public License
882+# along with this program. If not, see <http://www.gnu.org/licenses/>.
883+#
884+##############################################################################
885+from mock import MagicMock, patch
886+import openerp.tests.common as test_common
887+
888+
889+class ClaimRequisitionTester(test_common.TransactionCase):
890+
891+ def setUp(self):
892+ """Initialaize credit control level mock to test fees computations"""
893+ super(ClaimRequisitionTester, self).setUp()
894+ self.currency_model = self.registry('res.currency')
895+ self.euro = self.currency_model.search(self.cr, self.uid,
896+ [('name', '=', 'EUR')])
897+ self.assertTrue(self.euro)
898+ self.euro = self.registry('res.currency').browse(self.cr,
899+ self.uid,
900+ self.euro[0])
901+
902+ self.euro_level = MagicMock(name='Euro policy level')
903+ self.euro_level.dunning_fixed_amount = 5.0
904+ self.euro_level.dunning_currency_id = self.euro
905+ self.euro_level.dunning_type = 'fixed'
906+ self.euro_level.is_legal_claim = True
907+
908+ self.euro_level_no_claim = MagicMock(name='Euro policy level no claim')
909+ self.euro_level_no_claim.dunning_fixed_amount = 5.0
910+ self.euro_level_no_claim.dunning_currency_id = self.euro
911+ self.euro_level_no_claim.dunning_type = 'fixed'
912+ self.euro_level_no_claim.is_legal_claim = False
913+
914+ credit_line = MagicMock(name='Euro credit line')
915+ credit_line.policy_level_id = self.euro_level
916+ credit_line.currency_id = self.euro
917+ credit_line.dunning_fees_amount = 10
918+
919+ no_claim_credit_line = MagicMock(name='No claim credit line')
920+ no_claim_credit_line.policy_level_id = self.euro_level_no_claim
921+ no_claim_credit_line.currency_id = self.euro
922+ no_claim_credit_line.dunning_fees_amount = 33
923+ self.credit_line = credit_line
924+ self.no_claim_credit_line = no_claim_credit_line
925+
926+ self.claim_invoice_1 = MagicMock(name='Claim Invoice 1')
927+ self.claim_invoice_1.partner_id = self.browse_ref("base.res_partner_12")
928+ self.claim_invoice_1.currency_id = self.euro
929+ self.claim_invoice_1.residual = 50.00
930+ self.claim_invoice_1.amount_total = 130.00
931+ self.claim_invoice_1.credit_control_line_ids = [credit_line,
932+ credit_line]
933+
934+ self.claim_invoice_2 = MagicMock(name='Claim Invoice 1')
935+ self.claim_invoice_2.partner_id = self.browse_ref("base.res_partner_12")
936+ self.claim_invoice_2.currency_id = self.euro
937+ self.claim_invoice_2.residual = 50.00
938+ self.claim_invoice_2.amount_total = 130.00
939+ self.claim_invoice_2.credit_control_line_ids = [credit_line,
940+ credit_line]
941+
942+ self.non_claim_invoice_1 = MagicMock(name='Non Claim Invoice 1')
943+ self.non_claim_invoice_1.partner_id = self.browse_ref("base.res_partner_12")
944+ self.non_claim_invoice_1.currency_id = self.euro
945+ self.non_claim_invoice_1.residual = 50.00
946+ self.non_claim_invoice_1.amount_total = 130.00
947+ self.non_claim_invoice_1.credit_control_line_ids = [no_claim_credit_line,
948+ no_claim_credit_line]
949+
950+ scheme_id = self.registry('legal.claim.fees.scheme').create(
951+ self.cr,
952+ self.uid,
953+ {
954+ 'name': 'r1',
955+ 'product_id': self.browse_ref('product.product_product_3').id,
956+ 'currency_id': self.euro.id,
957+ }
958+ )
959+
960+ self.registry('legal.claim.fees.scheme.line').create(
961+ self.cr,
962+ self.uid,
963+ {
964+ 'claim_scheme_id': scheme_id,
965+ 'open_amount': 0,
966+ 'fees': 30
967+ }
968+ )
969+
970+ self.registry('legal.claim.fees.scheme.line').create(
971+ self.cr,
972+ self.uid,
973+ {
974+ 'claim_scheme_id': scheme_id,
975+ 'open_amount': 500,
976+ 'fees': 70,
977+ }
978+ )
979+
980+ claim_office_id = self.registry('legal.claim.office').create(
981+ self.cr,
982+ self.uid,
983+ {
984+ 'name': 'Lausanne',
985+ 'partner_id': self.browse_ref('base.res_partner_13').id,
986+ 'fees_scheme_id': scheme_id,
987+ }
988+ )
989+
990+ self.registry('res.better.zip').create(
991+ self.cr,
992+ self.uid,
993+ {
994+ 'name': '1001',
995+ 'city': 'lausanne',
996+ 'claim_office_id': claim_office_id,
997+ }
998+ )
999+
1000+ self.claim_office = self.registry('legal.claim.office').browse(
1001+ self.cr,
1002+ self.uid,
1003+ claim_office_id,
1004+ )
1005+
1006+ def test_00_filter(self):
1007+ """Test filter invoices"""
1008+ wiz_model = self.registry('credit.control.legal.claim.printer')
1009+ res = wiz_model._filter_claim_invoices(self.cr, self.uid,
1010+ [self.claim_invoice_1,
1011+ self.claim_invoice_2,
1012+ self.non_claim_invoice_1])
1013+ self.assertEqual(res, [self.claim_invoice_1,
1014+ self.claim_invoice_2])
1015+
1016+ def test_01_mark(self):
1017+ self.claim_invoice_1.credit_control_line_ids.append(self.no_claim_credit_line)
1018+ wiz_model = self.registry('credit.control.legal.claim.printer')
1019+ target = 'openerp.osv.orm.BaseModel.write'
1020+ with patch(target, MagicMock()):
1021+ res = wiz_model._mark_invoice_as_claimed(self.cr,
1022+ self.uid,
1023+ self.claim_invoice_1)
1024+ self.assertEqual(res, [self.no_claim_credit_line])
1025+
1026+ def test_02_get_fees(self):
1027+ scheme = self.claim_office.fees_scheme_id
1028+ fees = scheme.get_fees_from_amount(50.00)
1029+ self.assertEqual(fees, 30)
1030+ fees = scheme.get_fees_from_amount(550.00)
1031+ self.assertEqual(fees, 70)
1032+
1033+ def test_03_get_fees_from_invoices(self):
1034+ scheme = self.claim_office.fees_scheme_id
1035+ fees = scheme._get_fees_from_invoices([self.claim_invoice_1,
1036+ self.claim_invoice_1])
1037+ self.assertEqual(fees, 30)
1038+ self.claim_invoice_1.residual = 800
1039+ scheme = self.claim_office.fees_scheme_id
1040+ fees = scheme._get_fees_from_invoices([self.claim_invoice_1,
1041+ self.claim_invoice_1])
1042
1043=== added directory 'account_credit_control_legal_claim/view'
1044=== added file 'account_credit_control_legal_claim/view/claim_office_view.xml'
1045--- account_credit_control_legal_claim/view/claim_office_view.xml 1970-01-01 00:00:00 +0000
1046+++ account_credit_control_legal_claim/view/claim_office_view.xml 2014-05-27 07:08:15 +0000
1047@@ -0,0 +1,69 @@
1048+<?xml version="1.0" encoding="utf-8"?>
1049+<openerp>
1050+ <data>
1051+
1052+ <record id="claim_office_list_view" model="ir.ui.view">
1053+ <field name="name">claim office list view</field>
1054+ <field name="model">legal.claim.office</field>
1055+ <field name="arch" type="xml">
1056+ <tree version="7.0" string="Claim office">
1057+ <field name="name"/>
1058+ </tree>
1059+ </field>
1060+ </record>
1061+
1062+ <record id="claim_office_form_view" model="ir.ui.view">
1063+ <field name="name">claim office form view</field>
1064+ <field name="model">legal.claim.office</field>
1065+ <field name="arch" type="xml">
1066+ <form version="7.0" string="Claim office">
1067+ <header>
1068+ <button
1069+ type="action"
1070+ name="%(base_location.action_zip_tree)d"
1071+ string="Related Locations"/>
1072+ </header>
1073+ <group>
1074+ <field name="name"/>
1075+ <field name="partner_id"/>
1076+ <field name="fees_scheme_id"/>
1077+ </group>
1078+ </form>
1079+ </field>
1080+ </record>
1081+
1082+
1083+ <record model="ir.actions.act_window" id="claim_office_action">
1084+ <field name="name">Claim Office</field>
1085+ <field name="type">ir.actions.act_window</field>
1086+ <field name="res_model">legal.claim.office</field>
1087+ <field name="domain"></field>
1088+ <field name="view_type">form</field>
1089+ <field name="view_mode">tree,form</field>
1090+ <field name="view_id" ref="claim_office_list_view"/>
1091+ </record>
1092+
1093+ <menuitem
1094+ name="Credit control Legal Claim"
1095+ parent="account.menu_finance_configuration"
1096+ id="root_legal_claim_menu"/>
1097+
1098+ <menuitem
1099+ name="Claim Office"
1100+ parent="root_legal_claim_menu"
1101+ action="claim_office_action"
1102+ id="claim_office_action_menu"/>
1103+
1104+ <record id="add_office_to_location" model="ir.ui.view">
1105+ <field name="name">add office to location</field>
1106+ <field name="model">res.better.zip</field>
1107+ <field name="inherit_id" ref="base_location.better_zip_form" />
1108+ <field name="arch" type="xml">
1109+ <field name="country_id" position="after">
1110+ <field name="claim_office_id"/>
1111+ </field>
1112+ </field>
1113+ </record>
1114+
1115+ </data>
1116+</openerp>
1117
1118=== added file 'account_credit_control_legal_claim/view/claim_scheme_view.xml'
1119--- account_credit_control_legal_claim/view/claim_scheme_view.xml 1970-01-01 00:00:00 +0000
1120+++ account_credit_control_legal_claim/view/claim_scheme_view.xml 2014-05-27 07:08:15 +0000
1121@@ -0,0 +1,73 @@
1122+<?xml version="1.0" encoding="utf-8"?>
1123+<openerp>
1124+ <data>
1125+ <record id="claim_scheme_list_view" model="ir.ui.view">
1126+ <field name="name">claime scheme list view</field>
1127+ <field name="model">legal.claim.fees.scheme</field>
1128+ <field name="arch" type="xml">
1129+ <tree version="7.0" string="Claim fees"> <!-- editable="bottom" -->
1130+ <field name="name" />
1131+ <field name="company_id" groups="base.group_multi_company" widget="selection"/>
1132+ <field name="product_id"/>
1133+ </tree>
1134+ </field>
1135+ </record>
1136+
1137+
1138+ <record id="claim_scheme_form_view" model="ir.ui.view">
1139+ <field name="name">Claim Scheme form</field>
1140+ <field name="model">legal.claim.fees.scheme</field>
1141+ <field name="arch" type="xml">
1142+ <form version="7.0" string="Claim Scheme">
1143+ <header>
1144+ </header>
1145+ <sheet>
1146+ <group>
1147+ <group>
1148+ <field name="name"/>
1149+ </group>
1150+ </group>
1151+ <group>
1152+ <group>
1153+ <field name="company_id" groups="base.group_multi_company" widget="selection"/>
1154+ <field name="product_id"/>
1155+ <field name="currency_id"/>
1156+ </group>
1157+ </group>
1158+
1159+ <notebook>
1160+ <page string="Scheme values" colspan="4">
1161+ <field name="claim_scheme_line_ids"
1162+ required="1">
1163+ <tree type="7.0" string="Line" editable="top">
1164+ <field name="open_amount"/>
1165+ <field name="fees"/>
1166+ </tree>
1167+ </field>
1168+ </page>
1169+ </notebook>
1170+ </sheet>
1171+ </form>
1172+ </field>
1173+ </record>
1174+
1175+ <record model="ir.actions.act_window" id="claim_scheme_menu_action">
1176+ <field name="name">Claim office</field>
1177+ <field name="type">ir.actions.act_window</field>
1178+ <field name="res_model">legal.claim.fees.scheme</field>
1179+ <field name="domain"></field>
1180+ <field name="view_type">form</field>
1181+ <field name="view_mode">tree,form</field>
1182+ <field name="view_id" ref="claim_scheme_list_view"/>
1183+ </record>
1184+
1185+
1186+
1187+ <menuitem
1188+ name="Claim scheme"
1189+ parent="root_legal_claim_menu"
1190+ action="claim_scheme_menu_action"
1191+ id="claim_scheme_menu_action_menu"/>
1192+
1193+ </data>
1194+</openerp>
1195
1196=== added file 'account_credit_control_legal_claim/view/credit_control_claim_printer_view.xml'
1197--- account_credit_control_legal_claim/view/credit_control_claim_printer_view.xml 1970-01-01 00:00:00 +0000
1198+++ account_credit_control_legal_claim/view/credit_control_claim_printer_view.xml 2014-05-27 07:08:15 +0000
1199@@ -0,0 +1,65 @@
1200+<openerp>
1201+ <data>
1202+
1203+ <record id="credit_control_claim_printer_view" model="ir.ui.view">
1204+ <field name="name">credit control claim printer view</field>
1205+ <field name="model">credit.control.legal.claim.printer</field>
1206+ <field name="arch" type="xml">
1207+ <form version="7.0"
1208+ string="Claim Printer">
1209+ <separator string="Print claim requisition letter for invoices" colspan="4"/>
1210+ <newline/>
1211+ <group>
1212+ <field name="mark_as_claimed"
1213+ colspan="4"
1214+ attrs="{'invisible': [('state', '=', 'done')]}"/>
1215+ </group>
1216+ <newline/>
1217+ <notebook>
1218+ <page string="Invoices" attrs="{'invisible': [('state', '=', 'done')]}">
1219+ <field name="invoice_ids" colspan="4" nolabel="1"
1220+ attrs="{'invisible': [('state', '=', 'done')]}" />
1221+ </page>
1222+ </notebook>
1223+ <field name="report_name"
1224+ invisible="1"/>
1225+ <field name="report_file"
1226+ colspan="4"
1227+ filename="report_name"
1228+ attrs="{'invisible': [('state', '!=', 'done')]}"/>
1229+ <field name="state" invisible="1" />
1230+ <newline/>
1231+ <footer>
1232+ <button class="oe_highlight" name="print_claims" string="Print" type="object" attrs="{'invisible': [('state', '==', 'done')]}"/>
1233+ <button special="cancel" string="Cancel" icon='gtk-cancel' attrs="{'invisible': [('state', '==', 'done')]}"/>
1234+ <button special="cancel" string="Close" icon='gtk-close' attrs="{'invisible': [('state', '!=', 'done')]}"/>
1235+ </footer>
1236+
1237+
1238+ </form>
1239+ </field>
1240+ </record>
1241+
1242+ <!-- for button -->
1243+ <record id="legal_claim_printer_action" model="ir.actions.act_window">
1244+ <field name="name">Print Claim Requisition</field>
1245+ <field name="res_model">credit.control.legal.claim.printer</field>
1246+ <field name="src_model">account.invoice</field>
1247+ <field name="view_type">form</field>
1248+ <field name="view_mode">form</field>
1249+ <field name="view_id" ref="credit_control_claim_printer_view"/>
1250+ <field name="target">new</field>
1251+ <field name="help"></field>
1252+ </record>
1253+
1254+ <!-- for menu -->
1255+ <act_window name="Print Claim Requisition"
1256+ res_model="credit.control.legal.claim.printer"
1257+ src_model="account.invoice"
1258+ view_mode="form"
1259+ target="new"
1260+ key2="client_action_multi"
1261+ id="legal_claim_printer_action_menu_action"/>
1262+
1263+ </data>
1264+</openerp>
1265
1266=== added file 'account_credit_control_legal_claim/view/policy_view.xml'
1267--- account_credit_control_legal_claim/view/policy_view.xml 1970-01-01 00:00:00 +0000
1268+++ account_credit_control_legal_claim/view/policy_view.xml 2014-05-27 07:08:15 +0000
1269@@ -0,0 +1,24 @@
1270+<?xml version="1.0" encoding="utf-8"?>
1271+<openerp>
1272+ <data>
1273+ <record id="add_claim_on_policy_level" model="ir.ui.view">
1274+ <field name="name">add claim on policy level</field>
1275+ <field name="model">credit.control.policy</field>
1276+ <field name="inherit_id"
1277+ ref="account_credit_control.credit_control_policy_form"/>
1278+ <field name="arch" type="xml">
1279+ <page string="Mail and reporting" position="after">
1280+ <page string="Legal Claim">
1281+ <group>
1282+ <group>
1283+ <field name="is_legal_claim"/>
1284+ </group>
1285+ </group>
1286+ </page>
1287+ </page>
1288+
1289+ </field>
1290+ </record>
1291+
1292+ </data>
1293+</openerp>
1294
1295=== added directory 'account_credit_control_legal_claim/wizard'
1296=== added file 'account_credit_control_legal_claim/wizard/__init__.py'
1297--- account_credit_control_legal_claim/wizard/__init__.py 1970-01-01 00:00:00 +0000
1298+++ account_credit_control_legal_claim/wizard/__init__.py 2014-05-27 07:08:15 +0000
1299@@ -0,0 +1,21 @@
1300+# -*- coding: utf-8 -*-
1301+##############################################################################
1302+#
1303+# Author: Nicolas Bessi
1304+# Copyright 2014 Camptocamp SA
1305+#
1306+# This program is free software: you can redistribute it and/or modify
1307+# it under the terms of the GNU Affero General Public License as
1308+# published by the Free Software Foundation, either version 3 of the
1309+# License, or (at your option) any later version.
1310+#
1311+# This program is distributed in the hope that it will be useful,
1312+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1314+# GNU Affero General Public License for more details.
1315+#
1316+# You should have received a copy of the GNU Affero General Public License
1317+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1318+#
1319+##############################################################################
1320+from . import credit_control_claim_printer
1321
1322=== added file 'account_credit_control_legal_claim/wizard/credit_control_claim_printer.py'
1323--- account_credit_control_legal_claim/wizard/credit_control_claim_printer.py 1970-01-01 00:00:00 +0000
1324+++ account_credit_control_legal_claim/wizard/credit_control_claim_printer.py 2014-05-27 07:08:15 +0000
1325@@ -0,0 +1,154 @@
1326+# -*- coding: utf-8 -*-
1327+##############################################################################
1328+#
1329+# Author: Nicolas Bessi
1330+# Copyright 2014 Camptocamp SA
1331+#
1332+# This program is free software: you can redistribute it and/or modify
1333+# it under the terms of the GNU Affero General Public License as
1334+# published by the Free Software Foundation, either version 3 of the
1335+# License, or (at your option) any later version.
1336+#
1337+# This program is distributed in the hope that it will be useful,
1338+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1339+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1340+# GNU Affero General Public License for more details.
1341+#
1342+# You should have received a copy of the GNU Affero General Public License
1343+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1344+#
1345+##############################################################################
1346+import base64
1347+import netsvc
1348+from openerp.osv import orm, fields
1349+
1350+
1351+class credit_control_legal_printer(orm.TransientModel):
1352+ """Print claim requisition letter
1353+
1354+ And manage related credit lines
1355+
1356+ """
1357+
1358+ def _filter_claim_invoices(self, cr, uid, invoices, context=None):
1359+ """ Return invoices that are related to a claim
1360+ concretly that means the invoice must be related
1361+ to active credit line related to a claim policy level
1362+
1363+ :param invoices: list on invoices record to be filtered
1364+
1365+ """
1366+
1367+ filtered = []
1368+ for inv in invoices:
1369+ if any(x for x in inv.credit_control_line_ids
1370+ if x.policy_level_id.is_legal_claim):
1371+ filtered.append(inv)
1372+ return filtered
1373+
1374+ def _get_invoice_ids(self, cr, uid, context=None):
1375+ """Return invoices ids to be treated form context
1376+ A candidate invoice is related to a claim
1377+
1378+ """
1379+ inv_model = self.pool['account.invoice']
1380+ if context is None:
1381+ context = {}
1382+ res = False
1383+ if context.get('active_model') != 'account.invoice':
1384+ return res
1385+ res = context.get('active_ids', False)
1386+ if res:
1387+ invoices = inv_model.browse(cr, uid, res, context=context)
1388+ filtered = self._filter_claim_invoices(cr, uid, invoices,
1389+ context=context)
1390+ res = [x.id for x in filtered]
1391+ return res
1392+
1393+ _name = "credit.control.legal.claim.printer"
1394+ _rec_name = 'id'
1395+ _columns = {
1396+ 'mark_as_claimed': fields.boolean('Mark as Claimed'),
1397+ 'report_file': fields.binary('Report File',
1398+ readonly=True),
1399+ 'report_name': fields.char('Report Name'),
1400+ 'invoice_ids': fields.many2many('account.invoice',
1401+ string='Invoices'),
1402+ 'state': fields.selection([('draft', 'Draft'),
1403+ ('done', 'Done')]),
1404+ }
1405+
1406+ _defaults = {
1407+ 'invoice_ids': _get_invoice_ids,
1408+ 'mark_as_claimed': True,
1409+ }
1410+
1411+ def _generate_report(self, cr, uid, invoice_ids, context=None):
1412+ """Generate claim requisition report.
1413+
1414+ :param invoice_ids: list of invoice ids to print
1415+
1416+ :returns: report file
1417+
1418+ """
1419+ service = netsvc.LocalService('report.credit_control_legal_claim_requisition')
1420+ result, format = service.create(cr, uid, invoice_ids, {}, {})
1421+ return result
1422+
1423+ def _mark_invoice_as_claimed(self, cr, uid, invoice, context=None):
1424+ """Mark related credit line of an invoice as overridden.
1425+
1426+ Only non claim credit line will be marked
1427+
1428+ :param invoice: invoice recorrd to treat
1429+
1430+ :returns: marked credit lines
1431+ """
1432+ lines = [x for x in invoice.credit_control_line_ids
1433+ if not x.policy_level_id.is_legal_claim]
1434+ credit_line_model = self.pool['credit.control.line']
1435+ data = {'manually_overridden': True}
1436+ credit_line_model.write(cr, uid,
1437+ [x.id for x in lines],
1438+ data,
1439+ context=context)
1440+ return lines
1441+
1442+ def print_claims(self, cr, uid, wiz_id, context=None):
1443+ """Generate claim requisition report and manage credit lines.
1444+
1445+ Non claim credit lines will be overridden
1446+
1447+ :param invoice_ids: list of invoice ids to print
1448+
1449+ :returns: an ir.action to himself
1450+
1451+ """
1452+ if isinstance(wiz_id, list):
1453+ assert len(wiz_id) == 1
1454+ wiz_id = wiz_id[0]
1455+
1456+ current = self.browse(cr, uid, wiz_id, context=context)
1457+ invs = self._filter_claim_invoices(cr, uid, current.invoice_ids,
1458+ context=context)
1459+ invoice_ids = [x.id for x in invs]
1460+ assert invoice_ids
1461+ report_file = self._generate_report(cr, uid, invoice_ids,
1462+ context=context)
1463+ current.write(
1464+ {'report_file': base64.b64encode(report_file),
1465+ 'report_name': 'claim_letters_%s.pdf' % fields.datetime.now(),
1466+ 'state': 'done'}
1467+ )
1468+ if current.mark_as_claimed:
1469+ for inv in invs:
1470+ self._mark_invoice_as_claimed(cr, uid, inv, context=context)
1471+
1472+ return {'type': 'ir.actions.act_window',
1473+ 'res_model': 'credit.control.legal.claim.printer',
1474+ 'view_mode': 'form',
1475+ 'view_type': 'form',
1476+ 'res_id': current.id,
1477+ 'views': [(False, 'form')],
1478+ 'target': 'new',
1479+ }

Subscribers

People subscribed via source and target branches

to all changes: