Merge lp:~npg-team/openobject-addons/assembly_bom_npg into lp:openobject-addons

Proposed by Novapoint Group
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
Reviewer Review Type Date Requested Status
Olivier Dony (Odoo) policy + quick technical scan Disapprove
Review via email: mp+78433@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
Fabien (Open ERP) (fp-tinyerp) wrote :

s/ecoding/encoding/g

Revision history for this message
Fabien (Open ERP) (fp-tinyerp) wrote :

We think it's better to implement this in a community module.

Revision history for this message
Fabien (Open ERP) (fp-tinyerp) wrote :

it's not normal to add a reporting engine in this module.

Revision history for this message
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,

Revision history for this message
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://bit.ly/openerp-contrib-mp

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!

review: Disapprove (policy + quick technical scan)

Unmerged revisions

5304. By Novapoint Group

[Add]: assembly_bom module to provide true assembly sales support to OpenERP

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'assembly_bom'
=== added file 'assembly_bom/__init__.py'
--- assembly_bom/__init__.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/__init__.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,30 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23import mrp
24import report
25import wizard
26import product
27import procurement
28import stock
29import sale
30# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0\ No newline at end of file31\ No newline at end of file
132
=== added file 'assembly_bom/__openerp__.py'
--- assembly_bom/__openerp__.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/__openerp__.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,53 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23{
24 "name" : "Assembly BoM",
25 "version" : "0.22",
26 "author" : 'NovaPoint Group LLC',
27 "description": """
28 Adds a new catagory for the BOM as 'assembly bom'
29 """,
30 "category" : "Customization",
31 "website" : "http://www.novapointgroup.com/",
32 "depends" : [
33 'base',
34 'mrp',
35 'sale',
36 'stock',
37 ],
38 "init_xml" : [],
39
40 "demo_xml" : [],
41
42 "update_xml" : [
43 'report/report_view.xml',
44 'wizard/consumption_report_wizard.xml',
45 'stock_view.xml',
46 'product_view.xml',
47 ],
48 "test" : [],
49 "active": False,
50 "installable": True,
51 }
52
53# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0\ No newline at end of file54\ No newline at end of file
155
=== added file 'assembly_bom/change_log.txt'
--- assembly_bom/change_log.txt 1970-01-01 00:00:00 +0000
+++ assembly_bom/change_log.txt 2011-10-06 15:31:48 +0000
@@ -0,0 +1,85 @@
1Version 0.22 by Janeesh (22 Sept 2011)
2 * Updation of Weights and price of products of all Bom types
3
4Version 0.21 by Vinod (16 Sept 2011)
5 * 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.
6Version 0.20 by Vinod (15 Sept 2011)
7 * Customized the product view to include the BOM Stock.
8
9Version 0.19 by Jabir (18 July 2011)
10 * Removed location filtering according to available products
11
12Version 0.18 by Arif (5 July 2011)
13 * Update method on bom
14
15Version 0.16 > 0.17
16 * Display warning on no stock available for product with normal bom and make to order
17
18Version 0.15 > 0.16
19 * Display warning on no stock available according to the location selected
20
21Version 0.14 > 0.15
22 * Fixed the issue with product onchange function on sale order line
23 * Add filtering of stock location according to stock availability on delivery order line
24Version 0.13 > 0.14
25 * Done stock checking for assembly bom product
26 * Fixed the default date issue for stock move and stock picking
27Version 0.12 > 0.13
28 * Filter Source Location in Stock Moves
29 * Show pop-up alertif there is no stock available in stock move
30
31Version 0.11 > 0.12
32 * Call action_assign for all moves
33
34Version 0.10 > 0.11
35 * commenting
36Version 0.09 > 0.10
37 * Added the reference in the report
38 * cleared the issue with the extra move
39 * Added the sale id for the move with sale order of a product with normal BOM
40 * Added the from and to dates in the report
41 * cleared issue with the updation of the shipped (Delivered) field in Sale order Form
42
43Version 0.08 > 0.09
44 * Added the _product_qty function in the product object to correct bom stock value
45
46Version 0.07 > 0.08
47 * Added Sale Order Ref in stock move
48
49Version 0.06 > 0.07
50 * Added date fields in the wizard for consumption report
51 * Made modifications in the find consumption details method
52 * Added one more column in the consumption details report
53 * Modified the find consumption details method in product accordingly
54
55Version 0.05 > 0.06
56 * modified the method 'action_produce_assign_product' in procurement.order object
57 to remove the duplication of production order while the procurement is tried to run from the sale order
58 with a product with assembly bom
59
60 * Added new py files procurement and product and stock to neatly handle the objects
61
62Version 0.04 > 0.05
63 * Removed unwanted lines from files and modified the consumption report to be working with multiple documents
64 * and showing a no consumption details message in the report if the product is no longer consumed
65
66Version 0.03 > 0.04 by Sinoj
67 * Added the defaults value for ware house in the product consumption wizard
68
69Version 0.02 > 0.03 by Vijayakanth
70 * Added stock moves to suffice the proper updation of stock ie a move from production to stock then to output and then to
71 customer location and modified the assembly order destination location id so as to move the finished products to stock
72
73 * Added field parent_bom_id in the move object to support multiple lines in sale order (detailed check pending)
74
75Version 0.01 > 0.02 by Vijayakanth
76 * Added a wizard and report to the assembly bom module
77 * Added one more field production ids in stock move table to make it easy
78 for getting the relation ship with production
79 * Added the kit_id field in the move object to store assembly process id (production object)
80 * This is solely for the assembly bom
81
82 * phantom bom subproducts are sold separately and stock move occures to customer location
83 * assembly bom subroducts are moved to production and tracked using kit_id and finshed goods to customers
84 * Normal bom subproduct move occures when procurement operation completes and its also tracked using production_ids field
85
086
=== added file 'assembly_bom/mrp.py'
--- assembly_bom/mrp.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/mrp.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,98 @@
1# -*- ecoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23from osv import fields, osv
24import netsvc
25import datetime
26import time
27
28class bom(osv.osv):
29
30 def _update_product_weight(self, cr, uid, bom_obj, context=None):
31 weight = 0.00
32 weight_net = 0.00
33 standard_price = 0.00
34 if not context:
35 context = {}
36 child_ids = self.search(cr, uid, [('bom_id', 'child_of', [bom_obj.id])], context=context)
37 if child_ids and bom_obj.id in child_ids:
38 child_ids.remove(bom_obj.id)
39 if len(child_ids) == 0:
40 weight = bom_obj.product_id.weight * bom_obj.product_qty
41 weight_net = bom_obj.product_id.weight_net * bom_obj.product_qty
42 standard_price = bom_obj.product_id.standard_price * bom_obj.product_qty
43 else:
44 for bom_child in self.browse(cr, uid, child_ids, context=context):
45 res = self._update_product_weight(cr, uid, bom_child, context=context)
46 weight += res[0]
47 weight_net += res[1]
48 standard_price += res[2]
49 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))
50# self.write(cr, uid, bom_obj.product_id.id, {'weight' : weight, 'weight_net' : weight_net, 'standard_price' : standard_price}, context=context)
51 return (weight, weight_net, standard_price)
52
53 def write(self, cr, uid, ids, vals, context=None):
54
55 result = super(bom, self).write(cr, uid, ids, vals, context=context)
56 if result:
57 for bom_obj in self.browse(cr,uid,ids,context={}):
58 res = self._update_product_weight(cr,uid,bom_obj,context)
59# 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))
60 return result
61
62 def create(self, cr, uid, vals, context=None):
63 result = super(bom, self).create(cr, uid, vals, context)
64 bom_obj = self.browse(cr,uid,result,context={})
65 res = self._update_product_weight(cr,uid,bom_obj,context)
66 return result
67 def _compute_type(self, cr, uid, ids, field_name, arg, context=None):
68 print """ Sets particular method for the selected bom type.
69 @param field_name: Name of the field
70 @param arg: User defined argument
71 @return: Dictionary of values
72 """
73 res = dict(map(lambda x: (x,''), ids))
74 for line in self.browse(cr, uid, ids, context=context):
75 if line.type in ('phantom','assembly') and not line.bom_id:
76 res[line.id] = 'set'
77 continue
78 if line.bom_lines or line.type == 'phantom':
79 continue
80 if line.product_id.supply_method == 'produce':
81 if line.product_id.procure_method == 'make_to_stock':
82 res[line.id] = 'stock'
83 else:
84 res[line.id] = 'order'
85 return res
86
87
88
89 _inherit='mrp.bom'
90 _columns={
91 'method': fields.function(_compute_type, string='Method', method=True, type='selection', selection=[('',''),('stock','On Stock'),('order','On Order'),('set','Set / Pack')]),
92 'type': fields.selection([('normal','Normal BoM'),('phantom','Sets / Phantom'),('assembly','Assembly BoM')], 'BoM Type', required=True,
93 help= "If a sub-product is used in several products, it can be useful to create its own BoM. "\
94 "Though if you don't want separated production orders for this sub-product, select Set/Phantom as BoM type. "\
95 "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."),
96 }
97bom()
98
099
=== added file 'assembly_bom/procurement.py'
--- assembly_bom/procurement.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/procurement.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,60 @@
1# -*- ecoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23from osv import fields, osv
24import netsvc
25import datetime
26import time
27
28class procurement(osv.osv):
29 _inherit="procurement.order"
30
31 def action_produce_assign_product(self, cr, uid, ids, context=None):
32 """ Blocks the procurement being run for products with assembly bom
33 @param self: The object pointer.
34 @param ids: ids of the procurement order document
35 @param context: standard dictionary
36 @comment: Blocks the procurement to be run for products with assembly bom
37 @return: returns either the Manufacturing order id or 0
38 """
39 procurement_obj = self.pool.get('procurement.order')
40 bom_obj=self.pool.get('mrp.bom')
41 sale_line_obj=self.pool.get('sale.order.line')
42 res=[]
43 for procure_record in procurement_obj.browse(cr,uid,ids,context=context):
44 sale_line_ids=sale_line_obj.search(cr,uid,[('procurement_id','=',procure_record.id)],context=context)
45 sale_line_id=sale_line_ids and sale_line_ids[0] or False
46 if sale_line_id:
47 line=sale_line_obj.browse(cr,uid,sale_line_id,context=context)
48 if line.product_id:
49 bom_ids=bom_obj.search(cr,uid,[('product_id','=',line.product_id.id),('type','=','assembly')],context={})
50 bom_id=bom_ids and bom_ids[0] or False
51 if bom_id:
52 #1. print 'PROCUREMENT:"PROCUREMENT FOR THE PRODUCT:%s, Name:%s" HAS BEEN BLOCKED'%(line.product_id.id,line.product_id.name)
53 return 0
54 return super(procurement, self).action_produce_assign_product( cr, uid, [procure_record.id], context=context)
55
56procurement()
57
58# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
59
60
061
=== added file 'assembly_bom/product.py'
--- assembly_bom/product.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/product.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,242 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21
22from osv import fields, osv
23import netsvc
24import datetime
25import time
26
27class product_inherit(osv.osv):
28
29 _inherit = 'product.product'
30
31 def _product_available(self, cr, uid, ids, field_names=None, arg=False, context=None):
32 """
33 For showing the bom stock value as 0 for the products with no bom
34 @param self: The object pointer.
35 @param ids: ids of the procurement order document
36 @param context: standard dictionary
37 @comment: If 'bom_stock' is there in the field_names list then if the product is having not bom the bom stock value was
38 shown as real stock value. This override modifies it to zero
39 @return: returns 0 for the above conditions in the standard format dictionary for multi function fields
40 """
41 res = super(product_inherit, self)._product_available(cr, uid, ids, field_names, arg, context=context)
42 bom_obj=self.pool.get('mrp.bom')
43 if 'bom_stock' in field_names:
44 for product_id, stock_qty in res.iteritems():
45 product = self.browse(cr, uid, product_id)
46 bom_ids = bom_obj._bom_find(cr, uid, product.id, product.uom_id.id, properties=[])
47 if not bom_ids:
48 res[product_id]['bom_stock'] = 0
49 #1. If possible do this by adding this line at 102 c2c_bom_stock.py this is the reason why its not showing the
50 #stock value properly for the products with no boms
51
52 return res
53
54
55 def find_consumption_details(self,cr,uid,ids,context={}):
56 """
57 Finds the consumption details for the products with ids in 'ids'
58 @param self: The object pointer.
59 @param ids: ids of the procurement order document
60 @param context: standard dictionary
61 @return: returns a list of dictionaries that carries the information regarding the product consumption
62 """
63 move_obj=self.pool.get('stock.move')
64 product_ids=ids
65 source_loc_id=context.get("source_loc_id",False)
66 start_date=context.get("start_date",False)
67 end_date=context.get("end_date",False)
68 if source_loc_id :
69 for product_id in product_ids:
70 detail_list=[]
71 args=[('product_id',"=",product_id),
72 ('location_id','=',source_loc_id),
73 ('state','=','done')]
74 start_date and args.append(('date',">=",start_date+" 00:00:00"))
75 end_date and args.append(('date',"<=",end_date+" 00:00:00"))
76 move_ids=move_obj.search(cr,uid,args)
77 detail_list=[]
78 for move in move_obj.browse(cr,uid,move_ids):
79 details={}
80
81 #1. If move is having sale_line_id its assumed to be related with sale
82 if move.sale_line_id:
83 line=move.sale_line_id
84 product_qty=move.product_qty
85 parent_product=move.product_id
86 details={
87 'product_name':parent_product.name or "",
88 'reference':parent_product.default_code or "",
89 'type':'sale',
90 "product_qty":product_qty,
91 'consumption':parent_product.name
92 }
93
94 #2. If move is having production_ids its assumed to be related with production using normal bom
95 if move.production_ids:
96 production=move.production_ids[0]
97 bom=production.bom_id and production.bom_id or False
98 if bom:
99 bom_type=bom.type
100 if bom_type=='normal':
101 parent_product=production.product_id
102 product_name=parent_product.name
103 details={
104 'bom_type':bom_type,
105 "product_name":product_name,
106 "product_qty":move.product_qty,
107 "parent_product":parent_product,
108 'type':'production',
109 'consumption':product_name+'- '+bom_type,
110 'bom_type':bom_type,
111 'reference':parent_product.default_code or ""
112
113 }
114 #3. If move is having kit_id its assumed to be related with production using assembly bom
115 if move.kit_id:
116 production=move.kit_id
117 if production.state=='done':
118 parent_product=production.product_id
119 bom=production.bom_id and production.bom_id or False
120 if bom:
121 bom_type=bom.type
122 if bom_type=='assembly':
123 product_name=parent_product.name
124 product_qty=move.product_qty
125 details={
126 'bom_type':bom_type,
127 "product_name":product_name,
128 "product_qty":move.product_qty,
129 "parent_product":parent_product,
130 'type':'production',
131 'consumption':product_name+'- '+bom_type,
132 'bom_type':bom_type,
133 'reference':parent_product.default_code or ""
134 }
135
136 details and detail_list.append(details)
137 details={}
138 consumpt_lines=[]
139 res={}
140 #4. This block analyses the details to aggregate them with reference to type of consumption
141
142 for detail in detail_list:
143 product_name=detail.get('product_name')
144 consumption=detail.get('consumption')
145
146 if detail.get('type',False) and detail.get('type',False)=='sale':
147 if res.has_key(consumption):
148 new_qty=res.get(consumption,{}).get('product_qty',0)+detail.get('product_qty',0)
149 res[consumption].update({
150 'product_qty':new_qty,
151 'product_name':product_name
152 }
153 )
154 else:
155 res[consumption]={
156 'product_qty':detail.get('product_qty',0),
157 'consumption':"%(product_name)s- sold separately"%detail,
158 'product_name':product_name,
159 'bom_type':detail.get('bom_type',' '),
160 'type':'Sold separately',
161 'reference':detail.get("reference","")
162 }
163 if detail.get('type',False) and detail.get('type',False)=='production':
164
165 if res.has_key(consumption):
166 new_qty=res.get(consumption,{}).get('product_qty',0)+detail.get('product_qty',0)
167 res[consumption].update({
168 'product_qty':new_qty,
169 }
170 )
171 else:
172 res[consumption]={
173 'product_qty':detail.get('product_qty',0),
174 'consumption':consumption,
175 'product_name':product_name,
176 'bom_type':detail.get('bom_type',' '),
177 'type':'Production using: '+detail.get('bom_type',' ')+' BOM',
178 'reference':detail.get("reference","")
179 }
180
181
182 consumpt_lines=res.values()
183 total_qty=0
184 #5. Calculating percentage consumption
185 for line in consumpt_lines:
186 total_qty+=line.get('product_qty',0)
187 total_qty=float(total_qty)
188 new_consumpt_lines=[]
189 for line in consumpt_lines:
190 line.update({
191 'percentage':round(line.get('product_qty',0)*100/total_qty, 2)
192 })
193 new_consumpt_lines.append(line)
194 consumpt_lines=new_consumpt_lines
195
196 if not consumpt_lines:
197 consumpt_lines=False
198
199 ret={"source_loc_id":source_loc_id,'detail_list':consumpt_lines}
200
201 return ret
202 else:
203 return {}
204 _columns = {
205 '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'),
206 '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'),
207 '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'),
208 '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'),
209 }
210
211 def _get_root_bom(self, cr, uid, bom_obj, context=None):
212 if not context:
213 context = {}
214 if not bom_obj.bom_id:
215# if bom_obj.type == 'assembly':
216 return bom_obj
217 else:
218 return self._get_root_bom(cr, uid, bom_obj.bom_id, context=context)
219
220 return False
221
222
223 def write(self, cr, uid, ids, vals, context=None):
224 if not context:
225 context = {}
226 res = super(product_inherit, self).write(cr, uid, ids, vals, context=context)
227
228 if res and (vals.get('weight', False) or vals.get('weight_net', False) or vals.get('standard_price', False)):
229 updated_boms = []
230 mrp_bom_pool = self.pool.get('mrp.bom')
231 for prod in self.browse(cr, uid, ids, context=context):
232 bom_ids = mrp_bom_pool.search(cr, uid, [('product_id', '=', prod.id)], context=context)
233 for bom_obj in mrp_bom_pool.browse(cr, uid, bom_ids, context=context):
234 root_bom = self._get_root_bom(cr, uid, bom_obj, context=context)
235 if root_bom and root_bom not in updated_boms:
236 updated_boms.append(root_bom)
237 res = mrp_bom_pool._update_product_weight(cr, uid, root_bom, context=context)
238 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))
239# self.write(cr, uid, root_bom.product_id.id, {'weight' : res[0], 'weight_net' : res[1], 'standard_price' : res[2]}, context=context)
240 return res
241
242product_inherit()
0\ No newline at end of file243\ No newline at end of file
1244
=== added file 'assembly_bom/product_view.xml'
--- assembly_bom/product_view.xml 1970-01-01 00:00:00 +0000
+++ assembly_bom/product_view.xml 2011-10-06 15:31:48 +0000
@@ -0,0 +1,18 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <record id="product_product_tree_view_inherit" model="ir.ui.view">
5 <field name="name">product.product.tree.inherit</field>
6 <field name="model">product.product</field>
7 <field name="type">tree</field>
8 <field name="inherit_id" ref="product.product_product_tree_view"/>
9 <field eval="22" name="priority"/>
10 <field name="arch" type="xml">
11 <xpath expr="//field[@name='virtual_available']" position="after">
12 <field name="bom_stock"/>
13 </xpath>
14 </field>
15 </record>
16
17 </data>
18</openerp>
019
=== added directory 'assembly_bom/report'
=== added file 'assembly_bom/report/__init__.py'
--- assembly_bom/report/__init__.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/report/__init__.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,24 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22import consumption_report
23
24# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0\ No newline at end of file25\ No newline at end of file
126
=== added file 'assembly_bom/report/consumption_report.py'
--- assembly_bom/report/consumption_report.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/report/consumption_report.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,87 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22import time
23
24from report import report_sxw
25
26class consumption_report(report_sxw.rml_parse):
27 def _get_consumption_lines(self,product_id):
28
29 """ Finds the consumption details for the product
30 @param self: The object pointer.
31 @param product_id: ID of the product
32 @comment: fetches the consumption details of the product using 'find_consumption_details'
33 which analyses stock moves to find consumption details
34 @return: List of dictionaries showing the consumption details
35 """
36 res=[]
37 detail_list=self.localcontext.get('detail_list',[])
38 cr=self.cr;uid=self.uid
39 details=self.pool.get("product.product").find_consumption_details(cr,uid,[product_id],context=self.localcontext)
40 detail_list=details.get('detail_list',[])
41 return detail_list
42
43 def _get_us_date(self,date_string):
44 """ Converts the input date string to us format
45 @param self: The object pointer.
46 @param date_string: Expects date in ISO format YYYY-MM-DD
47 @comment: uses format_lang method to convert the date to the us format
48 @return: Returns either the us format date or an empty string
49 """
50 us_string=''
51 if date_string:
52 us_string=self.formatLang(date_string,date=True)
53 return us_string
54
55 def _format_product_name(self,product_name,reference):
56 """ Adds the product name and reference
57 @param self: The object pointer.
58 @param product_name: name of the product
59 @param reference: Reference of the product
60 @comment: adds the the reference and the product name if there is a reference string
61 @return: returns '[reference] product_name' or 'product_name'
62 """
63 if reference:
64 reference="[%s] "%reference
65 else:
66 reference=""
67 return reference+product_name
68
69 def __init__(self, cr, uid, name, context=None):
70 """ Parser __init__ override
71 """
72 super(consumption_report, self).__init__(cr, uid, name, context=context)
73 self.localcontext.update({
74 'time': time,
75 '_get_consumption_lines':self._get_consumption_lines,
76 '_get_':self._get_consumption_lines,
77 '_get_us_date':self._get_us_date,
78 '_format_product_name':self._format_product_name,
79 'source_loc_id':context.get('source_loc_id', False),#1. location id selected for getting consumption details in the wizard
80 'start_date':context.get('start_date',False),#2. getting start date selected in the wizard
81 'end_date':context.get('end_date',False),#3. getting end date selected in the wizard
82 })
83
84report_sxw.report_sxw('report.product.consumption', 'product.product', 'addons/assembly_bom/report/consumption_report.rml', parser=consumption_report, header=False)
85
86# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
87
088
=== added file 'assembly_bom/report/consumption_report.rml'
--- assembly_bom/report/consumption_report.rml 1970-01-01 00:00:00 +0000
+++ assembly_bom/report/consumption_report.rml 2011-10-06 15:31:48 +0000
@@ -0,0 +1,119 @@
1<?xml version="1.0"?>
2<document filename="test.pdf">
3 <template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20">
4 <pageTemplate id="first">
5 <frame id="first" x1="57.0" y1="57.0" width="481" height="728"/>
6 </pageTemplate>
7 </template>
8 <stylesheet>
9 <blockTableStyle id="Standard_Outline">
10 <blockAlignment value="LEFT"/>
11 <blockValign value="TOP"/>
12 </blockTableStyle>
13 <blockTableStyle id="Table1">
14 <blockAlignment value="LEFT"/>
15 <blockValign value="TOP"/>
16 </blockTableStyle>
17 <blockTableStyle id="Table2">
18 <blockAlignment value="LEFT"/>
19 <blockValign value="TOP"/>
20 </blockTableStyle>
21 <blockTableStyle id="Table3">
22 <blockAlignment value="LEFT"/>
23 <blockValign value="TOP"/>
24 </blockTableStyle>
25 <blockTableStyle id="Table4">
26 <blockAlignment value="LEFT"/>
27 <blockValign value="TOP"/>
28 </blockTableStyle>
29 <initialize>
30 <paraStyle name="all" alignment="justify"/>
31 </initialize>
32 <paraStyle name="P1" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/>
33 <paraStyle name="P2" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="CENTER" spaceBefore="12.0" spaceAfter="6.0"/>
34 <paraStyle name="P3" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/>
35 <paraStyle name="P4" fontName="Times-Roman" fontSize="12.0" leading="15" alignment="CENTER" spaceBefore="0.0" spaceAfter="6.0"/>
36 <paraStyle name="P5" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
37 <paraStyle name="P6" fontName="Helvetica" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
38 <paraStyle name="P7" fontName="Helvetica" fontSize="10.0" leading="13" alignment="CENTER"/>
39 <paraStyle name="P8" fontName="Times-Roman" fontSize="12.0" leading="15" alignment="CENTER"/>
40 <paraStyle name="P9" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/>
41 <paraStyle name="P10" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/>
42 <paraStyle name="Standard" fontName="Times-Roman"/>
43 <paraStyle name="Heading" fontName="Helvetica" fontSize="14.0" leading="17" spaceBefore="12.0" spaceAfter="6.0"/>
44 <paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
45 <paraStyle name="List" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
46 <paraStyle name="Caption" fontName="Times-Roman" fontSize="12.0" leading="15" spaceBefore="6.0" spaceAfter="6.0"/>
47 <paraStyle name="Index" fontName="Times-Roman"/>
48 <paraStyle name="Table Contents" fontName="Times-Roman"/>
49 <paraStyle name="terp_tblheader_General" fontName="Helvetica" fontSize="8.0" leading="10" spaceBefore="6.0" spaceAfter="6.0"/>
50 <paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
51 <paraStyle name="Table Heading" fontName="Times-Roman" alignment="CENTER"/>
52 <paraStyle name="terp_header" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="12.0" spaceAfter="6.0"/>
53 <paraStyle name="terp_default_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
54 <images/>
55 </stylesheet>
56 <story>
57 <para style="P2">Product Consumption Report</para>
58 <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>
59 <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>
60 <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>
61 <para style="P8">
62 <font color="white"> </font>
63 </para>
64 <blockTable colWidths="478.0" style="Table1">
65 <tr>
66 <td>
67 <para style="P1">[[repeatIn(objects,'o')]]</para>
68 <blockTable colWidths="473.0" style="Table2">
69 <tr>
70 <td>
71 <para style="P7">[[(_get_consumption_lines(o.id) and ' ') or removeParentNode('para')]]Product Name: <font face="Times-Roman">[[o.name]]</font></para>
72 </td>
73 </tr>
74 </blockTable>
75 <blockTable colWidths="142.0,142.0,95.0,95.0" repeatRows="1" style="Table3">
76 <tr>
77 <td>
78 <para style="P9">Product[[(_get_consumption_lines(o.id) and ' ') or removeParentNode('blockTable')]]</para>
79 </td>
80 <td>
81 <para style="P10">Consumption Type</para>
82 </td>
83 <td>
84 <para style="terp_tblheader_General_Centre">Quantity</para>
85 </td>
86 <td>
87 <para style="terp_tblheader_General_Centre">Percentage Consumption</para>
88 </td>
89 </tr>
90 </blockTable>
91 <blockTable colWidths="142.0,141.0,95.0,95.0" repeatRows="1" style="Table4">
92 <tr>
93 <td>
94 <para style="P5">[[repeatIn(_get_consumption_lines(o.id),'line')]] [[_format_product_name(line.get('product_name'),line.get('reference'))]]</para>
95 <para style="P5">[[(_get_consumption_lines(o.id) and ' ') or removeParentNode('blockTable')]]</para>
96 </td>
97 <td>
98 <para style="P5">[[line.get('type')]]</para>
99 </td>
100 <td>
101 <para style="P6">[[line.get('product_qty')]]</para>
102 </td>
103 <td>
104 <para style="P6">[[line.get('percentage')]]</para>
105 </td>
106 </tr>
107 </blockTable>
108 <para style="P3">
109 <font color="white"> </font>
110 </para>
111 </td>
112 </tr>
113 </blockTable>
114 <para style="P4">
115 <font color="white"> </font>
116 </para>
117 </story>
118</document>
119
0120
=== added file 'assembly_bom/report/consumption_report.sxw'
1Binary 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 differ121Binary 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
=== added file 'assembly_bom/report/consumption_report_reference+name.sxw'
2Binary 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 differ122Binary 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
=== added file 'assembly_bom/report/consumption_report_reference_column.sxw'
3Binary 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 differ123Binary 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
=== added file 'assembly_bom/report/delivery_report.py'
--- assembly_bom/report/delivery_report.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/report/delivery_report.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,70 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6#
7# This program is free software: you can redistribute it and/or modify
8# it under the terms of the GNU Affero General Public License as
9# published by the Free Software Foundation, either version 3 of the
10# License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Affero General Public License for more details.
16#
17# You should have received a copy of the GNU Affero General Public License
18# along with this program. If not, see <http://www.gnu.org/licenses/>.
19#
20##############################################################################
21
22import time
23
24from report import report_sxw
25
26class delivery_report(report_sxw.rml_parse):
27 def __init__(self, cr, uid, name, context=None):
28 super(delivery_report, self).__init__(cr, uid, name, context=context)
29 self.localcontext.update({
30 'time': time,
31# 'detail_list':context.get('detail_list', [])
32 '_get_parent':self._get_parent,
33 '_get_childs':self._get_childs
34 })
35
36 def _get_parent(self,pick_id):
37 cr=self.cr
38 uid=self.uid
39 context=self.localcontext
40 move_obj=self.pool.get('stock.move')
41 move_ids=move_obj.search(cr,uid,[('picking_id','=',pick_id),("parent_bom_id","!=",False)])
42 moves=move_obj.browse(cr,uid,move_ids,context=context)
43 for move in moves:
44 production=move.kit_id
45 if production:
46 product_qty=production.product_qty
47 sale_id=move.sale_id.id
48
49 parent_move_ids=move_obj.search(cr,uid,[("sale_id","=",sale_id),
50 ("product_qty","=",product_qty),
51 ("product_id","=",production.product_id.id)])
52 parent_moves=move_obj.browse(cr,uid,parent_move_ids)
53 print "parent_move_ids",parent_move_ids
54# return {'child_moves':moves,"parent_moves":parent_moves}
55 return parent_moves
56 break
57
58 def _get_childs(self,pick_id):
59 cr=self.cr
60 uid=self.uid
61 context=self.localcontext
62 move_obj=self.pool.get('stock.move')
63 move_ids=move_obj.search(cr,uid,[('picking_id','=',pick_id),("parent_bom_id","!=",False)])
64 print move_ids,'====================move_ids================================'
65 return move_obj.browse(cr,uid,move_ids,context=context)
66
67report_sxw.report_sxw('report.delivery.bom', 'stock.picking', 'addons/assembly_bom/report/delivery_report.rml', parser=delivery_report, header=False)
68
69# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
70
071
=== added file 'assembly_bom/report/delivery_report.rml'
--- assembly_bom/report/delivery_report.rml 1970-01-01 00:00:00 +0000
+++ assembly_bom/report/delivery_report.rml 2011-10-06 15:31:48 +0000
@@ -0,0 +1,384 @@
1<?xml version="1.0"?>
2<document filename="test.pdf">
3 <template pageSize="(595.0,842.0)" title="Test" author="Martin Simon" allowSplitting="20">
4 <pageTemplate id="first">
5 <frame id="first" x1="0.0" y1="57.0" width="538" height="728"/>
6 </pageTemplate>
7 </template>
8 <stylesheet>
9 <blockTableStyle id="Standard_Outline">
10 <blockAlignment value="LEFT"/>
11 <blockValign value="TOP"/>
12 </blockTableStyle>
13 <blockTableStyle id="Table_Address_detail">
14 <blockAlignment value="LEFT"/>
15 <blockValign value="TOP"/>
16 </blockTableStyle>
17 <blockTableStyle id="Table_Title_String">
18 <blockAlignment value="LEFT"/>
19 <blockValign value="TOP"/>
20 </blockTableStyle>
21 <blockTableStyle id="Header_Order_Reference_Tbl">
22 <blockAlignment value="LEFT"/>
23 <blockValign value="TOP"/>
24 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/>
25 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/>
26 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
27 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/>
28 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/>
29 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
30 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/>
31 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/>
32 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
33 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
34 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/>
35 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
36 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
37 <lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
38 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="4,0" stop="4,0"/>
39 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/>
40 </blockTableStyle>
41 <blockTableStyle id="Content_Order_Reference_Table">
42 <blockAlignment value="LEFT"/>
43 <blockValign value="TOP"/>
44 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="0,-1"/>
45 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="0,0"/>
46 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
47 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="1,0" stop="1,-1"/>
48 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="1,0" stop="1,0"/>
49 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
50 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="2,0" stop="2,-1"/>
51 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="2,0" stop="2,0"/>
52 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
53 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="3,0" stop="3,-1"/>
54 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="3,0" stop="3,0"/>
55 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
56 <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
57 <lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="4,0" stop="4,-1"/>
58 <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="4,0" stop="4,0"/>
59 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/>
60 </blockTableStyle>
61 <blockTableStyle id="Move_Line_Header">
62 <blockAlignment value="LEFT"/>
63 <blockValign value="TOP"/>
64 <lineStyle kind="LINEBELOW" colorName="#000000" start="0,-1" stop="0,-1"/>
65 <lineStyle kind="LINEBELOW" colorName="#000000" start="1,-1" stop="1,-1"/>
66 <lineStyle kind="LINEBELOW" colorName="#000000" start="2,-1" stop="2,-1"/>
67 <lineStyle kind="LINEBELOW" colorName="#000000" start="3,-1" stop="3,-1"/>
68 <lineStyle kind="LINEBELOW" colorName="#000000" start="4,-1" stop="4,-1"/>
69 </blockTableStyle>
70 <blockTableStyle id="Move_Line_Contect_Assign_State">
71 <blockAlignment value="LEFT"/>
72 <blockValign value="TOP"/>
73 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
74 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="1,2" stop="1,-1"/>
75 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="1,2" stop="1,2"/>
76 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="1,-1" stop="1,-1"/>
77 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="2,2" stop="2,-1"/>
78 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="2,2" stop="2,2"/>
79 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="2,-1" stop="2,-1"/>
80 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="3,2" stop="3,-1"/>
81 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="3,2" stop="3,2"/>
82 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="3,-1" stop="3,-1"/>
83 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="4,2" stop="4,-1"/>
84 <lineStyle kind="LINEAFTER" colorName="#ffffff" start="4,2" stop="4,-1"/>
85 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="4,2" stop="4,2"/>
86 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="4,-1" stop="4,-1"/>
87 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="0,3" stop="0,-1"/>
88 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="0,3" stop="0,3"/>
89 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="0,-1" stop="0,-1"/>
90 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="1,3" stop="1,-1"/>
91 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="1,3" stop="1,3"/>
92 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="1,-1" stop="1,-1"/>
93 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="2,3" stop="2,-1"/>
94 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="2,3" stop="2,3"/>
95 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="2,-1" stop="2,-1"/>
96 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="3,3" stop="3,-1"/>
97 <lineStyle kind="LINEAFTER" colorName="#ffffff" start="3,3" stop="3,-1"/>
98 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="3,3" stop="3,3"/>
99 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="3,-1" stop="3,-1"/>
100 </blockTableStyle>
101 <blockTableStyle id="Table1">
102 <blockAlignment value="LEFT"/>
103 <blockValign value="TOP"/>
104 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="0,0" stop="0,-1"/>
105 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="0,0" stop="0,0"/>
106 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="0,-1" stop="0,-1"/>
107 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="1,0" stop="1,-1"/>
108 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="1,0" stop="1,0"/>
109 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="1,-1" stop="1,-1"/>
110 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="2,0" stop="2,-1"/>
111 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="2,0" stop="2,0"/>
112 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="2,-1" stop="2,-1"/>
113 <lineStyle kind="LINEBEFORE" colorName="#ffffff" start="3,0" stop="3,-1"/>
114 <lineStyle kind="LINEAFTER" colorName="#ffffff" start="3,0" stop="3,-1"/>
115 <lineStyle kind="LINEABOVE" colorName="#ffffff" start="3,0" stop="3,0"/>
116 <lineStyle kind="LINEBELOW" colorName="#ffffff" start="3,-1" stop="3,-1"/>
117 </blockTableStyle>
118 <blockTableStyle id="Table4">
119 <blockAlignment value="LEFT"/>
120 <blockValign value="TOP"/>
121 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,-1" stop="0,-1"/>
122 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,-1" stop="1,-1"/>
123 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="2,-1" stop="2,-1"/>
124 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="3,-1" stop="3,-1"/>
125 <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="4,-1" stop="4,-1"/>
126 </blockTableStyle>
127 <blockTableStyle id="Table5">
128 <blockAlignment value="LEFT"/>
129 <blockValign value="TOP"/>
130 <lineStyle kind="LINEABOVE" colorName="#000000" start="1,0" stop="1,0"/>
131 <lineStyle kind="LINEABOVE" colorName="#000000" start="2,0" stop="2,0"/>
132 </blockTableStyle>
133 <initialize>
134 <paraStyle name="all" alignment="justify"/>
135 </initialize>
136 <paraStyle name="P1" fontName="Times-Roman" alignment="LEFT"/>
137 <paraStyle name="P2" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
138 <paraStyle name="P3" fontName="Helvetica" fontSize="14.0" leading="17" alignment="LEFT"/>
139 <paraStyle name="P4" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT"/>
140 <paraStyle name="P5" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
141 <paraStyle name="P6" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
142 <paraStyle name="P7" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
143 <paraStyle name="P8" fontName="Helvetica" fontSize="14.0" leading="17" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
144 <paraStyle name="P9" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
145 <paraStyle name="P10" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
146 <paraStyle name="P11" fontName="Helvetica-Bold" fontSize="14.0" leading="17" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
147 <paraStyle name="P12" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
148 <paraStyle name="Standard" fontName="Times-Roman"/>
149 <paraStyle name="Heading" fontName="Helvetica" fontSize="14.0" leading="17" spaceBefore="12.0" spaceAfter="6.0"/>
150 <paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
151 <paraStyle name="List" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
152 <paraStyle name="Caption" fontName="Times-Italic" fontSize="12.0" leading="15" spaceBefore="6.0" spaceAfter="6.0"/>
153 <paraStyle name="Index" fontName="Times-Roman"/>
154 <paraStyle name="terp_header" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
155 <paraStyle name="terp_header_Centre" fontName="Helvetica-Bold" fontSize="12.0" leading="15" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
156 <paraStyle name="terp_default_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
157 <paraStyle name="terp_default_Bold_8" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
158 <paraStyle name="terp_tblheader_Details" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
159 <paraStyle name="terp_tblheader_Details_Centre" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
160 <paraStyle name="terp_default_Centre_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
161 <paraStyle name="terp_default_Centre_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
162 <paraStyle name="terp_tblheader_General" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="6.0"/>
163 <paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
164 <paraStyle name="Table Contents" fontName="Times-Roman"/>
165 <paraStyle name="Footer" fontName="Times-Roman"/>
166 <paraStyle name="Table Heading" fontName="Times-Roman" alignment="CENTER"/>
167 <paraStyle name="Horizontal Line" fontName="Times-Roman" fontSize="6.0" leading="8" spaceBefore="0.0" spaceAfter="14.0"/>
168 <paraStyle name="Heading 9" fontName="Helvetica-Bold" fontSize="75%" leading="NaN" spaceBefore="12.0" spaceAfter="6.0"/>
169 <paraStyle name="terp_tblheader_General_Right" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
170 <paraStyle name="terp_tblheader_Details_Right" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
171 <paraStyle name="terp_default_Right_8" fontName="Helvetica" fontSize="8.0" leading="10" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
172 <paraStyle name="terp_header_Right" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
173 <paraStyle name="terp_default_address" fontName="Helvetica" fontSize="10.0" leading="13" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
174 <paraStyle name="terp_default_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
175 <paraStyle name="terp_default_Bold_9" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
176 <paraStyle name="terp_default_Right_9" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
177 <paraStyle name="terp_default_2" fontName="Helvetica" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
178 <paraStyle name="terp_default_5cm_Above_Space" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="6.0" spaceAfter="0.0"/>
179 <paraStyle name="terp_default_1cm_above_space" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="3.0" spaceAfter="0.0"/>
180 <images/>
181 </stylesheet>
182 <story>
183 <para style="P1">[[repeatIn(objects,'picking')]] </para>
184 <para style="terp_default_9">
185 <font color="white"> </font>
186 </para>
187 <blockTable colWidths="269.0,269.0" style="Table_Address_detail">
188 <tr>
189 <td>
190 <para style="terp_default_Bold_9">Shipping Address :</para>
191 <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>
192 <para style="terp_default_9">[[ picking.address_id and picking.address_id.street or '' ]]</para>
193 <para style="terp_default_9">[[ (picking.address_id and picking.address_id.street2) or removeParentNode('para') ]]</para>
194 <para style="terp_default_9">[[ picking.address_id and picking.address_id.zip or '' ]] [[ picking.address_id and picking.address_id.city or '' ]]</para>
195 <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>
196 <para style="terp_default_9">[[ (picking.address_id and picking.address_id.country_id and picking.address_id.country_id.name) or '' ]]</para>
197 </td>
198 <td>
199 <para style="terp_default_Bold_9">Contact Address :</para>
200 <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>
201 <para style="terp_default_9">[[ picking.address_id and picking.address_id.street or '' ]]</para>
202 <para style="terp_default_9">[[ (picking.address_id and picking.address_id.street2) or removeParentNode('para') ]]</para>
203 <para style="terp_default_9">[[ picking.address_id and picking.address_id.zip or '' ]] [[ picking.address_id and picking.address_id.city or '' ]]</para>
204 <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>
205 <para style="terp_default_9">[[ (picking.address_id and picking.address_id.country_id and picking.address_id.country_id.name) or '' ]]</para>
206 </td>
207 </tr>
208 </blockTable>
209 <para style="terp_default_5cm_Above_Space">
210 <font color="white"> </font>
211 </para>
212 <para style="terp_default_5cm_Above_Space">
213 <font color="white"> </font>
214 </para>
215 <blockTable colWidths="538.0" style="Table_Title_String">
216 <tr>
217 <td>
218 <para style="terp_header">Packing List: [[ picking.name ]]</para>
219 </td>
220 </tr>
221 </blockTable>
222 <para style="terp_default_5cm_Above_Space">
223 <font color="white"> </font>
224 </para>
225 <blockTable colWidths="100.0,100.0,108.0,107.0,109.0" style="Header_Order_Reference_Tbl">
226 <tr>
227 <td>
228 <para style="terp_tblheader_General_Centre">Journal</para>
229 </td>
230 <td>
231 <para style="terp_tblheader_General_Centre">Order(Origin)</para>
232 </td>
233 <td>
234 <para style="terp_tblheader_General_Centre">Recipient</para>
235 </td>
236 <td>
237 <para style="terp_tblheader_General_Centre">Expected Shipping Date </para>
238 </td>
239 <td>
240 <para style="terp_tblheader_General_Centre">weight</para>
241 </td>
242 </tr>
243 </blockTable>
244 <blockTable colWidths="100.0,100.0,108.0,107.0,109.0" style="Content_Order_Reference_Table">
245 <tr>
246 <td>
247 <para style="terp_default_Centre_8">[[ picking.stock_journal_id.name]]</para>
248 </td>
249 <td>
250 <para style="terp_default_Centre_8">[[ picking.origin or '']]</para>
251 </td>
252 <td>
253 <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>
254 </td>
255 <td>
256 <para style="terp_default_Centre_8">[[ formatLang(picking.min_date,date_time = True) ]]</para>
257 </td>
258 <td>
259 <para style="terp_default_Centre_8">[[ 'weight' in picking._columns.keys() and picking.weight or '']]</para>
260 </td>
261 </tr>
262 </blockTable>
263 <para style="terp_default_5cm_Above_Space">
264 <font color="white"> </font>
265 </para>
266 <blockTable colWidths="256.0,73.0,59.0,59.0,71.0" repeatRows="1" style="Move_Line_Header">
267 <tr>
268 <td>
269 <para style="terp_tblheader_Details">Description</para>
270 </td>
271 <td>
272 <para style="terp_tblheader_Details_Centre">Lot</para>
273 </td>
274 <td>
275 <para style="terp_tblheader_Details_Centre">State</para>
276 </td>
277 <td>
278 <para style="terp_tblheader_Details_Right">Location</para>
279 </td>
280 <td>
281 <para style="terp_tblheader_Details_Right">
282 <font color="white"> </font>
283 </para>
284 <para style="terp_tblheader_Details_Right">
285 <font color="white"> </font>
286 </para>
287 </td>
288 </tr>
289 </blockTable>
290 <section>
291 <para style="terp_default_2">
292 <font color="white"> </font>
293 </para>
294 <blockTable colWidths="522.0" style="Move_Line_Contect_Assign_State">
295 <tr>
296 <td>
297 <para style="P9">[[_get_parent(picking.id)[0].product_id.name]]</para>
298 <para style="P9">
299 <font color="white"> </font>
300 </para>
301 </td>
302 </tr>
303 <tr>
304 <td>
305 <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>
306 <para style="P10">
307 <font face="Times-Roman" size="9.0">[[ (picking.move_lines!=[] and removeParentNode('para')) or removeParentNode('section')]]</font>
308 </para>
309 </td>
310 </tr>
311 <tr>
312 <td>
313 <blockTable colWidths="129.0,129.0,129.0,129.0" style="Table1">
314 <tr>
315 <td>
316 <para style="terp_default_9">[[move_lines.product_id.name and '*'*4+(move_lines.product_id.name)or removeParentNode('tr')]] </para>
317 </td>
318 <td>
319 <para style="terp_default_Centre_9">[[ (move_lines.prodlot_id and move_lines.prodlot_id.name) or '' ]]</para>
320 </td>
321 <td>
322 <para style="terp_default_9">[[ move_lines.state ]]</para>
323 </td>
324 <td>
325 <para style="terp_default_Right_9">[[ (move_lines.location_id and move_lines.location_id.name) or '' ]] </para>
326 </td>
327 </tr>
328 </blockTable>
329 <para style="P9">
330 <font color="white"> </font>
331 </para>
332 </td>
333 </tr>
334 </blockTable>
335 </section>
336 <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>
337 <para style="terp_default_Bold_9">
338 <font color="white"> </font>
339 </para>
340 <para style="terp_default_2"/>
341 <section>
342 <para style="terp_default_2">[[ repeatIn([line for line in picking.move_lines if (line.state == 'draft' or line.state=='waiting')],'move_lines') ]]</para>
343 <para style="terp_default_2">[[ (picking.move_lines!=[] and removeParentNode('para')) or removeParentNode('section')]]</para>
344 <blockTable colWidths="257.0,74.0,57.0,61.0,72.0" style="Table4">
345 <tr>
346 <td>
347 <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>
348 </td>
349 <td>
350 <para style="terp_default_Centre_9">[[ (move_lines.prodlot_id and move_lines.prodlot_id.name) or '' ]]</para>
351 </td>
352 <td>
353 <para style="terp_default_9">[[ move_lines.state ]]</para>
354 </td>
355 <td>
356 <para style="terp_default_Right_9">[[ (move_lines.location_id and move_lines.location_id.name) or '' ]] </para>
357 </td>
358 <td>
359 <para style="terp_default_Right_9">[[ formatLang(move_lines.product_qty) ]] [[ move_lines.product_uom.name ]]</para>
360 </td>
361 </tr>
362 </blockTable>
363 </section>
364 <blockTable colWidths="388.0,56.0,77.0" style="Table5">
365 <tr>
366 <td>
367 <para style="terp_default_9">
368 <font color="white"> </font>
369 </para>
370 </td>
371 <td>
372 <para style="terp_tblheader_Details_Centre">Total</para>
373 </td>
374 <td>
375 <para style="terp_tblheader_Details_Right">[[ formatLang(get_qtytotal(picking.move_lines)['quantity']) ]] [[ get_qtytotal(picking.move_lines)['uom'] ]]</para>
376 </td>
377 </tr>
378 </blockTable>
379 <para style="P11">
380 <font color="white"> </font>
381 </para>
382 </story>
383</document>
384
0385
=== added file 'assembly_bom/report/normalized_oo2rml.xsl'
--- assembly_bom/report/normalized_oo2rml.xsl 1970-01-01 00:00:00 +0000
+++ assembly_bom/report/normalized_oo2rml.xsl 2011-10-06 15:31:48 +0000
@@ -0,0 +1,696 @@
1<?xml version="1.0" encoding="utf-8"?>
2<xsl:stylesheet
3 version="1.0"
4 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
5 xmlns:fo="http://www.w3.org/1999/XSL/Format"
6 xmlns:office="http://openoffice.org/2000/office"
7 xmlns:style="http://openoffice.org/2000/style"
8 xmlns:text="http://openoffice.org/2000/text"
9 xmlns:table="http://openoffice.org/2000/table"
10 xmlns:draw="http://openoffice.org/2000/drawing"
11 xmlns:xlink="http://www.w3.org/1999/xlink"
12 xmlns:number="http://openoffice.org/2000/datastyle"
13 xmlns:svg="http://www.w3.org/2000/svg"
14 xmlns:chart="http://openoffice.org/2000/chart"
15 xmlns:dr3d="http://openoffice.org/2000/dr3d"
16 xmlns:math="http://www.w3.org/1998/Math/MathML"
17 xmlns:form="http://openoffice.org/2000/form"
18 xmlns:script="http://openoffice.org/2000/script"
19 office:class="text" office:version="1.0"
20 exclude-result-prefixes = "xsl fo office style text table draw xlink number svg chart dr3d math form script">
21
22 <!--TODO's: indent, picture cache (trml2pdf) -->
23
24<xsl:output method="xml" indent="yes" />
25<xsl:strip-space elements="*"/>
26
27<xsl:key name="text_style" match="style:style[@style:family='text']" use="@style:name" />
28<xsl:key name="page_break_before" match="style:style[@style:family='paragraph' and ./style:properties/@fo:break-before='page']" use="@style:name" />
29<xsl:key name="page_break_after" match="style:style[@style:family='paragraph' and ./style:properties/@fo:break-after='page']" use="@style:name" />
30<xsl:key name="table_column_style" match="style:style[@style:family='table-column']" use="@style:name" />
31<xsl:key name="table_cell_style" match="style:style[@style:family='table-cell']" use="@style:name" />
32<xsl:key name="paragraph_style" match="style:style[@style:family='paragraph']" use="@style:name" />
33
34<xsl:template match="office:document-content">
35 <document filename="test.pdf">
36 <xsl:apply-templates select="office:automatic-styles" />
37 <xsl:apply-templates select="office:body" />
38 </document>
39</xsl:template>
40
41<xsl:template name="page_size">
42 <xsl:attribute name="pageSize">
43 <xsl:text>(</xsl:text>
44 <xsl:value-of select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" />
45 <xsl:text>,</xsl:text>
46 <xsl:value-of select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height" />
47 <xsl:text>)</xsl:text>
48 </xsl:attribute>
49</xsl:template>
50
51<xsl:template name="fixed_frame">
52 <xsl:for-each select="//draw:text-box">
53 <frame>
54 <xsl:attribute name="id"><xsl:value-of select="./@draw:name" /></xsl:attribute>
55 <xsl:attribute name="x1"><xsl:value-of select="./@svg:x" /></xsl:attribute>
56 <xsl:attribute name="y1">
57 <xsl:value-of
58 select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height - ./@svg:y - ./@fo:min-height" />
59 </xsl:attribute>
60 <xsl:attribute name="width">
61 <xsl:value-of select="./@svg:width" />
62 </xsl:attribute>
63 <xsl:attribute name="height">
64 <xsl:value-of select="./@fo:min-height" />
65 </xsl:attribute>
66 </frame>
67 </xsl:for-each>
68</xsl:template>
69
70<xsl:template name="margin_sizes">
71 <xsl:variable name="margin_left" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-left" />
72 <xsl:variable name="margin_right" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-right" />
73 <xsl:variable name="margin_top" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-top" />
74 <xsl:variable name="margin_bottom" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-bottom" />
75 <xsl:variable name="page_width" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" />
76 <xsl:variable name="page_height" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-height" />
77 <xsl:attribute name="x1"><xsl:value-of select="$margin_left" /></xsl:attribute>
78 <xsl:attribute name="y1"><xsl:value-of select="$margin_bottom" /></xsl:attribute>
79 <xsl:attribute name="width"><xsl:value-of select="$page_width - $margin_left - $margin_right"/></xsl:attribute>
80 <xsl:attribute name="height"><xsl:value-of select="$page_height - $margin_bottom - $margin_top"/></xsl:attribute>
81</xsl:template>
82
83<xsl:template name="text_width">
84 <!-- You need this for the workaround to make primitive outlines-->
85 <xsl:variable name="margin_left" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-left" />
86 <xsl:variable name="margin_right" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:margin-right" />
87 <xsl:variable name="page_width" select="//transferredfromstylesxml/style:page-master[1]/style:properties/@fo:page-width" />
88 <xsl:value-of select="$page_width - $margin_left - $margin_right - 18"/>
89</xsl:template>
90
91
92
93<xsl:template match="office:automatic-styles">
94 <!--<template pageSize="(21cm, 29.7cm)" leftMargin="1.0cm" rightMargin="2.0cm" topMargin="1.0cm" bottomMargin="1.0cm" title="Test" author="Martin Simon" allowSplitting="20">-->
95 <template pageSize="(21cm, 29.7cm)" title="Test" author="Martin Simon" allowSplitting="20">
96 <xsl:call-template name="page_size" />
97 <pageTemplate id="first">
98 <xsl:call-template name="fixed_frame" />
99 <frame id="first" x1="2cm" y1="2cm" width="17cm" height="26cm">
100 <xsl:call-template name="margin_sizes" />
101 </frame>
102 </pageTemplate>
103 </template>
104 <stylesheet>
105 <!--A table style to simulate primitive outlines -till the <addOutline> tag is implemented in trml2pdf -->
106 <blockTableStyle id="Standard_Outline">
107 <blockAlignment value="LEFT"/>
108 <blockValign value="TOP"/>
109 </blockTableStyle>
110 <!--use two standard table grid styles like PyOpenOffice "Old Way": with and without a grid-->
111 <!--TODO insert table cell colors here, not within the <td> tag - otherwise
112 it will not work with flowables as cell content-->
113 <xsl:call-template name="make_blocktablestyle" />
114 <initialize>
115 <paraStyle name="all" alignment="justify" />
116 </initialize>
117 <xsl:apply-templates select="style:style" />
118 </stylesheet>
119</xsl:template>
120
121<xsl:template name="make_blocktablestyle">
122 <xsl:for-each select="//table:table">
123 <xsl:variable name="test">
124 <xsl:value-of select="./@table:name" />
125 </xsl:variable>
126 <xsl:if test="not(boolean(count(preceding-sibling::table:table[@table:name=$test])))">
127 <!--Test if this is the first table with this style, nested tables not counted-->
128 <blockTableStyle id="{@table:name}">
129 <xsl:if test=".//draw:image">
130 <blockTopPadding value="0"/>
131 <blockBottomPadding value="0"/>
132 </xsl:if>
133 <blockAlignment value="LEFT" />
134 <blockValign value="TOP" />
135 <xsl:call-template name="make_linestyle" />
136 <xsl:call-template name="make_tablebackground" />
137 </blockTableStyle>
138 </xsl:if>
139 </xsl:for-each>
140</xsl:template>
141
142<xsl:template name="make_linestyle">
143 <xsl:for-each select=".//table:table-row">
144 <xsl:variable name="row" select="position() - 1"/>
145 <xsl:for-each select=".//table:table-cell">
146 <xsl:variable name="col" select="position() - 1"/>
147 <xsl:variable name="linebefore">
148 <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border-left"/>
149 </xsl:variable>
150 <xsl:if test="not($linebefore='') and not($linebefore='none')">
151 <xsl:variable name="colorname">
152 <xsl:value-of select="substring-after($linebefore,'#')"/>
153 </xsl:variable>
154 <lineStyle kind="LINEBEFORE" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},-1"/>
155 </xsl:if>
156 <xsl:variable name="lineafter">
157 <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border-right"/>
158 </xsl:variable>
159 <xsl:if test="not($lineafter='') and not($lineafter='none')">
160 <xsl:variable name="colorname">
161 <xsl:value-of select="substring-after($lineafter,'#')"/>
162 </xsl:variable>
163 <lineStyle kind="LINEAFTER" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},-1"/>
164 </xsl:if>
165 <xsl:variable name="lineabove">
166 <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border-top"/>
167 </xsl:variable>
168 <xsl:if test="not($lineabove='') and not($lineabove='none')">
169 <xsl:variable name="colorname">
170 <xsl:value-of select="substring-after($lineabove,'#')"/>
171 </xsl:variable>
172 <lineStyle kind="LINEABOVE" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},{$row}"/>
173 </xsl:if>
174 <xsl:variable name="linebelow">
175 <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border-bottom"/>
176 </xsl:variable>
177 <xsl:if test="not($linebelow='') and not($linebelow='none')">
178 <xsl:variable name="colorname">
179 <xsl:value-of select="substring-after($linebelow,'#')"/>
180 </xsl:variable>
181 <lineStyle kind="LINEBELOW" colorName="#{$colorname}" start="{$col},{-1}" stop="{$col},{-1}"/>
182 </xsl:if>
183 <xsl:variable name="grid">
184 <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:border"/>
185 </xsl:variable>
186 <xsl:if test="not($grid='') and not($grid='none')">
187 <xsl:variable name="colorname">
188 <xsl:value-of select="substring-after($grid,'#')"/>
189 </xsl:variable>
190 <!-- Don't use grid because we don't need a line between each rows -->
191 <lineStyle kind="LINEBEFORE" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},-1"/>
192 <lineStyle kind="LINEAFTER" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},-1"/>
193 <lineStyle kind="LINEABOVE" colorName="#{$colorname}" start="{$col},{$row}" stop="{$col},{$row}"/>
194 <lineStyle kind="LINEBELOW" colorName="#{$colorname}" start="{$col},{-1}" stop="{$col},{-1}"/>
195 </xsl:if>
196 </xsl:for-each>
197 </xsl:for-each>
198</xsl:template>
199
200<!-- Was needed to simulate bulleted lists:
201<xsl:template match="text:ordered-list|text:unordered-list">
202 <xsl:variable name = "text_width">
203 <xsl:call-template name="text_width" />
204 </xsl:variable>
205 <blockTable style="Standard_Outline" colWidths="18,{$text_width}">
206 <xsl:apply-templates match="text:list-item" />
207</blockTable>
208</xsl:template>
209
210<xsl:template match="text:list-item">
211 <tr>
212 <td><para><font face="Helvetica-Bold" size="10">*</font></para></td>
213 <td>
214 <xsl:apply-templates />
215 </td>
216 </tr>
217</xsl:template>
218
219-->
220
221
222<xsl:template match="office:body">
223 <story>
224 <xsl:apply-templates />
225 <xsl:for-each select="//draw:text-box">
226 <currentFrame>
227 <xsl:attribute name="name">
228 <xsl:value-of select="./@draw:name" />
229 </xsl:attribute>
230 </currentFrame>
231 <xsl:apply-templates>
232 <xsl:with-param name="skip_draw" select="0" />
233 </xsl:apply-templates>
234 <frameEnd />
235 </xsl:for-each>
236 <xsl:for-each select="//text:ordered-list">
237 <para><seqReset id="{./@text:style-name}"/></para>
238 </xsl:for-each>
239 </story>
240</xsl:template>
241
242<xsl:template match="table:table">
243 <blockTable>
244 <xsl:attribute name="colWidths">
245 <xsl:call-template name="make_columns" />
246 </xsl:attribute>
247 <xsl:call-template name="make_tableheaders" />
248 <xsl:attribute name="style">
249 <xsl:value-of select="@table:name" />
250 </xsl:attribute>
251 <xsl:apply-templates />
252 </blockTable>
253</xsl:template>
254
255<xsl:template name="make_tableheaders">
256 <xsl:if test="boolean(count(table:table-header-rows))">
257 <xsl:attribute name="repeatRows">1</xsl:attribute>
258 </xsl:if>
259</xsl:template>
260
261<xsl:template name="make_tablebackground">
262 <xsl:for-each select=".//table:table-row">
263 <!--Be careful when there are table:table-header-rows as
264 parent node of table:table-row -->
265 <xsl:variable name="row" select="position() - 1" />
266 <xsl:for-each select="./table:table-cell">
267 <xsl:variable name="col" select="position() - 1" />
268 <xsl:variable name="background">
269 <xsl:value-of select="key('table_cell_style',@table:style-name)/style:properties/@fo:background-color" />
270 </xsl:variable>
271 <xsl:if test="not($background='') and boolean(key('table_cell_style',@table:style-name)/style:properties/@fo:background-color) and starts-with($background,'#')">
272 <!--only RGB hexcolors are accepted -->
273 <blockBackground colorName="{$background}" start="{$col},{$row}" stop="{$col},-1" />
274 </xsl:if>
275 </xsl:for-each>
276 </xsl:for-each>
277</xsl:template>
278
279<xsl:template name="make_columns">
280 <xsl:variable name="columns" >
281 <xsl:for-each select="table:table-column">
282 <xsl:value-of select="key('table_column_style',@table:style-name)/style:properties/@style:column-width" />
283 <xsl:text>,</xsl:text>
284 </xsl:for-each>
285 </xsl:variable>
286 <xsl:value-of select="substring($columns,1,string-length($columns) - 1)" />
287 <!--strip the last comma-->
288</xsl:template>
289
290<xsl:template match="table:table-row">
291 <tr>
292 <xsl:apply-templates />
293 </tr>
294</xsl:template>
295
296<xsl:template match="table:table-cell">
297 <td>
298 <xsl:apply-templates />
299 </td>
300</xsl:template>
301
302<xsl:template match="text:section">
303 <section>
304 <xsl:apply-templates />
305 </section>
306</xsl:template>
307
308
309<xsl:template match="text:span">
310 <font>
311 <xsl:call-template name="make_fontnames_span" />
312 <xsl:call-template name="make_fontsize_span" />
313 <xsl:apply-templates />
314 </font>
315</xsl:template>
316
317<xsl:template name="make_fontsize_span">
318 <xsl:variable name ="fontsize">
319 <xsl:value-of select="key('text_style',@text:style-name)/style:properties/@fo:font-size" />
320 </xsl:variable>
321 <xsl:if test="not($fontsize='') and boolean(key('text_style',@text:style-name)/style:properties/@fo:font-size)" >
322 <xsl:attribute name="size">
323 <xsl:value-of select="$fontsize" />
324 </xsl:attribute>
325 </xsl:if>
326</xsl:template>
327
328<xsl:template name="make_fontnames_span">
329 <xsl:attribute name="face">
330 <xsl:call-template name="make_fontnames">
331 <xsl:with-param name="fontName" select="key('text_style',@text:style-name)/style:properties/@style:font-name" />
332 <xsl:with-param name="fontWeight" select="key('text_style',@text:style-name)/style:properties/@fo:font-weight" />
333 <xsl:with-param name="fontStyle" select="key('text_style',@text:style-name)/style:properties/@fo:font-style" />
334 </xsl:call-template>
335 </xsl:attribute>
336</xsl:template>
337
338<xsl:template name="make_image">
339 <illustration height="{.//draw:image/@svg:height}" width="{.//draw:image/@svg:width}">
340 <image x="0" y="0" file="{substring-after(.//draw:image/@xlink:href,'#Pictures/')}" height="{.//draw:image/@svg:height}" width="{.//draw:image/@svg:width}" />
341 </illustration>
342</xsl:template>
343
344<xsl:template name="empty_paragraph">
345 <xsl:if test="not(boolean(count(descendant::node())))">
346 <xsl:call-template name="distance_point">
347 <xsl:with-param name="background" select="key('paragraph_style',@text:style-name)/style:properties/@fo:background-color" />
348 </xsl:call-template>
349 </xsl:if>
350</xsl:template>
351
352<xsl:template name="distance_point">
353 <xsl:param name="background" />
354 <xsl:param name="tab_stop"></xsl:param>
355 <xsl:variable name="local_back">
356 <xsl:choose>
357 <xsl:when test="not(boolean($background)) or not(contains($background,'#'))">
358 <!-- Do not accept OO colors like "transparent", only hex-colors -->
359 <xsl:text>white</xsl:text>
360 </xsl:when>
361 <xsl:otherwise>
362 <xsl:value-of select="$background" />
363 </xsl:otherwise>
364 </xsl:choose>
365 </xsl:variable>
366 <font color="{$local_back}">
367 <xsl:text> </xsl:text>
368 <xsl:if test="boolean($tab_stop)">
369 <!-- simulate a tabstop with white/background-color points -->
370 <xsl:text>.........</xsl:text>
371 </xsl:if>
372 </font>
373</xsl:template>
374
375<xsl:template match="text:ordered-list">
376 <xsl:apply-templates />
377
378 <!-- Reset the counter. seqreset is not a trml2pdf tag, but a Platypus Intra Paragraph Markup,
379 so it needs a dummy paragraph to enclose it -->
380</xsl:template>
381
382<xsl:template name="make_listitem">
383 <xsl:if test="(name(..)='text:list-item')">
384 <xsl:attribute name="leftIndent">15</xsl:attribute>
385 <xsl:attribute name="bulletIndent">0</xsl:attribute>
386 <xsl:choose>
387 <xsl:when test="(name(../..)='text:unordered-list')">
388 <xsl:variable name="fontsize">
389 <xsl:value-of select="number(key('paragraph_style',@text:style-name)/style:properties/@fo:font-size)" />
390 </xsl:variable>
391 <xsl:choose>
392 <xsl:when test="$fontsize='NaN'">
393 <!-- you should exclude non-numerical values for bulletFontSize. <== Sometimes the preprocessing went wrong.-->
394 <!--use a default bullet font size-->
395 <xsl:attribute name="bulletFontSize">6</xsl:attribute>
396 </xsl:when>
397 <xsl:otherwise>
398 <xsl:attribute name="bulletFontSize"><xsl:value-of select="floor(($fontsize div 2) + 1)" /></xsl:attribute>
399 </xsl:otherwise>
400 </xsl:choose>
401 <xsl:attribute name="bulletFontName">ZapfDingbats</xsl:attribute>
402 <xsl:attribute name="bulletText">l</xsl:attribute>
403 </xsl:when>
404 <xsl:otherwise>
405 <!-- Generate the numbers for an ordered list -->
406 <xsl:variable name="size">
407 <xsl:value-of select="key('paragraph_style',@text:style-name)/style:properties/@fo:font-size" />
408 </xsl:variable>
409 <!-- For ordered lists we use the bullet tag from Platypus Intra Paragraph Markup -->
410 <bullet>
411 <xsl:if test="not($size='') and boolean(key('paragraph_style',@text:style-name)/style:properties/@fo:font-size)">
412 <xsl:attribute name="size">
413 <!-- adapt the fontsize to the fontsize of the current paragraph -->
414 <xsl:value-of select="$size" />
415 </xsl:attribute>
416 </xsl:if>
417 <seq id="{../../@text:style-name}"/>.</bullet>
418
419 </xsl:otherwise>
420 </xsl:choose>
421 </xsl:if>
422</xsl:template>
423
424<xsl:template match="text:drop-down">
425 <xsl:value-of select="text:label[2]/@text:value" />
426</xsl:template>
427
428
429<xsl:template match="text:p|text:h">
430 <xsl:param name="skip_draw" select="1" />
431 <xsl:if test="boolean(key('page_break_before',@text:style-name))" >
432 <pageBreak />
433 </xsl:if>
434 <xsl:choose>
435 <xsl:when test="boolean(.//draw:image)">
436 <xsl:call-template name="make_image" />
437 </xsl:when>
438 <xsl:when test="boolean(name(..) = 'draw:text-box') and boolean($skip_draw)">
439 </xsl:when>
440 <xsl:otherwise>
441 <para>
442 <xsl:attribute name="style">
443 <xsl:value-of select="@text:style-name" />
444 </xsl:attribute>
445 <xsl:call-template name="make_listitem" />
446 <xsl:apply-templates />
447 <xsl:call-template name="empty_paragraph" />
448 </para>
449 </xsl:otherwise>
450 </xsl:choose>
451 <xsl:if test="boolean(key('page_break_after',@text:style-name))" >
452 <pageBreak />
453 </xsl:if>
454</xsl:template>
455
456<xsl:template match="text:p/text:tab-stop">
457 <!-- simulate a tabstop -->
458 <xsl:call-template name="distance_point">
459 <xsl:with-param name="background" select="key('paragraph_style',@text:style-name)/style:properties/@fo:background-color" />
460 <xsl:with-param name="tab_stop">yes</xsl:with-param>
461 </xsl:call-template>
462</xsl:template>
463
464<!-- experimental - switched off
465<xsl:template match="text:h">
466 <para>
467 <xsl:attribute name="style">
468 <xsl:value-of select="@text:style-name" />
469 </xsl:attribute>
470 <xsl:call-template name="make_number" />
471 <xsl:apply-templates />
472 <xsl:call-template name="empty_paragraph" />
473 </para>
474</xsl:template>
475
476<xsl:template name="make_number">
477 <xsl:choose>
478 <xsl:when test="@text:level='1'">
479 <xsl:number format="1. " />
480 </xsl:when>
481 <xsl:when test="@text:level='2'">
482 <xsl:number count="text:h[@text:level='1']|text:h[text:level='2']" level="any" format="1.1." />
483 </xsl:when>
484 </xsl:choose>
485</xsl:template>
486
487-->
488
489<xsl:template match="style:style[@style:family='paragraph']">
490 <paraStyle>
491 <xsl:attribute name="name">
492 <xsl:value-of select="@style:name" />
493 </xsl:attribute>
494 <xsl:call-template name="make_indent_paragraph" />
495 <xsl:call-template name="make_fontnames_paragraph" />
496 <xsl:call-template name="make_fontsize" />
497 <!--<xsl:call-template name="make_parent" /> not necessary -
498 parent styles processed by PyOpenOffice -->
499 <xsl:call-template name="make_alignment" />
500 <xsl:call-template name="make_background" />
501 <xsl:call-template name="make_space_beforeafter" />
502 <xsl:call-template name="make_fontcolor" />
503 </paraStyle>
504</xsl:template>
505
506<xsl:template name="make_indent_paragraph">
507 <xsl:variable name="right_indent"><xsl:value-of select="style:properties/@fo:margin-right" /></xsl:variable>
508 <xsl:variable name="left_indent"><xsl:value-of select="style:properties/@fo:margin-left" /></xsl:variable>
509 <xsl:if test="not($right_indent='') and boolean(style:properties/@fo:margin-right)">
510 <xsl:attribute name="rightIndent">
511 <xsl:value-of select="$right_indent" />
512 </xsl:attribute>
513 </xsl:if>
514 <xsl:if test="not($left_indent='') and boolean(style:properties/@fo:margin-left)">
515 <xsl:attribute name="leftIndent">
516 <xsl:value-of select="$left_indent" />
517 </xsl:attribute>
518 </xsl:if>
519</xsl:template>
520
521<xsl:template name="make_background">
522 <xsl:variable name="background">
523 <xsl:value-of select="style:properties/@fo:background-color" />
524 </xsl:variable>
525 <xsl:if test="not($background='') and boolean(style:properties/@fo:background-color) and starts-with($background,'#')" >
526 <xsl:attribute name="backColor">
527 <xsl:value-of select="$background" />
528 </xsl:attribute>
529 </xsl:if>
530</xsl:template>
531
532<xsl:template name="make_space_beforeafter">
533 <xsl:variable name="before">
534 <xsl:value-of select="style:properties/@fo:margin-top" />
535 </xsl:variable>
536 <xsl:variable name="after">
537 <xsl:value-of select="style:properties/@fo:margin-bottom" />
538 </xsl:variable>
539 <xsl:if test="not($before='') and boolean(style:properties/@fo:margin-top)" >
540 <xsl:attribute name="spaceBefore">
541 <xsl:value-of select="$before" />
542 </xsl:attribute>
543 </xsl:if>
544 <xsl:if test="not($after='') and boolean(style:properties/@fo:margin-bottom)" >
545 <xsl:attribute name="spaceAfter">
546 <xsl:value-of select="$after" />
547 </xsl:attribute>
548 </xsl:if>
549</xsl:template>
550
551<xsl:template name="make_fontsize">
552 <xsl:variable name="fontSize">
553 <xsl:value-of select="style:properties/@fo:font-size" />
554 </xsl:variable>
555 <xsl:if test="not($fontSize='') and boolean(style:properties/@fo:font-size)">
556 <xsl:attribute name="fontSize">
557 <xsl:value-of select="$fontSize" />
558 </xsl:attribute>
559 <xsl:attribute name="leading">
560 <xsl:value-of select="$fontSize + floor($fontSize div 5) + 1" />
561 <!--use a standard leading related to the font size -->
562 </xsl:attribute>
563 </xsl:if>
564</xsl:template>
565
566<!--this template is not needed anymore for "normalized" sxw files -->
567<xsl:template name="make_parent">
568 <xsl:variable name="parent">
569 <xsl:value-of select="@style:parent-style-name" />
570 </xsl:variable>
571 <xsl:if test="not($parent='') and boolean(@style:parent-style-name)">
572 <xsl:attribute name="parent">
573 <xsl:value-of select="$parent" />
574 </xsl:attribute>
575 </xsl:if>
576</xsl:template>
577
578<xsl:template name="make_alignment">
579 <xsl:variable name="alignment">
580 <xsl:value-of select="style:properties/@fo:text-align" />
581 </xsl:variable>
582 <xsl:if test="not($alignment='') and boolean(style:properties/@fo:text-align)">
583 <xsl:choose>
584 <xsl:when test="$alignment='start'">
585 <xsl:attribute name="alignment">LEFT</xsl:attribute>
586 </xsl:when>
587 <xsl:when test="$alignment='center'">
588 <xsl:attribute name="alignment">CENTER</xsl:attribute>
589 </xsl:when>
590 <xsl:when test="$alignment='end'">
591 <xsl:attribute name="alignment">RIGHT</xsl:attribute>
592 </xsl:when>
593 <xsl:when test="$alignment='justify'">
594 <xsl:attribute name="alignment">JUSTIFY</xsl:attribute>
595 </xsl:when>
596 </xsl:choose>
597 </xsl:if>
598</xsl:template>
599
600<xsl:template name="make_fontnames_paragraph">
601 <xsl:attribute name="fontName">
602 <xsl:call-template name="make_fontnames">
603 <xsl:with-param name="fontName" select="style:properties/@style:font-name" />
604 <xsl:with-param name="fontWeight" select="style:properties/@fo:font-weight" />
605 <xsl:with-param name="fontStyle" select="style:properties/@fo:font-style" />
606 </xsl:call-template>
607 </xsl:attribute>
608</xsl:template>
609
610<xsl:template name="make_fontnames">
611 <!--much too verbose, needs improvement-->
612<xsl:param name="fontName" />
613<xsl:param name="fontWeight" />
614<xsl:param name="fontStyle" />
615<xsl:choose>
616<xsl:when test="not($fontName='') and boolean($fontName)">
617 <xsl:choose>
618 <xsl:when test="contains($fontName,'Courier')">
619 <xsl:choose>
620 <xsl:when test="($fontWeight='bold') and ($fontStyle='italic')">
621 <xsl:text>Courier-BoldOblique</xsl:text>
622 </xsl:when>
623 <xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')">
624 <xsl:text>Courier-Bold</xsl:text>
625 </xsl:when>
626 <xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')">
627 <xsl:text>Courier-Oblique</xsl:text>
628 </xsl:when>
629 <xsl:otherwise>
630 <xsl:text>Courier</xsl:text>
631 </xsl:otherwise>
632 </xsl:choose>
633 </xsl:when>
634 <xsl:when test="contains($fontName,'Helvetica') or contains($fontName,'Arial') or contains($fontName,'Sans')">
635 <xsl:choose>
636 <xsl:when test="($fontWeight='bold') and ($fontStyle='italic')">
637 <xsl:text>Helvetica-BoldOblique</xsl:text>
638 </xsl:when>
639 <xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')">
640 <xsl:text>Helvetica-Bold</xsl:text>
641 </xsl:when>
642 <xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')">
643 <xsl:text>Helvetica-Oblique</xsl:text>
644 </xsl:when>
645 <xsl:otherwise>
646 <xsl:text>Helvetica</xsl:text>
647 </xsl:otherwise>
648 </xsl:choose>
649 </xsl:when>
650 <xsl:otherwise>
651 <xsl:choose>
652 <xsl:when test="($fontWeight='bold') and ($fontStyle='italic')">
653 <xsl:text>Times-BoldItalic</xsl:text>
654 </xsl:when>
655 <xsl:when test="($fontWeight='bold') and not ($fontStyle='italic')">
656 <xsl:text>Times-Bold</xsl:text>
657 </xsl:when>
658 <xsl:when test="not($fontWeight='bold') and ($fontStyle='italic')">
659 <xsl:text>Times-Italic</xsl:text>
660 </xsl:when>
661 <xsl:otherwise>
662 <xsl:text>Times-Roman</xsl:text>
663 </xsl:otherwise>
664 </xsl:choose>
665 </xsl:otherwise>
666 </xsl:choose>
667</xsl:when>
668<xsl:otherwise>
669 <!--Use this as default -->
670 <xsl:text>Times-Roman</xsl:text>
671</xsl:otherwise>
672</xsl:choose>
673</xsl:template>
674<xsl:template name="make_fontcolor">
675 <xsl:variable name="textColor">
676 <xsl:value-of select="style:properties/@fo:color"/>
677 </xsl:variable>
678 <xsl:if test="not($textColor='') and boolean(style:properties/@fo:color)">
679 <xsl:attribute name="textColor">
680 <xsl:value-of select="$textColor" />
681 </xsl:attribute>
682 </xsl:if>
683</xsl:template>
684
685<!--
686This stylesheet is part of:
687PyOpenOffice Version 0.4
688Copyright (C) 2005: Martin Simon
689Homepage: www.bezirksreiter.de
690
691GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999
692-->
693
694</xsl:stylesheet>
695
696
0697
=== added file 'assembly_bom/report/picking_bom.sxw'
1Binary 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 differ698Binary 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
=== added file 'assembly_bom/report/report_view.xml'
--- assembly_bom/report/report_view.xml 1970-01-01 00:00:00 +0000
+++ assembly_bom/report/report_view.xml 2011-10-06 15:31:48 +0000
@@ -0,0 +1,23 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3<data>
4 <report
5 auto="False"
6 id="report_product_consumption_id"
7 model="product.product"
8 name="product.consumption"
9 rml="addons/assembly_bom/report/consumption_report.rml"
10 string="Product Consumption"
11 menu="False"
12 />
13
14 <!--report
15 auto="False"
16 id="report_delivery_bom_id"
17 model="stock.picking"
18 name="delivery.bom"
19 rml="addons/assembly_bom/report/delivery_report.rml"
20 string="Assembly Delivery Order"
21 /-->
22</data>
23</openerp>
024
=== added file 'assembly_bom/report/tiny_sxw2rml.py'
--- assembly_bom/report/tiny_sxw2rml.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/report/tiny_sxw2rml.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,377 @@
1#!/usr/bin/python
2# -*- encoding: utf-8 -*-
3##############################################################################
4#
5# Copyright (c):
6#
7# 2005 pyopenoffice.py Martin Simon (http://www.bezirksreiter.de)
8# 2005 Fabien Pinckaers, TINY SPRL. (http://tiny.be)
9#
10# WARNING: This program as such is intended to be used by professional
11# programmers who take the whole responsability of assessing all potential
12# consequences resulting from its eventual inadequacies and bugs
13# End users who are looking for a ready-to-use solution with commercial
14# garantees and support are strongly adviced to contact a Free Software
15# Service Company
16#
17# This program is Free Software; you can redistribute it and/or
18# modify it under the terms of the GNU General Public License
19# as published by the Free Software Foundation; either version 2
20# of the License, or (at your option) any later version.
21#
22# This program is distributed in the hope that it will be useful,
23# but WITHOUT ANY WARRANTY; without even the implied warranty of
24# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25# GNU General Public License for more details.
26#
27# You should have received a copy of the GNU General Public License
28# along with this program; if not, write to the Free Software
29# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30#
31##############################################################################
32
33"""
34Tiny SXW2RML - The Open ERP's report engine
35
36Tiny SXW2RMLis part of the Tiny report project.
37Tiny Report is a module that allows you to render high quality PDF document
38from an OpenOffice template (.sxw) and any relationnal database.
39
40The whole source code is distributed under the terms of the
41GNU Public Licence.
42
43(c) 2005 pyopenoffice.py Martin Simon (http://www.bezirksreiter.de)
44(c) 2005-TODAY, Fabien Pinckaers - Tiny sprl
45"""
46__version__ = '0.9'
47
48
49import re
50import string
51import os
52import zipfile
53import xml.dom.minidom
54from reportlab.lib.units import toLength
55import base64
56
57class DomApiGeneral:
58 """General DOM API utilities."""
59 def __init__(self,content_string="",file=""):
60 self.content_string = content_string
61 self.re_digits = re.compile(r"(.*?\d)(pt|cm|mm|inch|in)")
62
63 def _unitTuple(self,string):
64 """Split values and units to a tuple."""
65 temp = self.re_digits.findall(string)
66 if not temp:
67 return (string,"")
68 else:
69 return (temp[0])
70
71 def stringPercentToFloat(self,string):
72 temp = string.replace("""%""","")
73 return float(temp)/100
74
75 def findChildrenByName(self,parent,name,attr_dict={}):
76 """Helper functions. Does not work recursively.
77 Optional: also test for certain attribute/value pairs."""
78 children = []
79 for c in parent.childNodes:
80 if c.nodeType == c.ELEMENT_NODE and c.nodeName == name:
81 children.append(c)
82 if attr_dict == {}:
83 return children
84 else:
85 return self._selectForAttributes(nodelist=children,attr_dict=attr_dict)
86
87 def _selectForAttributes(self,nodelist,attr_dict):
88 "Helper function."""
89 selected_nodes = []
90 for n in nodelist:
91 check = 1
92 for a in attr_dict.keys():
93 if n.getAttribute(a) != attr_dict[a]:
94 # at least one incorrect attribute value?
95 check = 0
96 if check:
97 selected_nodes.append(n)
98 return selected_nodes
99
100 def _stringToTuple(self,s):
101 """Helper function."""
102 try:
103 temp = string.split(s,",")
104 return int(temp[0]),int(temp[1])
105 except:
106 return None
107
108 def _tupleToString(self,t):
109 try:
110 return self.openOfficeStringUtf8("%s,%s" % (t[0],t[1]))
111 except:
112 return None
113
114 def _lengthToFloat(self,value):
115 v = value
116 if not self.re_digits.search(v):
117 return v
118 try:
119 if v[-4:] == "inch":
120 # OO files use "inch" instead of "in" in Reportlab units
121 v = v[:-2]
122 except:
123 pass
124 try:
125 c = round(toLength(v))
126 return c
127 except:
128 return v
129
130 def openOfficeStringUtf8(self,string):
131 if type(string) == unicode:
132 return string.encode("utf-8")
133 tempstring = unicode(string,"cp1252").encode("utf-8")
134 return tempstring
135
136class DomApi(DomApiGeneral):
137 """This class provides a DOM-API for XML-Files from an SXW-Archive."""
138 def __init__(self,xml_content,xml_styles):
139 DomApiGeneral.__init__(self)
140 self.content_dom = xml.dom.minidom.parseString(xml_content)
141 self.styles_dom = xml.dom.minidom.parseString(xml_styles)
142 body = self.content_dom.getElementsByTagName("office:body")
143 self.body = body and body[0]
144
145 # TODO:
146 self.style_dict = {}
147 self.style_properties_dict = {}
148
149 # ******** always use the following order:
150 self.buildStyleDict()
151 self.buildStylePropertiesDict()
152 if self.styles_dom.getElementsByTagName("style:page-master").__len__()<>0:
153 self.page_master = self.styles_dom.getElementsByTagName("style:page-master")[0]
154 if self.styles_dom.getElementsByTagName("style:page-layout").__len__()<>0 :
155 self.page_master = self.styles_dom.getElementsByTagName("style:page-layout")[0]
156 self.document = self.content_dom.getElementsByTagName("office:document-content")[0]
157
158 def buildStylePropertiesDict(self):
159 for s in self.style_dict.keys():
160 self.style_properties_dict[s] = self.getStylePropertiesDict(s)
161
162 def updateWithPercents(self,dict,updatedict):
163 """Sometimes you find values like "115%" in the style hierarchy."""
164 if not updatedict:
165 # no style hierarchies for this style? =>
166 return
167 new_updatedict = copy.copy(updatedict)
168 for u in new_updatedict.keys():
169 try:
170 if new_updatedict[u].find("""%""") != -1 and dict.has_key(u):
171 number = float(self.re_digits.search(dict[u]).group(1))
172 unit = self.re_digits.search(dict[u]).group(2)
173 new_number = self.stringPercentToFloat(new_updatedict[u]) * number
174 if unit == "pt":
175 new_number = int(new_number)
176 # no floats allowed for "pt"
177 # OOo just takes the int, does not round (try it out!)
178 new_updatedict[u] = "%s%s" % (new_number,unit)
179 else:
180 dict[u] = new_updatedict[u]
181 except:
182 dict[u] = new_updatedict[u]
183 dict.update(new_updatedict)
184
185 def normalizeStyleProperties(self):
186 """Transfer all style:style-properties attributes from the
187 self.style_properties_hierarchical dict to the automatic-styles
188 from content.xml. Use this function to preprocess content.xml for
189 XSLT transformations etc.Do not try to implement this function
190 with XSlT - believe me, it's a terrible task..."""
191 styles_styles = self.styles_dom.getElementsByTagName("style:style")
192 automatic_styles = self.content_dom.getElementsByTagName("office:automatic-styles")[0]
193 for s in styles_styles:
194 automatic_styles.appendChild(s.cloneNode(deep=1))
195 content_styles = self.content_dom.getElementsByTagName("style:style")
196 # these are the content_styles with styles_styles added!!!
197 for s in content_styles:
198 c = self.findChildrenByName(s,"style:properties")
199 if c == []:
200 # some derived automatic styles do not have "style:properties":
201 temp = self.content_dom.createElement("style:properties")
202 s.appendChild(temp)
203 c = self.findChildrenByName(s,"style:properties")
204 c = c[0]
205 dict = self.style_properties_dict[(s.getAttribute("style:name")).encode("utf-8")] or {}
206 for attribute in dict.keys():
207 c.setAttribute(self.openOfficeStringUtf8(attribute),self.openOfficeStringUtf8(dict[attribute]))
208
209 def transferStylesXml(self):
210 """Transfer certain sub-trees from styles.xml to the normalized content.xml
211 (see above). It is not necessary to do this - for example - with paragraph styles.
212 the "normalized" style properties contain all information needed for
213 further processing."""
214 # TODO: What about table styles etc.?
215 outline_styles = self.styles_dom.getElementsByTagName("text:outline-style")
216 t = self.content_dom.createElement("transferredfromstylesxml")
217 self.document.insertBefore(t,self.body)
218 t_new = self.body.previousSibling
219 try:
220 page_master = self.page_master
221 t_new.appendChild(page_master.cloneNode(deep=1))
222 t_new.appendChild(outline_styles[0].cloneNode(deep=1))
223 except:
224 pass
225
226 def normalizeLength(self):
227 """Normalize all lengthes to floats (i.e: 1 inch = 72).
228 Always use this after "normalizeContent" and "transferStyles"!"""
229 # TODO: The complex attributes of table cell styles are not transferred yet.
230 #all_styles = self.content_dom.getElementsByTagName("style:properties")
231 #all_styles += self.content_dom.getElementsByTagName("draw:image")
232 all_styles = self.content_dom.getElementsByTagName("*")
233 for s in all_styles:
234 for x in s._attrs.keys():
235 v = s.getAttribute(x)
236 s.setAttribute(x,"%s" % self._lengthToFloat(v))
237 # convert float to string first!
238
239 def normalizeTableColumns(self):
240 """Handle this strange table:number-columns-repeated attribute."""
241 columns = self.content_dom.getElementsByTagName("table:table-column")
242 for c in columns:
243 if c.hasAttribute("table:number-columns-repeated"):
244 number = int(c.getAttribute("table:number-columns-repeated"))
245 c.removeAttribute("table:number-columns-repeated")
246 for i in range(number-1):
247 (c.parentNode).insertBefore(c.cloneNode(deep=1),c)
248
249 def buildStyleDict(self):
250 """Store all style:style-nodes from content.xml and styles.xml in self.style_dict.
251 Caution: in this dict the nodes from two dom apis are merged!"""
252 for st in (self.styles_dom,self.content_dom):
253 for s in st.getElementsByTagName("style:style"):
254 name = s.getAttribute("style:name").encode("utf-8")
255 self.style_dict[name] = s
256 return True
257
258 def toxml(self):
259 return self.content_dom.toxml(encoding="utf-8")
260
261 def getStylePropertiesDict(self,style_name):
262 res = {}
263
264 if self.style_dict[style_name].hasAttribute("style:parent-style-name"):
265 parent = self.style_dict[style_name].getAttribute("style:parent-style-name").encode("utf-8")
266 res = self.getStylePropertiesDict(parent)
267
268 childs = self.style_dict[style_name].childNodes
269 for c in childs:
270 if c.nodeType == c.ELEMENT_NODE and c.nodeName.find("properties")>0 :
271 for attr in c._attrs.keys():
272 res[attr] = c.getAttribute(attr).encode("utf-8")
273 return res
274
275class PyOpenOffice(object):
276 """This is the main class which provides all functionality."""
277 def __init__(self, path='.', save_pict=False):
278 self.path = path
279 self.save_pict = save_pict
280 self.images = {}
281
282 def oo_read(self,fname):
283 z = zipfile.ZipFile(fname,"r")
284 content = z.read('content.xml')
285 style = z.read('styles.xml')
286 all = z.namelist()
287 for a in all:
288 if a[:9]=='Pictures/' and len(a)>10:
289 pic_content = z.read(a)
290 self.images[a[9:]] = pic_content
291 if self.save_pict:
292 f=open(os.path.join(self.path, os.path.basename(a)),"wb")
293 f.write(pic_content)
294 f.close()
295 z.close()
296 return content,style
297
298 def oo_replace(self,content):
299 regex = [
300 (r"<para[^>]*/>", ""),
301 #(r"<text:ordered-list.*?>(.*?)</text:ordered-list>", "$1"),
302 #(r"<text:unordered-list.*?>(.*?)</text:unordered-list>", "$1"),
303 (r"<para(.*)>(.*?)<text:line-break[^>]*/>", "<para$1>$2</para><para$1>"),
304 ]
305 for key,val in regex:
306 content = re.sub(key, val, content)
307 return content
308
309 def unpackNormalize(self,sourcefile):
310 c,s = self.oo_read(sourcefile)
311 c = self.oo_replace(c)
312 dom = DomApi(c,s)
313 dom.normalizeStyleProperties()
314 dom.transferStylesXml()
315 dom.normalizeLength()
316 dom.normalizeTableColumns()
317 new_c = dom.toxml()
318 return new_c
319
320def sxw2rml(sxw_file, xsl, output='.', save_pict=False):
321 from lxml import etree
322 from StringIO import StringIO
323
324 tool = PyOpenOffice(output, save_pict = save_pict)
325 res = tool.unpackNormalize(sxw_file)
326
327 f = StringIO(xsl)
328 styledoc = etree.parse(f)
329 style = etree.XSLT(styledoc)
330
331 f = StringIO(res)
332 doc = etree.parse(f)
333 result = style(doc)
334 root = etree.XPathEvaluator(result)("/document/stylesheet")
335
336 if root:
337 root=root[0]
338 images = etree.Element("images")
339 for img in tool.images:
340 node = etree.Element('image', name=img)
341 node.text = base64.encodestring(tool.images[img])
342 images.append(node)
343 root.append(images)
344
345 try:
346 xml = str(result)
347 return xml
348 except:
349 return result
350
351if __name__ == "__main__":
352 import optparse
353 parser = optparse.OptionParser(
354 version="Tiny Report v%s" % __version__,
355 usage = 'tiny_sxw2rml.py [options] file.sxw')
356 parser.add_option("-v", "--verbose", default=False, dest="verbose", help="enable basic debugging")
357 parser.add_option("-o", "--output", dest="output", default='.', help="directory of image output")
358 (opt, args) = parser.parse_args()
359 if len(args) != 1:
360 parser.error("incorrect number of arguments")
361
362 import sys
363 import StringIO
364
365 fname = sys.argv[1]
366 f = fname
367 xsl_file = 'normalized_oo2rml.xsl'
368 z = zipfile.ZipFile(fname,"r")
369 mimetype = z.read('mimetype')
370 if mimetype.split('/')[-1] == 'vnd.oasis.opendocument.text' :
371 xsl_file = 'normalized_odt2rml.xsl'
372 xsl = file(os.path.join(os.getcwd(), os.path.dirname(sys.argv[0]), xsl_file)).read()
373 result = sxw2rml(f, xsl, output=opt.output, save_pict=False)
374
375 print result
376# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
377
0378
=== added file 'assembly_bom/sale.py'
--- assembly_bom/sale.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/sale.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,71 @@
1# -*- ecoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23from osv import fields, osv
24import netsvc
25import datetime
26import time
27from tools.translate import _
28
29class sale_order_line(osv.osv):
30 _inherit = 'sale.order.line'
31 def product_id_change(self, cr, uid, ids, pricelist, product, qty=0,
32 uom=False, qty_uos=0, uos=False, name='', partner_id=False,
33 lang=False, update_tax=True, date_order=False, packaging=False, fiscal_position=False, flag=False,partner_shipping_id=False, shop_id=False, context={}):
34
35 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)
36 if not ret.get('warning') and product:
37 product_obj = self.pool.get('product.product')
38 product_uom_obj = self.pool.get('product.uom')
39 product_obj = product_obj.browse(cr, uid, product, context=context)
40 uom2 = False
41 if uom:
42 uom2 = product_uom_obj.browse(cr, uid, uom)
43 if product_obj.uom_id.category_id.id != uom2.category_id.id:
44 uom = False
45
46 if (product_obj.type=='product') and product_obj.procure_method=='make_to_order':
47 bom_id = self.pool.get('mrp.bom').search(cr, uid, [
48 ('product_id', '=', product_obj.id),
49 ('bom_id', '=', False),
50 ('type', '=', 'assembly')])
51 if bom_id:
52 bom_id = bom_id[0]
53 bom_obj = self.pool.get('mrp.bom').browse(cr, uid, bom_id)
54 if bom_id and 'bom_stock_value' in bom_obj._columns.keys() and (bom_obj.bom_stock_value < qty * product_obj.uom_id.factor):
55 warning = {
56 'title': _('Not enough stock !'),
57 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') %
58 (qty, uom2 and uom2.name or product_obj.uom_id.name,
59 max(0,bom_obj.bom_stock_value), product_obj.uom_id.name,
60 max(0,product_obj.qty_available), product_obj.uom_id.name)
61 }
62 ret['warning'] = warning
63 return ret
64sale_order_line()
65
66
67
68
69
70
71# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0\ No newline at end of file72\ No newline at end of file
173
=== added file 'assembly_bom/stock.py'
--- assembly_bom/stock.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/stock.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,378 @@
1# -*- ecoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23from osv import fields, osv
24import netsvc
25import datetime
26import time
27from tools.translate import _
28
29class StockMove(osv.osv):
30 _inherit = 'stock.move'
31
32 def _action_explode(self, cr, uid, move, context=None):
33 """ Explodes pickings to produce many moves as per the bom lines for products assembly bom.
34 @param move: Stock moves
35 @constraints: explode takes place for pickings related to sale order
36 @return: True
37 """
38 result=super(StockMove, self)._action_explode(cr, uid, move, context=context)
39 bom_obj = self.pool.get('mrp.bom')
40 move_obj = self.pool.get('stock.move')
41 procurement_obj = self.pool.get('procurement.order')
42 product_obj = self.pool.get('product.product')
43 wf_service = netsvc.LocalService("workflow")
44 production_obj=self.pool.get('mrp.production')
45 if move.product_id.supply_method == 'produce' and move.product_id.procure_method == 'make_to_order':
46 bis = bom_obj.search(cr, uid, [
47 ('product_id','=',move.product_id.id),
48 ('bom_id','=',False),
49 ('type','=','assembly')])
50 if bis:
51 factor = move.product_qty
52 bom_point = bom_obj.browse(cr, uid, bis[0], context=context)
53 res = bom_obj._bom_explode(cr, uid, bom_point, factor, [])
54 dest = move.product_id.product_tmpl_id.property_stock_production.id
55
56 if move.sale_line_id:
57
58 #1. partial delivery is not allowed for kit type bom product
59 move.picking_id.write({'move_type':'one'})
60
61 #2. manually changing the state to confirmed for each exploded move to allow checking bom stock value
62 #related to mrp_jit
63 state = 'confirmed'
64 if move.state == 'assigned':
65 state = 'assigned'
66 if res[0] and res[0][0]:
67 line=res[0][0]
68 valdef = {
69 'picking_id': move.picking_id.id,
70 'product_id': line['product_id'],
71 'product_uom': line['product_uom'],
72 'product_qty': line['product_qty'],
73 'product_uos': line['product_uos'],
74 'product_uos_qty': line['product_uos_qty'],
75 'move_dest_id': move.id,
76 'state': state,
77 'name': line['name'],
78 'location_dest_id': dest,
79 #'move_history_ids': [(6,0,[move.id])],
80 #'move_history_ids2': [(6,0,[])],
81 'procurements': [],
82 'sale_line_id':False,
83 "kit_id":False,
84 "parent_bom_id":bis[0],
85 'sale_id':move.sale_line_id.order_id.id
86
87 }
88 move.write(valdef)
89
90 for line in res[0][1:]:
91 valdef = {
92 'picking_id': move.picking_id.id,
93 'product_id': line['product_id'],
94 'product_uom': line['product_uom'],
95 'product_qty': line['product_qty'],
96 'product_uos': line['product_uos'],
97 'product_uos_qty': line['product_uos_qty'],
98 'move_dest_id': move.id,
99 'state': state,
100 'name': line['name'],
101 'location_dest_id': dest,
102 #'move_history_ids': [(6,0,[move.id])],
103 #'move_history_ids2': [(6,0,[])],
104 'procurements': [],
105 'sale_line_id':False,
106 "kit_id":False,
107 "parent_bom_id":bis[0],
108 'sale_id':move.sale_line_id.order_id.id
109 }
110 mid = move_obj.copy(cr, uid, move.id, default=valdef)
111 move_obj.action_assign(cr, uid, [mid])
112 prodobj = product_obj.browse(cr, uid, line['product_id'], context=context)
113
114 cr.commit()
115 return result
116
117
118 _columns={
119 'sale_id': fields.many2one('sale.order',"Sale Reference"),
120 'kit_id':fields.many2one('mrp.production',"Assembly"),
121 'production_ids': fields.many2many('mrp.production', 'mrp_production_move_ids', 'move_id', 'production_id', 'Related Production'),
122 'parent_bom_id':fields.many2one("mrp.bom",'Related Bom')
123 }
124 def onchange_quantity(self, cr, uid, ids, product_id, product_qty,
125 product_uom, product_uos,location_id=False):
126 """ On change of product quantity finds UoM and UoS quantities
127 @param product_id: Product id
128 @param product_qty: Changed Quantity of product
129 @param product_uom: Unit of measure of product
130 @param product_uos: Unit of sale of product
131 @return: Dictionary of values
132 """
133 context={}
134 if location_id:
135 context['location'] =[location_id]
136 result=super(StockMove,self).onchange_quantity(cr, uid, ids, product_id, product_qty, product_uom, product_uos)
137 if (not product_id) or (product_qty <=0.0):
138 return result
139 product_obj = self.pool.get('product.product').browse(cr, uid, [product_id],context=context)[0]
140 uom2 = product_obj.uom_id
141 if (product_obj.type=='product') and (product_obj.virtual_available * uom2.factor < product_qty * product_obj.uom_id.factor) \
142 and (product_obj.procure_method=='make_to_stock'):
143 warning = {
144 'title': _('Not enough stock !'),
145 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') %
146 (product_qty, uom2 and uom2.name or product_obj.uom_id.name,
147 max(0,product_obj.virtual_available), product_obj.uom_id.name,
148 max(0,product_obj.qty_available), product_obj.uom_id.name)
149 }
150 result['warning'] = warning
151
152 if (product_obj.type=='product') and product_obj.procure_method=='make_to_order':
153 bom_id = self.pool.get('mrp.bom').search(cr, uid, [
154 ('product_id', '=', product_obj.id),
155 ('bom_id', '=', False)])
156 bom_obj = False
157 if bom_id:
158 bom_obj = self.pool.get('mrp.bom').browse(cr, uid, bom_id[0])
159
160 if bom_obj and (bom_obj.bom_stock_value < product_qty * product_obj.uom_id.factor) \
161 and (product_obj.procure_method=='make_to_order'):
162 warning = {
163 'title': _('Not enough stock !'),
164 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') %
165 (product_qty, uom2 and uom2.name or product_obj.uom_id.name,
166 max(0,bom_obj.bom_stock_value), product_obj.uom_id.name,
167 max(0,product_obj.qty_available), product_obj.uom_id.name)
168 }
169 result['warning'] = warning
170
171 return result
172 def onchange_product_id(self, cr, uid, ids, prod_id=False, loc_id=False,
173 loc_dest_id=False, address_id=False,product_qty=0):
174 """ On change of product id, .
175 @param prod_id: Changed Product id
176 @param loc_id: Source location id
177 @param loc_id: Destination location id
178 @param address_id: Address id of partner
179 @param product_qty: Product Quantity
180 @return: Dictionary of values
181 """
182 warning = {}
183 context = {}
184 res=super(StockMove,self).onchange_product_id(cr, uid, ids, prod_id=prod_id, loc_id=loc_id,
185 loc_dest_id=loc_dest_id, address_id=address_id)
186 if not prod_id:
187 return res
188 if loc_id:
189 context['location'] = [loc_id]
190 product_obj = self.pool.get('product.product').browse(cr, uid, [prod_id],context=context)[0]
191 uom2 = product_obj.uom_id
192 if (product_obj.type=='product') and (product_obj.virtual_available * uom2.factor < product_qty * product_obj.uom_id.factor) \
193 and (product_obj.procure_method=='make_to_stock'):
194 warning = {
195 'title': _('Not enough stock !'),
196 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') %
197 (product_qty, uom2 and uom2.name or product_obj.uom_id.name,
198 max(0,product_obj.virtual_available), product_obj.uom_id.name,
199 max(0,product_obj.qty_available), product_obj.uom_id.name)
200 }
201 res['warning'] = warning
202 if (product_obj.type=='product') and product_obj.procure_method=='make_to_order':
203 bom_id = self.pool.get('mrp.bom').search(cr, uid, [
204 ('product_id', '=', product_obj.id),
205 ('bom_id', '=', False)])
206 if bom_id:
207 bom_obj = self.pool.get('mrp.bom').browse(cr, uid, bom_id[0])
208 if bom_id and (bom_obj.bom_stock_value < product_qty * product_obj.uom_id.factor):
209 warning = {
210 'title': _('Not enough stock !'),
211 'message': _('You plan to move %.2f %s but you only have %.2f %s available !\nThe real stock is %.2f %s. (without reservations)') %
212 (product_qty, uom2 and uom2.name or product_obj.uom_id.name,
213 max(0,bom_obj.bom_stock_value), product_obj.uom_id.name,
214 max(0,product_obj.qty_available), product_obj.uom_id.name)
215 }
216 res['warning'] = warning
217 return res
218 _defaults = {
219 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
220 'date_expected': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
221 }
222
223StockMove()
224
225
226class stock_picking(osv.osv):
227 _inherit="stock.picking"
228
229 def do_partial(self, cr, uid, ids, partial_datas, context=None):
230 """Creates and processes the assembly (MO) operation for delivery of product with assembly bom during sale
231 @param self: The object pointer.
232 @param ids: ids of the procurement order document
233 @param context: standard dictionary
234 @comment: Creates Production order for assembly of the product with assembly bom and
235 deliveres the product to customers making moves to ensure stock tracking
236 @return: returns dictionary carrying delivered picking details
237 """
238 bom_obj = self.pool.get('mrp.bom')
239 picking_obj=self.pool.get('stock.picking')
240 produce_wiz_obj=self.pool.get("mrp.product.produce")
241 production_obj=self.pool.get('mrp.production')
242 move_obj=self.pool.get("stock.move")
243 sale_obj=self.pool.get("sale.order")
244 wf_service=netsvc.LocalService('workflow')
245 res=super(stock_picking,self).do_partial(cr, uid, ids, partial_datas)
246 picking_details=res.values()
247 picking_id=picking_details and picking_details[0].get('delivered_picking',False) or False
248 if picking_id:
249 #expecting the picking state will not be 'done'
250 picking=picking_obj.browse(cr,uid,picking_id,context=context)
251 sale_order=picking.sale_id
252 if not sale_order:
253 return res
254
255 sale_obj.action_ship_end(cr, uid, [picking.sale_id.id], context=context)
256 for line in sale_order.order_line:
257 bom_ids=bom_obj.search(cr,uid,[('product_id','=',line.product_id.id)],context={})
258# procure_id=production_obj.create(cr,uid,{ 'name':'ASSEMBLY'+sale_order.name,
259 bom_id=bom_ids and bom_ids[0] or False
260 if bom_id:
261 bom=bom_obj.browse(cr,uid,bom_id)
262 if bom and bom.type=='normal':
263 move_ids=[move.id for move in picking.move_lines] or []
264 normal_move_ids=move_obj.search(cr,uid,[('id','in',move_ids),('product_id','=',line.product_id.id)])
265 ###Expecting
266 #1. Sale order is having only one line with the product having normal bom
267 if normal_move_ids:
268 normal_move_id=normal_move_ids[0]#Refer:#1
269 normal_move=move_obj.browse(cr,uid,normal_move_id)
270 normal_move.write({
271 'sale_id':line.order_id.id
272 })
273
274 if bom and bom.type=='assembly':
275 #1. Warehouse stock and output location selected as stock and output
276 stock_id = sale_order.shop_id.warehouse_id.lot_stock_id.id#stock location
277 output_id = sale_order.shop_id.warehouse_id.lot_output_id.id#output warehouse location
278 #2. sale partner customer location selected as customer
279 customer_loc_id=sale_order.partner_id.property_stock_customer.id or False#customer location
280 mo_sequence=self.pool.get('ir.sequence').get(cr, uid, 'mrp.production')
281 src_loc_id=line.product_id.property_stock_production.id#stock location_id
282 production_id=production_obj.create(cr,uid,{
283 'name': mo_sequence or sale_order.name,
284 'origin':sale_order.name,
285 'product_id':line.product_id.id,
286 'product_qty':line.product_uom_qty,
287 'product_uom':line.product_uom.id,
288 'product_uos_qty':(line.product_uos and line.product_uos_qty)\
289 or line.product_uom_qty,
290 'product_uos':(line.product_uos and line.product_uos.id)\
291 or line.product_uom.id,
292 'location_src_id':src_loc_id,
293 # 'location_dest_id':sale_order.shop_id.warehouse_id.lot_stock_id.id,
294 'location_dest_id':stock_id,
295 'date_start':time.strftime('%Y-%m-%d'),
296 'bom_id':bom_ids and bom_ids[0] or False,
297 'picking_id':picking_id,
298 # 'procure_id':line.procurement_id.id,
299 },context=context)
300
301 # 3.To suit sale order with multiple lines its achieved by comparing the product in production order
302 # and the one sold and the one associated with the parent_bom stored in the move object
303
304 for move in picking.move_lines:
305 sold_product_id=line.product_id.id
306 parent_product_id=move.parent_bom_id and move.parent_bom_id.product_id.id or False
307 if parent_product_id and parent_product_id==sold_product_id:
308 move.write({'kit_id':production_id})
309
310
311 production=production_obj.browse(cr,uid,production_id)
312 wf_service.trg_validate(uid, 'mrp.production', production_id, 'button_confirm', cr)
313 move_ids=[move.id for move in production.move_lines]
314 move_obj.write(cr,uid,move_ids,{'sale_id':line.order_id.id},context=context)
315 production_obj.force_production(cr, uid, [production_id])
316 move_ids=[move.id for move in production.move_lines]
317 production_obj.action_produce(cr, uid, production_id,production.product_qty,'consume_produce')
318 wf_service.trg_validate(uid, 'mrp.production',production_id,'button_produce_done', cr)
319 date_planned=time.strftime('%Y-%m-%d')
320 cr.commit()
321 production=production_obj.browse(cr,uid,production_id)
322 production_finished=(production.state=='done')
323 if production_finished:
324 finished_ids=[move.id for move in production.move_created_ids2]
325
326 move_obj.write(cr,uid,finished_ids,{'sale_id':line.order_id.id},context=context)
327
328 finished_move_stock_id = self.pool.get('stock.move').create(cr, uid, {
329 'name': line.name[:64],
330 'picking_id': False,
331 'product_id': line.product_id.id,
332 'date': time.strftime('%Y-%m-%d'),
333 'date_expected': time.strftime('%Y-%m-%d'),
334 'product_qty': line.product_uom_qty,
335 'product_uom': line.product_uom.id,
336 'product_uos_qty': line.product_uos_qty,
337 'product_uos': (line.product_uos and line.product_uos.id)\
338 or line.product_uom.id,
339 'product_packaging': line.product_packaging.id,
340 'address_id': line.address_allotment_id.id or sale_order.partner_shipping_id.id,
341 'location_id': stock_id,
342 'location_dest_id':output_id,#move destination to output location of the warehouse
343 'sale_line_id': line.id,
344 'tracking_id': False,
345 'state': 'draft',
346 #'state': 'waiting',
347 'note': line.notes,
348 'kit_id':False,
349 'company_id': sale_order.company_id.id,
350 'sale_id': sale_order.id,
351 })
352
353 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
354
355 status=move_obj.action_confirm(cr,uid,[finished_move_stock_id,move2_id])
356
357 move_obj.action_done(cr,uid,[finished_move_stock_id,move2_id])
358 return res
359
360 def action_confirm(self, cr, uid, ids, context=None):
361 res=super(stock_picking,self).action_confirm(cr, uid, ids, context)
362 cr.commit()
363 try:
364 self.action_assign(cr, uid, ids)
365 except Exception, e:
366 print e
367 return True
368 _defaults = {
369 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
370 }
371
372
373stock_picking()
374
375
376
377# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
378
0379
=== added file 'assembly_bom/stock_view.xml'
--- assembly_bom/stock_view.xml 1970-01-01 00:00:00 +0000
+++ assembly_bom/stock_view.xml 2011-10-06 15:31:48 +0000
@@ -0,0 +1,100 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5
6 <record id="view_picking_out_form_inherit" model="ir.ui.view">
7 <field name="name">stock.picking.out.form.inherit</field>
8 <field name="model">stock.picking</field>
9 <field name="type">form</field>
10 <field name="inherit_id" ref="stock.view_picking_out_form" />
11 <field name="arch" type="xml">
12 <xpath expr="//field/form/group/field[@name='product_id']" position="replace">
13 <field name="product_id" on_change="onchange_product_id(product_id,location_id,location_dest_id, parent.address_id, product_qty)" colspan="4"/>
14 </xpath>
15 <xpath expr="//form/group/field[@name='product_qty']" position="replace">
16 <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)" colspan="3" />
17 </xpath>
18 <xpath expr="//tree/field[@name='product_qty']" position="replace">
19 <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)" />
20 </xpath>
21 </field>
22 </record>
23
24
25 <record id="view_picking_form_inherit" model="ir.ui.view">
26 <field name="name">stock.picking.forminherit</field>
27 <field name="model">stock.picking</field>
28 <field name="type">form</field>
29 <field name="inherit_id" ref="stock.view_picking_form" />
30 <field name="arch" type="xml">
31 <xpath expr="//field/form/group/field[@name='product_id']" position="replace">
32 <field name="product_id" on_change="onchange_product_id(product_id,location_id,location_dest_id, parent.address_id, product_qty)" colspan="4"/>
33 </xpath>
34 <xpath expr="//form/group/field[@name='product_qty']" position="replace">
35 <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)" colspan="3" />
36 </xpath>
37 <xpath expr="//tree/field[@name='product_qty']" position="replace">
38 <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)" />
39 </xpath>
40 </field>
41 </record>
42
43 <record id="view_move_form_inherit22" model="ir.ui.view">
44 <field name="name">stock.move.form.inherit</field>
45 <field name="model">stock.move</field>
46 <field name="type">form</field>
47 <field eval="4" name="priority"/>
48 <field name="inherit_id" ref="stock.view_move_form" />
49 <field name="arch" type="xml">
50 <data>
51 <xpath expr="//field[@name='prodlot_id']" position="after">
52 <field name="sale_id" readonly="1" select="1" />
53 </xpath>
54 <xpath expr="//field[@name='product_id']" position="replace">
55 <field name="product_id" on_change="onchange_product_id(product_id,location_id,location_dest_id, False, product_qty)"/>
56 </xpath>
57 <xpath expr="//field[@name='product_qty']" position="replace">
58 <field name="product_qty" on_change="onchange_quantity(product_id, product_qty, product_uom, product_uos,location_id)"/>
59 </xpath>
60
61 </data>
62 </field>
63 </record>
64
65
66 <record id="view_move_tree_inherit22" model="ir.ui.view">
67 <field name="name">stock.move.tree_inherit</field>
68 <field name="model">stock.move</field>
69 <field name="type">tree</field>
70 <field eval="6" name="priority"/>
71 <field name="inherit_id" ref="stock.view_move_tree" />
72 <field name="arch" type="xml">
73 <data>
74 <xpath expr="//field[@name='origin']" position="after">
75 <field name="sale_id" readonly="1"/>
76 </xpath>
77 </data>
78 </field>
79 </record>
80
81 <record id="view_move_search_inherit22" model="ir.ui.view">
82 <field name="name">stock.move.search_inherit</field>
83 <field name="model">stock.move</field>
84 <field name="type">search</field>
85 <field eval="3" name="priority"/>
86 <field name="inherit_id" ref="stock.view_move_search" />
87 <field name="arch" type="xml">
88 <data>
89 <xpath expr="//field[@name='origin']" position="after">
90 <field name="sale_id" />
91 </xpath>
92 </data>
93 </field>
94 </record>
95
96
97
98
99 </data>
100</openerp>
0101
=== added directory 'assembly_bom/wizard'
=== added file 'assembly_bom/wizard/__init__.py'
--- assembly_bom/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/wizard/__init__.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,24 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22
23import consumption_report_wizard
24# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0\ No newline at end of file25\ No newline at end of file
126
=== added file 'assembly_bom/wizard/consumption_report_wizard.py'
--- assembly_bom/wizard/consumption_report_wizard.py 1970-01-01 00:00:00 +0000
+++ assembly_bom/wizard/consumption_report_wizard.py 2011-10-06 15:31:48 +0000
@@ -0,0 +1,93 @@
1# -*- encoding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (C) 2011 NovaPoint Group LLC (<http://www.novapointgroup.com>)
6# Copyright (C) 2004-2010 OpenERP SA (<http://www.openerp.com>)
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU General Public License as published by
10# the Free Software Foundation, either version 3 of the License, or
11# (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>
20#
21##############################################################################
22import wizard
23import pooler
24from osv import osv,fields
25import tools
26from tools.translate import _
27
28class consumption_report_wizard(osv.osv_memory):
29
30 def print_consumption_report(self,cr,uid,ids,context={}):
31 """ Updates the context with the details given in the wizard form
32 @param self: The object pointer.
33 @param ids: ids of the procurement order document
34 @param context: standard dictionary
35 @comment: The data for stock move analysis is passed through context
36 @return: returns standard dictionary to make report
37 """
38 data = self.read(cr, uid, ids[0])
39 warehouse_id=data and data.get('warehouse_id',False) or False
40 start_date=data and data.get('start_date',False) or False
41 end_date=data and data.get('end_date',False) or False
42 warehouse=self.pool.get('stock.warehouse').browse(cr,uid,warehouse_id)
43 product_ids=context.get('active_ids',[])
44 source_loc_id=warehouse.lot_stock_id and warehouse.lot_stock_id.id or False
45 return {
46 'type': 'ir.actions.report.xml',
47 'report_name':"product.consumption",
48 'datas': {
49 'model':'product.product',
50 'id': product_ids and product_ids[0] or False,
51 'ids': product_ids and product_ids or [],
52 'report_type': 'pdf',
53 },
54 'nodestroy': False,
55 'context':{
56 "source_loc_id":source_loc_id,
57 "start_date":start_date,
58 "end_date":end_date
59 },
60
61 }
62
63 _name="product.consumption"
64 _columns={
65 'warehouse_id':fields.many2one('stock.warehouse','Select Your Warehouse'),
66 'start_date':fields.date("Start Date"),
67 'end_date':fields.date("End Date")
68
69 }
70
71
72 def _get_warehouse(self, cr, uid, context=None):
73 """ Fetches the default warehouse
74 @param self: The object pointer.
75 @param ids: ids of the procurement order document
76 @param context: standard dictionary
77 @comment: Pre-fills the warehouse field by the ware house related to user company
78 @return: returns standard dictionary to make report
79 """
80 cmpny_id = self.pool.get('res.users')._get_company(cr, uid, context=context)
81 shop = self.pool.get('sale.shop').search(cr, uid, [('company_id', '=', cmpny_id)])
82 if shop:
83 shop_obj = self.pool.get('sale.shop').browse(cr, uid, shop[0], context=context)
84 return shop_obj.warehouse_id and shop_obj.warehouse_id.id
85 return False
86
87 _defaults = {
88 'warehouse_id': _get_warehouse,
89 }
90
91consumption_report_wizard()
92
93
094
=== added file 'assembly_bom/wizard/consumption_report_wizard.xml'
--- assembly_bom/wizard/consumption_report_wizard.xml 1970-01-01 00:00:00 +0000
+++ assembly_bom/wizard/consumption_report_wizard.xml 2011-10-06 15:31:48 +0000
@@ -0,0 +1,43 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <!-- Make Procurement -->
6
7 <record id="view_product_consumption_id" model="ir.ui.view">
8 <field name="name">Product Consumption</field>
9 <field name="model">product.consumption</field>
10 <field name="type">form</field>
11 <field name="arch" type="xml">
12 <form string="Product Consumption">
13 <field name="warehouse_id" colspan="4" required="1"/>
14 <newline/>
15 <field name="start_date" colspan="2"/>
16 <field name="end_date" colspan="2" />
17 <button type="object" name="print_consumption_report" icon="gtk-print" string="Print"/>
18 <button special="cancel" icon="gtk-cancel" string="Cancel"/>
19 </form>
20 </field>
21 </record>
22
23
24
25 <act_window name="Product Consumption"
26 res_model="product.consumption"
27 src_model="product.product"
28 view_mode="form"
29 target="new"
30 key2="client_print_multi"
31 id="act_product_consumption_id"
32 />
33
34
35 <!--wizard
36 string="Consumption Report xxx"
37 model="product.product"
38 name="product.consumption.wiz"
39 keyword="client_print_multi"
40 id="product_consumption_wizard_id"/-->
41
42 </data>
43</openerp>
0\ No newline at end of file44\ No newline at end of file

Subscribers

People subscribed via source and target branches

to all changes: