Merge lp:~yannick-buron/contract-management/contract-management into lp:~contract-management-core-editors/contract-management/7.0

Proposed by YannickB (YOLO consulting)
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
Reviewer Review Type Date Requested Status
Joël Grand-Guillaume @ camptocamp code review, no tests Approve
Leonardo Pistone code review Approve
Review via email: mp+207630@code.launchpad.net

This proposal supersedes a proposal from 2014-02-04.

Description of the change

Add account_analytic_analysis_recurring, a backport of the new recurring invoice feature in trunk (V8)

To post a comment you must log in.
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : Posted in a previous version of this proposal

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

review: Needs Fixing (code review, no test)
Revision history for this message
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.

Revision history for this message
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

Revision history for this message
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.

Revision history for this message
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://code.launchpad.net/synerpgy-projects. I also made in 2011 the l10n_fr_hr_payroll because I wanted to prove that hr_payroll was able to manage the french payroll, and the module was integrated by OpenERP SA in official addons. But obviously nobody used it... nobody contacted me and no improvement happened on the module since.

Now I left the webagency to create another enterprise with an associate, with wikicompare project https://yannickburon.wordpress.com/2013/07/24/presentation-wikicompare/ and wezer which is an OpenERP for association with marketplace and internal currency.
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://code.launchpad.net/~yannick-buron, they are almost all generic modules which will be merged in OCA (or at least create another OpenObject project in the case of marketplace module because I'm not sure it's for OCA).

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://code.launchpad.net/~yannick-buron/sale-wkfl/sale-wkfl/+merge/207468, where I know I'll not find the time to merge the both module even if I aggree that I made some kind of duplication. Sorry for that I'll try to do my best, but if that's not enough thank you for your understanding.

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.

Revision history for this message
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 :)

review: Approve (code review)
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote :

LGTM now, thanks !

review: Approve (code review, no tests)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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'

Subscribers

People subscribed via source and target branches