merging from the openerp trunk addons

bzr revid: mga@tinyerp.com-20081205151902-toz3znie8k4gw6lu
This commit is contained in:
Mantavya Gajjar
2008-12-05 20:49:02 +05:30
34 changed files with 1124 additions and 217 deletions
+1 -1
View File
@@ -1369,7 +1369,7 @@ class account_tax(osv.osv):
r['amount'] *= quantity
return res
def _unit_compute_inv(self, cr, uid, taxes, price_unit, address_id=None, product=None, partner=None):
def _unit_compute_inv(self, cr, uid, taxes, price_unit, address_id=None, product=None, partner=None,tax_parent_tot=0.0):
taxes = self._applicable(cr, uid, taxes, price_unit, address_id, product, partner)
res = []
+2 -2
View File
@@ -118,8 +118,8 @@ class res_partner_job(osv.osv):
'address_id':fields.many2one('res.partner.address','Address'),
'contact_id':fields.many2one('res.partner.contact','Contact', required=True, ondelete='cascade'),
'function_id': fields.many2one('res.partner.function','Job Title'),
'sequence_contact':fields.integer('Sequence (Contact)',help='order of importance of this address in the list of addresses of the linked contact'),
'sequence_partner':fields.integer('Sequence (Partner)',help='order of importance of this job title in the list of job title of the linked partner'),
'sequence_contact':fields.integer('Sequence',help='Order of importance of this address in the list of addresses of the linked contact'),
'sequence_partner':fields.integer('Sequence',help='Order of importance of this job title in the list of job title of the linked partner'),
'email': fields.char('E-Mail', size=240),
'phone': fields.char('Phone', size=64),
'date_start' : fields.date('Date Start'),
+24
View File
@@ -0,0 +1,24 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+44
View File
@@ -0,0 +1,44 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{
"name" : "Module Merger",
"version" : "1.0",
"author" : "Tiny",
"website" : "http://tinyerp.com",
"category" : "Generic Modules/Base",
"description": """
* The wizard asks a many2many of modules
* And then generate a module which is the merge of all selected modules
* The new module is provided as a .zip file
The merge will works in all situations:
* Merging all .py files with the same name in the new module
* merging all .xml files and take care of id's.
""",
"depends" : ["base"],
"init_xml" : [ ],
"demo_xml" : [ ],
"update_xml" : [ "base_module_merge_wizard.xml" ],
"installable": True
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,20 @@
<?xml version="1.0"?>
<openerp>
<data>
<wizard
id="wizard_base_module_merger"
string="Merge module"
model="ir.module.module"
multi="True"
name="base_module_merge.module_merge"/>
<menuitem
parent="base.menu_management"
type="wizard"
action="wizard_base_module_merger"
id="menu_wizard_base_module_merger"/>
</data>
</openerp>
@@ -0,0 +1,25 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import base_module_merge
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,302 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import wizard
import osv
import pooler
import tools
import os
from xml.dom import minidom
info_start_form = '''<?xml version="1.0"?>
<form string="Module Merging">
<field name="modules_list" colspan="4"/>
</form>'''
info_start_fields = {
'modules_list': {'string':'Modules', 'type':'many2many','relation':'ir.module.module','help':'Select Modules which you want to merge in single module'},
}
intro_start_form = '''<?xml version="1.0"?>
<form string="Module Recording">
<separator string="Module Information" colspan="4"/>
<field name="name"/>
<field name="directory_name"/>
<field name="version"/>
<field name="author"/>
<field name="website" colspan="4"/>
<field name="category" colspan="4"/>
<field name="data_kind"/>
<newline/>
<field name="description" colspan="4"/>
</form>'''
intro_start_fields = {
'name': {'string':'Module Name', 'type':'char', 'size':64, 'required':True},
'directory_name': {'string':'Directory Name', 'type':'char', 'size':32, 'required':True},
'version': {'string':'Version', 'type':'char', 'size':16, 'required':True},
'author': {'string':'Author', 'type':'char', 'size':64, 'default': lambda *args: 'Tiny', 'required':True},
'category': {'string':'Category', 'type':'char', 'size':64, 'default': lambda *args: 'Vertical Modules/Parametrization', 'required':True},
'website': {'string':'Documentation URL', 'type':'char', 'size':64, 'default': lambda *args: 'http://tinyerp.com', 'required':True},
'description': {'string':'Full Description', 'type':'text', 'required':True},
'data_kind': {'string':'Type of Data', 'type':'selection', 'selection':[('demo','Demo Data'),('update','Normal Data')], 'required':True, 'default': lambda *args:'update'},
}
intro_save_form = '''<?xml version="1.0"?>
<form string="Module Recording">
<separator string="Module successfully created !" colspan="4"/>
<field name="module_filename"/>
<newline/>
<field name="module_file"/>
<separator string="Information" colspan="4"/>
<label string="If you think your module could interrest others people, we'd like you to publish it on TinyERP.com, in the 'Modules' section. You can do it through the website or using features of the 'base_module_publish' module." colspan="4" align="0.0"/>
<label string="Thanks in advance for your contribution." colspan="4" align="0.0"/>
</form>'''
intro_save_fields = {
'module_file': {'string': 'Module .zip File', 'type':'binary', 'readonly':True},
'module_filename': {'string': 'Filename', 'type':'char', 'size': 64, 'readonly':True},
}
import zipfile
from zipfile import PyZipFile, ZIP_DEFLATED
import StringIO
import base64
class base_module_merge(wizard.interface):
def _zip_writestr(self,file_name,data):
info = zipfile.ZipInfo(file_name)
info.compress_type = zipfile.ZIP_DEFLATED
info.external_attr = 2175008768
self.archive.writestr(info,data)
return True
def _remove_prefix_ref(self,fromurl,path):
infile=tools.file_open(os.path.join(fromurl,path))
xml=infile.read()
mydom = minidom.parseString(xml)
for child in mydom.getElementsByTagName("field"):
for attr in child.attributes.keys():
if attr=='ref':
old=child.getAttribute(attr)
if len(old.split('.')) > 1:
if old.split('.')[0] in self.dependencies:
child.setAttribute(attr,old.split('.')[1])
return mydom.toxml()
def _parse_init(self,path,filename):
res=[]
path=os.path.join(path,filename)
infile=open(path,'r')
for i in infile:
i=i.strip()
if len(i)>0:
if i[0]!="#":
res.append( i.strip().split('\n')[0])
infile.close()
return res
def _zippy(self,archive, fromurl, path, src=True):
if path!='':
url = os.path.join(fromurl, path)
else:
url=fromurl
if os.path.isdir(url):
if path.split('/')[-1].startswith('.'):
return False
for fname in os.listdir(url):
self._zippy(self.archive, fromurl, path and os.path.join(path, fname) or fname, src=src)
else:
if src:
exclude = ['pyo', 'pyc']
else:
exclude = ['py','pyo','pyc']
if (path.split('.')[-1] not in exclude):
if os.path.basename(path)=='__init__.py':
datas=self._parse_init(fromurl,path)
if path in self.dict_init:
self.dict_init[path]+=datas
else:
self.dict_init[path]=datas
return True
if os.path.basename(path)=='__terp__.py':
terp_file=os.path.join(fromurl,path)
terp_info=eval(tools.file_open(terp_file).read())
self.init_xml+=terp_info['init_xml']
self.demo_xml+=terp_info['demo_xml']
self.update_xml+=terp_info['update_xml']
return True
try:
info = self.archive.getinfo(path)
except KeyError:
if path.split('.')[-1] == 'xml':
xml_doc=self._remove_prefix_ref(fromurl,path)
xml_doc = xml_doc.encode("utf-8")
self._zip_writestr(path, xml_doc)
else:
file_data=tools.file_open(os.path.join(fromurl, path)).read()
self._zip_writestr(path, file_data)
else:
path2=os.path.split(fromurl)[-1]
new_path=path2+'_'+os.path.split(path)[-1]
if len(os.path.split(path))>1:
new_path=os.path.join(os.path.split(path)[0],new_path)
if path.split('.')[-1] == 'xml':
xml_doc=self._remove_prefix_ref(fromurl,path)
xml_doc = xml_doc.encode("utf-8")
self._zip_writestr(new_path, xml_doc)
if len(os.path.split(path))>1:
terp_file=os.path.join(fromurl,'__terp__.py')
terp_info=eval(tools.file_open(terp_file).read())
if os.path.basename(path) in terp_info['init_xml']:
print "in init_xml",new_path
self.init_xml+=[os.path.basename(new_path)]
elif os.path.basename(path) in terp_info['demo_xml']:
print "in demo_xml",new_path
self.demo_xml+=[os.path.basename(new_path)]
elif os.path.basename(path) in terp_info['update_xml']:
print "in update_xml",new_path
self.update_xml+=[os.path.basename(new_path)]
else:
file_data=tools.file_open(os.path.join(fromurl, path)).read()
self._zip_writestr(new_path, file_data)
if new_path.split('.')[-1] == 'py':
new_import='import '+os.path.basename(new_path).split('.')[0]
if os.path.dirname(path)=='':
dict_key='__init__.py'
else:
dict_key=os.path.join(os.path.dirname(path),'__init__.py')
if dict_key in self.dict_init:
self.dict_init[dict_key]+=[new_import]
else:
self.dict_init[dict_key]=[new_import]
return True
def rec_depend(self,cr, uid, ids, data, context=None, level=50):
pool = pooler.get_pool(cr.dbname)
dep_obj=pool.get('ir.module.module.dependency')
if level<1:
raise Exception, 'Recursion error in modules dependencies !'
for module in pool.get('ir.module.module').browse(cr, uid, ids):
dep_ids = dep_obj.search(cr, uid, [('module_id', '=', module.id)])
if dep_ids:
ids2 = []
for dep in dep_obj.browse(cr, uid, dep_ids):
dep_name=pool.get('ir.module.module').search(cr, uid, [('name','=',dep.name)])
ids2.append(dep_name[0])
self.rec_depend(cr, uid, ids2, data, context, level-1)
if module.name not in data['form']['dependencies']:
data['form']['dependencies'].append(module.name)
return True
def _compute_dependencies(self, cr, uid, data, context):
data['form']['dependencies']=[]
self.rec_depend(cr,uid,data['form']['modules_list'][0][2],data,context)
self.dependencies=data['form']['dependencies']
pool = pooler.get_pool(cr.dbname)
return {}
def _create_module(self, cr, uid, data, context):
self.dict_init={}
self.init_xml=[]
self.demo_xml=[]
self.update_xml=[]
self.archname = StringIO.StringIO('wb')
self.archive = zipfile.ZipFile(self.archname, "w", ZIP_DEFLATED)
for module in self.dependencies:
ad = tools.config['addons_path']
url = os.path.join(ad, module)
if not os.path.isdir(url):
url=url+'.zip'
self._zippy(self.archive, url, '', src=True)
dname = data['form']['directory_name']
data['form']['depen']=[]
data['form']['init_xml']=reduce(lambda l, x: x not in l and l.append(x) or l, self.init_xml, [])
data['form']['demo_xml']=reduce(lambda l, x: x not in l and l.append(x) or l, self.demo_xml, [])
data['form']['update_xml']=reduce(lambda l, x: x not in l and l.append(x) or l, self.update_xml, [])
_terp = """{
"name" : "%(name)s",
"version" : "%(version)s",
"author" : "%(author)s",
"website" : "%(website)s",
"category" : "%(category)s",
"description":\"\"\"%(description)s\"\"\",
"depends" : %(depen)s,
"init_xml" : %(init_xml)s,
"demo_xml" : %(demo_xml)s,
"update_xml" : %(update_xml)s,
"active": True,
"installable": True
} """ % data['form']
for name,datastr in self.dict_init.items():
self.dict_init[name]=reduce(lambda l, x: x not in l and l.append(x) or l, self.dict_init[name], [])
init_data='\n'.join(self.dict_init[name])
self._zip_writestr(name, init_data)
self._zip_writestr('__terp__.py', _terp)
self.archive.close()
return {
'module_file': base64.encodestring(self.archname.getvalue()),
'module_filename': data['form']['directory_name']+'-'+data['form']['version']+'.zip'
}
states = {
'init': {
'actions': [],
'result': {
'type':'form',
'arch':info_start_form,
'fields': info_start_fields,
'state':[
('end', 'Cancel', 'gtk-cancel'),
('info', 'Continue', 'gtk-ok'),
]
}
},
'info': {
'actions': [_compute_dependencies],
'result': {
'type':'form',
'arch':intro_start_form,
'fields': intro_start_fields,
'state':[
('end', 'Cancel', 'gtk-cancel'),
('save', 'Continue', 'gtk-ok'),
]
}
},
'save': {
'actions': [_create_module],
'result': {
'type':'form',
'arch':intro_save_form,
'fields': intro_save_fields,
'state':[
('end', 'Close', 'gtk-ok'),
]
}
}
}
base_module_merge('base_module_merge.module_merge')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+1
View File
@@ -21,6 +21,7 @@
##############################################################################
import base_module_quality
import wizard
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+3 -3
View File
@@ -23,13 +23,13 @@
"name" : "Base module quality",
"author" : "Tiny",
"version" : "1.0",
"depends" : ["base", "product"],
"depends" : ["base",],
"description": "Sample module to check the quality",
"init_xml" : [],
"update_xml" : ["base_module_quality_view.xml"],
"update_xml" : ["base_module_quality_wizard.xml"],
"category" : "Tiny Specific Modules/Base module quality",
"active": False,
"installable": False
"installable": True
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,27 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import netsvc
from osv import fields, osv
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<wizard id="base_module_quality" model="ir.module.module" name="base.module.quality" string="Check the Quality of module"/>
</data>
</openerp>
@@ -0,0 +1,27 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import module_quality_check
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,82 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import wizard
import pooler
import osv
import netsvc
import sys
import tools
import os
import pylint
form_check = '''<?xml version="1.0"?>
<form string="Quality check">
<field name="test" />
</form>'''
fields_check = {
'test': {
'string':'Tests', 'type':'selection', 'required':True,
'selection': [('pylint', 'Pylint'), ('othertest','other')],
'default': lambda *args: 'pylint'
},
}
view_form = """<?xml version="1.0"?>
<form string="Check quality">
<field name="module_info" nolabel="1" colspan="4" height="150" width="400"/>
</form>"""
view_field = {
"module_info": {'type': 'text', 'string': 'check quality', 'readonly':True},
}
class wiz_quality_check(wizard.interface):
def _check(self, cr, uid, data, context):
if data['form']['test'] == 'pylint':
pool=pooler.get_pool(cr.dbname)
module_data = pool.get('ir.module.module').browse(cr, uid, data['ids'])
from pylint_test import pylint_test
ad = tools.config['addons_path']
url = os.path.join(ad, module_data[0].name)
result = pylint_test._test_pylint(self, url)
string_ret = ''
for i in result:
string_ret = string_ret + i + ':\n' + result[i]
return {'module_info':string_ret}
states = {
'init': {
'actions': [],
'result': {'type':'form', 'arch':form_check, 'fields':fields_check, 'state':[('end','Cancel'),('do','Do Test')]}
},
'do': {
'actions': [_check],
'result': {'type':'form', 'arch':view_form, 'fields':view_field, 'state':[('end','Ok')]},
},
}
wiz_quality_check('base.module.quality')
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,25 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import pylint_test
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
@@ -0,0 +1,69 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2008 Tiny SPRL (<http://tiny.be>). All Rights Reserved
# $Id$
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import netsvc
from osv import fields, osv
import os
def _test_pylint(self, url, add_folder=None):
list_files = os.listdir(url)
new_list = []
subfolder = {}
for i in list_files:
if os.path.isdir(i):
path = os.path.join(url, i)
new_list.append(os.listdir(path))
res = _test_pylint(self, path, add_folder=i)
subfolder.update(res)
dict_files = {}
for file in list_files:
if file.split('.')[-1] == 'py':
save_file = file.split('.')[0]+".txt"
file_path = os.path.join(url, file)
os.system('pylint '+file_path+'>> '+save_file+' ')
a2 = os.system('cat '+save_file+' | tail -4 >> temp.txt')
os.system('rm '+save_file+' ')
fp = open('temp.txt','r')
result = fp.read()
fp.close()
str_result = ''
try:
for line in result:
str_result = str_result + line
finally:
fp = open('temp.txt','w')
fp.write('')
fp.close()
if str_result.startswith('Global'):
if add_folder:
dict_files[add_folder + '/' + file] = str_result
else:
dict_files[file] = str_result
os.system(' rm temp.txt ')
dict_files.update(subfolder)
return dict_files
#
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+3 -2
View File
@@ -125,7 +125,8 @@
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<separator string="Notes" position="before">
<field name="carrier_id"/>
<field name="id" invisible="True"/>
<field name="carrier_id" context="{'order_id':id}"/>
</separator>
</field>
</record>
@@ -136,7 +137,7 @@
<field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_out_form"/>
<field name="arch" type="xml">
<field name="address_id" position="after">
<field name="address_id" position="after">
<field name="carrier_id"/>
<field name="weight"/>
</field>
+1
View File
@@ -28,6 +28,7 @@ class sale_order(osv.osv):
_inherit = 'sale.order'
_columns = {
'carrier_id':fields.many2one("delivery.carrier","Delivery method", help="Complete this field if you plan to invoice the shipping based on packings made."),
'id': fields.integer('ID', readonly=True,invisible=True),
}
def onchange_partner_id(self, cr, uid, ids, part):
+2 -1
View File
@@ -51,7 +51,8 @@ class event(osv.osv):
def write(self, cr, uid, ids,vals, *args, **kwargs):
if 'date_begin' in vals and vals['date_begin']:
for eve in self.browse(cr, uid, ids):
self.pool.get('project.project').write(cr, uid, [eve.project_id.id], {'date_end':eve.date_begin})
if eve.project_id:
self.pool.get('project.project').write(cr, uid, [eve.project_id.id], {'date_end':eve.date_begin[:10]})
return super(event,self).write(cr, uid, ids,vals, *args, **kwargs)
@@ -134,7 +134,10 @@ class invoice_create(wizard.interface):
if data['form']['date']:
details.append(line['date'])
if data['form']['time']:
details.append("%s %s" % (line['unit_amount'], pool.get('product.uom').browse(cr, uid, [line['product_uom_id']])[0].name))
if line['product_uom_id']:
details.append("%s %s" % (line['unit_amount'], pool.get('product.uom').browse(cr, uid, [line['product_uom_id']])[0].name))
else:
details.append("%s" % (line['unit_amount'], ))
if data['form']['name']:
details.append(line['name'])
#if data['form']['price']:
+2 -2
View File
@@ -891,7 +891,7 @@ class mrp_procurement(osv.osv):
res = True
user = self.pool.get('res.users').browse(cr, uid, uid)
for procurement in self.browse(cr, uid, ids):
if procurement.product_id.product_tmpl_id.supply_method=='buy':
if procurement.product_id.product_tmpl_id.supply_method<>'produce':
if procurement.product_id.seller_ids:
partner = procurement.product_id.seller_ids[0].name
if user.company_id and user.company_id.partner_id:
@@ -909,7 +909,7 @@ class mrp_procurement(osv.osv):
def check_buy(self, cr, uid, ids):
user = self.pool.get('res.users').browse(cr, uid, uid)
for procurement in self.browse(cr, uid, ids):
if procurement.product_id.product_tmpl_id.supply_method=='produce':
if procurement.product_id.product_tmpl_id.supply_method<>'buy':
return False
if not procurement.product_id.seller_ids:
cr.execute('update mrp_procurement set message=%s where id=%d', ('No supplier defined for this product !', procurement.id))
+9 -1
View File
@@ -36,7 +36,15 @@
"category":"Custom",
"depends":["base","sale","account"],
"demo_xml":[],
"update_xml":["mrp_repair_sequence.xml","mrp_repair_wizard.xml", "mrp_repair_view.xml", "mrp_repair_workflow.xml", "mrp_repair_report.xml"],
"update_xml":[
#"security/mrp_repair_security.xml",
"security/ir.model.access.csv",
"mrp_repair_sequence.xml",
"mrp_repair_wizard.xml",
"mrp_repair_view.xml",
"mrp_repair_workflow.xml",
"mrp_repair_report.xml",
],
"active": False,
"installable": True,
}
+79 -76
View File
@@ -50,11 +50,13 @@ class mrp_repair(osv.osv):
val = 0.0
cur=repair.pricelist_id.currency_id
for line in repair.operations:
for c in self.pool.get('account.tax').compute(cr, uid, line.tax_id, line.price_unit, line.product_uom_qty, repair.partner_invoice_id.id, line.product_id, repair.partner_id):
val+= c['amount']
if line.to_invoice:
for c in self.pool.get('account.tax').compute(cr, uid, line.tax_id, line.price_unit, line.product_uom_qty, repair.partner_invoice_id.id, line.product_id, repair.partner_id):
val+= c['amount']
for line in repair.fees_lines:
for c in self.pool.get('account.tax').compute(cr, uid, line.tax_id, line.price_unit, line.product_uom_qty, repair.partner_invoice_id.id, line.product_id, repair.partner_id):
val+= c['amount']
if line.to_invoice:
for c in self.pool.get('account.tax').compute(cr, uid, line.tax_id, line.price_unit, line.product_uom_qty, repair.partner_invoice_id.id, line.product_id, repair.partner_id):
val+= c['amount']
res[repair.id]=cur_obj.round(cr, uid, cur, val)
return res
@@ -68,10 +70,11 @@ class mrp_repair(osv.osv):
cur=repair.pricelist_id.currency_id
res[id] = cur_obj.round(cr, uid, cur, untax.get(id, 0.0) + tax.get(id, 0.0))
return res
_columns = {
'name' : fields.char('Name',size=24, required=True),
'name' : fields.char('Repair Ref',size=24, required=True),
'product_id': fields.many2one('product.product', string='Product to Repair', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'partner_id' : fields.many2one('res.partner', 'Partner', select=True),
'partner_id' : fields.many2one('res.partner', 'Partner', select=True, help='This field allow you to choose the parner that will be invoiced and delivered'),
'address_id': fields.many2one('res.partner.address', 'Delivery Address', domain="[('partner_id','=',partner_id)]"),
'prodlot_id': fields.many2one('stock.production.lot', 'Lot Number', select=True, domain="[('product_id','=',product_id)]"),
'state': fields.selection([
@@ -79,30 +82,30 @@ class mrp_repair(osv.osv):
('confirmed','Confirmed'),
('ready','Ready to Repair'),
('under_repair','Under Repair'),
('2binvoiced','To be Invoiced'),
('2binvoiced','To be Invoiced'),
('invoice_except','Invoice Exception'),
('done','Done'),
('cancel','Cancel')
], 'Repair State', readonly=True, help="Gives the state of the Repair Order"),
'location_id': fields.many2one('stock.location', 'Current Location', required=True, select=True, readonly=True, states={'draft':[('readonly',False)]}),
'location_dest_id': fields.many2one('stock.location', 'Delivery Location', readonly=True, states={'draft':[('readonly',False)]}),
'move_id': fields.many2one('stock.move', 'Move',required=True, domain="[('product_id','=',product_id)]", readonly=True, states={'draft':[('readonly',False)]}),#,('location_dest_id','=',location_id),('prodlot_id','=',prodlot_id)
'guarantee_limit': fields.date('Guarantee limit'),
'operations' : fields.one2many('mrp.repair.line', 'repair_id', 'Operation Lines', readonly=True, states={'draft':[('readonly',False)]}),
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist'),
'move_id': fields.many2one('stock.move', 'Move',required=True, domain="[('product_id','=',product_id)]", readonly=True, states={'draft':[('readonly',False)]}),
'guarantee_limit': fields.date('Guarantee limit', help="The garantee limit is computed as: last move date + warranty defined on selected product. If the current date is below the garantee limit, each operation and fee you will add will be set as 'not to invoiced' by default. Note that you can change manually afterwards."),
'operations' : fields.one2many('mrp.repair.line', 'repair_id', 'Operation Lines', readonly=True, states={'draft':[('readonly',False)]}),
'pricelist_id': fields.many2one('product.pricelist', 'Pricelist', help='The pricelist comes from the selected partner, by default.'),
'partner_invoice_id':fields.many2one('res.partner.address', 'Invoice to', domain="[('partner_id','=',partner_id)]"),
'invoice_method':fields.selection([
("none","No Invoice"),
("b4repair","Before Repair"),
("after_repair","After Repair")
], "Invoice Method",
select=True, required=True, states={'draft':[('readonly',False)]}, readonly=True),
select=True, required=True, states={'draft':[('readonly',False)]}, readonly=True, help='This field allow you to change the workflow of the repair order. If value selected is different from \'No Invoice\', it also allow you to select the pricelist and invoicing address.'),
'invoice_id': fields.many2one('account.invoice', 'Invoice', readonly=True),
'picking_id': fields.many2one('stock.picking', 'Packing',readonly=True),
'fees_lines' : fields.one2many('mrp.repair.fee', 'repair_id', 'Fees Lines', readonly=True, states={'draft':[('readonly',False)]}),
'internal_notes' : fields.text('Internal Notes'),
'quotation_notes' : fields.text('Quotation Notes'),
'deliver_bool': fields.boolean('Deliver'),
'deliver_bool': fields.boolean('Deliver', help="Check this box if you want to manage the delivery once the product is repaired. If cheked, it will create a packing with selected product. Note that you can select the locations in the Info tab, if you have the extended view."),
'invoiced': fields.boolean('Invoiced', readonly=True),
'repaired' : fields.boolean('Repaired', readonly=True),
'amount_untaxed': fields.function(_amount_untaxed, method=True, string='Untaxed Amount'),
@@ -150,12 +153,15 @@ class mrp_repair(osv.osv):
if move_id:
move = self.pool.get('stock.move').browse(cr, uid, move_id)
product = self.pool.get('product.product').browse(cr, uid, prod_id)
date = move.picking_id.date_done
date = move.date_planned
limit = mx.DateTime.strptime(date, '%Y-%m-%d %H:%M:%S') + RelativeDateTime(months=product.warranty)
data['value']['guarantee_limit'] = limit.strftime('%Y-%m-%d')
data['value']['location_id'] = move.location_dest_id.id
data['value']['location_dest_id'] = move.location_dest_id.id
data['value']['partner_id'] = move.address_id and move.address_id.partner_id and move.address_id.partner_id.id
if move.address_id:
data['value']['partner_id'] = move.address_id.partner_id and move.address_id.partner_id.id
else:
data['value']['partner_id'] = False
data['value']['address_id'] = move.address_id and move.address_id.id
d = self.onchange_partner_id(cr, uid, ids, data['value']['partner_id'], data['value']['address_id'])
data['value'].update(d['value'])
@@ -200,7 +206,7 @@ class mrp_repair(osv.osv):
return data
def get_last_move(lst_move):
while lst_move.move_dest_id and lst_move.move_dest_id and lst_move.move_dest_id.picking_id.state == 'done':
while lst_move.move_dest_id and lst_move.move_dest_id.state == 'done':
lst_move = lst_move.move_dest_id
return lst_move
@@ -223,10 +229,10 @@ class mrp_repair(osv.osv):
wf_service.trg_create(uid, 'mrp.repair', id, cr)
return True
def action_confirm(self, cr, uid, ids, *args):
def action_confirm(self, cr, uid, ids, *args):
mrp_line_obj = self.pool.get('mrp.repair.line')
for o in self.browse(cr, uid, ids):
if (o.invoice_method == 'b4repair'):
if (o.invoice_method == 'b4repair'):
self.write(cr, uid, [o.id], {'state': '2binvoiced'})
else:
self.write(cr, uid, [o.id], {'state': 'confirmed'})
@@ -262,14 +268,14 @@ class mrp_repair(osv.osv):
'name': invoice.name +', '+repair.name,
'origin': invoice.origin+', '+repair.name,
'comment':(comment and (invoice.comment and invoice.comment+"\n"+comment or comment)) or (invoice.comment and invoice.comment or ''),
}
}
invoice_obj.write(cr, uid, [inv_id],invoice_vals,context=context)
else:
a = repair.partner_id.property_account_receivable.id
inv = {
'name': repair.name,
'origin':repair.name,
'type': 'out_invoice',
'type': 'out_invoice',
'account_id': a,
'partner_id': repair.partner_id.id,
'address_invoice_id': repair.address_id.id,
@@ -282,7 +288,7 @@ class mrp_repair(osv.osv):
self.write(cr, uid, repair.id , {'invoiced':True,'invoice_id' : inv_id})
for operation in repair.operations:
if operation.to_invoice == True:
if operation.to_invoice == True:
if group:
name = repair.name + '-' + operation.name
else:
@@ -298,7 +304,7 @@ class mrp_repair(osv.osv):
'price_unit' : operation.price_unit,
'price_subtotal' : operation.product_uom_qty*operation.price_unit,
'product_id' : operation.product_id and operation.product_id.id or False
})
})
self.pool.get('mrp.repair.line').write(cr, uid, [operation.id], {'invoiced':True,'invoice_line_id':invoice_line_id})
for fee in repair.fees_lines:
if fee.to_invoice == True:
@@ -335,13 +341,13 @@ class mrp_repair(osv.osv):
self.write(cr, uid, ids, {'state':'under_repair'})
return True
def action_invoice_end(self, cr, uid, ids, context=None):
def action_invoice_end(self, cr, uid, ids, context=None):
for order in self.browse(cr, uid, ids):
val = {}
if (order.invoice_method=='b4repair'):
val['state'] = 'ready'
else:
#val['state'] = 'done'
else:
#val['state'] = 'done'
pass
self.write(cr, uid, [order.id], val)
return True
@@ -351,11 +357,11 @@ class mrp_repair(osv.osv):
val = {}
val['repaired']=True
if (not order.invoiced and order.invoice_method=='after_repair'):
val['state'] = '2binvoiced'
val['state'] = '2binvoiced'
elif (not order.invoiced and order.invoice_method=='b4repair'):
val['state'] = 'ready'
else:
#val['state'] = 'done'
else:
#val['state'] = 'done'
pass
self.write(cr, uid, [order.id], val)
return True
@@ -364,10 +370,25 @@ class mrp_repair(osv.osv):
res=self.action_repair_done(cr,uid,ids)
return True
def action_repair_done(self, cr, uid, ids, context=None):
def action_repair_done(self, cr, uid, ids, context=None):
res = {}
company = self.pool.get('res.users').browse(cr, uid, uid).company_id
for repair in self.browse(cr, uid, ids, context=context):
#TODO: create the moves add/remove
for move in repair.operations:
move_id = self.pool.get('stock.move').create(cr, uid, {
'name': move.name,
'product_id': move.product_id.id,
'product_qty': move.product_uom_qty,
'product_uom': move.product_uom.id,
'address_id': repair.address_id and repair.address_id.id or False,
'location_id': move.location_id.id,
'location_dest_id': move.location_dest_id.id,
'tracking_id': False,
'state': 'assigned',
})
self.pool.get('mrp.repair.line').write(cr, uid, [move.id], {'move_id': move_id})
if repair.deliver_bool:
picking = self.pool.get('stock.picking').create(cr, uid, {
'origin': repair.name,
@@ -400,7 +421,7 @@ class mrp_repair(osv.osv):
res[repair.id] = picking
else:
self.write(cr, uid, [repair.id], {'state':'done'})
return res
return res
mrp_repair()
@@ -410,13 +431,17 @@ class ProductChangeMixin(object):
def product_id_change(self, cr, uid, ids, pricelist, product, uom=False, product_uom_qty=0, partner_id=False, guarantee_limit=False):
result = {}
warning = {}
if not product_uom_qty:
product_uom_qty = 1
result['product_uom_qty'] = product_uom_qty
if product:
product_obj = self.pool.get('product.product').browse(cr, uid, product)
if partner_id:
partner = self.pool.get('res.partner').browse(cr, uid, partner_id)
result['tax_id'] = self.pool.get('account.fiscal.position').map_tax(cr, uid, partner, product_obj.taxes_id)
result['name'] = product_obj.partner_ref
result['product_uom'] = product_obj.uom_id and product_obj.uom_id.id or False
if not pricelist:
@@ -449,7 +474,7 @@ class mrp_repair_line(osv.osv, ProductChangeMixin):
def copy(self, cr, uid, id, default=None, context=None):
if not default: default = {}
default.update( {'invoice_line_id':False,'move_ids':[],'invoiced':False,'state':'draft'})
default.update( {'invoice_line_id':False,'move_id':False,'invoiced':False,'state':'draft'})
return super(mrp_repair_line, self).copy(cr, uid, id, default, context)
def _amount_line(self, cr, uid, ids, field_name, arg, context):
@@ -464,53 +489,52 @@ class mrp_repair_line(osv.osv, ProductChangeMixin):
_columns = {
'name' : fields.char('Description',size=64,required=True),
'repair_id': fields.many2one('mrp.repair', 'Repair Order Ref',ondelete='cascade', select=True),
'type': fields.selection([('add','Add'),('remove','Remove')],'Type'),
'to_invoice': fields.boolean('To Invoice'),
'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok','=',True)]),
'invoiced': fields.boolean('Invoiced',readonly=True),
'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))),
'type': fields.selection([('add','Add'),('remove','Remove')],'Type', required=True),
'to_invoice': fields.boolean('To Invoice'),
'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok','=',True)], required=True),
'invoiced': fields.boolean('Invoiced',readonly=True),
'price_unit': fields.float('Unit Price', required=True, digits=(16, int(config['price_accuracy']))),
'price_subtotal': fields.function(_amount_line, method=True, string='Subtotal',digits=(16, int(config['price_accuracy']))),
'tax_id': fields.many2many('account.tax', 'repair_operation_line_tax', 'repair_operation_line_id', 'tax_id', 'Taxes'),
'tax_id': fields.many2many('account.tax', 'repair_operation_line_tax', 'repair_operation_line_id', 'tax_id', 'Taxes'),
'product_uom_qty': fields.float('Quantity (UoM)', digits=(16,2), required=True),
'product_uom': fields.many2one('product.uom', 'Product UoM', required=True),
'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', readonly=True),
'product_uom': fields.many2one('product.uom', 'Product UoM', required=True),
'invoice_line_id': fields.many2one('account.invoice.line', 'Invoice Line', readonly=True),
'location_id': fields.many2one('stock.location', 'Source Location', required=True, select=True),
'location_dest_id': fields.many2one('stock.location', 'Dest. Location', required=True, select=True),
'move_ids': fields.one2many('stock.move', 'repair_line_id', 'Inventory Moves', readonly=True),
'move_id': fields.many2one('stock.move', 'Inventory Move', readonly=True),
'state': fields.selection([('draft','Draft'),('confirmed','Confirmed'),('done','Done'),('cancel','Canceled')], 'Status', required=True, readonly=True),
}
_defaults = {
_defaults = {
'state': lambda *a: 'draft',
'product_uom_qty':lambda *a:1,
'product_uom_qty':lambda *a:1,
}
def onchange_operation_type(self, cr, uid, ids, type,guarantee_limit):
def onchange_operation_type(self, cr, uid, ids, type, guarantee_limit):
if not type:
return {'value': {
'location_id': False,
'location_dest_id': False
}
}
stock_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Stock')])[0]
produc_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Production')])[0]
to_invoice=False
if guarantee_limit and today() > mx.DateTime.strptime(guarantee_limit, '%Y-%m-%d'):
to_invoice=True
if type == 'add':
stock_id = self.pool.get('stock.location').search(cr, uid, [('name','=','Stock')])[0]
to_invoice=False
if guarantee_limit and today() > mx.DateTime.strptime(guarantee_limit, '%Y-%m-%d'):
to_invoice=True
return {'value': {
'to_invoice': to_invoice,
'location_id': stock_id,
'location_dest_id' : produc_id
}
}
if type == 'remove':
return {'value': {
'to_invoice': False,
'location_id': produc_id,
'location_dest_id':False
}
return {'value': {
'to_invoice': False,
'location_id': produc_id,
'location_dest_id':False
}
}
mrp_repair_line()
class mrp_repair_fee(osv.osv, ProductChangeMixin):
@@ -547,25 +571,4 @@ class mrp_repair_fee(osv.osv, ProductChangeMixin):
}
mrp_repair_fee()
class stock_move(osv.osv):
_inherit = 'stock.move'
_columns = {
'repair_line_id': fields.many2one('mrp.repair.line', 'Repair Operation Line', ondelete='set null', select=True, readonly=True),
}
_defaults = {
'repair_line_id': lambda *a:False
}
stock_move()
class stock_picking(osv.osv):
_inherit = 'stock.picking'
_columns = {
'repair_id': fields.many2one('mrp.repair', 'Repair Order', ondelete='set null', select=True, readonly=True),
}
_defaults = {
'repair_id': lambda *a: False
}
stock_picking()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+1 -1
View File
@@ -3,7 +3,7 @@
<data>
<report
id="report_mrp_repair"
string="Repair Order"
string="Quotation / Order"
model="mrp.repair"
name="repair.order"
rml="mrp_repair/report/order.rml"
+20 -22
View File
@@ -17,14 +17,12 @@
<field name="move_id" on_change="onchange_move_id(product_id, move_id)"/>
<field name="repaired"/>
<newline/>
<field name="partner_id" select="2" on_change="onchange_partner_id(partner_id,address_id)" attrs="{'readonly':[('deliver_bool','=', False)]}"/>
<field name="address_id" attrs="{'readonly':[('deliver_bool','=', False)]}"/>
<field name="partner_id" select="2" on_change="onchange_partner_id(partner_id,address_id)"/>
<field name="address_id" attrs="{'readonly':[('deliver_bool','=', False)]}"/>
<field name="invoiced"/>
</group>
<notebook colspan="4">
<page string="Products">
<field name="location_id"/>
<field name="location_dest_id" attrs="{'readonly':[('deliver_bool','=', False)], 'required':[('deliver_bool','=', True)]}"/>
<page string="Operations">
<field name="guarantee_limit" />
<newline/>
<field colspan="4" mode="tree,form" name="operations" nolabel="1" widget="one2many_list">
@@ -33,7 +31,7 @@
<page string="Repair Line">
<field name="name" colspan="4"/>
<field name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id)" colspan="4"/>
<field name="product_uom_qty" string="Qty" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id)"/>
<field name="product_uom_qty" string="Qty" />
<field name="product_uom" string="UoM"/>
<field name="price_unit"/>
<field name="price_subtotal"/>
@@ -41,7 +39,7 @@
<field name="location_dest_id"/>
<newline/>
<field name="type" on_change="onchange_operation_type(type,parent.guarantee_limit)"/>
<group colspan="2">
<group colspan="2">
<field name="to_invoice"/>
<field name="invoiced"/>
</group>
@@ -51,11 +49,8 @@
<field name="state"/>
</page>
<page string="History" groups="base.group_extended">
<separator colspan="4" string="Invoice Lines"/>
<field colspan="4" name="invoice_line_id" nolabel="1"/>
<separator colspan="4" string="Stock Moves"/>
<field colspan="4" name="move_ids" nolabel="1" widget="many2many"/>
<field colspan="4" name="move_id" />
<field colspan="4" name="invoice_line_id"/>
</page>
</notebook>
@@ -66,9 +61,10 @@
<field name='name'/>
<field name="location_id"/>
<field name="location_dest_id"/>
<field name="product_uom_qty" string="Qty" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id)"/>
<field name="product_uom_qty" string="Qty"/>
<field name="product_uom" string="UoM"/>
<field name="price_unit"/>
<field name="tax_id"/>
<field name="to_invoice"/>
<field name="price_subtotal"/>
</tree>
@@ -81,7 +77,7 @@
<button name="button_dummy" states="draft" string="Compute" type="object"/>
</group>
<newline/>
<group col="13" colspan="4">
<group col="13" colspan="4">
<field name="state" select="2"/>
<button name="repair_confirm" states="draft" string="Confirm Repair"/>
<button name="repair_ready" states="confirmed" string="Start Repair"/>
@@ -97,17 +93,17 @@
</group>
</page>
<page string="Invoicing">
<field name="pricelist_id" context="product_id=product_id"/>
<field name="partner_invoice_id"/>
<field name="invoice_method" attrs="{'readonly':[('deliver_bool','=', False)]}"/>
<field name="invoice_id"/>
<field name="invoice_method" colspan="4" />
<field name="pricelist_id" context="product_id=product_id" attrs="{'readonly':[('invoice_method','=', 'none')]}"/>
<field name="partner_invoice_id" attrs="{'readonly':[('invoice_method','=', 'none')]}"/>
<!--<field name="invoice_id"/>-->
<field colspan="4" mode="tree,form" name="fees_lines" nolabel="1" widget="one2many_list">
<form string="Fees">
<notebook>
<page string="Fees Line">
<field name='name'/>
<field name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id,parent.guarantee_limit)" colspan="4"/>
<field name="product_uom_qty" string="Qty" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id,parent.guarantee_limit)"/>
<field name="product_uom_qty" string="Qty"/>
<field name="product_uom" string="UoM" />
<field name="price_unit"/>
<field name="price_subtotal"/>
@@ -127,7 +123,7 @@
<tree string="Fees" editable="bottom">
<field name="product_id" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id,parent.guarantee_limit)"/>
<field name='name'/>
<field name="product_uom_qty" string="Qty" on_change="product_id_change(parent.pricelist_id,product_id,product_uom,product_uom_qty, parent.partner_id,parent.guarantee_limit)"/>
<field name="product_uom_qty" string="Qty"/>
<field name="product_uom" string="UoM"/>
<field name="price_unit"/>
<field name="to_invoice"/>
@@ -141,9 +137,11 @@
<separator colspan="4" string="Quotation Notes"/>
<field colspan="4" name="quotation_notes" nolabel="1"/>
</page>
<page string="History" groups="base.group_extended">
<!-- <field name="invoice_id"/> -->
<page string="Extra Info" groups="base.group_extended">
<field name="invoice_id"/>
<field name="picking_id"/>
<field name="location_id"/>
<field name="location_dest_id" attrs="{'readonly':[('deliver_bool','=', False)], 'required':[('deliver_bool','=', True)]}"/>
</page>
</notebook>
</form>
+259 -88
View File
@@ -70,6 +70,19 @@
<blockTableStyle id="Table6">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<<<<<<< TREE
<lineStyle kind="LINEBELOW" colorName="#000000" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBELOW" colorName="#000000" start="1,-1" stop="1,-1"/>
<lineStyle kind="LINEBELOW" colorName="#000000" start="2,-1" stop="2,-1"/>
<lineStyle kind="LINEBELOW" colorName="#000000" start="3,-1" stop="3,-1"/>
<lineStyle kind="LINEBELOW" colorName="#000000" start="4,-1" stop="4,-1"/>
<lineStyle kind="LINEBELOW" colorName="#000000" start="5,-1" stop="5,-1"/>
</blockTableStyle>
<blockTableStyle id="Table7">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEBELOW" colorName="#000000" start="3,1" stop="-1,-1"/>
=======
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="0,-1" stop="0,-1"/>
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="1,-1" stop="1,-1"/>
<lineStyle kind="LINEBELOW" colorName="#cccccc" start="2,-1" stop="2,-1"/>
@@ -80,14 +93,13 @@
<blockTableStyle id="Table9">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
</blockTableStyle>
<blockTableStyle id="Table10">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
</blockTableStyle>
<blockTableStyle id="Table11">
<blockAlignment value="LEFT"/>
<blockValign value="TOP"/>
<lineStyle kind="LINEABOVE" colorName="#000000" start="1,0" stop="1,0"/>
<lineStyle kind="LINEABOVE" colorName="#000000" start="2,0" stop="2,0"/>
<lineStyle kind="LINEABOVE" colorName="#000000" start="3,0" stop="3,0"/>
<lineStyle kind="LINEABOVE" colorName="#000000" start="1,2" stop="1,2"/>
<lineStyle kind="LINEABOVE" colorName="#000000" start="2,2" stop="2,2"/>
<lineStyle kind="LINEABOVE" colorName="#000000" start="3,2" stop="3,2"/>
>>>>>>> MERGE-SOURCE
</blockTableStyle>
<blockTableStyle id="Table8">
<blockAlignment value="LEFT"/>
@@ -101,34 +113,55 @@
<paraStyle name="P3" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P4" fontName="Helvetica-Oblique" fontSize="7.0" leading="9" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P5" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P6" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P7" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P6" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P7" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P8" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P9" fontName="Helvetica-Bold" fontSize="5.0" leading="7" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P10" fontName="Helvetica-Bold" fontSize="7.0" leading="9" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P11" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P12" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P13" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P14" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P15" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P16" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P9" fontName="Helvetica-Bold" fontSize="15.0" leading="19" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P10" fontName="Helvetica-Bold" fontSize="5.0" leading="7" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P11" fontName="Helvetica-Bold" fontSize="7.0" leading="9" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P12" fontName="Helvetica" fontSize="8.0" leading="10" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P13" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P14" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P15" fontName="Helvetica-Bold" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P16" fontName="Helvetica" fontSize="8.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P17" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P18" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P19" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P20" fontName="Helvetica-Oblique" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P21" fontName="Helvetica"/>
<paraStyle name="P22" fontName="Times-Roman"/>
<paraStyle name="P23" fontName="Times-Roman"/>
<paraStyle name="P24" fontName="Helvetica-Oblique" fontSize="2.0" leading="3"/>
<paraStyle name="P25" fontName="Helvetica-Oblique" fontSize="2.0" leading="3" alignment="RIGHT"/>
<paraStyle name="P26" fontName="Helvetica-Bold" fontSize="9.0" leading="11"/>
<paraStyle name="P27" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<<<<<<< TREE
<paraStyle name="P18" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P19" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P20" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P21" fontName="Helvetica-Oblique" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P22" fontName="Helvetica-Bold" fontSize="9.0" leading="11"/>
<paraStyle name="P23" fontName="Helvetica"/>
<paraStyle name="P24" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P25" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P26" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P27" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P28" fontName="Helvetica" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P29" fontName="Times-Roman"/>
<paraStyle name="P30" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P31" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P32" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P33" fontName="Helvetica" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P34" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P35" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P36" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P37" fontName="Helvetica-Oblique" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P38" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
=======
<paraStyle name="P18" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P19" fontName="Helvetica-Bold" fontSize="10.0" leading="13" alignment="RIGHT" spaceBefore="6.0" spaceAfter="6.0"/>
<paraStyle name="P20" fontName="Helvetica" fontSize="9.0" leading="11" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P21" fontName="Helvetica-Oblique" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P22" fontName="Helvetica-Oblique" fontSize="2.0" leading="3"/>
<paraStyle name="P23" fontName="Helvetica-Bold" fontSize="9.0" leading="11"/>
<paraStyle name="P24" fontName="Helvetica"/>
<paraStyle name="P25" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P26" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P27" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P28" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P29" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P30" fontName="Helvetica" fontSize="9.0" leading="11" alignment="RIGHT"/>
<paraStyle name="P31" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P32" fontName="Helvetica" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P33" fontName="Helvetica" fontSize="5.0" leading="7" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P29" fontName="Helvetica-Bold" fontSize="9.0" leading="11" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
<paraStyle name="P30" fontName="Helvetica" fontSize="2.0" leading="3" alignment="LEFT" spaceBefore="0.0" spaceAfter="0.0"/>
>>>>>>> MERGE-SOURCE
<paraStyle name="Standard" fontName="Times-Roman"/>
<paraStyle name="Text body" fontName="Times-Roman" spaceBefore="0.0" spaceAfter="6.0"/>
<paraStyle name="Heading" fontName="Helvetica" fontSize="8.0" leading="10" spaceBefore="12.0" spaceAfter="6.0"/>
@@ -166,7 +199,7 @@
</stylesheet>
<images/>
<story>
<para style="P11">[[ repeatIn(objects,'o') ]]</para>
<para style="P12">[[ repeatIn(objects,'o') ]]</para>
<blockTable colWidths="265.0,51.0,225.0" style="Table1">
<tr>
<td>
@@ -180,12 +213,12 @@
<para style="P3">
<font color="white"> </font>
</para>
<para style="P12">Invoice address :[[ o.partner_id and o.partner_id.property_payment_term.name ]]</para>
<para style="P13">Invoice address :[[ o.partner_id and o.partner_id.property_payment_term.name ]]</para>
<para style="P3">[[ o.partner_invoice_id.street ]] [[ o.partner_invoice_id.street2 and (', %s' % o.partner_invoice_id.street2 or '') ]]</para>
<para style="P3">[[ o.partner_invoice_id.zip or '' ]] [[ o.partner_invoice_id.city or '' ]] [[ o.partner_invoice_id.country_id and (', %s' % (o.partner_invoice_id.country_id and o.partner_invoice_id.country_id.name or '')) ]]</para>
</td>
<td>
<para style="P11">
<para style="P12">
<font color="white"> </font>
</para>
</td>
@@ -210,94 +243,112 @@
</td>
</tr>
</blockTable>
<para style="P11">
<para style="P12">
<font color="white"> </font>
</para>
<para style="P9">
<font color="white"> </font>
</para>
<para style="P7">[[ o.state&lt;&gt;'draft' and removeParentNode('para') ]]Repair Quotation <font face="Helvetica">N° : [[ o.name ]]</font></para>
<para style="P8">[[ o.state=='draft' and removeParentNode('para') ]]Repair Order N° : [[ o.name ]]</para>
<para style="P10">
<font color="white"> </font>
</para>
<para style="P6">
<para style="P8">[[ o.state&lt;&gt;'draft' and removeParentNode('para') ]]Repair Quotation <font face="Helvetica">N° : [[ o.name ]]</font></para>
<para style="P9">[[ o.state=='draft' and removeParentNode('para') ]]Repair Order N° : [[ o.name ]]</para>
<para style="P11">
<font color="white"> </font>
</para>
<para style="P7">
<font color="white"> </font>
</para>
<blockTable colWidths="130.0,136.0,136.0,136.0" style="Table2">
<tr>
<td>
<para style="P14">Product to Repair </para>
<para style="P15">Product to Repair </para>
</td>
<td>
<para style="P14">Lot Number</para>
<para style="P15">Lot Number</para>
</td>
<td>
<para style="P14">Guarantee Limit </para>
<para style="P15">Guarantee Limit </para>
</td>
<td>
<para style="P14">Printing Date</para>
<para style="P15">Printing Date</para>
</td>
</tr>
</blockTable>
<blockTable colWidths="130.0,136.0,136.0,136.0" style="Table3">
<tr>
<td>
<para style="P15">[[ o.product_id.name or '' ]]</para>
<para style="P16">[[ o.product_id.name or '' ]]</para>
</td>
<td>
<para style="P15">[[ o.prodlot_id.name or ' ' ]]</para>
<para style="P16">[[ o.prodlot_id.name or ' ' ]]</para>
</td>
<td>
<para style="P15">[[ time.strftime('%d/%m/%Y', time.strptime(o.guarantee_limit, '%Y-%m-%d')) ]]</para>
<para style="P16">[[ time.strftime('%d/%m/%Y', time.strptime(o.guarantee_limit, '%Y-%m-%d')) ]]</para>
</td>
<td>
<para style="P15">[[ time.strftime('%d/%m/%Y')]] </para>
<para style="P16">[[ time.strftime('%d/%m/%Y')]] </para>
</td>
</tr>
</blockTable>
<para style="P11">
<para style="P12">
<font color="white"> </font>
</para>
<para style="P11">
<para style="P12">
<font color="white"> </font>
</para>
<blockTable colWidths="165.0,165.0,71.0,70.0,64.0" repeatRows="1" style="Table4">
<tr>
<td>
<para style="P13">Description</para>
<para style="P14">Description</para>
</td>
<td>
<para style="P13">VAT</para>
<para style="P14">VAT</para>
</td>
<td>
<para style="P16">Quantity</para>
<para style="P17">Quantity</para>
</td>
<td>
<para style="P17">Unit Price</para>
<para style="P18">Unit Price</para>
</td>
<td>
<para style="P18">Price</para>
<para style="P19">Price</para>
</td>
</tr>
</blockTable>
<section>
<para style="P32"/>
<para style="P31">Operation Line(s)</para>
<<<<<<< TREE
<para style="P28"/>
<para style="P27">Operation Line(s)</para>
<blockTable colWidths="26.0,142.0,153.0,95.0,52.0,69.0" style="Table5">
=======
<para style="P30">
<font color="white"> </font>
</para>
<para style="P29">Operation Line(s)</para>
<blockTable colWidths="28.0,145.0,150.0,96.0,51.0,69.0" style="Table5">
>>>>>>> MERGE-SOURCE
<tr>
<td>
<para style="P4">[[ repeatIn(o.operations,'line') ]] </para> <para style="P4">Add [[ ((line.type == 'add') or removeParentNode('para')) and '' ]] </para>
<para style="P4"><font face="Times-Roman" size="2.0">[[ repeatIn(o.operations,'line') ]]</font>Add [[ ((line.type == 'add') or removeParentNode('para')) and '' ]] </para>
<para style="P4">Remove [[ ((line.type == 'remove') or removeParentNode('para')) and '' ]]</para>
</td>
<td>
<<<<<<< TREE
<para style="P3">[[ line.name ]]</para>
</td>
<td>
<para style="P27">[[ ','.join(map( lambda x: x.name, line.tax_id)) or '0.00' ]]</para>
<para style="P6">[[ ','.join(map( lambda x: x.name, line.tax_id)) or '0.00' ]]</para>
</td>
<td>
<para style="P19">[[ line.product_uom_qty or '0.00' ]] [[ line.product_uom.name ]] </para>
<para style="P20">[[ line.product_uom_qty or '0.00' ]] [[ line.product_uom.name ]] </para>
=======
<para style="P3">[[ line.name ]][[ (line.to_invoice==True) or removeParentNode('tr') ]]</para>
</td>
<td>
<para style="P6">[[ ','.join(map( lambda x: x.name, line.tax_id)) or '0.00' ]]</para>
</td>
<td>
<para style="P20">[[ line.product_uom_qty or '0.00' ]] [[ line.product_uom.name ]]</para>
>>>>>>> MERGE-SOURCE
</td>
<td>
<para style="P1">[[ line.price_unit ]]</para>
@@ -308,23 +359,41 @@
</tr>
</blockTable>
</section>
<para style="P26">Fees Line(s)</para>
<para style="P20">
<<<<<<< TREE
<para style="P22">Fees Line(s)</para>
<para style="P21">
<font color="white"> </font>
</para>
=======
<para style="P23">Fees Line(s)</para>
<para style="P21"/>
>>>>>>> MERGE-SOURCE
<blockTable colWidths="28.0,145.0,150.0,96.0,51.0,69.0" style="Table6">
<tr>
<td>
<para style="P20">[[ repeatIn(o.fees_lines,'fees') ]]</para>
<<<<<<< TREE
<para style="P21">[[ repeatIn(o.fees_lines,'fees') ]]</para>
</td>
<td>
<para style="P3">[[ fees.name ]]</para>
</td>
<td>
<para style="P27">[[ ','.join(map( lambda x: x.name, fees.tax_id)) or '0.00' ]]</para>
<para style="P6">[[ ','.join(map( lambda x: x.name, fees.tax_id)) or '0.00' ]]</para>
</td>
<td>
<para style="P19">[[ fees.product_uom_qty or '0.00' ]] [[ fees.product_uom.name ]] </para>
<para style="P20">[[ fees.product_uom_qty or '0.00' ]] [[ fees.product_uom.name ]] </para>
=======
<para style="P21">[[ repeatIn(o.fees_lines,'fees') ]]</para>
</td>
<td>
<para style="P3">[[ fees.name ]][[ (fees.to_invoice==True) or removeParentNode('tr') ]]</para>
</td>
<td>
<para style="P6">[[ ','.join(map( lambda x: x.name, fees.tax_id)) or '0.00' ]]</para>
</td>
<td>
<para style="P20">[[ fees.product_uom_qty or '0.00' ]] [[ fees.product_uom.name ]] </para>
>>>>>>> MERGE-SOURCE
</td>
<td>
<para style="P1">[[ fees.price_unit ]]</para>
@@ -334,48 +403,145 @@
</td>
</tr>
</blockTable>
<para style="P24">
<font color="white"> </font>
</para>
<para style="P24">
<font color="white"> </font>
</para>
<blockTable colWidths="444.0,61.0,34.0" style="Table9">
<<<<<<< TREE
<blockTable colWidths="90.0,90.0,221.0,57.0,54.0,28.0" style="Table7">
<tr>
<td>
<para style="P28">Net Total :</para>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P29">[[ o.amount_untaxed or '0.00' ]]</para>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P29">[[ o.pricelist_id.currency_id.name ]]</para>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P24">Net Total :</para>
</td>
<td>
<para style="P25">[[ o.amount_untaxed or '0.00' ]]</para>
</td>
<td>
<para style="P25">[[ o.pricelist_id.currency_id.name ]]</para>
</td>
</tr>
<tr>
<td>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P24">Taxes:</para>
</td>
<td>
<para style="P25">[[ o.amount_tax or '0.00']]</para>
</td>
<td>
<para style="P25">[[ o.pricelist_id.currency_id.name ]]</para>
</td>
</tr>
<tr>
<td>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="Table Contents">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P24">Total :</para>
</td>
<td>
<para style="P26">[[ total(o) ]]</para>
</td>
<td>
<para style="P25">[[ o.pricelist_id.currency_id.name ]]</para>
</td>
</tr>
</blockTable>
<blockTable colWidths="444.0,61.0,34.0" style="Table10">
<para style="P29">
<font color="white"> </font>
</para>
<para style="P29">
=======
<para style="P22">
<font color="white"> </font>
</para>
<para style="P22">
<font color="white"> </font>
</para>
<blockTable colWidths="384.0,67.0,64.0,24.0" style="Table9">
<tr>
<td>
<para style="P28">Taxes:</para>
<para style="P28">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P29">[[ o.amount_tax or '0.00']]</para>
<para style="P25">Net Total :</para>
</td>
<td>
<para style="P29">[[ o.pricelist_id.currency_id.name ]]</para>
<para style="P26">[[ o.amount_untaxed or '0.00' ]]</para>
</td>
<td>
<para style="P26">[[ o.pricelist_id.currency_id.name ]]</para>
</td>
</tr>
</blockTable>
<blockTable colWidths="444.0,61.0,34.0" style="Table11">
<tr>
<td>
<para style="P28">Total :</para>
<para style="P28">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P30">[[ total(o) ]]</para>
<para style="P25">Taxes:</para>
</td>
<td>
<para style="P29">[[ o.pricelist_id.currency_id.name ]]</para>
<para style="P26">[[ o.amount_tax or '0.00']]</para>
</td>
<td>
<para style="P26">[[ o.pricelist_id.currency_id.name ]]</para>
</td>
</tr>
<tr>
<td>
<para style="P28">
<font color="white"> </font>
</para>
</td>
<td>
<para style="P25">Total :</para>
</td>
<td>
<para style="P27">[[ total(o) ]]</para>
</td>
<td>
<para style="P26">[[ o.pricelist_id.currency_id.name ]]</para>
</td>
</tr>
</blockTable>
@@ -383,6 +549,7 @@
<font color="white"> </font>
</para>
<para style="Standard">
>>>>>>> MERGE-SOURCE
<font color="white"> </font>
</para>
<blockTable colWidths="534.0" style="Table8">
@@ -392,8 +559,12 @@
</td>
</tr>
</blockTable>
<para style="P21">
<<<<<<< TREE
<para style="P23"/>
=======
<para style="P24">
<font color="white"> </font>
</para>
>>>>>>> MERGE-SOURCE
</story>
</document>
@@ -0,0 +1,7 @@
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
"access_mrp_repair_user","MRP Repair user","model_mrp_repair","stock.group_stock_user",1,0,0,0
"access_mrp_repair_manager","MRP Repair manager","model_mrp_repair","stock.group_stock_manager",1,1,1,1
"access_mrp_repair_line_user","MRP Repair Line user","model_mrp_repair_line","stock.group_stock_user",1,0,0,0
"access_mrp_repair_line_manager","MRP Repair Line manager","model_mrp_repair_line","stock.group_stock_manager",1,1,1,1
"access_mrp_repair_fee_user","MRP Repair Fee user","model_mrp_repair_fee","stock.group_stock_user",1,0,0,0
"access_mrp_repair_fee_manager","MRP Repair Fee manager","model_mrp_repair_fee","stock.group_stock_manager",1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_mrp_repair_user MRP Repair user model_mrp_repair stock.group_stock_user 1 0 0 0
3 access_mrp_repair_manager MRP Repair manager model_mrp_repair stock.group_stock_manager 1 1 1 1
4 access_mrp_repair_line_user MRP Repair Line user model_mrp_repair_line stock.group_stock_user 1 0 0 0
5 access_mrp_repair_line_manager MRP Repair Line manager model_mrp_repair_line stock.group_stock_manager 1 1 1 1
6 access_mrp_repair_fee_user MRP Repair Fee user model_mrp_repair_fee stock.group_stock_user 1 0 0 0
7 access_mrp_repair_fee_manager MRP Repair Fee manager model_mrp_repair_fee stock.group_stock_manager 1 1 1 1
@@ -29,3 +29,4 @@
"access_product_pricelist_item_user","product.pricelist.item.user","model_product_pricelist_item","base.group_user",1,0,0,0
"access_product_pricelist_type_partner_manager","product.pricelist.type partner manager","model_product_pricelist_type","base.group_partner_manager",1,0,0,0
"access_product_pricelist_partner_manager","product.pricelist partner manager","model_product_pricelist","base.group_partner_manager",1,0,0,0
"access_ir_property_group_product_manager","ir_property group_product_manager","base.model_ir_property",product.group_product_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
29 access_product_pricelist_item_user product.pricelist.item.user model_product_pricelist_item base.group_user 1 0 0 0
30 access_product_pricelist_type_partner_manager product.pricelist.type partner manager model_product_pricelist_type base.group_partner_manager 1 0 0 0
31 access_product_pricelist_partner_manager product.pricelist partner manager model_product_pricelist base.group_partner_manager 1 0 0 0
32 access_ir_property_group_product_manager ir_property group_product_manager base.model_ir_property product.group_product_manager 1 1 1 1
+37 -9
View File
@@ -247,15 +247,6 @@ class task(osv.osv):
# ('remaining_hours', 'CHECK (remaining_hours>=0)', 'Please increase and review remaining hours ! It can not be smaller than 0.'),
#]
def _button_dummy(self, cr, uid, ids, context={}):
tot_work=0
for obj in self.browse(cr,uid,ids):
for work in obj.work_ids:
tot_work+=work.hours
final_val = obj.planned_hours - tot_work
self.write(cr,uid,ids[0],{'remaining_hours':final_val})
return True
def copy(self, cr, uid, id, default={},context={}):
default = default or {}
default['work_ids'] = []
@@ -417,8 +408,45 @@ class project_work(osv.osv):
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S')
}
_order = "date desc"
def create(self, cr, uid, vals, *args, **kwargs):
if 'task_id' in vals:
cr.execute('update project_task set remaining_hours=remaining_hours+%.2f where id=%d', (-vals.get('hours',0.0), vals['task_id']))
return super(project_work,self).create(cr, uid, vals, *args, **kwargs)
def write(self, cr, uid, ids,vals,context={}):
for work in self.browse(cr, uid, ids, context):
cr.execute('update project_task set remaining_hours=remaining_hours+%.2f+(%.2f) where id=%d', (-vals.get('hours',0.0), work.hours, work.task_id.id))
return super(project_work,self).write(cr, uid, ids, vals, context)
def unlink(self, cr, uid, ids, *args, **kwargs):
for work in self.browse(cr, uid, ids):
cr.execute('update project_task set remaining_hours=remaining_hours+%.2f where id=%d', (work.hours, work.task_id.id))
return super(project_work,self).unlink(cr, uid, ids,*args, **kwargs)
project_work()
class config_compute_remaining(osv.osv_memory):
_name='config.compute.remaining'
def _get_remaining(self,cr, uid, ctx):
if 'active_id' in ctx:
return self.pool.get('project.task').browse(cr,uid,ctx['active_id']).remaining_hours
return False
_columns = {
'remaining_hours' : fields.float('Remaining Hours', digits=(16,2), help="Total remaining time, can be re-estimated periodically by the assignee of the task."),
}
_defaults = {
'remaining_hours': _get_remaining
}
def compute_hours(self, cr, uid, ids, context=None):
if 'active_id' in context:
remaining_hrs=self.browse(cr,uid,ids)[0].remaining_hours
self.pool.get('project.task').write(cr,uid,context['active_id'],{'remaining_hours':remaining_hrs})
return {
'type': 'ir.actions.act_window_close',
}
config_compute_remaining()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+32 -2
View File
@@ -197,6 +197,34 @@
id="menu_open_view_my_project_open"
parent="project.menu_all_project"/>
<!-- Wizard for compute remaining hours -->
<record id="view_config_compute_remaining" model="ir.ui.view">
<field name="name">Compute Remaining Hours </field>
<field name="model">config.compute.remaining</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Remaining Hours">
<separator colspan="4" string="Change Remaining Hours"/>
<newline/>
<field name="remaining_hours" widget="float_time"/>
<group col="4" colspan="4">
<button icon="gtk-cancel" special="cancel" string="Cancel"/>
<button icon="gtk-ok" name="compute_hours" string="Update" type="object"/>
</group>
</form>
</field>
</record>
<record id="action_config_compute_remaining" model="ir.actions.act_window">
<field name="name">Compute Remaining Hours</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">config.compute.remaining</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
<!-- Task -->
<record id="view_task_form2" model="ir.ui.view">
<field name="name">project.task.form</field>
@@ -220,8 +248,10 @@
widget="float_time"
on_change="onchange_planned(planned_hours,effective_hours)"/>
<field name="delay_hours" widget="float_time"/>
<field name="remaining_hours" select="2" widget="float_time" attrs="{'readonly':[('state','!=','draft')]}" colspan="1"/>
<button name="_button_dummy" string="Compute" type="object" colspan="1"/>
<group col="3" colspan="2">
<field name="remaining_hours" select="2" widget="float_time" attrs="{'readonly':[('state','!=','draft')]}" colspan="2"/>
<button name="%(action_config_compute_remaining)d" string="Review" type="action" colspan="1" target="new" attrs="{'invisible':[('state','=','draft')]}"/>
</group>
<field name="effective_hours" widget="float_time"/>
<field colspan="4" name="description" nolabel="1" select="2"/>
@@ -6,3 +6,4 @@
"access_project_task_manager","project.task manager","model_project_task","project.group_project_manager",1,1,1,1
"access_project_task","project.task","model_project_task","project.group_project_user",1,1,1,1
"access_project_task_work","project.task.work","model_project_task_work","project.group_project_user",1,1,1,1
"access_config_compute_remaining","project.config.compute.remaining","model_config_compute_remaining","project.group_project_manager",1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
6 access_project_task_manager project.task manager model_project_task project.group_project_manager 1 1 1 1
7 access_project_task project.task model_project_task project.group_project_user 1 1 1 1
8 access_project_task_work project.task.work model_project_task_work project.group_project_user 1 1 1 1
9 access_config_compute_remaining project.config.compute.remaining model_config_compute_remaining project.group_project_manager 1 1 1 1
+3 -3
View File
@@ -209,15 +209,15 @@ class sale_order(osv.osv):
'picking_policy': fields.selection([('direct','Partial Delivery'),('one','Complete Delivery')],
'Packing Policy', required=True, help="""If you don't have enough stock available to deliver all at once, do you accept partial shippings or not."""),
'order_policy': fields.selection([
('prepaid','Payment before delivery'),
('prepaid','Payment Before Delivery'),
('manual','Shipping & Manual Invoice'),
('postpaid','Automatic Invoice after delivery'),
('postpaid','Invoice on Order After Delivery'),
('picking','Invoice from the packings'),
], 'Shipping Policy', required=True, readonly=True, states={'draft':[('readonly',False)]},
help="""The Shipping Policy is used to synchronise invoice and delivery operations.
- The 'Pay before delivery' choice will first generate the invoice and then generate the packing order after the payment of this invoice.
- The 'Shipping & Manual Invoice' will create the packing order directly and wait for the user to manually click on the 'Invoice' button to generate the draft invoice.
- The 'Invoice after delivery' choice will generate the draft invoice after the packing list have been finished.
- The 'Invoice on Order Ater Delivery' choice will generate the draft invoice based on sale order after all packing lists have been finished.
- The 'Invoice from the packings' choice is used to create an invoice during the packing process."""),
'pricelist_id':fields.many2one('product.pricelist', 'Pricelist', required=True, readonly=True, states={'draft':[('readonly',False)]}),
'project_id':fields.many2one('account.analytic.account', 'Analytic Account', readonly=True, states={'draft':[('readonly', False)]}),
+1 -1
View File
@@ -27,7 +27,7 @@
<field name="arch" type="xml">
<form string="Stock Inventory Lines">
<field colspan="4" domain="[('usage','=','internal')]" name="location_id" select="1"/>
<field context="location=location_id,uom=product_uom" name="product_id" on_change="on_change_product_id(location_id,product_id,product_uom)" select="1"/>
<field context="location=location_id,uom=product_uom" name="product_id" on_change="on_change_product_id(location_id,product_id,product_uom)" select="1" domain="[('type','&lt;&gt;','service')]"/>
<field name="product_qty"/>
<field name="product_uom"/>
</form>
+4 -2
View File
@@ -99,14 +99,16 @@
<field name="name" select="1"/>
<field name="group_id" select="1" on_change="onchange_group_id(group_id, text_area)"/>
<field name="section" select="2" invisible="not context.get('section',False)"/>
</group>
<field name="text_area" nolabel="1" colspan="4" select="1" widget="text_wiki"/>
<separator colspan="4" string="Modifications"/>
<group col="6" colspan="4">
<field name="write_date" readonly="1" select="2"/>
<field name="review" select="1"/>
<field name="minor_edit" select="2" groups="base.group_extended"/>
<field name="toc"/>
<field name="tags" select="2" groups="base.group_extended"/>
<field name="summary" colspan="4" select="2" groups="base.group_extended"/>
</group>
<field name="text_area" nolabel="1" colspan="4" select="1" widget="text_wiki"/>
</form>
</field>
</record>