Merge lp:~yannick-buron/contract-management/contract-management into lp:~contract-management-core-editors/contract-management/7.0
- contract-management
- Merge into 7.0
Status: | Merged |
---|---|
Merged at revision: | 13 |
Proposed branch: | lp:~yannick-buron/contract-management/contract-management |
Merge into: | lp:~contract-management-core-editors/contract-management/7.0 |
Diff against target: |
500 lines (+468/-0) 6 files modified
account_analytic_analysis_recurring/__init__.py (+22/-0) account_analytic_analysis_recurring/__openerp__.py (+48/-0) account_analytic_analysis_recurring/account_analytic_analysis_recurring.pot (+129/-0) account_analytic_analysis_recurring/account_analytic_analysis_recurring.py (+209/-0) account_analytic_analysis_recurring/account_analytic_analysis_recurring_cron.xml (+16/-0) account_analytic_analysis_recurring/account_analytic_analysis_recurring_view.xml (+44/-0) |
To merge this branch: | bzr merge lp:~yannick-buron/contract-management/contract-management |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Joël Grand-Guillaume @ camptocamp | code review, no tests | Approve | |
Leonardo Pistone | code review | Approve | |
Review via email:
|
This proposal supersedes a proposal from 2014-02-04.
Commit message
Description of the change
Add account_
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ronald Portier (Therp) (rportier1962) wrote : Posted in a previous version of this proposal | # |
As for the 2nd and 3rd points: in this case I think it is best to leave the backported code as is.
If there are any enhancements in the code in trunk, it will be much easier to adopt them when the backport is really a backport.
If we really would like to have a module fashioned after community standards, we should also have orm.Model instead of osv.osv, shorter lines etc.
I did no deep analysis of the code, nor a test, so I will leave my comment just as a comment.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal | # |
Hi Ronald and Yannick,
Ok, after coming back on this one, I agree with you Ronald. We should leave it as is, so fixes will be much easier to port !
So @Yannick, if you can just correct 1st and 4th point and it ok for me.
Regards,
Joël
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Pedro Manuel Baeza (pedro.baeza) wrote : Posted in a previous version of this proposal | # |
Hi, Joël,
I would say contributors section instead of author for your first point, doesn't it?
Regards.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
YannickB (YOLO consulting) (yannick-buron) wrote : | # |
I'm really sorry guys, I took so long for answering even if you answered right away... I guess I missed the notice email.
1) It was a oversight, I copy/paste another file of my own module, I corrected line 10 but forgot line 68. I didn't planned to add my name on this module, but you're right adding it in the description is a good idea.
2)3) Agree, we shouldn't improve too much the module since it will be deprecated in V8 anyway. I just added the feature with #START# and #END# because it was really simple and I needed it.
4) Good idea, that's done. In general, any guidelines somewhere to be sure it's OCA quality?
Also one word about my contributions : It's true, even if I am in the community since 2009 I didn't contributed that much because it really took me time before being confident enough in my code (and in 2009-2011 I was making more commercial than development).
Then I joined a web-agency as a employee and the only one OpenERP developer, it was such rush here that I didn't had time to make my development generic enough to reverse them in community. Still everything I done is visible in https:/
Now I left the webagency to create another enterprise with an associate, with wikicompare project https:/
Now, even if I am still the only developper, I am much more confident in my skill and I have a good process to make generic module. Also, OCA and OCB help A LOT because I fear less that nobody use my generic module and so quickly become deprecated. Really kuddo for that.
You can check the branch on my profile https:/
One last thing : I am working on Wikicompare, on Wezer, and on two customers projects. I am organized enough to manage this, but after the MPs I sometimes have some difficulties to find the time to make the corrections following the feedbacks of the MPs. This is especially visible on this MP https:/
PS : I supersedes the MP because I made an error pushing my branch and am not yet so used to how MP works, sorry for that I saw after that the diff is updated directly when I update my branch.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Leonardo Pistone (lepistone) wrote : | # |
Thanks Yannick, agree with others on for not diverging for a backport. I would be happier backporting something that has tests, but that's not your fault, Yannick :)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
LGTM now, thanks !
Preview Diff
1 | === added directory 'account_analytic_analysis_recurring' |
2 | === added file 'account_analytic_analysis_recurring/__init__.py' |
3 | --- account_analytic_analysis_recurring/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ account_analytic_analysis_recurring/__init__.py 2014-02-21 11:50:24 +0000 |
5 | @@ -0,0 +1,22 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# OpenERP, Open Source Management Solution |
10 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>) |
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 | + |
27 | +import account_analytic_analysis_recurring |
28 | |
29 | === added file 'account_analytic_analysis_recurring/__openerp__.py' |
30 | --- account_analytic_analysis_recurring/__openerp__.py 1970-01-01 00:00:00 +0000 |
31 | +++ account_analytic_analysis_recurring/__openerp__.py 2014-02-21 11:50:24 +0000 |
32 | @@ -0,0 +1,48 @@ |
33 | +# -*- coding: utf-8 -*- |
34 | +############################################################################## |
35 | +# |
36 | +# OpenERP, Open Source Management Solution |
37 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
38 | +# |
39 | +# This program is free software: you can redistribute it and/or modify |
40 | +# it under the terms of the GNU Affero General Public License as |
41 | +# published by the Free Software Foundation, either version 3 of the |
42 | +# License, or (at your option) any later version. |
43 | +# |
44 | +# This program is distributed in the hope that it will be useful, |
45 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
46 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
47 | +# GNU Affero General Public License for more details. |
48 | +# |
49 | +# You should have received a copy of the GNU Affero General Public License |
50 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
51 | +# |
52 | +############################################################################## |
53 | + |
54 | + |
55 | +{ |
56 | + 'name': 'Contracts Management recurring', |
57 | + 'version': '0.1', |
58 | + 'category': 'Other', |
59 | + 'description': """ |
60 | +This module add a new feature in contracts to manage recurring invoice |
61 | +======================================================================================= |
62 | + |
63 | +This is a backport of the new V8 feature available in trunk and saas. With the V8 release this module will be deprecated. |
64 | +It also add a little feature, you can use #START# and #END# in the contract line to automatically insert the dates of the invoiced period. |
65 | + |
66 | +Backport done By Yannick Buron. |
67 | +""", |
68 | + 'author': 'OpenERP SA', |
69 | + 'website': 'http://openerp.com', |
70 | + 'depends': ['base', 'account_analytic_analysis'], |
71 | + 'data': [ |
72 | + 'account_analytic_analysis_recurring_cron.xml', |
73 | + 'account_analytic_analysis_recurring_view.xml', |
74 | + ], |
75 | + 'demo': [''], |
76 | + 'test':[], |
77 | + 'installable': True, |
78 | + 'images': [], |
79 | +} |
80 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
81 | |
82 | === added file 'account_analytic_analysis_recurring/account_analytic_analysis_recurring.pot' |
83 | --- account_analytic_analysis_recurring/account_analytic_analysis_recurring.pot 1970-01-01 00:00:00 +0000 |
84 | +++ account_analytic_analysis_recurring/account_analytic_analysis_recurring.pot 2014-02-21 11:50:24 +0000 |
85 | @@ -0,0 +1,129 @@ |
86 | +# Translation of OpenERP Server. |
87 | +# This file contains the translation of the following modules: |
88 | +# * account_analytic_analysis_recurring |
89 | +# |
90 | +msgid "" |
91 | +msgstr "" |
92 | +"Project-Id-Version: OpenERP Server 7.0\n" |
93 | +"Report-Msgid-Bugs-To: \n" |
94 | +"POT-Creation-Date: 2014-02-21 11:41+0000\n" |
95 | +"PO-Revision-Date: 2014-02-21 11:41+0000\n" |
96 | +"Last-Translator: <>\n" |
97 | +"Language-Team: \n" |
98 | +"MIME-Version: 1.0\n" |
99 | +"Content-Type: text/plain; charset=UTF-8\n" |
100 | +"Content-Transfer-Encoding: \n" |
101 | +"Plural-Forms: \n" |
102 | + |
103 | +#. module: account_analytic_analysis_recurring |
104 | +#: field:account.analytic.invoice.line,price_subtotal:0 |
105 | +msgid "Sub Total" |
106 | +msgstr "" |
107 | + |
108 | +#. module: account_analytic_analysis_recurring |
109 | +#: field:account.analytic.account,recurring_rule_type:0 |
110 | +msgid "Recurrency" |
111 | +msgstr "" |
112 | + |
113 | +#. module: account_analytic_analysis_recurring |
114 | +#: field:account.analytic.invoice.line,price_unit:0 |
115 | +msgid "Unit Price" |
116 | +msgstr "" |
117 | + |
118 | +#. module: account_analytic_analysis_recurring |
119 | +#: view:account.analytic.account:0 |
120 | +msgid ". create invoices" |
121 | +msgstr "" |
122 | + |
123 | +#. module: account_analytic_analysis_recurring |
124 | +#: view:account.analytic.account:0 |
125 | +msgid "Account Analytic Lines" |
126 | +msgstr "" |
127 | + |
128 | +#. module: account_analytic_analysis_recurring |
129 | +#: field:account.analytic.account,recurring_invoice_line_ids:0 |
130 | +msgid "Invoice Lines" |
131 | +msgstr "" |
132 | + |
133 | +#. module: account_analytic_analysis_recurring |
134 | +#: field:account.analytic.invoice.line,uom_id:0 |
135 | +msgid "Unit of Measure" |
136 | +msgstr "" |
137 | + |
138 | +#. module: account_analytic_analysis_recurring |
139 | +#: selection:account.analytic.account,recurring_rule_type:0 |
140 | +msgid "Day(s)" |
141 | +msgstr "" |
142 | + |
143 | +#. module: account_analytic_analysis_recurring |
144 | +#: help:account.analytic.account,recurring_rule_type:0 |
145 | +msgid "Invoice automatically repeat at specified interval" |
146 | +msgstr "" |
147 | + |
148 | +#. module: account_analytic_analysis_recurring |
149 | +#: field:account.analytic.invoice.line,product_id:0 |
150 | +msgid "Product" |
151 | +msgstr "" |
152 | + |
153 | +#. module: account_analytic_analysis_recurring |
154 | +#: field:account.analytic.invoice.line,name:0 |
155 | +msgid "Description" |
156 | +msgstr "" |
157 | + |
158 | +#. module: account_analytic_analysis_recurring |
159 | +#: field:account.analytic.account,recurring_interval:0 |
160 | +msgid "Repeat Every" |
161 | +msgstr "" |
162 | + |
163 | +#. module: account_analytic_analysis_recurring |
164 | +#: view:account.analytic.account:0 |
165 | +msgid "Recurring Invoices" |
166 | +msgstr "" |
167 | + |
168 | +#. module: account_analytic_analysis_recurring |
169 | +#: field:account.analytic.account,recurring_invoices:0 |
170 | +msgid "Generate recurring invoices automatically" |
171 | +msgstr "" |
172 | + |
173 | +#. module: account_analytic_analysis_recurring |
174 | +#: selection:account.analytic.account,recurring_rule_type:0 |
175 | +msgid "Year(s)" |
176 | +msgstr "" |
177 | + |
178 | +#. module: account_analytic_analysis_recurring |
179 | +#: selection:account.analytic.account,recurring_rule_type:0 |
180 | +msgid "Week(s)" |
181 | +msgstr "" |
182 | + |
183 | +#. module: account_analytic_analysis_recurring |
184 | +#: field:account.analytic.invoice.line,quantity:0 |
185 | +msgid "Quantity" |
186 | +msgstr "" |
187 | + |
188 | +#. module: account_analytic_analysis_recurring |
189 | +#: model:ir.model,name:account_analytic_analysis_recurring.model_account_analytic_invoice_line |
190 | +msgid "account.analytic.invoice.line" |
191 | +msgstr "" |
192 | + |
193 | +#. module: account_analytic_analysis_recurring |
194 | +#: field:account.analytic.account,recurring_next_date:0 |
195 | +msgid "Date of Next Invoice" |
196 | +msgstr "" |
197 | + |
198 | +#. module: account_analytic_analysis_recurring |
199 | +#: field:account.analytic.invoice.line,analytic_account_id:0 |
200 | +#: model:ir.model,name:account_analytic_analysis_recurring.model_account_analytic_account |
201 | +msgid "Analytic Account" |
202 | +msgstr "" |
203 | + |
204 | +#. module: account_analytic_analysis_recurring |
205 | +#: selection:account.analytic.account,recurring_rule_type:0 |
206 | +msgid "Month(s)" |
207 | +msgstr "" |
208 | + |
209 | +#. module: account_analytic_analysis_recurring |
210 | +#: help:account.analytic.account,recurring_interval:0 |
211 | +msgid "Repeat every (Days/Week/Month/Year)" |
212 | +msgstr "" |
213 | + |
214 | + |
215 | |
216 | === added file 'account_analytic_analysis_recurring/account_analytic_analysis_recurring.py' |
217 | --- account_analytic_analysis_recurring/account_analytic_analysis_recurring.py 1970-01-01 00:00:00 +0000 |
218 | +++ account_analytic_analysis_recurring/account_analytic_analysis_recurring.py 2014-02-21 11:50:24 +0000 |
219 | @@ -0,0 +1,209 @@ |
220 | +# -*- coding: utf-8 -*- |
221 | +############################################################################## |
222 | +# |
223 | +# OpenERP, Open Source Management Solution |
224 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
225 | +# |
226 | +# This program is free software: you can redistribute it and/or modify |
227 | +# it under the terms of the GNU Affero General Public License as |
228 | +# published by the Free Software Foundation, either version 3 of the |
229 | +# License, or (at your option) any later version. |
230 | +# |
231 | +# This program is distributed in the hope that it will be useful, |
232 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
233 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
234 | +# GNU Affero General Public License for more details. |
235 | +# |
236 | +# You should have received a copy of the GNU Affero General Public License |
237 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
238 | +# |
239 | +############################################################################## |
240 | +from dateutil.relativedelta import relativedelta |
241 | +import datetime |
242 | +import logging |
243 | +import time |
244 | + |
245 | +from openerp.osv import osv, fields |
246 | +from openerp.osv.orm import intersect, except_orm |
247 | +import openerp.tools |
248 | +from openerp.tools.translate import _ |
249 | + |
250 | +from openerp.addons.decimal_precision import decimal_precision as dp |
251 | + |
252 | +_logger = logging.getLogger(__name__) |
253 | + |
254 | +class account_analytic_invoice_line(osv.osv): |
255 | + _name = "account.analytic.invoice.line" |
256 | + |
257 | + def _amount_line(self, cr, uid, ids, prop, unknow_none, unknow_dict, context=None): |
258 | + res = {} |
259 | + for line in self.browse(cr, uid, ids, context=context): |
260 | + res[line.id] = line.quantity * line.price_unit |
261 | + if line.analytic_account_id.pricelist_id: |
262 | + cur = line.analytic_account_id.pricelist_id.currency_id |
263 | + res[line.id] = self.pool.get('res.currency').round(cr, uid, cur, res[line.id]) |
264 | + return res |
265 | + |
266 | + _columns = { |
267 | + 'product_id': fields.many2one('product.product','Product',required=True), |
268 | + 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account'), |
269 | + 'name': fields.text('Description', required=True), |
270 | + 'quantity': fields.float('Quantity', required=True), |
271 | + 'uom_id': fields.many2one('product.uom', 'Unit of Measure',required=True), |
272 | + 'price_unit': fields.float('Unit Price', required=True), |
273 | + 'price_subtotal': fields.function(_amount_line, string='Sub Total', type="float",digits_compute= dp.get_precision('Account')), |
274 | + } |
275 | + _defaults = { |
276 | + 'quantity' : 1, |
277 | + } |
278 | + |
279 | + def product_id_change(self, cr, uid, ids, product, uom_id, qty=0, name='', partner_id=False, price_unit=False, pricelist_id=False, company_id=None, context=None): |
280 | + context = context or {} |
281 | + uom_obj = self.pool.get('product.uom') |
282 | + company_id = company_id or False |
283 | + context.update({'company_id': company_id, 'force_company': company_id, 'pricelist_id': pricelist_id}) |
284 | + |
285 | + if not product: |
286 | + return {'value': {'price_unit': 0.0}, 'domain':{'product_uom':[]}} |
287 | + if partner_id: |
288 | + part = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context) |
289 | + if part.lang: |
290 | + context.update({'lang': part.lang}) |
291 | + |
292 | + result = {} |
293 | + res = self.pool.get('product.product').browse(cr, uid, product, context=context) |
294 | + result.update({'name':res.partner_ref or False,'uom_id': uom_id or res.uom_id.id or False, 'price_unit': res.list_price or 0.0}) |
295 | + if res.description: |
296 | + result['name'] += '\n'+res.description |
297 | + |
298 | + res_final = {'value':result} |
299 | + if result['uom_id'] != res.uom_id.id: |
300 | + selected_uom = uom_obj.browse(cr, uid, result['uom_id'], context=context) |
301 | + new_price = uom_obj._compute_price(cr, uid, res.uom_id.id, res_final['value']['price_unit'], result['uom_id']) |
302 | + res_final['value']['price_unit'] = new_price |
303 | + return res_final |
304 | + |
305 | + |
306 | +class account_analytic_account(osv.osv): |
307 | + _name = "account.analytic.account" |
308 | + _inherit = "account.analytic.account" |
309 | + |
310 | + _columns = { |
311 | + 'recurring_invoice_line_ids': fields.one2many('account.analytic.invoice.line', 'analytic_account_id', 'Invoice Lines'), |
312 | + 'recurring_invoices' : fields.boolean('Generate recurring invoices automatically'), |
313 | + 'recurring_rule_type': fields.selection([ |
314 | + ('daily', 'Day(s)'), |
315 | + ('weekly', 'Week(s)'), |
316 | + ('monthly', 'Month(s)'), |
317 | + ('yearly', 'Year(s)'), |
318 | + ], 'Recurrency', help="Invoice automatically repeat at specified interval"), |
319 | + 'recurring_interval': fields.integer('Repeat Every', help="Repeat every (Days/Week/Month/Year)"), |
320 | + 'recurring_next_date': fields.date('Date of Next Invoice'), |
321 | + } |
322 | + |
323 | + _defaults = { |
324 | + 'recurring_interval': 1, |
325 | + 'recurring_next_date': lambda *a: time.strftime('%Y-%m-%d'), |
326 | + 'recurring_rule_type':'monthly' |
327 | + } |
328 | + |
329 | + def onchange_recurring_invoices(self, cr, uid, ids, recurring_invoices, date_start=False, context=None): |
330 | + value = {} |
331 | + if date_start and recurring_invoices: |
332 | + value = {'value': {'recurring_next_date': date_start}} |
333 | + return value |
334 | + |
335 | + def _prepare_invoice(self, cr, uid, contract, context=None): |
336 | + context = context or {} |
337 | + |
338 | + inv_obj = self.pool.get('account.invoice') |
339 | + journal_obj = self.pool.get('account.journal') |
340 | + fpos_obj = self.pool.get('account.fiscal.position') |
341 | + lang_obj = self.pool.get('res.lang') |
342 | + |
343 | + if not contract.partner_id: |
344 | + raise osv.except_osv(_('No Customer Defined!'),_("You must first select a Customer for Contract %s!") % contract.name ) |
345 | + |
346 | + fpos = contract.partner_id.property_account_position or False |
347 | + journal_ids = journal_obj.search(cr, uid, [('type', '=','sale'),('company_id', '=', contract.company_id.id or False)], limit=1) |
348 | + if not journal_ids: |
349 | + raise osv.except_osv(_('Error!'), |
350 | + _('Please define a sale journal for the company "%s".') % (contract.company_id.name or '', )) |
351 | + |
352 | + partner_payment_term = contract.partner_id.property_payment_term and contract.partner_id.property_payment_term.id or False |
353 | + |
354 | + |
355 | + inv_data = { |
356 | + 'reference': contract.code or False, |
357 | + 'account_id': contract.partner_id.property_account_receivable.id, |
358 | + 'type': 'out_invoice', |
359 | + 'partner_id': contract.partner_id.id, |
360 | + 'currency_id': contract.partner_id.property_product_pricelist.id or False, |
361 | + 'journal_id': len(journal_ids) and journal_ids[0] or False, |
362 | + 'date_invoice': contract.recurring_next_date, |
363 | + 'origin': contract.name, |
364 | + 'fiscal_position': fpos and fpos.id, |
365 | + 'payment_term': partner_payment_term, |
366 | + 'company_id': contract.company_id.id or False, |
367 | + } |
368 | + invoice_id = inv_obj.create(cr, uid, inv_data, context=context) |
369 | + |
370 | + for line in contract.recurring_invoice_line_ids: |
371 | + |
372 | + res = line.product_id |
373 | + account_id = res.property_account_income.id |
374 | + if not account_id: |
375 | + account_id = res.categ_id.property_account_income_categ.id |
376 | + account_id = fpos_obj.map_account(cr, uid, fpos, account_id) |
377 | + |
378 | + taxes = res.taxes_id or False |
379 | + tax_id = fpos_obj.map_tax(cr, uid, fpos, taxes) |
380 | + |
381 | + if 'old_date' in context: |
382 | + lang_ids = lang_obj.search(cr, uid, [('code', '=', contract.partner_id.lang)], context=context) |
383 | + format = lang_obj.browse(cr, uid, lang_ids, context=context)[0].date_format |
384 | + line.name = line.name.replace('#START#', context['old_date'].strftime(format)) |
385 | + line.name = line.name.replace('#END#', context['next_date'].strftime(format)) |
386 | + |
387 | + invoice_line_vals = { |
388 | + 'name': line.name, |
389 | + 'account_id': account_id, |
390 | + 'account_analytic_id': contract.id, |
391 | + 'price_unit': line.price_unit or 0.0, |
392 | + 'quantity': line.quantity, |
393 | + 'uos_id': line.uom_id.id or False, |
394 | + 'product_id': line.product_id.id or False, |
395 | + 'invoice_id' : invoice_id, |
396 | + 'invoice_line_tax_id': [(6, 0, tax_id)], |
397 | + } |
398 | + self.pool.get('account.invoice.line').create(cr, uid, invoice_line_vals, context=context) |
399 | + |
400 | + inv_obj.button_compute(cr, uid, [invoice_id], context=context) |
401 | + return invoice_id |
402 | + |
403 | + def recurring_create_invoice(self, cr, uid, automatic=False, context=None): |
404 | + context = context or {} |
405 | + current_date = time.strftime('%Y-%m-%d') |
406 | + |
407 | + contract_ids = self.search(cr, uid, [('recurring_next_date','<=', current_date), ('state','=', 'open'), ('recurring_invoices','=', True)]) |
408 | + for contract in self.browse(cr, uid, contract_ids, context=context): |
409 | + |
410 | + next_date = datetime.datetime.strptime(contract.recurring_next_date or current_date, "%Y-%m-%d") |
411 | + interval = contract.recurring_interval |
412 | + if contract.recurring_rule_type == 'daily': |
413 | + old_date = next_date-relativedelta(days=+interval) |
414 | + new_date = next_date+relativedelta(days=+interval) |
415 | + elif contract.recurring_rule_type == 'weekly': |
416 | + old_date = next_date-relativedelta(weeks=+interval) |
417 | + new_date = next_date+relativedelta(weeks=+interval) |
418 | + else: |
419 | + old_date = next_date+relativedelta(months=+interval) |
420 | + new_date = next_date+relativedelta(months=+interval) |
421 | + |
422 | + context['old_date'] = old_date |
423 | + context['next_date'] = datetime.datetime.strptime(contract.recurring_next_date or current_date,"%Y-%m-%d") |
424 | + invoice_id = self._prepare_invoice(cr, uid, contract, context=context) |
425 | + |
426 | + self.write(cr, uid, [contract.id], {'recurring_next_date': new_date.strftime('%Y-%m-%d')}, context=context) |
427 | + return True |
428 | + |
429 | |
430 | === added file 'account_analytic_analysis_recurring/account_analytic_analysis_recurring_cron.xml' |
431 | --- account_analytic_analysis_recurring/account_analytic_analysis_recurring_cron.xml 1970-01-01 00:00:00 +0000 |
432 | +++ account_analytic_analysis_recurring/account_analytic_analysis_recurring_cron.xml 2014-02-21 11:50:24 +0000 |
433 | @@ -0,0 +1,16 @@ |
434 | +<?xml version="1.0" encoding='UTF-8'?> |
435 | +<openerp> |
436 | + <data> |
437 | + |
438 | + <record model="ir.cron" id="account_analytic_cron_for_invoice"> |
439 | + <field name="name">Generate Recurring Invoices from Contracts</field> |
440 | + <field name="interval_number">1</field> |
441 | + <field name="interval_type">days</field> |
442 | + <field name="numbercall">-1</field> |
443 | + <field name="model" eval="'account.analytic.account'"/> |
444 | + <field name="function" eval="'recurring_create_invoice'"/> |
445 | + <field name="args" eval="'()'"/> |
446 | + </record> |
447 | + |
448 | + </data> |
449 | +</openerp> |
450 | |
451 | === added file 'account_analytic_analysis_recurring/account_analytic_analysis_recurring_view.xml' |
452 | --- account_analytic_analysis_recurring/account_analytic_analysis_recurring_view.xml 1970-01-01 00:00:00 +0000 |
453 | +++ account_analytic_analysis_recurring/account_analytic_analysis_recurring_view.xml 2014-02-21 11:50:24 +0000 |
454 | @@ -0,0 +1,44 @@ |
455 | +<?xml version="1.0" encoding="utf-8"?> |
456 | +<openerp> |
457 | + <data> |
458 | + |
459 | + <record id="account_analytic_account_recurring_form_form" model="ir.ui.view"> |
460 | + <field name="name">account.analytic.account.invoice.recurring.form.inherit</field> |
461 | + <field name="model">account.analytic.account</field> |
462 | + <field name="inherit_id" ref="account_analytic_analysis.account_analytic_account_form_form"/> |
463 | + <field eval="40" name="priority"/> |
464 | + <field name="arch" type="xml"> |
465 | + <group name='invoice_on_timesheets' position='after'> |
466 | + <separator string="Recurring Invoices" attrs="{'invisible': [('recurring_invoices','!=',True)]}"/> |
467 | + <div> |
468 | + <field name="recurring_invoices" on_change="onchange_recurring_invoices(recurring_invoices, date_start)" class="oe_inline"/> |
469 | + <label for="recurring_invoices" /> |
470 | + <button class="oe_link" name="recurring_create_invoice" attrs="{'invisible': [('recurring_invoices','!=',True)]}" string=". create invoices" type="object" groups="base.group_no_one"/> |
471 | + </div> |
472 | + <group attrs="{'invisible': [('recurring_invoices','!=',True)]}"> |
473 | + <label for="recurring_interval"/> |
474 | + <div> |
475 | + <field name="recurring_interval" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/> |
476 | + <field name="recurring_rule_type" class="oe_inline" attrs="{'required': [('recurring_invoices', '=', True)]}"/> |
477 | + </div> |
478 | + <field name="recurring_next_date"/> |
479 | + </group> |
480 | + <label for="recurring_invoice_line_ids" attrs="{'invisible': [('recurring_invoices','=',False)]}"/> |
481 | + <div attrs="{'invisible': [('recurring_invoices','=',False)]}"> |
482 | + <field name="recurring_invoice_line_ids"> |
483 | + <tree string="Account Analytic Lines" editable="bottom"> |
484 | + <field name="product_id" on_change="product_id_change(product_id, uom_id, quantity, name, parent.partner_id, price_unit, parent.pricelist_id, parent.company_id)"/> |
485 | + <field name="name"/> |
486 | + <field name="quantity"/> |
487 | + <field name="uom_id"/> |
488 | + <field name="price_unit"/> |
489 | + <field name="price_subtotal"/> |
490 | + </tree> |
491 | + </field> |
492 | + </div> |
493 | + </group> |
494 | + </field> |
495 | + </record> |
496 | + |
497 | + </data> |
498 | +</openerp> |
499 | |
500 | === added directory 'account_analytic_analysis_recurring/i18n' |
Hi Yannick,
Thanks for this back port and I very welcome your first (if I'm not wrong) contribution here ! I've just a couple of remarks:
* Line 66: For the author part, as it's OpenERP who did it first, I think it's fair to let OpenERP here. I suggest to add an author section in description of the __openerp__.py where you can explain you did the back port. This is also the new way we try to deal with authors in community module.
* Line 199: This method is quite long, and if I would like to override one, it's probably the one I would need to change. So I would suggest to add 2 methods: _prepare_ invoice_ vals (to fill inv_data) and _prepare_ invoice_ line_vals (to fill invoice_line_vals). With this anyone would easily override that part of the code. Now the question is : should we or shouldn't we change OpenERP's code as you took it from trunk.
* In general, I also see that PEP8 is not really respected here, but well, I know you just take the code in the trunk.. So same question: should we improve that here, or better to let "as it is" in trunk.
* No .pot file or i18n folder. Would be good to add it to enable the translation here.
Otherwise, it looks good to me. Would be happy to have other's opinion for 2nd and 3rd point.
Regards,
Joël