# -*- coding: utf-8 -*-
+
import base64
-import glob, os
+import csv
+import glob
+import operator
+import os
+import re
+import simplejson
+import textwrap
+import xmlrpclib
from xml.etree import ElementTree
from cStringIO import StringIO
-import simplejson
+import cherrypy
import openerpweb
import openerpweb.ast
import openerpweb.nonliterals
-import cherrypy
-import xmlrpclib
+from babel.messages.pofile import read_po
# Should move to openerpweb.Xml2Json
class Xml2Json:
# OpenERP Web base Controllers
#----------------------------------------------------------
+def manifest_glob(addons, key):
+ files = []
+ for addon in addons:
+ globlist = openerpweb.addons_manifest.get(addon, {}).get(key, [])
+ print globlist
+ for pattern in globlist:
+ for path in glob.glob(os.path.join(openerpweb.path_addons, addon, pattern)):
+ files.append(path[len(openerpweb.path_addons):])
+ return files
+
+def concat_files(file_list):
+ """ Concatenate file content
+ return (concat,timestamp)
+ concat: concatenation of file content
+ timestamp: max(os.path.getmtime of file_list)
+ """
+ root = openerpweb.path_root
+ files_content = []
+ files_timestamp = 0
+ for i in file_list:
+ fname = os.path.join(root, i)
+ ftime = os.path.getmtime(fname)
+ if ftime > files_timestamp:
+ files_timestamp = ftime
+ files_content = open(fname).read()
+ files_concat = "".join(files_content)
+ return files_concat
+
+home_template = textwrap.dedent("""<!DOCTYPE html>
+<html style="height: 100%%">
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+ <title>OpenERP</title>
+ %(javascript)s
+ <script type="text/javascript">
+ $(function() {
+ QWeb = new QWeb2.Engine();
+ openerp.init().base.webclient("oe");
+ });
+ </script>
+ <link rel="shortcut icon" href="/base/static/src/img/favicon.ico" type="image/x-icon"/>
+ %(css)s
+ <!--[if lte IE 7]>
+ <link rel="stylesheet" href="/base/static/src/css/base-ie7.css" type="text/css"/>
+ <![endif]-->
+ </head>
+ <body id="oe" class="openerp"></body>
+</html>
+""")
+class WebClient(openerpweb.Controller):
+ _cp_path = "/base/webclient"
+
+ @openerpweb.jsonrequest
+ def csslist(self, req, mods='base'):
+ return manifest_glob(mods.split(','), 'css')
+
+ @openerpweb.jsonrequest
+ def jslist(self, req, mods='base'):
+ return manifest_glob(mods.split(','), 'js')
+
+ @openerpweb.httprequest
+ def css(self, req, mods='base'):
+ cherrypy.response.headers['Content-Type'] = 'text/css'
+ files = manifest_glob(mods.split(','), 'css')
+ concat = concat_files(files)[0]
+ # TODO request set the Date of last modif and Etag
+ return concat
+
+ @openerpweb.httprequest
+ def js(self, req, mods='base'):
+ cherrypy.response.headers['Content-Type'] = 'application/javascript'
+ files = manifest_glob(mods.split(','), 'js')
+ concat = concat_files(files)[0]
+ # TODO request set the Date of last modif and Etag
+ return concat
+
+ @openerpweb.httprequest
+ def home(self, req, s_action=None):
+ # script tags
+ jslist = ['/base/webclient/js']
+ if 1: # debug == 1
+ jslist = manifest_glob(['base'], 'js')
+ js = "\n ".join(['<script type="text/javascript" src="%s"></script>'%i for i in jslist])
+
+ # css tags
+ csslist = ['/base/webclient/css']
+ if 1: # debug == 1
+ csslist = manifest_glob(['base'], 'css')
+ css = "\n ".join(['<link rel="stylesheet" href="%s">'%i for i in csslist])
+ r = home_template % {
+ 'javascript': js,
+ 'css': css
+ }
+ return r
+
+ @openerpweb.jsonrequest
+ def translations(self, req, mods, lang):
+ transs = {}
+ for addon_name in mods:
+ transl = {"messages":[]}
+ transs[addon_name] = transl
+ f_name = os.path.join(openerpweb.path_addons, addon_name, "po", lang + ".po")
+ if not os.path.exists(f_name):
+ continue
+ try:
+ with open(f_name) as t_file:
+ po = read_po(t_file)
+ except:
+ continue
+ for x in po:
+ if x.id:
+ transl["messages"].append({'id': x.id, 'string': x.string})
+ return {"modules": transs}
+
+
+class Database(openerpweb.Controller):
+ _cp_path = "/base/database"
+
+ @openerpweb.jsonrequest
+ def get_list(self, req):
+ proxy = req.session.proxy("db")
+ dbs = proxy.list()
+ h = req.httprequest.headers['Host'].split(':')[0]
+ d = h.split('.')[0]
+ r = cherrypy.config['openerp.dbfilter'].replace('%h', h).replace('%d', d)
+ dbs = [i for i in dbs if re.match(r, i)]
+ return {"db_list": dbs}
+
+ @openerpweb.jsonrequest
+ def progress(self, req, password, id):
+ return req.session.proxy('db').get_progress(password, id)
+
+ @openerpweb.jsonrequest
+ def create(self, req, fields):
+
+ params = dict(map(operator.itemgetter('name', 'value'), fields))
+ create_attrs = (
+ params['super_admin_pwd'],
+ params['db_name'],
+ bool(params.get('demo_data')),
+ params['db_lang'],
+ params['create_admin_pwd']
+ )
+
+ try:
+ return req.session.proxy("db").create(*create_attrs)
+ except xmlrpclib.Fault, e:
+ if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
+ return {'error': e.faultCode, 'title': 'Create Database'}
+ return {'error': 'Could not create database !', 'title': 'Create Database'}
+
+ @openerpweb.jsonrequest
+ def drop(self, req, fields):
+ password, db = operator.itemgetter(
+ 'drop_pwd', 'drop_db')(
+ dict(map(operator.itemgetter('name', 'value'), fields)))
+
+ try:
+ return req.session.proxy("db").drop(password, db)
+ except xmlrpclib.Fault, e:
+ if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
+ return {'error': e.faultCode, 'title': 'Drop Database'}
+ return {'error': 'Could not drop database !', 'title': 'Drop Database'}
+
+ @openerpweb.httprequest
+ def backup(self, req, backup_db, backup_pwd, token):
+ try:
+ db_dump = base64.decodestring(
+ req.session.proxy("db").dump(backup_pwd, backup_db))
+ cherrypy.response.headers['Content-Type'] = "application/octet-stream; charset=binary"
+ cherrypy.response.headers['Content-Disposition'] = 'attachment; filename="' + backup_db + '.dump"'
+ cherrypy.response.cookie['fileToken'] = token
+ cherrypy.response.cookie['fileToken']['path'] = '/'
+ return db_dump
+ except xmlrpclib.Fault, e:
+ if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
+ return 'Backup Database|' + e.faultCode
+ return 'Backup Database|Could not generate database backup'
+
+ @openerpweb.httprequest
+ def restore(self, req, db_file, restore_pwd, new_db):
+ try:
+ data = base64.encodestring(db_file.file.read())
+ req.session.proxy("db").restore(restore_pwd, new_db, data)
+ return ''
+ except xmlrpclib.Fault, e:
+ if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
+ raise cherrypy.HTTPError(403)
+
+ raise cherrypy.HTTPError()
+
+ @openerpweb.jsonrequest
+ def change_password(self, req, fields):
+ old_password, new_password = operator.itemgetter(
+ 'old_pwd', 'new_pwd')(
+ dict(map(operator.itemgetter('name', 'value'), fields)))
+ try:
+ return req.session.proxy("db").change_admin_password(old_password, new_password)
+ except xmlrpclib.Fault, e:
+ if e.faultCode and e.faultCode.split(':')[0] == 'AccessDenied':
+ return {'error': e.faultCode, 'title': 'Change Password'}
+ return {'error': 'Error, password not changed !', 'title': 'Change Password'}
+
class Session(openerpweb.Controller):
_cp_path = "/base/session"
- def manifest_glob(self, addons, key):
- files = []
- for addon in addons:
- globlist = openerpweb.addons_manifest.get(addon, {}).get(key, [])
-
- files.extend([
- resource_path[len(openerpweb.path_addons):]
- for pattern in globlist
- for resource_path in glob.glob(os.path.join(
- openerpweb.path_addons, addon, pattern))
- ])
- return files
-
- def concat_files(self, file_list):
- """ Concatenate file content
- return (concat,timestamp)
- concat: concatenation of file content
- timestamp: max(os.path.getmtime of file_list)
- """
- root = openerpweb.path_root
- files_content = []
- files_timestamp = 0
- for i in file_list:
- fname = os.path.join(root, i)
- ftime = os.path.getmtime(fname)
- if ftime > files_timestamp:
- files_timestamp = ftime
- files_content = open(fname).read()
- files_concat = "".join(files_content)
- return files_concat
-
@openerpweb.jsonrequest
def login(self, req, db, login, password):
req.session.login(db, login, password)
+ ctx = req.session.get_context()
return {
"session_id": req.session_id,
"uid": req.session._uid,
+ "context": ctx
}
@openerpweb.jsonrequest
req.session.eval_context(req.context))
@openerpweb.jsonrequest
- def get_databases_list(self, req):
- proxy = req.session.proxy("db")
- dbs = proxy.list()
-
- return {"db_list": dbs}
-
- @openerpweb.jsonrequest
def get_lang_list(self, req):
- lang_list = [('en_US', 'English (US)')]
try:
- lang_list = lang_list + (req.session.proxy("db").list_lang() or [])
+ return {
+ 'lang_list': (req.session.proxy("db").list_lang() or []),
+ 'error': ""
+ }
except Exception, e:
- pass
- return {"lang_list": lang_list}
-
- @openerpweb.jsonrequest
- def db_operation(self, req, flag, **kw):
-
- if flag == 'create':
- pass
-
- elif flag == 'drop':
- db = kw.get('db')
- password = kw.get('password')
-
- return req.session.proxy("db").drop(password, db)
-
- elif flag == 'backup':
- db = kw.get('db')
- password = kw.get('password')
- try:
- res = req.session.proxy("db").dump(password, db)
- if res:
- cherrypy.response.headers['Content-Type'] = "application/data"
- cherrypy.response.headers['Content-Disposition'] = 'filename="' + db + '.dump"'
- return base64.decodestring(res)
- except Exception:
- return {'error': 'Could not create backup !'}
-
- elif flag == 'restore':
- filename = kw.get('filename')
- db = kw.get('db')
- password = kw.get('password')
-
- try:
- if filename:
- data = base64.encodestring(filename.file.read())
- return req.session.proxy("db").restore(password, db, data)
- except Exception:
- return {'error': 'Could not restore database !'}
-
- elif flag == 'change_password':
- old_password = kw.get('old_password')
- new_password = kw.get('new_password')
- confirm_password = kw.get('confirm_password')
-
- if old_password and new_password and confirm_password:
- return req.session.proxy("db").change_admin_password(old_password, new_password)
+ return {"error": e, "title": "Languages"}
@openerpweb.jsonrequest
def modules(self, req):
- return {"modules": [name
- for name, manifest in openerpweb.addons_manifest.iteritems()
- if manifest.get('active', True)]}
-
- @openerpweb.jsonrequest
- def csslist(self, req, mods='base'):
- return {'files': self.manifest_glob(mods.split(','), 'css')}
-
- @openerpweb.jsonrequest
- def jslist(self, req, mods='base'):
- return {'files': self.manifest_glob(mods.split(','), 'js')}
-
- def css(self, req, mods='base'):
- files = self.manifest_glob(mods.split(','), 'css')
- concat = self.concat_files(files)[0]
- # TODO request set the Date of last modif and Etag
- return concat
- css.exposed = True
-
- def js(self, req, mods='base'):
- files = self.manifest_glob(mods.split(','), 'js')
- concat = self.concat_files(files)[0]
- # TODO request set the Date of last modif and Etag
- return concat
- js.exposed = True
+ # TODO query server for installed web modules
+ mods = []
+ for name, manifest in openerpweb.addons_manifest.items():
+ if name != 'base' and manifest.get('active', True):
+ mods.append(name)
+ return mods
@openerpweb.jsonrequest
def eval_domain_and_context(self, req, contexts, domains,
context, domain = eval_context_and_domain(req.session,
openerpweb.nonliterals.CompoundContext(*(contexts or [])),
openerpweb.nonliterals.CompoundDomain(*(domains or [])))
-
+
group_by_sequence = []
for candidate in (group_by_seq or []):
ctx = req.session.eval_context(candidate, context)
group_by_sequence.append(group_by)
else:
group_by_sequence.extend(group_by)
-
+
return {
'context': context,
'domain': domain,
This method store an action object in the session object and returns an integer
identifying that action. The method get_session_action() can be used to get
back the action.
-
+
:param the_action: The action to save in the session.
:type the_action: anything
:return: A key identifying the saved action.
"""
Gets back a previously saved action. This method can return None if the action
was saved since too much time (this case should be handled in a smart way).
-
+
:param key: The key given by save_session_action()
:type key: integer
:return: The saved action or None.
if not saved_actions:
return None
return saved_actions["actions"].get(key)
-
+
+ @openerpweb.jsonrequest
+ def check(self, req):
+ req.session.assert_valid()
+ return None
+
def eval_context_and_domain(session, context, domain=None):
e_context = session.eval_context(context)
# should we give the evaluated context as an evaluation context to the domain?
e_domain = session.eval_domain(domain or [])
return e_context, e_domain
-
+
def load_actions_from_ir_values(req, key, key2, models, meta, context):
Values = req.session.model('ir.values')
actions = Values.get(key, key2, models, meta, context)
- return [(id, name, clean_action(action, req.session))
+ return [(id, name, clean_action(action, req.session, context=context))
for id, name, action in actions]
-def clean_action(action, session):
+def clean_action(action, session, context=None):
+ action.setdefault('flags', {})
if action['type'] != 'ir.actions.act_window':
return action
# values come from the server, we can just eval them
- if isinstance(action.get('context', None), basestring):
+ if isinstance(action.get('context'), basestring):
action['context'] = eval(
action['context'],
- session.evaluation_context()) or {}
+ session.evaluation_context(context=context)) or {}
- if isinstance(action.get('domain', None), basestring):
+ if isinstance(action.get('domain'), basestring):
action['domain'] = eval(
action['domain'],
session.evaluation_context(
- action['context'])) or []
- if 'flags' not in action:
- # Set empty flags dictionary for web client.
- action['flags'] = dict()
+ action.get('context', {}))) or []
+
return fix_view_modes(action)
def generate_views(action):
return
action['views'] = [(view_id, view_modes[0])]
-
def fix_view_modes(action):
""" For historical reasons, OpenERP has weird dealings in relation to
view_mode and the view_type attribute (on window actions):
generate_views(action)
if action.pop('view_type') != 'form':
- return
+ return action
action['views'] = [
[id, mode if mode != 'tree' else 'list']
menu_items = Menus.read(menu_ids, ['name', 'sequence', 'parent_id'], context)
menu_root = {'id': False, 'name': 'root', 'parent_id': [-1, '']}
menu_items.append(menu_root)
-
+
# make a tree using parent_id
menu_items_map = dict((menu_item["id"], menu_item) for menu_item in menu_items)
for menu_item in menu_items:
:rtype: list
"""
Model = request.session.model(model)
+
context, domain = eval_context_and_domain(
request.session, request.context, domain)
@openerpweb.jsonrequest
+ def read(self, request, model, ids, fields=False):
+ return self.do_search_read(request, model, ids, fields)
+
+ @openerpweb.jsonrequest
def get(self, request, model, ids, fields=False):
return self.do_get(request, model, ids, fields)
+
def do_get(self, request, model, ids, fields=False):
""" Fetches and returns the records of the model ``model`` whose ids
are in ``ids``.
record_map = dict((record['id'], record) for record in records)
return [record_map[id] for id in ids if record_map.get(id)]
-
+
@openerpweb.jsonrequest
def load(self, req, model, id, fields):
m = req.session.model(model)
@openerpweb.jsonrequest
def call(self, req, model, method, args, domain_id=None, context_id=None):
- return {'result': self.call_common(req, model, method, args, domain_id, context_id)}
+ return self.call_common(req, model, method, args, domain_id, context_id)
@openerpweb.jsonrequest
def call_button(self, req, model, method, args, domain_id=None, context_id=None):
@openerpweb.jsonrequest
def default_get(self, req, model, fields):
+ Model = req.session.model(model)
+ return Model.default_get(fields, req.session.eval_context(req.context))
+
+ @openerpweb.jsonrequest
+ def name_search(self, req, model, search_str, domain=[], context={}):
m = req.session.model(model)
- r = m.default_get(fields, req.session.eval_context(req.context))
+ r = m.name_search(search_str+'%', domain, '=ilike', context)
return {'result': r}
class DataGroup(openerpweb.Controller):
_cp_path = "/base/group"
@openerpweb.jsonrequest
- def read(self, request, model, group_by_fields, domain=None):
+ def read(self, request, model, fields, group_by_fields, domain=None, sort=None):
Model = request.session.model(model)
context, domain = eval_context_and_domain(request.session, request.context, domain)
return Model.read_group(
- domain or [], False, group_by_fields, 0, False,
- dict(context, group_by=group_by_fields))
+ domain or [], fields, group_by_fields, 0, False,
+ dict(context, group_by=group_by_fields), sort or False)
class View(openerpweb.Controller):
_cp_path = "/base/view"
# todo fme?: check that we should pass the evaluated context here
self.process_view(request.session, fvg, context, transform)
return fvg
-
+
def process_view(self, session, fvg, context, transform):
# depending on how it feels, xmlrpclib.ServerProxy can translate
# XML-RPC strings to ``str`` or ``unicode``. ElementTree does not
else:
xml = ElementTree.fromstring(arch)
fvg['arch'] = Xml2Json.convert_element(xml)
- for field in fvg['fields'].values():
- if field.has_key('views') and field['views']:
- for view in field["views"].values():
+
+ for field in fvg['fields'].itervalues():
+ if field.get('views'):
+ for view in field["views"].itervalues():
self.process_view(session, view, None, transform)
+ if field.get('domain'):
+ field["domain"] = self.parse_domain(field["domain"], session)
+ if field.get('context'):
+ field["context"] = self.parse_context(field["context"], session)
@openerpweb.jsonrequest
def add_custom(self, request, view_id, arch):
self.parse_domains_and_contexts(elem, session)
return root
- def parse_domain(self, elem, attr_name, session):
- """ Parses an attribute of the provided name as a domain, transforms it
+ def parse_domain(self, domain, session):
+ """ Parses an arbitrary string containing a domain, transforms it
to either a literal domain or a :class:`openerpweb.nonliterals.Domain`
- :param elem: the node being parsed
- :type param: xml.etree.ElementTree.Element
- :param str attr_name: the name of the attribute which should be parsed
+ :param domain: the domain to parse, if the domain is not a string it
+ is assumed to be a literal domain and is returned as-is
:param session: Current OpenERP session
:type session: openerpweb.openerpweb.OpenERPSession
"""
- domain = elem.get(attr_name, '').strip()
- if domain:
- try:
- elem.set(
- attr_name,
- openerpweb.ast.literal_eval(
- domain))
- except ValueError:
- # not a literal
- elem.set(attr_name,
- openerpweb.nonliterals.Domain(session, domain))
+ if not isinstance(domain, (str, unicode)):
+ return domain
+ try:
+ return openerpweb.ast.literal_eval(domain)
+ except ValueError:
+ # not a literal
+ return openerpweb.nonliterals.Domain(session, domain)
+
+ def parse_context(self, context, session):
+ """ Parses an arbitrary string containing a context, transforms it
+ to either a literal context or a :class:`openerpweb.nonliterals.Context`
+
+ :param context: the context to parse, if the context is not a string it
+ is assumed to be a literal domain and is returned as-is
+ :param session: Current OpenERP session
+ :type session: openerpweb.openerpweb.OpenERPSession
+ """
+ if not isinstance(context, (str, unicode)):
+ return context
+ try:
+ return openerpweb.ast.literal_eval(context)
+ except ValueError:
+ return openerpweb.nonliterals.Context(session, context)
def parse_domains_and_contexts(self, elem, session):
""" Converts domains and contexts from the view into Python objects,
non-literal objects
:type session: openerpweb.openerpweb.OpenERPSession
"""
- self.parse_domain(elem, 'domain', session)
- self.parse_domain(elem, 'filter_domain', session)
+ for el in ['domain', 'filter_domain']:
+ domain = elem.get(el, '').strip()
+ if domain:
+ elem.set(el, self.parse_domain(domain, session))
for el in ['context', 'default_get']:
context_string = elem.get(el, '').strip()
if context_string:
- try:
- elem.set(el,
- openerpweb.ast.literal_eval(context_string))
- except ValueError:
- elem.set(el,
- openerpweb.nonliterals.Context(
- session, context_string))
+ elem.set(el, self.parse_context(context_string, session))
class FormView(View):
_cp_path = "/base/formview"
def fields_get(self, req, model):
Model = req.session.model(model)
fields = Model.fields_get(False, req.session.eval_context(req.context))
+ for field in fields.values():
+ # shouldn't convert the views too?
+ if field.get('domain'):
+ field["domain"] = self.parse_domain(field["domain"], req.session)
+ if field.get('context'):
+ field["context"] = self.parse_domain(field["context"], req.session)
return {'fields': fields}
+
+ @openerpweb.jsonrequest
+ def get_filters(self, req, model):
+ Model = req.session.model("ir.filters")
+ filters = Model.get_filters(model)
+ for filter in filters:
+ filter["context"] = req.session.eval_context(self.parse_context(filter["context"], req.session))
+ filter["domain"] = req.session.eval_domain(self.parse_domain(filter["domain"], req.session))
+ return filters
+
+ @openerpweb.jsonrequest
+ def save_filter(self, req, model, name, context_to_save, domain):
+ Model = req.session.model("ir.filters")
+ ctx = openerpweb.nonliterals.CompoundContext(context_to_save)
+ ctx.session = req.session
+ ctx = ctx.evaluate()
+ domain = openerpweb.nonliterals.CompoundDomain(domain)
+ domain.session = req.session
+ domain = domain.evaluate()
+ uid = req.session._uid
+ context = req.session.eval_context(req.context)
+ to_return = Model.create_or_replace({"context": ctx,
+ "domain": domain,
+ "model_id": model,
+ "name": name,
+ "user_id": uid
+ }, context)
+ return to_return
class Binary(openerpweb.Controller):
_cp_path = "/base/binary"
def run(self, req, action_id):
return clean_action(req.session.model('ir.actions.server').run(
[action_id], req.session.eval_context(req.context)), req.session)
+
+class TreeView(View):
+ _cp_path = "/base/treeview"
+
+ @openerpweb.jsonrequest
+ def load(self, req, model, view_id, toolbar=False):
+ return self.fields_view_get(req, model, view_id, 'tree', toolbar=toolbar)
+
+ @openerpweb.jsonrequest
+ def action(self, req, model, id):
+ return load_actions_from_ir_values(
+ req,'action', 'tree_but_open',[(model, id)],
+ False, req.session.eval_context(req.context))
+
+def export_csv(fields, result):
+ fp = StringIO()
+ writer = csv.writer(fp, quoting=csv.QUOTE_ALL)
+
+ writer.writerow(fields)
+
+ for data in result:
+ row = []
+ for d in data:
+ if isinstance(d, basestring):
+ d = d.replace('\n',' ').replace('\t',' ')
+ try:
+ d = d.encode('utf-8')
+ except:
+ pass
+ if d is False: d = None
+ row.append(d)
+ writer.writerow(row)
+
+ fp.seek(0)
+ data = fp.read()
+ fp.close()
+ return data
+
+def export_xls(fieldnames, table):
+ try:
+ import xlwt
+ except ImportError:
+ common.error(_('Import Error.'), _('Please install xlwt library to export to MS Excel.'))
+
+ workbook = xlwt.Workbook()
+ worksheet = workbook.add_sheet('Sheet 1')
+
+ for i, fieldname in enumerate(fieldnames):
+ worksheet.write(0, i, str(fieldname))
+ worksheet.col(i).width = 8000 # around 220 pixels
+
+ style = xlwt.easyxf('align: wrap yes')
+
+ for row_index, row in enumerate(table):
+ for cell_index, cell_value in enumerate(row):
+ cell_value = str(cell_value)
+ cell_value = re.sub("\r", " ", cell_value)
+ worksheet.write(row_index + 1, cell_index, cell_value, style)
+
+
+ fp = StringIO()
+ workbook.save(fp)
+ fp.seek(0)
+ data = fp.read()
+ fp.close()
+ #return data.decode('ISO-8859-1')
+ return unicode(data, 'utf-8', 'replace')
+
+class Export(View):
+ _cp_path = "/base/export"
+
+ def fields_get(self, req, model):
+ Model = req.session.model(model)
+ fields = Model.fields_get(False, req.session.eval_context(req.context))
+ return fields
+
+ @openerpweb.jsonrequest
+ def get_fields(self, req, model, prefix='', name= '', field_parent=None, params={}):
+ import_compat = params.get("import_compat", False)
+
+ fields = self.fields_get(req, model)
+ field_parent_type = params.get("parent_field_type",False)
+
+ if import_compat and field_parent_type and field_parent_type == "many2one":
+ fields = {}
+
+ fields.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
+ records = []
+ fields_order = fields.keys()
+ fields_order.sort(lambda x,y: -cmp(fields[x].get('string', ''), fields[y].get('string', '')))
+
+ for index, field in enumerate(fields_order):
+ value = fields[field]
+ record = {}
+ if import_compat and value.get('readonly', False):
+ ok = False
+ for sl in value.get('states', {}).values():
+ for s in sl:
+ ok = ok or (s==['readonly',False])
+ if not ok: continue
+
+ id = prefix + (prefix and '/'or '') + field
+ nm = name + (name and '/' or '') + value['string']
+ record.update(id=id, string= nm, action='javascript: void(0)',
+ target=None, icon=None, children=[], field_type=value.get('type',False), required=value.get('required', False))
+ records.append(record)
+
+ if len(nm.split('/')) < 3 and value.get('relation', False):
+ if import_compat:
+ ref = value.pop('relation')
+ cfields = self.fields_get(req, ref)
+ if (value['type'] == 'many2many'):
+ record['children'] = []
+ record['params'] = {'model': ref, 'prefix': id, 'name': nm}
+
+ elif value['type'] == 'many2one':
+ record['children'] = [id + '/id', id + '/.id']
+ record['params'] = {'model': ref, 'prefix': id, 'name': nm}
+
+ else:
+ cfields_order = cfields.keys()
+ cfields_order.sort(lambda x,y: -cmp(cfields[x].get('string', ''), cfields[y].get('string', '')))
+ children = []
+ for j, fld in enumerate(cfields_order):
+ cid = id + '/' + fld
+ cid = cid.replace(' ', '_')
+ children.append(cid)
+ record['children'] = children or []
+ record['params'] = {'model': ref, 'prefix': id, 'name': nm}
+ else:
+ ref = value.pop('relation')
+ cfields = self.fields_get(req, ref)
+ cfields_order = cfields.keys()
+ cfields_order.sort(lambda x,y: -cmp(cfields[x].get('string', ''), cfields[y].get('string', '')))
+ children = []
+ for j, fld in enumerate(cfields_order):
+ cid = id + '/' + fld
+ cid = cid.replace(' ', '_')
+ children.append(cid)
+ record['children'] = children or []
+ record['params'] = {'model': ref, 'prefix': id, 'name': nm}
+
+ records.reverse()
+ return records
+
+ @openerpweb.jsonrequest
+ def save_export_lists(self, req, name, model, field_list):
+ result = {'resource':model, 'name':name, 'export_fields': []}
+ for field in field_list:
+ result['export_fields'].append((0, 0, {'name': field}))
+ return req.session.model("ir.exports").create(result, req.session.eval_context(req.context))
+
+ @openerpweb.jsonrequest
+ def exist_export_lists(self, req, model):
+ export_model = req.session.model("ir.exports")
+ return export_model.read(export_model.search([('resource', '=', model)]), ['name'])
+
+ @openerpweb.jsonrequest
+ def delete_export(self, req, export_id):
+ req.session.model("ir.exports").unlink(export_id, req.session.eval_context(req.context))
+ return True
+
+ @openerpweb.jsonrequest
+ def namelist(self,req, model, export_id):
+
+ result = self.get_data(req, model, req.session.eval_context(req.context))
+ ir_export_obj = req.session.model("ir.exports")
+ ir_export_line_obj = req.session.model("ir.exports.line")
+
+ field = ir_export_obj.read(export_id)
+ fields = ir_export_line_obj.read(field['export_fields'])
+
+ name_list = {}
+ [name_list.update({field['name']: result.get(field['name'])}) for field in fields]
+ return name_list
+
+ def get_data(self, req, model, context=None):
+ ids = []
+ context = context or {}
+ fields_data = {}
+ proxy = req.session.model(model)
+ fields = self.fields_get(req, model)
+ if not ids:
+ f1 = proxy.fields_view_get(False, 'tree', context)['fields']
+ f2 = proxy.fields_view_get(False, 'form', context)['fields']
+
+ fields = dict(f1)
+ fields.update(f2)
+ fields.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
+
+ def rec(fields):
+ _fields = {'id': 'ID' , '.id': 'Database ID' }
+ def model_populate(fields, prefix_node='', prefix=None, prefix_value='', level=2):
+ fields_order = fields.keys()
+ fields_order.sort(lambda x,y: -cmp(fields[x].get('string', ''), fields[y].get('string', '')))
+
+ for field in fields_order:
+ fields_data[prefix_node+field] = fields[field]
+ if prefix_node:
+ fields_data[prefix_node + field]['string'] = '%s%s' % (prefix_value, fields_data[prefix_node + field]['string'])
+ st_name = fields[field]['string'] or field
+ _fields[prefix_node+field] = st_name
+ if fields[field].get('relation', False) and level>0:
+ fields2 = self.fields_get(req, fields[field]['relation'])
+ fields2.update({'id': {'string': 'ID'}, '.id': {'string': 'Database ID'}})
+ model_populate(fields2, prefix_node+field+'/', None, st_name+'/', level-1)
+ model_populate(fields)
+ return _fields
+ return rec(fields)
+
+ @openerpweb.jsonrequest
+ def export_data(self, req, model, fields, ids, domain, import_compat=False, export_format="csv", context=None):
+ context = req.session.eval_context(req.context)
+ modle_obj = req.session.model(model)
+ ids = ids or modle_obj.search(domain, context=context)
+
+ field = fields.keys()
+ result = modle_obj.export_data(ids, field , context).get('datas',[])
+
+ if not import_compat:
+ field = [val.strip() for val in fields.values()]
+
+ if export_format == 'xls':
+ return export_xls(field, result)
+ else:
+ return export_csv(field, result)