Merge lp:~camptocamp/margin-analysis/7.0-product_cost_incl_bom_price_history-mismatch-product-template into lp:~margin-analysis-core-editors/margin-analysis/7.0
Proposed by
Guewen Baconnier @ Camptocamp
Status: | Merged |
---|---|
Merged at revision: | 57 |
Proposed branch: | lp:~camptocamp/margin-analysis/7.0-product_cost_incl_bom_price_history-mismatch-product-template |
Merge into: | lp:~margin-analysis-core-editors/margin-analysis/7.0 |
Diff against target: |
304 lines (+115/-46) 6 files modified
product_cost_incl_bom_price_history/product.py (+42/-33) product_historical_margin/account_invoice_view.xml (+28/-0) product_price_history/product_price_history.py (+14/-1) product_price_history/product_price_history_view.xml (+26/-10) product_price_history/wizard/historic_prices.py (+5/-1) product_price_history/wizard/historic_prices_view.xml (+0/-1) |
To merge this branch: | bzr merge lp:~camptocamp/margin-analysis/7.0-product_cost_incl_bom_price_history-mismatch-product-template |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Joël Grand-Guillaume @ camptocamp | code review + test | Approve | |
Review via email: mp+201447@code.launchpad.net |
Commit message
Description of the change
Fixes lp:1268638
Mismatch between product.product and product.template
It expects product.template ids but receive product.product ids.
To post a comment you must log in.
lp:~camptocamp/margin-analysis/7.0-product_cost_incl_bom_price_history-mismatch-product-template
updated
- 58. By Guewen Baconnier @ Camptocamp
-
[MRG] from lp:~camptocamp/margin-analysis/7.0-product_cost_incl_bom_price_history-mismatch-product-template
- 59. By Joël Grand-Guillaume @ camptocamp
-
[FIX] The open price history button now display the product correctly by adding domain on template, not product
[IMP] Historic price view now display an inteliggent group by by default
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
review:
Approve
(code review + test)
lp:~camptocamp/margin-analysis/7.0-product_cost_incl_bom_price_history-mismatch-product-template
updated
- 60. By Joël Grand-Guillaume @ camptocamp
-
[FIX] Add a form view on margin details to avoid a keyerror bug
Revision history for this message
Joël Grand-Guillaume @ camptocamp (jgrandguillaume-c2c) wrote : | # |
Add a little fix in the meanwhile
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'product_cost_incl_bom_price_history/product.py' | |||
2 | --- product_cost_incl_bom_price_history/product.py 2013-12-12 10:09:02 +0000 | |||
3 | +++ product_cost_incl_bom_price_history/product.py 2014-02-05 09:14:09 +0000 | |||
4 | @@ -21,11 +21,9 @@ | |||
5 | 21 | 21 | ||
6 | 22 | from openerp.osv import orm, fields | 22 | from openerp.osv import orm, fields |
7 | 23 | import decimal_precision as dp | 23 | import decimal_precision as dp |
8 | 24 | import openerp | ||
9 | 25 | from openerp.addons.product_price_history.product_price_history import ( | 24 | from openerp.addons.product_price_history.product_price_history import ( |
10 | 26 | PRODUCT_FIELD_HISTORIZE | 25 | PRODUCT_FIELD_HISTORIZE |
11 | 27 | ) | 26 | ) |
12 | 28 | from openerp import SUPERUSER_ID | ||
13 | 29 | import time | 27 | import time |
14 | 30 | from datetime import datetime, timedelta | 28 | from datetime import datetime, timedelta |
15 | 31 | import logging | 29 | import logging |
16 | @@ -60,7 +58,7 @@ | |||
17 | 60 | if not field_flag: | 58 | if not field_flag: |
18 | 61 | field_flag = True | 59 | field_flag = True |
19 | 62 | if self._columns[field_name]._multi: | 60 | if self._columns[field_name]._multi: |
21 | 63 | raise ValueError('multi is not supported on the cost_price field') | 61 | raise ValueError('multi is not supported on the %s field' % field_name) |
22 | 64 | # use admin user for accessing objects having rules defined on | 62 | # use admin user for accessing objects having rules defined on |
23 | 65 | # store fields | 63 | # store fields |
24 | 66 | result = self._columns[field_name].get(cr, self, ids, | 64 | result = self._columns[field_name].get(cr, self, ids, |
25 | @@ -71,16 +69,12 @@ | |||
26 | 71 | if r in field_dict.keys(): | 69 | if r in field_dict.keys(): |
27 | 72 | if field_name in field_dict[r]: | 70 | if field_name in field_dict[r]: |
28 | 73 | result.pop(r) | 71 | result.pop(r) |
39 | 74 | for id, value in result.items(): | 72 | prods = self.read(cr, uid, result.keys(), ['product_tmpl_id'], |
40 | 75 | tpl_id = self.read(cr, uid, id, | 73 | context=context, load='_classic_write') |
41 | 76 | ['product_tmpl_id'], | 74 | tmpls = dict((row['id'], row['product_tmpl_id']) for row in prods) |
42 | 77 | context=context)['product_tmpl_id'] | 75 | for prod_id, value in result.iteritems(): |
43 | 78 | _logger.debug("set price history: %s, product_tpl_id: %s, " | 76 | tmpl_id = tmpls[prod_id] |
44 | 79 | "context: %s", | 77 | prod_tpl_obj._log_price_change(cr, uid, tmpl_id, |
35 | 80 | value, | ||
36 | 81 | tpl_id, | ||
37 | 82 | context) | ||
38 | 83 | prod_tpl_obj._log_price_change(cr, uid, id, | ||
45 | 84 | field_name, | 78 | field_name, |
46 | 85 | value, | 79 | value, |
47 | 86 | context=context) | 80 | context=context) |
48 | @@ -101,9 +95,6 @@ | |||
49 | 101 | fields = list(set(fields)) | 95 | fields = list(set(fields)) |
50 | 102 | fields.remove('cost_price') | 96 | fields.remove('cost_price') |
51 | 103 | self._set_field_name_values(cr, uid, ids, 'cost_price', context) | 97 | self._set_field_name_values(cr, uid, ids, 'cost_price', context) |
52 | 104 | _logger.debug("call _store_set_values, ids %s, fields: %s", | ||
53 | 105 | ids, | ||
54 | 106 | fields) | ||
55 | 107 | res = super(product_product, self)._store_set_values(cr, | 98 | res = super(product_product, self)._store_set_values(cr, |
56 | 108 | uid, | 99 | uid, |
57 | 109 | ids, | 100 | ids, |
58 | @@ -138,37 +129,57 @@ | |||
59 | 138 | context=None, load='_classic_read'): | 129 | context=None, load='_classic_read'): |
60 | 139 | if context is None: | 130 | if context is None: |
61 | 140 | context = {} | 131 | context = {} |
63 | 141 | if fields: | 132 | if not fields: |
64 | 133 | fields = [] | ||
65 | 134 | else: | ||
66 | 135 | fields = fields[:] # avoid to modify the callee's list | ||
67 | 136 | if fields and not 'id' in fields: | ||
68 | 142 | fields.append('id') | 137 | fields.append('id') |
69 | 143 | pt_obj = self.pool.get('product.template') | 138 | pt_obj = self.pool.get('product.template') |
70 | 139 | |||
71 | 140 | historized_fields = [f for f in fields if f in PRODUCT_FIELD_HISTORIZE] | ||
72 | 141 | remove_tmpl_field = False | ||
73 | 142 | if fields and not 'product_tmpl_id' in fields and historized_fields: | ||
74 | 143 | remove_tmpl_field = True | ||
75 | 144 | fields.append('product_tmpl_id') | ||
76 | 145 | |||
77 | 144 | results = super(product_product, self)._read_flat(cr, uid, ids, | 146 | results = super(product_product, self)._read_flat(cr, uid, ids, |
78 | 145 | fields, | 147 | fields, |
79 | 146 | context=context, | 148 | context=context, |
80 | 147 | load=load) | 149 | load=load) |
81 | 148 | # Note if fields is empty => read all, so look at history table | 150 | # Note if fields is empty => read all, so look at history table |
83 | 149 | if not fields or any([f in PRODUCT_FIELD_HISTORIZE for f in fields]): | 151 | if not fields or historized_fields: |
84 | 150 | date_crit = False | 152 | date_crit = False |
85 | 151 | price_history = self.pool.get('product.price.history') | 153 | price_history = self.pool.get('product.price.history') |
86 | 152 | company_id = pt_obj._get_transaction_company_id(cr, uid, | 154 | company_id = pt_obj._get_transaction_company_id(cr, uid, |
87 | 153 | context=context) | 155 | context=context) |
88 | 154 | if context.get('to_date'): | 156 | if context.get('to_date'): |
89 | 155 | date_crit = context['to_date'] | 157 | date_crit = context['to_date'] |
94 | 156 | # if fields is empty we read all price fields | 158 | if load == '_classic_write': |
95 | 157 | if not fields: | 159 | # list of ids |
96 | 158 | price_fields = PRODUCT_FIELD_HISTORIZE | 160 | tmpl_ids = [row['product_tmpl_id'] for row in results] |
93 | 159 | # Otherwise we filter on price fields asked in read | ||
97 | 160 | else: | 161 | else: |
106 | 161 | price_fields = [f for f in PRODUCT_FIELD_HISTORIZE | 162 | # list of (id, name) |
107 | 162 | if f in fields] | 163 | tmpl_ids = [row['product_tmpl_id'][0] for row in results] |
108 | 163 | prod_prices = price_history._get_historic_price(cr, uid, | 164 | prod_prices = price_history._get_historic_price( |
109 | 164 | ids, | 165 | cr, uid, |
110 | 165 | company_id, | 166 | tmpl_ids, |
111 | 166 | datetime=date_crit, | 167 | company_id, |
112 | 167 | field_names=price_fields, | 168 | datetime=date_crit, |
113 | 168 | context=context) | 169 | field_names=historized_fields or PRODUCT_FIELD_HISTORIZE, |
114 | 170 | context=context) | ||
115 | 169 | for result in results: | 171 | for result in results: |
117 | 170 | dict_value = prod_prices[result['id']] | 172 | if load == '_classic_write': |
118 | 173 | tmpl_id = result['product_tmpl_id'] | ||
119 | 174 | else: | ||
120 | 175 | tmpl_id = result['product_tmpl_id'][0] | ||
121 | 176 | dict_value = prod_prices[tmpl_id] | ||
122 | 171 | result.update(dict_value) | 177 | result.update(dict_value) |
123 | 178 | |||
124 | 179 | if remove_tmpl_field: | ||
125 | 180 | for row in results: | ||
126 | 181 | # this field was not asked by the callee | ||
127 | 182 | del row['product_tmpl_id'] | ||
128 | 172 | return results | 183 | return results |
129 | 173 | 184 | ||
130 | 174 | def _product_value(self, cr, uid, ids, field_names=None, | 185 | def _product_value(self, cr, uid, ids, field_names=None, |
131 | @@ -184,8 +195,6 @@ | |||
132 | 184 | products = self.read(cr, uid, ids, | 195 | products = self.read(cr, uid, ids, |
133 | 185 | ['id', 'qty_available', 'cost_price'], | 196 | ['id', 'qty_available', 'cost_price'], |
134 | 186 | context=context) | 197 | context=context) |
135 | 187 | _logger.debug("product value get, result :%s, context: %s", | ||
136 | 188 | products, context) | ||
137 | 189 | for product in products: | 198 | for product in products: |
138 | 190 | res[product['id']] = product['qty_available'] * product['cost_price'] | 199 | res[product['id']] = product['qty_available'] * product['cost_price'] |
139 | 191 | return res | 200 | return res |
140 | 192 | 201 | ||
141 | === modified file 'product_historical_margin/account_invoice_view.xml' | |||
142 | --- product_historical_margin/account_invoice_view.xml 2013-11-28 15:20:12 +0000 | |||
143 | +++ product_historical_margin/account_invoice_view.xml 2014-02-05 09:14:09 +0000 | |||
144 | @@ -31,6 +31,34 @@ | |||
145 | 31 | </field> | 31 | </field> |
146 | 32 | </record> | 32 | </record> |
147 | 33 | 33 | ||
148 | 34 | <record id="view_invoice_line_form_from_product" model="ir.ui.view"> | ||
149 | 35 | <field name="name">account.invoice.line.from.product.form</field> | ||
150 | 36 | <field name="model">account.invoice.line</field> | ||
151 | 37 | <field name="arch" type="xml"> | ||
152 | 38 | <form string="Invoice Line" create="false"> | ||
153 | 39 | <field name="invoice_type"/> | ||
154 | 40 | <field name="partner_id"/> | ||
155 | 41 | <field name="invoice_user_id"/> | ||
156 | 42 | <field name="invoice_id"/> | ||
157 | 43 | <field name="invoice_date"/> | ||
158 | 44 | <field name="name" invisible="1"/> | ||
159 | 45 | <field name="product_id"/> | ||
160 | 46 | <field name="account_id" invisible="1"/> | ||
161 | 47 | <field name="quantity"/> | ||
162 | 48 | <field name="uos_id"/> | ||
163 | 49 | <field name="price_unit" invisible="1"/> | ||
164 | 50 | <field name="discount" invisible="1"/> | ||
165 | 51 | <field name="price_subtotal" invisible="1"/> | ||
166 | 52 | <field name="subtotal_cost_price" invisible="1"/> | ||
167 | 53 | <field name="company_id" invisible="1"/> | ||
168 | 54 | <field name="subtotal_company" sum="Total Net Sales "/> | ||
169 | 55 | <field name="subtotal_cost_price_company" sum="Total Cost"/> | ||
170 | 56 | <field name="margin_absolute" sum="Total Absolute Margin"/> | ||
171 | 57 | <field name="margin_relative" /> | ||
172 | 58 | </form> | ||
173 | 59 | </field> | ||
174 | 60 | </record> | ||
175 | 61 | |||
176 | 34 | <record id="view_account_invoice_line_filter" model="ir.ui.view"> | 62 | <record id="view_account_invoice_line_filter" model="ir.ui.view"> |
177 | 35 | <field name="name">account.invoice.line.select</field> | 63 | <field name="name">account.invoice.line.select</field> |
178 | 36 | <field name="model">account.invoice.line</field> | 64 | <field name="model">account.invoice.line</field> |
179 | 37 | 65 | ||
180 | === modified file 'product_price_history/product_price_history.py' | |||
181 | --- product_price_history/product_price_history.py 2013-12-11 15:09:00 +0000 | |||
182 | +++ product_price_history/product_price_history.py 2014-02-05 09:14:09 +0000 | |||
183 | @@ -22,7 +22,7 @@ | |||
184 | 22 | 22 | ||
185 | 23 | import logging | 23 | import logging |
186 | 24 | import time | 24 | import time |
188 | 25 | from openerp.osv import orm, fields | 25 | from openerp.osv import orm, fields, expression |
189 | 26 | import openerp.addons.decimal_precision as dp | 26 | import openerp.addons.decimal_precision as dp |
190 | 27 | from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT | 27 | from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT |
191 | 28 | 28 | ||
192 | @@ -140,6 +140,19 @@ | |||
193 | 140 | "goods stored at this Location, or any of its children."), | 140 | "goods stored at this Location, or any of its children."), |
194 | 141 | } | 141 | } |
195 | 142 | 142 | ||
196 | 143 | def open_product_historic_prices(self, cr, uid, ids, context=None): | ||
197 | 144 | if context is None: | ||
198 | 145 | context = {} | ||
199 | 146 | prod_tpl_obj = self.pool.get('product.template') | ||
200 | 147 | prod_tpl_ids = [] | ||
201 | 148 | for product in self.browse(cr, uid, ids, context=context): | ||
202 | 149 | if product.product_tmpl_id.id not in prod_tpl_ids: | ||
203 | 150 | prod_tpl_ids.append(product.product_tmpl_id.id) | ||
204 | 151 | res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, | ||
205 | 152 | 'product_price_history', 'action_price_history', context=context) | ||
206 | 153 | res['domain'] = expression.AND([res.get('domain', []), | ||
207 | 154 | [('product_id', 'in', prod_tpl_ids)]]) | ||
208 | 155 | return res | ||
209 | 143 | 156 | ||
210 | 144 | class product_template(orm.Model): | 157 | class product_template(orm.Model): |
211 | 145 | _inherit = "product.template" | 158 | _inherit = "product.template" |
212 | 146 | 159 | ||
213 | === modified file 'product_price_history/product_price_history_view.xml' | |||
214 | --- product_price_history/product_price_history_view.xml 2013-12-10 13:52:28 +0000 | |||
215 | +++ product_price_history/product_price_history_view.xml 2014-02-05 09:14:09 +0000 | |||
216 | @@ -56,10 +56,10 @@ | |||
217 | 56 | <field name="product_id"/> | 56 | <field name="product_id"/> |
218 | 57 | <field name="company_id" groups="base.group_multi_company"/> | 57 | <field name="company_id" groups="base.group_multi_company"/> |
219 | 58 | <group expand="0" string="Group By..."> | 58 | <group expand="0" string="Group By..."> |
224 | 59 | <filter string="Date" icon="terp-go-month" domain="[]" context="{'group_by':'datetime'}"/> | 59 | <filter string="Date" name="group_date" icon="terp-go-month" domain="[]" context="{'group_by':'datetime'}"/> |
225 | 60 | <filter string="Product" domain="[]" context="{'group_by':'product_id'}"/> | 60 | <filter string="Product" name="group_product_id" domain="[]" context="{'group_by':'product_id'}"/> |
226 | 61 | <filter string="Name" domain="[]" context="{'group_by':'name'}"/> | 61 | <filter string="Name" domain="[]" name="group_name" context="{'group_by':'name'}"/> |
227 | 62 | <filter string="Company" domain="[]" context="{'group_by':'company_id'}" groups="base.group_multi_company"/> | 62 | <filter string="Company" domain="[]" name="group_company_id" context="{'group_by':'company_id'}" groups="base.group_multi_company"/> |
228 | 63 | </group> | 63 | </group> |
229 | 64 | </search> | 64 | </search> |
230 | 65 | 65 | ||
231 | @@ -73,18 +73,34 @@ | |||
232 | 73 | <field name="view_type">form</field> | 73 | <field name="view_type">form</field> |
233 | 74 | <field name="view_id" ref="view_product_price_history_from_product"/> | 74 | <field name="view_id" ref="view_product_price_history_from_product"/> |
234 | 75 | <field name="search_view_id" ref="view_product_price_history_filter"/> | 75 | <field name="search_view_id" ref="view_product_price_history_filter"/> |
235 | 76 | <field name="context">{'search_default_group_product_id':1,'search_default_group_name': 1,'group_by':[]}</field> | ||
236 | 76 | </record> | 77 | </record> |
237 | 77 | 78 | ||
239 | 78 | <act_window | 79 | |
240 | 80 | <menuitem action="action_price_history" | ||
241 | 81 | id="menu_product_price_history_action_form" | ||
242 | 82 | parent="stock.next_id_61" sequence="2"/> | ||
243 | 83 | |||
244 | 84 | <!-- <act_window | ||
245 | 79 | context="{'search_default_product_id': [active_id], 'default_product_id': active_id}" | 85 | context="{'search_default_product_id': [active_id], 'default_product_id': active_id}" |
246 | 80 | id="act_product_prices_history_open" | 86 | id="act_product_prices_history_open" |
247 | 81 | name="Prices History" | 87 | name="Prices History" |
248 | 82 | res_model="product.price.history" | 88 | res_model="product.price.history" |
254 | 83 | src_model="product.product"/> | 89 | src_model="product.product"/> --> |
255 | 84 | 90 | ||
256 | 85 | <menuitem action="action_price_history" | 91 | <record id="product_search_form_view_stock" model="ir.ui.view"> |
257 | 86 | id="menu_product_price_history_action_form" | 92 | <field name="name">product.product.price_history.form</field> |
258 | 87 | parent="stock.next_id_61" sequence="2"/> | 93 | <field name="model">product.product</field> |
259 | 94 | <field name="inherit_id" ref="product.product_normal_form_view"/> | ||
260 | 95 | <field name="arch" type="xml"> | ||
261 | 96 | <div class="oe_right oe_button_box" name="buttons" position="inside"> | ||
262 | 97 | <button name="open_product_historic_prices" | ||
263 | 98 | string="Prices History" groups="product.group_costing_method" | ||
264 | 99 | type="object" /> | ||
265 | 100 | </div> | ||
266 | 101 | </field> | ||
267 | 102 | </record> | ||
268 | 103 | |||
269 | 88 | 104 | ||
270 | 89 | </data> | 105 | </data> |
271 | 90 | </openerp> | 106 | </openerp> |
272 | 91 | 107 | ||
273 | === modified file 'product_price_history/wizard/historic_prices.py' | |||
274 | --- product_price_history/wizard/historic_prices.py 2013-12-12 10:09:02 +0000 | |||
275 | +++ product_price_history/wizard/historic_prices.py 2014-02-05 09:14:09 +0000 | |||
276 | @@ -25,8 +25,11 @@ | |||
277 | 25 | 25 | ||
278 | 26 | 26 | ||
279 | 27 | class historic_prices(orm.TransientModel): | 27 | class historic_prices(orm.TransientModel): |
280 | 28 | """ Will display an inventory valuation of the stock with quantity > 0 | ||
281 | 29 | at the given date. | ||
282 | 30 | """ | ||
283 | 28 | _name = 'historic.prices' | 31 | _name = 'historic.prices' |
285 | 29 | _description = 'Product historical prices' | 32 | _description = 'Inventory Valuation' |
286 | 30 | 33 | ||
287 | 31 | def _default_location(self, cr, uid, ids, context=None): | 34 | def _default_location(self, cr, uid, ids, context=None): |
288 | 32 | try: | 35 | try: |
289 | @@ -159,3 +162,4 @@ | |||
290 | 159 | 'domain': domain, | 162 | 'domain': domain, |
291 | 160 | 'search_view_id': filter_id, | 163 | 'search_view_id': filter_id, |
292 | 161 | } | 164 | } |
293 | 165 | |||
294 | 162 | 166 | ||
295 | === modified file 'product_price_history/wizard/historic_prices_view.xml' | |||
296 | --- product_price_history/wizard/historic_prices_view.xml 2013-12-10 10:36:54 +0000 | |||
297 | +++ product_price_history/wizard/historic_prices_view.xml 2014-02-05 09:14:09 +0000 | |||
298 | @@ -32,6 +32,5 @@ | |||
299 | 32 | id="menu_action_product_historic_prices_tree" | 32 | id="menu_action_product_historic_prices_tree" |
300 | 33 | parent="stock.next_id_61" /> | 33 | parent="stock.next_id_61" /> |
301 | 34 | 34 | ||
302 | 35 | |||
303 | 36 | </data> | 35 | </data> |
304 | 37 | </openerp> | 36 | </openerp> |
Hi,
LGTM, thanks !
Just added the same support to open historic price from product form.
Regards