Merge lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m into lp:c2c-financial-addons
- c2c-financial-addons-fix-rule-m2m
- Merge into trunk
Proposed by
Sébastien BEAU - http://www.akretion.com
Status: | Superseded |
---|---|
Proposed branch: | lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m |
Merge into: | lp:c2c-financial-addons |
Diff against target: |
3107 lines (+2882/-2) 41 files modified
account_credit_management/__init__.py (+28/-0) account_credit_management/__openerp__.py (+47/-0) account_credit_management/credit_management_account.py (+220/-0) account_credit_management/credit_management_account_view.xml (+41/-0) account_credit_management/credit_management_company.py (+28/-0) account_credit_management/credit_management_company_view.xml (+15/-0) account_credit_management/credit_management_demo.xml (+33/-0) account_credit_management/credit_management_line.py (+181/-0) account_credit_management/credit_management_line_view.xml (+145/-0) account_credit_management/credit_management_partner.py (+36/-0) account_credit_management/credit_management_partner_view.xml (+25/-0) account_credit_management/credit_management_profile.py (+292/-0) account_credit_management/credit_management_profile_view.xml (+118/-0) account_credit_management/credit_management_run.py (+150/-0) account_credit_management/credit_management_run_view.xml (+65/-0) account_credit_management/data.xml (+173/-0) account_credit_management/report/__init__.py (+1/-0) account_credit_management/report/credit_management_summary.html.mako (+19/-0) account_credit_management/report/credit_management_summary.py (+37/-0) account_credit_management/report/report.xml (+12/-0) account_credit_management/scenarios/credit_management/00_credit_management_param.feature (+23/-0) account_credit_management/scenarios/credit_management/01_credit_management_partners.feature (+60/-0) account_credit_management/scenarios/credit_management/credit_management_01_data.feature (+224/-0) account_credit_management/scenarios/credit_management/credit_management_02_run.feature (+33/-0) account_credit_management/scenarios/credit_management/credit_management_03_run.feature (+26/-0) account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb (+115/-0) account_credit_management/scenarios/run_command.txt (+1/-0) account_credit_management/security/ir.model.access.csv (+27/-0) account_credit_management/wizard/__init__.py (+24/-0) account_credit_management/wizard/credit_management_communication.py (+178/-0) account_credit_management/wizard/credit_management_mailer.py (+64/-0) account_credit_management/wizard/credit_management_mailer_view.xml (+44/-0) account_credit_management/wizard/credit_management_marker.py (+83/-0) account_credit_management/wizard/credit_management_marker_view.xml (+44/-0) account_credit_management/wizard/credit_management_printer.py (+74/-0) account_credit_management/wizard/credit_management_printer_view.xml (+47/-0) account_fiscal_position_rule_m2m/fiscal_rules.py (+2/-2) account_payment_ext/__init__.py (+32/-0) account_payment_ext/__openerp__.py (+50/-0) account_payment_ext/account_payment.py (+47/-0) account_payment_ext/account_payment_view.xml (+18/-0) |
To merge this branch: | bzr merge lp:~sebastien.beau/c2c-financial-addons/c2c-financial-addons-fix-rule-m2m |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guewen Baconnier @ Camptocamp | Approve | ||
Alexandre Fayolle - camptocamp | Needs Fixing | ||
Review via email: mp+129642@code.launchpad.net |
This proposal has been superseded by a proposal from 2012-10-23.
Commit message
Description of the change
FIX a bug
To post a comment you must log in.
Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
review:
Needs Fixing
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : | # |
Hi Sébastien,
I merged your fix (slightly modified) from the revision 90 in our 6.1 branch.
Thanks
Guewen
review:
Approve
Unmerged revisions
- 90. By Sébastien BEAU - http://www.akretion.com
-
[FIX] account_
fiscal_ position_ rule_m2m: fix wizard to generate rule from template - 89. By Vincent Renaville@camptocamp
-
[ADD] account_payment ext
- 88. By Vincent Renaville@camptocamp
-
[MERGE] credit management
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added directory 'account_credit_management' |
2 | === added file 'account_credit_management/__init__.py' |
3 | --- account_credit_management/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ account_credit_management/__init__.py 2012-10-15 10:14:35 +0000 |
5 | @@ -0,0 +1,28 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# Author: Nicolas Bessi |
10 | +# Copyright 2012 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 credit_management_run |
27 | +from . import credit_management_line |
28 | +from . import credit_management_account |
29 | +from . import credit_management_partner |
30 | +from . import credit_management_profile |
31 | +from . import credit_management_company |
32 | +import wizard |
33 | +import report |
34 | |
35 | === added file 'account_credit_management/__openerp__.py' |
36 | --- account_credit_management/__openerp__.py 1970-01-01 00:00:00 +0000 |
37 | +++ account_credit_management/__openerp__.py 2012-10-15 10:14:35 +0000 |
38 | @@ -0,0 +1,47 @@ |
39 | +# -*- coding: utf-8 -*- |
40 | +############################################################################## |
41 | +# |
42 | +# Author: Nicolas Bessi |
43 | +# Copyright 2012 Camptocamp SA |
44 | +# |
45 | +# This program is free software: you can redistribute it and/or modify |
46 | +# it under the terms of the GNU Affero General Public License as |
47 | +# published by the Free Software Foundation, either version 3 of the |
48 | +# License, or (at your option) any later version. |
49 | +# |
50 | +# This program is distributed in the hope that it will be useful, |
51 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
52 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
53 | +# GNU Affero General Public License for more details. |
54 | +# |
55 | +# You should have received a copy of the GNU Affero General Public License |
56 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
57 | +# |
58 | +############################################################################## |
59 | +{'name' : 'Account Credit Management', |
60 | + 'version' : '0.1', |
61 | + 'author' : 'Camptocamp', |
62 | + 'maintainer': 'Camptocamp', |
63 | + 'category': 'Finance', |
64 | + 'complexity': "normal", # easy, normal, expert |
65 | + 'depends' : ['base', 'account', 'email_template', 'report_webkit'], |
66 | + 'description': """Credit control management TODO""", |
67 | + 'website': 'http://www.camptocamp.com', |
68 | + 'init_xml': ["data.xml"], |
69 | + 'update_xml': ["credit_management_line_view.xml", |
70 | + "credit_management_account_view.xml", |
71 | + "credit_management_partner_view.xml", |
72 | + "credit_management_profile_view.xml", |
73 | + "credit_management_run_view.xml", |
74 | + "credit_management_company_view.xml", |
75 | + "wizard/credit_management_mailer_view.xml", |
76 | + "wizard/credit_management_marker_view.xml", |
77 | + "wizard/credit_management_printer_view.xml", |
78 | + "report/report.xml", |
79 | + "security/ir.model.access.csv",], |
80 | + #"credit_management_demo.xml"], |
81 | + 'demo_xml': ["credit_management_demo.xml"], |
82 | + 'tests': [], |
83 | + 'installable': True, |
84 | + 'license': 'AGPL-3', |
85 | + 'application': True} |
86 | |
87 | === added file 'account_credit_management/credit_management_account.py' |
88 | --- account_credit_management/credit_management_account.py 1970-01-01 00:00:00 +0000 |
89 | +++ account_credit_management/credit_management_account.py 2012-10-15 10:14:35 +0000 |
90 | @@ -0,0 +1,220 @@ |
91 | +# -*- coding: utf-8 -*- |
92 | +############################################################################## |
93 | +# |
94 | +# Author: Nicolas Bessi |
95 | +# Copyright 2012 Camptocamp SA |
96 | +# |
97 | +# This program is free software: you can redistribute it and/or modify |
98 | +# it under the terms of the GNU Affero General Public License as |
99 | +# published by the Free Software Foundation, either version 3 of the |
100 | +# License, or (at your option) any later version. |
101 | +# |
102 | +# This program is distributed in the hope that it will be useful, |
103 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
104 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
105 | +# GNU Affero General Public License for more details. |
106 | +# |
107 | +# You should have received a copy of the GNU Affero General Public License |
108 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
109 | +# |
110 | +############################################################################## |
111 | +from datetime import datetime |
112 | +import operator |
113 | +from openerp.osv.orm import Model, fields |
114 | +from openerp.tools.translate import _ |
115 | +from openerp.addons.account_credit_management import credit_management_run |
116 | + |
117 | +class AccountAccount(Model): |
118 | + """Add a link to a credit management profile on account account""" |
119 | + |
120 | + |
121 | + def _check_account_type_compatibility(self, cursor, uid, acc_ids, context=None): |
122 | + """We check that account is of type reconcile""" |
123 | + if not isinstance(acc_ids, list): |
124 | + acc_ids = [acc_ids] |
125 | + for acc in self.browse(cursor, uid, acc_ids, context): |
126 | + if acc.credit_profile_id and not acc.reconcile: |
127 | + return False |
128 | + return True |
129 | + |
130 | + _inherit = "account.account" |
131 | + _description = """Add a link to a credit profile""" |
132 | + _columns = {'credit_profile_id': fields.many2one('credit.management.profile', |
133 | + 'Credit management profile', |
134 | + help=("Define global credit profile" |
135 | + "order is account partner invoice")), |
136 | + |
137 | + 'credit_management_line_ids': fields.one2many('credit.management.line', |
138 | + 'account_id', |
139 | + string='Credit Lines', |
140 | + readonly=True)} |
141 | + |
142 | + _constraints = [(_check_account_type_compatibility, |
143 | + _('You can not set a credit profile on a non reconciliable account'), |
144 | + ['credit_profile_id'])] |
145 | + |
146 | +class AccountInvoice(Model): |
147 | + """Add a link to a credit management profile on account account""" |
148 | + |
149 | + _inherit = "account.invoice" |
150 | + _description = """Add a link to a credit profile""" |
151 | + _columns = {'credit_profile_id': fields.many2one('credit.management.profile', |
152 | + 'Credit management profile', |
153 | + help=("Define global credit profile" |
154 | + "order is account partner invoice")), |
155 | + |
156 | + 'credit_management_line_ids': fields.one2many('credit.management.line', |
157 | + 'account_id', |
158 | + string='Credit Lines', |
159 | + readonly=True)} |
160 | + |
161 | + def action_move_create(self, cursor, uid, ids, context=None): |
162 | + """We ensure writing of invoice id in move line because |
163 | + Trigger field may not work without account_voucher addon""" |
164 | + res = super(AccountInvoice, self).action_move_create(cursor, uid, ids, context=context) |
165 | + for inv in self.browse(cursor, uid, ids, context=context): |
166 | + if inv.move_id: |
167 | + for line in inv.move_id.line_id: |
168 | + line.write({'invoice_id': inv.id}) |
169 | + return res |
170 | + |
171 | + |
172 | +class AccountMoveLine(Model): |
173 | + """Add a function that compute the residual amount using a follow up date |
174 | + Add relation between move line and invoicex""" |
175 | + |
176 | + _inherit = "account.move.line" |
177 | + # Store fields has strange behavior with voucher module we had to overwrite invoice |
178 | + |
179 | + |
180 | + # def _invoice_id(self, cursor, user, ids, name, arg, context=None): |
181 | + # #Code taken from OpenERP account addon |
182 | + # invoice_obj = self.pool.get('account.invoice') |
183 | + # res = {} |
184 | + # for line_id in ids: |
185 | + # res[line_id] = False |
186 | + # cursor.execute('SELECT l.id, i.id ' \ |
187 | + # 'FROM account_move_line l, account_invoice i ' \ |
188 | + # 'WHERE l.move_id = i.move_id ' \ |
189 | + # 'AND l.id IN %s', |
190 | + # (tuple(ids),)) |
191 | + # invoice_ids = [] |
192 | + # for line_id, invoice_id in cursor.fetchall(): |
193 | + # res[line_id] = invoice_id |
194 | + # invoice_ids.append(invoice_id) |
195 | + # invoice_names = {False: ''} |
196 | + # for invoice_id, name in invoice_obj.name_get(cursor, user, invoice_ids, context=context): |
197 | + # invoice_names[invoice_id] = name |
198 | + # for line_id in res.keys(): |
199 | + # invoice_id = res[line_id] |
200 | + # res[line_id] = (invoice_id, invoice_names[invoice_id]) |
201 | + # return res |
202 | + |
203 | + # def _get_invoice(self, cursor, uid, ids, context=None): |
204 | + # result = set() |
205 | + # for line in self.pool.get('account.invoice').browse(cursor, uid, ids, context=context): |
206 | + # if line.move_id: |
207 | + # ids = [x.id for x in line.move_id.line_id or []] |
208 | + # return list(result) |
209 | + |
210 | + # _columns = {'invoice_id': fields.function(_invoice_id, string='Invoice', |
211 | + # type='many2one', relation='account.invoice', |
212 | + # store={'account.invoice': (_get_invoice, ['move_id'], 20)})} |
213 | + |
214 | + _columns = {'invoice_id': fields.many2one('account.invoice', 'Invoice')} |
215 | + |
216 | + def _get_payment_and_credit_lines(self, moveline_array, lookup_date): |
217 | + credit_lines = [] |
218 | + payment_lines = [] |
219 | + for line in moveline_array: |
220 | + if self._should_exlude_line(line): |
221 | + continue |
222 | + if line.account_id.type == 'receivable' and line.debit: |
223 | + credit_lines.append(line) |
224 | + else: |
225 | + if line.reconcile_partial_id: |
226 | + payment_lines.append(line) |
227 | + credit_lines.sort(key=operator.attrgetter('date')) |
228 | + payment_lines.sort(key=operator.attrgetter('date')) |
229 | + return (credit_lines, payment_lines) |
230 | + |
231 | + def _validate_line_currencies(self, credit_lines): |
232 | + """Raise an excpetion if there is lines with different currency""" |
233 | + if len(credit_lines) == 0: |
234 | + return True |
235 | + currency = credit_lines[0].currency_id.id |
236 | + if not all(obj.currency_id.id == currency for obj in credit_lines): |
237 | + raise Exception('Not all line of move line are in the same currency') |
238 | + |
239 | + def _get_value_amount(self, mv_line_br): |
240 | + if mv_line_br.currency_id: |
241 | + return mv_line_br.amount_currency |
242 | + else: |
243 | + return mv_line_br.debit - mv_line_br.credit |
244 | + |
245 | + def _validate_partial(self, credit_lines): |
246 | + if len(credit_lines) == 0: |
247 | + return True |
248 | + else: |
249 | + line_with_partial = 0 |
250 | + for line in credit_lines: |
251 | + if not line.reconcile_partial_id: |
252 | + line_with_partial += 1 |
253 | + if line_with_partial and line_with_partial != len(credit_lines): |
254 | + raise Exception('Can not compute credit line if multiple' |
255 | + ' lines are not all linked to a partial') |
256 | + |
257 | + def _get_applicable_payment_lines(self, credit_line, payment_lines): |
258 | + applicable_payment = [] |
259 | + for pay_line in payment_lines: |
260 | + if datetime.strptime(pay_line.date, "%Y-%m-%d").date() \ |
261 | + <= datetime.strptime(credit_line.date, "%Y-%m-%d").date(): |
262 | + applicable_payment.append(pay_line) |
263 | + return applicable_payment |
264 | + |
265 | + def _compute_partial_reconcile_residual(self, move_lines, lookup_date, move_id, memoizer): |
266 | + """ Compute open amount of multiple credit lines linked to multiple payment lines""" |
267 | + credit_lines, payment_lines = self._get_payment_and_credit_lines(move_lines, lookup_date, memoizer) |
268 | + self._validate_line_currencies(credit_lines) |
269 | + self._validate_line_currencies(payment_lines) |
270 | + self._validate_partial(credit_lines) |
271 | + # memoizer structure move_id : {move_line_id: open_amount} |
272 | + # paymnent line and credit line are sorted by date |
273 | + rest = 0.0 |
274 | + for credit_line in credit_lines: |
275 | + applicable_payment = self._get_applicable_payment_lines(credit_line, payment_lines) |
276 | + paid_amount = 0.0 |
277 | + for pay_line in applicable_payment: |
278 | + paid_amount += self._get_value_amount(pay_line) |
279 | + balance_amount = self._get_value_amount(credit_lines) - (paid_amount + rest) |
280 | + memoizer[move_id][credit_line.id] = balance_amount |
281 | + if balance_amount < 0.0: |
282 | + rest = balance_amount |
283 | + else: |
284 | + rest = 0.0 |
285 | + return memoizer |
286 | + |
287 | + def _compute_fully_open_amount(self, move_lines, lookup_date, move_id, memoizer): |
288 | + for move_line in move_lines: |
289 | + memoizer[move_id][move_line.id] = self._get_value_amount(move_line) |
290 | + return memoizer |
291 | + |
292 | + |
293 | + def _amount_residual_from_date(self, cursor, uid, mv_line_br, lookup_date, context=None): |
294 | + """ |
295 | + Code from function _amount_residual of account/account_move_line.py does not take |
296 | + in account mulitple line payment and reconciliation. We have to rewrite it |
297 | + Code computes residual amount at lookup date for mv_line_br in entry |
298 | + """ |
299 | + memoizer = credit_management_run.memoizers['credit_line_residuals'] |
300 | + move_id = mv_line_br.move_id.id |
301 | + if mv_line_br.move_id.id in memoizer: |
302 | + pass # get back value |
303 | + else: |
304 | + memoizer[move_id] = {} |
305 | + move_lines = mv_line_br.move_id.line_id |
306 | + if mv_line_br.reconcile_partial_id: |
307 | + self._compute_partial_reconcile_residual(move_lines, lookup_date, move_id, memoizer) |
308 | + else: |
309 | + self._compute_fully_open_amount(move_lines, lookup_date, move_id, memoizer) |
310 | + return memoizer[move_id][mv_line_br.id] |
311 | |
312 | === added file 'account_credit_management/credit_management_account_view.xml' |
313 | --- account_credit_management/credit_management_account_view.xml 1970-01-01 00:00:00 +0000 |
314 | +++ account_credit_management/credit_management_account_view.xml 2012-10-15 10:14:35 +0000 |
315 | @@ -0,0 +1,41 @@ |
316 | +<openerp> |
317 | + <data> |
318 | + |
319 | + <record id="account_followup_form_view" model="ir.ui.view"> |
320 | + <field name="name">account.followup.form.view</field> |
321 | + <field name="model">account.account</field> |
322 | + <field name="inherit_id" ref="account.view_account_form" /> |
323 | + <field name="type">form</field> |
324 | + <field name="arch" type="xml"> |
325 | + <field name="reconcile" position="after"> |
326 | + <field name="credit_profile_id" groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user"/> |
327 | + </field> |
328 | + </field> |
329 | + </record> |
330 | + |
331 | + <act_window |
332 | + id="act_account_credit_relation_relation" |
333 | + name="Credit lines" |
334 | + groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user" |
335 | + domain="[('account_id', '=', active_id)]" |
336 | + res_model="credit.management.line" |
337 | + src_model="account.account"/> |
338 | + |
339 | + <record id="invoice_followup_form_view" model="ir.ui.view"> |
340 | + <field name="name">invoice.followup.form.view</field> |
341 | + <field name="model">account.invoice</field> |
342 | + <field name="inherit_id" ref="account.invoice_form" /> |
343 | + <field name="type">form</field> |
344 | + <field name="arch" type="xml"> |
345 | + <notebook position="inside"> |
346 | + <page string="Credit Management" |
347 | + groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user,group_account_credit_management_info"> |
348 | + <field name="credit_profile_id"/> |
349 | + <field name="credit_management_line_ids" colspan="4" nolabel="1"/> |
350 | + </page> |
351 | + </notebook> |
352 | + </field> |
353 | + </record> |
354 | + |
355 | + </data> |
356 | +</openerp> |
357 | |
358 | === added file 'account_credit_management/credit_management_company.py' |
359 | --- account_credit_management/credit_management_company.py 1970-01-01 00:00:00 +0000 |
360 | +++ account_credit_management/credit_management_company.py 2012-10-15 10:14:35 +0000 |
361 | @@ -0,0 +1,28 @@ |
362 | +# -*- coding: utf-8 -*- |
363 | +############################################################################## |
364 | +# |
365 | +# Author: Nicolas Bessi |
366 | +# Copyright 2012 Camptocamp SA |
367 | +# |
368 | +# This program is free software: you can redistribute it and/or modify |
369 | +# it under the terms of the GNU Affero General Public License as |
370 | +# published by the Free Software Foundation, either version 3 of the |
371 | +# License, or (at your option) any later version. |
372 | +# |
373 | +# This program is distributed in the hope that it will be useful, |
374 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
375 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
376 | +# GNU Affero General Public License for more details. |
377 | +# |
378 | +# You should have received a copy of the GNU Affero General Public License |
379 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
380 | +# |
381 | +############################################################################## |
382 | +from openerp.osv.orm import Model, fields |
383 | + |
384 | +class ResCompany(Model): |
385 | + _inherit = "res.company" |
386 | + |
387 | + _columns = {"credit_management_tolerance": fields.float('Credit Tolerance')} |
388 | + |
389 | + _defaults = {"credit_management_tolerance": 0.1} |
390 | |
391 | === added file 'account_credit_management/credit_management_company_view.xml' |
392 | --- account_credit_management/credit_management_company_view.xml 1970-01-01 00:00:00 +0000 |
393 | +++ account_credit_management/credit_management_company_view.xml 2012-10-15 10:14:35 +0000 |
394 | @@ -0,0 +1,15 @@ |
395 | +<openerp> |
396 | + <data> |
397 | + <record id="credit_management_company_form" model="ir.ui.view"> |
398 | + <field name="name">credit.management.company.form</field> |
399 | + <field name="model">res.company</field> |
400 | + <field name="type">form</field> |
401 | + <field name="inherit_id" ref="base.view_company_form"/> |
402 | + <field name="arch" type="xml"> |
403 | + <field name="currency_id" position="after"> |
404 | + <field name="credit_management_tolerance"/> |
405 | + </field> |
406 | + </field> |
407 | + </record> |
408 | + </data> |
409 | +</openerp> |
410 | |
411 | === added file 'account_credit_management/credit_management_demo.xml' |
412 | --- account_credit_management/credit_management_demo.xml 1970-01-01 00:00:00 +0000 |
413 | +++ account_credit_management/credit_management_demo.xml 2012-10-15 10:14:35 +0000 |
414 | @@ -0,0 +1,33 @@ |
415 | +<openerp> |
416 | + <data> |
417 | + <record id="a_recv_1" model="account.account"> |
418 | + <field name="code">X11002-a</field> |
419 | + <field name="name">B2B Debtors - (test)</field> |
420 | + <field ref="account.cas" name="parent_id"/> |
421 | + <field name="type">receivable</field> |
422 | + <field eval="True" name="reconcile"/> |
423 | + <field name="credit_profile_id" ref="credit_management_no_follow"/> |
424 | + <field name="user_type" ref="account.data_account_type_receivable"/> |
425 | + </record> |
426 | + |
427 | + <record id="a_recv_2" model="account.account"> |
428 | + <field name="code">X11002-b</field> |
429 | + <field name="name">B2C Debtors - (test)</field> |
430 | + <field ref="account.cas" name="parent_id"/> |
431 | + <field name="type">receivable</field> |
432 | + <field eval="True" name="reconcile"/> |
433 | + <field name="credit_profile_id" ref="credit_management_2_time"/> |
434 | + <field name="user_type" ref="account.data_account_type_receivable"/> |
435 | + </record> |
436 | + |
437 | + <record id="a_recv_3" model="account.account"> |
438 | + <field name="code">X11002-c</field> |
439 | + <field name="name">New Debtors - (test)</field> |
440 | + <field ref="account.cas" name="parent_id"/> |
441 | + <field name="type">receivable</field> |
442 | + <field eval="True" name="reconcile"/> |
443 | + <field name="credit_profile_id" ref="credit_management_3_time"/> |
444 | + <field name="user_type" ref="account.data_account_type_receivable"/> |
445 | + </record> |
446 | + </data> |
447 | +</openerp> |
448 | |
449 | === added file 'account_credit_management/credit_management_line.py' |
450 | --- account_credit_management/credit_management_line.py 1970-01-01 00:00:00 +0000 |
451 | +++ account_credit_management/credit_management_line.py 2012-10-15 10:14:35 +0000 |
452 | @@ -0,0 +1,181 @@ |
453 | +# -*- coding: utf-8 -*- |
454 | +############################################################################## |
455 | +# |
456 | +# Author: Nicolas Bessi |
457 | +# Copyright 2012 Camptocamp SA |
458 | +# |
459 | +# This program is free software: you can redistribute it and/or modify |
460 | +# it under the terms of the GNU Affero General Public License as |
461 | +# published by the Free Software Foundation, either version 3 of the |
462 | +# License, or (at your option) any later version. |
463 | +# |
464 | +# This program is distributed in the hope that it will be useful, |
465 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
466 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
467 | +# GNU Affero General Public License for more details. |
468 | +# |
469 | +# You should have received a copy of the GNU Affero General Public License |
470 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
471 | +# |
472 | +############################################################################## |
473 | +import logging |
474 | + |
475 | +from openerp.osv.orm import Model, fields |
476 | +import pooler |
477 | +#from datetime import datetime |
478 | + |
479 | +logger = logging.getLogger('credit.line.management') |
480 | + |
481 | +class CreditManagementLine (Model): |
482 | + """A credit Management line decribe a line of amount due by a customer. |
483 | + It is linked to all required financial account. |
484 | + It has various state draft open to be send send. For more information about |
485 | + usage please read __openerp__.py file""" |
486 | + |
487 | + _name = "credit.management.line" |
488 | + _description = """A credit Management line""" |
489 | + _rec_name = "id" |
490 | + |
491 | + _columns = {'date': fields.date('Controlling date', required=True), |
492 | + # maturity date of related move line we do not use a related field in order to |
493 | + # allow manual changes |
494 | + 'date_due': fields.date('Due date', |
495 | + required=True, |
496 | + readonly=True, |
497 | + states={'draft': [('readonly', False)]}), |
498 | + |
499 | + 'date_sent': fields.date('Sent date', |
500 | + readonly=True, |
501 | + states={'draft': [('readonly', False)]}), |
502 | + |
503 | + 'state': fields.selection([('draft', 'Draft'), |
504 | + ('to_be_sent', 'To be sent'), |
505 | + ('sent', 'Done'), |
506 | + ('error', 'Error'), |
507 | + ('mail_error', 'Mailing Error')], |
508 | + 'State', required=True, readonly=True), |
509 | + |
510 | + 'canal': fields.selection([('manual', 'Manual'), |
511 | + ('mail', 'Mail')], |
512 | + 'Canal', required=True, |
513 | + readonly=True, |
514 | + states={'draft': [('readonly', False)]}), |
515 | + |
516 | + 'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True), |
517 | + 'partner_id': fields.many2one('res.partner', "Partner", required=True), |
518 | + 'amount_due': fields.float('Due Amount Tax inc.', required=True, readonly=True), |
519 | + 'balance_due': fields.float('Due balance', required=True, readonly=True), |
520 | + 'mail_message_id': fields.many2one('mail.message', 'Sent mail', readonly=True), |
521 | + |
522 | + 'move_line_id': fields.many2one('account.move.line', 'Move line', |
523 | + required=True, readonly=True), |
524 | + |
525 | + 'account_id': fields.related('move_line_id', 'account_id', type='many2one', |
526 | + relation='account.account', string='Account', |
527 | + store=True, readonly=True), |
528 | + |
529 | + 'currency_id': fields.related('move_line_id', 'currency_id', type='many2one', |
530 | + relation='res.currency', string='Currency', |
531 | + store=True, readonly=True), |
532 | + |
533 | + 'company_id': fields.related('move_line_id', 'company_id', type='many2one', |
534 | + relation='res.company', string='Company', |
535 | + store=True, readonly=True), |
536 | + |
537 | + # we can allow a manual change of profile in draft state |
538 | + 'profile_rule_id':fields.many2one('credit.management.profile.rule', |
539 | + 'Overdue Rule', required=True, readonly=True, |
540 | + states={'draft': [('readonly', False)]}), |
541 | + |
542 | + 'profile_id': fields.related('profile_rule_id', 'profile_id', type='many2one', |
543 | + relation='credit.management.profile', string='Profile', |
544 | + store=True, readonly=True), |
545 | + |
546 | + 'level': fields.related('profile_rule_id', 'level', type='float', |
547 | + relation='credit.management.profile', string='Level', |
548 | + store=True, readonly=True),} |
549 | + |
550 | + |
551 | + _defaults = {'state': 'draft'} |
552 | + |
553 | + def _update_from_mv_line(self, cursor, uid, ids, mv_line_br, rule_br, |
554 | + lookup_date, context=None): |
555 | + """hook function to update line if required""" |
556 | + context = context or {} |
557 | + return [] |
558 | + |
559 | + def _create_from_mv_line(self, cursor, uid, ids, mv_line_br, |
560 | + rule_br, lookup_date, context=None): |
561 | + """Create credit line""" |
562 | + acc_line_obj = self.pool.get('account.move.line') |
563 | + context = context or {} |
564 | + data_dict = {} |
565 | + data_dict['date'] = lookup_date |
566 | + data_dict['date_due'] = mv_line_br.date_maturity |
567 | + data_dict['state'] = 'draft' |
568 | + data_dict['canal'] = rule_br.canal |
569 | + data_dict['invoice_id'] = (mv_line_br.invoice_id and mv_line_br.invoice_id.id |
570 | + or False) |
571 | + data_dict['partner_id'] = mv_line_br.partner_id.id |
572 | + data_dict['amount_due'] = (mv_line_br.amount_currency or mv_line_br.debit |
573 | + or mv_line_br.credit) |
574 | + data_dict['balance_due'] = acc_line_obj._amount_residual_from_date(cursor, uid, mv_line_br, |
575 | + lookup_date, context=context) |
576 | + data_dict['profile_rule_id'] = rule_br.id |
577 | + data_dict['company_id'] = mv_line_br.company_id.id |
578 | + data_dict['move_line_id'] = mv_line_br.id |
579 | + return [self.create(cursor, uid, data_dict)] |
580 | + |
581 | + |
582 | + def create_or_update_from_mv_lines(self, cursor, uid, ids, lines, |
583 | + rule_id, lookup_date, errors=None, context=None): |
584 | + """Create or update line base on rules""" |
585 | + context = context or {} |
586 | + currency_obj = self.pool.get('res.currency') |
587 | + rule_obj = self.pool.get('credit.management.profile.rule') |
588 | + ml_obj = self.pool.get('account.move.line') |
589 | + rule = rule_obj.browse(cursor, uid, rule_id, context) |
590 | + current_lvl = rule.level |
591 | + credit_line_ids = [] |
592 | + user = self.pool.get('res.users').browse(cursor, uid, uid) |
593 | + tolerance_base = user.company_id.credit_management_tolerance |
594 | + tolerance = {} |
595 | + currency_ids = currency_obj.search(cursor, uid, []) |
596 | + |
597 | + acc_line_obj = self.pool.get('account.move.line') |
598 | + for c_id in currency_ids: |
599 | + tmp = currency_obj.compute(cursor, uid, c_id, |
600 | + user.company_id.currency_id.id, tolerance_base) |
601 | + tolerance[c_id] = tmp |
602 | + |
603 | + existings = self.search(cursor, uid, [('move_line_id', 'in', lines), |
604 | + ('level', '=', current_lvl)]) |
605 | + db, pool = pooler.get_db_and_pool(cursor.dbname) |
606 | + for line in ml_obj.browse(cursor, uid, lines, context): |
607 | + # we want to create as many line as possible |
608 | + local_cr = db.cursor() |
609 | + try: |
610 | + if line.id in existings: |
611 | + # does nothing just a hook |
612 | + credit_line_ids += self._update_from_mv_line(local_cr, uid, ids, |
613 | + line, rule, lookup_date, |
614 | + context=context) |
615 | + else: |
616 | + # as we use memoizer pattern this has almost no cost to get it |
617 | + # multiple time |
618 | + open_amount = acc_line_obj._amount_residual_from_date(cursor, uid, line, |
619 | + lookup_date, context=context) |
620 | + |
621 | + if open_amount > tolerance.get(line.currency_id.id, tolerance_base): |
622 | + credit_line_ids += self._create_from_mv_line(local_cr, uid, ids, |
623 | + line, rule, lookup_date, |
624 | + context=context) |
625 | + except Exception, exc: |
626 | + logger.error(exc) |
627 | + if errors: |
628 | + errors.append(unicode(exc)) #obj-c common pattern |
629 | + local_cr.rollback() |
630 | + finally: |
631 | + local_cr.commit() |
632 | + local_cr.close() |
633 | + return credit_line_ids |
634 | |
635 | === added file 'account_credit_management/credit_management_line_view.xml' |
636 | --- account_credit_management/credit_management_line_view.xml 1970-01-01 00:00:00 +0000 |
637 | +++ account_credit_management/credit_management_line_view.xml 2012-10-15 10:14:35 +0000 |
638 | @@ -0,0 +1,145 @@ |
639 | +<openerp> |
640 | + <data> |
641 | + <record id="credit_management_line_form" model="ir.ui.view"> |
642 | + <field name="name">credit.management.line.form</field> |
643 | + <field name="model">credit.management.line</field> |
644 | + <field name="type">form</field> |
645 | + <field name="arch" type="xml"> |
646 | + <form> |
647 | + <field name="date"/> |
648 | + <field name="date_due"/> |
649 | + <field name="date_sent"/> |
650 | + <field name="level"/> |
651 | + <field name="state"/> |
652 | + <field name="canal"/> |
653 | + <field name="invoice_id"/> |
654 | + <field name="partner_id"/> |
655 | + <!-- <field name="address_id" domain="[('partner_id', '=', partner_id)]"/> --> |
656 | + <field name="amount_due"/> |
657 | + <field name="balance_due"/> |
658 | + <field name="currency_id"/> |
659 | + <field name="move_line_id"/> |
660 | + <field name="account_id"/> |
661 | + <field name="profile_rule_id"/> |
662 | + <field name="profile_id"/> |
663 | + <field name="mail_message_id"/> |
664 | + </form> |
665 | + </field> |
666 | + </record> |
667 | + |
668 | + <record id="credit_management_line_search" model="ir.ui.view"> |
669 | + <field name="name">Credit lines</field> |
670 | + <field name="model">credit.management.lines</field> |
671 | + <field name="type">search</field> |
672 | + <field name="arch" type="xml"> |
673 | + <search string="Search credit lines Items"> |
674 | + <group> |
675 | + <filter icon="terp-document-new" string="New" |
676 | + domain="[('state', '=', 'draft')]" |
677 | + help="New lines"/> |
678 | + <filter icon="terp-dolar_ok!" string="To be sent" |
679 | + domain="[('state', '=', 'to_be_sent')]" |
680 | + help="New lines"/> |
681 | + <filter icon="terp-check" string="Sent" |
682 | + domain="[('state', '=', 'sent')]" |
683 | + help="New lines"/> |
684 | + <separator orientation="vertical"/> |
685 | + <filter icon="terp-gtk-stop" string="Error" |
686 | + domain="[('state', 'in', ('error', 'mail_error'))]" |
687 | + help="New lines"/> |
688 | + <separator orientation="vertical"/> |
689 | + |
690 | + <field name="date"/> |
691 | + <field name="level"/> |
692 | + <field name="partner_id"/> |
693 | + <field name="account_id"/> |
694 | + <newline/> |
695 | + <field name="invoice_id"/> |
696 | + <field name="profile_id"/> |
697 | + <field name="profile_rule_id"/> |
698 | + <field name ="canal" /> |
699 | + </group> |
700 | + <newline/> |
701 | + |
702 | + <group expand="0" string="Group By..."> |
703 | + <separator orientation="vertical"/> |
704 | + <filter domain='[]' context="{'group_by': 'date'}" |
705 | + icon="terp-go-month" string="Run date"/> |
706 | + <separator orientation="vertical"/> |
707 | + <filter domain='[]' context="{'group_by': 'level'}" |
708 | + icon="terp-gtk-jump-to-rtl" string="Level"/> |
709 | + <separator orientation="vertical"/> |
710 | + <filter domain='[]' context="{'group_by': 'partner_id'}" |
711 | + icon="terp-partner" string="Partner"/> |
712 | + <separator orientation="vertical"/> |
713 | + <filter domain='[]' context="{'group_by': 'account_id'}" |
714 | + icon="terp-folder-green" string="Account"/> |
715 | + <separator orientation="vertical"/> |
716 | + <filter domain='[]' context="{'group_by': 'invoice_id'}" |
717 | + icon="terp-document-new" string="Invoice"/> |
718 | + <separator orientation="vertical"/> |
719 | + <filter domain='[]' context="{'group_by': 'profile_id'}" |
720 | + icon="terp-document-new" string="Credit Profile"/> |
721 | + <separator orientation="vertical"/> |
722 | + <filter domain='[]' context="{'group_by': 'profile_rule_id'}" |
723 | + icon="terp-document-new" string="Credit Profile rule"/> |
724 | + <separator orientation="vertical"/> |
725 | + <filter domain='[]' context="{'group_by': 'canal'}" |
726 | + icon="terp-document-new" string="Canal"/> |
727 | + </group> |
728 | + <newline/> |
729 | + </search> |
730 | + </field> |
731 | + </record> |
732 | + |
733 | + <record id="credit_management_line_tree" model="ir.ui.view"> |
734 | + <field name="name">credit.management.line.tree</field> |
735 | + <field name="model">credit.management.line</field> |
736 | + <field name="type">tree</field> |
737 | + <field name="arch" type="xml"> |
738 | + <tree editable="bottom" colors="green:state == 'sent';red:state in ('error', 'mail_error');"> |
739 | + <field name="date"/> |
740 | + <field name="date_due"/> |
741 | + <field name="level"/> |
742 | + <field name="state"/> |
743 | + <field name="canal"/> |
744 | + <field name="invoice_id"/> |
745 | + <field name="partner_id"/> |
746 | + <field name="amount_due"/> |
747 | + <field name="balance_due"/> |
748 | + <field name="currency_id"/> |
749 | + <field name="move_line_id"/> |
750 | + <field name="account_id"/> |
751 | + <field name="profile_rule_id"/> |
752 | + <field name="profile_id"/> |
753 | + <field name="mail_message_id"/> |
754 | + </tree> |
755 | + </field> |
756 | + </record> |
757 | + |
758 | + <menuitem |
759 | + name="Credit management" |
760 | + parent="account.menu_finance_periodical_processing" |
761 | + id="base_credit_management_menu"/> |
762 | + |
763 | + <record model="ir.actions.act_window" id="credit_management_line_action"> |
764 | + <field name="name">Credit lines</field> |
765 | + <field name="type">ir.actions.act_window</field> |
766 | + <field name="res_model">credit.management.line</field> |
767 | + <field name="domain"></field> |
768 | + <field name="view_type">form</field> |
769 | + <field name="view_mode">tree,form</field> |
770 | + <field name="view_id" ref="credit_management_line_tree"/> |
771 | + <field name="search_view_id" ref="credit_management_line_search"/> |
772 | + </record> |
773 | + |
774 | + |
775 | + <menuitem |
776 | + name="Credit lines" |
777 | + parent="base_credit_management_menu" |
778 | + action="credit_management_line_action" |
779 | + id="credit_management_line_action_menu"/> |
780 | + |
781 | + |
782 | + </data> |
783 | +</openerp> |
784 | |
785 | === added file 'account_credit_management/credit_management_partner.py' |
786 | --- account_credit_management/credit_management_partner.py 1970-01-01 00:00:00 +0000 |
787 | +++ account_credit_management/credit_management_partner.py 2012-10-15 10:14:35 +0000 |
788 | @@ -0,0 +1,36 @@ |
789 | +# -*- coding: utf-8 -*- |
790 | +############################################################################## |
791 | +# |
792 | +# Author: Nicolas Bessi |
793 | +# Copyright 2012 Camptocamp SA |
794 | +# |
795 | +# This program is free software: you can redistribute it and/or modify |
796 | +# it under the terms of the GNU Affero General Public License as |
797 | +# published by the Free Software Foundation, either version 3 of the |
798 | +# License, or (at your option) any later version. |
799 | +# |
800 | +# This program is distributed in the hope that it will be useful, |
801 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
802 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
803 | +# GNU Affero General Public License for more details. |
804 | +# |
805 | +# You should have received a copy of the GNU Affero General Public License |
806 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
807 | +# |
808 | +############################################################################## |
809 | +from openerp.osv.orm import Model, fields |
810 | + |
811 | +class ResPartner(Model): |
812 | + """Add a link to a credit management profile on account account""" |
813 | + |
814 | + _inherit = "res.partner" |
815 | + _description = """Add a link to a credit profile""" |
816 | + _columns = {'credit_profile_id': fields.many2one('credit.management.profile', |
817 | + 'Credit management profile', |
818 | + help=("Define global credit profile" |
819 | + "order is account partner invoice")), |
820 | + |
821 | + 'credit_management_line_ids': fields.one2many('credit.management.line', |
822 | + 'invoice_id', |
823 | + string='Credit Lines', |
824 | + readonly=True)} |
825 | |
826 | === added file 'account_credit_management/credit_management_partner_view.xml' |
827 | --- account_credit_management/credit_management_partner_view.xml 1970-01-01 00:00:00 +0000 |
828 | +++ account_credit_management/credit_management_partner_view.xml 2012-10-15 10:14:35 +0000 |
829 | @@ -0,0 +1,25 @@ |
830 | +<openerp> |
831 | +<data> |
832 | +<record id="partner_followup_form_view" model="ir.ui.view"> |
833 | + <field name="name">partner.credit_management.form.view</field> |
834 | + <field name="model">res.partner</field> |
835 | + <field name="inherit_id" ref="base.view_partner_form" /> |
836 | + <field name="type">form</field> |
837 | + <field name="arch" type="xml"> |
838 | + <field name="last_reconciliation_date" position="after"> |
839 | + <field name="credit_profile_id" |
840 | + groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_use"/> |
841 | + </field> |
842 | + </field> |
843 | +</record> |
844 | + |
845 | + <act_window |
846 | + id="act_partner_credit_relation_relation" |
847 | + name="Credit lines" |
848 | + groups="account_credit_management.group_account_credit_management_manager,account_credit_management.group_account_credit_management_user" |
849 | + domain="[('partner_id', '=', active_id)]" |
850 | + res_model="credit.management.line" |
851 | + src_model="res.partner"/> |
852 | + |
853 | +</data> |
854 | +</openerp> |
855 | |
856 | === added file 'account_credit_management/credit_management_profile.py' |
857 | --- account_credit_management/credit_management_profile.py 1970-01-01 00:00:00 +0000 |
858 | +++ account_credit_management/credit_management_profile.py 2012-10-15 10:14:35 +0000 |
859 | @@ -0,0 +1,292 @@ |
860 | +# -*- coding: utf-8 -*- |
861 | +############################################################################## |
862 | +# |
863 | +# Author: Nicolas Bessi |
864 | +# Copyright 2012 Camptocamp SA |
865 | +# |
866 | +# This program is free software: you can redistribute it and/or modify |
867 | +# it under the terms of the GNU Affero General Public License as |
868 | +# published by the Free Software Foundation, either version 3 of the |
869 | +# License, or (at your option) any later version. |
870 | +# |
871 | +# This program is distributed in the hope that it will be useful, |
872 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
873 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
874 | +# GNU Affero General Public License for more details. |
875 | +# |
876 | +# You should have received a copy of the GNU Affero General Public License |
877 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
878 | +# |
879 | +############################################################################## |
880 | +from openerp.osv.orm import Model, fields |
881 | +from openerp.tools.translate import _ |
882 | + |
883 | +class CreditManagementProfile(Model): |
884 | + """Define a profile of reminder""" |
885 | + |
886 | + _name = "credit.management.profile" |
887 | + _description = """Define a reminder profile""" |
888 | + _columns = {'name': fields.char('Name', required=True, size=128), |
889 | + |
890 | + 'profile_rule_ids' : fields.one2many('credit.management.profile.rule', |
891 | + 'profile_id', |
892 | + 'Profile Rules'), |
893 | + |
894 | + 'do_nothing' : fields.boolean('Do nothing', |
895 | + help=('For profiling who should not ' |
896 | + 'generate lines or are obsolete')), |
897 | + |
898 | + 'company_id' : fields.many2one('res.company', 'Company') |
899 | + } |
900 | + |
901 | + |
902 | + def _get_account_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None): |
903 | + """ We get all the lines related to accounts with given credit profile. |
904 | + We try not to use direct SQL in order to respect security rules. |
905 | + As we define the first set it is important, The date is used to do a prefilter. |
906 | + !!!We take the asumption that only receivable lines have a maturity date |
907 | + and account must be reconcillable""" |
908 | + context = context or {} |
909 | + move_l_obj = self.pool.get('account.move.line') |
910 | + account_obj = self.pool.get('account.account') |
911 | + acc_ids = account_obj.search(cursor, uid, [('credit_profile_id', '=', profile_id)]) |
912 | + if not acc_ids: |
913 | + return lines |
914 | + move_ids = move_l_obj.search(cursor, uid, [('account_id', 'in', acc_ids), |
915 | + ('date_maturity', '<=', lookup_date), |
916 | + ('reconcile_id', '=', False), |
917 | + ('partner_id', '!=', False)]) |
918 | + |
919 | + lines += move_ids |
920 | + return lines |
921 | + |
922 | + |
923 | + def _get_sum_reduce_range(self, cursor, uid, profile_id, lookup_date, lines, model, |
924 | + move_relation_field, context=None): |
925 | + """ We get all the lines related to the model with given credit profile. |
926 | + We also reduce from the global set (lines) the move line to be excluded. |
927 | + We try not to use direct SQL in order to respect security rules. |
928 | + As we define the first set it is important. |
929 | + The profile relation field MUST be named credit_profile_id |
930 | + and the model must have a relation |
931 | + with account move line. |
932 | + !!! We take the asumption that only receivable lines have a maturity date |
933 | + and account must be reconcillable""" |
934 | + # MARK possible place for a good optimisation |
935 | + context = context or {} |
936 | + my_obj = self.pool.get(model) |
937 | + move_l_obj = self.pool.get('account.move.line') |
938 | + add_obj_ids = my_obj.search(cursor, uid, [('credit_profile_id', '=', profile_id)]) |
939 | + if add_obj_ids: |
940 | + add_lines = move_l_obj.search(cursor, uid, [(move_relation_field, 'in', add_obj_ids), |
941 | + ('date_maturity', '<=', lookup_date), |
942 | + ('partner_id', '!=', False), |
943 | + ('reconcile_id', '=', False)]) |
944 | + lines = list(set(lines + add_lines)) |
945 | + # we get all the lines that must be excluded at partner_level |
946 | + # from the global set (even the one included at account level) |
947 | + neg_obj_ids = my_obj.search(cursor, uid, [('credit_profile_id', '!=', profile_id), |
948 | + ('credit_profile_id', '!=', False)]) |
949 | + if neg_obj_ids: |
950 | + # should we add ('id', 'in', lines) in domain ? it may give a veeery long SQL... |
951 | + neg_lines = move_l_obj.search(cursor, uid, [(move_relation_field, 'in', neg_obj_ids), |
952 | + ('date_maturity', '<=', lookup_date), |
953 | + ('partner_id', '!=', False), |
954 | + ('reconcile_id', '=', False)]) |
955 | + if neg_lines: |
956 | + lines = list(set(lines) - set(neg_lines)) |
957 | + return lines |
958 | + |
959 | + |
960 | + def _get_partner_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None): |
961 | + return self._get_sum_reduce_range(cursor, uid, profile_id, lookup_date, lines, |
962 | + 'res.partner', 'partner_id', context=context) |
963 | + |
964 | + |
965 | + def _get_invoice_related_lines(self, cursor, uid, profile_id, lookup_date, lines, context=None): |
966 | + return self._get_sum_reduce_range(cursor, uid, profile_id, lookup_date, lines, |
967 | + 'account.invoice', 'invoice', context=context) |
968 | + |
969 | + |
970 | + def _get_moves_line_to_process(self, cursor, uid, profile_id, lookup_date, context=None): |
971 | + """Retrive all the move line to be procces for current profile. |
972 | + This function is planned to be use only on one id. |
973 | + Priority of inclustion, exlusion is account, partner, invoice""" |
974 | + context = context or {} |
975 | + lines = [] |
976 | + if isinstance(profile_id, list): |
977 | + profile_id = profile_id[0] |
978 | + # order of call MUST be respected priority is account, partner, invoice |
979 | + lines = self._get_account_related_lines(cursor, uid, profile_id, |
980 | + lookup_date, lines, context=context) |
981 | + lines = self._get_partner_related_lines(cursor, uid, profile_id, |
982 | + lookup_date, lines, context=context) |
983 | + lines = self._get_invoice_related_lines(cursor, uid, profile_id, |
984 | + lookup_date, lines, context=context) |
985 | + return lines |
986 | + |
987 | + def _check_lines_profiles(self, cursor, uid, profile_id, lines, context=None): |
988 | + """ Check if there is credit line related to same move line but |
989 | + related to an other profile""" |
990 | + context = context or {} |
991 | + if not lines: |
992 | + return [] |
993 | + if isinstance(profile_id, list): |
994 | + profile_id = profile_id[0] |
995 | + cursor.execute("SELECT move_line_id FROM credit_management_line" |
996 | + " WHERE profile_id != %s and move_line_id in %s", |
997 | + (profile_id, tuple(lines))) |
998 | + res = cursor.fetchall() |
999 | + if res: |
1000 | + return [x[0] for x in res] |
1001 | + else: |
1002 | + return [] |
1003 | + |
1004 | + |
1005 | + |
1006 | +class CreditManagementProfileRule (Model): |
1007 | + """Define a profile rule. A rule allows to determine if |
1008 | + a move line is due and the level of overdue of the line""" |
1009 | + |
1010 | + _name = "credit.management.profile.rule" |
1011 | + _order = 'level' |
1012 | + _description = """A credit management profile rule""" |
1013 | + _columns = {'profile_id': fields.many2one('credit.management.profile', |
1014 | + 'Related Policy', required=True), |
1015 | + 'name': fields.char('Name', size=128, required=True), |
1016 | + 'level': fields.float('level', required=True), |
1017 | + |
1018 | + 'computation_mode': fields.selection([('net_days', 'Due date'), |
1019 | + ('end_of_month', 'Due Date: end of Month'), |
1020 | + ('previous_date', 'Previous reminder')], |
1021 | + 'Compute mode', |
1022 | + required=True), |
1023 | + |
1024 | + 'delay_days': fields.integer('Delay in day', required='True'), |
1025 | + 'mail_template_id': fields.many2one('email.template', 'Mail template', |
1026 | + required=True), |
1027 | + 'canal': fields.selection([('manual', 'Manual'), |
1028 | + ('mail', 'Mail')], |
1029 | + 'Canal', required=True), |
1030 | + 'custom_text': fields.text('Custom message', required=True, translate=True), |
1031 | + } |
1032 | + |
1033 | + |
1034 | + def _check_level_mode(self, cursor, uid, rids, context=None): |
1035 | + """We check that the smallest level is not based |
1036 | + on a rule using previous_date mode""" |
1037 | + if not isinstance(rids, list): |
1038 | + rids = [rids] |
1039 | + for rule in self.browse(cursor, uid, rids, context): |
1040 | + smallest_rule_id = self.search(cursor, uid, [('profile_id', '=', rule.profile_id.id)], |
1041 | + order='level asc', limit=1, context=context) |
1042 | + smallest_rule = self.browse(cursor, uid, smallest_rule_id[0], context) |
1043 | + if smallest_rule.computation_mode == 'previous_date': |
1044 | + return False |
1045 | + return True |
1046 | + |
1047 | + |
1048 | + |
1049 | + _sql_constraint = [('unique level', |
1050 | + 'UNIQUE (profile_id, level)', |
1051 | + 'Level must be unique per profile')] |
1052 | + |
1053 | + _constraints = [(_check_level_mode, |
1054 | + 'The smallest level can not be of type Previous reminder', |
1055 | + ['level'])] |
1056 | + |
1057 | + def _is_first_level(self, cursor, uid, rule_br, context=None): |
1058 | + """Check if rule has the smallest priority""" |
1059 | + first_rule = self.search(cursor, uid, [('profile_id', '=', rule_br.profile_id.id)], |
1060 | + order='level asc', limit=1, context=context) |
1061 | + return first_rule[0] == rule_br.id |
1062 | + # ----- time related functions --------- |
1063 | + |
1064 | + def _net_days_get_boundary(self): |
1065 | + return " (mv_line.date_maturity + %(delay)s)::date <= date(%(lookup_date)s)" |
1066 | + |
1067 | + def _end_of_month_get_boundary(self): |
1068 | + return ("(date_trunc('MONTH', (mv_line.date_maturity + %(delay)s))+INTERVAL '1 MONTH - 1 day')::date" |
1069 | + "<= date(%(lookup_date)s)") |
1070 | + |
1071 | + def _previous_date_get_boundary(self): |
1072 | + return "(cr_line.date + %(delay)s)::date <= date(%(lookup_date)s)" |
1073 | + |
1074 | + def _get_sql_date_boundary_for_computation_mode(self, cursor, uid, rule_br, lookup_date, context=None): |
1075 | + """Return a where clauses statement for the given |
1076 | + lookup date and computation mode of the rule""" |
1077 | + fname = "_%s_get_boundary" % (rule_br.computation_mode,) |
1078 | + if hasattr(self, fname): |
1079 | + fnc = getattr(self, fname) |
1080 | + return fnc() |
1081 | + else: |
1082 | + raise NotImplementedError(_('Can not get function for computation mode: ' |
1083 | + '%s is not implemented') % (fname,)) |
1084 | + |
1085 | + # ----------------------------------------- |
1086 | + |
1087 | + def _get_first_level_lines(self, cursor, uid, rule_br, lookup_date, lines, context=None): |
1088 | + if not lines: |
1089 | + return [] |
1090 | + """Retrieve all the line that are linked to a frist level rules. |
1091 | + We use Raw SQL for perf. Security rule where applied in |
1092 | + profile object when line where retrieved""" |
1093 | + sql = ("SELECT DISTINCT mv_line.id\n" |
1094 | + " FROM account_move_line mv_line\n" |
1095 | + " WHERE mv_line.id in %(line_ids)s\n" |
1096 | + " AND NOT EXISTS (SELECT cr_line.id from credit_management_line cr_line\n" |
1097 | + " WHERE cr_line.move_line_id = mv_line.id)") |
1098 | + sql += " AND" + self._get_sql_date_boundary_for_computation_mode(cursor, |
1099 | + uid, rule_br, |
1100 | + lookup_date, context) |
1101 | + data_dict = {'lookup_date': lookup_date, 'line_ids': tuple(lines), |
1102 | + 'delay': rule_br.delay_days} |
1103 | + |
1104 | + cursor.execute(sql, data_dict) |
1105 | + res = cursor.fetchall() |
1106 | + if not res: |
1107 | + return [] |
1108 | + return [x[0] for x in res] |
1109 | + |
1110 | + |
1111 | + def _get_other_level_lines(self, cursor, uid, rule_br, lookup_date, lines, context=None): |
1112 | + # We filter line that have a level smaller than current one |
1113 | + # TODO if code fits need refactor _get_first_level_lines and _get_other_level_lines |
1114 | + # Code is not DRY |
1115 | + if not lines: |
1116 | + return [] |
1117 | + sql = ("SELECT mv_line.id\n" |
1118 | + " FROM account_move_line mv_line\n" |
1119 | + " JOIN credit_management_line cr_line\n" |
1120 | + " ON (mv_line.id = cr_line.move_line_id)\n" |
1121 | + " WHERE cr_line.id = (SELECT credit_management_line.id FROM credit_management_line\n" |
1122 | + " WHERE credit_management_line.move_line_id = mv_line.id\n" |
1123 | + " ORDER BY credit_management_line.level desc limit 1)\n" |
1124 | + " AND cr_line.level < %(level)s\n" |
1125 | + " AND mv_line.id in %(line_ids)s\n") |
1126 | + sql += " AND " + self._get_sql_date_boundary_for_computation_mode(cursor, |
1127 | + uid, rule_br, |
1128 | + lookup_date, context) |
1129 | + data_dict = {'lookup_date': lookup_date, 'line_ids': tuple(lines), |
1130 | + 'delay': rule_br.delay_days, 'level': rule_br.level} |
1131 | + |
1132 | + cursor.execute(sql, data_dict) |
1133 | + res = cursor.fetchall() |
1134 | + if not res: |
1135 | + return [] |
1136 | + return [x[0] for x in res] |
1137 | + |
1138 | + def get_rule_lines(self, cursor, uid, rule_id, lookup_date, lines, context=None): |
1139 | + """get all move lines in entry lines that match the current rule""" |
1140 | + if isinstance(rule_id, list): |
1141 | + rule_id = rule_id[0] |
1142 | + matching_lines = [] |
1143 | + rule = self.browse(cursor, uid, rule_id, context=context) |
1144 | + if self._is_first_level(cursor, uid, rule): |
1145 | + matching_lines += self._get_first_level_lines(cursor, uid, rule, lookup_date, |
1146 | + lines, context=context) |
1147 | + else: |
1148 | + matching_lines += self._get_other_level_lines(cursor, uid, rule, lookup_date, |
1149 | + lines, context=context) |
1150 | + |
1151 | + return matching_lines |
1152 | |
1153 | === added file 'account_credit_management/credit_management_profile_view.xml' |
1154 | --- account_credit_management/credit_management_profile_view.xml 1970-01-01 00:00:00 +0000 |
1155 | +++ account_credit_management/credit_management_profile_view.xml 2012-10-15 10:14:35 +0000 |
1156 | @@ -0,0 +1,118 @@ |
1157 | +<openerp> |
1158 | + <data> |
1159 | + |
1160 | + <record id="credit_management_profile_form" model="ir.ui.view"> |
1161 | + <field name="name">credit.management.profile.form</field> |
1162 | + <field name="model">credit.management.profile</field> |
1163 | + <field name="type">form</field> |
1164 | + <field name="arch" type="xml"> |
1165 | + <form> <!-- editable="bottom" --> |
1166 | + <field name="name"/> |
1167 | + <field name="do_nothing"/> |
1168 | + <field name="company_id"/> |
1169 | + <notebook colspan="4"> |
1170 | + <page string="Rules"> |
1171 | + <field name="profile_rule_ids" colspan="4" > |
1172 | + <tree editable="bottom"> |
1173 | + <field name="name"/> |
1174 | + <field name="level"/> |
1175 | + <field name="canal"/> |
1176 | + <field name="delay_days"/> |
1177 | + <field name="computation_mode"/> |
1178 | + <field name="mail_template_id"/> |
1179 | + </tree> |
1180 | + <form> |
1181 | + <field name="name"/> |
1182 | + <notebook colspan="4"> |
1183 | + <page string="Delay Setting"> |
1184 | + <field name="level"/> |
1185 | + <field name="canal"/> |
1186 | + <field name="delay_days"/> |
1187 | + <field name="computation_mode"/> |
1188 | + </page> |
1189 | + <page string="Mail and reporting"> |
1190 | + <field name="mail_template_id"/> |
1191 | + <field name="custom_text"/> |
1192 | + </page> |
1193 | + </notebook> |
1194 | + </form> |
1195 | + </field> |
1196 | + </page> |
1197 | + </notebook> |
1198 | + </form> |
1199 | + </field> |
1200 | + </record> |
1201 | + |
1202 | + <record id="credit_management_profile_tree" model="ir.ui.view"> |
1203 | + <field name="name">credit.management.profile.tree</field> |
1204 | + <field name="model">credit.management.profile</field> |
1205 | + <field name="type">tree</field> |
1206 | + <field name="arch" type="xml"> |
1207 | + <tree> <!-- editable="bottom" --> |
1208 | + <field name="name"/> |
1209 | + <field name="do_nothing"/> |
1210 | + </tree> |
1211 | + </field> |
1212 | + </record> |
1213 | + |
1214 | + <menuitem |
1215 | + name="Credit management configuration" |
1216 | + parent="account.menu_finance_configuration" |
1217 | + id="base_credit_management_configuration_menu"/> |
1218 | + |
1219 | + <record model="ir.actions.act_window" id="credit_profile_configuration_action"> |
1220 | + <field name="name">Credit profiles</field> |
1221 | + <field name="type">ir.actions.act_window</field> |
1222 | + <field name="res_model">credit.management.profile</field> |
1223 | + <field name="domain"></field> |
1224 | + <field name="view_type">form</field> |
1225 | + <field name="view_mode">tree,form</field> |
1226 | + <field name="view_id" ref="credit_management_profile_tree"/> |
1227 | + </record> |
1228 | + |
1229 | + <menuitem |
1230 | + name="Credit profiles" |
1231 | + parent="base_credit_management_configuration_menu" |
1232 | + action="credit_profile_configuration_action" |
1233 | + id="credit_profile_configuration_action_menu"/> |
1234 | + |
1235 | + <record id="credit_mangement_profile_rule_form" model="ir.ui.view"> |
1236 | + <field name="name">credit.mangement.profile.rule.form</field> |
1237 | + <field name="model">credit.management.profile.rule</field> |
1238 | + <field name="type">form</field> |
1239 | + <field name="arch" type="xml"> |
1240 | + <form> <!-- editable="bottom" --> |
1241 | + <field name="name"/> |
1242 | + <notebook colspan="4"> |
1243 | + <page string="Delay Setting"> |
1244 | + <field name="level"/> |
1245 | + <field name="canal"/> |
1246 | + <field name="delay_days"/> |
1247 | + <field name="computation_mode"/> |
1248 | + </page> |
1249 | + <page string="Mail and reporting"> |
1250 | + <field name="mail_template_id"/> |
1251 | + <field name="custom_text"/> |
1252 | + </page> |
1253 | + </notebook> |
1254 | + </form> |
1255 | + </field> |
1256 | + </record> |
1257 | + |
1258 | + <record id="credit_management_profile_rule_tree" model="ir.ui.view"> |
1259 | + <field name="name">credit.management.profile.rule.tree</field> |
1260 | + <field name="model">credit.management.profile.rule</field> |
1261 | + <field name="type">tree</field> |
1262 | + <field name="arch" type="xml"> |
1263 | + <tree editable="bottom"> |
1264 | + <field name="name"/> |
1265 | + <field name="level"/> |
1266 | + <field name="canal"/> |
1267 | + <field name="delay_days"/> |
1268 | + <field name="computation_mode"/> |
1269 | + <field name="mail_template_id"/> |
1270 | + </tree> |
1271 | + </field> |
1272 | + </record> |
1273 | + </data> |
1274 | +</openerp> |
1275 | |
1276 | === added file 'account_credit_management/credit_management_run.py' |
1277 | --- account_credit_management/credit_management_run.py 1970-01-01 00:00:00 +0000 |
1278 | +++ account_credit_management/credit_management_run.py 2012-10-15 10:14:35 +0000 |
1279 | @@ -0,0 +1,150 @@ |
1280 | +# -*- coding: utf-8 -*- |
1281 | +############################################################################## |
1282 | +# |
1283 | +# Author: Nicolas Bessi |
1284 | +# Copyright 2012 Camptocamp SA |
1285 | +# |
1286 | +# This program is free software: you can redistribute it and/or modify |
1287 | +# it under the terms of the GNU Affero General Public License as |
1288 | +# published by the Free Software Foundation, either version 3 of the |
1289 | +# License, or (at your option) any later version. |
1290 | +# |
1291 | +# This program is distributed in the hope that it will be useful, |
1292 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1293 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1294 | +# GNU Affero General Public License for more details. |
1295 | +# |
1296 | +# You should have received a copy of the GNU Affero General Public License |
1297 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1298 | +# |
1299 | +############################################################################## |
1300 | +import sys |
1301 | +import traceback |
1302 | +import logging |
1303 | + |
1304 | +from openerp.osv.orm import Model, fields |
1305 | +from openerp.tools.translate import _ |
1306 | +from openerp.osv.osv import except_osv |
1307 | + |
1308 | +logger = logging.getLogger('Credit management run') |
1309 | + |
1310 | +memoizers = {} |
1311 | + |
1312 | + |
1313 | +class CreditManagementRun(Model): |
1314 | + """Credit management run generate all credit management lines and reject""" |
1315 | + |
1316 | + _name = "credit.management.run" |
1317 | + _rec_name = 'date' |
1318 | + _description = """Credit management line generator""" |
1319 | + _columns = {'date': fields.date('Lookup date', required=True), |
1320 | + 'profile_ids': fields.many2many('credit.management.profile', |
1321 | + rel="credit_run_profile_rel", |
1322 | + string='Profiles', |
1323 | + readonly=True, |
1324 | + help="If nothing set all profile will be used", |
1325 | + |
1326 | + states={'draft': [('readonly', False)]}), |
1327 | + |
1328 | + 'report': fields.text('Report', readonly=True), |
1329 | + |
1330 | + 'state': fields.selection([('draft', 'Draft'), |
1331 | + ('running', 'Running'), |
1332 | + ('done', 'Done'), |
1333 | + ('error', 'Error')], |
1334 | + string='State', |
1335 | + required=True, |
1336 | + readonly=True), |
1337 | + |
1338 | + 'manual_ids': fields.many2many('account.move.line', |
1339 | + rel="credit_runreject_rel", |
1340 | + string='Line to be handled manually', |
1341 | + readonly=True), |
1342 | + } |
1343 | + |
1344 | + _defaults = {'state': 'draft'} |
1345 | + |
1346 | + def check_run_date(self, cursor, uid, ids, lookup_date, context=None): |
1347 | + """Ensure that there is no credit line in the future using lookup_date""" |
1348 | + line_obj = self.pool.get('credit.management.line') |
1349 | + lines = line_obj.search(cursor, uid, [('date', '>', lookup_date)], |
1350 | + order='date DESC', limit=1) |
1351 | + if lines: |
1352 | + line = line_obj.browse(cursor, uid, lines[0]) |
1353 | + raise except_osv(_('A run was already executed in a greater date'), |
1354 | + _('Run date should be >= %s') % (line.date)) |
1355 | + |
1356 | + |
1357 | + def _generate_credit_lines(self, cursor, uid, run_id, context=None): |
1358 | + """ Generate credit line. Function can be a little dryer but |
1359 | + it does almost noting, initalise variable maange error and call |
1360 | + real know how method""" |
1361 | + memoizers['credit_line_residuals'] = {} |
1362 | + cr_line_obj = self.pool.get('credit.management.line') |
1363 | + if isinstance(run_id, list): |
1364 | + run_id = run_id[0] |
1365 | + run = self.browse(cursor, uid, run_id, context=context) |
1366 | + errors = [] |
1367 | + manualy_managed_lines = [] #line who changed profile |
1368 | + credit_line_ids = [] # generated lines |
1369 | + run.check_run_date(run.date, context=context) |
1370 | + profile_ids = run.profile_ids |
1371 | + if not profile_ids: |
1372 | + profile_obj = self.pool.get('credit.management.profile') |
1373 | + profile_ids_ids = profile_obj.search(cursor, uid, []) |
1374 | + profile_ids = profile_obj.browse(cursor, uid, profile_ids_ids) |
1375 | + for profile in profile_ids: |
1376 | + if profile.do_nothing: |
1377 | + continue |
1378 | + try: |
1379 | + lines = profile._get_moves_line_to_process(run.date, context=context) |
1380 | + tmp_manual = profile._check_lines_profiles(lines, context=context) |
1381 | + lines = list(set(lines) - set(tmp_manual)) |
1382 | + manualy_managed_lines += tmp_manual |
1383 | + if not lines: |
1384 | + continue |
1385 | + # profile rules are sorted by level so iteration is in the correct order |
1386 | + for rule in profile.profile_rule_ids: |
1387 | + rule_lines = rule.get_rule_lines(run.date, lines) |
1388 | + #only this write action own a separate cursor |
1389 | + credit_line_ids += cr_line_obj.create_or_update_from_mv_lines(cursor, uid, [], |
1390 | + rule_lines, rule.id, |
1391 | + run.date, errors=errors, |
1392 | + context=context) |
1393 | + lines = list(set(lines) - set(rule_lines)) |
1394 | + except Exception, exc: |
1395 | + cursor.rollback() |
1396 | + error_type, error_value, trbk = sys.exc_info() |
1397 | + st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) |
1398 | + st += ''.join(traceback.format_tb(trbk, 30)) |
1399 | + logger.error(st) |
1400 | + self.write(cursor, uid, [run.id], {'report':st, 'state': 'error'}) |
1401 | + return False |
1402 | + vals = {'report': u"Number of generated lines : %s \n" % (len(credit_line_ids),), |
1403 | + 'state': 'done', |
1404 | + 'manual_ids': [(6, 0, manualy_managed_lines)]} |
1405 | + if errors: |
1406 | + vals['report'] += u"Following line generation errors appends:" |
1407 | + vals['report'] += u"----\n".join(errors) |
1408 | + vals['state'] = 'done' |
1409 | + run.write(vals) |
1410 | + # lines will correspond to line that where not treated |
1411 | + return lines |
1412 | + |
1413 | + |
1414 | + |
1415 | + def generate_credit_lines(self, cursor, uid, run_id, context=None): |
1416 | + """Generate credit management lines""" |
1417 | + context = context or {} |
1418 | + # we do a little magical tips in order to ensure non concurrent run |
1419 | + # of the function generate_credit_lines |
1420 | + try: |
1421 | + cursor.execute('SELECT id FROM credit_management_run' |
1422 | + ' LIMIT 1 FOR UPDATE NOWAIT' ) |
1423 | + except Exception, exc: |
1424 | + cursor.rollback() |
1425 | + raise except_osv(_('A credit management run is allready running' |
1426 | + ' in background please try later'), |
1427 | + str(exc)) |
1428 | + # in case of exception openerp will do a rollback for us and free the lock |
1429 | + return self._generate_credit_lines(cursor, uid, run_id, context) |
1430 | |
1431 | === added file 'account_credit_management/credit_management_run_view.xml' |
1432 | --- account_credit_management/credit_management_run_view.xml 1970-01-01 00:00:00 +0000 |
1433 | +++ account_credit_management/credit_management_run_view.xml 2012-10-15 10:14:35 +0000 |
1434 | @@ -0,0 +1,65 @@ |
1435 | +<openerp> |
1436 | + <data> |
1437 | + |
1438 | + <record id="credit_management_run_tree" model="ir.ui.view"> |
1439 | + <field name="name">credit.management.run.tree</field> |
1440 | + <field name="model">credit.management.run</field> |
1441 | + <field name="type">tree</field> |
1442 | + <field name="arch" type="xml"> |
1443 | + <tree> <!-- editable="bottom" --> |
1444 | + <field name="date"/> |
1445 | + <field name="state"/> |
1446 | + </tree> |
1447 | + </field> |
1448 | + </record> |
1449 | + |
1450 | + <record id="credit_management_run_form" model="ir.ui.view"> |
1451 | + <field name="name">credit.management.run.form</field> |
1452 | + <field name="model">credit.management.run</field> |
1453 | + <field name="type">form</field> |
1454 | + <field name="arch" type="xml"> |
1455 | + <form> <!-- editable="bottom" --> |
1456 | + <field name="date"/> |
1457 | + <newline/> |
1458 | + <notebook colspan="4"> |
1459 | + <page string="Profile"> |
1460 | + <field name="profile_ids" colspan="4" nolabel="1"/> |
1461 | + </page> |
1462 | + <page string="Report and Errors"> |
1463 | + <field name="report" colspan="4" nolabel="1"/> |
1464 | + <separator string="Move lines To be treated manually"/> |
1465 | + <field name="manual_ids" colspan="4" nolabel="1"/> |
1466 | + </page> |
1467 | + </notebook> |
1468 | + <group col="3" colspan="4"> |
1469 | + <button name="generate_credit_lines" |
1470 | + string="Compute credit lines" |
1471 | + colspan="1" |
1472 | + type="object" icon="gtk-execute" |
1473 | + attrs="{'invisible': [('state', '!=', 'draft')]}"/> |
1474 | + </group> |
1475 | + <field name="state"/> |
1476 | + </form> |
1477 | + </field> |
1478 | + </record> |
1479 | + |
1480 | + |
1481 | + <record model="ir.actions.act_window" id="credit_management_run"> |
1482 | + <field name="name">Credit management run</field> |
1483 | + <field name="type">ir.actions.act_window</field> |
1484 | + <field name="res_model">credit.management.run</field> |
1485 | + <field name="domain"></field> |
1486 | + <field name="view_type">form</field> |
1487 | + <field name="view_mode">tree,form</field> |
1488 | + <field name="view_id" ref="credit_management_run_tree"/> |
1489 | + </record> |
1490 | + |
1491 | + |
1492 | + <menuitem |
1493 | + name="Credit management run" |
1494 | + parent="base_credit_management_menu" |
1495 | + action="credit_management_run" |
1496 | + id="credit_management_run_menu"/> |
1497 | + |
1498 | + </data> |
1499 | +</openerp> |
1500 | |
1501 | === added file 'account_credit_management/data.xml' |
1502 | --- account_credit_management/data.xml 1970-01-01 00:00:00 +0000 |
1503 | +++ account_credit_management/data.xml 2012-10-15 10:14:35 +0000 |
1504 | @@ -0,0 +1,173 @@ |
1505 | +<openerp> |
1506 | + <data noupdate="1"> |
1507 | + <!--Email template --> |
1508 | + <record id="email_template_credit_management_base" model="email.template"> |
1509 | + <field name="name">Credit Management demo mail</field> |
1510 | + <field name="email_from">noreply@localhost</field> |
1511 | + <field name="subject">Credit Management Invoice (${object.current_profile_rule.level or 'n/a' })</field> |
1512 | + <field name="email_to">${object.get_mail() or ''}</field> |
1513 | + <field name="model_id" ref="model_credit_management_communication"/> |
1514 | + <field name="auto_delete" eval="True"/> |
1515 | + <field name="body_html"><![CDATA[ |
1516 | + <%page args="object, mode" /> |
1517 | + %if mode != 'pdf': |
1518 | + <!-- your css here --> |
1519 | + <style type="text/css"> |
1520 | + </style> |
1521 | + %endif |
1522 | + <div> |
1523 | + |
1524 | + <p>Dear ${object.partner_id.name or ''},</p> |
1525 | + |
1526 | + <pre class="custom_text">${object.current_profile_rule.level.custom_text}</pre> |
1527 | + |
1528 | + <table style="border: 1px solid" width="100%"> |
1529 | + <caption><b>Summary</b></caption> |
1530 | + <tr> |
1531 | + <th>date due</th> |
1532 | + <th>Amount due</th> |
1533 | + <th>Amount balance</th> |
1534 | + <th>Invoice number</th> |
1535 | + </tr> |
1536 | +%for line in object.credit_lines: |
1537 | + <tr> |
1538 | + <td>${line.date_due}</td> |
1539 | + <td>${line.amount_due}</td> |
1540 | + <td>${line.balance_due}</td> |
1541 | + %if line.invoice_id: |
1542 | + <td>${line.invoice_id.number}</td> |
1543 | + %else: |
1544 | + <td>n/a</td> |
1545 | + %endif |
1546 | +%endfor |
1547 | + </table> |
1548 | + <br/> |
1549 | + <br/> |
1550 | + |
1551 | + <p> If you have any question, do not hesitate to contact us.</p> |
1552 | + |
1553 | + |
1554 | + <p>Thank you for choosing ${object.company_id.name}! </p> |
1555 | + |
1556 | + -- more info here -- |
1557 | + <p>${object.user_id.name} ${object.user_id.user_email and '<%s>'%(object.user_id.user_email) or ''}<br/> |
1558 | + ${object.company_id.name}<br/> |
1559 | + % if object.company_id.street: |
1560 | + ${object.company_id.street or ''}<br/> |
1561 | + |
1562 | + % endif |
1563 | + |
1564 | + % if object.company_id.street2: |
1565 | + ${object.company_id.street2}<br/> |
1566 | + % endif |
1567 | + % if object.company_id.city or object.company_id.zip: |
1568 | + ${object.company_id.zip or ''} ${object.company_id.city or ''}<br/> |
1569 | + % endif |
1570 | + % if object.company_id.country_id: |
1571 | + ${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}<br/> |
1572 | + % endif |
1573 | + % if object.company_id.phone: |
1574 | + Phone: ${object.company_id.phone}<br/> |
1575 | + % endif |
1576 | + % if object.company_id.website: |
1577 | + ${object.company_id.website or ''}<br/> |
1578 | + % endif |
1579 | + ]]></field> |
1580 | + </record> |
1581 | + |
1582 | + <!-- profile no follow --> |
1583 | + <record model="credit.management.profile" |
1584 | + id="credit_management_no_follow"> |
1585 | + <field name="name">No follow</field> |
1586 | + <field name="do_nothing" eval="1"/> |
1587 | + </record> |
1588 | + |
1589 | + <!-- profile 1 --> |
1590 | + <record model="credit.management.profile" |
1591 | + id="credit_management_3_time"> |
1592 | + <field name="name">3 time policy</field> |
1593 | + </record> |
1594 | + |
1595 | + <record model="credit.management.profile.rule" |
1596 | + id="3_time_1"> |
1597 | + <field name="name">10 days net</field> |
1598 | + <field name="level" eval="1"/> |
1599 | + <field name="computation_mode">net_days</field> |
1600 | + <field name="delay_days" eval="10"/> |
1601 | + <field name="mail_template_id" ref="email_template_credit_management_base"/> |
1602 | + <field name="profile_id" ref="credit_management_3_time"/> |
1603 | + <field name="canal">mail</field> |
1604 | + <field name="custom_text">Replace this text in rule by your message</field> |
1605 | + </record> |
1606 | + |
1607 | + <record model="credit.management.profile.rule" |
1608 | + id="3_time_2"> |
1609 | + <field name="name">30 days end of month</field> |
1610 | + <field name="level" eval="2"/> |
1611 | + <field name="computation_mode">end_of_month</field> |
1612 | + <field name="delay_days" eval="30"/> |
1613 | + <field name="mail_template_id" ref="email_template_credit_management_base"/> |
1614 | + <field name="profile_id" ref="credit_management_3_time"/> |
1615 | + <field name="canal">mail</field> |
1616 | + <field name="custom_text">Replace this text in rule by your message</field> |
1617 | + </record> |
1618 | + |
1619 | + <record model="credit.management.profile.rule" |
1620 | + id="3_time_3"> |
1621 | + <field name="name">10 days sommation</field> |
1622 | + <field name="level" eval="3"/> |
1623 | + <field name="computation_mode">previous_date</field> |
1624 | + <field name="delay_days" eval="10"/> |
1625 | + <field name="mail_template_id" ref="email_template_credit_management_base"/> |
1626 | + <field name="profile_id" ref="credit_management_3_time"/> |
1627 | + <field name="canal">manual</field> |
1628 | + <field name="custom_text">Replace this text in rule by your message</field> |
1629 | + </record> |
1630 | + |
1631 | + <!-- profile 2 --> |
1632 | + <record model="credit.management.profile" |
1633 | + id="credit_management_2_time"> |
1634 | + <field name="name">2 time policy</field> |
1635 | + </record> |
1636 | + |
1637 | + <record model="credit.management.profile.rule" |
1638 | + id="2_time_1"> |
1639 | + <field name="name">30 days end of month</field> |
1640 | + <field name="level" eval="1"/> |
1641 | + <field name="computation_mode">end_of_month</field> |
1642 | + <field name="delay_days" eval="30"/> |
1643 | + <field name="mail_template_id" ref="email_template_credit_management_base"/> |
1644 | + <field name="profile_id" ref="credit_management_2_time"/> |
1645 | + <field name="canal">mail</field> |
1646 | + <field name="custom_text">Replace this text in rule by your message</field> |
1647 | + </record> |
1648 | + |
1649 | + <record model="credit.management.profile.rule" |
1650 | + id="2_time_2"> |
1651 | + <field name="name">60 days sommation</field> |
1652 | + <field name="level" eval="2"/> |
1653 | + <field name="computation_mode">previous_date</field> |
1654 | + <field name="delay_days" eval="60"/> |
1655 | + <field name="mail_template_id" ref="email_template_credit_management_base"/> |
1656 | + <field name="profile_id" ref="credit_management_2_time"/> |
1657 | + <field name="canal">manual</field> |
1658 | + <field name="custom_text">Replace this text in rule by your message</field> |
1659 | + </record> |
1660 | + |
1661 | + <record id="group_account_credit_management_manager" model="res.groups"> |
1662 | + <field name="name">Credit Management manager</field> |
1663 | + <field name="category_id" ref="base.module_category_accounting_and_finance"/> |
1664 | + </record> |
1665 | + |
1666 | + <record id="group_account_credit_management_user" model="res.groups" context="{'noadmin':True}"> |
1667 | + <field name="name">Credit Management user</field> |
1668 | + <field name="category_id" ref="base.module_category_accounting_and_finance"/> |
1669 | + </record> |
1670 | + |
1671 | + <record id="group_account_credit_management_info" model="res.groups" context="{'noadmin':True}"> |
1672 | + <field name="name">Credit Management info</field> |
1673 | + <field name="category_id" ref="base.module_category_accounting_and_finance"/> |
1674 | + </record> |
1675 | + |
1676 | + </data> |
1677 | +</openerp> |
1678 | |
1679 | === added directory 'account_credit_management/i18n' |
1680 | === added directory 'account_credit_management/report' |
1681 | === added file 'account_credit_management/report/__init__.py' |
1682 | --- account_credit_management/report/__init__.py 1970-01-01 00:00:00 +0000 |
1683 | +++ account_credit_management/report/__init__.py 2012-10-15 10:14:35 +0000 |
1684 | @@ -0,0 +1,1 @@ |
1685 | +from . import credit_management_summary |
1686 | |
1687 | === added file 'account_credit_management/report/credit_management_summary.html.mako' |
1688 | --- account_credit_management/report/credit_management_summary.html.mako 1970-01-01 00:00:00 +0000 |
1689 | +++ account_credit_management/report/credit_management_summary.html.mako 2012-10-15 10:14:35 +0000 |
1690 | @@ -0,0 +1,19 @@ |
1691 | +<html> |
1692 | +<head> |
1693 | + <style type="text/css"> |
1694 | + ${css} |
1695 | + </style> |
1696 | +</head> |
1697 | +<body> |
1698 | + %for comm in objects : |
1699 | + ${setLang(comm.partner_id.lang)} |
1700 | + <% |
1701 | + current_uri = '%s_profile_template' % (comm.partner_id.lang) |
1702 | + if not context.lookup.has_template(current_uri): |
1703 | + context.lookup.put_string(current_uri, comm.current_profile_rule.mail_template_id.body_html) |
1704 | + %> |
1705 | + <%include file="${current_uri}" args="object=comm,mode='pdf'"/> |
1706 | + </br> |
1707 | + %endfor |
1708 | +</body> |
1709 | +</html> |
1710 | |
1711 | === added file 'account_credit_management/report/credit_management_summary.py' |
1712 | --- account_credit_management/report/credit_management_summary.py 1970-01-01 00:00:00 +0000 |
1713 | +++ account_credit_management/report/credit_management_summary.py 2012-10-15 10:14:35 +0000 |
1714 | @@ -0,0 +1,37 @@ |
1715 | +# -*- coding: utf-8 -*- |
1716 | +############################################################################## |
1717 | +# |
1718 | +# Author: Nicolas Bessi |
1719 | +# Copyright 2012 Camptocamp SA |
1720 | +# |
1721 | +# This program is free software: you can redistribute it and/or modify |
1722 | +# it under the terms of the GNU Affero General Public License as |
1723 | +# published by the Free Software Foundation, either version 3 of the |
1724 | +# License, or (at your option) any later version. |
1725 | +# |
1726 | +# This program is distributed in the hope that it will be useful, |
1727 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1728 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1729 | +# GNU Affero General Public License for more details. |
1730 | +# |
1731 | +# You should have received a copy of the GNU Affero General Public License |
1732 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1733 | +# |
1734 | +############################################################################## |
1735 | +import time |
1736 | + |
1737 | +from openerp.report import report_sxw |
1738 | + |
1739 | +class CreditSummaryReport(report_sxw.rml_parse): |
1740 | + def __init__(self, cr, uid, name, context): |
1741 | + super(CreditSummaryReport, self).__init__(cr, uid, name, context=context) |
1742 | + self.localcontext.update({ |
1743 | + 'time': time, |
1744 | + 'cr':cr, |
1745 | + 'uid': uid, |
1746 | + }) |
1747 | + |
1748 | +report_sxw.report_sxw('report.credit_management_summary', |
1749 | + 'credit.management.communication', |
1750 | + 'addons/account_credit_management/report/credit_management_summary.html.mako', |
1751 | + parser=CreditSummaryReport) |
1752 | |
1753 | === added file 'account_credit_management/report/report.xml' |
1754 | --- account_credit_management/report/report.xml 1970-01-01 00:00:00 +0000 |
1755 | +++ account_credit_management/report/report.xml 2012-10-15 10:14:35 +0000 |
1756 | @@ -0,0 +1,12 @@ |
1757 | +<openerp> |
1758 | + <data> |
1759 | + <report auto="False" |
1760 | + id="report_webkit_html" |
1761 | + model="credit.management.communication" |
1762 | + name="credit_management_summary" |
1763 | + file="account_credit_management/report/credit_management_summary.html.mako" |
1764 | + string="Credit Summary" |
1765 | + report_type="webkit" |
1766 | + webkit_header="report_webkit.ir_header_webkit_basesample0"/> |
1767 | + </data> |
1768 | +</openerp> |
1769 | |
1770 | === added directory 'account_credit_management/scenarios' |
1771 | === added directory 'account_credit_management/scenarios/credit_management' |
1772 | === added file 'account_credit_management/scenarios/credit_management/00_credit_management_param.feature' |
1773 | --- account_credit_management/scenarios/credit_management/00_credit_management_param.feature 1970-01-01 00:00:00 +0000 |
1774 | +++ account_credit_management/scenarios/credit_management/00_credit_management_param.feature 2012-10-15 10:14:35 +0000 |
1775 | @@ -0,0 +1,23 @@ |
1776 | +############################################################################### |
1777 | +# |
1778 | +# OERPScenario, OpenERP Functional Tests |
1779 | +# Copyright 2009 Camptocamp SA |
1780 | +# |
1781 | +############################################################################## |
1782 | +############################################################################## |
1783 | +# Branch # Module # Processes # System |
1784 | +@credit_management_module @credit_management_param |
1785 | + |
1786 | +Feature: In order to validate account voucher behavious as an admin user I prepare data |
1787 | + @credit_management_addon_install |
1788 | + Scenario: Install module |
1789 | + Given I need a "ir.module.module" with name: account_voucher |
1790 | + And having: |
1791 | + |name | value | |
1792 | + | demo | 0 | |
1793 | + |
1794 | + Given I do not want all demo data to be loaded on install |
1795 | + And I install the required modules with dependencies: |
1796 | + | name | |
1797 | + | account_credit_management | |
1798 | + Then my modules should have been installed and models reloaded |
1799 | \ No newline at end of file |
1800 | |
1801 | === added file 'account_credit_management/scenarios/credit_management/01_credit_management_partners.feature' |
1802 | --- account_credit_management/scenarios/credit_management/01_credit_management_partners.feature 1970-01-01 00:00:00 +0000 |
1803 | +++ account_credit_management/scenarios/credit_management/01_credit_management_partners.feature 2012-10-15 10:14:35 +0000 |
1804 | @@ -0,0 +1,60 @@ |
1805 | +############################################################################### |
1806 | +# |
1807 | +# OERPScenario, OpenERP Functional Tests |
1808 | +# Copyright 2009 Camptocamp SA |
1809 | +# |
1810 | +############################################################################## |
1811 | +############################################################################## |
1812 | +# Branch # Module # Processes # System |
1813 | +@credit_management_module @credit_management_partner |
1814 | + |
1815 | +Feature: I add profile to partners already created |
1816 | + @credit_management_partner_1 |
1817 | + Scenario: Partner_1 |
1818 | + Given I need a "res.partner" with oid: scen.partner_1 |
1819 | + And having: |
1820 | + | name | value | |
1821 | + | name | partner_1 | |
1822 | + | credit_profile_id | by name: No follow | |
1823 | + |
1824 | + @credit_management_customer_1 |
1825 | + Scenario: Customer_1 |
1826 | + Given I need a "res.partner" with oid: scen.customer_1 |
1827 | + And having: |
1828 | + | name | value | |
1829 | + | name | customer_1 | |
1830 | + | credit_profile_id | by name: 2 time policy| |
1831 | + |
1832 | + @credit_management_customer_2 |
1833 | + Scenario: Customer_2 |
1834 | + Given I need a "res.partner" with oid: scen.customer_2 |
1835 | + And having: |
1836 | + | name | value | |
1837 | + | name | customer_2 | |
1838 | + | credit_profile_id | by name: 2 time policy| |
1839 | + |
1840 | + @credit_management_customer_3 |
1841 | + Scenario: Customer_3 |
1842 | + Given I need a "res.partner" with oid: scen.customer_3 |
1843 | + And having: |
1844 | + | name | value | |
1845 | + | name | customer_3 | |
1846 | + | credit_profile_id | by name: 2 time policy| |
1847 | + |
1848 | + @credit_management_customer_4 |
1849 | + Scenario: Customer_4 |
1850 | + Given I need a "res.partner" with oid: scen.customer_4 |
1851 | + And having: |
1852 | + | name | value | |
1853 | + | name | customer_4 | |
1854 | + | credit_profile_id | by name: 3 time policy| |
1855 | + |
1856 | + @credit_management_customer_5 |
1857 | + Scenario: Customer_5 |
1858 | + Given I need a "res.partner" with oid: scen.customer_5 |
1859 | + And having: |
1860 | + | name | value | |
1861 | + | name | customer_5_usd | |
1862 | + | credit_profile_id | by name: 3 time policy| |
1863 | + |
1864 | + |
1865 | |
1866 | === added file 'account_credit_management/scenarios/credit_management/credit_management_01_data.feature' |
1867 | --- account_credit_management/scenarios/credit_management/credit_management_01_data.feature 1970-01-01 00:00:00 +0000 |
1868 | +++ account_credit_management/scenarios/credit_management/credit_management_01_data.feature 2012-10-15 10:14:35 +0000 |
1869 | @@ -0,0 +1,224 @@ |
1870 | +############################################################################### |
1871 | +# |
1872 | +# OERPScenario, OpenERP Functional Tests |
1873 | +# Copyright 2012 Camptocamp SA |
1874 | +# Author Nicolas Bessi |
1875 | +############################################################################## |
1876 | + |
1877 | +# Features Generic tags (none for all) |
1878 | +############################################################################## |
1879 | + |
1880 | +@credit_management_module @credit_management_base_data |
1881 | + |
1882 | +Feature: Ensure that mail credit management is correct |
1883 | + |
1884 | + |
1885 | + @credit_management_data |
1886 | + Scenario: Create data |
1887 | + Given I need a "ir.module.module" with name: account_credit_management |
1888 | + And having: |
1889 | + |name|value| |
1890 | + | demo | 1 | |
1891 | + Given I install the required modules with dependencies: |
1892 | + | name | |
1893 | + | account_credit_management | |
1894 | + Given I need a "res.partner" with oid: credit_management.trusted_partner |
1895 | + And having: |
1896 | + | name | value | |
1897 | + | name | Credit m. trusted partner | |
1898 | + | customer | 1 | |
1899 | + | credit_profile_id | by name: No follow | |
1900 | + |
1901 | + Given I need a "res.partner.address" with oid: credit_management.trusted_address |
1902 | + And having: |
1903 | + | name | value | |
1904 | + | name | Luc Maurer | |
1905 | + | zip | 1015 | |
1906 | + | city | lausanne | |
1907 | + | email | openerp@locahost.dummy | |
1908 | + | phone | +41 21 619 10 12 | |
1909 | + | street | PSE-A, EPF | |
1910 | + | partner_id | by oid: credit_management.trusted_partner | |
1911 | + |
1912 | + |
1913 | + Given I need a "res.partner" with oid: credit_management.not_so_trusted_partner |
1914 | + And having: |
1915 | + | name | value | |
1916 | + | name | Credit m. not so trusted partner | |
1917 | + | customer | 1 | |
1918 | + | credit_profile_id | by name: 2 time policy | |
1919 | + |
1920 | + Given I need a "res.partner.address" with oid: credit_management.not_so_trusted_address |
1921 | + And having: |
1922 | + | name | value | |
1923 | + | name | Not so trusted | |
1924 | + | zip | 1015 | |
1925 | + | city | lausanne | |
1926 | + | email | openerp@locahost.dummy | |
1927 | + | phone | +41 21 619 10 12 | |
1928 | + | street | PSE-A, EPF | |
1929 | + | partner_id | by oid: credit_management.not_so_trusted_partner | |
1930 | + |
1931 | + |
1932 | + Given I need a "res.partner" with oid: credit_management.untrusted_partner |
1933 | + And having: |
1934 | + | name | value | |
1935 | + | name | Credit m. untrusted partner | |
1936 | + | customer | 1 | |
1937 | + | credit_profile_id | by name: 3 time policy | |
1938 | + |
1939 | + Given I need a "res.partner.address" with oid: credit_management.untrusted_address |
1940 | + And having: |
1941 | + | name | value | |
1942 | + | name | Untrusted | |
1943 | + | zip | 1015 | |
1944 | + | city | lausanne | |
1945 | + | email | openerp@locahost.dummy | |
1946 | + | phone | +41 21 619 10 12 | |
1947 | + | street | PSE-A, EPF | |
1948 | + | partner_id | by oid: credit_management.untrusted_partner | |
1949 | + |
1950 | + |
1951 | + Given I need a "res.partner" with oid: credit_management.lambda_partner |
1952 | + And having: |
1953 | + | name | value | |
1954 | + | name | Credit m. lambda partner | |
1955 | + | customer | 1 | |
1956 | + |
1957 | + Given I need a "res.partner.address" with oid: credit_management.lambda_address |
1958 | + And having: |
1959 | + | name | value | |
1960 | + | name | Lambda | |
1961 | + | zip | 1015 | |
1962 | + | city | lausanne | |
1963 | + | email | openerp@locahost.dummy | |
1964 | + | phone | +41 21 619 10 12 | |
1965 | + | street | PSE-A, EPF | |
1966 | + | partner_id | by oid: credit_management.lambda_partner | |
1967 | + |
1968 | + |
1969 | + |
1970 | + @inv1 |
1971 | + Scenario: invoices |
1972 | + # trusted invoice on trusted partner no follow |
1973 | + Given I need a "account.invoice" with oid: credit_management.inv1 |
1974 | + And having: |
1975 | + | name | value | |
1976 | + | name | trusted invoice 1 | |
1977 | + | date_invoice | 2012-01-01 | |
1978 | + | date_due | 2012-02-15 | |
1979 | + | address_invoice_id | by oid: credit_management.trusted_address | |
1980 | + | partner_id | by oid: credit_management.trusted_partner | |
1981 | + | account_id | by name: Trusted Debtors - (test) | |
1982 | + | journal_id | by name: Sales Journal - (test) | |
1983 | + |
1984 | + |
1985 | + Given I need a "account.invoice.line" with oid: credit_management.inv_line1 |
1986 | + And having: |
1987 | + | name | value | |
1988 | + | name | trusted invoice line 1 | |
1989 | + | quantity | 1 | |
1990 | + | price_unit | 100 | |
1991 | + | account_id | by name: Product Sales - (test) | |
1992 | + | invoice_id | by oid: credit_management.inv1 | |
1993 | + Given I find a "account.invoice" with oid: credit_management.inv1 |
1994 | + And I open the credit invoice |
1995 | + |
1996 | + |
1997 | + |
1998 | + Given I need a "account.invoice" with oid: credit_management.inv2 |
1999 | + And having: |
2000 | + | name | value | |
2001 | + | name | lambda invoice 1 | |
2002 | + | date_invoice | 2012-01-01 | |
2003 | + | date_due | 2012-02-15 | |
2004 | + | address_invoice_id | by oid: credit_management.lambda_address | |
2005 | + | partner_id | by oid: credit_management.lambda_partner | |
2006 | + | account_id | by name: Not so trusted Debtors - (test) | |
2007 | + | journal_id | by name: Sales Journal - (test) | |
2008 | + |
2009 | + Given I need a "account.invoice.line" with oid: credit_management.inv_line2 |
2010 | + And having: |
2011 | + | name | value | |
2012 | + | name | lambda invoice line 1 | |
2013 | + | quantity | 1 | |
2014 | + | price_unit | 130 | |
2015 | + | account_id | by name: Product Sales - (test) | |
2016 | + | invoice_id | by oid: credit_management.inv2 | |
2017 | + Given I find a "account.invoice" with oid: credit_management.inv2 |
2018 | + And I open the credit invoice |
2019 | + |
2020 | + |
2021 | + Given I need a "account.invoice" with oid: credit_management.inv3 |
2022 | + And having: |
2023 | + | name | value | |
2024 | + | name | Not so trusted invoice | |
2025 | + | date_invoice | 2012-01-01 | |
2026 | + | date_due | 2012-02-15 | |
2027 | + | address_invoice_id | by oid: credit_management.not_so_trusted_address | |
2028 | + | partner_id | by oid: credit_management.not_so_trusted_partner | |
2029 | + | account_id | by name: Not so trusted Debtors - (test) | |
2030 | + | journal_id | by name: Sales Journal - (test) | |
2031 | + |
2032 | + |
2033 | + Given I need a "account.invoice.line" with oid: credit_management.inv_line3 |
2034 | + And having: |
2035 | + | name | value | |
2036 | + | name | Not so trusted invoice line 1 | |
2037 | + | quantity | 1 | |
2038 | + | price_unit | 150 | |
2039 | + | account_id | by name: Product Sales - (test) | |
2040 | + | invoice_id | by oid: credit_management.inv3 | |
2041 | + Given I find a "account.invoice" with oid: credit_management.inv3 |
2042 | + And I open the credit invoice |
2043 | + |
2044 | + |
2045 | + |
2046 | + |
2047 | + Given I need a "account.invoice" with oid: credit_management.inv4 |
2048 | + And having: |
2049 | + | name | value | |
2050 | + | name | Untrusted invoice | |
2051 | + | date_invoice | 2012-01-01 | |
2052 | + | date_due | 2012-02-15 | |
2053 | + | address_invoice_id | by oid: credit_management.untrusted_address | |
2054 | + | partner_id | by oid: credit_management.untrusted_partner | |
2055 | + | account_id | by name: Not so trusted Debtors - (test) | |
2056 | + | journal_id | by name: Sales Journal - (test) | |
2057 | + |
2058 | + |
2059 | + Given I need a "account.invoice.line" with oid: credit_management.inv_line4 |
2060 | + And having: |
2061 | + | name | value | |
2062 | + | name | Un trusted invoice line 1 | |
2063 | + | quantity | 1 | |
2064 | + | price_unit | 170 | |
2065 | + | account_id | by name: Product Sales - (test) | |
2066 | + | invoice_id | by oid: credit_management.inv4 | |
2067 | + Given I find a "account.invoice" with oid: credit_management.inv4 |
2068 | + And I open the credit invoice |
2069 | + |
2070 | + |
2071 | + Given I need a "account.invoice" with oid: credit_management.inv5 |
2072 | + And having: |
2073 | + | name | value | |
2074 | + | name | lamba invoice with untrusted policy | |
2075 | + | date_invoice | 2012-01-01 | |
2076 | + | date_due | 2012-02-15 | |
2077 | + | address_invoice_id | by oid: credit_management.lambda_address | |
2078 | + | partner_id | by oid: credit_management.lambda_partner | |
2079 | + | account_id | by name: Not so trusted Debtors - (test) | |
2080 | + | journal_id | by name: Sales Journal - (test) | |
2081 | + | credit_profile_id | by name: 3 time policy | |
2082 | + |
2083 | + |
2084 | + Given I need a "account.invoice.line" with oid: credit_management.inv_line5 |
2085 | + And having: |
2086 | + | name | value | |
2087 | + | name | Un trusted invoice line 1 | |
2088 | + | quantity | 1 | |
2089 | + | price_unit | 200 | |
2090 | + | account_id | by name: Product Sales - (test) | |
2091 | + | invoice_id | by oid: credit_management.inv5 | |
2092 | + Given I find a "account.invoice" with oid: credit_management.inv5 |
2093 | + And I open the credit invoice |
2094 | |
2095 | === added file 'account_credit_management/scenarios/credit_management/credit_management_02_run.feature' |
2096 | --- account_credit_management/scenarios/credit_management/credit_management_02_run.feature 1970-01-01 00:00:00 +0000 |
2097 | +++ account_credit_management/scenarios/credit_management/credit_management_02_run.feature 2012-10-15 10:14:35 +0000 |
2098 | @@ -0,0 +1,33 @@ |
2099 | +############################################################################### |
2100 | +# |
2101 | +# OERPScenario, OpenERP Functional Tests |
2102 | +# Copyright 2012 Camptocamp SA |
2103 | +# Author Nicolas Bessi |
2104 | +############################################################################## |
2105 | + |
2106 | +# Features Generic tags (none for all) |
2107 | +############################################################################## |
2108 | + |
2109 | +@credit_management_module |
2110 | + |
2111 | +Feature: Ensure that mail credit line generation first pass is correct |
2112 | + |
2113 | + |
2114 | + @credit_management_first_run |
2115 | + Scenario: clean data |
2116 | + Given I clean all the credit lines |
2117 | + #Given I unreconcile and clean all move line |
2118 | + |
2119 | + @credit_management_first_run |
2120 | + Scenario: Create run |
2121 | + Given I need a "credit.management.run" with oid: credit_management.run1 |
2122 | + And having: |
2123 | + | name | value | |
2124 | + | date | 2012-03-01 | |
2125 | + When I launch the credit run |
2126 | + Then my credit run should be in state "done" |
2127 | + And I should have "2" credit lines of level "1" |
2128 | + And credit lines should have following values: |
2129 | + | balance | date due | account | profile | date | partner | canal | level | move line | profile rule | state | amount due | currency | |
2130 | + | 170 | 2012-02-15 | B2C Debtors - (test) | 3 time policy | 2012-03-01 | Credit m. untrusted partner | mail | 1.00 | Untrusted invoice | 10 days net | draft | 170 | | |
2131 | + | 200 | 2012-02-15 | B2C Debtors - (test) | 3 time policy | 2012-03-01 | Credit m. lambda partner | mail | 1.00 | lamba invoice with untrusted policy | 10 days net | draft | 200 | | |
2132 | |
2133 | === added file 'account_credit_management/scenarios/credit_management/credit_management_03_run.feature' |
2134 | --- account_credit_management/scenarios/credit_management/credit_management_03_run.feature 1970-01-01 00:00:00 +0000 |
2135 | +++ account_credit_management/scenarios/credit_management/credit_management_03_run.feature 2012-10-15 10:14:35 +0000 |
2136 | @@ -0,0 +1,26 @@ |
2137 | +############################################################################### |
2138 | +# |
2139 | +# OERPScenario, OpenERP Functional Tests |
2140 | +# Copyright 2012 Camptocamp SA |
2141 | +# Author Nicolas Bessi |
2142 | +############################################################################## |
2143 | + |
2144 | +# Features Generic tags (none for all) |
2145 | +############################################################################## |
2146 | + |
2147 | +@credit_management_mark_mail |
2148 | + |
2149 | +Feature: Ensure that mail credit line generation first pass is correct |
2150 | + |
2151 | + |
2152 | + @credit_management_mark |
2153 | + Scenario: mark lines |
2154 | + Given there is "draft" credit lines |
2155 | + And I mark all draft mail to state "to_be_sent" |
2156 | + Then the draft line should be in state "to_be_sent" |
2157 | + |
2158 | + @credit_management_mail |
2159 | + Scenario: mail lines |
2160 | + Given there is "to_be_sent" credit lines |
2161 | + And I mail all ready lines |
2162 | + Then All sent lines should be linked to a mail and in mail status "sent" |
2163 | |
2164 | === added directory 'account_credit_management/scenarios/credit_management/step_definitions' |
2165 | === added file 'account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb' |
2166 | --- account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb 1970-01-01 00:00:00 +0000 |
2167 | +++ account_credit_management/scenarios/credit_management/step_definitions/credit_management.rb 2012-10-15 10:14:35 +0000 |
2168 | @@ -0,0 +1,115 @@ |
2169 | +# Given /^I open the credit invoice$/ do |
2170 | +# @found_item.should_not be_nil, |
2171 | +# "no invoice found" |
2172 | +# ['draft', 'open'].should include(@found_item.state), |
2173 | +# "Invoice is not draf or open" |
2174 | +# if @found_item.state == 'draft' |
2175 | +# @found_item.wkf_action('invoice_open') |
2176 | +# end |
2177 | +# end |
2178 | + |
2179 | +Then /^I launch the credit run$/ do |
2180 | + @found_item.should_not be_nil, |
2181 | + "no run found" |
2182 | + @found_item.generate_credit_lines() |
2183 | +end |
2184 | + |
2185 | +Given /^there is "(.*?)" credit lines$/ do |state| |
2186 | + @credit_lines = CreditManagementLine.find_all_by_state(state) |
2187 | + @credit_lines.should_not be_empty, |
2188 | + "not #{state} lines found" |
2189 | +end |
2190 | + |
2191 | +Given /^I mark all draft mail to state "(.*?)"$/ do | state | |
2192 | + wiz = CreditManagementMarker.new |
2193 | + wiz.name = state |
2194 | + wiz.mark_all = true |
2195 | + wiz.save |
2196 | + wiz.mark_lines |
2197 | +end |
2198 | + |
2199 | +Then /^the draft line should be in state "(.*?)"$/ do | state | |
2200 | + @credit_lines.should_not be_nil, |
2201 | + "no line where stored" |
2202 | + @credit_lines.each do |line| |
2203 | + line = CreditManagementLine.find(line.id) |
2204 | + line.state.should eql(state), |
2205 | + "The line #{line.id} is not in state #{state} he is is in state #{line.state} " |
2206 | + end |
2207 | + |
2208 | +end |
2209 | + |
2210 | +Given /^I mail all ready lines$/ do |
2211 | + @credit_lines.should_not be_nil, |
2212 | + "no line where stored" |
2213 | + wiz = CreditManagementMailer.new |
2214 | + wiz.mail_all = true |
2215 | + wiz.save |
2216 | + wiz.mail_lines |
2217 | +end |
2218 | + |
2219 | +Given /^I clean all the credit lines$/ do |
2220 | + CreditManagementLine.find(:all).each do | line | |
2221 | + line.destroy |
2222 | + end |
2223 | +end |
2224 | + |
2225 | +Then /^my credit run should be in state "(.*?)"$/ do |state| |
2226 | + @found_item.should_not be nil |
2227 | + @run = CreditManagementRun.find(@found_item.id) |
2228 | + @run.state.should eq(state), |
2229 | + "Run state is in state #{@run.state} instead of #{state}" |
2230 | +end |
2231 | + |
2232 | + |
2233 | +Then /^All sent lines should be linked to a mail and in mail status "(.*?)"$/ do |status| |
2234 | + @credit_lines.should_not be_nil, |
2235 | + "no line where stored" |
2236 | + @credit_lines.each do |line| |
2237 | + line = CreditManagementLine.find(line.id) |
2238 | + line.state.should eql(status), |
2239 | + "The line #{line.id} is has no mail status #{status} but #{line.state}" |
2240 | + end |
2241 | +end |
2242 | + |
2243 | +Then /^I should have "(.*?)" credit lines of level "(.*?)"$/ do |number, level| |
2244 | + CreditManagementLine.find_all_by_level(level).length.should eq (number.to_i) |
2245 | +end |
2246 | + |
2247 | +Then /^credit lines should have following values:$/ do |table| |
2248 | + h_list = table.hashes |
2249 | + h_list.each do | h | |
2250 | + h.delete_if {|k, v| v.empty?} |
2251 | + end |
2252 | + errors = [] |
2253 | + h_list.each do | row | |
2254 | + account = AccountAccount.find_by_name(row['account'], :fields=>['id']) |
2255 | + account.should_not be_nil, "no account named #{row['account']} found" |
2256 | + |
2257 | + profile = CreditManagementProfile.find_by_name(row['profile'], :fields=>['id']) |
2258 | + profile.should_not be_nil, "No account #{row['account']} found" |
2259 | + |
2260 | + partner = ResPartner.find_by_name(row['partner'], :fields=>['id']) |
2261 | + partner.should_not be_nil, "No partner #{row['partner']} found" |
2262 | + |
2263 | + move_line = AccountMoveLine.find_by_name(row['move line'], :fields=>['id']) |
2264 | + move_line.should_not be_nil, "No move line #{row['move line']} found" |
2265 | + |
2266 | + rule = CreditManagementProfileRule.find_by_name(row['profile rule'], :fields=>['id']) |
2267 | + rule.should_not be_nil, "No profile rune #{row['profile rule']} found" |
2268 | + |
2269 | + domain = [['account_id', '=', account.id], ['profile_id', '=', profile.id], |
2270 | + ['partner_id', '=', partner.id], ['move_line_id', '=', move_line.id], |
2271 | + ['profile_rule_id', '=', rule.id], ['amount_due', '=', row.fetch('amount due', 0.0)], |
2272 | + ['state', '=', row.fetch('state')], ['level', '=', row.fetch('level', 0.0)], |
2273 | + ['canal', '=', row.fetch('canal')], ['balance_due', '=', row.fetch('balance', 0.0)], |
2274 | + ['date_due', '=', row.fetch('date due')], ['date', '=', row.fetch('date')]] |
2275 | + if row['currency'] |
2276 | + curreny = ResCurrency.find_by_name(row['currency'], :fields=>['id']) |
2277 | + domain.push ['currency_id', '=', curreny.id] |
2278 | + end |
2279 | + pp domain |
2280 | + line = CreditManagementLine.find(:first, :domain=>domain) |
2281 | + line.should_not be_nil, "Can not find line #{row.inspect}" |
2282 | + end |
2283 | +end |
2284 | |
2285 | === added file 'account_credit_management/scenarios/run_command.txt' |
2286 | --- account_credit_management/scenarios/run_command.txt 1970-01-01 00:00:00 +0000 |
2287 | +++ account_credit_management/scenarios/run_command.txt 2012-10-15 10:14:35 +0000 |
2288 | @@ -0,0 +1,1 @@ |
2289 | +cucumber CONF=nbessi.conf --tags=@credit_management_first_run features /opt/openerp_geoengine/src/c2c-financial-addons/account_credit_management/scenarios/ |
2290 | |
2291 | === added directory 'account_credit_management/security' |
2292 | === added file 'account_credit_management/security/ir.model.access.csv' |
2293 | --- account_credit_management/security/ir.model.access.csv 1970-01-01 00:00:00 +0000 |
2294 | +++ account_credit_management/security/ir.model.access.csv 2012-10-15 10:14:35 +0000 |
2295 | @@ -0,0 +1,27 @@ |
2296 | +"id","perm_create","perm_unlink","group_id/id","name","model_id/id","perm_read","perm_write" |
2297 | +"account_credit_management.ir_model_access_270",1,1,"group_account_credit_management_manager","credit_management_manager_line","account_credit_management.model_credit_management_line",1,1 |
2298 | +"account_credit_management.ir_model_access_271",1,1,"group_account_credit_management_user","credit_management_user_line","account_credit_management.model_credit_management_line",1,1 |
2299 | +"account_credit_management.ir_model_access_272",0,0,"group_account_credit_management_info","credit_management_info_line","account_credit_management.model_credit_management_line",1,0 |
2300 | +"account_credit_management.ir_model_access_273",1,1,"group_account_credit_management_manager","credit_management_manager_mail_template","email_template.model_email_template",1,1 |
2301 | +"account_credit_management.ir_model_access_274",1,1,"group_account_credit_management_manager","credit_management_manager_mail_template_preview","email_template.model_email_template_preview",1,1 |
2302 | +"account_credit_management.ir_model_access_275",1,1,"group_account_credit_management_manager","credit_management_manager_mail_message","mail.model_mail_message",1,1 |
2303 | +"account_credit_management.ir_model_access_276",1,0,"group_account_credit_management_user","credit_management_user_mail_message","mail.model_mail_message",1,1 |
2304 | +"account_credit_management.ir_model_access_277",0,0,"group_account_credit_management_info","credit_management_info_mail_message","mail.model_mail_message",1,0 |
2305 | +"account_credit_management.ir_model_access_278",1,1,"group_account_credit_management_manager","credit_management_manager_comm","account_credit_management.model_credit_management_communication",1,1 |
2306 | +"account_credit_management.ir_model_access_279",1,1,"base.group_sale_salesman","credit_management_user_comm","account_credit_management.model_credit_management_communication",1,1 |
2307 | +"account_credit_management.ir_model_access_280",0,0,"group_account_credit_management_info","credit_management_info_comm","account_credit_management.model_credit_management_communication",1,0 |
2308 | +"account_credit_management.ir_model_access_281",1,1,"group_account_credit_management_manager","credit_management_mananger_run","account_credit_management.model_credit_management_run",1,1 |
2309 | +"account_credit_management.ir_model_access_282",1,1,"group_account_credit_management_user","credit_management_user_run","account_credit_management.model_credit_management_run",1,1 |
2310 | +"account_credit_management.ir_model_access_283",0,0,"group_account_credit_management_info","credit_management_info_run","account_credit_management.model_credit_management_run",1,0 |
2311 | +"account_credit_management.ir_model_access_284",1,1,"group_account_credit_management_manager","credit_management_manager_profile","account_credit_management.model_credit_management_profile",1,1 |
2312 | +"account_credit_management.ir_model_access_285",0,0,"group_account_credit_management_user","credit_management_user_profile","account_credit_management.model_credit_management_profile",1,0 |
2313 | +"account_credit_management.ir_model_access_286",0,0,"group_account_credit_management_info","credit_management_info_profile","account_credit_management.model_credit_management_profile",1,0 |
2314 | +"account_credit_management.ir_model_access_287",1,1,"group_account_credit_management_manager","credit_management_manager_rule","account_credit_management.model_credit_management_profile_rule",1,1 |
2315 | +"account_credit_management.ir_model_access_288",0,0,"group_account_credit_management_user","credit_management_user_rule","account_credit_management.model_credit_management_profile_rule",1,0 |
2316 | +"account_credit_management.ir_model_access_289",0,0,"group_account_credit_management_info","credit_management_info_rule","account_credit_management.model_credit_management_profile_rule",1,0 |
2317 | +"account_credit_management.ir_model_access_290",1,1,"group_account_credit_management_manager","credit_management_manager_mailer","account_credit_management.model_credit_management_mailer",1,1 |
2318 | +"account_credit_management.ir_model_access_291",1,1,"group_account_credit_management_user","credit_management_user_mailer","account_credit_management.model_credit_management_mailer",1,1 |
2319 | +"account_credit_management.ir_model_access_292",1,1,"group_account_credit_management_manager","credit_management_manager_marker","account_credit_management.model_credit_management_marker",1,1 |
2320 | +"account_credit_management.ir_model_access_293",1,1,"group_account_credit_management_user","credit_management_user_marker","account_credit_management.model_credit_management_marker",1,1 |
2321 | +"account_credit_management.ir_model_access_294",1,1,"group_account_credit_management_manager","credit_management_manager_printer","account_credit_management.model_credit_management_printer",1,1 |
2322 | +"account_credit_management.ir_model_access_295",1,1,"group_account_credit_management_user","credit_management_user_printer","account_credit_management.model_credit_management_printer",1,1 |
2323 | |
2324 | === added directory 'account_credit_management/wizard' |
2325 | === added file 'account_credit_management/wizard/__init__.py' |
2326 | --- account_credit_management/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
2327 | +++ account_credit_management/wizard/__init__.py 2012-10-15 10:14:35 +0000 |
2328 | @@ -0,0 +1,24 @@ |
2329 | +# -*- coding: utf-8 -*- |
2330 | +############################################################################## |
2331 | +# |
2332 | +# Author: Nicolas Bessi |
2333 | +# Copyright 2012 Camptocamp SA |
2334 | +# |
2335 | +# This program is free software: you can redistribute it and/or modify |
2336 | +# it under the terms of the GNU Affero General Public License as |
2337 | +# published by the Free Software Foundation, either version 3 of the |
2338 | +# License, or (at your option) any later version. |
2339 | +# |
2340 | +# This program is distributed in the hope that it will be useful, |
2341 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2342 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2343 | +# GNU Affero General Public License for more details. |
2344 | +# |
2345 | +# You should have received a copy of the GNU Affero General Public License |
2346 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2347 | +# |
2348 | +############################################################################## |
2349 | +from . import credit_management_mailer |
2350 | +from . import credit_management_marker |
2351 | +from . import credit_management_printer |
2352 | +from . import credit_management_communication |
2353 | |
2354 | === added file 'account_credit_management/wizard/credit_management_communication.py' |
2355 | --- account_credit_management/wizard/credit_management_communication.py 1970-01-01 00:00:00 +0000 |
2356 | +++ account_credit_management/wizard/credit_management_communication.py 2012-10-15 10:14:35 +0000 |
2357 | @@ -0,0 +1,178 @@ |
2358 | +# -*- coding: utf-8 -*- |
2359 | +############################################################################## |
2360 | +# |
2361 | +# Author: Nicolas Bessi |
2362 | +# Copyright 2012 Camptocamp SA |
2363 | +# |
2364 | +# This program is free software: you can redistribute it and/or modify |
2365 | +# it under the terms of the GNU Affero General Public License as |
2366 | +# published by the Free Software Foundation, either version 3 of the |
2367 | +# License, or (at your option) any later version. |
2368 | +# |
2369 | +# This program is distributed in the hope that it will be useful, |
2370 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2371 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2372 | +# GNU Affero General Public License for more details. |
2373 | +# |
2374 | +# You should have received a copy of the GNU Affero General Public License |
2375 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2376 | +# |
2377 | +############################################################################## |
2378 | +from openerp.osv.orm import TransientModel, fields |
2379 | +from openerp.osv.osv import except_osv |
2380 | +from openerp.tools.translate import _ |
2381 | +import netsvc |
2382 | +import logging |
2383 | + |
2384 | +logger = logging.getLogger('credit.line.management mailing') |
2385 | + |
2386 | + |
2387 | +class CreditCommunication(TransientModel): |
2388 | + """Shell calss used to provide a base model to email template and reporting. |
2389 | + Il use this approche in version 7 a browse record will exist even if not saved""" |
2390 | + _name = "credit.management.communication" |
2391 | + _description = "credit management communication" |
2392 | + _rec_name = 'partner_id' |
2393 | + _columns = {'partner_id': fields.many2one('res.partner', 'Partner', required=True), |
2394 | + |
2395 | + 'current_profile_rule': fields.many2one('credit.management.profile.rule', |
2396 | + 'Rule', required=True), |
2397 | + |
2398 | + 'credit_lines': fields.many2many('credit.management.line', |
2399 | + rel='comm_credit_rel', |
2400 | + string='Credit Lines'), |
2401 | + |
2402 | + 'company_id': fields.many2one('res.company', 'Company', |
2403 | + required=True), |
2404 | + |
2405 | + 'user_id': fields.many2one('res.users', 'User')} |
2406 | + |
2407 | + _defaults = {'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get( |
2408 | + cr, uid, 'credit.management.profile', context=c), |
2409 | + 'user_id': lambda s, cr, uid, c: uid} |
2410 | + |
2411 | + def get_address(self, cursor, uid, com_id, context=None): |
2412 | + """Return a valid address for customer""" |
2413 | + |
2414 | + context = context or {} |
2415 | + if isinstance(com_id, list): |
2416 | + com_id = com_id[0] |
2417 | + current = self.browse(cursor, uid, com_id, context=context) |
2418 | + part_obj = self.pool.get('res.partner') |
2419 | + adds = part_obj.address_get(cursor, uid, [current.partner_id.id], |
2420 | + adr_pref=['invoice', 'default']) |
2421 | + |
2422 | + add = adds.get('invoice', adds.get('default')) |
2423 | + if not add: |
2424 | + raise except_osv(_('No address for partner %s') % (current.partner_id.name), |
2425 | + _('Please set one')) |
2426 | + add_obj = self.pool.get('res.partner.address') |
2427 | + return add_obj.browse(cursor, uid, add, context=context) |
2428 | + |
2429 | + |
2430 | + def get_mail(self, cursor, uid, com_id, context=None): |
2431 | + """Return a valid email for customer""" |
2432 | + context = context or {} |
2433 | + if isinstance(com_id, list): |
2434 | + com_id = com_id[0] |
2435 | + current = self.browse(cursor, uid, com_id, context=context) |
2436 | + email = current.get_address().email |
2437 | + if not email: |
2438 | + raise except_osv(_('No invoicing or default email for partner %s') % |
2439 | + (current.partner_id.name), |
2440 | + _('Please set one')) |
2441 | + return email |
2442 | + |
2443 | + def _get_credit_lines(self, cursor, uid, line_ids, partner_id, rule_id, context=None): |
2444 | + """Return credit lines related to a partner and a profile rule""" |
2445 | + cr_line_obj = self.pool.get('credit.management.line') |
2446 | + cr_l_ids = cr_line_obj.search(cursor, |
2447 | + uid, |
2448 | + [('id', 'in', line_ids), |
2449 | + ('partner_id', '=', partner_id), |
2450 | + ('profile_rule_id', '=', rule_id)], |
2451 | + context=context) |
2452 | + #return cr_line_obj.browse(cursor, uid, cr_l_ids, context=context) |
2453 | + return cr_l_ids |
2454 | + |
2455 | + def _generate_comm_from_credit_line_ids(self, cursor, uid, line_ids, context=None): |
2456 | + if not line_ids: |
2457 | + return [] |
2458 | + comms = [] |
2459 | + sql = ("SELECT distinct partner_id, profile_rule_id, credit_management_profile_rule.level" |
2460 | + " FROM credit_management_line JOIN credit_management_profile_rule " |
2461 | + " ON (credit_management_line.profile_rule_id = credit_management_profile_rule.id)" |
2462 | + " WHERE credit_management_line.id in %s" |
2463 | + " ORDER by credit_management_profile_rule.level") |
2464 | + |
2465 | + cursor.execute(sql, (tuple(line_ids),)) |
2466 | + res = cursor.dictfetchall() |
2467 | + for rule_assoc in res: |
2468 | + data = {} |
2469 | + data['credit_lines'] = [(6, 0, self._get_credit_lines(cursor, uid, line_ids, |
2470 | + rule_assoc['partner_id'], |
2471 | + rule_assoc['profile_rule_id'], |
2472 | + context=context))] |
2473 | + data['partner_id'] = rule_assoc['partner_id'] |
2474 | + data['current_profile_rule'] = rule_assoc['profile_rule_id'] |
2475 | + comm_id = self.create(cursor, uid, data, context=context) |
2476 | + |
2477 | + |
2478 | + comms.append(self.browse(cursor, uid, comm_id, context=context)) |
2479 | + return comms |
2480 | + |
2481 | + def _generate_mails(self, cursor, uid, comms, context=None): |
2482 | + """Generate mail message using template related to rule""" |
2483 | + cr_line_obj = self.pool.get('credit.management.line') |
2484 | + mail_temp_obj = self.pool.get('email.template') |
2485 | + mail_message_obj = self.pool.get('mail.message') |
2486 | + mail_ids = [] |
2487 | + for comm in comms: |
2488 | + # we want to use a local cursor in order to send the maximum |
2489 | + # of email |
2490 | + try: |
2491 | + template = comm.current_profile_rule.mail_template_id.id |
2492 | + |
2493 | + mvalues = mail_temp_obj.generate_email(cursor, uid, |
2494 | + template, |
2495 | + comm.id, |
2496 | + context=context) |
2497 | + essential_values = ['subject', 'body_html', |
2498 | + 'email_from', 'email_to'] |
2499 | + for val in essential_values: |
2500 | + if not mvalues.get(val): |
2501 | + raise Exception('Mail generation error with %s', val) |
2502 | + mail_id = mail_message_obj.create(cursor, uid, mvalues, context=context) |
2503 | + |
2504 | + cl_ids = [cl.id for cl in comm.credit_lines] |
2505 | + |
2506 | + # we do not use local cusros else we have a lock |
2507 | + cr_line_obj.write(cursor, uid, cl_ids, |
2508 | + {'mail_message_id': mail_id, |
2509 | + 'state': 'sent'}) |
2510 | + mail_ids.append(mail_id) |
2511 | + except Exception, exc: |
2512 | + logger.error(exc) |
2513 | + cursor.rollback() |
2514 | + cl_ids = [cl.id for cl in comm.credit_lines] |
2515 | + # we do not use local cusros else we have a lock |
2516 | + cr_line_obj.write(cursor, uid, cl_ids, |
2517 | + {'state': 'mail_error'}) |
2518 | + finally: |
2519 | + cursor.commit() |
2520 | + return mail_ids |
2521 | + |
2522 | + def _generate_report(self, cursor, uid, comms, context=None): |
2523 | + """Will generate a report by inserting mako template of related profile template""" |
2524 | + service = netsvc.LocalService('report.credit_management_summary') |
2525 | + ids = [x.id for x in comms] |
2526 | + result, format = service.create(cursor, uid, ids, {}, {}) |
2527 | + return result |
2528 | + |
2529 | + def _mark_credit_line_as_sent(self, cursor, uid, comms, context=None): |
2530 | + line_ids = [] |
2531 | + for comm in comms: |
2532 | + line_ids += [x.id for x in comm.credit_lines] |
2533 | + l_obj = self.pool.get('credit.management.line') |
2534 | + l_obj.write(cursor, uid, line_ids, {'state': 'sent'}, context=context) |
2535 | + return line_ids |
2536 | |
2537 | === added file 'account_credit_management/wizard/credit_management_mailer.py' |
2538 | --- account_credit_management/wizard/credit_management_mailer.py 1970-01-01 00:00:00 +0000 |
2539 | +++ account_credit_management/wizard/credit_management_mailer.py 2012-10-15 10:14:35 +0000 |
2540 | @@ -0,0 +1,64 @@ |
2541 | +# -*- coding: utf-8 -*- |
2542 | +############################################################################## |
2543 | +# |
2544 | +# Author: Nicolas Bessi |
2545 | +# Copyright 2012 Camptocamp SA |
2546 | +# |
2547 | +# This program is free software: you can redistribute it and/or modify |
2548 | +# it under the terms of the GNU Affero General Public License as |
2549 | +# published by the Free Software Foundation, either version 3 of the |
2550 | +# License, or (at your option) any later version. |
2551 | +# |
2552 | +# This program is distributed in the hope that it will be useful, |
2553 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2554 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2555 | +# GNU Affero General Public License for more details. |
2556 | +# |
2557 | +# You should have received a copy of the GNU Affero General Public License |
2558 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2559 | +# |
2560 | +############################################################################## |
2561 | +from openerp.osv.orm import TransientModel, fields |
2562 | +from openerp.osv.osv import except_osv |
2563 | +from openerp.tools.translate import _ |
2564 | + |
2565 | +class CreditManagementMailer(TransientModel): |
2566 | + """Change the state of lines in mass""" |
2567 | + |
2568 | + _name = "credit.management.mailer" |
2569 | + _description = """Mass credit line mailer""" |
2570 | + _rec_name = 'id' |
2571 | + |
2572 | + _columns = {'mail_all': fields.boolean('Mail all ready lines')} |
2573 | + |
2574 | + |
2575 | + def _get_lids(self, cursor, uid, mail_all, active_ids, context=None): |
2576 | + """get line to be marked filter done lines""" |
2577 | + # TODO DRY with printer |
2578 | + line_obj = self.pool.get('credit.management.line') |
2579 | + if mail_all: |
2580 | + domain = [('state', '=', 'to_be_sent'), |
2581 | + ('canal', '=', 'mail')] |
2582 | + else: |
2583 | + domain = [('state', '=', 'to_be_sent'), |
2584 | + ('id', 'in', active_ids), |
2585 | + ('canal', '=', 'mail')] |
2586 | + return line_obj.search(cursor, uid, domain, context=context) |
2587 | + |
2588 | + |
2589 | + def mail_lines(self, cursor, uid, wiz_id, context=None): |
2590 | + comm_obj = self.pool.get('credit.management.communication') |
2591 | + context = context or {} |
2592 | + if isinstance(wiz_id, list): |
2593 | + wiz_id = wiz_id[0] |
2594 | + current = self.browse(cursor, uid, wiz_id, context) |
2595 | + lines_ids = context.get('active_ids') |
2596 | + |
2597 | + if not lines_ids and not current.mail_all: |
2598 | + raise except_osv(_('Not lines ids are selected'), |
2599 | + _('You may check "Mail all ready lines"')) |
2600 | + filtered_ids = self._get_lids(cursor, uid, current.mail_all, lines_ids, context) |
2601 | + comms = comm_obj._generate_comm_from_credit_line_ids(cursor, uid, filtered_ids, |
2602 | + context=context) |
2603 | + comm_obj._generate_mails(cursor, uid, comms, context=context) |
2604 | + return {} |
2605 | |
2606 | === added file 'account_credit_management/wizard/credit_management_mailer_view.xml' |
2607 | --- account_credit_management/wizard/credit_management_mailer_view.xml 1970-01-01 00:00:00 +0000 |
2608 | +++ account_credit_management/wizard/credit_management_mailer_view.xml 2012-10-15 10:14:35 +0000 |
2609 | @@ -0,0 +1,44 @@ |
2610 | +<openerp> |
2611 | + <data> |
2612 | + |
2613 | + <record id="credit_line_mailer_form" model="ir.ui.view"> |
2614 | + <field name="name">credit.line.mailer.form</field> |
2615 | + <field name="model">credit.management.mailer</field> |
2616 | + <field name="type">form</field> |
2617 | + <field name="arch" type="xml"> |
2618 | + <form> <!-- editable="bottom" --> |
2619 | + <separator string="Mail selected lines. Sucessfuly mailed lines will be in state done. Related email will be linked to the line" colspan="4"/> |
2620 | + <newline/> |
2621 | + <field name="mail_all" colspan="4"/> |
2622 | + <newline/> |
2623 | + <group colspan="4"> |
2624 | + <button name="mail_lines" string="Mail lines" type="object" icon="gtk-execute"/> |
2625 | + <button special="cancel" string="Cancel" icon='gtk-cancel'/> |
2626 | + </group> |
2627 | + </form> |
2628 | + </field> |
2629 | + </record> |
2630 | + |
2631 | + <!-- for menu --> |
2632 | + <act_window name="Mail lines" |
2633 | + res_model="credit.management.mailer" |
2634 | + src_model="credit.management.line" |
2635 | + view_mode="form" |
2636 | + target="new" |
2637 | + key2="client_action_multi" |
2638 | + id="open_credit_line_mailer_wizard_menu_action"/> |
2639 | + |
2640 | + <!-- for button --> |
2641 | + <record id="open_credit_line_mailer_wizard" model="ir.actions.act_window"> |
2642 | + <field name="name">Mail lines</field> |
2643 | + <field name="res_model">credit.management.mailer</field> |
2644 | + <field name="view_type">form</field> |
2645 | + <field name="view_mode">form</field> |
2646 | + <field name="view_id" ref="credit_line_mailer_form"/> |
2647 | + <field name="target">new</field> |
2648 | + <field name="help">Mail all marked lines</field> |
2649 | + </record> |
2650 | + |
2651 | + |
2652 | + </data> |
2653 | +</openerp> |
2654 | |
2655 | === added file 'account_credit_management/wizard/credit_management_marker.py' |
2656 | --- account_credit_management/wizard/credit_management_marker.py 1970-01-01 00:00:00 +0000 |
2657 | +++ account_credit_management/wizard/credit_management_marker.py 2012-10-15 10:14:35 +0000 |
2658 | @@ -0,0 +1,83 @@ |
2659 | +# -*- coding: utf-8 -*- |
2660 | +############################################################################## |
2661 | +# |
2662 | +# Author: Nicolas Bessi |
2663 | +# Copyright 2012 Camptocamp SA |
2664 | +# |
2665 | +# This program is free software: you can redistribute it and/or modify |
2666 | +# it under the terms of the GNU Affero General Public License as |
2667 | +# published by the Free Software Foundation, either version 3 of the |
2668 | +# License, or (at your option) any later version. |
2669 | +# |
2670 | +# This program is distributed in the hope that it will be useful, |
2671 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2672 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2673 | +# GNU Affero General Public License for more details. |
2674 | +# |
2675 | +# You should have received a copy of the GNU Affero General Public License |
2676 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2677 | +# |
2678 | +############################################################################## |
2679 | +from openerp.osv.orm import TransientModel, fields |
2680 | +from openerp.osv.osv import except_osv |
2681 | +from openerp.tools.translate import _ |
2682 | + |
2683 | +class CreditManagementMarker(TransientModel): |
2684 | + """Change the state of lines in mass""" |
2685 | + |
2686 | + _name = "credit.management.marker" |
2687 | + _description = """Mass marker""" |
2688 | + _columns = {'name': fields.selection([('to_be_sent', 'To be sent'), |
2689 | + ('sent', 'Done')], |
2690 | + 'Mark as', required=True), |
2691 | + |
2692 | + 'mark_all': fields.boolean('Mark all draft lines')} |
2693 | + |
2694 | + _defaults = {'name': 'to_be_sent'} |
2695 | + |
2696 | + def _get_lids(self, cursor, uid, mark_all, active_ids, context=None): |
2697 | + """get line to be marked filter done lines""" |
2698 | + line_obj = self.pool.get('credit.management.line') |
2699 | + if mark_all: |
2700 | + domain = [('state', '=', 'draft')] |
2701 | + else: |
2702 | + domain = [('state', '!=', 'sent'), ('id', 'in', active_ids)] |
2703 | + return line_obj.search(cursor, uid, domain, context=context) |
2704 | + |
2705 | + def _mark_lines(self, cursor, uid, filtered_ids, state, context=None): |
2706 | + """write hook""" |
2707 | + line_obj = self.pool.get('credit.management.line') |
2708 | + if not state: |
2709 | + raise ValueError(_('state can not be empty')) |
2710 | + line_obj.write(cursor, uid, filtered_ids, {'state': state}) |
2711 | + return filtered_ids |
2712 | + |
2713 | + |
2714 | + |
2715 | + def mark_lines(self, cursor, uid, wiz_id, context=None): |
2716 | + """Write state of selected credit lines to the one in entry |
2717 | + done credit line will be ignored""" |
2718 | + context = context or {} |
2719 | + if isinstance(wiz_id, list): |
2720 | + wiz_id = wiz_id[0] |
2721 | + current = self.browse(cursor, uid, wiz_id, context) |
2722 | + lines_ids = context.get('active_ids') |
2723 | + |
2724 | + if not lines_ids and not current.mark_all: |
2725 | + raise except_osv(_('Not lines ids are selected'), |
2726 | + _('You may check "Mark all draft lines"')) |
2727 | + filtered_ids = self._get_lids(cursor, uid, current.mark_all, lines_ids, context) |
2728 | + if not filtered_ids: |
2729 | + raise except_osv(_('No lines will be changed'), |
2730 | + _('All selected lines are allready done')) |
2731 | + |
2732 | + # hook function a simple write should be enought |
2733 | + self._mark_lines(cursor, uid, filtered_ids, current.name, context) |
2734 | + |
2735 | + return {'domain': "[('id','in',%s)]" % (filtered_ids,), |
2736 | + 'name': _('%s marked line') % (current.name,), |
2737 | + 'view_type': 'form', |
2738 | + 'view_mode': 'tree,form', |
2739 | + 'view_id': False, |
2740 | + 'res_model': 'credit.management.line', |
2741 | + 'type': 'ir.actions.act_window'} |
2742 | |
2743 | === added file 'account_credit_management/wizard/credit_management_marker_view.xml' |
2744 | --- account_credit_management/wizard/credit_management_marker_view.xml 1970-01-01 00:00:00 +0000 |
2745 | +++ account_credit_management/wizard/credit_management_marker_view.xml 2012-10-15 10:14:35 +0000 |
2746 | @@ -0,0 +1,44 @@ |
2747 | +<openerp> |
2748 | + <data> |
2749 | + |
2750 | + <record id="credit_line_marker_form" model="ir.ui.view"> |
2751 | + <field name="name">credit.line.marker.form</field> |
2752 | + <field name="model">credit.management.marker</field> |
2753 | + <field name="type">form</field> |
2754 | + <field name="arch" type="xml"> |
2755 | + <form> <!-- editable="bottom" --> |
2756 | + <separator string="This wizard will mark selected draft lines to the selected state. Done Lines will be ignored " colspan="4"/> |
2757 | + <newline/> |
2758 | + <field name="name"/> |
2759 | + <field name="mark_all"/> |
2760 | + <newline/> |
2761 | + <group colspan="4"> |
2762 | + <button name="mark_lines" string="Mark lines" type="object" icon="gtk-execute"/> |
2763 | + <button special="cancel" string="Cancel" icon='gtk-cancel'/> |
2764 | + </group> |
2765 | + </form> |
2766 | + </field> |
2767 | + </record> |
2768 | + |
2769 | + <!-- for menu --> |
2770 | + <act_window name="Mark lines" |
2771 | + res_model="credit.management.marker" |
2772 | + src_model="credit.management.line" |
2773 | + view_mode="form" |
2774 | + target="new" |
2775 | + key2="client_action_multi" |
2776 | + id="open_credit_line_marker_wizard_menu_action"/> |
2777 | + |
2778 | + <record id="open_credit_line_marker_wizard" model="ir.actions.act_window"> |
2779 | + <field name="name">Mark lines</field> |
2780 | + <field name="res_model">credit.management.marker</field> |
2781 | + <field name="src_model">credit.management.line</field> |
2782 | + <field name="view_type">form</field> |
2783 | + <field name="view_mode">form</field> |
2784 | + <field name="view_id" ref="credit_line_marker_form"/> |
2785 | + <field name="target">new</field> |
2786 | + <field name="help">Mark all lines. You can the send marked lines</field> |
2787 | + </record> |
2788 | + |
2789 | + </data> |
2790 | +</openerp> |
2791 | |
2792 | === added file 'account_credit_management/wizard/credit_management_printer.py' |
2793 | --- account_credit_management/wizard/credit_management_printer.py 1970-01-01 00:00:00 +0000 |
2794 | +++ account_credit_management/wizard/credit_management_printer.py 2012-10-15 10:14:35 +0000 |
2795 | @@ -0,0 +1,74 @@ |
2796 | +# -*- coding: utf-8 -*- |
2797 | +############################################################################## |
2798 | +# |
2799 | +# Author: Nicolas Bessi |
2800 | +# Copyright 2012 Camptocamp SA |
2801 | +# |
2802 | +# This program is free software: you can redistribute it and/or modify |
2803 | +# it under the terms of the GNU Affero General Public License as |
2804 | +# published by the Free Software Foundation, either version 3 of the |
2805 | +# License, or (at your option) any later version. |
2806 | +# |
2807 | +# This program is distributed in the hope that it will be useful, |
2808 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2809 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2810 | +# GNU Affero General Public License for more details. |
2811 | +# |
2812 | +# You should have received a copy of the GNU Affero General Public License |
2813 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
2814 | +# |
2815 | +############################################################################## |
2816 | +import base64 |
2817 | + |
2818 | +from openerp.osv.orm import TransientModel, fields |
2819 | +from openerp.osv.osv import except_osv |
2820 | +from openerp.tools.translate import _ |
2821 | + |
2822 | +class CreditManagementPrinter(TransientModel): |
2823 | + """Change the state of lines in mass""" |
2824 | + |
2825 | + _name = "credit.management.printer" |
2826 | + _rec_name = 'id' |
2827 | + _description = """Mass printer""" |
2828 | + _columns = {'mark_as_sent': fields.boolean('Mark lines as send', |
2829 | + help="Lines to emailed will be ignored"), |
2830 | + 'print_all': fields.boolean('Print all ready lines'), |
2831 | + 'report_file': fields.binary('Generated Report'), |
2832 | + 'state': fields.char('state', size=32)} |
2833 | + |
2834 | + def _get_lids(self, cursor, uid, print_all, active_ids, context=None): |
2835 | + """get line to be marked filter done lines""" |
2836 | + # TODO Dry with mailer maybe in comm |
2837 | + line_obj = self.pool.get('credit.management.line') |
2838 | + if print_all: |
2839 | + domain = [('state', '=', 'to_be_sent'), |
2840 | + ('canal', '=', 'manual')] |
2841 | + else: |
2842 | + domain = [('state', '=', 'to_be_sent'), |
2843 | + ('id', 'in', active_ids), |
2844 | + ('canal', '=', 'manual')] |
2845 | + return line_obj.search(cursor, uid, domain, context=context) |
2846 | + |
2847 | + |
2848 | + def print_lines(self, cursor, uid, wiz_id, context=None): |
2849 | + comm_obj = self.pool.get('credit.management.communication') |
2850 | + context = context or {} |
2851 | + if isinstance(wiz_id, list): |
2852 | + wiz_id = wiz_id[0] |
2853 | + current = self.browse(cursor, uid, wiz_id, context) |
2854 | + lines_ids = context.get('active_ids') |
2855 | + if not lines_ids and not current.print_all: |
2856 | + raise except_osv(_('Not lines ids are selected'), |
2857 | + _('You may check "Print all ready lines"')) |
2858 | + if current.print_all: |
2859 | + filtered_ids = self._get_lids(cursor, uid, current.print_all, lines_ids, context) |
2860 | + else: |
2861 | + filtered_ids = lines_ids |
2862 | + comms = comm_obj._generate_comm_from_credit_line_ids(cursor, uid, filtered_ids, |
2863 | + context=context) |
2864 | + report_file = comm_obj._generate_report(cursor, uid, comms, context=context) |
2865 | + current.write({'report_file': base64.b64encode(report_file), 'state': 'done'}) |
2866 | + if current.mark_as_sent: |
2867 | + filtered_ids = self._get_lids(cursor, uid, False, lines_ids, context) |
2868 | + comm_obj._mark_credit_line_as_sent(cursor, uid, comms, context=context) |
2869 | + return False |
2870 | |
2871 | === added file 'account_credit_management/wizard/credit_management_printer_view.xml' |
2872 | --- account_credit_management/wizard/credit_management_printer_view.xml 1970-01-01 00:00:00 +0000 |
2873 | +++ account_credit_management/wizard/credit_management_printer_view.xml 2012-10-15 10:14:35 +0000 |
2874 | @@ -0,0 +1,47 @@ |
2875 | +<openerp> |
2876 | + <data> |
2877 | + |
2878 | + <record id="credit_line_printer_form" model="ir.ui.view"> |
2879 | + <field name="name">credit.line.printer.form</field> |
2880 | + <field name="model">credit.management.printer</field> |
2881 | + <field name="type">form</field> |
2882 | + <field name="arch" type="xml"> |
2883 | + <form> <!-- editable="bottom" --> |
2884 | + <separator colspan="4" string="This wizard will print all manual lines. Mark lines, lines will pass lines to state done. Lines with canal email will not be passed to state done"/> |
2885 | + <newline/> |
2886 | + <field name="mark_as_sent"/> |
2887 | + <field name="print_all"/> |
2888 | + <newline/> |
2889 | + <field name="report_file" attrs="{'readonly': [('state', '!=', 'done')]}" colspan="4"/> |
2890 | + <field name="state" invisible="1" /> |
2891 | + <newline/> |
2892 | + <group colspan="4"> |
2893 | + <button name="print_lines" string="Print lines" type="object" icon="gtk-execute"/> |
2894 | + <button special="cancel" string="Cancel" icon='gtk-cancel'/> |
2895 | + </group> |
2896 | + </form> |
2897 | + </field> |
2898 | + </record> |
2899 | + |
2900 | + <!-- for menu --> |
2901 | + <act_window name="Print lines" |
2902 | + res_model="credit.management.printer" |
2903 | + src_model="credit.management.line" |
2904 | + view_mode="form" |
2905 | + target="new" |
2906 | + key2="client_action_multi" |
2907 | + id="open_credit_line_printer_wizard_menu_action"/> |
2908 | + |
2909 | + <record id="open_credit_line_printer_wizard" model="ir.actions.act_window"> |
2910 | + <field name="name">Print lines</field> |
2911 | + <field name="res_model">credit.management.printer</field> |
2912 | + <field name="src_model">credit.management.line</field> |
2913 | + <field name="view_type">form</field> |
2914 | + <field name="view_mode">form</field> |
2915 | + <field name="view_id" ref="credit_line_printer_form"/> |
2916 | + <field name="target">new</field> |
2917 | + <field name="help">Print all lines</field> |
2918 | + </record> |
2919 | + |
2920 | + </data> |
2921 | +</openerp> |
2922 | |
2923 | === modified file 'account_fiscal_position_rule_m2m/fiscal_rules.py' |
2924 | --- account_fiscal_position_rule_m2m/fiscal_rules.py 2012-04-03 14:27:22 +0000 |
2925 | +++ account_fiscal_position_rule_m2m/fiscal_rules.py 2012-10-15 10:14:35 +0000 |
2926 | @@ -177,8 +177,8 @@ |
2927 | ) |
2928 | |
2929 | for field in account_fiscal_position_rule.m2o_replaced_fields: |
2930 | - field_ids = [item.id for item in template[field]] |
2931 | - vals[field] = [(6, 0, field_ids)] |
2932 | + field_ids = [item.id for item in template["%s_ids"%field]] |
2933 | + vals["%s_ids"%field] = [(6, 0, field_ids)] |
2934 | |
2935 | return vals |
2936 | |
2937 | |
2938 | === added directory 'account_payment_ext' |
2939 | === added file 'account_payment_ext/__init__.py' |
2940 | --- account_payment_ext/__init__.py 1970-01-01 00:00:00 +0000 |
2941 | +++ account_payment_ext/__init__.py 2012-10-15 10:14:35 +0000 |
2942 | @@ -0,0 +1,32 @@ |
2943 | +# -*- encoding: utf-8 -*- |
2944 | +# |
2945 | +# c2c_scan_bvr |
2946 | +# |
2947 | +# Created by Nicolas Bessi and Vincent Renaville |
2948 | +# |
2949 | +# Copyright (c) 2012 CamptoCamp. All rights reserved. |
2950 | +############################################################################## |
2951 | +# |
2952 | +# WARNING: This program as such is intended to be used by professional |
2953 | +# programmers who take the whole responsability of assessing all potential |
2954 | +# consequences resulting from its eventual inadequacies and bugs |
2955 | +# End users who are looking for a ready-to-use solution with commercial |
2956 | +# garantees and support are strongly adviced to contract a Free Software |
2957 | +# Service Company |
2958 | +# |
2959 | +# This program is Free Software; you can redistribute it and/or |
2960 | +# modify it under the terms of the GNU General Public License |
2961 | +# as published by the Free Software Foundation; either version 2 |
2962 | +# of the License, or (at your option) any later version. |
2963 | +# |
2964 | +# This program is distributed in the hope that it will be useful, |
2965 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2966 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2967 | +# GNU General Public License for more details. |
2968 | +# |
2969 | +# You should have received a copy of the GNU General Public License |
2970 | +# along with this program; if not, write to the Free Software |
2971 | +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
2972 | +# |
2973 | +############################################################################## |
2974 | +import account_payment |
2975 | \ No newline at end of file |
2976 | |
2977 | === added file 'account_payment_ext/__openerp__.py' |
2978 | --- account_payment_ext/__openerp__.py 1970-01-01 00:00:00 +0000 |
2979 | +++ account_payment_ext/__openerp__.py 2012-10-15 10:14:35 +0000 |
2980 | @@ -0,0 +1,50 @@ |
2981 | +# -*- encoding: utf-8 -*- |
2982 | +# |
2983 | +# c2c_scan_bvr |
2984 | +# |
2985 | +# Created by Nicolas Bessi and Vincent Renaville |
2986 | +# |
2987 | +# Copyright (c) 2012 CamptoCamp. All rights reserved. |
2988 | +############################################################################## |
2989 | +# |
2990 | +# WARNING: This program as such is intended to be used by professional |
2991 | +# programmers who take the whole responsability of assessing all potential |
2992 | +# consequences resulting from its eventual inadequacies and bugs |
2993 | +# End users who are looking for a ready-to-use solution with commercial |
2994 | +# garantees and support are strongly adviced to contract a Free Software |
2995 | +# Service Company |
2996 | +# |
2997 | +# This program is Free Software; you can redistribute it and/or |
2998 | +# modify it under the terms of the GNU General Public License |
2999 | +# as published by the Free Software Foundation; either version 2 |
3000 | +# of the License, or (at your option) any later version. |
3001 | +# |
3002 | +# This program is distributed in the hope that it will be useful, |
3003 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3004 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3005 | +# GNU General Public License for more details. |
3006 | +# |
3007 | +# You should have received a copy of the GNU General Public License |
3008 | +# along with this program; if not, write to the Free Software |
3009 | +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
3010 | +# |
3011 | +############################################################################## |
3012 | +{ |
3013 | + "name" : "Account Payment improvement", |
3014 | + "description" : """In case of a payment order |
3015 | + set to pay directly , when the payment will pass to stade done, it will set payment line date to the current date |
3016 | + """, |
3017 | + "version" : "1.0", |
3018 | + "author" : "Camptocamp", |
3019 | + "category" : "Generic Modules/Others", |
3020 | + "website": "http://www.camptocamp.com", |
3021 | + "depends" : [ |
3022 | + "account_payment" |
3023 | + ], |
3024 | + "init_xml" : [], |
3025 | + "update_xml" : [ |
3026 | + 'account_payment_view.xml' |
3027 | + ], |
3028 | + "active": False, |
3029 | + "installable": True |
3030 | +} |
3031 | |
3032 | === added file 'account_payment_ext/account_payment.py' |
3033 | --- account_payment_ext/account_payment.py 1970-01-01 00:00:00 +0000 |
3034 | +++ account_payment_ext/account_payment.py 2012-10-15 10:14:35 +0000 |
3035 | @@ -0,0 +1,47 @@ |
3036 | +# -*- coding: utf-8 -*- |
3037 | +############################################################################## |
3038 | +# |
3039 | +# OpenERP, Open Source Management Solution |
3040 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
3041 | +# |
3042 | +# This program is free software: you can redistribute it and/or modify |
3043 | +# it under the terms of the GNU Affero General Public License as |
3044 | +# published by the Free Software Foundation, either version 3 of the |
3045 | +# License, or (at your option) any later version. |
3046 | +# |
3047 | +# This program is distributed in the hope that it will be useful, |
3048 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3049 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3050 | +# GNU Affero General Public License for more details. |
3051 | +# |
3052 | +# You should have received a copy of the GNU Affero General Public License |
3053 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
3054 | +# |
3055 | +############################################################################## |
3056 | + |
3057 | +import time |
3058 | + |
3059 | +from osv import osv, fields |
3060 | +import netsvc |
3061 | + |
3062 | + |
3063 | +class payment_order(osv.osv): |
3064 | + _inherit = 'payment.order' |
3065 | + ### It will set the date |
3066 | + def action_open(self, cr, uid, ids, *args): |
3067 | + return_code = super(payment_order,self).action_open(cr, uid, ids, args) |
3068 | + payment_line_obj = self.pool.get('payment.line') |
3069 | + if return_code: |
3070 | + for order in self.browse(cr,uid,ids): |
3071 | + ### In the case of a date prefered to Directy , we set the current date into the bank statement |
3072 | + if order.date_prefered == 'now': |
3073 | + for line in order.line_ids: |
3074 | + ## in case of no date defined on line |
3075 | + if not line.date: |
3076 | + payment_line_obj.write(cr, uid, [line.id], {'date': time.strftime('%Y-%m-%d')}) |
3077 | + return return_code |
3078 | + |
3079 | +payment_order() |
3080 | + |
3081 | + |
3082 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
3083 | |
3084 | === added file 'account_payment_ext/account_payment_view.xml' |
3085 | --- account_payment_ext/account_payment_view.xml 1970-01-01 00:00:00 +0000 |
3086 | +++ account_payment_ext/account_payment_view.xml 2012-10-15 10:14:35 +0000 |
3087 | @@ -0,0 +1,18 @@ |
3088 | +<?xml version="1.0" encoding="utf-8"?> |
3089 | +<openerp> |
3090 | + <data> |
3091 | + |
3092 | + <record id="view_payment_order_form_date_required" model="ir.ui.view"> |
3093 | + <field name="name">payment.order.form</field> |
3094 | + <field name="model">payment.order</field> |
3095 | + <field name="inherit_id" ref="account_payment.view_payment_order_form"/> |
3096 | + <field name="type">form</field> |
3097 | + <field name="arch" type="xml"> |
3098 | + <xpath expr='//field[@name="date_scheduled"]' position='replace'> |
3099 | + <field name="date_scheduled" select="1" attrs="{'readonly':[('date_prefered','!=','fixed')],'required':[('date_prefered','=','fixed')]}" /> |
3100 | + </xpath> |
3101 | + </field> |
3102 | + </record> |
3103 | + |
3104 | + </data> |
3105 | +</openerp> |
3106 | |
3107 | === added directory 'account_payment_ext/i18n' |
The merge is huge for "a bug". Can you check you requested the merge on the right branch + describe the bug you're trying to fix (or link to a bug on the tracker)?
Thanks