Merge lp:~unifield-team/unifield-wm/us-802 into lp:unifield-wm
- us-802
- Merge into trunk
Proposed by
jftempo
Status: | Merged |
---|---|
Merged at revision: | 2716 |
Proposed branch: | lp:~unifield-team/unifield-wm/us-802 |
Merge into: | lp:unifield-wm |
Diff against target: |
676 lines (+513/-4) 11 files modified
delivery_mechanism/delivery_mechanism.py (+28/-4) product_attributes/__init__.py (+2/-0) product_attributes/__openerp__.py (+1/-0) product_attributes/product_attributes.py (+20/-0) product_attributes/report/__init__.py (+24/-0) product_attributes/report/standard_price_track_changes.mako (+134/-0) product_attributes/report/standard_price_track_changes_report.py (+84/-0) product_attributes/report/standard_price_track_changes_report.xml (+19/-0) product_attributes/security/ir.model.access.csv (+1/-0) product_attributes/standard_price_track_changes.py (+180/-0) specific_rules/stock.py (+20/-0) |
To merge this branch: | bzr merge lp:~unifield-team/unifield-wm/us-802 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
UniField Reviewer Team | Pending | ||
Review via email: mp+283080@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'delivery_mechanism/delivery_mechanism.py' |
2 | --- delivery_mechanism/delivery_mechanism.py 2015-11-23 16:52:52 +0000 |
3 | +++ delivery_mechanism/delivery_mechanism.py 2016-01-19 10:41:08 +0000 |
4 | @@ -733,6 +733,16 @@ |
5 | |
6 | # Write the field according to price type field |
7 | product_obj.write(cr, uid, [line.product_id.id], {'standard_price': new_std_price}) |
8 | + pchanged = False |
9 | + # Is price changed ? |
10 | + if line.cost and move.purchase_line_id: |
11 | + p_price = move.purchase_line_id.price_unit |
12 | + pchanged = abs(p_price - line.cost) > 10**-3 |
13 | + sptc_values = { |
14 | + 'standard_price': new_std_price, |
15 | + 'old_price': line.product_id.standard_price, |
16 | + 'manually_changed': pchanged, |
17 | + } |
18 | |
19 | # Record the values that were chosen in the wizard, so they can be |
20 | # used for inventory valuation of real-time valuation is enabled. |
21 | @@ -741,7 +751,7 @@ |
22 | 'price_currency_id': line.currency.id, |
23 | } |
24 | |
25 | - return average_values |
26 | + return average_values, sptc_values |
27 | |
28 | def _get_values_from_line(self, cr, uid, move, line, db_data, context=None): |
29 | """ |
30 | @@ -925,6 +935,7 @@ |
31 | move_obj = self.pool.get('stock.move') |
32 | sequence_obj = self.pool.get('ir.sequence') |
33 | cur_obj = self.pool.get('res.currency') |
34 | + sptc_obj = self.pool.get('standard.price.track.changes') |
35 | wf_service = netsvc.LocalService("workflow") |
36 | usb_entity = self._get_usb_entity_type(cr, uid) |
37 | |
38 | @@ -983,6 +994,7 @@ |
39 | mirror_data = move_obj.get_mirror_move(cr, uid, [move.id], data_back, context=context)[move.id] |
40 | out_moves = mirror_data['moves'] |
41 | average_values = {} |
42 | + move_sptc_values = [] |
43 | |
44 | for line in move_proc_obj.browse(cr, uid, proc_ids, context=context): |
45 | values = self._get_values_from_line(cr, uid, move, line, db_data_dict, context=context) |
46 | @@ -996,8 +1008,9 @@ |
47 | compute_average = picking.type == 'in' and line.product_id.cost_method == 'average' |
48 | |
49 | if compute_average: |
50 | - average_values = self._compute_average_values(cr, uid, move, line, product_availability, context=context) |
51 | + average_values, sptc_values = self._compute_average_values(cr, uid, move, line, product_availability, context=context) |
52 | values.update(average_values) |
53 | + move_sptc_values.append(sptc_values) |
54 | |
55 | # The quantity |
56 | if line.uom_id.id != move.product_uom.id: |
57 | @@ -1155,7 +1168,12 @@ |
58 | # If there is remaining quantity for the move, put the ID of the move |
59 | # and the remaining quantity to list of moves to put in backorder |
60 | if diff_qty > 0.00 and move.state != 'cancel': |
61 | - backordered_moves.append((move, diff_qty, average_values, data_back)) |
62 | + backordered_moves.append((move, diff_qty, average_values, data_back, move_sptc_values)) |
63 | + else: |
64 | + for sptc_values in move_sptc_values: |
65 | + sptc_obj.track_change(cr, uid, move.product_id.id, |
66 | + _('Reception %s') % move.picking_id.name, |
67 | + sptc_values, context=context) |
68 | |
69 | # UTP-967 |
70 | if move.state != 'cancel' and move.purchase_line_id and move.purchase_line_id.procurement_id: |
71 | @@ -1202,8 +1220,10 @@ |
72 | if backorder_ids: |
73 | backorder_id = backorder_ids[0] |
74 | |
75 | + backorder_name = picking.name |
76 | if not backorder_id: |
77 | backorder_id = self.copy(cr, uid, picking.id, initial_vals_copy, context=context) |
78 | + backorder_name = self.read(cr, uid, backorder_id, ['name'], context=context)['name'] |
79 | |
80 | back_order_post_copy_vals = {} |
81 | if usb_entity == self.CENTRAL_PLATFORM and context.get('rw_backorder_name', False): |
82 | @@ -1220,7 +1240,11 @@ |
83 | if back_order_post_copy_vals: |
84 | self.write(cr, uid, backorder_id, back_order_post_copy_vals, context=context) |
85 | |
86 | - for bo_move, bo_qty, av_values, data_back in backordered_moves: |
87 | + for bo_move, bo_qty, av_values, data_back, move_sptc_values in backordered_moves: |
88 | + for sptc_values in move_sptc_values: |
89 | + sptc_obj.track_change(cr, uid, move.product_id.id, |
90 | + _('Reception %s') % backorder_name, |
91 | + sptc_values, context=context) |
92 | if bo_move.product_qty != bo_qty: |
93 | # Create the corresponding move in the backorder - reset batch - reset asset_id |
94 | bo_values = { |
95 | |
96 | === modified file 'product_attributes/__init__.py' |
97 | --- product_attributes/__init__.py 2013-08-08 14:14:44 +0000 |
98 | +++ product_attributes/__init__.py 2016-01-19 10:41:08 +0000 |
99 | @@ -20,6 +20,8 @@ |
100 | ############################################################################## |
101 | |
102 | import product_attributes |
103 | +import standard_price_track_changes |
104 | import wizard |
105 | +import report |
106 | |
107 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
108 | |
109 | === modified file 'product_attributes/__openerp__.py' |
110 | --- product_attributes/__openerp__.py 2014-12-01 13:28:42 +0000 |
111 | +++ product_attributes/__openerp__.py 2016-01-19 10:41:08 +0000 |
112 | @@ -31,6 +31,7 @@ |
113 | 'init_xml': [ |
114 | 'security/ir.model.access.csv', |
115 | 'wizard/product_where_used_view.xml', |
116 | + 'report/standard_price_track_changes_report.xml', |
117 | 'data/product_section_code.xml', |
118 | 'data/product_supply_source.xml', |
119 | 'data/product_justification_code.xml', |
120 | |
121 | === modified file 'product_attributes/product_attributes.py' |
122 | --- product_attributes/product_attributes.py 2015-11-25 13:05:56 +0000 |
123 | +++ product_attributes/product_attributes.py 2016-01-19 10:41:08 +0000 |
124 | @@ -1055,6 +1055,26 @@ |
125 | (_check_gmdn_code, 'Warning! GMDN code must be digits!', ['gmdn_code']) |
126 | ] |
127 | |
128 | + def create(self, cr, user, vals, context=None): |
129 | + """ |
130 | + At product.product creation, create a standard.price.track.changes |
131 | + record with the standard price as new value and None as old value. |
132 | + :param cr: Cursor to the database |
133 | + :param user: ID of the user that creates the record |
134 | + :param vals: Values of the new product.product to create |
135 | + :param context: Context of the call |
136 | + :return: The ID of the new product.template record |
137 | + """ |
138 | + sptc_obj = self.pool.get('standard.price.track.changes') |
139 | + |
140 | + res = super(product_attributes, self).create(cr, user, vals, |
141 | + context=context) |
142 | + |
143 | + sptc_obj.track_change(cr, user, res, _('Product creation'), vals, |
144 | + context=context) |
145 | + |
146 | + return res |
147 | + |
148 | product_attributes() |
149 | |
150 | |
151 | |
152 | === added directory 'product_attributes/report' |
153 | === added file 'product_attributes/report/__init__.py' |
154 | --- product_attributes/report/__init__.py 1970-01-01 00:00:00 +0000 |
155 | +++ product_attributes/report/__init__.py 2016-01-19 10:41:08 +0000 |
156 | @@ -0,0 +1,24 @@ |
157 | +# -*- coding: utf-8 -*- |
158 | +############################################################################## |
159 | +# |
160 | +# OpenERP, Open Source Management Solution |
161 | +# Copyright (C) 2015 TeMPO consulting, MSF |
162 | +# |
163 | +# This program is free software: you can redistribute it and/or modify |
164 | +# it under the terms of the GNU Affero General Public License as |
165 | +# published by the Free Software Foundation, either version 3 of the |
166 | +# License, or (at your option) any later version. |
167 | +# |
168 | +# This program is distributed in the hope that it will be useful, |
169 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
170 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
171 | +# GNU Affero General Public License for more details. |
172 | +# |
173 | +# You should have received a copy of the GNU Affero General Public License |
174 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
175 | +# |
176 | +############################################################################## |
177 | + |
178 | +import standard_price_track_changes_report |
179 | + |
180 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
181 | |
182 | === added file 'product_attributes/report/standard_price_track_changes.mako' |
183 | --- product_attributes/report/standard_price_track_changes.mako 1970-01-01 00:00:00 +0000 |
184 | +++ product_attributes/report/standard_price_track_changes.mako 2016-01-19 10:41:08 +0000 |
185 | @@ -0,0 +1,134 @@ |
186 | +<?xml version="1.0"?> |
187 | +<?mso-application progid="Excel.Sheet"?> |
188 | +<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" |
189 | + xmlns:o="urn:schemas-microsoft-com:office:office" |
190 | + xmlns:x="urn:schemas-microsoft-com:office:excel" |
191 | + xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" |
192 | + xmlns:html="http://www.w3.org/TR/REC-html40"> |
193 | + <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"> |
194 | + <Author>MSF</Author> |
195 | + <LastAuthor>MSF</LastAuthor> |
196 | + <Created>${time.strftime('%Y-%m-%dT%H:%M:%SZ')|x}</Created> |
197 | + <Company>Medecins Sans Frontieres</Company> |
198 | + <Version>11.9999</Version> |
199 | + </DocumentProperties> |
200 | + <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel"> |
201 | + <WindowHeight>13170</WindowHeight> |
202 | + <WindowWidth>19020</WindowWidth> |
203 | + <WindowTopX>120</WindowTopX> |
204 | + <WindowTopY>60</WindowTopY> |
205 | + <ProtectStructure>False</ProtectStructure> |
206 | + <ProtectWindows>False</ProtectWindows> |
207 | + </ExcelWorkbook> |
208 | + <Styles> |
209 | + <Style ss:ID="line_header"> |
210 | + <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="0"/> |
211 | + <Font ss:FontName="Calibri" x:Family="Swiss" ss:Color="#000000" ss:Bold="1" /> |
212 | + <Interior ss:Color="#E6E6E6" ss:Pattern="Solid"/> |
213 | + <Borders> |
214 | + <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" /> |
215 | + <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" /> |
216 | + <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" /> |
217 | + <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" /> |
218 | + </Borders> |
219 | + </Style> |
220 | + <Style ss:ID="line"> |
221 | + <Alignment ss:Horizontal="Left" ss:Vertical="Center" ss:WrapText="1"/> |
222 | + <Font ss:FontName="Calibri" x:Family="Swiss" ss:Color="#000000" ss:Bold="0" /> |
223 | + <Borders> |
224 | + <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" /> |
225 | + <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" /> |
226 | + <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" /> |
227 | + <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" /> |
228 | + </Borders> |
229 | + </Style> |
230 | + <Style ss:ID="line_short_date"> |
231 | + <Alignment ss:Horizontal="Left" ss:Vertical="Center" ss:WrapText="1"/> |
232 | + <Font ss:FontName="Calibri" x:Family="Swiss" ss:Color="#000000" ss:Bold="0" /> |
233 | + <Borders> |
234 | + <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" /> |
235 | + <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" /> |
236 | + <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" /> |
237 | + <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" /> |
238 | + </Borders> |
239 | + <NumberFormat ss:Format="General Date"/> |
240 | + </Style> |
241 | + </Styles> |
242 | + % for o in objects: |
243 | + <ss:Worksheet ss:Name="${o.default_code|x}"> |
244 | + <Table> |
245 | + <Column ss:AutoFitWidth="1" ss:Width="120" /> |
246 | + <Column ss:AutoFitWidth="1" ss:Width="120" /> |
247 | + <Column ss:AutoFitWidth="1" ss:Width="120" /> |
248 | + <Column ss:AutoFitWidth="1" ss:Width="120" /> |
249 | + <Column ss:AutoFitWidth="1" ss:Width="120" /> |
250 | + <Column ss:AutoFitWidth="1" ss:Width="120" /> |
251 | + |
252 | + <Row> |
253 | + <Cell ss:StyleID="line_header" ss:MergeAcross="1"> |
254 | + <Data ss:Type="String">Product code</Data> |
255 | + </Cell> |
256 | + <Cell ss:StyleID="line" ss:MergeAcross="3"> |
257 | + <Data ss:Type="String">${o.default_code|x}</Data> |
258 | + </Cell> |
259 | + </Row> |
260 | + <Row> |
261 | + <Cell ss:StyleID="line_header" ss:MergeAcross="1"> |
262 | + <Data ss:Type="String">Product description</Data> |
263 | + </Cell> |
264 | + <Cell ss:StyleID="line" ss:MergeAcross="3"> |
265 | + <Data ss:Type="String">${o.name|x}</Data> |
266 | + </Cell> |
267 | + </Row> |
268 | + |
269 | + <!-- Empty row --> |
270 | + <Row></Row> |
271 | + |
272 | + <Row> |
273 | + <Cell ss:StyleID="line_header"> |
274 | + <Data ss:Type="String">Date</Data> |
275 | + </Cell> |
276 | + <Cell ss:StyleID="line_header"> |
277 | + <Data ss:Type="String">User</Data> |
278 | + </Cell> |
279 | + <Cell ss:StyleID="line_header"> |
280 | + <Data ss:Type="String">Old Cost Price</Data> |
281 | + </Cell> |
282 | + <Cell ss:StyleID="line_header"> |
283 | + <Data ss:Type="String">New Cost Price</Data> |
284 | + </Cell> |
285 | + <Cell ss:StyleID="line_header"> |
286 | + <Data ss:Type="String">Transaction</Data> |
287 | + </Cell> |
288 | + <Cell ss:StyleID="line_header"> |
289 | + <Data ss:Type="String">Manually changed (at reception)</Data> |
290 | + </Cell> |
291 | + </Row> |
292 | + % for sptc in getSPTC(o.id): |
293 | + <Row> |
294 | + <Cell ss:StyleID="line_short_date"> |
295 | + <Data ss:Type="DateTime">${sptc.change_date.replace(' ', 'T')|n}.000</Data> |
296 | + </Cell> |
297 | + <Cell ss:StyleID="line"> |
298 | + <Data ss:Type="String">${sptc.user_id.name|x}</Data> |
299 | + </Cell> |
300 | + <Cell ss:StyleID="line"> |
301 | + <Data ss:Type="Number">${sptc.old_standard_price|x}</Data> |
302 | + </Cell> |
303 | + <Cell ss:StyleID="line"> |
304 | + <Data ss:Type="Number">${sptc.new_standard_price|x}</Data> |
305 | + </Cell> |
306 | + <Cell ss:StyleID="line"> |
307 | + <Data ss:Type="String">${sptc.transaction_name or ''|x}</Data> |
308 | + </Cell> |
309 | + <Cell ss:StyleID="line"> |
310 | + <Data ss:Type="String">${sptc.in_price_changed and 'X' or ''|x}</Data> |
311 | + </Cell> |
312 | + </Row> |
313 | + % endfor--> |
314 | + </Table> |
315 | + <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel"> |
316 | + </WorksheetOptions> |
317 | + </ss:Worksheet> |
318 | + % endfor |
319 | +</Workbook> |
320 | \ No newline at end of file |
321 | |
322 | === added file 'product_attributes/report/standard_price_track_changes_report.py' |
323 | --- product_attributes/report/standard_price_track_changes_report.py 1970-01-01 00:00:00 +0000 |
324 | +++ product_attributes/report/standard_price_track_changes_report.py 2016-01-19 10:41:08 +0000 |
325 | @@ -0,0 +1,84 @@ |
326 | +# -*- coding: utf-8 -*- |
327 | +############################################################################## |
328 | +# |
329 | +# OpenERP, Open Source Management Solution |
330 | +# Copyright (C) 2015 TeMPO Consulting, MSF. All Rights Reserved |
331 | +# |
332 | +# This program is free software: you can redistribute it and/or modify |
333 | +# it under the terms of the GNU Affero General Public License as |
334 | +# published by the Free Software Foundation, either version 3 of the |
335 | +# License, or (at your option) any later version. |
336 | +# |
337 | +# This program is distributed in the hope that it will be useful, |
338 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
339 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
340 | +# GNU Affero General Public License for more details. |
341 | +# |
342 | +# You should have received a copy of the GNU Affero General Public License |
343 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
344 | +# |
345 | +############################################################################## |
346 | +import time |
347 | + |
348 | +import pooler |
349 | + |
350 | +from report import report_sxw |
351 | +from msf_supply_doc_export.msf_supply_doc_export import WebKitParser |
352 | +from msf_supply_doc_export.msf_supply_doc_export import getIds |
353 | + |
354 | + |
355 | +class parser_standard_price_track_changes_report_xls(report_sxw.rml_parse): |
356 | + def __init__(self, cr, uid, name, context): |
357 | + super(parser_standard_price_track_changes_report_xls, self).__init__( |
358 | + cr, uid, name, context=context) |
359 | + self.localcontext.update({ |
360 | + 'time': time, |
361 | + 'getSPTC': self._get_sptc, |
362 | + }) |
363 | + |
364 | + def _get_sptc(self, product_id): |
365 | + """ |
366 | + Return the standard.price.track.changes related to the product_id |
367 | + :param product_id: |
368 | + :return: List of browse_record of standard.price.track.changes |
369 | + """ |
370 | + sptc_obj = self.pool.get('standard.price.track.changes') |
371 | + sptc_ids = sptc_obj.search(self.cr, self.uid, [ |
372 | + ('product_id', '=', product_id), |
373 | + ]) |
374 | + return sptc_obj.browse(self.cr, self.uid, sptc_ids) |
375 | + |
376 | + |
377 | +class standard_price_track_changes_report_xls(WebKitParser): |
378 | + """ |
379 | + Parser to generate the Cost Price Track Changes Excel report for a |
380 | + specific product. |
381 | + """ |
382 | + |
383 | + def __init__(self, name, table, rml=False, parser=report_sxw.rml_parse, |
384 | + header='external', store=False): |
385 | + WebKitParser.__init__(self, name, table, rml=rml, parser=parser, |
386 | + header=header, store=store) |
387 | + |
388 | + def create_single_pdf(self, cr, uid, ids, data, report_xml, context=None): |
389 | + report_xml.webkit_debug = 1 |
390 | + report_xml.header= " " |
391 | + report_xml.webkit_header.html = "${_debug or ''|n}" |
392 | + return super(standard_price_track_changes_report_xls, |
393 | + self).create_single_pdf(cr, uid, ids, data, report_xml, |
394 | + context=context) |
395 | + |
396 | + def create(self, cr, uid, ids, data, context=None): |
397 | + ids = getIds(self, cr, uid, ids, context) |
398 | + a = super(standard_price_track_changes_report_xls, self).create(cr, |
399 | + uid, |
400 | + ids, |
401 | + data, |
402 | + context) |
403 | + return a[0], 'xls' |
404 | + |
405 | +standard_price_track_changes_report_xls( |
406 | + 'report.product.cost.track.changes.xls', |
407 | + 'product.product', |
408 | + 'addons/product_attributes/report/standard_price_track_changes.mako', |
409 | + parser=parser_standard_price_track_changes_report_xls) |
410 | \ No newline at end of file |
411 | |
412 | === added file 'product_attributes/report/standard_price_track_changes_report.xml' |
413 | --- product_attributes/report/standard_price_track_changes_report.xml 1970-01-01 00:00:00 +0000 |
414 | +++ product_attributes/report/standard_price_track_changes_report.xml 2016-01-19 10:41:08 +0000 |
415 | @@ -0,0 +1,19 @@ |
416 | +<?xml version="1.0" encoding="utf-8" ?> |
417 | +<openerp> |
418 | + <data> |
419 | + |
420 | + <!-- Product Cost Price Track Changes --> |
421 | + <report |
422 | + id="report_product_cost_track_changes_xls" |
423 | + string="Track changes - Product prices" |
424 | + model="product.product" |
425 | + name="product.cost.track.changes.xls" |
426 | + file="product_attributes/report/standard_price_track_changes.mako" |
427 | + report_type="webkit" |
428 | + header="False" |
429 | + auto="False" |
430 | + menu="True" |
431 | + /> |
432 | + |
433 | + </data> |
434 | +</openerp> |
435 | \ No newline at end of file |
436 | |
437 | === modified file 'product_attributes/security/ir.model.access.csv' |
438 | --- product_attributes/security/ir.model.access.csv 2012-08-02 16:08:42 +0000 |
439 | +++ product_attributes/security/ir.model.access.csv 2016-01-19 10:41:08 +0000 |
440 | @@ -3,3 +3,4 @@ |
441 | "access_product_justification_code_all","product.justification.code.all","model_product_justification_code",,1,1,1,1 |
442 | "access_product_supply_source_all","product.supply.source.all","model_product_supply_source",,1,1,1,1 |
443 | "access_res_country_restriction_all","res.country.restriction.all","model_res_country_restriction",,1,1,1,1 |
444 | +"access_standrad_price_track_changes_all","standard.price.track.changes.all","model_standard_price_track_changes",,1,1,1,1 |
445 | |
446 | === added file 'product_attributes/standard_price_track_changes.py' |
447 | --- product_attributes/standard_price_track_changes.py 1970-01-01 00:00:00 +0000 |
448 | +++ product_attributes/standard_price_track_changes.py 2016-01-19 10:41:08 +0000 |
449 | @@ -0,0 +1,180 @@ |
450 | +# encoding: utf-8 |
451 | +############################################################################## |
452 | +# |
453 | +# OpenERP, Open Source Management Solution |
454 | +# Copyright (C) 2015 TeMPO consulting, MSF |
455 | +# |
456 | +# This program is free software: you can redistribute it and/or modify |
457 | +# it under the terms of the GNU General Public License as published by |
458 | +# the Free Software Foundation, either version 3 of the License, or |
459 | +# (at your option) any later version. |
460 | +# |
461 | +# This program is distributed in the hope that it will be useful, |
462 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
463 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
464 | +# GNU General Public License for more details. |
465 | +# |
466 | +# You should have received a copy of the GNU General Public License |
467 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
468 | +# |
469 | +############################################################################## |
470 | +import time |
471 | + |
472 | +import decimal_precision as dp |
473 | + |
474 | +from tools.translate import _ |
475 | +from osv import fields |
476 | +from osv import osv |
477 | + |
478 | + |
479 | +class standard_price_track_changes(osv.osv): |
480 | + """ |
481 | + Records the modification of the cost price (standard_price) of a product. |
482 | + It is complementary (but independent) to the Track Changes feature. |
483 | + |
484 | + To record the modification of the cost price, the product Costing Method |
485 | + should always be average price. The recorded prices are always in |
486 | + functional currency. |
487 | + |
488 | + Here is the list of transactions where a modification of the cost price |
489 | + is recorded: |
490 | + * at original import/creation of Product, |
491 | + * at Initial stock inventory, |
492 | + * Each time product is received via IN, cost is re-calculated based on |
493 | + Moving Average Cost calculation, |
494 | + * When Product Cost re-valuation is done. |
495 | + |
496 | + These records are only available with an Excel report on the product form. |
497 | + """ |
498 | + _name = 'standard.price.track.changes' |
499 | + _description = 'Product Cost Price Track Changes' |
500 | + _rec_name = 'change_date' |
501 | + _order = 'change_date, id' |
502 | + |
503 | + _columns = { |
504 | + 'change_date': fields.datetime( |
505 | + string='Date', |
506 | + required=True, |
507 | + readonly=True, |
508 | + ), |
509 | + 'product_id': fields.many2one( |
510 | + 'product.product', |
511 | + string='Product', |
512 | + required=True, |
513 | + readonly=True, |
514 | + ondelete='cascade', |
515 | + ), |
516 | + 'old_standard_price': fields.float( |
517 | + string='Old Cost Price', |
518 | + digits_compute=dp.get_precision('Account'), |
519 | + required=False, |
520 | + readonly=True, |
521 | + ), |
522 | + 'new_standard_price': fields.float( |
523 | + string='New Cost Price', |
524 | + digits_compute=dp.get_precision('Account'), |
525 | + required=True, |
526 | + readonly=True, |
527 | + ), |
528 | + 'user_id': fields.many2one( |
529 | + 'res.users', |
530 | + string='User', |
531 | + required=True, |
532 | + readonly=True, |
533 | + ondelete='set null', |
534 | + ), |
535 | + 'transaction_name': fields.char( |
536 | + string='Transaction name', |
537 | + size=256, |
538 | + required=False, |
539 | + readonly=True, |
540 | + translate=True, |
541 | + help="Name of the transaction which changed the product cost price", |
542 | + ), |
543 | + 'in_price_changed': fields.boolean( |
544 | + string='IN price changed', |
545 | + help="True if the price has been manually changed during reception", |
546 | + ), |
547 | + } |
548 | + |
549 | + _defaults = { |
550 | + 'change_date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), |
551 | + 'user_id': lambda obj, cr, uid, c={}: hasattr(uid, 'realUid') and uid.realUid or uid, |
552 | + 'in_price_changed': False, |
553 | + } |
554 | + |
555 | + def copy(self, cr, uid, obj_id, default=None, context=None): |
556 | + """ |
557 | + Disallow the possibility to copy standard.price.track.changes object |
558 | + :param cr: Cursor to the database |
559 | + :param uid: ID of the user that copy the record |
560 | + :param obj_id: ID of the standard.price.track.changes to copy |
561 | + :param default: Default values for the new record |
562 | + :param context: Context of the call |
563 | + :return: The ID of the new standard.price.track.changes record |
564 | + """ |
565 | + raise osv.except_osv( |
566 | + _('Operation not allowed'), |
567 | + _('Copy of standard.price.track.changes is not allowed'), |
568 | + ) |
569 | + |
570 | + def track_change(self, cr, uid, product_id, transaction_name, vals=None, |
571 | + context=None): |
572 | + """ |
573 | + Create a new standard.price.track.changes record linked to the given |
574 | + `product_id`. Values are taken from `vals` or from the product |
575 | + information if the value is not in `vals`. |
576 | + :param cr: Cursor to the database |
577 | + :param uid: ID of the user that creates the record |
578 | + :param product_id: ID of the product.product which the cost price was |
579 | + changed |
580 | + :param transaction_name: Label of the transaction that made the price |
581 | + change |
582 | + :param vals: Values of the transaction |
583 | + :param context: Context of the call |
584 | + :return: The ID of new standard.price.track.changes record |
585 | + """ |
586 | + prod_obj = self.pool.get('product.product') |
587 | + |
588 | + if vals is None: |
589 | + vals = {} |
590 | + |
591 | + prod_info = prod_obj.read(cr, uid, product_id, [ |
592 | + 'cost_method', |
593 | + 'standard_price', |
594 | + ], context=context) |
595 | + |
596 | + # If the product costing method is not 'Average Price', don't track |
597 | + # price changes. |
598 | + if vals.get('cost_method', prod_info['cost_method']) != 'average': |
599 | + return None |
600 | + |
601 | + new_price = vals.get('standard_price', False) |
602 | + old_price = vals.get('old_price', False) |
603 | + |
604 | + if new_price and old_price and abs(new_price - old_price) <= 10**-3: |
605 | + return None |
606 | + |
607 | + # If it is the first standard.price.track.changes for this product |
608 | + # the old price must be False and the new price is the current |
609 | + # standard price of the product. |
610 | + if not old_price: |
611 | + new_sptc = self.search(cr, uid, [ |
612 | + ('product_id', '=', product_id), |
613 | + ], limit=1, context=context) |
614 | + if new_sptc: |
615 | + old_price = prod_info['standard_price'] |
616 | + elif not new_price: |
617 | + new_price = prod_info['standard_price'] |
618 | + |
619 | + return self.create(cr, uid, { |
620 | + 'product_id': product_id, |
621 | + 'old_standard_price': old_price, |
622 | + 'new_standard_price': new_price, |
623 | + 'transaction_name': transaction_name, |
624 | + 'in_price_changed': vals.get('manually_changed', False), |
625 | + }, context=context) |
626 | + |
627 | +standard_price_track_changes() |
628 | + |
629 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
630 | |
631 | === modified file 'specific_rules/stock.py' |
632 | --- specific_rules/stock.py 2015-11-09 09:46:22 +0000 |
633 | +++ specific_rules/stock.py 2016-01-19 10:41:08 +0000 |
634 | @@ -136,10 +136,20 @@ |
635 | |
636 | move_obj = self.pool.get('stock.move') |
637 | prod_obj = self.pool.get('product.product') |
638 | + sptc_obj = self.pool.get('standard.price.track.changes') |
639 | for inv in self.browse(cr, uid, ids, context=context): |
640 | # Set the cost price on product form with the new value, and process the stock move |
641 | for move in inv.move_ids: |
642 | new_std_price = move.price_unit |
643 | + sptc_obj.track_change(cr, |
644 | + uid, |
645 | + move.product_id.id, |
646 | + _('Initial stock inventory %s') % inv.name, |
647 | + vals={ |
648 | + 'standard_price': new_std_price, |
649 | + 'old_price': move.product_id.standard_price, |
650 | + }, |
651 | + context=context) |
652 | prod_obj.write(cr, uid, move.product_id.id, {'standard_price': new_std_price}, context=context) |
653 | move_obj.action_done(cr, uid, move.id, context=context) |
654 | |
655 | @@ -477,11 +487,21 @@ |
656 | ''' |
657 | Change the price of the products in the lines |
658 | ''' |
659 | + sptc_obj = self.pool.get('standard.price.track.changes') |
660 | + |
661 | if isinstance(ids, (int, long)): |
662 | ids = [ids] |
663 | |
664 | for obj in self.browse(cr, uid, ids, context=context): |
665 | for line in obj.reevaluation_line_ids: |
666 | + sptc_obj.track_change(cr, |
667 | + uid, |
668 | + line.product_id.id, |
669 | + _('Product cost reevaluation %s') % obj.name, |
670 | + vals={ |
671 | + 'standard_price': line.average_cost, |
672 | + 'old_price': line.product_id.standard_price, |
673 | + }, context=context) |
674 | self.pool.get('product.product').write(cr, uid, line.product_id.id, {'standard_price': line.average_cost}) |
675 | |
676 | return self.write(cr, uid, ids, {'state': 'done'}, context=context) |