Merge lp:~akretion-team/openobject-addons/trunk_prepare_refund into lp:openobject-addons
- trunk_prepare_refund
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 8395 |
Proposed branch: | lp:~akretion-team/openobject-addons/trunk_prepare_refund |
Merge into: | lp:openobject-addons |
Diff against target: |
188 lines (+88/-64) 3 files modified
account/account_invoice.py (+86/-62) account/wizard/account_invoice_refund.py (+1/-1) point_of_sale/wizard/pos_return.py (+1/-1) |
To merge this branch: | bzr merge lp:~akretion-team/openobject-addons/trunk_prepare_refund |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Dony (Odoo) | Approve | ||
Nhomar - Vauxoo (community) | Approve | ||
Review via email: mp+122024@code.launchpad.net |
Commit message
Description of the change
This merge add a method prepare_refund to help the customization of the creation of a refund with the wizard. It also add the context as arguments of the methods def refund and _refund_
Olivier Dony (Odoo) (odo-openerp) wrote : | # |
Nice work, thanks!
It looks good, except what is the purpose of the "refund_id" parameter passed to _prepare_refund(), and seemingly unused?
It would also be a nice touch to add docstrings explaining the meaning and types of the various parameters (not cr, uid, and context, but the others), similarly to what was done in the other _prepare_* methods, like here:
http://
Thanks!
Benoit Guillot - http://www.akretion.com (benoit-guillot-z) wrote : | # |
Thanks Nhomar for the approval and Olivier for the comments !
I have added the dosctring for the method prepare.
Concerning the parameter "refund_id", it is a typo, I meant "invoice_id". I have fixed it.
I think it can be useful to have the id of the invoice in the method prepare.
Moreover, I would like to add a new prepare method : _prepare_
This method allows us to add new fields for the creation of the refund lines.
Tell me what you think about it please :)
Thank you.
Benoît
Olivier Dony (Odoo) (odo-openerp) wrote : | # |
On 10/10/2012 05:56 PM, Benoit Guillot - http://
> I have added the dosctring for the method prepare.
Thanks! The param type in docstrings is actually meant to be a Python type
(int/str/etc.), but we can fix it when merging, so no big deal.
> Concerning the parameter "refund_id", it is a typo, I meant "invoice_id". I have fixed it.
> I think it can be useful to have the id of the invoice in the method prepare.
Hmm, the thing is this parameter is unused, and redundant because the `invoice`
parameter contains the ID. In general we avoid passing unused parameters
because they risk being removed in the future, and prefer passing higher level
data structures that give you indirect access to more info. In this case the
`invoice` param plays that role.
Now if you prefer having an even higher-level param, you could replace the
`invoice` dict by a browse_record (and update the code accordingly). Not sure
if that's really useful, but it could save extra read() calls in inheriting
methods that need to access more columns of the invoice.
> Moreover, I would like to add a new prepare method : _prepare_
> This method allows us to add new fields for the creation of the refund lines.
> Tell me what you think about it please :)
It looks a bit overkill to me, as the main purpose of _refund_
is to fix the lines data, no need for a separate one. If your issue is simply
to have this method support custom m2o fields as well, why not remove the
hardcoded list of fields and instead check the type of the fields (via
account.
Benoit Guillot - http://www.akretion.com (benoit-guillot-z) wrote : | # |
Hello Olivier,
I agree with you about the invoice dict. I am ready to spend more time on this to replace it by a browse_record if you think it's worth it. As far as I'm concerned, I think it does, as you said it can save extra read() calls. Then I just have to manage also the refund_
Otherwise, if we should keep the dict instead of the browse_record, I can manage the invoice_id in the dict and remove it from the parameters. It is indeed redundant. Moreover, about the method _refund_
So I can propose the two solutions, but maybe it worth to use this proposal to improve the refund creation with a browse_record instead of several reads.
Olivier Dony (Odoo) (odo-openerp) wrote : | # |
On 10/11/2012 12:57 PM, Benoit Guillot - http://
> I agree with you about the invoice dict. I am ready to spend more time on
> this to replace it by a browse_record if you think it's worth it. As far as
> I'm concerned, I think it does, as you said it can save extra read() calls.
> Then I just have to manage also the refund_
Sure, go ahead, this should not break the current API and should be safe :-)
The fields that were read() from the invoice were limited, so it should be easy
to craft a new dictionary from a browse_record instead of a dict, taking care
of fixing m2o values as you go (based on the type coming from _all_columns)
Tip: browse_records support __getitem__ just like dict, so you can simply use
``invoice[f]`` to get the value for field ``f``, without having to use
getattr(invoice, f)
Benoit Guillot - http://www.akretion.com (benoit-guillot-z) wrote : | # |
Thanks for the tip, it has helped me !
I have removed some fields from the dict of the invoice:
- 'type', 'number' because theses are overwriten
- 'partner_contact', 'partner_insite', 'partner_ref' because theses seem not exist anymore
I have refactored the method _refund_
def _browse_
for field in browse.
if field_type == 'many2one':
return dict_from_browse
This method can be used in copy() and probably in other cases.
About the merge, I have tested, it seems to work. I haven't try it on the runbot, because akretion has been kicked out from the runbot (probably because of the 'a' of akretion).
Olivier Dony (Odoo) (odo-openerp) wrote : | # |
On 10/12/2012 02:37 PM, Benoit Guillot - http://
> Thanks for the tip, it has helped me !
>
> I have removed some fields from the dict of the invoice:
> - 'type', 'number' because theses are overwriten
> - 'partner_contact', 'partner_insite', 'partner_ref' because theses seem not exist anymore
Looks good, and how about the `journal_id` field, it seems overwritten as well
if I'm not mistaken?
> I have refactored the method _refund_
> useful to create a generic method for instance : _browse_to_dict() which can
> be something like that (it's just an idea it can be improved):
<SNIP>
It might be useful in other circumstances, however it should not be located in
the account module. In order to speed up the merge I suggest not doing it now.
Also you have an issue with o2m fields now (and m2m to some extent), because
you have removed the list of fields to copy in _refund_
I suppose this is to make the code simpler and possibly avoid having to inherit
this method when you add extra fields to the lines. However this may have
dangerous side effects. A module could track individual payment lines or some
special analytic lines and link them to the invoice line using a o2m or m2m -
but these should not be copied over to the refund line!
You do not handle the o2m case at all at the moment, so it will simply crash if
a module ever does this.
I think it would be much safer to keep a list of fields to copy, or at least
skip all o2m/m2m by default and handle `invoice_
As you see, even with a _browse_to_dict() helper method you'd still need to
iterate on the fields to filter them based on their type (to fix the above
problem), so the code might not even be shorter...
> About the merge, I have tested, it seems to work. I haven't try it on the
> runbot, because akretion has been kicked out from the runbot (probably
> because of the 'a' of akretion).
Akretion has not been kicked out of runbot, but the list of registered teams
was recently wiped out by mistake[1]. Sorry about it, you just need to
re-register your team. It would be great to check the status of the tests on
your branch indeed!
Great job, thanks again for your efforts and dedication!
[1] Already happened in the past:
https:/
Benoit Guillot - http://www.akretion.com (benoit-guillot-z) wrote : | # |
Yes indeed the 'journal_id' field is overwritten, so I removed it.
I have changed also the method refund_
About the browse_to_dict() method, I was also thinking to put it somewhere else than in the module account, but the purpose of that was just to have a feedback ;)
Thanks for your time spent to discuss about it !
Benoit Guillot - http://www.akretion.com (benoit-guillot-z) wrote : | # |
Hello Olivier,
Have you verified my last changes ?
What do you think of them ?
I insist because I think we really need this merge for the V7 !
Thanks again for the time you spend on this merge proposal.
Regards,
Benoît
Olivier Dony (Odoo) (odo-openerp) wrote : | # |
Looks very good to me now, I'm merging it after resolving the latest conflicts.
Thanks for your patience and your excellent contribution! :-)
Benoit Guillot - http://www.akretion.com (benoit-guillot-z) wrote : | # |
Thanks a lot for the merge !
Preview Diff
1 | === modified file 'account/account_invoice.py' |
2 | --- account/account_invoice.py 2012-10-08 12:17:45 +0000 |
3 | +++ account/account_invoice.py 2012-10-16 16:41:28 +0000 |
4 | @@ -1124,72 +1124,96 @@ |
5 | ids = self.search(cr, user, [('name',operator,name)] + args, limit=limit, context=context) |
6 | return self.name_get(cr, user, ids, context) |
7 | |
8 | - def _refund_cleanup_lines(self, cr, uid, lines): |
9 | + def _refund_cleanup_lines(self, cr, uid, lines, context=None): |
10 | + clean_lines = [] |
11 | for line in lines: |
12 | - del line['id'] |
13 | - del line['invoice_id'] |
14 | - for field in ('company_id', 'partner_id', 'account_id', 'product_id', |
15 | - 'uos_id', 'account_analytic_id', 'tax_code_id', 'base_code_id'): |
16 | - if line.get(field): |
17 | - line[field] = line[field][0] |
18 | - if 'invoice_line_tax_id' in line: |
19 | - line['invoice_line_tax_id'] = [(6,0, line.get('invoice_line_tax_id', [])) ] |
20 | - return map(lambda x: (0,0,x), lines) |
21 | - |
22 | - def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=None): |
23 | - invoices = self.read(cr, uid, ids, ['name', 'type', 'number', 'reference', 'comment', 'date_due', 'partner_id', 'partner_contact', 'partner_insite', 'partner_ref', 'payment_term', 'account_id', 'currency_id', 'invoice_line', 'tax_line', 'journal_id', 'company_id']) |
24 | - obj_invoice_line = self.pool.get('account.invoice.line') |
25 | - obj_invoice_tax = self.pool.get('account.invoice.tax') |
26 | + clean_line = {} |
27 | + for field in line._all_columns.keys(): |
28 | + if line._all_columns[field].column._type == 'many2one': |
29 | + clean_line[field] = line[field].id |
30 | + elif line._all_columns[field].column._type not in ['many2many','one2many']: |
31 | + clean_line[field] = line[field] |
32 | + elif field == 'invoice_line_tax_id': |
33 | + tax_list = [] |
34 | + for tax in line[field]: |
35 | + tax_list.append(tax.id) |
36 | + clean_line[field] = [(6,0, tax_list)] |
37 | + clean_lines.append(clean_line) |
38 | + return map(lambda x: (0,0,x), clean_lines) |
39 | + |
40 | + def _prepare_refund(self, cr, uid, invoice, date=None, period_id=None, description=None, journal_id=None, context=None): |
41 | + """Prepare the dict of values to create the new refund from the invoice. |
42 | + This method may be overridden to implement custom |
43 | + refund generation (making sure to call super() to establish |
44 | + a clean extension chain). |
45 | + |
46 | + :param integer invoice_id: id of the invoice to refund |
47 | + :param dict invoice: read of the invoice to refund |
48 | + :param string date: refund creation date from the wizard |
49 | + :param integer period_id: force account.period from the wizard |
50 | + :param string description: description of the refund from the wizard |
51 | + :param integer journal_id: account.journal from the wizard |
52 | + :return: dict of value to create() the refund |
53 | + """ |
54 | obj_journal = self.pool.get('account.journal') |
55 | + |
56 | + type_dict = { |
57 | + 'out_invoice': 'out_refund', # Customer Invoice |
58 | + 'in_invoice': 'in_refund', # Supplier Invoice |
59 | + 'out_refund': 'out_invoice', # Customer Refund |
60 | + 'in_refund': 'in_invoice', # Supplier Refund |
61 | + } |
62 | + invoice_data = {} |
63 | + for field in ['name', 'reference', 'comment', 'date_due', 'partner_id', 'company_id', |
64 | + 'account_id', 'currency_id', 'payment_term']: |
65 | + if invoice._all_columns[field].column._type == 'many2one': |
66 | + invoice_data[field] = invoice[field].id |
67 | + else: |
68 | + invoice_data[field] = invoice[field] and invoice[field] or False |
69 | + |
70 | + invoice_lines = self._refund_cleanup_lines(cr, uid, invoice.invoice_line, context=context) |
71 | + |
72 | + tax_lines = filter(lambda l: l['manual'], invoice.tax_line) |
73 | + tax_lines = self._refund_cleanup_lines(cr, uid, tax_lines, context=context) |
74 | + if journal_id: |
75 | + refund_journal_ids = [journal_id] |
76 | + elif invoice['type'] == 'in_invoice': |
77 | + refund_journal_ids = obj_journal.search(cr, uid, [('type','=','purchase_refund')], context=context) |
78 | + else: |
79 | + refund_journal_ids = obj_journal.search(cr, uid, [('type','=','sale_refund')], context=context) |
80 | + |
81 | + if not date: |
82 | + date = time.strftime('%Y-%m-%d') |
83 | + invoice_data.update({ |
84 | + 'type': type_dict[invoice['type']], |
85 | + 'date_invoice': date, |
86 | + 'state': 'draft', |
87 | + 'number': False, |
88 | + 'invoice_line': invoice_lines, |
89 | + 'tax_line': tax_lines, |
90 | + 'journal_id': refund_journal_ids and refund_journal_ids[0] or False, |
91 | + }) |
92 | + if period_id: |
93 | + invoice_data.update({ |
94 | + 'period_id': period_id, |
95 | + }) |
96 | + if description: |
97 | + invoice_data.update({ |
98 | + 'name': description, |
99 | + }) |
100 | + return invoice_data |
101 | + |
102 | + def refund(self, cr, uid, ids, date=None, period_id=None, description=None, journal_id=None, context=None): |
103 | new_ids = [] |
104 | - for invoice in invoices: |
105 | - del invoice['id'] |
106 | - |
107 | - type_dict = { |
108 | - 'out_invoice': 'out_refund', # Customer Invoice |
109 | - 'in_invoice': 'in_refund', # Supplier Invoice |
110 | - 'out_refund': 'out_invoice', # Customer Refund |
111 | - 'in_refund': 'in_invoice', # Supplier Refund |
112 | - } |
113 | - |
114 | - invoice_lines = obj_invoice_line.read(cr, uid, invoice['invoice_line']) |
115 | - invoice_lines = self._refund_cleanup_lines(cr, uid, invoice_lines) |
116 | - |
117 | - tax_lines = obj_invoice_tax.read(cr, uid, invoice['tax_line']) |
118 | - tax_lines = filter(lambda l: l['manual'], tax_lines) |
119 | - tax_lines = self._refund_cleanup_lines(cr, uid, tax_lines) |
120 | - if journal_id: |
121 | - refund_journal_ids = [journal_id] |
122 | - elif invoice['type'] == 'in_invoice': |
123 | - refund_journal_ids = obj_journal.search(cr, uid, [('type','=','purchase_refund')]) |
124 | - else: |
125 | - refund_journal_ids = obj_journal.search(cr, uid, [('type','=','sale_refund')]) |
126 | - |
127 | - if not date: |
128 | - date = time.strftime('%Y-%m-%d') |
129 | - invoice.update({ |
130 | - 'type': type_dict[invoice['type']], |
131 | - 'date_invoice': date, |
132 | - 'state': 'draft', |
133 | - 'number': False, |
134 | - 'invoice_line': invoice_lines, |
135 | - 'tax_line': tax_lines, |
136 | - 'journal_id': refund_journal_ids |
137 | - }) |
138 | - if period_id: |
139 | - invoice.update({ |
140 | - 'period_id': period_id, |
141 | - }) |
142 | - if description: |
143 | - invoice.update({ |
144 | - 'name': description, |
145 | - }) |
146 | - # take the id part of the tuple returned for many2one fields |
147 | - for field in ('partner_id', 'company_id', |
148 | - 'account_id', 'currency_id', 'payment_term', 'journal_id'): |
149 | - invoice[field] = invoice[field] and invoice[field][0] |
150 | + for invoice in self.browse(cr, uid, ids, context=context): |
151 | + invoice = self._prepare_refund(cr, uid, invoice, |
152 | + date=date, |
153 | + period_id=period_id, |
154 | + description=description, |
155 | + journal_id=journal_id, |
156 | + context=context) |
157 | # create the new invoice |
158 | - new_ids.append(self.create(cr, uid, invoice)) |
159 | + new_ids.append(self.create(cr, uid, invoice, context=context)) |
160 | |
161 | return new_ids |
162 | |
163 | |
164 | === modified file 'account/wizard/account_invoice_refund.py' |
165 | --- account/wizard/account_invoice_refund.py 2012-09-30 17:02:56 +0000 |
166 | +++ account/wizard/account_invoice_refund.py 2012-10-16 16:41:28 +0000 |
167 | @@ -146,7 +146,7 @@ |
168 | raise osv.except_osv(_('Insufficient Data!'), \ |
169 | _('No period found on the invoice.')) |
170 | |
171 | - refund_id = inv_obj.refund(cr, uid, [inv.id], date, period, description, journal_id) |
172 | + refund_id = inv_obj.refund(cr, uid, [inv.id], date, period, description, journal_id, context=context) |
173 | refund = inv_obj.browse(cr, uid, refund_id[0], context=context) |
174 | inv_obj.write(cr, uid, [refund.id], {'date_due': date, |
175 | 'check_total': inv.check_total}) |
176 | |
177 | === modified file 'point_of_sale/wizard/pos_return.py' |
178 | --- point_of_sale/wizard/pos_return.py 2012-03-30 08:27:51 +0000 |
179 | +++ point_of_sale/wizard/pos_return.py 2012-10-16 16:41:28 +0000 |
180 | @@ -278,7 +278,7 @@ |
181 | location_id=res and res[0] or None |
182 | |
183 | if order_id.invoice_id: |
184 | - invoice_obj.refund(cr, uid, [order_id.invoice_id.id], time.strftime('%Y-%m-%d'), False, order_id.name) |
185 | + invoice_obj.refund(cr, uid, [order_id.invoice_id.id], time.strftime('%Y-%m-%d'), False, order_id.name, context=context) |
186 | new_picking=picking_obj.create(cr, uid, { |
187 | 'name':'%s (return)' %order_id.name, |
188 | 'move_lines':[], 'state':'draft', |
Wao.
Dude, yesterday we fix a lot of thing in ur both localization writting all the original method.
For V7 this is a must to have ;-)