Merge lp:~openerp-dev/openobject-addons/trunk-bug-724131-rpa into lp:openobject-addons

Proposed by Rucha (Open ERP)
Status: Merged
Merged at revision: 5691
Proposed branch: lp:~openerp-dev/openobject-addons/trunk-bug-724131-rpa
Merge into: lp:openobject-addons
Diff against target: 192 lines (+81/-57)
3 files modified
account_anglo_saxon/purchase.py (+3/-3)
purchase/purchase.py (+75/-51)
purchase_analytic_plans/purchase_analytic_plans.py (+3/-3)
To merge this branch: bzr merge lp:~openerp-dev/openobject-addons/trunk-bug-724131-rpa
Reviewer Review Type Date Requested Status
Rucha (Open ERP) Pending
qdp (OpenERP) Pending
Review via email: mp+82254@code.launchpad.net

This proposal supersedes a proposal from 2011-11-14.

Description of the change

lp:724131: Fixed missing relation between PO line and Invoice line when purchase order invoice control is Based on generated invoice,

To post a comment you must log in.
Revision history for this message
qdp (OpenERP) (qdp) wrote : Posted in a previous version of this proposal

Hello Rucha,

just few comments:
1) can you make a new function to retrieve the dict to use to create the invoice line, _prepare_invoice_line_data(), in order to increase the inheritability and flexibility of our code

2) really strange: i didn't know that the field invoice_id on account.invoice.line wasn't mandatory! anyway, for performance reasons it would be better to create the invoice with no lines, then to create the lines with the invoice_id set.

3) i don't like this syntax. Is there a reason to do it? a good one? if no, i propose that you let it like that to keep the code as much consistent as possible.
75 - self.write(cr, uid, [o.id], {'invoice_ids': [(4, inv_id)]})
78 + o.write({'invoice_ids': [(4, inv_id)]})

4) we need more comments, more docstrings in the new functions

5) some context may be added in function calls, from here to there, in the lines you already changed

Thanks

review: Needs Fixing
Revision history for this message
qdp (OpenERP) (qdp) wrote : Posted in a previous version of this proposal

just a thought for point 2: not sure that doing like this will call only once the fonctional fields of the invoice. Test it and if it's not the case then you can forget this point.

thanks

Revision history for this message
Rucha (Open ERP) (rpa-openerp) wrote : Posted in a previous version of this proposal

Thanks Quentin for your time,
my reply on your comments

> just few comments:
> 1) can you make a new function to retrieve the dict to use to create the invoice line,
> _prepare_invoice_line_data(), in order to increase the inheritability and flexibility of our code

I can not make a new function as inv_line_create function is used in other modules too, and might be used somewhere else in other community modules. I just changed signature of inv_line_create to return dict of data and this will be less risky as it requires less changes in overridden method.

> 2) really strange: i didn't know that the field invoice_id on account.invoice.line wasn't mandatory! anyway, for performance reasons it would be better to create the invoice with no lines, then to create the lines with the invoice_id set.

I found its good "to create the invoice with no lines, then to create the lines with the invoice_id set."
  so I did that.

3) i don't like this syntax. Is there a reason to do it? a good one? if no, i propose that you let it like that to keep the code as much consistent as possible.
75 - self.write(cr, uid, [o.id], {'invoice_ids': [(4, inv_id)]})
78 + o.write({'invoice_ids': [(4, inv_id)]})

> 4) we need more comments, more docstrings in the new functions

Added!

> 5) some context may be added in function calls, from here to there, in the lines you already changed

true, I just tried to keep it more clean in order to focus on only fix, but anyways I agree on that point and improved.

And as a bonus I changed stupid variable names a, o, il ..
this will cost you more to review but will be better, what do you think?

Thanks

review: Needs Resubmitting
Revision history for this message
Rucha (Open ERP) (rpa-openerp) wrote :

> 3) i don't like this syntax. Is there a reason to do it? a good one? if no, i propose that you let it like that to keep the code as much consistent as possible.
> 75 - self.write(cr, uid, [o.id], {'invoice_ids': [(4, inv_id)]})
> 78 + o.write({'invoice_ids': [(4, inv_id)]})

as now we use attributes of self.pool.get() for browse_record too, thats quite good, easy and consistent too (if we make practice of using that.)

Revision history for this message
qdp (OpenERP) (qdp) wrote :

> just few comments:
> 1) can you make a new function to retrieve the dict to use to create the invoice line,
> _prepare_invoice_line_data(), in order to increase the inheritability and flexibility of our code

I can not make a new function as inv_line_create function is used in other modules too, and might be used somewhere else in other community modules. I just changed signature of inv_line_create to return dict of data and this will be less risky as it requires less changes in overridden method.

=> o_O geez.. no you're wrong changing the signature is the same as it break the API too, maybe even worst as it may silent errors in some cases. Thus changing the name makes it more clear and that the good opportunity do to it.

>And as a bonus I changed stupid variable names a, o, il ..
>this will cost you more to review but will be better, what do you think?
=> that's an excelent idea

great work, i merged after changing the name of function

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'account_anglo_saxon/purchase.py'
2--- account_anglo_saxon/purchase.py 2011-10-27 21:11:24 +0000
3+++ account_anglo_saxon/purchase.py 2011-11-15 11:51:27 +0000
4@@ -26,8 +26,8 @@
5 _inherit = "purchase.order"
6 _description = "Purchase Order"
7
8- def inv_line_create(self, cr, uid, a, ol):
9- line = super(purchase_order, self).inv_line_create(cr, uid, a, ol)
10+ def prepare_inv_line(self, cr, uid, account_id, order_line, context=None):
11+ line = super(purchase_order, self).prepare_inv_line(cr, uid, account_id, order_line, context=context)
12 if ol.product_id and not ol.product_id.type == 'service':
13 oa = ol.product_id.property_stock_account_input and ol.product_id.property_stock_account_input.id
14 if not oa:
15@@ -35,6 +35,6 @@
16 if oa:
17 fpos = ol.order_id.fiscal_position or False
18 a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, oa)
19- line[2].update({'account_id': a})
20+ line.update({'account_id': a})
21 return line
22 purchase_order()
23
24=== modified file 'purchase/purchase.py'
25--- purchase/purchase.py 2011-11-14 11:18:10 +0000
26+++ purchase/purchase.py 2011-11-15 11:51:27 +0000
27@@ -319,17 +319,25 @@
28 'ref_partner_id': po.partner_id.id,
29 'ref_doc1': 'purchase.order,%d' % (po.id,),
30 })
31- def inv_line_create(self, cr, uid, a, ol):
32- return (0, False, {
33- 'name': ol.name,
34- 'account_id': a,
35- 'price_unit': ol.price_unit or 0.0,
36- 'quantity': ol.product_qty,
37- 'product_id': ol.product_id.id or False,
38- 'uos_id': ol.product_uom.id or False,
39- 'invoice_line_tax_id': [(6, 0, [x.id for x in ol.taxes_id])],
40- 'account_analytic_id': ol.account_analytic_id.id or False,
41- })
42+
43+ def prepare_inv_line(self, cr, uid, account_id, order_line, context=None):
44+ """Collects require data from purchase order line that is used to create invoice line
45+ for that purchase order line
46+ :param account_id: Expense account of the product of PO line if any.
47+ :param browse_record order_line: Purchase order line browse record
48+ :return: Value for fields of invoice lines.
49+ :rtype: dict
50+ """
51+ return {
52+ 'name': order_line.name,
53+ 'account_id': account_id,
54+ 'price_unit': order_line.price_unit or 0.0,
55+ 'quantity': order_line.product_qty,
56+ 'product_id': order_line.product_id.id or False,
57+ 'uos_id': order_line.product_uom.id or False,
58+ 'invoice_line_tax_id': [(6, 0, [x.id for x in order_line.taxes_id])],
59+ 'account_analytic_id': order_line.account_analytic_id.id or False,
60+ }
61
62 def action_cancel_draft(self, cr, uid, ids, *args):
63 if not len(ids):
64@@ -345,55 +353,71 @@
65 self.log(cr, uid, id, message)
66 return True
67
68- #TOFIX
69- # - implement hook method on create invoice and invoice line
70- # - doc string
71- def action_invoice_create(self, cr, uid, ids, *args):
72+ def action_invoice_create(self, cr, uid, ids, context=None):
73+ """Generates invoice for given ids of purchase orders and links that invoice ID to purchase order.
74+ :param ids: list of ids of purchase orders.
75+ :return: ID of created invoice.
76+ :rtype: int
77+ """
78 res = False
79
80 journal_obj = self.pool.get('account.journal')
81- for o in self.browse(cr, uid, ids):
82- il = []
83- todo = []
84- for ol in o.order_line:
85- todo.append(ol.id)
86- if ol.product_id:
87- a = ol.product_id.product_tmpl_id.property_account_expense.id
88- if not a:
89- a = ol.product_id.categ_id.property_account_expense_categ.id
90- if not a:
91- raise osv.except_osv(_('Error !'), _('There is no expense account defined for this product: "%s" (id:%d)') % (ol.product_id.name, ol.product_id.id,))
92- else:
93- a = self.pool.get('ir.property').get(cr, uid, 'property_account_expense_categ', 'product.category').id
94- fpos = o.fiscal_position or False
95- a = self.pool.get('account.fiscal.position').map_account(cr, uid, fpos, a)
96- il.append(self.inv_line_create(cr, uid, a, ol))
97+ inv_obj = self.pool.get('account.invoice')
98+ inv_line_obj = self.pool.get('account.invoice.line')
99+ fiscal_obj = self.pool.get('account.fiscal.position')
100+ property_obj = self.pool.get('ir.property')
101
102- a = o.partner_id.property_account_payable.id
103- journal_ids = journal_obj.search(cr, uid, [('type', '=','purchase'),('company_id', '=', o.company_id.id)], limit=1)
104+ for order in self.browse(cr, uid, ids, context=context):
105+ pay_acc_id = order.partner_id.property_account_payable.id
106+ journal_ids = journal_obj.search(cr, uid, [('type', '=','purchase'),('company_id', '=', order.company_id.id)], limit=1)
107 if not journal_ids:
108 raise osv.except_osv(_('Error !'),
109- _('There is no purchase journal defined for this company: "%s" (id:%d)') % (o.company_id.name, o.company_id.id))
110- inv = {
111- 'name': o.partner_ref or o.name,
112- 'reference': o.partner_ref or o.name,
113- 'account_id': a,
114+ _('There is no purchase journal defined for this company: "%s" (id:%d)') % (order.company_id.name, order.company_id.id))
115+
116+ # generate invoice line correspond to PO line and link that to created invoice (inv_id) and PO line
117+ inv_lines = []
118+ for po_line in order.order_line:
119+ if po_line.product_id:
120+ acc_id = po_line.product_id.product_tmpl_id.property_account_expense.id
121+ if not acc_id:
122+ acc_id = po_line.product_id.categ_id.property_account_expense_categ.id
123+ if not acc_id:
124+ raise osv.except_osv(_('Error !'), _('There is no expense account defined for this product: "%s" (id:%d)') % (po_line.product_id.name, po_line.product_id.id,))
125+ else:
126+ acc_id = property_obj.get(cr, uid, 'property_account_expense_categ', 'product.category').id
127+ fpos = order.fiscal_position or False
128+ acc_id = fiscal_obj.map_account(cr, uid, fpos, acc_id)
129+
130+ inv_line_data = self.prepare_inv_line(cr, uid, acc_id, po_line, context=context)
131+ inv_line_id = inv_line_obj.create(cr, uid, inv_line_data, context=context)
132+ inv_lines.append(inv_line_id)
133+
134+ po_line.write({'invoiced':True, 'invoice_lines': [(4, inv_line_id)]}, context=context)
135+
136+ # get invoice data and create invoice
137+ inv_data = {
138+ 'name': order.partner_ref or order.name,
139+ 'reference': order.partner_ref or order.name,
140+ 'account_id': pay_acc_id,
141 'type': 'in_invoice',
142- 'partner_id': o.partner_id.id,
143- 'currency_id': o.pricelist_id.currency_id.id,
144- 'address_invoice_id': o.partner_address_id.id,
145- 'address_contact_id': o.partner_address_id.id,
146+ 'partner_id': order.partner_id.id,
147+ 'currency_id': order.pricelist_id.currency_id.id,
148+ 'address_invoice_id': order.partner_address_id.id,
149+ 'address_contact_id': order.partner_address_id.id,
150 'journal_id': len(journal_ids) and journal_ids[0] or False,
151- 'origin': o.name,
152- 'invoice_line': il,
153- 'fiscal_position': o.fiscal_position.id or o.partner_id.property_account_position.id,
154- 'payment_term': o.partner_id.property_payment_term and o.partner_id.property_payment_term.id or False,
155- 'company_id': o.company_id.id,
156+ 'invoice_line': [(6, 0, inv_lines)],
157+ 'origin': order.name,
158+ 'fiscal_position': order.fiscal_position.id or order.partner_id.property_account_position.id,
159+ 'payment_term': order.partner_id.property_payment_term and order.partner_id.property_payment_term.id or False,
160+ 'company_id': order.company_id.id,
161 }
162- inv_id = self.pool.get('account.invoice').create(cr, uid, inv, {'type':'in_invoice'})
163- self.pool.get('account.invoice').button_compute(cr, uid, [inv_id], {'type':'in_invoice'}, set_total=True)
164- self.pool.get('purchase.order.line').write(cr, uid, todo, {'invoiced':True})
165- self.write(cr, uid, [o.id], {'invoice_ids': [(4, inv_id)]})
166+ inv_id = inv_obj.create(cr, uid, inv_data, context=context)
167+
168+ # compute the invoice
169+ inv_obj.button_compute(cr, uid, [inv_id], context=context, set_total=True)
170+
171+ # Link this new invoice to related purchase order
172+ order.write({'invoice_ids': [(4, inv_id)]}, context=context)
173 res = inv_id
174 return res
175
176
177=== modified file 'purchase_analytic_plans/purchase_analytic_plans.py'
178--- purchase_analytic_plans/purchase_analytic_plans.py 2011-01-14 00:11:01 +0000
179+++ purchase_analytic_plans/purchase_analytic_plans.py 2011-11-15 11:51:27 +0000
180@@ -35,9 +35,9 @@
181 _name='purchase.order'
182 _inherit='purchase.order'
183
184- def inv_line_create(self, cr, uid, a, ol):
185- res=super(purchase_order,self).inv_line_create(cr, uid, a, ol)
186- res[2]['analytics_id']=ol.analytics_id.id
187+ def prepare_inv_line(self, cr, uid, account_id, order_line, context=None):
188+ res = super(purchase_order, self).prepare_inv_line(cr, uid, account_id, order_line, context=context)
189+ res['analytics_id'] = order_line.analytics_id.id
190 return res
191
192 purchase_order()

Subscribers

People subscribed via source and target branches

to all changes: