[IMP]:mrp:Product Cost Structure Report
[odoo/odoo.git] / addons / mrp / report / price.py
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 import time
22 import ir
23 import pooler
24 from report.interface import report_rml
25 from report.interface import toxml
26 from tools import to_xml
27 from report import report_sxw
28 from datetime import datetime
29 from tools.translate import _
30
31
32 #FIXME: we should use toxml
33 class report_custom(report_rml):
34     def create_xml(self, cr, uid, ids, datas, context={}):
35         number = (datas.get('form', False) and datas['form']['number']) or 1
36         pool = pooler.get_pool(cr.dbname)
37         product_pool = pool.get('product.product')
38         product_uom_pool = pool.get('product.uom')
39         supplier_info_pool = pool.get('product.supplierinfo')
40         workcenter_pool = pool.get('mrp.workcenter')
41         user_pool = pool.get('res.users')
42         bom_pool = pool.get('mrp.bom')
43         rml_obj=report_sxw.rml_parse(cr, uid, product_pool._name,context)
44         rml_obj.localcontext.update({'lang':context.get('lang',False)})
45         company_currency = user_pool.browse(cr, uid, uid).company_id.currency_id
46         def process_bom(bom, currency_id, factor=1):
47             xml = '<row>'
48             sum = 0
49             sum_strd = 0
50             prod = product_pool.browse(cr, uid, bom['product_id'])
51
52             prod_name = bom['name']
53             prod_qtty = factor * bom['product_qty']
54             product_uom = product_uom_pool.browse(cr, uid, bom['product_uom'], context=context)
55             level = 1
56             main_sp_price, main_sp_name , main_strd_price = '','',''
57             sellers, sellers_price = '',''
58
59             if prod.seller_id:
60                 main_sp_name = "<b>%s</b>\r\n" %(prod.seller_id.name)
61                 price = supplier_info_pool.price_get(cr, uid, prod.seller_id.id, prod.id, number*prod_qtty)[prod.seller_id.id]
62                 price = product_uom_pool._compute_price(cr, uid, prod.uom_id.id, price, to_uom_id=product_uom.id)
63                 main_sp_price = """<b>"""+rml_obj.formatLang(price)+' '+ company_currency.symbol+"""</b>\r\n"""
64                 sum += prod_qtty*price
65             std_price = product_uom_pool._compute_price(cr, uid, prod.uom_id.id, prod.standard_price, to_uom_id=product_uom.id)
66             main_strd_price = str(std_price) + '\r\n'
67             sum_strd = prod_qtty*std_price
68             for seller_id in prod.seller_ids:
69                 sellers +=  '- <i>'+ seller_id.name.name +'</i>\r\n'
70                 price = supplier_info_pool.price_get(cr, uid, seller_id.name.id, prod.id, number*prod_qtty)[seller_id.name.id]
71                 price = product_uom_pool._compute_price(cr, uid, prod.uom_id.id, price, to_uom_id=product_uom.id)
72                 sellers_price += """<i>"""+rml_obj.formatLang(price) +' '+ company_currency.symbol +"""</i>\r\n"""
73             xml += """<col para='yes'> """+ prod_name +""" </col>
74                     <col para='yes'> """+ main_sp_name + sellers + """ </col>
75                     <col f='yes'>"""+ rml_obj.formatLang(prod_qtty) +' '+ product_uom.name +"""</col>
76                     <col f='yes'>"""+ rml_obj.formatLang(float(main_strd_price)) +' '+ company_currency.symbol +"""</col>
77                     <col f='yes'>""" + main_sp_price + sellers_price + """</col>'"""
78
79             xml += '</row>'
80             return xml, sum, sum_strd
81
82         def process_workcenter(wrk):
83             workcenter = workcenter_pool.browse(cr, uid, wrk['workcenter_id'])
84             cost_cycle = wrk['cycle']*workcenter.costs_cycle
85             cost_hour = wrk['hour']*workcenter.costs_hour
86             total = cost_cycle + cost_hour
87             xml = '<row>'
88             xml += "<col para='yes'>" + workcenter.name + '</col>'
89             xml += "<col/>"
90             xml += """<col f='yes'>"""+rml_obj.formatLang(cost_cycle)+' '+ company_currency.symbol + """</col>"""
91             xml += """<col f='yes'>"""+rml_obj.formatLang(cost_hour)+' '+ company_currency.symbol + """</col>"""
92             xml += """<col f='yes'>"""+rml_obj.formatLang(cost_hour + cost_cycle)+' '+ company_currency.symbol + """</col>"""
93             xml += '</row>'
94
95             return xml, total
96
97
98         xml = ''
99         config_start = """
100         <config>
101             <date>""" + to_xml(rml_obj.formatLang(datetime.now().strftime('%Y-%m-%d %H:%M:%S'),date_time=True)) + """</date>
102             <company>%s</company>
103             <PageSize>210.00mm,297.00mm</PageSize>
104             <PageWidth>595.27</PageWidth>
105             <PageHeight>841.88</PageHeight>
106             <tableSize>55.00mm,58.00mm,29.00mm,29.00mm,29.00mm</tableSize>
107             """ % (user_pool.browse(cr, uid, uid).company_id.name)
108         config_stop = """
109             <report-footer>Generated by OpenERP</report-footer>
110         </config>
111         """
112
113         workcenter_header = """
114             <lines style='header'>
115                 <row>
116                     <col>%s</col>
117                     <col t='yes'/>
118                     <col t='yes'>%s</col>
119                     <col t='yes'>%s</col>
120                     <col t='yes'>%s</col>
121                 </row>
122             </lines>
123         """ % (_('Work Center name'), _('Cycles Cost'), _('Hourly Cost'),_('Work Cost'))
124         prod_header = """
125                 <row>
126                     <col>%s</col>
127                     <col>%s</col>
128                     <col t='yes'>%s</col>
129                     <col t='yes'>%s</col>
130                     <col t='yes'>%s</col>
131                 </row>
132         """ % (_('Component'), _('Component suppliers'), _('Quantity'),_('Cost Price per Uom'), _('Supplier Price per Uom'))
133
134         purchase_price_digits = rml_obj.get_digits(dp='Purchase Price')
135
136         for product in product_pool.browse(cr, uid, ids, context=context):
137             bom_id = bom_pool._bom_find(cr, uid, product.id, product.uom_id.id)
138             title = "<title>%s</title>" %(_("Cost Structure"))
139             title += "<title>%s</title>" %product.name
140             xml += "<lines style='header'>" + title + prod_header + "</lines>"
141             if not bom_id:
142                 total_strd = number * product.standard_price
143                 total = number * product_pool.price_get(cr, uid, [product.id], 'standard_price')[product.id]
144                 xml += """<lines style='lines'><row>
145                     <col para='yes'>-</col>
146                     <col para='yes'>-</col>
147                     <col para='yes'>-</col>
148                     <col para='yes'>-</col>
149                     <col para='yes'>-</col>
150                     </row></lines>"""
151                 xml += """<lines style='total'> <row>
152                     <col> """ + _('Total Cost ') + _('of ') + str(number) +' '+ product.uom_id.name + """: </col>
153                     <col/>
154                     <col f='yes'/>
155                     <col t='yes'>"""+ rml_obj.formatLang(total_strd, digits=purchase_price_digits) +' '+ company_currency.symbol + """</col>
156                     <col t='yes'>"""+ rml_obj.formatLang(total, digits=purchase_price_digits) +' '+ company_currency.symbol + """</col>
157                     </row></lines>'"""
158             else:
159                 bom = bom_pool.browse(cr, uid, bom_id, context=context)
160                 factor = number * product.uom_id.factor / bom.product_uom.factor
161                 sub_boms = bom_pool._bom_explode(cr, uid, bom, factor / bom.product_qty)
162                 total = 0
163                 total_strd = 0
164                 parent_bom = {
165                         'product_qty': bom.product_qty,
166                         'name': bom.product_id.name,
167                         'product_uom': bom.product_uom.id,
168                         'product_id': bom.product_id.id
169                 }
170                 xml_tmp = ''
171                 for sub_bom in (sub_boms and sub_boms[0]) or [parent_bom]:
172                     txt, sum, sum_strd = process_bom(sub_bom, company_currency.id)
173                     xml_tmp +=  txt
174                     total += sum
175                     total_strd += sum_strd
176
177                 xml += "<lines style='lines'>" + xml_tmp + '</lines>'
178                 xml += """<lines style='sub_total'> <row>
179                     <col> """ + _('Component ') + _('Cost ') + _('of ') + str(number) +' '+ product.uom_id.name + """: </col>
180                     <col/>
181                     <col t='yes'/>
182                     <col t='yes'>"""+ rml_obj.formatLang(total_strd, digits=purchase_price_digits) +' '+ company_currency.symbol + """</col>
183                     <col t='yes'></col>
184                     </row></lines>'"""
185
186                 total2 = 0
187                 xml_tmp = ''
188                 for wrk in (sub_boms and sub_boms[1]):
189                     txt, sum = process_workcenter(wrk)
190                     xml_tmp += txt
191                     total2 += sum
192                 if xml_tmp:
193                     xml += workcenter_header
194                     xml += "<lines style='lines'>" + xml_tmp + '</lines>'
195                     xml += """<lines style='sub_total'> <row>
196                     <col> """ + _('Work Cost ') + _('of ') + str(number) +' '+ product.uom_id.name +""": </col>
197                     <col/>
198                     <col/>
199                     <col/>
200                     <col t='yes'>"""+ rml_obj.formatLang(total2, digits=purchase_price_digits) +' '+ company_currency.symbol +"""</col>
201                     </row></lines>'"""
202                 xml += """<lines style='total'> <row>
203                     <col> """ + _('Total Cost ') + _('of ') + str(number) +' '+ product.uom_id.name + """: </col>
204                     <col/>
205                     <col t='yes'/>
206                     <col t='yes'>"""+ rml_obj.formatLang(total_strd+total2, digits=purchase_price_digits) +' '+ company_currency.symbol + """</col>
207                     <col t='yes'></col>
208                     </row></lines>'"""
209
210         xml = '<?xml version="1.0" ?><report>' + config_start + config_stop + xml + '</report>'
211
212         return xml
213
214 report_custom('report.product.price', 'product.product', '', 'addons/mrp/report/price.xsl')