Merge lp:~npg-team/openobject-addons/assembly_bom_npg into lp:openobject-addons
- assembly_bom_npg
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Fabien (Open ERP) |
Proposed branch: | lp:~npg-team/openobject-addons/assembly_bom_npg |
Merge into: | lp:openobject-addons |
Diff against target: |
3197 lines (+3075/-0) 21 files modified
assembly_bom/__init__.py (+30/-0) assembly_bom/__openerp__.py (+53/-0) assembly_bom/change_log.txt (+85/-0) assembly_bom/mrp.py (+98/-0) assembly_bom/procurement.py (+60/-0) assembly_bom/product.py (+242/-0) assembly_bom/product_view.xml (+18/-0) assembly_bom/report/__init__.py (+24/-0) assembly_bom/report/consumption_report.py (+87/-0) assembly_bom/report/consumption_report.rml (+119/-0) assembly_bom/report/delivery_report.py (+70/-0) assembly_bom/report/delivery_report.rml (+384/-0) assembly_bom/report/normalized_oo2rml.xsl (+696/-0) assembly_bom/report/report_view.xml (+23/-0) assembly_bom/report/tiny_sxw2rml.py (+377/-0) assembly_bom/sale.py (+71/-0) assembly_bom/stock.py (+378/-0) assembly_bom/stock_view.xml (+100/-0) assembly_bom/wizard/__init__.py (+24/-0) assembly_bom/wizard/consumption_report_wizard.py (+93/-0) assembly_bom/wizard/consumption_report_wizard.xml (+43/-0) |
To merge this branch: | bzr merge lp:~npg-team/openobject-addons/assembly_bom_npg |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Dony (Odoo) | policy + quick technical scan | Disapprove | |
Review via email: mp+78433@code.launchpad.net |
Commit message
Description of the change
NovaPoint Group has developed this module to provide true assembly sales bom support to OpenERP. Adds a new bom type, allows for assembling the BOM at time of picking. Accurately records the inventory.
Fabien (Open ERP) (fp-tinyerp) wrote : | # |
Fabien (Open ERP) (fp-tinyerp) wrote : | # |
We think it's better to implement this in a community module.
Fabien (Open ERP) (fp-tinyerp) wrote : | # |
it's not normal to add a reporting engine in this module.
Fabien (Open ERP) (fp-tinyerp) wrote : | # |
Hello,
Thank you for this good contribution. I checked your branches and I would suggest to keep them in your own branch for now on, instead of putting them in the official release. Please register them in apps.openerp.com if it's not already done; if people use them in v6.1, we will think about merging them to the official branch.
As these modules have thousands lines of code, we would not have the time to efficiently review the code, check the usability experience and test for v6.1. I propose to review this later on, if we see people using it from apps.
Thanks,
Olivier Dony (Odoo) (odo-openerp) wrote : | # |
Hello,
I would like to explain a little bit more why this merge proposal was rejected, in 2 parts: our policy for merge proposals, then some specific hints.
1. Merge Proposal Acceptance Policy
=======
There may have been contradicting messages about how and when it is useful to make a merge proposal.
We would like to state this policy very clearly, especially now that extra-addons have been deprecated due to the introduction of OpenERP Apps. So we have now added an official Merge Proposal Acceptance Policy to our contributor documentation, please have a look: http://
2. Remarks specific to this merge proposal
=======
In approximate order of importance:
- based on your minimal description (it would help to have more), it looks like this module should be:
+ either a general purpose extra feature that would be a great addition for OpenERP Apps, as explained in the policy, but does not need to be included in official addons now
+ or simply a modification of the original mrp module, to make the implementation simpler and less brittle (if validated functionally)
- the size of the merge proposal diff is very large (+3000 lines) compared to the scope:
+ lot of copy/pasted code from original addons, are they all really necessary? (if yes, please make merge proposals to split the original functions into smaller, more extensible functions)
+ you included a "tiny_sxw2rml.py" script and dependent files that look totally useless and out of place (1100+ lines!)
+ some parts look quite optional or not directly related to the module's purpose, reports, etc.
- there's a cr.commit() in your code, this is unacceptable! (see coding guidelines)
- usability: no tooltips explaining what an assembly bom is and how it differs from phantom bom (on the Bom type selection)
- you should be careful when comparing computed float values, due to float rounding
- no proper description of the features in the module manifest, nor how to use them
- many useless python imports (netsvc, pooler, ...)
- multiple leftover "print" debugging statements
- some remaining commented out code lines, which should be removed
I hope this helps,
Thanks!
Unmerged revisions
- 5304. By Novapoint Group
-
[Add]: assembly_bom module to provide true assembly sales support to OpenERP
Preview Diff
1 | === added directory 'assembly_bom' |
2 | === added file 'assembly_bom/__init__.py' |
3 | --- assembly_bom/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ assembly_bom/__init__.py 2011-10-06 15:31:48 +0000 |
5 | @@ -0,0 +1,30 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# OpenERP, Open Source Management Solution |
10 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
11 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
12 | +# |
13 | +# This program is free software: you can redistribute it and/or modify |
14 | +# it under the terms of the GNU General Public License as published by |
15 | +# the Free Software Foundation, either version 3 of the License, or |
16 | +# (at your option) any later version. |
17 | +# |
18 | +# This program is distributed in the hope that it will be useful, |
19 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | +# GNU General Public License for more details. |
22 | +# |
23 | +# You should have received a copy of the GNU General Public License |
24 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
25 | +# |
26 | +############################################################################## |
27 | + |
28 | +import mrp |
29 | +import report |
30 | +import wizard |
31 | +import product |
32 | +import procurement |
33 | +import stock |
34 | +import sale |
35 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
36 | \ No newline at end of file |
37 | |
38 | === added file 'assembly_bom/__openerp__.py' |
39 | --- assembly_bom/__openerp__.py 1970-01-01 00:00:00 +0000 |
40 | +++ assembly_bom/__openerp__.py 2011-10-06 15:31:48 +0000 |
41 | @@ -0,0 +1,53 @@ |
42 | +# -*- coding: utf-8 -*- |
43 | +############################################################################## |
44 | +# |
45 | +# OpenERP, Open Source Management Solution |
46 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
47 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
48 | +# |
49 | +# This program is free software: you can redistribute it and/or modify |
50 | +# it under the terms of the GNU General Public License as published by |
51 | +# the Free Software Foundation, either version 3 of the License, or |
52 | +# (at your option) any later version. |
53 | +# |
54 | +# This program is distributed in the hope that it will be useful, |
55 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
56 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
57 | +# GNU General Public License for more details. |
58 | +# |
59 | +# You should have received a copy of the GNU General Public License |
60 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
61 | +# |
62 | +############################################################################## |
63 | + |
64 | +{ |
65 | + "name" : "Assembly BoM", |
66 | + "version" : "0.22", |
67 | + "author" : 'NovaPoint Group LLC', |
68 | + "description": """ |
69 | + Adds a new catagory for the BOM as 'assembly bom' |
70 | + """, |
71 | + "category" : "Customization", |
72 | + "website" : "http://www.novapointgroup.com/", |
73 | + "depends" : [ |
74 | + 'base', |
75 | + 'mrp', |
76 | + 'sale', |
77 | + 'stock', |
78 | + ], |
79 | + "init_xml" : [], |
80 | + |
81 | + "demo_xml" : [], |
82 | + |
83 | + "update_xml" : [ |
84 | + 'report/report_view.xml', |
85 | + 'wizard/consumption_report_wizard.xml', |
86 | + 'stock_view.xml', |
87 | + 'product_view.xml', |
88 | + ], |
89 | + "test" : [], |
90 | + "active": False, |
91 | + "installable": True, |
92 | + } |
93 | + |
94 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
95 | \ No newline at end of file |
96 | |
97 | === added file 'assembly_bom/change_log.txt' |
98 | --- assembly_bom/change_log.txt 1970-01-01 00:00:00 +0000 |
99 | +++ assembly_bom/change_log.txt 2011-10-06 15:31:48 +0000 |
100 | @@ -0,0 +1,85 @@ |
101 | +Version 0.22 by Janeesh (22 Sept 2011) |
102 | + * Updation of Weights and price of products of all Bom types |
103 | + |
104 | +Version 0.21 by Vinod (16 Sept 2011) |
105 | + * Weights and price of products which are of type assembly bom is automatically updated with the sum of the values of its components when they change for any component. |
106 | +Version 0.20 by Vinod (15 Sept 2011) |
107 | + * Customized the product view to include the BOM Stock. |
108 | + |
109 | +Version 0.19 by Jabir (18 July 2011) |
110 | + * Removed location filtering according to available products |
111 | + |
112 | +Version 0.18 by Arif (5 July 2011) |
113 | + * Update method on bom |
114 | + |
115 | +Version 0.16 > 0.17 |
116 | + * Display warning on no stock available for product with normal bom and make to order |
117 | + |
118 | +Version 0.15 > 0.16 |
119 | + * Display warning on no stock available according to the location selected |
120 | + |
121 | +Version 0.14 > 0.15 |
122 | + * Fixed the issue with product onchange function on sale order line |
123 | + * Add filtering of stock location according to stock availability on delivery order line |
124 | +Version 0.13 > 0.14 |
125 | + * Done stock checking for assembly bom product |
126 | + * Fixed the default date issue for stock move and stock picking |
127 | +Version 0.12 > 0.13 |
128 | + * Filter Source Location in Stock Moves |
129 | + * Show pop-up alertif there is no stock available in stock move |
130 | + |
131 | +Version 0.11 > 0.12 |
132 | + * Call action_assign for all moves |
133 | + |
134 | +Version 0.10 > 0.11 |
135 | + * commenting |
136 | +Version 0.09 > 0.10 |
137 | + * Added the reference in the report |
138 | + * cleared the issue with the extra move |
139 | + * Added the sale id for the move with sale order of a product with normal BOM |
140 | + * Added the from and to dates in the report |
141 | + * cleared issue with the updation of the shipped (Delivered) field in Sale order Form |
142 | + |
143 | +Version 0.08 > 0.09 |
144 | + * Added the _product_qty function in the product object to correct bom stock value |
145 | + |
146 | +Version 0.07 > 0.08 |
147 | + * Added Sale Order Ref in stock move |
148 | + |
149 | +Version 0.06 > 0.07 |
150 | + * Added date fields in the wizard for consumption report |
151 | + * Made modifications in the find consumption details method |
152 | + * Added one more column in the consumption details report |
153 | + * Modified the find consumption details method in product accordingly |
154 | + |
155 | +Version 0.05 > 0.06 |
156 | + * modified the method 'action_produce_assign_product' in procurement.order object |
157 | + to remove the duplication of production order while the procurement is tried to run from the sale order |
158 | + with a product with assembly bom |
159 | + |
160 | + * Added new py files procurement and product and stock to neatly handle the objects |
161 | + |
162 | +Version 0.04 > 0.05 |
163 | + * Removed unwanted lines from files and modified the consumption report to be working with multiple documents |
164 | + * and showing a no consumption details message in the report if the product is no longer consumed |
165 | + |
166 | +Version 0.03 > 0.04 by Sinoj |
167 | + * Added the defaults value for ware house in the product consumption wizard |
168 | + |
169 | +Version 0.02 > 0.03 by Vijayakanth |
170 | + * Added stock moves to suffice the proper updation of stock ie a move from production to stock then to output and then to |
171 | + customer location and modified the assembly order destination location id so as to move the finished products to stock |
172 | + |
173 | + * Added field parent_bom_id in the move object to support multiple lines in sale order (detailed check pending) |
174 | + |
175 | +Version 0.01 > 0.02 by Vijayakanth |
176 | + * Added a wizard and report to the assembly bom module |
177 | + * Added one more field production ids in stock move table to make it easy |
178 | + for getting the relation ship with production |
179 | + * Added the kit_id field in the move object to store assembly process id (production object) |
180 | + * This is solely for the assembly bom |
181 | + |
182 | + * phantom bom subproducts are sold separately and stock move occures to customer location |
183 | + * assembly bom subroducts are moved to production and tracked using kit_id and finshed goods to customers |
184 | + * Normal bom subproduct move occures when procurement operation completes and its also tracked using production_ids field |
185 | + |
186 | |
187 | === added file 'assembly_bom/mrp.py' |
188 | --- assembly_bom/mrp.py 1970-01-01 00:00:00 +0000 |
189 | +++ assembly_bom/mrp.py 2011-10-06 15:31:48 +0000 |
190 | @@ -0,0 +1,98 @@ |
191 | +# -*- ecoding: utf-8 -*- |
192 | +############################################################################## |
193 | +# |
194 | +# OpenERP, Open Source Management Solution |
195 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
196 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
197 | +# |
198 | +# This program is free software: you can redistribute it and/or modify |
199 | +# it under the terms of the GNU General Public License as published by |
200 | +# the Free Software Foundation, either version 3 of the License, or |
201 | +# (at your option) any later version. |
202 | +# |
203 | +# This program is distributed in the hope that it will be useful, |
204 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
205 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
206 | +# GNU General Public License for more details. |
207 | +# |
208 | +# You should have received a copy of the GNU General Public License |
209 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
210 | +# |
211 | +############################################################################## |
212 | + |
213 | +from osv import fields, osv |
214 | +import netsvc |
215 | +import datetime |
216 | +import time |
217 | + |
218 | +class bom(osv.osv): |
219 | + |
220 | + def _update_product_weight(self, cr, uid, bom_obj, context=None): |
221 | + weight = 0.00 |
222 | + weight_net = 0.00 |
223 | + standard_price = 0.00 |
224 | + if not context: |
225 | + context = {} |
226 | + child_ids = self.search(cr, uid, [('bom_id', 'child_of', [bom_obj.id])], context=context) |
227 | + if child_ids and bom_obj.id in child_ids: |
228 | + child_ids.remove(bom_obj.id) |
229 | + if len(child_ids) == 0: |
230 | + weight = bom_obj.product_id.weight * bom_obj.product_qty |
231 | + weight_net = bom_obj.product_id.weight_net * bom_obj.product_qty |
232 | + standard_price = bom_obj.product_id.standard_price * bom_obj.product_qty |
233 | + else: |
234 | + for bom_child in self.browse(cr, uid, child_ids, context=context): |
235 | + res = self._update_product_weight(cr, uid, bom_child, context=context) |
236 | + weight += res[0] |
237 | + weight_net += res[1] |
238 | + standard_price += res[2] |
239 | + cr.execute('update product_template set weight=%s, weight_net=%s, standard_price=%s where id=%s'%(weight/bom_obj.product_qty, weight_net/bom_obj.product_qty, standard_price/bom_obj.product_qty, bom_obj.product_id.product_tmpl_id.id)) |
240 | +# self.write(cr, uid, bom_obj.product_id.id, {'weight' : weight, 'weight_net' : weight_net, 'standard_price' : standard_price}, context=context) |
241 | + return (weight, weight_net, standard_price) |
242 | + |
243 | + def write(self, cr, uid, ids, vals, context=None): |
244 | + |
245 | + result = super(bom, self).write(cr, uid, ids, vals, context=context) |
246 | + if result: |
247 | + for bom_obj in self.browse(cr,uid,ids,context={}): |
248 | + res = self._update_product_weight(cr,uid,bom_obj,context) |
249 | +# cr.execute('update product_template set weight=%s, weight_net=%s, standard_price=%s where id=%s'%(res[0], res[1], res[2], bom_obj.product_id.product_tmpl_id.id)) |
250 | + return result |
251 | + |
252 | + def create(self, cr, uid, vals, context=None): |
253 | + result = super(bom, self).create(cr, uid, vals, context) |
254 | + bom_obj = self.browse(cr,uid,result,context={}) |
255 | + res = self._update_product_weight(cr,uid,bom_obj,context) |
256 | + return result |
257 | + def _compute_type(self, cr, uid, ids, field_name, arg, context=None): |
258 | + print """ Sets particular method for the selected bom type. |
259 | + @param field_name: Name of the field |
260 | + @param arg: User defined argument |
261 | + @return: Dictionary of values |
262 | + """ |
263 | + res = dict(map(lambda x: (x,''), ids)) |
264 | + for line in self.browse(cr, uid, ids, context=context): |
265 | + if line.type in ('phantom','assembly') and not line.bom_id: |
266 | + res[line.id] = 'set' |
267 | + continue |
268 | + if line.bom_lines or line.type == 'phantom': |
269 | + continue |
270 | + if line.product_id.supply_method == 'produce': |
271 | + if line.product_id.procure_method == 'make_to_stock': |
272 | + res[line.id] = 'stock' |
273 | + else: |
274 | + res[line.id] = 'order' |
275 | + return res |
276 | + |
277 | + |
278 | + |
279 | + _inherit='mrp.bom' |
280 | + _columns={ |
281 | + 'method': fields.function(_compute_type, string='Method', method=True, type='selection', selection=[('',''),('stock','On Stock'),('order','On Order'),('set','Set / Pack')]), |
282 | + 'type': fields.selection([('normal','Normal BoM'),('phantom','Sets / Phantom'),('assembly','Assembly BoM')], 'BoM Type', required=True, |
283 | + help= "If a sub-product is used in several products, it can be useful to create its own BoM. "\ |
284 | + "Though if you don't want separated production orders for this sub-product, select Set/Phantom as BoM type. "\ |
285 | + "If a Phantom BoM is used for a root product, it will be sold and shipped as a set of components, instead of being produced."), |
286 | + } |
287 | +bom() |
288 | + |
289 | |
290 | === added file 'assembly_bom/procurement.py' |
291 | --- assembly_bom/procurement.py 1970-01-01 00:00:00 +0000 |
292 | +++ assembly_bom/procurement.py 2011-10-06 15:31:48 +0000 |
293 | @@ -0,0 +1,60 @@ |
294 | +# -*- ecoding: utf-8 -*- |
295 | +############################################################################## |
296 | +# |
297 | +# OpenERP, Open Source Management Solution |
298 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
299 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
300 | +# |
301 | +# This program is free software: you can redistribute it and/or modify |
302 | +# it under the terms of the GNU General Public License as published by |
303 | +# the Free Software Foundation, either version 3 of the License, or |
304 | +# (at your option) any later version. |
305 | +# |
306 | +# This program is distributed in the hope that it will be useful, |
307 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
308 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
309 | +# GNU General Public License for more details. |
310 | +# |
311 | +# You should have received a copy of the GNU General Public License |
312 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
313 | +# |
314 | +############################################################################## |
315 | + |
316 | +from osv import fields, osv |
317 | +import netsvc |
318 | +import datetime |
319 | +import time |
320 | + |
321 | +class procurement(osv.osv): |
322 | + _inherit="procurement.order" |
323 | + |
324 | + def action_produce_assign_product(self, cr, uid, ids, context=None): |
325 | + """ Blocks the procurement being run for products with assembly bom |
326 | + @param self: The object pointer. |
327 | + @param ids: ids of the procurement order document |
328 | + @param context: standard dictionary |
329 | + @comment: Blocks the procurement to be run for products with assembly bom |
330 | + @return: returns either the Manufacturing order id or 0 |
331 | + """ |
332 | + procurement_obj = self.pool.get('procurement.order') |
333 | + bom_obj=self.pool.get('mrp.bom') |
334 | + sale_line_obj=self.pool.get('sale.order.line') |
335 | + res=[] |
336 | + for procure_record in procurement_obj.browse(cr,uid,ids,context=context): |
337 | + sale_line_ids=sale_line_obj.search(cr,uid,[('procurement_id','=',procure_record.id)],context=context) |
338 | + sale_line_id=sale_line_ids and sale_line_ids[0] or False |
339 | + if sale_line_id: |
340 | + line=sale_line_obj.browse(cr,uid,sale_line_id,context=context) |
341 | + if line.product_id: |
342 | + bom_ids=bom_obj.search(cr,uid,[('product_id','=',line.product_id.id),('type','=','assembly')],context={}) |
343 | + bom_id=bom_ids and bom_ids[0] or False |
344 | + if bom_id: |
345 | + #1. print 'PROCUREMENT:"PROCUREMENT FOR THE PRODUCT:%s, Name:%s" HAS BEEN BLOCKED'%(line.product_id.id,line.product_id.name) |
346 | + return 0 |
347 | + return super(procurement, self).action_produce_assign_product( cr, uid, [procure_record.id], context=context) |
348 | + |
349 | +procurement() |
350 | + |
351 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
352 | + |
353 | + |
354 | |
355 | === added file 'assembly_bom/product.py' |
356 | --- assembly_bom/product.py 1970-01-01 00:00:00 +0000 |
357 | +++ assembly_bom/product.py 2011-10-06 15:31:48 +0000 |
358 | @@ -0,0 +1,242 @@ |
359 | +# -*- coding: utf-8 -*- |
360 | +############################################################################## |
361 | +# |
362 | +# OpenERP, Open Source Management Solution |
363 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
364 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
365 | +# |
366 | +# This program is free software: you can redistribute it and/or modify |
367 | +# it under the terms of the GNU General Public License as published by |
368 | +# the Free Software Foundation, either version 3 of the License, or |
369 | +# (at your option) any later version. |
370 | +# |
371 | +# This program is distributed in the hope that it will be useful, |
372 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
373 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
374 | +# GNU General Public License for more details. |
375 | +# |
376 | +# You should have received a copy of the GNU General Public License |
377 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
378 | +# |
379 | + |
380 | +from osv import fields, osv |
381 | +import netsvc |
382 | +import datetime |
383 | +import time |
384 | + |
385 | +class product_inherit(osv.osv): |
386 | + |
387 | + _inherit = 'product.product' |
388 | + |
389 | + def _product_available(self, cr, uid, ids, field_names=None, arg=False, context=None): |
390 | + """ |
391 | + For showing the bom stock value as 0 for the products with no bom |
392 | + @param self: The object pointer. |
393 | + @param ids: ids of the procurement order document |
394 | + @param context: standard dictionary |
395 | + @comment: If 'bom_stock' is there in the field_names list then if the product is having not bom the bom stock value was |
396 | + shown as real stock value. This override modifies it to zero |
397 | + @return: returns 0 for the above conditions in the standard format dictionary for multi function fields |
398 | + """ |
399 | + res = super(product_inherit, self)._product_available(cr, uid, ids, field_names, arg, context=context) |
400 | + bom_obj=self.pool.get('mrp.bom') |
401 | + if 'bom_stock' in field_names: |
402 | + for product_id, stock_qty in res.iteritems(): |
403 | + product = self.browse(cr, uid, product_id) |
404 | + bom_ids = bom_obj._bom_find(cr, uid, product.id, product.uom_id.id, properties=[]) |
405 | + if not bom_ids: |
406 | + res[product_id]['bom_stock'] = 0 |
407 | + #1. If possible do this by adding this line at 102 c2c_bom_stock.py this is the reason why its not showing the |
408 | + #stock value properly for the products with no boms |
409 | + |
410 | + return res |
411 | + |
412 | + |
413 | + def find_consumption_details(self,cr,uid,ids,context={}): |
414 | + """ |
415 | + Finds the consumption details for the products with ids in 'ids' |
416 | + @param self: The object pointer. |
417 | + @param ids: ids of the procurement order document |
418 | + @param context: standard dictionary |
419 | + @return: returns a list of dictionaries that carries the information regarding the product consumption |
420 | + """ |
421 | + move_obj=self.pool.get('stock.move') |
422 | + product_ids=ids |
423 | + source_loc_id=context.get("source_loc_id",False) |
424 | + start_date=context.get("start_date",False) |
425 | + end_date=context.get("end_date",False) |
426 | + if source_loc_id : |
427 | + for product_id in product_ids: |
428 | + detail_list=[] |
429 | + args=[('product_id',"=",product_id), |
430 | + ('location_id','=',source_loc_id), |
431 | + ('state','=','done')] |
432 | + start_date and args.append(('date',">=",start_date+" 00:00:00")) |
433 | + end_date and args.append(('date',"<=",end_date+" 00:00:00")) |
434 | + move_ids=move_obj.search(cr,uid,args) |
435 | + detail_list=[] |
436 | + for move in move_obj.browse(cr,uid,move_ids): |
437 | + details={} |
438 | + |
439 | + #1. If move is having sale_line_id its assumed to be related with sale |
440 | + if move.sale_line_id: |
441 | + line=move.sale_line_id |
442 | + product_qty=move.product_qty |
443 | + parent_product=move.product_id |
444 | + details={ |
445 | + 'product_name':parent_product.name or "", |
446 | + 'reference':parent_product.default_code or "", |
447 | + 'type':'sale', |
448 | + "product_qty":product_qty, |
449 | + 'consumption':parent_product.name |
450 | + } |
451 | + |
452 | + #2. If move is having production_ids its assumed to be related with production using normal bom |
453 | + if move.production_ids: |
454 | + production=move.production_ids[0] |
455 | + bom=production.bom_id and production.bom_id or False |
456 | + if bom: |
457 | + bom_type=bom.type |
458 | + if bom_type=='normal': |
459 | + parent_product=production.product_id |
460 | + product_name=parent_product.name |
461 | + details={ |
462 | + 'bom_type':bom_type, |
463 | + "product_name":product_name, |
464 | + "product_qty":move.product_qty, |
465 | + "parent_product":parent_product, |
466 | + 'type':'production', |
467 | + 'consumption':product_name+'- '+bom_type, |
468 | + 'bom_type':bom_type, |
469 | + 'reference':parent_product.default_code or "" |
470 | + |
471 | + } |
472 | + #3. If move is having kit_id its assumed to be related with production using assembly bom |
473 | + if move.kit_id: |
474 | + production=move.kit_id |
475 | + if production.state=='done': |
476 | + parent_product=production.product_id |
477 | + bom=production.bom_id and production.bom_id or False |
478 | + if bom: |
479 | + bom_type=bom.type |
480 | + if bom_type=='assembly': |
481 | + product_name=parent_product.name |
482 | + product_qty=move.product_qty |
483 | + details={ |
484 | + 'bom_type':bom_type, |
485 | + "product_name":product_name, |
486 | + "product_qty":move.product_qty, |
487 | + "parent_product":parent_product, |
488 | + 'type':'production', |
489 | + 'consumption':product_name+'- '+bom_type, |
490 | + 'bom_type':bom_type, |
491 | + 'reference':parent_product.default_code or "" |
492 | + } |
493 | + |
494 | + details and detail_list.append(details) |
495 | + details={} |
496 | + consumpt_lines=[] |
497 | + res={} |
498 | + #4. This block analyses the details to aggregate them with reference to type of consumption |
499 | + |
500 | + for detail in detail_list: |
501 | + product_name=detail.get('product_name') |
502 | + consumption=detail.get('consumption') |
503 | + |
504 | + if detail.get('type',False) and detail.get('type',False)=='sale': |
505 | + if res.has_key(consumption): |
506 | + new_qty=res.get(consumption,{}).get('product_qty',0)+detail.get('product_qty',0) |
507 | + res[consumption].update({ |
508 | + 'product_qty':new_qty, |
509 | + 'product_name':product_name |
510 | + } |
511 | + ) |
512 | + else: |
513 | + res[consumption]={ |
514 | + 'product_qty':detail.get('product_qty',0), |
515 | + 'consumption':"%(product_name)s- sold separately"%detail, |
516 | + 'product_name':product_name, |
517 | + 'bom_type':detail.get('bom_type',' '), |
518 | + 'type':'Sold separately', |
519 | + 'reference':detail.get("reference","") |
520 | + } |
521 | + if detail.get('type',False) and detail.get('type',False)=='production': |
522 | + |
523 | + if res.has_key(consumption): |
524 | + new_qty=res.get(consumption,{}).get('product_qty',0)+detail.get('product_qty',0) |
525 | + res[consumption].update({ |
526 | + 'product_qty':new_qty, |
527 | + } |
528 | + ) |
529 | + else: |
530 | + res[consumption]={ |
531 | + 'product_qty':detail.get('product_qty',0), |
532 | + 'consumption':consumption, |
533 | + 'product_name':product_name, |
534 | + 'bom_type':detail.get('bom_type',' '), |
535 | + 'type':'Production using: '+detail.get('bom_type',' ')+' BOM', |
536 | + 'reference':detail.get("reference","") |
537 | + } |
538 | + |
539 | + |
540 | + consumpt_lines=res.values() |
541 | + total_qty=0 |
542 | + #5. Calculating percentage consumption |
543 | + for line in consumpt_lines: |
544 | + total_qty+=line.get('product_qty',0) |
545 | + total_qty=float(total_qty) |
546 | + new_consumpt_lines=[] |
547 | + for line in consumpt_lines: |
548 | + line.update({ |
549 | + 'percentage':round(line.get('product_qty',0)*100/total_qty, 2) |
550 | + }) |
551 | + new_consumpt_lines.append(line) |
552 | + consumpt_lines=new_consumpt_lines |
553 | + |
554 | + if not consumpt_lines: |
555 | + consumpt_lines=False |
556 | + |
557 | + ret={"source_loc_id":source_loc_id,'detail_list':consumpt_lines} |
558 | + |
559 | + return ret |
560 | + else: |
561 | + return {} |
562 | + _columns = { |
563 | + 'qty_available': fields.function(_product_available, method=True, type='float', string='Real Stock', help="Current quantities of products in selected locations or all internal if none have been selected.", multi='qty_available'), |
564 | + 'virtual_available': fields.function(_product_available, method=True, type='float', string='Virtual Stock', help="Futur stock for this product according to the selected location or all internal if none have been selected. Computed as: Real Stock - Outgoing + Incoming.", multi='qty_available'), |
565 | + 'immediately_usable_qty': fields.function(_product_available, method=True, type='float', string='Immediately Usable Stock', help="Quantities of products really available for sale. Computed as: Real Stock - Outgoing.", multi='qty_available'), |
566 | + 'bom_stock': fields.function(_product_available, method=True, type='float', string='BoM Stock Value', help="Quantities of products, useful to know how much of this product you could have. Computed as: (Reference stock of This product + How much could I produce of this product)", multi='qty_available'), |
567 | + } |
568 | + |
569 | + def _get_root_bom(self, cr, uid, bom_obj, context=None): |
570 | + if not context: |
571 | + context = {} |
572 | + if not bom_obj.bom_id: |
573 | +# if bom_obj.type == 'assembly': |
574 | + return bom_obj |
575 | + else: |
576 | + return self._get_root_bom(cr, uid, bom_obj.bom_id, context=context) |
577 | + |
578 | + return False |
579 | + |
580 | + |
581 | + def write(self, cr, uid, ids, vals, context=None): |
582 | + if not context: |
583 | + context = {} |
584 | + res = super(product_inherit, self).write(cr, uid, ids, vals, context=context) |
585 | + |
586 | + if res and (vals.get('weight', False) or vals.get('weight_net', False) or vals.get('standard_price', False)): |
587 | + updated_boms = [] |
588 | + mrp_bom_pool = self.pool.get('mrp.bom') |
589 | + for prod in self.browse(cr, uid, ids, context=context): |
590 | + bom_ids = mrp_bom_pool.search(cr, uid, [('product_id', '=', prod.id)], context=context) |
591 | + for bom_obj in mrp_bom_pool.browse(cr, uid, bom_ids, context=context): |
592 | + root_bom = self._get_root_bom(cr, uid, bom_obj, context=context) |
593 | + if root_bom and root_bom not in updated_boms: |
594 | + updated_boms.append(root_bom) |
595 | + res = mrp_bom_pool._update_product_weight(cr, uid, root_bom, context=context) |
596 | + cr.execute('update product_template set weight=%s, weight_net=%s, standard_price=%s where id=%s'%(res[0]/root_bom.product_qty, res[1]/root_bom.product_qty, res[2]/root_bom.product_qty, root_bom.product_id.product_tmpl_id.id)) |
597 | +# self.write(cr, uid, root_bom.product_id.id, {'weight' : res[0], 'weight_net' : res[1], 'standard_price' : res[2]}, context=context) |
598 | + return res |
599 | + |
600 | +product_inherit() |
601 | \ No newline at end of file |
602 | |
603 | === added file 'assembly_bom/product_view.xml' |
604 | --- assembly_bom/product_view.xml 1970-01-01 00:00:00 +0000 |
605 | +++ assembly_bom/product_view.xml 2011-10-06 15:31:48 +0000 |
606 | @@ -0,0 +1,18 @@ |
607 | +<?xml version="1.0" encoding="utf-8"?> |
608 | +<openerp> |
609 | + <data> |
610 | + <record id="product_product_tree_view_inherit" model="ir.ui.view"> |
611 | + <field name="name">product.product.tree.inherit</field> |
612 | + <field name="model">product.product</field> |
613 | + <field name="type">tree</field> |
614 | + <field name="inherit_id" ref="product.product_product_tree_view"/> |
615 | + <field eval="22" name="priority"/> |
616 | + <field name="arch" type="xml"> |
617 | + <xpath expr="//field[@name='virtual_available']" position="after"> |
618 | + <field name="bom_stock"/> |
619 | + </xpath> |
620 | + </field> |
621 | + </record> |
622 | + |
623 | + </data> |
624 | +</openerp> |
625 | |
626 | === added directory 'assembly_bom/report' |
627 | === added file 'assembly_bom/report/__init__.py' |
628 | --- assembly_bom/report/__init__.py 1970-01-01 00:00:00 +0000 |
629 | +++ assembly_bom/report/__init__.py 2011-10-06 15:31:48 +0000 |
630 | @@ -0,0 +1,24 @@ |
631 | +# -*- coding: utf-8 -*- |
632 | +############################################################################## |
633 | +# |
634 | +# OpenERP, Open Source Management Solution |
635 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
636 | +# |
637 | +# This program is free software: you can redistribute it and/or modify |
638 | +# it under the terms of the GNU Affero General Public License as |
639 | +# published by the Free Software Foundation, either version 3 of the |
640 | +# License, or (at your option) any later version. |
641 | +# |
642 | +# This program is distributed in the hope that it will be useful, |
643 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
644 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
645 | +# GNU Affero General Public License for more details. |
646 | +# |
647 | +# You should have received a copy of the GNU Affero General Public License |
648 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
649 | +# |
650 | +############################################################################## |
651 | + |
652 | +import consumption_report |
653 | + |
654 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
655 | \ No newline at end of file |
656 | |
657 | === added file 'assembly_bom/report/consumption_report.py' |
658 | --- assembly_bom/report/consumption_report.py 1970-01-01 00:00:00 +0000 |
659 | +++ assembly_bom/report/consumption_report.py 2011-10-06 15:31:48 +0000 |
660 | @@ -0,0 +1,87 @@ |
661 | +# -*- coding: utf-8 -*- |
662 | +############################################################################## |
663 | +# |
664 | +# OpenERP, Open Source Management Solution |
665 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
666 | +# |
667 | +# This program is free software: you can redistribute it and/or modify |
668 | +# it under the terms of the GNU Affero General Public License as |
669 | +# published by the Free Software Foundation, either version 3 of the |
670 | +# License, or (at your option) any later version. |
671 | +# |
672 | +# This program is distributed in the hope that it will be useful, |
673 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
674 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
675 | +# GNU Affero General Public License for more details. |
676 | +# |
677 | +# You should have received a copy of the GNU Affero General Public License |
678 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
679 | +# |
680 | +############################################################################## |
681 | + |
682 | +import time |
683 | + |
684 | +from report import report_sxw |
685 | + |
686 | +class consumption_report(report_sxw.rml_parse): |
687 | + def _get_consumption_lines(self,product_id): |
688 | + |
689 | + """ Finds the consumption details for the product |
690 | + @param self: The object pointer. |
691 | + @param product_id: ID of the product |
692 | + @comment: fetches the consumption details of the product using 'find_consumption_details' |
693 | + which analyses stock moves to find consumption details |
694 | + @return: List of dictionaries showing the consumption details |
695 | + """ |
696 | + res=[] |
697 | + detail_list=self.localcontext.get('detail_list',[]) |
698 | + cr=self.cr;uid=self.uid |
699 | + details=self.pool.get("product.product").find_consumption_details(cr,uid,[product_id],context=self.localcontext) |
700 | + detail_list=details.get('detail_list',[]) |
701 | + return detail_list |
702 | + |
703 | + def _get_us_date(self,date_string): |
704 | + """ Converts the input date string to us format |
705 | + @param self: The object pointer. |
706 | + @param date_string: Expects date in ISO format YYYY-MM-DD |
707 | + @comment: uses format_lang method to convert the date to the us format |
708 | + @return: Returns either the us format date or an empty string |
709 | + """ |
710 | + us_string='' |
711 | + if date_string: |
712 | + us_string=self.formatLang(date_string,date=True) |
713 | + return us_string |
714 | + |
715 | + def _format_product_name(self,product_name,reference): |
716 | + """ Adds the product name and reference |
717 | + @param self: The object pointer. |
718 | + @param product_name: name of the product |
719 | + @param reference: Reference of the product |
720 | + @comment: adds the the reference and the product name if there is a reference string |
721 | + @return: returns '[reference] product_name' or 'product_name' |
722 | + """ |
723 | + if reference: |
724 | + reference="[%s] "%reference |
725 | + else: |
726 | + reference="" |
727 | + return reference+product_name |
728 | + |
729 | + def __init__(self, cr, uid, name, context=None): |
730 | + """ Parser __init__ override |
731 | + """ |
732 | + super(consumption_report, self).__init__(cr, uid, name, context=context) |
733 | + self.localcontext.update({ |
734 | + 'time': time, |
735 | + '_get_consumption_lines':self._get_consumption_lines, |
736 | + '_get_':self._get_consumption_lines, |
737 | + '_get_us_date':self._get_us_date, |
738 | + '_format_product_name':self._format_product_name, |
739 | + 'source_loc_id':context.get('source_loc_id', False),#1. location id selected for getting consumption details in the wizard |
740 | + 'start_date':context.get('start_date',False),#2. getting start date selected in the wizard |
741 | + 'end_date':context.get('end_date',False),#3. getting end date selected in the wizard |
742 | + }) |
743 | + |
744 | +report_sxw.report_sxw('report.product.consumption', 'product.product', 'addons/assembly_bom/report/consumption_report.rml', parser=consumption_report, header=False) |
745 | + |
746 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
747 | + |
748 | |
749 | === added file 'assembly_bom/report/consumption_report.rml' |
750 | --- assembly_bom/report/consumption_report.rml 1970-01-01 00:00:00 +0000 |
751 | +++ assembly_bom/report/consumption_report.rml 2011-10-06 15:31:48 +0000 |
752 | @@ -0,0 +1,119 @@ |
753 | +<?xml version="1.0"?> |
754 | +<document filename="test.pdf"> |
755 | + <template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20"> |
756 | + <pageTemplate id="first"> |
757 | + <frame id="first" x1="57.0" y1="57.0" width="481" height="728"/> |
758 | + </pageTemplate> |
759 | + </template> |
760 | + <stylesheet> |
761 | + <blockTableStyle id="Standard_Outline"> |
762 | + <blockAlignment value="LEFT"/> |
763 | + <blockValign value="TOP"/> |
764 | + </blockTableStyle> |
765 | + <blockTableStyle id="Table1"> |
766 | + <blockAlignment value="LEFT"/> |
767 | + <blockValign value="TOP"/> |
768 | + </blockTableStyle> |
769 | + <blockTableStyle id="Table2"> |
770 | + <blockAlignment value="LEFT"/> |
771 | + <blockValign value="TOP"/> |
772 | + </blockTableStyle> |
773 | + <blockTableStyle id="Table3"> |
774 | + <blockAlignment value="LEFT"/> |
775 | + <blockValign value="TOP"/> |
776 | + </blockTableStyle> |
777 | + <blockTableStyle id="Table4"> |
778 | + <blockAlignment value="LEFT"/> |
779 | + <blockValign value="TOP"/> |
780 | + </blockTableStyle> |
781 | + <initialize> |
782 | + <paraStyle name="all" alignment="justify"/> |
783 | + </initialize> |
784 | + <paraStyle name="P1" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/> |
785 | + <paraStyle name="P2" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="CENTER" spaceBefore="12.0" spaceAfter="6.0"/> |
786 | + <paraStyle name="P3" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/> |
787 | + <paraStyle name="P4" fontName="Times-Roman" fontSize="12.0" leading="15" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/> |
788 | + <paraStyle name="P5" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
789 | + <paraStyle name="P6" fontName="Helvetica" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/> |
790 | + <paraStyle name="P7" fontName="Helvetica" fontSize="10.0" leading="13" alignment="CENTER"/> |
791 | + <paraStyle name="P8" fontName="Times-Roman" fontSize="12.0" leading="15" alignment="CENTER"/> |
792 | + <paraStyle name="P9" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/> |
793 | + <paraStyle name="P10" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/> |
794 | + <paraStyle name="Standard" fontName="Times-Roman"/> |
795 | + <paraStyle name="Heading" fontName="Helvetica" fontSize="14.0" leading="17" spaceBefore="12.0" spaceAfter="6.0"/> |
796 | + <paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/> |
797 | + <paraStyle name="List" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/> |
798 | + <paraStyle name="Caption" fontName="Times-Roman" fontSize="12.0" leading="15" spaceBefore="6.0" spaceAfter="6.0"/> |
799 | + <paraStyle name="Index" fontName="Times-Roman"/> |
800 | + <paraStyle name="Table Contents" fontName="Times-Roman"/> |
801 | + <paraStyle name="terp_tblheader_General" fontName="Helvetica" fontSize="8.0" leading="10" spaceBefore="6.0" spaceAfter="6.0"/> |
802 | + <paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/> |
803 | + <paraStyle name="Table Heading" fontName="Times-Roman" alignment="CENTER"/> |
804 | + <paraStyle name="terp_header" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/> |
805 | + <paraStyle name="terp_default_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
806 | + <images/> |
807 | + </stylesheet> |
808 | + <story> |
809 | + <para style="P2">Product Consumption Report</para> |
810 | + <para style="P4">From: [[(_get_us_date(start_date) and _get_us_date(end_date)) and _get_us_date(start_date) or removeParentNode('para')]], To: [[_get_us_date(end_date)]]</para> |
811 | + <para style="P4">From: [[(_get_us_date(start_date) and not _get_us_date(end_date)) and _get_us_date(start_date) or removeParentNode('para')]]</para> |
812 | + <para style="P4">To: [[(_get_us_date(end_date) and not _get_us_date(start_date)) and _get_us_date(end_date) or removeParentNode('para')]]</para> |
813 | + <para style="P8"> |
814 | + <font color="white"> </font> |
815 | + </para> |
816 | + <blockTable colWidths="478.0" style="Table1"> |
817 | + <tr> |
818 | + <td> |
819 | + <para style="P1">[[repeatIn(objects,'o')]]</para> |
820 | + <blockTable colWidths="473.0" style="Table2"> |
821 | + <tr> |
822 | + <td> |
823 | + <para style="P7">[[(_get_consumption_lines(o.id) and ' ') or removeParentNode('para')]]Product Name: <font face="Times-Roman">[[o.name]]</font></para> |
824 | + </td> |
825 | + </tr> |
826 | + </blockTable> |
827 | + <blockTable colWidths="142.0,142.0,95.0,95.0" repeatRows="1" style="Table3"> |
828 | + <tr> |
829 | + <td> |
830 | + <para style="P9">Product[[(_get_consumption_lines(o.id) and ' ') or removeParentNode('blockTable')]]</para> |
831 | + </td> |
832 | + <td> |
833 | + <para style="P10">Consumption Type</para> |
834 | + </td> |
835 | + <td> |
836 | + <para style="terp_tblheader_General_Centre">Quantity</para> |
837 | + </td> |
838 | + <td> |
839 | + <para style="terp_tblheader_General_Centre">Percentage Consumption</para> |
840 | + </td> |
841 | + </tr> |
842 | + </blockTable> |
843 | + <blockTable colWidths="142.0,141.0,95.0,95.0" repeatRows="1" style="Table4"> |
844 | + <tr> |
845 | + <td> |
846 | + <para style="P5">[[repeatIn(_get_consumption_lines(o.id),'line')]] [[_format_product_name(line.get('product_name'),line.get('reference'))]]</para> |
847 | + <para style="P5">[[(_get_consumption_lines(o.id) and ' ') or removeParentNode('blockTable')]]</para> |
848 | + </td> |
849 | + <td> |
850 | + <para style="P5">[[line.get('type')]]</para> |
851 | + </td> |
852 | + <td> |
853 | + <para style="P6">[[line.get('product_qty')]]</para> |
854 | + </td> |
855 | + <td> |
856 | + <para style="P6">[[line.get('percentage')]]</para> |
857 | + </td> |
858 | + </tr> |
859 | + </blockTable> |
860 | + <para style="P3"> |
861 | + <font color="white"> </font> |
862 | + </para> |
863 | + </td> |
864 | + </tr> |
865 | + </blockTable> |
866 | + <para style="P4"> |
867 | + <font color="white"> </font> |
868 | + </para> |
869 | + </story> |
870 | +</document> |
871 | + |
872 | |
873 | === added file 'assembly_bom/report/consumption_report.sxw' |
874 | Binary files assembly_bom/report/consumption_report.sxw 1970-01-01 00:00:00 +0000 and assembly_bom/report/consumption_report.sxw 2011-10-06 15:31:48 +0000 differ |
875 | === added file 'assembly_bom/report/consumption_report_reference+name.sxw' |
876 | Binary files assembly_bom/report/consumption_report_reference+name.sxw 1970-01-01 00:00:00 +0000 and assembly_bom/report/consumption_report_reference+name.sxw 2011-10-06 15:31:48 +0000 differ |
877 | === added file 'assembly_bom/report/consumption_report_reference_column.sxw' |
878 | Binary files assembly_bom/report/consumption_report_reference_column.sxw 1970-01-01 00:00:00 +0000 and assembly_bom/report/consumption_report_reference_column.sxw 2011-10-06 15:31:48 +0000 differ |
879 | === added file 'assembly_bom/report/delivery_report.py' |
880 | --- assembly_bom/report/delivery_report.py 1970-01-01 00:00:00 +0000 |
881 | +++ assembly_bom/report/delivery_report.py 2011-10-06 15:31:48 +0000 |
882 | @@ -0,0 +1,70 @@ |
883 | +# -*- coding: utf-8 -*- |
884 | +############################################################################## |
885 | +# |
886 | +# OpenERP, Open Source Management Solution |
887 | +# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>). |
888 | +# |
889 | +# This program is free software: you can redistribute it and/or modify |
890 | +# it under the terms of the GNU Affero General Public License as |
891 | +# published by the Free Software Foundation, either version 3 of the |
892 | +# License, or (at your option) any later version. |
893 | +# |
894 | +# This program is distributed in the hope that it will be useful, |
895 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
896 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
897 | +# GNU Affero General Public License for more details. |
898 | +# |
899 | +# You should have received a copy of the GNU Affero General Public License |
900 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
901 | +# |
902 | +############################################################################## |
903 | + |
904 | +import time |
905 | + |
906 | +from report import report_sxw |
907 | + |
908 | +class delivery_report(report_sxw.rml_parse): |
909 | + def __init__(self, cr, uid, name, context=None): |
910 | + super(delivery_report, self).__init__(cr, uid, name, context=context) |
911 | + self.localcontext.update({ |
912 | + 'time': time, |
913 | +# 'detail_list':context.get('detail_list', []) |
914 | + '_get_parent':self._get_parent, |
915 | + '_get_childs':self._get_childs |
916 | + }) |
917 | + |
918 | + def _get_parent(self,pick_id): |
919 | + cr=self.cr |
920 | + uid=self.uid |
921 | + context=self.localcontext |
922 | + move_obj=self.pool.get('stock.move') |
923 | + move_ids=move_obj.search(cr,uid,[('picking_id','=',pick_id),("parent_bom_id","!=",False)]) |
924 | + moves=move_obj.browse(cr,uid,move_ids,context=context) |
925 | + for move in moves: |
926 | + production=move.kit_id |
927 | + if production: |
928 | + product_qty=production.product_qty |
929 | + sale_id=move.sale_id.id |
930 | + |
931 | + parent_move_ids=move_obj.search(cr,uid,[("sale_id","=",sale_id), |
932 | + ("product_qty","=",product_qty), |
933 | + ("product_id","=",production.product_id.id)]) |
934 | + parent_moves=move_obj.browse(cr,uid,parent_move_ids) |
935 | + print "parent_move_ids",parent_move_ids |
936 | +# return {'child_moves':moves,"parent_moves":parent_moves} |
937 | + return parent_moves |
938 | + break |
939 | + |
940 | + def _get_childs(self,pick_id): |
941 | + cr=self.cr |
942 | + uid=self.uid |
943 | + context=self.localcontext |
944 | + move_obj=self.pool.get('stock.move') |
945 | + move_ids=move_obj.search(cr,uid,[('picking_id','=',pick_id),("parent_bom_id","!=",False)]) |
946 | + print move_ids,'====================move_ids================================' |
947 | + return move_obj.browse(cr,uid,move_ids,context=context) |
948 | + |
949 | +report_sxw.report_sxw('report.delivery.bom', 'stock.picking', 'addons/assembly_bom/report/delivery_report.rml', parser=delivery_report, header=False) |
950 | + |
951 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
952 | + |
953 | |
954 | === added file 'assembly_bom/report/delivery_report.rml' |
955 | --- assembly_bom/report/delivery_report.rml 1970-01-01 00:00:00 +0000 |
956 | +++ assembly_bom/report/delivery_report.rml 2011-10-06 15:31:48 +0000 |
957 | @@ -0,0 +1,384 @@ |
958 | +<?xml version="1.0"?> |
959 | +<document filename="test.pdf"> |
960 | + <template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20"> |
961 | + <pageTemplate id="first"> |
962 | + <frame id="first" x1="0.0" y1="57.0" width="538" height="728"/> |
963 | + </pageTemplate> |
964 | + </template> |
965 | + <stylesheet> |
966 | + <blockTableStyle id="Standard_Outline"> |
967 | + <blockAlignment value="LEFT"/> |
968 | + <blockValign value="TOP"/> |
969 | + </blockTableStyle> |
970 | + <blockTableStyle id="Table_Address_detail"> |
971 | + <blockAlignment value="LEFT"/> |
972 | + <blockValign value="TOP"/> |
973 | + </blockTableStyle> |
974 | + <blockTableStyle id="Table_Title_String"> |
975 | + <blockAlignment value="LEFT"/> |
976 | + <blockValign value="TOP"/> |
977 | + </blockTableStyle> |
978 | + <blockTableStyle id="Header_Order_Reference_Tbl"> |
979 | + <blockAlignment value="LEFT"/> |
980 | + <blockValign value="TOP"/> |
981 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/> |
982 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/> |
983 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/> |
984 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/> |
985 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/> |
986 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/> |
987 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/> |
988 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/> |
989 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/> |
990 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/> |
991 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/> |
992 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/> |
993 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="4,0" stop="4,-1"/> |
994 | + <lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="4,0" stop="4,-1"/> |
995 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="4,0" stop="4,0"/> |
996 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/> |
997 | + </blockTableStyle> |
998 | + <blockTableStyle id="Content_Order_Reference_Table"> |
999 | + <blockAlignment value="LEFT"/> |
1000 | + <blockValign value="TOP"/> |
1001 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/> |
1002 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/> |
1003 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/> |
1004 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/> |
1005 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/> |
1006 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/> |
1007 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/> |
1008 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/> |
1009 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/> |
1010 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/> |
1011 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/> |
1012 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/> |
1013 | + <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="4,0" stop="4,-1"/> |
1014 | + <lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="4,0" stop="4,-1"/> |
1015 | + <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="4,0" stop="4,0"/> |
1016 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/> |
1017 | + </blockTableStyle> |
1018 | + <blockTableStyle id="Move_Line_Header"> |
1019 | + <blockAlignment value="LEFT"/> |
1020 | + <blockValign value="TOP"/> |
1021 | + <lineStyle kind="LINEBELOW" colorName="#000000" start="0,-1" stop="0,-1"/> |
1022 | + <lineStyle kind="LINEBELOW" colorName="#000000" start="1,-1" stop="1,-1"/> |
1023 | + <lineStyle kind="LINEBELOW" colorName="#000000" start="2,-1" stop="2,-1"/> |
1024 | + <lineStyle kind="LINEBELOW" colorName="#000000" start="3,-1" stop="3,-1"/> |
1025 | + <lineStyle kind="LINEBELOW" colorName="#000000" start="4,-1" stop="4,-1"/> |
1026 | + </blockTableStyle> |
1027 | + <blockTableStyle id="Move_Line_Contect_Assign_State"> |
1028 | + <blockAlignment value="LEFT"/> |
1029 | + <blockValign value="TOP"/> |
1030 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/> |
1031 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="1,2" stop="1,-1"/> |
1032 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="1,2" stop="1,2"/> |
1033 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="1,-1" stop="1,-1"/> |
1034 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="2,2" stop="2,-1"/> |
1035 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="2,2" stop="2,2"/> |
1036 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="2,-1" stop="2,-1"/> |
1037 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="3,2" stop="3,-1"/> |
1038 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="3,2" stop="3,2"/> |
1039 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="3,-1" stop="3,-1"/> |
1040 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="4,2" stop="4,-1"/> |
1041 | + <lineStyle kind="LINEAFTER" colorName="#ffffff" start="4,2" stop="4,-1"/> |
1042 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="4,2" stop="4,2"/> |
1043 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="4,-1" stop="4,-1"/> |
1044 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="0,3" stop="0,-1"/> |
1045 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="0,3" stop="0,3"/> |
1046 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="0,-1" stop="0,-1"/> |
1047 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="1,3" stop="1,-1"/> |
1048 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="1,3" stop="1,3"/> |
1049 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="1,-1" stop="1,-1"/> |
1050 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="2,3" stop="2,-1"/> |
1051 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="2,3" stop="2,3"/> |
1052 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="2,-1" stop="2,-1"/> |
1053 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="3,3" stop="3,-1"/> |
1054 | + <lineStyle kind="LINEAFTER" colorName="#ffffff" start="3,3" stop="3,-1"/> |
1055 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="3,3" stop="3,3"/> |
1056 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="3,-1" stop="3,-1"/> |
1057 | + </blockTableStyle> |
1058 | + <blockTableStyle id="Table1"> |
1059 | + <blockAlignment value="LEFT"/> |
1060 | + <blockValign value="TOP"/> |
1061 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="0,0" stop="0,-1"/> |
1062 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="0,0" stop="0,0"/> |
1063 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="0,-1" stop="0,-1"/> |
1064 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="1,0" stop="1,-1"/> |
1065 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="1,0" stop="1,0"/> |
1066 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="1,-1" stop="1,-1"/> |
1067 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="2,0" stop="2,-1"/> |
1068 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="2,0" stop="2,0"/> |
1069 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="2,-1" stop="2,-1"/> |
1070 | + <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="3,0" stop="3,-1"/> |
1071 | + <lineStyle kind="LINEAFTER" colorName="#ffffff" start="3,0" stop="3,-1"/> |
1072 | + <lineStyle kind="LINEABOVE" colorName="#ffffff" start="3,0" stop="3,0"/> |
1073 | + <lineStyle kind="LINEBELOW" colorName="#ffffff" start="3,-1" stop="3,-1"/> |
1074 | + </blockTableStyle> |
1075 | + <blockTableStyle id="Table4"> |
1076 | + <blockAlignment value="LEFT"/> |
1077 | + <blockValign value="TOP"/> |
1078 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/> |
1079 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/> |
1080 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/> |
1081 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/> |
1082 | + <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/> |
1083 | + </blockTableStyle> |
1084 | + <blockTableStyle id="Table5"> |
1085 | + <blockAlignment value="LEFT"/> |
1086 | + <blockValign value="TOP"/> |
1087 | + <lineStyle kind="LINEABOVE" colorName="#000000" start="1,0" stop="1,0"/> |
1088 | + <lineStyle kind="LINEABOVE" colorName="#000000" start="2,0" stop="2,0"/> |
1089 | + </blockTableStyle> |
1090 | + <initialize> |
1091 | + <paraStyle name="all" alignment="justify"/> |
1092 | + </initialize> |
1093 | + <paraStyle name="P1" fontName="Times-Roman" alignment="LEFT"/> |
1094 | + <paraStyle name="P2" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> |
1095 | + <paraStyle name="P3" fontName="Helvetica" fontSize="14.0" leading="17" alignment="LEFT"/> |
1096 | + <paraStyle name="P4" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT"/> |
1097 | + <paraStyle name="P5" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/> |
1098 | + <paraStyle name="P6" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1099 | + <paraStyle name="P7" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1100 | + <paraStyle name="P8" fontName="Helvetica" fontSize="14.0" leading="17" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1101 | + <paraStyle name="P9" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1102 | + <paraStyle name="P10" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1103 | + <paraStyle name="P11" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1104 | + <paraStyle name="P12" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1105 | + <paraStyle name="Standard" fontName="Times-Roman"/> |
1106 | + <paraStyle name="Heading" fontName="Helvetica" fontSize="14.0" leading="17" spaceBefore="12.0" spaceAfter="6.0"/> |
1107 | + <paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/> |
1108 | + <paraStyle name="List" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/> |
1109 | + <paraStyle name="Caption" fontName="Times-Italic" fontSize="12.0" leading="15" spaceBefore="6.0" spaceAfter="6.0"/> |
1110 | + <paraStyle name="Index" fontName="Times-Roman"/> |
1111 | + <paraStyle name="terp_header" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1112 | + <paraStyle name="terp_header_Centre" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> |
1113 | + <paraStyle name="terp_default_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1114 | + <paraStyle name="terp_default_Bold_8" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1115 | + <paraStyle name="terp_tblheader_Details" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1116 | + <paraStyle name="terp_tblheader_Details_Centre" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> |
1117 | + <paraStyle name="terp_default_Centre_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> |
1118 | + <paraStyle name="terp_default_Centre_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> |
1119 | + <paraStyle name="terp_tblheader_General" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/> |
1120 | + <paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/> |
1121 | + <paraStyle name="Table Contents" fontName="Times-Roman"/> |
1122 | + <paraStyle name="Footer" fontName="Times-Roman"/> |
1123 | + <paraStyle name="Table Heading" fontName="Times-Roman" alignment="CENTER"/> |
1124 | + <paraStyle name="Horizontal Line" fontName="Times-Roman" fontSize="6.0" leading="8" spaceBefore="0.0" spaceAfter="14.0"/> |
1125 | + <paraStyle name="Heading 9" fontName="Helvetica-Bold" fontSize="75%" leading="NaN" spaceBefore="12.0" spaceAfter="6.0"/> |
1126 | + <paraStyle name="terp_tblheader_General_Right" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/> |
1127 | + <paraStyle name="terp_tblheader_Details_Right" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/> |
1128 | + <paraStyle name="terp_default_Right_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/> |
1129 | + <paraStyle name="terp_header_Right" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1130 | + <paraStyle name="terp_default_address" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1131 | + <paraStyle name="terp_default_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1132 | + <paraStyle name="terp_default_Bold_9" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1133 | + <paraStyle name="terp_default_Right_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/> |
1134 | + <paraStyle name="terp_default_2" fontName="Helvetica" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/> |
1135 | + <paraStyle name="terp_default_5cm_Above_Space" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="0.0"/> |
1136 | + <paraStyle name="terp_default_1cm_above_space" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="3.0" spaceAfter="0.0"/> |
1137 | + <images/> |
1138 | + </stylesheet> |
1139 | + <story> |
1140 | + <para style="P1">[[repeatIn(objects,'picking')]] </para> |
1141 | + <para style="terp_default_9"> |
1142 | + <font color="white"> </font> |
1143 | + </para> |
1144 | + <blockTable colWidths="269.0,269.0" style="Table_Address_detail"> |
1145 | + <tr> |
1146 | + <td> |
1147 | + <para style="terp_default_Bold_9">Shipping Address :</para> |
1148 | + <para style="terp_default_9">[[ (picking.address_id and picking.address_id.partner_id and picking.address_id.partner_id.title.name) or '' ]] [[ picking.address_id and picking.address_id.partner_id and picking.address_id.partner_id.name ]]</para> |
1149 | + <para style="terp_default_9">[[ picking.address_id and picking.address_id.street or '' ]]</para> |
1150 | + <para style="terp_default_9">[[ (picking.address_id and picking.address_id.street2) or removeParentNode('para') ]]</para> |
1151 | + <para style="terp_default_9">[[ picking.address_id and picking.address_id.zip or '' ]] [[ picking.address_id and picking.address_id.city or '' ]]</para> |
1152 | + <para style="terp_default_9">[[ (picking.address_id and picking.address_id.state_id and picking.address_id.state_id.name) or removeParentNode('para') ]]</para> |
1153 | + <para style="terp_default_9">[[ (picking.address_id and picking.address_id.country_id and picking.address_id.country_id.name) or '' ]]</para> |
1154 | + </td> |
1155 | + <td> |
1156 | + <para style="terp_default_Bold_9">Contact Address :</para> |
1157 | + <para style="terp_default_9">[[ picking.address_id and picking.address_id.title.name or '' ]] [[ picking.address_id and picking.address_id.name or '' ]]</para> |
1158 | + <para style="terp_default_9">[[ picking.address_id and picking.address_id.street or '' ]]</para> |
1159 | + <para style="terp_default_9">[[ (picking.address_id and picking.address_id.street2) or removeParentNode('para') ]]</para> |
1160 | + <para style="terp_default_9">[[ picking.address_id and picking.address_id.zip or '' ]] [[ picking.address_id and picking.address_id.city or '' ]]</para> |
1161 | + <para style="terp_default_9">[[ (picking.address_id and picking.address_id.state_id and picking.address_id.state_id.name) or removeParentNode('para') ]]</para> |
1162 | + <para style="terp_default_9">[[ (picking.address_id and picking.address_id.country_id and picking.address_id.country_id.name) or '' ]]</para> |
1163 | + </td> |
1164 | + </tr> |
1165 | + </blockTable> |
1166 | + <para style="terp_default_5cm_Above_Space"> |
1167 | + <font color="white"> </font> |
1168 | + </para> |
1169 | + <para style="terp_default_5cm_Above_Space"> |
1170 | + <font color="white"> </font> |
1171 | + </para> |
1172 | + <blockTable colWidths="538.0" style="Table_Title_String"> |
1173 | + <tr> |
1174 | + <td> |
1175 | + <para style="terp_header">Packing List: [[ picking.name ]]</para> |
1176 | + </td> |
1177 | + </tr> |
1178 | + </blockTable> |
1179 | + <para style="terp_default_5cm_Above_Space"> |
1180 | + <font color="white"> </font> |
1181 | + </para> |
1182 | + <blockTable colWidths="100.0,100.0,108.0,107.0,109.0" style="Header_Order_Reference_Tbl"> |
1183 | + <tr> |
1184 | + <td> |
1185 | + <para style="terp_tblheader_General_Centre">Journal</para> |
1186 | + </td> |
1187 | + <td> |
1188 | + <para style="terp_tblheader_General_Centre">Order(Origin)</para> |
1189 | + </td> |
1190 | + <td> |
1191 | + <para style="terp_tblheader_General_Centre">Recipient</para> |
1192 | + </td> |
1193 | + <td> |
1194 | + <para style="terp_tblheader_General_Centre">Expected Shipping Date </para> |
1195 | + </td> |
1196 | + <td> |
1197 | + <para style="terp_tblheader_General_Centre">weight</para> |
1198 | + </td> |
1199 | + </tr> |
1200 | + </blockTable> |
1201 | + <blockTable colWidths="100.0,100.0,108.0,107.0,109.0" style="Content_Order_Reference_Table"> |
1202 | + <tr> |
1203 | + <td> |
1204 | + <para style="terp_default_Centre_8">[[ picking.stock_journal_id.name]]</para> |
1205 | + </td> |
1206 | + <td> |
1207 | + <para style="terp_default_Centre_8">[[ picking.origin or '']]</para> |
1208 | + </td> |
1209 | + <td> |
1210 | + <para style="terp_default_Centre_8">[[ (picking.address_id and picking.address_id.title.name) or '' ]] [[ (picking.address_id and picking.address_id.name) or '' ]] </para> |
1211 | + </td> |
1212 | + <td> |
1213 | + <para style="terp_default_Centre_8">[[ formatLang(picking.min_date,date_time = True) ]]</para> |
1214 | + </td> |
1215 | + <td> |
1216 | + <para style="terp_default_Centre_8">[[ 'weight' in picking._columns.keys() and picking.weight or '']]</para> |
1217 | + </td> |
1218 | + </tr> |
1219 | + </blockTable> |
1220 | + <para style="terp_default_5cm_Above_Space"> |
1221 | + <font color="white"> </font> |
1222 | + </para> |
1223 | + <blockTable colWidths="256.0,73.0,59.0,59.0,71.0" repeatRows="1" style="Move_Line_Header"> |
1224 | + <tr> |
1225 | + <td> |
1226 | + <para style="terp_tblheader_Details">Description</para> |
1227 | + </td> |
1228 | + <td> |
1229 | + <para style="terp_tblheader_Details_Centre">Lot</para> |
1230 | + </td> |
1231 | + <td> |
1232 | + <para style="terp_tblheader_Details_Centre">State</para> |
1233 | + </td> |
1234 | + <td> |
1235 | + <para style="terp_tblheader_Details_Right">Location</para> |
1236 | + </td> |
1237 | + <td> |
1238 | + <para style="terp_tblheader_Details_Right"> |
1239 | + <font color="white"> </font> |
1240 | + </para> |
1241 | + <para style="terp_tblheader_Details_Right"> |
1242 | + <font color="white"> </font> |
1243 | + </para> |
1244 | + </td> |
1245 | + </tr> |
1246 | + </blockTable> |
1247 | + <section> |
1248 | + <para style="terp_default_2"> |
1249 | + <font color="white"> </font> |
1250 | + </para> |
1251 | + <blockTable colWidths="522.0" style="Move_Line_Contect_Assign_State"> |
1252 | + <tr> |
1253 | + <td> |
1254 | + <para style="P9">[[_get_parent(picking.id)[0].product_id.name]]</para> |
1255 | + <para style="P9"> |
1256 | + <font color="white"> </font> |
1257 | + </para> |
1258 | + </td> |
1259 | + </tr> |
1260 | + <tr> |
1261 | + <td> |
1262 | + <para style="P12">[[ repeatIn([line for line in picking.move_lines if (line.state == 'confirmed' or line.state=='done' or line.state=='assigned')],'move_lines') ]]</para> |
1263 | + <para style="P10"> |
1264 | + <font face="Times-Roman" size="9.0">[[ (picking.move_lines!=[] and removeParentNode('para')) or removeParentNode('section')]]</font> |
1265 | + </para> |
1266 | + </td> |
1267 | + </tr> |
1268 | + <tr> |
1269 | + <td> |
1270 | + <blockTable colWidths="129.0,129.0,129.0,129.0" style="Table1"> |
1271 | + <tr> |
1272 | + <td> |
1273 | + <para style="terp_default_9">[[move_lines.product_id.name and '*'*4+(move_lines.product_id.name)or removeParentNode('tr')]] </para> |
1274 | + </td> |
1275 | + <td> |
1276 | + <para style="terp_default_Centre_9">[[ (move_lines.prodlot_id and move_lines.prodlot_id.name) or '' ]]</para> |
1277 | + </td> |
1278 | + <td> |
1279 | + <para style="terp_default_9">[[ move_lines.state ]]</para> |
1280 | + </td> |
1281 | + <td> |
1282 | + <para style="terp_default_Right_9">[[ (move_lines.location_id and move_lines.location_id.name) or '' ]] </para> |
1283 | + </td> |
1284 | + </tr> |
1285 | + </blockTable> |
1286 | + <para style="P9"> |
1287 | + <font color="white"> </font> |
1288 | + </para> |
1289 | + </td> |
1290 | + </tr> |
1291 | + </blockTable> |
1292 | + </section> |
1293 | + <para style="terp_default_Bold_9">[[ ([line for line in picking.move_lines if (line.state == 'draft' or line.state=='waiting' )]) and 'Non Assigned Products:' or removeParentNode('para') ]]</para> |
1294 | + <para style="terp_default_Bold_9"> |
1295 | + <font color="white"> </font> |
1296 | + </para> |
1297 | + <para style="terp_default_2"/> |
1298 | + <section> |
1299 | + <para style="terp_default_2">[[ repeatIn([line for line in picking.move_lines if (line.state == 'draft' or line.state=='waiting')],'move_lines') ]]</para> |
1300 | + <para style="terp_default_2">[[ (picking.move_lines!=[] and removeParentNode('para')) or removeParentNode('section')]]</para> |
1301 | + <blockTable colWidths="257.0,74.0,57.0,61.0,72.0" style="Table4"> |
1302 | + <tr> |
1303 | + <td> |
1304 | + <para style="terp_default_9"><font face="Times-Roman" size="9.0">[[ (move_lines.product_id.default_code) or removeParentNode('font') ]] </font>[[“..”*5 +move_lines.product_id.name ]] [[ move_lines.product_id.variants or '']]</para> |
1305 | + </td> |
1306 | + <td> |
1307 | + <para style="terp_default_Centre_9">[[ (move_lines.prodlot_id and move_lines.prodlot_id.name) or '' ]]</para> |
1308 | + </td> |
1309 | + <td> |
1310 | + <para style="terp_default_9">[[ move_lines.state ]]</para> |
1311 | + </td> |
1312 | + <td> |
1313 | + <para style="terp_default_Right_9">[[ (move_lines.location_id and move_lines.location_id.name) or '' ]] </para> |
1314 | + </td> |
1315 | + <td> |
1316 | + <para style="terp_default_Right_9">[[ formatLang(move_lines.product_qty) ]] [[ move_lines.product_uom.name ]]</para> |
1317 | + </td> |
1318 | + </tr> |
1319 | + </blockTable> |
1320 | + </section> |
1321 | + <blockTable colWidths="388.0,56.0,77.0" style="Table5"> |
1322 | + <tr> |
1323 | + <td> |
1324 | + <para style="terp_default_9"> |
1325 | + <font color="white"> </font> |
1326 | + </para> |
1327 | + </td> |
1328 | + <td> |
1329 | + <para style="terp_tblheader_Details_Centre">Total</para> |
1330 | + </td> |
1331 | + <td> |
1332 | + <para style="terp_tblheader_Details_Right">[[ formatLang(get_qtytotal(picking.move_lines)['quantity']) ]] [[ get_qtytotal(picking.move_lines)['uom'] ]]</para> |
1333 | + </td> |
1334 | + </tr> |
1335 | + </blockTable> |
1336 | + <para style="P11"> |
1337 | + <font color="white"> </font> |
1338 | + </para> |
1339 | + </story> |
1340 | +</document> |
1341 | + |
1342 | |
1343 | === added file 'assembly_bom/report/normalized_oo2rml.xsl' |
1344 | --- assembly_bom/report/normalized_oo2rml.xsl 1970-01-01 00:00:00 +0000 |
1345 | +++ assembly_bom/report/normalized_oo2rml.xsl 2011-10-06 15:31:48 +0000 |
1346 | @@ -0,0 +1,696 @@ |
1347 | +<?xml version="1.0" encoding="utf-8"?> |
1348 | +<xsl:stylesheet |
1349 | + version="1.0" |
1350 | + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" |
1351 | + xmlns:fo="http://www.w3.org/1999/XSL/Format" |
1352 | + xmlns:office="http://openoffice.org/2000/office" |
1353 | + xmlns:style="http://openoffice.org/2000/style" |
1354 | + xmlns:text="http://openoffice.org/2000/text" |
1355 | + xmlns:table="http://openoffice.org/2000/table" |
1356 | + xmlns:draw="http://openoffice.org/2000/drawing" |
1357 | + xmlns:xlink="http://www.w3.org/1999/xlink" |
1358 | + xmlns:number="http://openoffice.org/2000/datastyle" |
1359 | + xmlns:svg="http://www.w3.org/2000/svg" |
1360 | + xmlns:chart="http://openoffice.org/2000/chart" |
1361 | + xmlns:dr3d="http://openoffice.org/2000/dr3d" |
1362 | + xmlns:math="http://www.w3.org/1998/Math/MathML" |
1363 | + xmlns:form="http://openoffice.org/2000/form" |
1364 | + xmlns:script="http://openoffice.org/2000/script" |
1365 | + office:class="text" office:version="1.0" |
1366 | + exclude-result-prefixes = "xsl fo office style text table draw xlink number svg chart dr3d math form script"> |
1367 | + |
1368 | + <!--TODO's: indent, picture cache (trml2pdf) --> |
1369 | + |
1370 | +<xsl:output method="xml" indent="yes" /> |
1371 | +<xsl:strip-space elements="*"/> |
1372 | + |
1373 | +<xsl:key name="text_style" match="style:style[@style:family='text']" use="@style:name" /> |
1374 | +<xsl:key name="page_break_before" match="style:style[@style:family='paragraph' and ./style:properties/@fo:break-before='page']" use="@style:name" /> |
1375 | +<xsl:key name="page_break_after" match="style:style[@style:family='paragraph' and ./style:properties/@fo:break-after='page']" use="@style:name" /> |
1376 | +<xsl:key name="table_column_style" match="style:style[@style:family='table-column']" use="@style:name" /> |
1377 | +<xsl:key name="table_cell_style" match="style:style[@style:family='table-cell']" use="@style:name" /> |
1378 | +<xsl:key name="paragraph_style" match="style:style[@style:family='paragraph']" use="@style:name" /> |
1379 | + |
1380 | +<xsl:template match="office:document-content"> |
1381 | + <document filename="test.pdf"> |
1382 | + <xsl:apply-templates select="office:automatic-styles" /> |
1383 | + <xsl:apply-templates select="office:body" /> |
1384 | + </document> |
1385 | +</xsl:template> |
1386 | + |
1387 | +<xsl:template name="page_size"> |
1388 | + <xsl:attribute name="pageSize"> |
1389 | + <xsl:text>(</xsl:text> |
1390 | + <xsl:value-of select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" /> |
1391 | + <xsl:text>,</xsl:text> |
1392 | + <xsl:value-of select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height" /> |
1393 | + <xsl:text>)</xsl:text> |
1394 | + </xsl:attribute> |
1395 | +</xsl:template> |
1396 | + |
1397 | +<xsl:template name="fixed_frame"> |
1398 | + <xsl:for-each select="//draw:text-box"> |
1399 | + <frame> |
1400 | + <xsl:attribute name="id"><xsl:value-of select="./@draw:name" /></xsl:attribute> |
1401 | + <xsl:attribute name="x1"><xsl:value-of select="./@svg:x" /></xsl:attribute> |
1402 | + <xsl:attribute name="y1"> |
1403 | + <xsl:value-of |
1404 | + select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height - ./@svg:y - ./@fo:min-height" /> |
1405 | + </xsl:attribute> |
1406 | + <xsl:attribute name="width"> |
1407 | + <xsl:value-of select="./@svg:width" /> |
1408 | + </xsl:attribute> |
1409 | + <xsl:attribute name="height"> |
1410 | + <xsl:value-of select="./@fo:min-height" /> |
1411 | + </xsl:attribute> |
1412 | + </frame> |
1413 | + </xsl:for-each> |
1414 | +</xsl:template> |
1415 | + |
1416 | +<xsl:template name="margin_sizes"> |
1417 | + <xsl:variable name="margin_left" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-left" /> |
1418 | + <xsl:variable name="margin_right" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-right" /> |
1419 | + <xsl:variable name="margin_top" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-top" /> |
1420 | + <xsl:variable name="margin_bottom" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-bottom" /> |
1421 | + <xsl:variable name="page_width" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" /> |
1422 | + <xsl:variable name="page_height" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height" /> |
1423 | + <xsl:attribute name="x1"><xsl:value-of select="$margin_left" /></xsl:attribute> |
1424 | + <xsl:attribute name="y1"><xsl:value-of select="$margin_bottom" /></xsl:attribute> |
1425 | + <xsl:attribute name="width"><xsl:value-of select="$page_width - $margin_left - $margin_right"/></xsl:attribute> |
1426 | + <xsl:attribute name="height"><xsl:value-of select="$page_height - $margin_bottom - $margin_top"/></xsl:attribute> |
1427 | +</xsl:template> |
1428 | + |
1429 | +<xsl:template name="text_width"> |
1430 | + <!-- You need this for the workaround to make primitive outlines--> |
1431 | + <xsl:variable name="margin_left" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-left" /> |
1432 | + <xsl:variable name="margin_right" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-right" /> |
1433 | + <xsl:variable name="page_width" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" /> |
1434 | + <xsl:value-of select="$page_width - $margin_left - $margin_right - 18"/> |
1435 | +</xsl:template> |
1436 | + |
1437 | + |
1438 | + |
1439 | +<xsl:template match="office:automatic-styles"> |
1440 | + <!--<template pageSize="(21cm, 29.7cm)" leftMargin="1.0cm" rightMargin="2.0cm" topMargin="1.0cm" bottomMargin="1.0cm" title="Test" author="Martin Simon" allowSplitting="20">--> |
1441 | + <template pageSize="(21cm, 29.7cm)" title="Test" author="Martin Simon" allowSplitting="20"> |
1442 | + <xsl:call-template name="page_size" /> |
1443 | + <pageTemplate id="first"> |
1444 | + <xsl:call-template name="fixed_frame" /> |
1445 | + <frame id="first" x1="2cm" y1="2cm" width="17cm" height="26cm"> |
1446 | + <xsl:call-template name="margin_sizes" /> |
1447 | + </frame> |
1448 | + </pageTemplate> |
1449 | + </template> |
1450 | + <stylesheet> |
1451 | + <!--A table style to simulate primitive outlines -till the <addOutline> tag is implemented in trml2pdf --> |
1452 | + <blockTableStyle id="Standard_Outline"> |
1453 | + <blockAlignment value="LEFT"/> |
1454 | + <blockValign value="TOP"/> |
1455 | + </blockTableStyle> |
1456 | + <!--use two standard table grid styles like PyOpenOffice "Old Way": with and without a grid--> |
1457 | + <!--TODO insert table cell colors here, not within the <td> tag - otherwise |
1458 | + it will not work with flowables as cell content--> |
1459 | + <xsl:call-template name="make_blocktablestyle" /> |
1460 | + <initialize> |
1461 | + <paraStyle name="all" alignment="justify" /> |
1462 | + </initialize> |
1463 | + <xsl:apply-templates select="style:style" /> |
1464 | + </stylesheet> |
1465 | +</xsl:template> |
1466 | + |
1467 | +<xsl:template name="make_blocktablestyle"> |
1468 | + <xsl:for-each select="//table:table"> |
1469 | + <xsl:variable name="test"> |
1470 | + <xsl:value-of select="./@table:name" /> |
1471 | + </xsl:variable> |
1472 | + <xsl:if test="not(boolean(count(preceding-sibling::table:table[@table:name=$test])))"> |
1473 | + <!--Test if this is the first table with this style, nested tables not counted--> |
1474 | + <blockTableStyle id="{@table:name}"> |
1475 | + <xsl:if test=".//draw:image"> |
1476 | + <blockTopPadding value="0"/> |
1477 | + <blockBottomPadding value="0"/> |
1478 | + </xsl:if> |
1479 | + <blockAlignment value="LEFT" /> |
1480 | + <blockValign value="TOP" /> |
1481 | + <xsl:call-template name="make_linestyle" /> |
1482 | + <xsl:call-template name="make_tablebackground" /> |
1483 | + </blockTableStyle> |
1484 | + </xsl:if> |
1485 | + </xsl:for-each> |
1486 | +</xsl:template> |
1487 | + |
1488 | +<xsl:template name="make_linestyle"> |
1489 | + <xsl:for-each select=".//table:table-row"> |
1490 | + <xsl:variable name="row" select="position() - 1"/> |
1491 | + <xsl:for-each select=".//table:table-cell"> |
1492 | + <xsl:variable name="col" select="position() - 1"/> |
1493 | + <xsl:variable name="linebefore"> |
1494 | + <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border-left"/> |
1495 | + </xsl:variable> |
1496 | + <xsl:if test="not($linebefore='') and not($linebefore='none')"> |
1497 | + <xsl:variable name="colorname"> |
1498 | + <xsl:value-of select="substring-after($linebefore,'#')"/> |
1499 | + </xsl:variable> |
1500 | + <lineStyle kind="LINEBEFORE" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},-1"/> |
1501 | + </xsl:if> |
1502 | + <xsl:variable name="lineafter"> |
1503 | + <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border-right"/> |
1504 | + </xsl:variable> |
1505 | + <xsl:if test="not($lineafter='') and not($lineafter='none')"> |
1506 | + <xsl:variable name="colorname"> |
1507 | + <xsl:value-of select="substring-after($lineafter,'#')"/> |
1508 | + </xsl:variable> |
1509 | + <lineStyle kind="LINEAFTER" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},-1"/> |
1510 | + </xsl:if> |
1511 | + <xsl:variable name="lineabove"> |
1512 | + <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border-top"/> |
1513 | + </xsl:variable> |
1514 | + <xsl:if test="not($lineabove='') and not($lineabove='none')"> |
1515 | + <xsl:variable name="colorname"> |
1516 | + <xsl:value-of select="substring-after($lineabove,'#')"/> |
1517 | + </xsl:variable> |
1518 | + <lineStyle kind="LINEABOVE" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},{$row}"/> |
1519 | + </xsl:if> |
1520 | + <xsl:variable name="linebelow"> |
1521 | + <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border-bottom"/> |
1522 | + </xsl:variable> |
1523 | + <xsl:if test="not($linebelow='') and not($linebelow='none')"> |
1524 | + <xsl:variable name="colorname"> |
1525 | + <xsl:value-of select="substring-after($linebelow,'#')"/> |
1526 | + </xsl:variable> |
1527 | + <lineStyle kind="LINEBELOW" colorName="#{$colorname}" start="{$col},{-1}" stop="{$col},{-1}"/> |
1528 | + </xsl:if> |
1529 | + <xsl:variable name="grid"> |
1530 | + <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border"/> |
1531 | + </xsl:variable> |
1532 | + <xsl:if test="not($grid='') and not($grid='none')"> |
1533 | + <xsl:variable name="colorname"> |
1534 | + <xsl:value-of select="substring-after($grid,'#')"/> |
1535 | + </xsl:variable> |
1536 | + <!-- Don't use grid because we don't need a line between each rows --> |
1537 | + <lineStyle kind="LINEBEFORE" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},-1"/> |
1538 | + <lineStyle kind="LINEAFTER" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},-1"/> |
1539 | + <lineStyle kind="LINEABOVE" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},{$row}"/> |
1540 | + <lineStyle kind="LINEBELOW" colorName="#{$colorname}" start="{$col},{-1}" stop="{$col},{-1}"/> |
1541 | + </xsl:if> |
1542 | + </xsl:for-each> |
1543 | + </xsl:for-each> |
1544 | +</xsl:template> |
1545 | + |
1546 | +<!-- Was needed to simulate bulleted lists: |
1547 | +<xsl:template match="text:ordered-list|text:unordered-list"> |
1548 | + <xsl:variable name = "text_width"> |
1549 | + <xsl:call-template name="text_width" /> |
1550 | + </xsl:variable> |
1551 | + <blockTable style="Standard_Outline" colWidths="18,{$text_width}"> |
1552 | + <xsl:apply-templates match="text:list-item" /> |
1553 | +</blockTable> |
1554 | +</xsl:template> |
1555 | + |
1556 | +<xsl:template match="text:list-item"> |
1557 | + <tr> |
1558 | + <td><para><font face="Helvetica-Bold" size="10">*</font></para></td> |
1559 | + <td> |
1560 | + <xsl:apply-templates /> |
1561 | + </td> |
1562 | + </tr> |
1563 | +</xsl:template> |
1564 | + |
1565 | +--> |
1566 | + |
1567 | + |
1568 | +<xsl:template match="office:body"> |
1569 | + <story> |
1570 | + <xsl:apply-templates /> |
1571 | + <xsl:for-each select="//draw:text-box"> |
1572 | + <currentFrame> |
1573 | + <xsl:attribute name="name"> |
1574 | + <xsl:value-of select="./@draw:name" /> |
1575 | + </xsl:attribute> |
1576 | + </currentFrame> |
1577 | + <xsl:apply-templates> |
1578 | + <xsl:with-param name="skip_draw" select="0" /> |
1579 | + </xsl:apply-templates> |
1580 | + <frameEnd /> |
1581 | + </xsl:for-each> |
1582 | + <xsl:for-each select="//text:ordered-list"> |
1583 | + <para><seqReset id="{./@text:style-name}"/></para> |
1584 | + </xsl:for-each> |
1585 | + </story> |
1586 | +</xsl:template> |
1587 | + |
1588 | +<xsl:template match="table:table"> |
1589 | + <blockTable> |
1590 | + <xsl:attribute name="colWidths"> |
1591 | + <xsl:call-template name="make_columns" /> |
1592 | + </xsl:attribute> |
1593 | + <xsl:call-template name="make_tableheaders" /> |
1594 | + <xsl:attribute name="style"> |
1595 | + <xsl:value-of select="@table:name" /> |
1596 | + </xsl:attribute> |
1597 | + <xsl:apply-templates /> |
1598 | + </blockTable> |
1599 | +</xsl:template> |
1600 | + |
1601 | +<xsl:template name="make_tableheaders"> |
1602 | + <xsl:if test="boolean(count(table:table-header-rows))"> |
1603 | + <xsl:attribute name="repeatRows">1</xsl:attribute> |
1604 | + </xsl:if> |
1605 | +</xsl:template> |
1606 | + |
1607 | +<xsl:template name="make_tablebackground"> |
1608 | + <xsl:for-each select=".//table:table-row"> |
1609 | + <!--Be careful when there are table:table-header-rows as |
1610 | + parent node of table:table-row --> |
1611 | + <xsl:variable name="row" select="position() - 1" /> |
1612 | + <xsl:for-each select="./table:table-cell"> |
1613 | + <xsl:variable name="col" select="position() - 1" /> |
1614 | + <xsl:variable name="background"> |
1615 | + <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:background-color" /> |
1616 | + </xsl:variable> |
1617 | + <xsl:if test="not($background='') and boolean(key('table_cell_style',@table:style-name)/style:properties/@fo:background-color) and starts-with($background,'#')"> |
1618 | + <!--only RGB hexcolors are accepted --> |
1619 | + <blockBackground colorName="{$background}" start="{$col},{$row}" stop="{$col},-1" /> |
1620 | + </xsl:if> |
1621 | + </xsl:for-each> |
1622 | + </xsl:for-each> |
1623 | +</xsl:template> |
1624 | + |
1625 | +<xsl:template name="make_columns"> |
1626 | + <xsl:variable name="columns" > |
1627 | + <xsl:for-each select="table:table-column"> |
1628 | + <xsl:value-of select="key('table_column_style',@table:style-name)/style:properties/@style:column-width" /> |
1629 | + <xsl:text>,</xsl:text> |
1630 | + </xsl:for-each> |
1631 | + </xsl:variable> |
1632 | + <xsl:value-of select="substring($columns,1,string-length($columns) - 1)" /> |
1633 | + <!--strip the last comma--> |
1634 | +</xsl:template> |
1635 | + |
1636 | +<xsl:template match="table:table-row"> |
1637 | + <tr> |
1638 | + <xsl:apply-templates /> |
1639 | + </tr> |
1640 | +</xsl:template> |
1641 | + |
1642 | +<xsl:template match="table:table-cell"> |
1643 | + <td> |
1644 | + <xsl:apply-templates /> |
1645 | + </td> |
1646 | +</xsl:template> |
1647 | + |
1648 | +<xsl:template match="text:section"> |
1649 | + <section> |
1650 | + <xsl:apply-templates /> |
1651 | + </section> |
1652 | +</xsl:template> |
1653 | + |
1654 | + |
1655 | +<xsl:template match="text:span"> |
1656 | + <font> |
1657 | + <xsl:call-template name="make_fontnames_span" /> |
1658 | + <xsl:call-template name="make_fontsize_span" /> |
1659 | + <xsl:apply-templates /> |
1660 | + </font> |
1661 | +</xsl:template> |
1662 | + |
1663 | +<xsl:template name="make_fontsize_span"> |
1664 | + <xsl:variable name ="fontsize"> |
1665 | + <xsl:value-of select="key('text_style',@text:style-name)/style:properties/@fo:font-size" /> |
1666 | + </xsl:variable> |
1667 | + <xsl:if test="not($fontsize='') and boolean(key('text_style',@text:style-name)/style:properties/@fo:font-size)" > |
1668 | + <xsl:attribute name="size"> |
1669 | + <xsl:value-of select="$fontsize" /> |
1670 | + </xsl:attribute> |
1671 | + </xsl:if> |
1672 | +</xsl:template> |
1673 | + |
1674 | +<xsl:template name="make_fontnames_span"> |
1675 | + <xsl:attribute name="face"> |
1676 | + <xsl:call-template name="make_fontnames"> |
1677 | + <xsl:with-param name="fontName" select="key('text_style',@text:style-name)/style:properties/@style:font-name" /> |
1678 | + <xsl:with-param name="fontWeight" select="key('text_style',@text:style-name)/style:properties/@fo:font-weight" /> |
1679 | + <xsl:with-param name="fontStyle" select="key('text_style',@text:style-name)/style:properties/@fo:font-style" /> |
1680 | + </xsl:call-template> |
1681 | + </xsl:attribute> |
1682 | +</xsl:template> |
1683 | + |
1684 | +<xsl:template name="make_image"> |
1685 | + <illustration height="{.//draw:image/@svg:height}" width="{.//draw:image/@svg:width}"> |
1686 | + <image x="0" y="0" file="{substring-after(.//draw:image/@xlink:href,'#Pictures/')}" height="{.//draw:image/@svg:height}" width="{.//draw:image/@svg:width}" /> |
1687 | + </illustration> |
1688 | +</xsl:template> |
1689 | + |
1690 | +<xsl:template name="empty_paragraph"> |
1691 | + <xsl:if test="not(boolean(count(descendant::node())))"> |
1692 | + <xsl:call-template name="distance_point"> |
1693 | + <xsl:with-param name="background" select="key('paragraph_style',@text:style-name)/style:properties/@fo:background-color" /> |
1694 | + </xsl:call-template> |
1695 | + </xsl:if> |
1696 | +</xsl:template> |
1697 | + |
1698 | +<xsl:template name="distance_point"> |
1699 | + <xsl:param name="background" /> |
1700 | + <xsl:param name="tab_stop"></xsl:param> |
1701 | + <xsl:variable name="local_back"> |
1702 | + <xsl:choose> |
1703 | + <xsl:when test="not(boolean($background)) or not(contains($background,'#'))"> |
1704 | + <!-- Do not accept OO colors like "transparent", only hex-colors --> |
1705 | + <xsl:text>white</xsl:text> |
1706 | + </xsl:when> |
1707 | + <xsl:otherwise> |
1708 | + <xsl:value-of select="$background" /> |
1709 | + </xsl:otherwise> |
1710 | + </xsl:choose> |
1711 | + </xsl:variable> |
1712 | + <font color="{$local_back}"> |
1713 | + <xsl:text> </xsl:text> |
1714 | + <xsl:if test="boolean($tab_stop)"> |
1715 | + <!-- simulate a tabstop with white/background-color points --> |
1716 | + <xsl:text>.........</xsl:text> |
1717 | + </xsl:if> |
1718 | + </font> |
1719 | +</xsl:template> |
1720 | + |
1721 | +<xsl:template match="text:ordered-list"> |
1722 | + <xsl:apply-templates /> |
1723 | + |
1724 | + <!-- Reset the counter. seqreset is not a trml2pdf tag, but a Platypus Intra Paragraph Markup, |
1725 | + so it needs a dummy paragraph to enclose it --> |
1726 | +</xsl:template> |
1727 | + |
1728 | +<xsl:template name="make_listitem"> |
1729 | + <xsl:if test="(name(..)='text:list-item')"> |
1730 | + <xsl:attribute name="leftIndent">15</xsl:attribute> |
1731 | + <xsl:attribute name="bulletIndent">0</xsl:attribute> |
1732 | + <xsl:choose> |
1733 | + <xsl:when test="(name(../..)='text:unordered-list')"> |
1734 | + <xsl:variable name="fontsize"> |
1735 | + <xsl:value-of select="number(key('paragraph_style',@text:style-name)/style:properties/@fo:font-size)" /> |
1736 | + </xsl:variable> |
1737 | + <xsl:choose> |
1738 | + <xsl:when test="$fontsize='NaN'"> |
1739 | + <!-- you should exclude non-numerical values for bulletFontSize. <== Sometimes the preprocessing went wrong.--> |
1740 | + <!--use a default bullet font size--> |
1741 | + <xsl:attribute name="bulletFontSize">6</xsl:attribute> |
1742 | + </xsl:when> |
1743 | + <xsl:otherwise> |
1744 | + <xsl:attribute name="bulletFontSize"><xsl:value-of select="floor(($fontsize div 2) + 1)" /></xsl:attribute> |
1745 | + </xsl:otherwise> |
1746 | + </xsl:choose> |
1747 | + <xsl:attribute name="bulletFontName">ZapfDingbats</xsl:attribute> |
1748 | + <xsl:attribute name="bulletText">l</xsl:attribute> |
1749 | + </xsl:when> |
1750 | + <xsl:otherwise> |
1751 | + <!-- Generate the numbers for an ordered list --> |
1752 | + <xsl:variable name="size"> |
1753 | + <xsl:value-of select="key('paragraph_style',@text:style-name)/style:properties/@fo:font-size" /> |
1754 | + </xsl:variable> |
1755 | + <!-- For ordered lists we use the bullet tag from Platypus Intra Paragraph Markup --> |
1756 | + <bullet> |
1757 | + <xsl:if test="not($size='') and boolean(key('paragraph_style',@text:style-name)/style:properties/@fo:font-size)"> |
1758 | + <xsl:attribute name="size"> |
1759 | + <!-- adapt the fontsize to the fontsize of the current paragraph --> |
1760 | + <xsl:value-of select="$size" /> |
1761 | + </xsl:attribute> |
1762 | + </xsl:if> |
1763 | + <seq id="{../../@text:style-name}"/>.</bullet> |
1764 | + |
1765 | + </xsl:otherwise> |
1766 | + </xsl:choose> |
1767 | + </xsl:if> |
1768 | +</xsl:template> |
1769 | + |
1770 | +<xsl:template match="text:drop-down"> |
1771 | + <xsl:value-of select="text:label[2]/@text:value" /> |
1772 | +</xsl:template> |
1773 | + |
1774 | + |
1775 | +<xsl:template match="text:p|text:h"> |
1776 | + <xsl:param name="skip_draw" select="1" /> |
1777 | + <xsl:if test="boolean(key('page_break_before',@text:style-name))" > |
1778 | + <pageBreak /> |
1779 | + </xsl:if> |
1780 | + <xsl:choose> |
1781 | + <xsl:when test="boolean(.//draw:image)"> |
1782 | + <xsl:call-template name="make_image" /> |
1783 | + </xsl:when> |
1784 | + <xsl:when test="boolean(name(..) = 'draw:text-box') and boolean($skip_draw)"> |
1785 | + </xsl:when> |
1786 | + <xsl:otherwise> |
1787 | + <para> |
1788 | + <xsl:attribute name="style"> |
1789 | + <xsl:value-of select="@text:style-name" /> |
1790 | + </xsl:attribute> |
1791 | + <xsl:call-template name="make_listitem" /> |
1792 | + <xsl:apply-templates /> |
1793 | + <xsl:call-template name="empty_paragraph" /> |
1794 | + </para> |
1795 | + </xsl:otherwise> |
1796 | + </xsl:choose> |
1797 | + <xsl:if test="boolean(key('page_break_after',@text:style-name))" > |
1798 | + <pageBreak /> |
1799 | + </xsl:if> |
1800 | +</xsl:template> |
1801 | + |
1802 | +<xsl:template match="text:p/text:tab-stop"> |
1803 | + <!-- simulate a tabstop --> |
1804 | + <xsl:call-template name="distance_point"> |
1805 | + <xsl:with-param name="background" select="key('paragraph_style',@text:style-name)/style:properties/@fo:background-color" /> |
1806 | + <xsl:with-param name="tab_stop">yes</xsl:with-param> |
1807 | + </xsl:call-template> |
1808 | +</xsl:template> |
1809 | + |
1810 | +<!-- experimental - switched off |
1811 | +<xsl:template match="text:h"> |
1812 | + <para> |
1813 | + <xsl:attribute name="style"> |
1814 | + <xsl:value-of select="@text:style-name" /> |
1815 | + </xsl:attribute> |
1816 | + <xsl:call-template name="make_number" /> |
1817 | + <xsl:apply-templates /> |
1818 | + <xsl:call-template name="empty_paragraph" /> |
1819 | + </para> |
1820 | +</xsl:template> |
1821 | + |
1822 | +<xsl:template name="make_number"> |
1823 | + <xsl:choose> |
1824 | + <xsl:when test="@text:level='1'"> |
1825 | + <xsl:number format="1. " /> |
1826 | + </xsl:when> |
1827 | + <xsl:when test="@text:level='2'"> |
1828 | + <xsl:number count="text:h[@text:level='1']|text:h[text:level='2']" level="any" format="1.1." /> |
1829 | + </xsl:when> |
1830 | + </xsl:choose> |
1831 | +</xsl:template> |
1832 | + |
1833 | +--> |
1834 | + |
1835 | +<xsl:template match="style:style[@style:family='paragraph']"> |
1836 | + <paraStyle> |
1837 | + <xsl:attribute name="name"> |
1838 | + <xsl:value-of select="@style:name" /> |
1839 | + </xsl:attribute> |
1840 | + <xsl:call-template name="make_indent_paragraph" /> |
1841 | + <xsl:call-template name="make_fontnames_paragraph" /> |
1842 | + <xsl:call-template name="make_fontsize" /> |
1843 | + <!--<xsl:call-template name="make_parent" /> not necessary - |
1844 | + parent styles processed by PyOpenOffice --> |
1845 | + <xsl:call-template name="make_alignment" /> |
1846 | + <xsl:call-template name="make_background" /> |
1847 | + <xsl:call-template name="make_space_beforeafter" /> |
1848 | + <xsl:call-template name="make_fontcolor" /> |
1849 | + </paraStyle> |
1850 | +</xsl:template> |
1851 | + |
1852 | +<xsl:template name="make_indent_paragraph"> |
1853 | + <xsl:variable name="right_indent"><xsl:value-of select="style:properties/@fo:margin-right" /></xsl:variable> |
1854 | + <xsl:variable name="left_indent"><xsl:value-of select="style:properties/@fo:margin-left" /></xsl:variable> |
1855 | + <xsl:if test="not($right_indent='') and boolean(style:properties/@fo:margin-right)"> |
1856 | + <xsl:attribute name="rightIndent"> |
1857 | + <xsl:value-of select="$right_indent" /> |
1858 | + </xsl:attribute> |
1859 | + </xsl:if> |
1860 | + <xsl:if test="not($left_indent='') and boolean(style:properties/@fo:margin-left)"> |
1861 | + <xsl:attribute name="leftIndent"> |
1862 | + <xsl:value-of select="$left_indent" /> |
1863 | + </xsl:attribute> |
1864 | + </xsl:if> |
1865 | +</xsl:template> |
1866 | + |
1867 | +<xsl:template name="make_background"> |
1868 | + <xsl:variable name="background"> |
1869 | + <xsl:value-of select="style:properties/@fo:background-color" /> |
1870 | + </xsl:variable> |
1871 | + <xsl:if test="not($background='') and boolean(style:properties/@fo:background-color) and starts-with($background,'#')" > |
1872 | + <xsl:attribute name="backColor"> |
1873 | + <xsl:value-of select="$background" /> |
1874 | + </xsl:attribute> |
1875 | + </xsl:if> |
1876 | +</xsl:template> |
1877 | + |
1878 | +<xsl:template name="make_space_beforeafter"> |
1879 | + <xsl:variable name="before"> |
1880 | + <xsl:value-of select="style:properties/@fo:margin-top" /> |
1881 | + </xsl:variable> |
1882 | + <xsl:variable name="after"> |
1883 | + <xsl:value-of select="style:properties/@fo:margin-bottom" /> |
1884 | + </xsl:variable> |
1885 | + <xsl:if test="not($before='') and boolean(style:properties/@fo:margin-top)" > |
1886 | + <xsl:attribute name="spaceBefore"> |
1887 | + <xsl:value-of select="$before" /> |
1888 | + </xsl:attribute> |
1889 | + </xsl:if> |
1890 | + <xsl:if test="not($after='') and boolean(style:properties/@fo:margin-bottom)" > |
1891 | + <xsl:attribute name="spaceAfter"> |
1892 | + <xsl:value-of select="$after" /> |
1893 | + </xsl:attribute> |
1894 | + </xsl:if> |
1895 | +</xsl:template> |
1896 | + |
1897 | +<xsl:template name="make_fontsize"> |
1898 | + <xsl:variable name="fontSize"> |
1899 | + <xsl:value-of select="style:properties/@fo:font-size" /> |
1900 | + </xsl:variable> |
1901 | + <xsl:if test="not($fontSize='') and boolean(style:properties/@fo:font-size)"> |
1902 | + <xsl:attribute name="fontSize"> |
1903 | + <xsl:value-of select="$fontSize" /> |
1904 | + </xsl:attribute> |
1905 | + <xsl:attribute name="leading"> |
1906 | + <xsl:value-of select="$fontSize + floor($fontSize div 5) + 1" /> |
1907 | + <!--use a standard leading related to the font size --> |
1908 | + </xsl:attribute> |
1909 | + </xsl:if> |
1910 | +</xsl:template> |
1911 | + |
1912 | +<!--this template is not needed anymore for "normalized" sxw files --> |
1913 | +<xsl:template name="make_parent"> |
1914 | + <xsl:variable name="parent"> |
1915 | + <xsl:value-of select="@style:parent-style-name" /> |
1916 | + </xsl:variable> |
1917 | + <xsl:if test="not($parent='') and boolean(@style:parent-style-name)"> |
1918 | + <xsl:attribute name="parent"> |
1919 | + <xsl:value-of select="$parent" /> |
1920 | + </xsl:attribute> |
1921 | + </xsl:if> |
1922 | +</xsl:template> |
1923 | + |
1924 | +<xsl:template name="make_alignment"> |
1925 | + <xsl:variable name="alignment"> |
1926 | + <xsl:value-of select="style:properties/@fo:text-align" /> |
1927 | + </xsl:variable> |
1928 | + <xsl:if test="not($alignment='') and boolean(style:properties/@fo:text-align)"> |
1929 | + <xsl:choose> |
1930 | + <xsl:when test="$alignment='start'"> |
1931 | + <xsl:attribute name="alignment">LEFT</xsl:attribute> |
1932 | + </xsl:when> |
1933 | + <xsl:when test="$alignment='center'"> |
1934 | + <xsl:attribute name="alignment">CENTER</xsl:attribute> |
1935 | + </xsl:when> |
1936 | + <xsl:when test="$alignment='end'"> |
1937 | + <xsl:attribute name="alignment">RIGHT</xsl:attribute> |
1938 | + </xsl:when> |
1939 | + <xsl:when test="$alignment='justify'"> |
1940 | + <xsl:attribute name="alignment">JUSTIFY</xsl:attribute> |
1941 | + </xsl:when> |
1942 | + </xsl:choose> |
1943 | + </xsl:if> |
1944 | +</xsl:template> |
1945 | + |
1946 | +<xsl:template name="make_fontnames_paragraph"> |
1947 | + <xsl:attribute name="fontName"> |
1948 | + <xsl:call-template name="make_fontnames"> |
1949 | + <xsl:with-param name="fontName" select="style:properties/@style:font-name" /> |
1950 | + <xsl:with-param name="fontWeight" select="style:properties/@fo:font-weight" /> |
1951 | + <xsl:with-param name="fontStyle" select="style:properties/@fo:font-style" /> |
1952 | + </xsl:call-template> |
1953 | + </xsl:attribute> |
1954 | +</xsl:template> |
1955 | + |
1956 | +<xsl:template name="make_fontnames"> |
1957 | + <!--much too verbose, needs improvement--> |
1958 | +<xsl:param name="fontName" /> |
1959 | +<xsl:param name="fontWeight" /> |
1960 | +<xsl:param name="fontStyle" /> |
1961 | +<xsl:choose> |
1962 | +<xsl:when test="not($fontName='') and boolean($fontName)"> |
1963 | + <xsl:choose> |
1964 | + <xsl:when test="contains($fontName,'Courier')"> |
1965 | + <xsl:choose> |
1966 | + <xsl:when test="($fontWeight='bold') and ($fontStyle='italic')"> |
1967 | + <xsl:text>Courier-BoldOblique</xsl:text> |
1968 | + </xsl:when> |
1969 | + <xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')"> |
1970 | + <xsl:text>Courier-Bold</xsl:text> |
1971 | + </xsl:when> |
1972 | + <xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')"> |
1973 | + <xsl:text>Courier-Oblique</xsl:text> |
1974 | + </xsl:when> |
1975 | + <xsl:otherwise> |
1976 | + <xsl:text>Courier</xsl:text> |
1977 | + </xsl:otherwise> |
1978 | + </xsl:choose> |
1979 | + </xsl:when> |
1980 | + <xsl:when test="contains($fontName,'Helvetica') or contains($fontName,'Arial') or contains($fontName,'Sans')"> |
1981 | + <xsl:choose> |
1982 | + <xsl:when test="($fontWeight='bold') and ($fontStyle='italic')"> |
1983 | + <xsl:text>Helvetica-BoldOblique</xsl:text> |
1984 | + </xsl:when> |
1985 | + <xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')"> |
1986 | + <xsl:text>Helvetica-Bold</xsl:text> |
1987 | + </xsl:when> |
1988 | + <xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')"> |
1989 | + <xsl:text>Helvetica-Oblique</xsl:text> |
1990 | + </xsl:when> |
1991 | + <xsl:otherwise> |
1992 | + <xsl:text>Helvetica</xsl:text> |
1993 | + </xsl:otherwise> |
1994 | + </xsl:choose> |
1995 | + </xsl:when> |
1996 | + <xsl:otherwise> |
1997 | + <xsl:choose> |
1998 | + <xsl:when test="($fontWeight='bold') and ($fontStyle='italic')"> |
1999 | + <xsl:text>Times-BoldItalic</xsl:text> |
2000 | + </xsl:when> |
2001 | + <xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')"> |
2002 | + <xsl:text>Times-Bold</xsl:text> |
2003 | + </xsl:when> |
2004 | + <xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')"> |
2005 | + <xsl:text>Times-Italic</xsl:text> |
2006 | + </xsl:when> |
2007 | + <xsl:otherwise> |
2008 | + <xsl:text>Times-Roman</xsl:text> |
2009 | + </xsl:otherwise> |
2010 | + </xsl:choose> |
2011 | + </xsl:otherwise> |
2012 | + </xsl:choose> |
2013 | +</xsl:when> |
2014 | +<xsl:otherwise> |
2015 | + <!--Use this as default --> |
2016 | + <xsl:text>Times-Roman</xsl:text> |
2017 | +</xsl:otherwise> |
2018 | +</xsl:choose> |
2019 | +</xsl:template> |
2020 | +<xsl:template name="make_fontcolor"> |
2021 | + <xsl:variable name="textColor"> |
2022 | + <xsl:value-of select="style:properties/@fo:color"/> |
2023 | + </xsl:variable> |
2024 | + <xsl:if test="not($textColor='') and boolean(style:properties/@fo:color)"> |
2025 | + <xsl:attribute name="textColor"> |
2026 | + <xsl:value-of select="$textColor" /> |
2027 | + </xsl:attribute> |
2028 | + </xsl:if> |
2029 | +</xsl:template> |
2030 | + |
2031 | +<!-- |
2032 | +This stylesheet is part of: |
2033 | +PyOpenOffice Version 0.4 |
2034 | +Copyright (C) 2005: Martin Simon |
2035 | +Homepage: www.bezirksreiter.de |
2036 | + |
2037 | +GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 |
2038 | +--> |
2039 | + |
2040 | +</xsl:stylesheet> |
2041 | + |
2042 | + |
2043 | |
2044 | === added file 'assembly_bom/report/picking_bom.sxw' |
2045 | Binary files assembly_bom/report/picking_bom.sxw 1970-01-01 00:00:00 +0000 and assembly_bom/report/picking_bom.sxw 2011-10-06 15:31:48 +0000 differ |
2046 | === added file 'assembly_bom/report/report_view.xml' |
2047 | --- assembly_bom/report/report_view.xml 1970-01-01 00:00:00 +0000 |
2048 | +++ assembly_bom/report/report_view.xml 2011-10-06 15:31:48 +0000 |
2049 | @@ -0,0 +1,23 @@ |
2050 | +<?xml version="1.0" encoding="utf-8"?> |
2051 | +<openerp> |
2052 | +<data> |
2053 | + <report |
2054 | + auto="False" |
2055 | + id="report_product_consumption_id" |
2056 | + model="product.product" |
2057 | + name="product.consumption" |
2058 | + rml="addons/assembly_bom/report/consumption_report.rml" |
2059 | + string="Product Consumption" |
2060 | + menu="False" |
2061 | + /> |
2062 | + |
2063 | + <!--report |
2064 | + auto="False" |
2065 | + id="report_delivery_bom_id" |
2066 | + model="stock.picking" |
2067 | + name="delivery.bom" |
2068 | + rml="addons/assembly_bom/report/delivery_report.rml" |
2069 | + string="Assembly Delivery Order" |
2070 | + /--> |
2071 | +</data> |
2072 | +</openerp> |
2073 | |
2074 | === added file 'assembly_bom/report/tiny_sxw2rml.py' |
2075 | --- assembly_bom/report/tiny_sxw2rml.py 1970-01-01 00:00:00 +0000 |
2076 | +++ assembly_bom/report/tiny_sxw2rml.py 2011-10-06 15:31:48 +0000 |
2077 | @@ -0,0 +1,377 @@ |
2078 | +#!/usr/bin/python |
2079 | +# -*- encoding: utf-8 -*- |
2080 | +############################################################################## |
2081 | +# |
2082 | +# Copyright (c): |
2083 | +# |
2084 | +# 2005 pyopenoffice.py Martin Simon (http://www.bezirksreiter.de) |
2085 | +# 2005 Fabien Pinckaers, TINY SPRL. (http://tiny.be) |
2086 | +# |
2087 | +# WARNING: This program as such is intended to be used by professional |
2088 | +# programmers who take the whole responsability of assessing all potential |
2089 | +# consequences resulting from its eventual inadequacies and bugs |
2090 | +# End users who are looking for a ready-to-use solution with commercial |
2091 | +# garantees and support are strongly adviced to contact a Free Software |
2092 | +# Service Company |
2093 | +# |
2094 | +# This program is Free Software; you can redistribute it and/or |
2095 | +# modify it under the terms of the GNU General Public License |
2096 | +# as published by the Free Software Foundation; either version 2 |
2097 | +# of the License, or (at your option) any later version. |
2098 | +# |
2099 | +# This program is distributed in the hope that it will be useful, |
2100 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2101 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2102 | +# GNU General Public License for more details. |
2103 | +# |
2104 | +# You should have received a copy of the GNU General Public License |
2105 | +# along with this program; if not, write to the Free Software |
2106 | +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
2107 | +# |
2108 | +############################################################################## |
2109 | + |
2110 | +""" |
2111 | +Tiny SXW2RML - The Open ERP's report engine |
2112 | + |
2113 | +Tiny SXW2RMLis part of the Tiny report project. |
2114 | +Tiny Report is a module that allows you to render high quality PDF document |
2115 | +from an OpenOffice template (.sxw) and any relationnal database. |
2116 | + |
2117 | +The whole source code is distributed under the terms of the |
2118 | +GNU Public Licence. |
2119 | + |
2120 | +(c) 2005 pyopenoffice.py Martin Simon (http://www.bezirksreiter.de) |
2121 | +(c) 2005-TODAY, Fabien Pinckaers - Tiny sprl |
2122 | +""" |
2123 | +__version__ = '0.9' |
2124 | + |
2125 | + |
2126 | +import re |
2127 | +import string |
2128 | +import os |
2129 | +import zipfile |
2130 | +import xml.dom.minidom |
2131 | +from reportlab.lib.units import toLength |
2132 | +import base64 |
2133 | + |
2134 | +class DomApiGeneral: |
2135 | + """General DOM API utilities.""" |
2136 | + def __init__(self,content_string="",file=""): |
2137 | + self.content_string = content_string |
2138 | + self.re_digits = re.compile(r"(.*?\d)(pt|cm|mm|inch|in)") |
2139 | + |
2140 | + def _unitTuple(self,string): |
2141 | + """Split values and units to a tuple.""" |
2142 | + temp = self.re_digits.findall(string) |
2143 | + if not temp: |
2144 | + return (string,"") |
2145 | + else: |
2146 | + return (temp[0]) |
2147 | + |
2148 | + def stringPercentToFloat(self,string): |
2149 | + temp = string.replace("""%""","") |
2150 | + return float(temp)/100 |
2151 | + |
2152 | + def findChildrenByName(self,parent,name,attr_dict={}): |
2153 | + """Helper functions. Does not work recursively. |
2154 | + Optional: also test for certain attribute/value pairs.""" |
2155 | + children = [] |
2156 | + for c in parent.childNodes: |
2157 | + if c.nodeType == c.ELEMENT_NODE and c.nodeName == name: |
2158 | + children.append(c) |
2159 | + if attr_dict == {}: |
2160 | + return children |
2161 | + else: |
2162 | + return self._selectForAttributes(nodelist=children,attr_dict=attr_dict) |
2163 | + |
2164 | + def _selectForAttributes(self,nodelist,attr_dict): |
2165 | + "Helper function.""" |
2166 | + selected_nodes = [] |
2167 | + for n in nodelist: |
2168 | + check = 1 |
2169 | + for a in attr_dict.keys(): |
2170 | + if n.getAttribute(a) != attr_dict[a]: |
2171 | + # at least one incorrect attribute value? |
2172 | + check = 0 |
2173 | + if check: |
2174 | + selected_nodes.append(n) |
2175 | + return selected_nodes |
2176 | + |
2177 | + def _stringToTuple(self,s): |
2178 | + """Helper function.""" |
2179 | + try: |
2180 | + temp = string.split(s,",") |
2181 | + return int(temp[0]),int(temp[1]) |
2182 | + except: |
2183 | + return None |
2184 | + |
2185 | + def _tupleToString(self,t): |
2186 | + try: |
2187 | + return self.openOfficeStringUtf8("%s,%s" % (t[0],t[1])) |
2188 | + except: |
2189 | + return None |
2190 | + |
2191 | + def _lengthToFloat(self,value): |
2192 | + v = value |
2193 | + if not self.re_digits.search(v): |
2194 | + return v |
2195 | + try: |
2196 | + if v[-4:] == "inch": |
2197 | + # OO files use "inch" instead of "in" in Reportlab units |
2198 | + v = v[:-2] |
2199 | + except: |
2200 | + pass |
2201 | + try: |
2202 | + c = round(toLength(v)) |
2203 | + return c |
2204 | + except: |
2205 | + return v |
2206 | + |
2207 | + def openOfficeStringUtf8(self,string): |
2208 | + if type(string) == unicode: |
2209 | + return string.encode("utf-8") |
2210 | + tempstring = unicode(string,"cp1252").encode("utf-8") |
2211 | + return tempstring |
2212 | + |
2213 | +class DomApi(DomApiGeneral): |
2214 | + """This class provides a DOM-API for XML-Files from an SXW-Archive.""" |
2215 | + def __init__(self,xml_content,xml_styles): |
2216 | + DomApiGeneral.__init__(self) |
2217 | + self.content_dom = xml.dom.minidom.parseString(xml_content) |
2218 | + self.styles_dom = xml.dom.minidom.parseString(xml_styles) |
2219 | + body = self.content_dom.getElementsByTagName("office:body") |
2220 | + self.body = body and body[0] |
2221 | + |
2222 | + # TODO: |
2223 | + self.style_dict = {} |
2224 | + self.style_properties_dict = {} |
2225 | + |
2226 | + # ******** always use the following order: |
2227 | + self.buildStyleDict() |
2228 | + self.buildStylePropertiesDict() |
2229 | + if self.styles_dom.getElementsByTagName("style:page-master").__len__()<>0: |
2230 | + self.page_master = self.styles_dom.getElementsByTagName("style:page-master")[0] |
2231 | + if self.styles_dom.getElementsByTagName("style:page-layout").__len__()<>0 : |
2232 | + self.page_master = self.styles_dom.getElementsByTagName("style:page-layout")[0] |
2233 | + self.document = self.content_dom.getElementsByTagName("office:document-content")[0] |
2234 | + |
2235 | + def buildStylePropertiesDict(self): |
2236 | + for s in self.style_dict.keys(): |
2237 | + self.style_properties_dict[s] = self.getStylePropertiesDict(s) |
2238 | + |
2239 | + def updateWithPercents(self,dict,updatedict): |
2240 | + """Sometimes you find values like "115%" in the style hierarchy.""" |
2241 | + if not updatedict: |
2242 | + # no style hierarchies for this style? => |
2243 | + return |
2244 | + new_updatedict = copy.copy(updatedict) |
2245 | + for u in new_updatedict.keys(): |
2246 | + try: |
2247 | + if new_updatedict[u].find("""%""") != -1 and dict.has_key(u): |
2248 | + number = float(self.re_digits.search(dict[u]).group(1)) |
2249 | + unit = self.re_digits.search(dict[u]).group(2) |
2250 | + new_number = self.stringPercentToFloat(new_updatedict[u]) * number |
2251 | + if unit == "pt": |
2252 | + new_number = int(new_number) |
2253 | + # no floats allowed for "pt" |
2254 | + # OOo just takes the int, does not round (try it out!) |
2255 | + new_updatedict[u] = "%s%s" % (new_number,unit) |
2256 | + else: |
2257 | + dict[u] = new_updatedict[u] |
2258 | + except: |
2259 | + dict[u] = new_updatedict[u] |
2260 | + dict.update(new_updatedict) |
2261 | + |
2262 | + def normalizeStyleProperties(self): |
2263 | + """Transfer all style:style-properties attributes from the |
2264 | + self.style_properties_hierarchical dict to the automatic-styles |
2265 | + from content.xml. Use this function to preprocess content.xml for |
2266 | + XSLT transformations etc.Do not try to implement this function |
2267 | + with XSlT - believe me, it's a terrible task...""" |
2268 | + styles_styles = self.styles_dom.getElementsByTagName("style:style") |
2269 | + automatic_styles = self.content_dom.getElementsByTagName("office:automatic-styles")[0] |
2270 | + for s in styles_styles: |
2271 | + automatic_styles.appendChild(s.cloneNode(deep=1)) |
2272 | + content_styles = self.content_dom.getElementsByTagName("style:style") |
2273 | + # these are the content_styles with styles_styles added!!! |
2274 | + for s in content_styles: |
2275 | + c = self.findChildrenByName(s,"style:properties") |
2276 | + if c == []: |
2277 | + # some derived automatic styles do not have "style:properties": |
2278 | + temp = self.content_dom.createElement("style:properties") |
2279 | + s.appendChild(temp) |
2280 | + c = self.findChildrenByName(s,"style:properties") |
2281 | + c = c[0] |
2282 | + dict = self.style_properties_dict[(s.getAttribute("style:name")).encode("utf-8")] or {} |
2283 | + for attribute in dict.keys(): |
2284 | + c.setAttribute(self.openOfficeStringUtf8(attribute),self.openOfficeStringUtf8(dict[attribute])) |
2285 | + |
2286 | + def transferStylesXml(self): |
2287 | + """Transfer certain sub-trees from styles.xml to the normalized content.xml |
2288 | + (see above). It is not necessary to do this - for example - with paragraph styles. |
2289 | + the "normalized" style properties contain all information needed for |
2290 | + further processing.""" |
2291 | + # TODO: What about table styles etc.? |
2292 | + outline_styles = self.styles_dom.getElementsByTagName("text:outline-style") |
2293 | + t = self.content_dom.createElement("transferredfromstylesxml") |
2294 | + self.document.insertBefore(t,self.body) |
2295 | + t_new = self.body.previousSibling |
2296 | + try: |
2297 | + page_master = self.page_master |
2298 | + t_new.appendChild(page_master.cloneNode(deep=1)) |
2299 | + t_new.appendChild(outline_styles[0].cloneNode(deep=1)) |
2300 | + except: |
2301 | + pass |
2302 | + |
2303 | + def normalizeLength(self): |
2304 | + """Normalize all lengthes to floats (i.e: 1 inch = 72). |
2305 | + Always use this after "normalizeContent" and "transferStyles"!""" |
2306 | + # TODO: The complex attributes of table cell styles are not transferred yet. |
2307 | + #all_styles = self.content_dom.getElementsByTagName("style:properties") |
2308 | + #all_styles += self.content_dom.getElementsByTagName("draw:image") |
2309 | + all_styles = self.content_dom.getElementsByTagName("*") |
2310 | + for s in all_styles: |
2311 | + for x in s._attrs.keys(): |
2312 | + v = s.getAttribute(x) |
2313 | + s.setAttribute(x,"%s" % self._lengthToFloat(v)) |
2314 | + # convert float to string first! |
2315 | + |
2316 | + def normalizeTableColumns(self): |
2317 | + """Handle this strange table:number-columns-repeated attribute.""" |
2318 | + columns = self.content_dom.getElementsByTagName("table:table-column") |
2319 | + for c in columns: |
2320 | + if c.hasAttribute("table:number-columns-repeated"): |
2321 | + number = int(c.getAttribute("table:number-columns-repeated")) |
2322 | + c.removeAttribute("table:number-columns-repeated") |
2323 | + for i in range(number-1): |
2324 | + (c.parentNode).insertBefore(c.cloneNode(deep=1),c) |
2325 | + |
2326 | + def buildStyleDict(self): |
2327 | + """Store all style:style-nodes from content.xml and styles.xml in self.style_dict. |
2328 | + Caution: in this dict the nodes from two dom apis are merged!""" |
2329 | + for st in (self.styles_dom,self.content_dom): |
2330 | + for s in st.getElementsByTagName("style:style"): |
2331 | + name = s.getAttribute("style:name").encode("utf-8") |
2332 | + self.style_dict[name] = s |
2333 | + return True |
2334 | + |
2335 | + def toxml(self): |
2336 | + return self.content_dom.toxml(encoding="utf-8") |
2337 | + |
2338 | + def getStylePropertiesDict(self,style_name): |
2339 | + res = {} |
2340 | + |
2341 | + if self.style_dict[style_name].hasAttribute("style:parent-style-name"): |
2342 | + parent = self.style_dict[style_name].getAttribute("style:parent-style-name").encode("utf-8") |
2343 | + res = self.getStylePropertiesDict(parent) |
2344 | + |
2345 | + childs = self.style_dict[style_name].childNodes |
2346 | + for c in childs: |
2347 | + if c.nodeType == c.ELEMENT_NODE and c.nodeName.find("properties")>0 : |
2348 | + for attr in c._attrs.keys(): |
2349 | + res[attr] = c.getAttribute(attr).encode("utf-8") |
2350 | + return res |
2351 | + |
2352 | +class PyOpenOffice(object): |
2353 | + """This is the main class which provides all functionality.""" |
2354 | + def __init__(self, path='.', save_pict=False): |
2355 | + self.path = path |
2356 | + self.save_pict = save_pict |
2357 | + self.images = {} |
2358 | + |
2359 | + def oo_read(self,fname): |
2360 | + z = zipfile.ZipFile(fname,"r") |
2361 | + content = z.read('content.xml') |
2362 | + style = z.read('styles.xml') |
2363 | + all = z.namelist() |
2364 | + for a in all: |
2365 | + if a[:9]=='Pictures/' and len(a)>10: |
2366 | + pic_content = z.read(a) |
2367 | + self.images[a[9:]] = pic_content |
2368 | + if self.save_pict: |
2369 | + f=open(os.path.join(self.path, os.path.basename(a)),"wb") |
2370 | + f.write(pic_content) |
2371 | + f.close() |
2372 | + z.close() |
2373 | + return content,style |
2374 | + |
2375 | + def oo_replace(self,content): |
2376 | + regex = [ |
2377 | + (r"<para[^>]*/>", ""), |
2378 | + #(r"<text:ordered-list.*?>(.*?)</text:ordered-list>", "$1"), |
2379 | + #(r"<text:unordered-list.*?>(.*?)</text:unordered-list>", "$1"), |
2380 | + (r"<para(.*)>(.*?)<text:line-break[^>]*/>", "<para$1>$2</para><para$1>"), |
2381 | + ] |
2382 | + for key,val in regex: |
2383 | + content = re.sub(key, val, content) |
2384 | + return content |
2385 | + |
2386 | + def unpackNormalize(self,sourcefile): |
2387 | + c,s = self.oo_read(sourcefile) |
2388 | + c = self.oo_replace(c) |
2389 | + dom = DomApi(c,s) |
2390 | + dom.normalizeStyleProperties() |
2391 | + dom.transferStylesXml() |
2392 | + dom.normalizeLength() |
2393 | + dom.normalizeTableColumns() |
2394 | + new_c = dom.toxml() |
2395 | + return new_c |
2396 | + |
2397 | +def sxw2rml(sxw_file, xsl, output='.', save_pict=False): |
2398 | + from lxml import etree |
2399 | + from StringIO import StringIO |
2400 | + |
2401 | + tool = PyOpenOffice(output, save_pict = save_pict) |
2402 | + res = tool.unpackNormalize(sxw_file) |
2403 | + |
2404 | + f = StringIO(xsl) |
2405 | + styledoc = etree.parse(f) |
2406 | + style = etree.XSLT(styledoc) |
2407 | + |
2408 | + f = StringIO(res) |
2409 | + doc = etree.parse(f) |
2410 | + result = style(doc) |
2411 | + root = etree.XPathEvaluator(result)("/document/stylesheet") |
2412 | + |
2413 | + if root: |
2414 | + root=root[0] |
2415 | + images = etree.Element("images") |
2416 | + for img in tool.images: |
2417 | + node = etree.Element('image', name=img) |
2418 | + node.text = base64.encodestring(tool.images[img]) |
2419 | + images.append(node) |
2420 | + root.append(images) |
2421 | + |
2422 | + try: |
2423 | + xml = str(result) |
2424 | + return xml |
2425 | + except: |
2426 | + return result |
2427 | + |
2428 | +if __name__ == "__main__": |
2429 | + import optparse |
2430 | + parser = optparse.OptionParser( |
2431 | + version="Tiny Report v%s" % __version__, |
2432 | + usage = 'tiny_sxw2rml.py [options] file.sxw') |
2433 | + parser.add_option("-v", "--verbose", default=False, dest="verbose", help="enable basic debugging") |
2434 | + parser.add_option("-o", "--output", dest="output", default='.', help="directory of image output") |
2435 | + (opt, args) = parser.parse_args() |
2436 | + if len(args) != 1: |
2437 | + parser.error("incorrect number of arguments") |
2438 | + |
2439 | + import sys |
2440 | + import StringIO |
2441 | + |
2442 | + fname = sys.argv[1] |
2443 | + f = fname |
2444 | + xsl_file = 'normalized_oo2rml.xsl' |
2445 | + z = zipfile.ZipFile(fname,"r") |
2446 | + mimetype = z.read('mimetype') |
2447 | + if mimetype.split('/')[-1] == 'vnd.oasis.opendocument.text' : |
2448 | + xsl_file = 'normalized_odt2rml.xsl' |
2449 | + xsl = file(os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]), xsl_file)).read() |
2450 | + result = sxw2rml(f, xsl, output=opt.output, save_pict=False) |
2451 | + |
2452 | + print result |
2453 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
2454 | + |
2455 | |
2456 | === added file 'assembly_bom/sale.py' |
2457 | --- assembly_bom/sale.py 1970-01-01 00:00:00 +0000 |
2458 | +++ assembly_bom/sale.py 2011-10-06 15:31:48 +0000 |
2459 | @@ -0,0 +1,71 @@ |
2460 | +# -*- ecoding: utf-8 -*- |
2461 | +############################################################################## |
2462 | +# |
2463 | +# OpenERP, Open Source Management Solution |
2464 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
2465 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
2466 | +# |
2467 | +# This program is free software: you can redistribute it and/or modify |
2468 | +# it under the terms of the GNU General Public License as published by |
2469 | +# the Free Software Foundation, either version 3 of the License, or |
2470 | +# (at your option) any later version. |
2471 | +# |
2472 | +# This program is distributed in the hope that it will be useful, |
2473 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2474 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2475 | +# GNU General Public License for more details. |
2476 | +# |
2477 | +# You should have received a copy of the GNU General Public License |
2478 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
2479 | +# |
2480 | +############################################################################## |
2481 | + |
2482 | +from osv import fields, osv |
2483 | +import netsvc |
2484 | +import datetime |
2485 | +import time |
2486 | +from tools.translate import _ |
2487 | + |
2488 | +class sale_order_line(osv.osv): |
2489 | + _inherit = 'sale.order.line' |
2490 | + def product_id_change(self, cr, uid, ids, pricelist, product, qty=0, |
2491 | + uom=False, qty_uos=0, uos=False, name='', partner_id=False, |
2492 | + lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False,partner_shipping_id=False, shop_id=False, context={}): |
2493 | + |
2494 | + ret=super(sale_order_line, self).product_id_change(cr, uid, ids, pricelist, product, qty=qty,uom=uom, qty_uos=qty_uos, uos=uos, name=name, partner_id=partner_id,lang=lang, update_tax=update_tax, date_order=date_order, packaging=packaging, fiscal_position=fiscal_position, flag=flag) |
2495 | + if not ret.get('warning') and product: |
2496 | + product_obj = self.pool.get('product.product') |
2497 | + product_uom_obj = self.pool.get('product.uom') |
2498 | + product_obj = product_obj.browse(cr, uid, product, context=context) |
2499 | + uom2 = False |
2500 | + if uom: |
2501 | + uom2 = product_uom_obj.browse(cr, uid, uom) |
2502 | + if product_obj.uom_id.category_id.id != uom2.category_id.id: |
2503 | + uom = False |
2504 | + |
2505 | + if (product_obj.type=='product') and product_obj.procure_method=='make_to_order': |
2506 | + bom_id = self.pool.get('mrp.bom').search(cr, uid, [ |
2507 | + ('product_id', '=', product_obj.id), |
2508 | + ('bom_id', '=', False), |
2509 | + ('type', '=', 'assembly')]) |
2510 | + if bom_id: |
2511 | + bom_id = bom_id[0] |
2512 | + bom_obj = self.pool.get('mrp.bom').browse(cr, uid, bom_id) |
2513 | + if bom_id and 'bom_stock_value' in bom_obj._columns.keys() and (bom_obj.bom_stock_value < qty * product_obj.uom_id.factor): |
2514 | + warning = { |
2515 | + 'title': _('Not enough stock !'), |
2516 | + 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % |
2517 | + (qty, uom2 and uom2.name or product_obj.uom_id.name, |
2518 | + max(0,bom_obj.bom_stock_value), product_obj.uom_id.name, |
2519 | + max(0,product_obj.qty_available), product_obj.uom_id.name) |
2520 | + } |
2521 | + ret['warning'] = warning |
2522 | + return ret |
2523 | +sale_order_line() |
2524 | + |
2525 | + |
2526 | + |
2527 | + |
2528 | + |
2529 | + |
2530 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
2531 | \ No newline at end of file |
2532 | |
2533 | === added file 'assembly_bom/stock.py' |
2534 | --- assembly_bom/stock.py 1970-01-01 00:00:00 +0000 |
2535 | +++ assembly_bom/stock.py 2011-10-06 15:31:48 +0000 |
2536 | @@ -0,0 +1,378 @@ |
2537 | +# -*- ecoding: utf-8 -*- |
2538 | +############################################################################## |
2539 | +# |
2540 | +# OpenERP, Open Source Management Solution |
2541 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
2542 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
2543 | +# |
2544 | +# This program is free software: you can redistribute it and/or modify |
2545 | +# it under the terms of the GNU General Public License as published by |
2546 | +# the Free Software Foundation, either version 3 of the License, or |
2547 | +# (at your option) any later version. |
2548 | +# |
2549 | +# This program is distributed in the hope that it will be useful, |
2550 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
2551 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2552 | +# GNU General Public License for more details. |
2553 | +# |
2554 | +# You should have received a copy of the GNU General Public License |
2555 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
2556 | +# |
2557 | +############################################################################## |
2558 | + |
2559 | +from osv import fields, osv |
2560 | +import netsvc |
2561 | +import datetime |
2562 | +import time |
2563 | +from tools.translate import _ |
2564 | + |
2565 | +class StockMove(osv.osv): |
2566 | + _inherit = 'stock.move' |
2567 | + |
2568 | + def _action_explode(self, cr, uid, move, context=None): |
2569 | + """ Explodes pickings to produce many moves as per the bom lines for products assembly bom. |
2570 | + @param move: Stock moves |
2571 | + @constraints: explode takes place for pickings related to sale order |
2572 | + @return: True |
2573 | + """ |
2574 | + result=super(StockMove, self)._action_explode(cr, uid, move, context=context) |
2575 | + bom_obj = self.pool.get('mrp.bom') |
2576 | + move_obj = self.pool.get('stock.move') |
2577 | + procurement_obj = self.pool.get('procurement.order') |
2578 | + product_obj = self.pool.get('product.product') |
2579 | + wf_service = netsvc.LocalService("workflow") |
2580 | + production_obj=self.pool.get('mrp.production') |
2581 | + if move.product_id.supply_method == 'produce' and move.product_id.procure_method == 'make_to_order': |
2582 | + bis = bom_obj.search(cr, uid, [ |
2583 | + ('product_id','=',move.product_id.id), |
2584 | + ('bom_id','=',False), |
2585 | + ('type','=','assembly')]) |
2586 | + if bis: |
2587 | + factor = move.product_qty |
2588 | + bom_point = bom_obj.browse(cr, uid, bis[0], context=context) |
2589 | + res = bom_obj._bom_explode(cr, uid, bom_point, factor, []) |
2590 | + dest = move.product_id.product_tmpl_id.property_stock_production.id |
2591 | + |
2592 | + if move.sale_line_id: |
2593 | + |
2594 | + #1. partial delivery is not allowed for kit type bom product |
2595 | + move.picking_id.write({'move_type':'one'}) |
2596 | + |
2597 | + #2. manually changing the state to confirmed for each exploded move to allow checking bom stock value |
2598 | + #related to mrp_jit |
2599 | + state = 'confirmed' |
2600 | + if move.state == 'assigned': |
2601 | + state = 'assigned' |
2602 | + if res[0] and res[0][0]: |
2603 | + line=res[0][0] |
2604 | + valdef = { |
2605 | + 'picking_id': move.picking_id.id, |
2606 | + 'product_id': line['product_id'], |
2607 | + 'product_uom': line['product_uom'], |
2608 | + 'product_qty': line['product_qty'], |
2609 | + 'product_uos': line['product_uos'], |
2610 | + 'product_uos_qty': line['product_uos_qty'], |
2611 | + 'move_dest_id': move.id, |
2612 | + 'state': state, |
2613 | + 'name': line['name'], |
2614 | + 'location_dest_id': dest, |
2615 | + #'move_history_ids': [(6,0,[move.id])], |
2616 | + #'move_history_ids2': [(6,0,[])], |
2617 | + 'procurements': [], |
2618 | + 'sale_line_id':False, |
2619 | + "kit_id":False, |
2620 | + "parent_bom_id":bis[0], |
2621 | + 'sale_id':move.sale_line_id.order_id.id |
2622 | + |
2623 | + } |
2624 | + move.write(valdef) |
2625 | + |
2626 | + for line in res[0][1:]: |
2627 | + valdef = { |
2628 | + 'picking_id': move.picking_id.id, |
2629 | + 'product_id': line['product_id'], |
2630 | + 'product_uom': line['product_uom'], |
2631 | + 'product_qty': line['product_qty'], |
2632 | + 'product_uos': line['product_uos'], |
2633 | + 'product_uos_qty': line['product_uos_qty'], |
2634 | + 'move_dest_id': move.id, |
2635 | + 'state': state, |
2636 | + 'name': line['name'], |
2637 | + 'location_dest_id': dest, |
2638 | + #'move_history_ids': [(6,0,[move.id])], |
2639 | + #'move_history_ids2': [(6,0,[])], |
2640 | + 'procurements': [], |
2641 | + 'sale_line_id':False, |
2642 | + "kit_id":False, |
2643 | + "parent_bom_id":bis[0], |
2644 | + 'sale_id':move.sale_line_id.order_id.id |
2645 | + } |
2646 | + mid = move_obj.copy(cr, uid, move.id, default=valdef) |
2647 | + move_obj.action_assign(cr, uid, [mid]) |
2648 | + prodobj = product_obj.browse(cr, uid, line['product_id'], context=context) |
2649 | + |
2650 | + cr.commit() |
2651 | + return result |
2652 | + |
2653 | + |
2654 | + _columns={ |
2655 | + 'sale_id': fields.many2one('sale.order',"Sale Reference"), |
2656 | + 'kit_id':fields.many2one('mrp.production',"Assembly"), |
2657 | + 'production_ids': fields.many2many('mrp.production', 'mrp_production_move_ids', 'move_id', 'production_id', 'Related Production'), |
2658 | + 'parent_bom_id':fields.many2one("mrp.bom",'Related Bom') |
2659 | + } |
2660 | + def onchange_quantity(self, cr, uid, ids, product_id, product_qty, |
2661 | + product_uom, product_uos,location_id=False): |
2662 | + """ On change of product quantity finds UoM and UoS quantities |
2663 | + @param product_id: Product id |
2664 | + @param product_qty: Changed Quantity of product |
2665 | + @param product_uom: Unit of measure of product |
2666 | + @param product_uos: Unit of sale of product |
2667 | + @return: Dictionary of values |
2668 | + """ |
2669 | + context={} |
2670 | + if location_id: |
2671 | + context['location'] =[location_id] |
2672 | + result=super(StockMove,self).onchange_quantity(cr, uid, ids, product_id, product_qty, product_uom, product_uos) |
2673 | + if (not product_id) or (product_qty <=0.0): |
2674 | + return result |
2675 | + product_obj = self.pool.get('product.product').browse(cr, uid, [product_id],context=context)[0] |
2676 | + uom2 = product_obj.uom_id |
2677 | + if (product_obj.type=='product') and (product_obj.virtual_available * uom2.factor < product_qty * product_obj.uom_id.factor) \ |
2678 | + and (product_obj.procure_method=='make_to_stock'): |
2679 | + warning = { |
2680 | + 'title': _('Not enough stock !'), |
2681 | + 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % |
2682 | + (product_qty, uom2 and uom2.name or product_obj.uom_id.name, |
2683 | + max(0,product_obj.virtual_available), product_obj.uom_id.name, |
2684 | + max(0,product_obj.qty_available), product_obj.uom_id.name) |
2685 | + } |
2686 | + result['warning'] = warning |
2687 | + |
2688 | + if (product_obj.type=='product') and product_obj.procure_method=='make_to_order': |
2689 | + bom_id = self.pool.get('mrp.bom').search(cr, uid, [ |
2690 | + ('product_id', '=', product_obj.id), |
2691 | + ('bom_id', '=', False)]) |
2692 | + bom_obj = False |
2693 | + if bom_id: |
2694 | + bom_obj = self.pool.get('mrp.bom').browse(cr, uid, bom_id[0]) |
2695 | + |
2696 | + if bom_obj and (bom_obj.bom_stock_value < product_qty * product_obj.uom_id.factor) \ |
2697 | + and (product_obj.procure_method=='make_to_order'): |
2698 | + warning = { |
2699 | + 'title': _('Not enough stock !'), |
2700 | + 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % |
2701 | + (product_qty, uom2 and uom2.name or product_obj.uom_id.name, |
2702 | + max(0,bom_obj.bom_stock_value), product_obj.uom_id.name, |
2703 | + max(0,product_obj.qty_available), product_obj.uom_id.name) |
2704 | + } |
2705 | + result['warning'] = warning |
2706 | + |
2707 | + return result |
2708 | + def onchange_product_id(self, cr, uid, ids, prod_id=False, loc_id=False, |
2709 | + loc_dest_id=False, address_id=False,product_qty=0): |
2710 | + """ On change of product id, . |
2711 | + @param prod_id: Changed Product id |
2712 | + @param loc_id: Source location id |
2713 | + @param loc_id: Destination location id |
2714 | + @param address_id: Address id of partner |
2715 | + @param product_qty: Product Quantity |
2716 | + @return: Dictionary of values |
2717 | + """ |
2718 | + warning = {} |
2719 | + context = {} |
2720 | + res=super(StockMove,self).onchange_product_id(cr, uid, ids, prod_id=prod_id, loc_id=loc_id, |
2721 | + loc_dest_id=loc_dest_id, address_id=address_id) |
2722 | + if not prod_id: |
2723 | + return res |
2724 | + if loc_id: |
2725 | + context['location'] = [loc_id] |
2726 | + product_obj = self.pool.get('product.product').browse(cr, uid, [prod_id],context=context)[0] |
2727 | + uom2 = product_obj.uom_id |
2728 | + if (product_obj.type=='product') and (product_obj.virtual_available * uom2.factor < product_qty * product_obj.uom_id.factor) \ |
2729 | + and (product_obj.procure_method=='make_to_stock'): |
2730 | + warning = { |
2731 | + 'title': _('Not enough stock !'), |
2732 | + 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % |
2733 | + (product_qty, uom2 and uom2.name or product_obj.uom_id.name, |
2734 | + max(0,product_obj.virtual_available), product_obj.uom_id.name, |
2735 | + max(0,product_obj.qty_available), product_obj.uom_id.name) |
2736 | + } |
2737 | + res['warning'] = warning |
2738 | + if (product_obj.type=='product') and product_obj.procure_method=='make_to_order': |
2739 | + bom_id = self.pool.get('mrp.bom').search(cr, uid, [ |
2740 | + ('product_id', '=', product_obj.id), |
2741 | + ('bom_id', '=', False)]) |
2742 | + if bom_id: |
2743 | + bom_obj = self.pool.get('mrp.bom').browse(cr, uid, bom_id[0]) |
2744 | + if bom_id and (bom_obj.bom_stock_value < product_qty * product_obj.uom_id.factor): |
2745 | + warning = { |
2746 | + 'title': _('Not enough stock !'), |
2747 | + 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') % |
2748 | + (product_qty, uom2 and uom2.name or product_obj.uom_id.name, |
2749 | + max(0,bom_obj.bom_stock_value), product_obj.uom_id.name, |
2750 | + max(0,product_obj.qty_available), product_obj.uom_id.name) |
2751 | + } |
2752 | + res['warning'] = warning |
2753 | + return res |
2754 | + _defaults = { |
2755 | + 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), |
2756 | + 'date_expected': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), |
2757 | + } |
2758 | + |
2759 | +StockMove() |
2760 | + |
2761 | + |
2762 | +class stock_picking(osv.osv): |
2763 | + _inherit="stock.picking" |
2764 | + |
2765 | + def do_partial(self, cr, uid, ids, partial_datas, context=None): |
2766 | + """Creates and processes the assembly (MO) operation for delivery of product with assembly bom during sale |
2767 | + @param self: The object pointer. |
2768 | + @param ids: ids of the procurement order document |
2769 | + @param context: standard dictionary |
2770 | + @comment: Creates Production order for assembly of the product with assembly bom and |
2771 | + deliveres the product to customers making moves to ensure stock tracking |
2772 | + @return: returns dictionary carrying delivered picking details |
2773 | + """ |
2774 | + bom_obj = self.pool.get('mrp.bom') |
2775 | + picking_obj=self.pool.get('stock.picking') |
2776 | + produce_wiz_obj=self.pool.get("mrp.product.produce") |
2777 | + production_obj=self.pool.get('mrp.production') |
2778 | + move_obj=self.pool.get("stock.move") |
2779 | + sale_obj=self.pool.get("sale.order") |
2780 | + wf_service=netsvc.LocalService('workflow') |
2781 | + res=super(stock_picking,self).do_partial(cr, uid, ids, partial_datas) |
2782 | + picking_details=res.values() |
2783 | + picking_id=picking_details and picking_details[0].get('delivered_picking',False) or False |
2784 | + if picking_id: |
2785 | + #expecting the picking state will not be 'done' |
2786 | + picking=picking_obj.browse(cr,uid,picking_id,context=context) |
2787 | + sale_order=picking.sale_id |
2788 | + if not sale_order: |
2789 | + return res |
2790 | + |
2791 | + sale_obj.action_ship_end(cr, uid, [picking.sale_id.id], context=context) |
2792 | + for line in sale_order.order_line: |
2793 | + bom_ids=bom_obj.search(cr,uid,[('product_id','=',line.product_id.id)],context={}) |
2794 | +# procure_id=production_obj.create(cr,uid,{ 'name':'ASSEMBLY'+sale_order.name, |
2795 | + bom_id=bom_ids and bom_ids[0] or False |
2796 | + if bom_id: |
2797 | + bom=bom_obj.browse(cr,uid,bom_id) |
2798 | + if bom and bom.type=='normal': |
2799 | + move_ids=[move.id for move in picking.move_lines] or [] |
2800 | + normal_move_ids=move_obj.search(cr,uid,[('id','in',move_ids),('product_id','=',line.product_id.id)]) |
2801 | + ###Expecting |
2802 | + #1. Sale order is having only one line with the product having normal bom |
2803 | + if normal_move_ids: |
2804 | + normal_move_id=normal_move_ids[0]#Refer:#1 |
2805 | + normal_move=move_obj.browse(cr,uid,normal_move_id) |
2806 | + normal_move.write({ |
2807 | + 'sale_id':line.order_id.id |
2808 | + }) |
2809 | + |
2810 | + if bom and bom.type=='assembly': |
2811 | + #1. Warehouse stock and output location selected as stock and output |
2812 | + stock_id = sale_order.shop_id.warehouse_id.lot_stock_id.id#stock location |
2813 | + output_id = sale_order.shop_id.warehouse_id.lot_output_id.id#output warehouse location |
2814 | + #2. sale partner customer location selected as customer |
2815 | + customer_loc_id=sale_order.partner_id.property_stock_customer.id or False#customer location |
2816 | + mo_sequence=self.pool.get('ir.sequence').get(cr, uid, 'mrp.production') |
2817 | + src_loc_id=line.product_id.property_stock_production.id#stock location_id |
2818 | + production_id=production_obj.create(cr,uid,{ |
2819 | + 'name': mo_sequence or sale_order.name, |
2820 | + 'origin':sale_order.name, |
2821 | + 'product_id':line.product_id.id, |
2822 | + 'product_qty':line.product_uom_qty, |
2823 | + 'product_uom':line.product_uom.id, |
2824 | + 'product_uos_qty':(line.product_uos and line.product_uos_qty)\ |
2825 | + or line.product_uom_qty, |
2826 | + 'product_uos':(line.product_uos and line.product_uos.id)\ |
2827 | + or line.product_uom.id, |
2828 | + 'location_src_id':src_loc_id, |
2829 | + # 'location_dest_id':sale_order.shop_id.warehouse_id.lot_stock_id.id, |
2830 | + 'location_dest_id':stock_id, |
2831 | + 'date_start':time.strftime('%Y-%m-%d'), |
2832 | + 'bom_id':bom_ids and bom_ids[0] or False, |
2833 | + 'picking_id':picking_id, |
2834 | + # 'procure_id':line.procurement_id.id, |
2835 | + },context=context) |
2836 | + |
2837 | + # 3.To suit sale order with multiple lines its achieved by comparing the product in production order |
2838 | + # and the one sold and the one associated with the parent_bom stored in the move object |
2839 | + |
2840 | + for move in picking.move_lines: |
2841 | + sold_product_id=line.product_id.id |
2842 | + parent_product_id=move.parent_bom_id and move.parent_bom_id.product_id.id or False |
2843 | + if parent_product_id and parent_product_id==sold_product_id: |
2844 | + move.write({'kit_id':production_id}) |
2845 | + |
2846 | + |
2847 | + production=production_obj.browse(cr,uid,production_id) |
2848 | + wf_service.trg_validate(uid, 'mrp.production', production_id, 'button_confirm', cr) |
2849 | + move_ids=[move.id for move in production.move_lines] |
2850 | + move_obj.write(cr,uid,move_ids,{'sale_id':line.order_id.id},context=context) |
2851 | + production_obj.force_production(cr, uid, [production_id]) |
2852 | + move_ids=[move.id for move in production.move_lines] |
2853 | + production_obj.action_produce(cr, uid, production_id,production.product_qty,'consume_produce') |
2854 | + wf_service.trg_validate(uid, 'mrp.production',production_id,'button_produce_done', cr) |
2855 | + date_planned=time.strftime('%Y-%m-%d') |
2856 | + cr.commit() |
2857 | + production=production_obj.browse(cr,uid,production_id) |
2858 | + production_finished=(production.state=='done') |
2859 | + if production_finished: |
2860 | + finished_ids=[move.id for move in production.move_created_ids2] |
2861 | + |
2862 | + move_obj.write(cr,uid,finished_ids,{'sale_id':line.order_id.id},context=context) |
2863 | + |
2864 | + finished_move_stock_id = self.pool.get('stock.move').create(cr, uid, { |
2865 | + 'name': line.name[:64], |
2866 | + 'picking_id': False, |
2867 | + 'product_id': line.product_id.id, |
2868 | + 'date': time.strftime('%Y-%m-%d'), |
2869 | + 'date_expected': time.strftime('%Y-%m-%d'), |
2870 | + 'product_qty': line.product_uom_qty, |
2871 | + 'product_uom': line.product_uom.id, |
2872 | + 'product_uos_qty': line.product_uos_qty, |
2873 | + 'product_uos': (line.product_uos and line.product_uos.id)\ |
2874 | + or line.product_uom.id, |
2875 | + 'product_packaging': line.product_packaging.id, |
2876 | + 'address_id': line.address_allotment_id.id or sale_order.partner_shipping_id.id, |
2877 | + 'location_id': stock_id, |
2878 | + 'location_dest_id':output_id,#move destination to output location of the warehouse |
2879 | + 'sale_line_id': line.id, |
2880 | + 'tracking_id': False, |
2881 | + 'state': 'draft', |
2882 | + #'state': 'waiting', |
2883 | + 'note': line.notes, |
2884 | + 'kit_id':False, |
2885 | + 'company_id': sale_order.company_id.id, |
2886 | + 'sale_id': sale_order.id, |
2887 | + }) |
2888 | + |
2889 | + move2_id=move_obj.copy(cr,uid,finished_move_stock_id,{'location_id':output_id, 'sale_line_id':False,'location_dest_id': customer_loc_id})#move to customer location |
2890 | + |
2891 | + status=move_obj.action_confirm(cr,uid,[finished_move_stock_id,move2_id]) |
2892 | + |
2893 | + move_obj.action_done(cr,uid,[finished_move_stock_id,move2_id]) |
2894 | + return res |
2895 | + |
2896 | + def action_confirm(self, cr, uid, ids, context=None): |
2897 | + res=super(stock_picking,self).action_confirm(cr, uid, ids, context) |
2898 | + cr.commit() |
2899 | + try: |
2900 | + self.action_assign(cr, uid, ids) |
2901 | + except Exception, e: |
2902 | + print e |
2903 | + return True |
2904 | + _defaults = { |
2905 | + 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'), |
2906 | + } |
2907 | + |
2908 | + |
2909 | +stock_picking() |
2910 | + |
2911 | + |
2912 | + |
2913 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
2914 | + |
2915 | |
2916 | === added file 'assembly_bom/stock_view.xml' |
2917 | --- assembly_bom/stock_view.xml 1970-01-01 00:00:00 +0000 |
2918 | +++ assembly_bom/stock_view.xml 2011-10-06 15:31:48 +0000 |
2919 | @@ -0,0 +1,100 @@ |
2920 | +<?xml version="1.0" encoding="utf-8"?> |
2921 | +<openerp> |
2922 | + <data> |
2923 | + |
2924 | + |
2925 | + <record id="view_picking_out_form_inherit" model="ir.ui.view"> |
2926 | + <field name="name">stock.picking.out.form.inherit</field> |
2927 | + <field name="model">stock.picking</field> |
2928 | + <field name="type">form</field> |
2929 | + <field name="inherit_id" ref="stock.view_picking_out_form" /> |
2930 | + <field name="arch" type="xml"> |
2931 | + <xpath expr="//field/form/group/field[@name='product_id']" position="replace"> |
2932 | + <field name="product_id" on_change="onchange_product_id(product_id,location_id,location_dest_id, parent.address_id, product_qty)" colspan="4"/> |
2933 | + </xpath> |
2934 | + <xpath expr="//form/group/field[@name='product_qty']" position="replace"> |
2935 | + <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)" colspan="3" /> |
2936 | + </xpath> |
2937 | + <xpath expr="//tree/field[@name='product_qty']" position="replace"> |
2938 | + <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)" /> |
2939 | + </xpath> |
2940 | + </field> |
2941 | + </record> |
2942 | + |
2943 | + |
2944 | + <record id="view_picking_form_inherit" model="ir.ui.view"> |
2945 | + <field name="name">stock.picking.forminherit</field> |
2946 | + <field name="model">stock.picking</field> |
2947 | + <field name="type">form</field> |
2948 | + <field name="inherit_id" ref="stock.view_picking_form" /> |
2949 | + <field name="arch" type="xml"> |
2950 | + <xpath expr="//field/form/group/field[@name='product_id']" position="replace"> |
2951 | + <field name="product_id" on_change="onchange_product_id(product_id,location_id,location_dest_id, parent.address_id, product_qty)" colspan="4"/> |
2952 | + </xpath> |
2953 | + <xpath expr="//form/group/field[@name='product_qty']" position="replace"> |
2954 | + <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)" colspan="3" /> |
2955 | + </xpath> |
2956 | + <xpath expr="//tree/field[@name='product_qty']" position="replace"> |
2957 | + <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)" /> |
2958 | + </xpath> |
2959 | + </field> |
2960 | + </record> |
2961 | + |
2962 | + <record id="view_move_form_inherit22" model="ir.ui.view"> |
2963 | + <field name="name">stock.move.form.inherit</field> |
2964 | + <field name="model">stock.move</field> |
2965 | + <field name="type">form</field> |
2966 | + <field eval="4" name="priority"/> |
2967 | + <field name="inherit_id" ref="stock.view_move_form" /> |
2968 | + <field name="arch" type="xml"> |
2969 | + <data> |
2970 | + <xpath expr="//field[@name='prodlot_id']" position="after"> |
2971 | + <field name="sale_id" readonly="1" select="1" /> |
2972 | + </xpath> |
2973 | + <xpath expr="//field[@name='product_id']" position="replace"> |
2974 | + <field name="product_id" on_change="onchange_product_id(product_id,location_id,location_dest_id, False, product_qty)"/> |
2975 | + </xpath> |
2976 | + <xpath expr="//field[@name='product_qty']" position="replace"> |
2977 | + <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)"/> |
2978 | + </xpath> |
2979 | + |
2980 | + </data> |
2981 | + </field> |
2982 | + </record> |
2983 | + |
2984 | + |
2985 | + <record id="view_move_tree_inherit22" model="ir.ui.view"> |
2986 | + <field name="name">stock.move.tree_inherit</field> |
2987 | + <field name="model">stock.move</field> |
2988 | + <field name="type">tree</field> |
2989 | + <field eval="6" name="priority"/> |
2990 | + <field name="inherit_id" ref="stock.view_move_tree" /> |
2991 | + <field name="arch" type="xml"> |
2992 | + <data> |
2993 | + <xpath expr="//field[@name='origin']" position="after"> |
2994 | + <field name="sale_id" readonly="1"/> |
2995 | + </xpath> |
2996 | + </data> |
2997 | + </field> |
2998 | + </record> |
2999 | + |
3000 | + <record id="view_move_search_inherit22" model="ir.ui.view"> |
3001 | + <field name="name">stock.move.search_inherit</field> |
3002 | + <field name="model">stock.move</field> |
3003 | + <field name="type">search</field> |
3004 | + <field eval="3" name="priority"/> |
3005 | + <field name="inherit_id" ref="stock.view_move_search" /> |
3006 | + <field name="arch" type="xml"> |
3007 | + <data> |
3008 | + <xpath expr="//field[@name='origin']" position="after"> |
3009 | + <field name="sale_id" /> |
3010 | + </xpath> |
3011 | + </data> |
3012 | + </field> |
3013 | + </record> |
3014 | + |
3015 | + |
3016 | + |
3017 | + |
3018 | + </data> |
3019 | +</openerp> |
3020 | |
3021 | === added directory 'assembly_bom/wizard' |
3022 | === added file 'assembly_bom/wizard/__init__.py' |
3023 | --- assembly_bom/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
3024 | +++ assembly_bom/wizard/__init__.py 2011-10-06 15:31:48 +0000 |
3025 | @@ -0,0 +1,24 @@ |
3026 | +# -*- coding: utf-8 -*- |
3027 | +############################################################################## |
3028 | +# |
3029 | +# OpenERP, Open Source Management Solution |
3030 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
3031 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
3032 | +# |
3033 | +# This program is free software: you can redistribute it and/or modify |
3034 | +# it under the terms of the GNU General Public License as published by |
3035 | +# the Free Software Foundation, either version 3 of the License, or |
3036 | +# (at your option) any later version. |
3037 | +# |
3038 | +# This program is distributed in the hope that it will be useful, |
3039 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3040 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3041 | +# GNU General Public License for more details. |
3042 | +# |
3043 | +# You should have received a copy of the GNU General Public License |
3044 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
3045 | +# |
3046 | +############################################################################## |
3047 | + |
3048 | +import consumption_report_wizard |
3049 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
3050 | \ No newline at end of file |
3051 | |
3052 | === added file 'assembly_bom/wizard/consumption_report_wizard.py' |
3053 | --- assembly_bom/wizard/consumption_report_wizard.py 1970-01-01 00:00:00 +0000 |
3054 | +++ assembly_bom/wizard/consumption_report_wizard.py 2011-10-06 15:31:48 +0000 |
3055 | @@ -0,0 +1,93 @@ |
3056 | +# -*- encoding: utf-8 -*- |
3057 | +############################################################################## |
3058 | +# |
3059 | +# OpenERP, Open Source Management Solution |
3060 | +# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>) |
3061 | +# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>) |
3062 | +# |
3063 | +# This program is free software: you can redistribute it and/or modify |
3064 | +# it under the terms of the GNU General Public License as published by |
3065 | +# the Free Software Foundation, either version 3 of the License, or |
3066 | +# (at your option) any later version. |
3067 | +# |
3068 | +# This program is distributed in the hope that it will be useful, |
3069 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
3070 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3071 | +# GNU General Public License for more details. |
3072 | +# |
3073 | +# You should have received a copy of the GNU General Public License |
3074 | +# along with this program. If not, see <http://www.gnu.org/licenses/> |
3075 | +# |
3076 | +############################################################################## |
3077 | +import wizard |
3078 | +import pooler |
3079 | +from osv import osv,fields |
3080 | +import tools |
3081 | +from tools.translate import _ |
3082 | + |
3083 | +class consumption_report_wizard(osv.osv_memory): |
3084 | + |
3085 | + def print_consumption_report(self,cr,uid,ids,context={}): |
3086 | + """ Updates the context with the details given in the wizard form |
3087 | + @param self: The object pointer. |
3088 | + @param ids: ids of the procurement order document |
3089 | + @param context: standard dictionary |
3090 | + @comment: The data for stock move analysis is passed through context |
3091 | + @return: returns standard dictionary to make report |
3092 | + """ |
3093 | + data = self.read(cr, uid, ids[0]) |
3094 | + warehouse_id=data and data.get('warehouse_id',False) or False |
3095 | + start_date=data and data.get('start_date',False) or False |
3096 | + end_date=data and data.get('end_date',False) or False |
3097 | + warehouse=self.pool.get('stock.warehouse').browse(cr,uid,warehouse_id) |
3098 | + product_ids=context.get('active_ids',[]) |
3099 | + source_loc_id=warehouse.lot_stock_id and warehouse.lot_stock_id.id or False |
3100 | + return { |
3101 | + 'type': 'ir.actions.report.xml', |
3102 | + 'report_name':"product.consumption", |
3103 | + 'datas': { |
3104 | + 'model':'product.product', |
3105 | + 'id': product_ids and product_ids[0] or False, |
3106 | + 'ids': product_ids and product_ids or [], |
3107 | + 'report_type': 'pdf', |
3108 | + }, |
3109 | + 'nodestroy': False, |
3110 | + 'context':{ |
3111 | + "source_loc_id":source_loc_id, |
3112 | + "start_date":start_date, |
3113 | + "end_date":end_date |
3114 | + }, |
3115 | + |
3116 | + } |
3117 | + |
3118 | + _name="product.consumption" |
3119 | + _columns={ |
3120 | + 'warehouse_id':fields.many2one('stock.warehouse','Select Your Warehouse'), |
3121 | + 'start_date':fields.date("Start Date"), |
3122 | + 'end_date':fields.date("End Date") |
3123 | + |
3124 | + } |
3125 | + |
3126 | + |
3127 | + def _get_warehouse(self, cr, uid, context=None): |
3128 | + """ Fetches the default warehouse |
3129 | + @param self: The object pointer. |
3130 | + @param ids: ids of the procurement order document |
3131 | + @param context: standard dictionary |
3132 | + @comment: Pre-fills the warehouse field by the ware house related to user company |
3133 | + @return: returns standard dictionary to make report |
3134 | + """ |
3135 | + cmpny_id = self.pool.get('res.users')._get_company(cr, uid, context=context) |
3136 | + shop = self.pool.get('sale.shop').search(cr, uid, [('company_id', '=', cmpny_id)]) |
3137 | + if shop: |
3138 | + shop_obj = self.pool.get('sale.shop').browse(cr, uid, shop[0], context=context) |
3139 | + return shop_obj.warehouse_id and shop_obj.warehouse_id.id |
3140 | + return False |
3141 | + |
3142 | + _defaults = { |
3143 | + 'warehouse_id': _get_warehouse, |
3144 | + } |
3145 | + |
3146 | +consumption_report_wizard() |
3147 | + |
3148 | + |
3149 | |
3150 | === added file 'assembly_bom/wizard/consumption_report_wizard.xml' |
3151 | --- assembly_bom/wizard/consumption_report_wizard.xml 1970-01-01 00:00:00 +0000 |
3152 | +++ assembly_bom/wizard/consumption_report_wizard.xml 2011-10-06 15:31:48 +0000 |
3153 | @@ -0,0 +1,43 @@ |
3154 | +<?xml version="1.0" encoding="utf-8"?> |
3155 | +<openerp> |
3156 | + <data> |
3157 | + |
3158 | + <!-- Make Procurement --> |
3159 | + |
3160 | + <record id="view_product_consumption_id" model="ir.ui.view"> |
3161 | + <field name="name">Product Consumption</field> |
3162 | + <field name="model">product.consumption</field> |
3163 | + <field name="type">form</field> |
3164 | + <field name="arch" type="xml"> |
3165 | + <form string="Product Consumption"> |
3166 | + <field name="warehouse_id" colspan="4" required="1"/> |
3167 | + <newline/> |
3168 | + <field name="start_date" colspan="2"/> |
3169 | + <field name="end_date" colspan="2" /> |
3170 | + <button type="object" name="print_consumption_report" icon="gtk-print" string="Print"/> |
3171 | + <button special="cancel" icon="gtk-cancel" string="Cancel"/> |
3172 | + </form> |
3173 | + </field> |
3174 | + </record> |
3175 | + |
3176 | + |
3177 | + |
3178 | + <act_window name="Product Consumption" |
3179 | + res_model="product.consumption" |
3180 | + src_model="product.product" |
3181 | + view_mode="form" |
3182 | + target="new" |
3183 | + key2="client_print_multi" |
3184 | + id="act_product_consumption_id" |
3185 | + /> |
3186 | + |
3187 | + |
3188 | + <!--wizard |
3189 | + string="Consumption Report xxx" |
3190 | + model="product.product" |
3191 | + name="product.consumption.wiz" |
3192 | + keyword="client_print_multi" |
3193 | + id="product_consumption_wizard_id"/--> |
3194 | + |
3195 | + </data> |
3196 | +</openerp> |
3197 | \ No newline at end of file |
s/ecoding/ encoding/ g