[MERGE] Merge from openerp-web.

bzr revid: jra@tinyerp.com-20110831062056-oftc3hgx8297sfhj
This commit is contained in:
Jiten (OpenERP) 2011-08-31 11:50:56 +05:30
commit f9a31ab33e
33 changed files with 472 additions and 289 deletions

View File

@ -1 +1,6 @@
import common
import controllers
# TODO
# if we detect that we are imported from the openerp server register common.Root() as a wsgi entry point

View File

@ -0,0 +1,5 @@
#!/usr/bin/python
# TODO if from openerpserver use backendlocal
# from backendlocal import *
from backendrpc import *
from dispatch import *

View File

@ -0,0 +1,23 @@
#----------------------------------------------------------
# OpenERPSession local openerp backend access
#----------------------------------------------------------
class OpenERPUnboundException(Exception):
pass
class OpenERPConnector(object):
pass
class OpenERPAuth(object):
pass
class OpenERPModel(object):
def __init__(self, session, model):
self._session = session
self._model = model
def __getattr__(self, name):
return lambda *l:self._session.execute(self._model, name, *l)
class OpenERPSession(object):
def __init__(self, model_factory=OpenERPModel):
pass

View File

@ -0,0 +1,212 @@
#!/usr/bin/python
import datetime
import urllib
import dateutil.relativedelta
import functools
import logging
import optparse
import os
import sys
import tempfile
import time
import traceback
import uuid
import xmlrpclib
import cherrypy
import cherrypy.lib.static
import simplejson
import nonliterals
#----------------------------------------------------------
# OpenERPSession RPC openerp backend access
#----------------------------------------------------------
class OpenERPUnboundException(Exception):
pass
class OpenERPConnector(object):
pass
class OpenERPAuth(object):
pass
class OpenERPModel(object):
def __init__(self, session, model):
self._session = session
self._model = model
def __getattr__(self, name):
return lambda *l:self._session.execute(self._model, name, *l)
class OpenERPSession(object):
"""
An OpenERP RPC session, a given user can own multiple such sessions
in a web session.
.. attribute:: context
The session context, a ``dict``. Can be reloaded by calling
:meth:`openerpweb.openerpweb.OpenERPSession.get_context`
.. attribute:: domains_store
A ``dict`` matching domain keys to evaluable (but non-literal) domains.
Used to store references to non-literal domains which need to be
round-tripped to the client browser.
"""
def __init__(self, server='127.0.0.1', port=8069, model_factory=OpenERPModel):
self._server = server
self._port = port
self._db = False
self._uid = False
self._login = False
self._password = False
self.model_factory = model_factory
self._locale = 'en_US'
self.context = {}
self.contexts_store = {}
self.domains_store = {}
self._lang = {}
self.remote_timezone = 'utc'
self.client_timezone = False
def proxy(self, service):
s = xmlrpclib.ServerProxy('http://%s:%s/xmlrpc/%s' % (self._server, self._port, service))
return s
def bind(self, db, uid, password):
self._db = db
self._uid = uid
self._password = password
def login(self, db, login, password):
uid = self.proxy('common').login(db, login, password)
self.bind(db, uid, password)
self._login = login
if uid: self.get_context()
return uid
def assert_valid(self):
"""
Ensures this session is valid (logged into the openerp server)
"""
if not (self._db and self._uid and self._password):
raise OpenERPUnboundException()
def execute(self, model, func, *l, **d):
self.assert_valid()
r = self.proxy('object').execute(self._db, self._uid, self._password, model, func, *l, **d)
return r
def exec_workflow(self, model, id, signal):
self.assert_valid()
r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
return r
def model(self, model):
""" Get an RPC proxy for the object ``model``, bound to this session.
:param model: an OpenERP model name
:type model: str
:rtype: :class:`openerpweb.openerpweb.OpenERPModel`
"""
return self.model_factory(self, model)
def get_context(self):
""" Re-initializes the current user's session context (based on
his preferences) by calling res.users.get_context() with the old
context
:returns: the new context
"""
assert self._uid, "The user needs to be logged-in to initialize his context"
self.context = self.model('res.users').context_get(self.context)
self.context = self.context or {}
self.client_timezone = self.context.get("tz", False)
# invalid code, anyway we decided the server will be in UTC
#if self.client_timezone:
# self.remote_timezone = self.execute('common', 'timezone_get')
self._locale = self.context.get('lang','en_US')
lang_ids = self.execute('res.lang','search', [('code', '=', self._locale)])
if lang_ids:
self._lang = self.execute('res.lang', 'read',lang_ids[0], [])
return self.context
@property
def base_eval_context(self):
""" Default evaluation context for the session.
Used to evaluate contexts and domains.
"""
base = dict(
uid=self._uid,
current_date=datetime.date.today().strftime('%Y-%m-%d'),
time=time,
datetime=datetime,
relativedelta=dateutil.relativedelta.relativedelta
)
base.update(self.context)
return base
def evaluation_context(self, context=None):
""" Returns the session's evaluation context, augmented with the
provided context if any.
:param dict context: to add merge in the session's base eval context
:returns: the augmented context
:rtype: dict
"""
d = dict(self.base_eval_context)
if context:
d.update(context)
d['context'] = d
return d
def eval_context(self, context_to_eval, context=None):
""" Evaluates the provided context_to_eval in the context (haha) of
the context. Also merges the evaluated context with the session's context.
:param context_to_eval: a context to evaluate. Must be a dict or a
non-literal context. If it's a dict, will be
returned as-is
:type context_to_eval: openerpweb.nonliterals.Context
:returns: the evaluated context
:rtype: dict
:raises: ``TypeError`` if ``context_to_eval`` is neither a dict nor
a Context
"""
ctx = dict(
self.base_eval_context,
**(context or {}))
# adding the context of the session to send to the openerp server
ccontext = nonliterals.CompoundContext(self.context, context_to_eval or {})
ccontext.session = self
return ccontext.evaluate(ctx)
def eval_domain(self, domain, context=None):
""" Evaluates the provided domain using the provided context
(merged with the session's evaluation context)
:param domain: an OpenERP domain as a list or as a
:class:`openerpweb.nonliterals.Domain` instance
In the second case, it will be evaluated and returned.
:type domain: openerpweb.nonliterals.Domain
:param dict context: the context to use in the evaluation, if any.
:returns: the evaluated domain
:rtype: list
:raises: ``TypeError`` if ``domain`` is neither a list nor a Domain
"""
if isinstance(domain, list):
return domain
cdomain = nonliterals.CompoundDomain(domain)
cdomain.session = self
return cdomain.evaluate(context or {})

View File

@ -3,6 +3,7 @@ import datetime
import urllib
import dateutil.relativedelta
import functools
import logging
import optparse
import os
import sys
@ -17,14 +18,18 @@ import cherrypy.lib.static
import simplejson
import nonliterals
import logging
# TODO if from openerpserver use backendlocal
# from backendlocal import *
from backendrpc import *
#-----------------------------------------------------------
# Globals
#-----------------------------------------------------------
path_root = os.path.dirname(os.path.dirname(os.path.normpath(__file__)))
path_addons = os.path.join(path_root, 'addons')
import __main__
path_root = __main__.path_root
path_addons = __main__.path_addons
cherrypy_root = None
#-----------------------------------------------------------
@ -38,199 +43,6 @@ controllers_class = {}
controllers_object = {}
controllers_path = {}
#----------------------------------------------------------
# OpenERP Client Library
#----------------------------------------------------------
class OpenERPUnboundException(Exception):
pass
class OpenERPConnector(object):
pass
class OpenERPAuth(object):
pass
class OpenERPModel(object):
def __init__(self, session, model):
self._session = session
self._model = model
def __getattr__(self, name):
return lambda *l:self._session.execute(self._model, name, *l)
class OpenERPSession(object):
"""
An OpenERP RPC session, a given user can own multiple such sessions
in a web session.
.. attribute:: context
The session context, a ``dict``. Can be reloaded by calling
:meth:`openerpweb.openerpweb.OpenERPSession.get_context`
.. attribute:: domains_store
A ``dict`` matching domain keys to evaluable (but non-literal) domains.
Used to store references to non-literal domains which need to be
round-tripped to the client browser.
"""
def __init__(self, server='127.0.0.1', port=8069, model_factory=OpenERPModel):
self._server = server
self._port = port
self._db = False
self._uid = False
self._login = False
self._password = False
self.model_factory = model_factory
self._locale = 'en_US'
self.context = {}
self.contexts_store = {}
self.domains_store = {}
self._lang = {}
self.remote_timezone = 'utc'
self.client_timezone = False
def proxy(self, service):
s = xmlrpclib.ServerProxy('http://%s:%s/xmlrpc/%s' % (self._server, self._port, service))
return s
def bind(self, db, uid, password):
self._db = db
self._uid = uid
self._password = password
def login(self, db, login, password):
uid = self.proxy('common').login(db, login, password)
self.bind(db, uid, password)
self._login = login
if uid: self.get_context()
return uid
def assert_valid(self):
"""
Ensures this session is valid (logged into the openerp server)
"""
if not (self._db and self._uid and self._password):
raise OpenERPUnboundException()
def execute(self, model, func, *l, **d):
self.assert_valid()
r = self.proxy('object').execute(self._db, self._uid, self._password, model, func, *l, **d)
return r
def exec_workflow(self, model, id, signal):
self.assert_valid()
r = self.proxy('object').exec_workflow(self._db, self._uid, self._password, model, signal, id)
return r
def model(self, model):
""" Get an RPC proxy for the object ``model``, bound to this session.
:param model: an OpenERP model name
:type model: str
:rtype: :class:`openerpweb.openerpweb.OpenERPModel`
"""
return self.model_factory(self, model)
def get_context(self):
""" Re-initializes the current user's session context (based on
his preferences) by calling res.users.get_context() with the old
context
:returns: the new context
"""
assert self._uid, "The user needs to be logged-in to initialize his context"
self.context = self.model('res.users').context_get(self.context)
self.context = self.context or {}
self.client_timezone = self.context.get("tz", False)
# invalid code, anyway we decided the server will be in UTC
#if self.client_timezone:
# self.remote_timezone = self.execute('common', 'timezone_get')
self._locale = self.context.get('lang','en_US')
lang_ids = self.execute('res.lang','search', [('code', '=', self._locale)])
if lang_ids:
self._lang = self.execute('res.lang', 'read',lang_ids[0], [])
return self.context
@property
def base_eval_context(self):
""" Default evaluation context for the session.
Used to evaluate contexts and domains.
"""
base = dict(
uid=self._uid,
current_date=datetime.date.today().strftime('%Y-%m-%d'),
time=time,
datetime=datetime,
relativedelta=dateutil.relativedelta.relativedelta
)
base.update(self.context)
return base
def evaluation_context(self, context=None):
""" Returns the session's evaluation context, augmented with the
provided context if any.
:param dict context: to add merge in the session's base eval context
:returns: the augmented context
:rtype: dict
"""
d = dict(self.base_eval_context)
if context:
d.update(context)
d['context'] = d
return d
def eval_context(self, context_to_eval, context=None):
""" Evaluates the provided context_to_eval in the context (haha) of
the context. Also merges the evaluated context with the session's context.
:param context_to_eval: a context to evaluate. Must be a dict or a
non-literal context. If it's a dict, will be
returned as-is
:type context_to_eval: openerpweb.nonliterals.Context
:returns: the evaluated context
:rtype: dict
:raises: ``TypeError`` if ``context_to_eval`` is neither a dict nor
a Context
"""
ctx = dict(
self.base_eval_context,
**(context or {}))
# adding the context of the session to send to the openerp server
ccontext = nonliterals.CompoundContext(self.context, context_to_eval or {})
ccontext.session = self
return ccontext.evaluate(ctx)
def eval_domain(self, domain, context=None):
""" Evaluates the provided domain using the provided context
(merged with the session's evaluation context)
:param domain: an OpenERP domain as a list or as a
:class:`openerpweb.nonliterals.Domain` instance
In the second case, it will be evaluated and returned.
:type domain: openerpweb.nonliterals.Domain
:param dict context: the context to use in the evaluation, if any.
:returns: the evaluated domain
:rtype: list
:raises: ``TypeError`` if ``domain`` is neither a list nor a Domain
"""
if isinstance(domain, list):
return domain
cdomain = nonliterals.CompoundDomain(domain)
cdomain.session = self
return cdomain.evaluate(context or {})
#----------------------------------------------------------
# OpenERP Web RequestHandler
#----------------------------------------------------------
@ -425,12 +237,16 @@ class Root(object):
controllers_path[o._cp_path] = o
def default(self, *l, **kw):
#print "default",l,kw
print "default",l,kw
# handle static files
if len(l) > 2 and l[1] == 'static':
# sanitize path
p = os.path.normpath(os.path.join(*l))
return cherrypy.lib.static.serve_file(os.path.join(path_addons, p))
p2 = os.path.join(path_addons, p)
print "p",p
print "p2",p2
return cherrypy.lib.static.serve_file(p2)
elif len(l) > 1:
for i in range(len(l), 1, -1):
ps = "/" + "/".join(l[0:i])

View File

@ -9,17 +9,22 @@ import re
import simplejson
import textwrap
import xmlrpclib
import time
from xml.etree import ElementTree
from cStringIO import StringIO
import cherrypy
import openerpweb
import openerpweb.ast
import openerpweb.nonliterals
import base.common as openerpweb
import base.common.ast
import base.common.nonliterals
openerpweb.ast = base.common.ast
openerpweb.nonliterals = base.common.nonliterals
from babel.messages.pofile import read_po
_REPORT_POLLER_DELAY = 0.05
# Should move to openerpweb.Xml2Json
class Xml2Json:
# xml2json-direct
@ -432,10 +437,13 @@ def load_actions_from_ir_values(req, key, key2, models, meta):
for id, name, action in actions]
def clean_action(req, action):
action.setdefault('flags', {})
if action['type'] != 'ir.actions.act_window':
return action
context = req.session.eval_context(req.context)
eval_ctx = req.session.evaluation_context(context)
action.setdefault('flags', {})
# values come from the server, we can just eval them
if isinstance(action.get('context'), basestring):
action['context'] = eval( action['context'], eval_ctx ) or {}
@ -1272,3 +1280,25 @@ class Export(View):
return export_xls(field, result)
else:
return export_csv(field, result)
class Export(View):
_cp_path = "/base/report"
@openerpweb.jsonrequest
def get_report(self, req, action):
report_srv = req.session.proxy("report")
context = req.session.eval_context(openerpweb.nonliterals.CompoundContext(req.context, \
action["context"]))
args = [req.session._db, req.session._uid, req.session._password, action["report_name"], context["active_ids"], {"id": context["active_id"], "model": context["active_model"], "report_type": action["report_type"]}, context]
report_id = report_srv.report(*args)
report = None
while True:
args2 = [req.session._db, req.session._uid, req.session._password, report_id]
report = report_srv.report_get(*args2)
if report["state"]:
break
time.sleep(_REPORT_POLLER_DELAY)
#TODO: ok now we've got the report, and so what?
return False

View File

@ -32,7 +32,7 @@
if(!menu) {
menu=$('<div id="jqContextMenu"></div>').hide().css({
position:'absolute',
zIndex:'500'
zIndex:'2000'
}).appendTo('body').bind('click', function(e) {
e.stopPropagation()
})

View File

@ -895,6 +895,9 @@ label.error {
position: relative;
top: 4px;
}
.openerp .oe_trad_field.touched {
border: 1px solid green !important;
}
/* http://www.quirksmode.org/dom/inputfile.html
* http://stackoverflow.com/questions/2855589/replace-input-type-file-by-an-image

View File

@ -479,8 +479,6 @@ openerp.base.Login = openerp.base.Widget.extend({
this.selected_login = localStorage.getItem('last_login_login_success');
}
if (jQuery.deparam(jQuery.param.querystring()).debug != undefined) {
this.selected_db = this.selected_db || "trunk";
this.selected_login = this.selected_login || "admin";
this.selected_password = this.selected_password || "a";
}
},
@ -564,22 +562,25 @@ openerp.base.Login = openerp.base.Widget.extend({
});
openerp.base.Header = openerp.base.Widget.extend({
init: function(parent, element_id) {
this._super(parent, element_id);
if (jQuery.deparam(jQuery.param.querystring()).debug !== undefined) {
this.qs = '?debug'
} else {
this.qs = ''
}
template: "Header",
identifier_prefix: 'oe-app-header-',
init: function(parent) {
this._super(parent);
this.qs = "?" + jQuery.param.querystring();
this.$content = $();
},
start: function() {
return this.do_update();
this._super();
},
do_update: function () {
this.$element.html(QWeb.render("Header", this));
this.$content = $(QWeb.render("Header-content", {widget: this}));
this.$content.appendTo(this.$element);
this.$element.find(".logout").click(this.on_logout);
return this.shortcut_load();
},
do_reset: function() {
this.$content.remove();
},
shortcut_load :function(){
var self = this,
sc = self.session.shortcuts,
@ -749,21 +750,23 @@ openerp.base.WebClient = openerp.base.Widget.extend({
// Do you autorize this ? will be replaced by notify() in controller
openerp.base.Widget.prototype.notification = new openerp.base.Notification(this, "oe_notification");
this.header = new openerp.base.Header(this, "oe_header");
this.header = new openerp.base.Header(this);
this.login = new openerp.base.Login(this, "oe_login");
this.header.on_logout.add(this.login.on_logout);
this.header.on_action.add(this.on_menu_action);
this.session.on_session_invalid.add(this.login.do_ask_login);
this.session.on_session_valid.add_last(this.header.do_update);
this.session.on_session_invalid.add_last(this.header.do_reset);
this.session.on_session_valid.add_last(this.on_logged);
this.menu = new openerp.base.Menu(this, "oe_menu", "oe_secondary_menu");
this.menu.on_action.add(this.on_menu_action);
this.header.on_action.add(this.on_menu_action);
},
start: function() {
this.header.appendTo($("#oe_header"));
this.session.start();
this.header.start();
this.login.start();
this.menu.start();
this.notification.notify("OpenERP Client", "The openerp client has been initialized.");

View File

@ -355,12 +355,13 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
* @param {Function} error_callback function called in case of write error
* @returns {$.Deferred}
*/
write: function (id, data, callback, error_callback) {
write: function (id, data, options, callback, error_callback) {
var options = options || {};
return this.rpc('/base/dataset/save', {
model: this.model,
id: id,
data: data,
context: this.get_context()
context: this.get_context(options.context)
}, callback, error_callback);
},
/**
@ -440,7 +441,7 @@ openerp.base.DataSet = openerp.base.Widget.extend( /** @lends openerp.base.Data
return this.call_and_eval('name_get', [ids, this.get_context()], null, 1, callback);
},
/**
*
*
* @param {String} name name to perform a search for/on
* @param {Array} [domain=[]] filters for the objects returned, OpenERP domain
* @param {String} [operator='ilike'] matching operator to use with the provided name value

View File

@ -157,6 +157,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
this.do_update_pager(record.id == null);
if (this.sidebar) {
this.sidebar.attachments.do_update();
this.sidebar.$element.find('.oe_sidebar_translate').toggleClass('oe_hide', !record.id);
}
if (this.default_focus_field && !this.embedded_view) {
this.default_focus_field.focus();
@ -342,7 +343,7 @@ openerp.base.FormView = openerp.base.View.extend( /** @lends openerp.base.FormVi
self.on_created(r, success, prepend_on_create);
});
} else {
return this.dataset.write(this.datarecord.id, values, function(r) {
return this.dataset.write(this.datarecord.id, values, {}, function(r) {
self.on_saved(r, success);
});
}
@ -879,6 +880,9 @@ openerp.base.form.Field = openerp.base.form.Widget.extend({
},
update_dom: function() {
this._super.apply(this, arguments);
if (this.field.translate) {
this.$element.find('.oe_field_translate').toggle(!!this.view.datarecord.id);
}
if (!this.disable_utility_classes) {
this.$element.toggleClass('disabled', this.readonly);
this.$element.toggleClass('required', this.required);
@ -1519,12 +1523,14 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
},
set_value: function(value) {
value = value || null;
this.invalid = false;
var self = this;
var _super = this._super;
this.tmp_value = value;
self.update_dom();
self.on_value_changed();
var real_set_value = function(rval) {
self.tmp_value = undefined;
_super.apply(self, rval);
self.value = rval;
self.original_value = undefined;
self._change_int_ext_value(rval);
};
@ -1550,7 +1556,8 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
},
validate: function() {
this.invalid = false;
if (this.value === null) {
var val = this.tmp_value !== undefined ? this.tmp_value : this.value;
if (val === null) {
this.invalid = this.required;
}
},
@ -1558,14 +1565,16 @@ openerp.base.form.FieldMany2One = openerp.base.form.Field.extend({
var self = this;
if (!self.value)
return;
self.rpc("/base/action/load", {
action_id: related[2].id,
context: {
var additional_context = {
active_id: self.value[0],
active_ids: [self.value[0]],
active_model: self.field.relation
}
};
self.rpc("/base/action/load", {
action_id: related[2].id,
context: additional_context
}, function(result) {
result.result.context = _.extend(result.result.context || {}, additional_context);
self.do_action(result.result);
});
}
@ -1863,10 +1872,13 @@ openerp.base.form.One2ManyListView = openerp.base.ListView.extend({
pop.show_element(self.o2m.field.relation, id, self.o2m.build_context(),{
auto_write: false,
alternative_form_view: self.o2m.field.views ? self.o2m.field.views["form"] : undefined,
parent_view: self.o2m.view
parent_view: self.o2m.view,
read_function: function() {
return self.o2m.dataset.read_ids.apply(self.o2m.dataset, arguments);
}
});
pop.on_write.add(function(id, data) {
self.o2m.dataset.write(id, data, function(r) {
self.o2m.dataset.write(id, data, {}, function(r) {
self.o2m.reload_current_view();
});
});
@ -2135,6 +2147,7 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
* options:
* - alternative_form_view
* - auto_write (default true)
* - read_function
* - parent_view
*/
show_element: function(model, row_id, context, options) {
@ -2150,7 +2163,8 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
},
start: function() {
this._super();
this.dataset = new openerp.base.ReadOnlyDataSetSearch(this, this.model, this.context);
this.dataset = new openerp.base.form.FormOpenDataset(this, this.model, this.context);
this.dataset.fop = this;
this.dataset.ids = [this.row_id];
this.dataset.index = 0;
this.dataset.parent_view = this.options.parent_view;
@ -2163,7 +2177,7 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
var self = this;
var wdataset = new openerp.base.DataSetSearch(this, this.model, this.context, this.domain);
wdataset.parent_view = this.options.parent_view;
wdataset.write(id, data, function(r) {
wdataset.write(id, data, {}, function(r) {
self.on_write_completed();
});
},
@ -2192,6 +2206,16 @@ openerp.base.form.FormOpenPopup = openerp.base.OldWidget.extend({
}
});
openerp.base.form.FormOpenDataset = openerp.base.ReadOnlyDataSetSearch.extend({
read_ids: function() {
if (this.fop.options.read_function) {
return this.fop.options.read_function.apply(null, arguments);
} else {
return this._super.apply(this, arguments);
}
}
});
openerp.base.form.FieldReference = openerp.base.form.Field.extend({
init: function(view, node) {
this._super(view, node);

View File

@ -28,8 +28,10 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
case 'float':
var precision = descriptor.digits ? descriptor.digits[1] : 2;
var int_part = Math.floor(value);
var dec_part = Math.floor((value % 1) * Math.pow(10, precision));
return _.sprintf('%d' + openerp.base._t.database.parameters.decimal_point + '%d', int_part, dec_part);
var dec_part = Math.abs(Math.floor((value % 1) * Math.pow(10, precision)));
return _.sprintf('%d%s%d',
int_part, dec_part,
openerp.base._t.database.parameters.decimal_point);
case 'float_time':
return _.sprintf("%02d:%02d",
Math.floor(value),
@ -45,7 +47,7 @@ openerp.base.format_value = function (value, descriptor, value_if_empty) {
if (typeof(value) == "string")
value = openerp.base.str_to_datetime(value);
try {
return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
return value.toString(_.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
Date.CultureInfo.formatPatterns.longTime));
} catch (e) {
return value.format("%m/%d/%Y %H:%M:%S");
@ -108,7 +110,7 @@ openerp.base.parse_value = function (value, descriptor, value_if_empty) {
case 'progressbar':
return openerp.base.parse_value(value, {type: "float"});
case 'datetime':
var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
var tmp = Date.parseExact(value, _.sprintf("%s %s", Date.CultureInfo.formatPatterns.shortDate,
Date.CultureInfo.formatPatterns.longTime));
if (tmp !== null)
return tmp;

View File

@ -123,6 +123,14 @@ openerp.base.ActionManager = openerp.base.Widget.extend({
this.content_stop();
var ClientWidget = openerp.base.client_actions.get_object(action.tag);
(this.client_widget = new ClientWidget(this, action.params)).appendTo(this);
},
ir_actions_report_xml: function(action) {
this.rpc('/base/report/get_report', {
action: action,
context: {}
}).then(function(result) {
debugger;
});
}
});
@ -438,14 +446,17 @@ openerp.base.Sidebar = openerp.base.Widget.extend({
//TODO niv: maybe show a warning?
return false;
}
var additional_context = {
active_id: ids[0],
active_ids: ids,
active_model: self.widget_parent.dataset.model
};
self.rpc("/base/action/load", {
action_id: item.action.id,
context: {
active_id: ids[0],
active_ids: ids,
active_model: self.widget_parent.dataset.model
}
context: additional_context
}, function(result) {
result.result.context = _.extend(result.result.context || {},
additional_context);
result.result.flags = result.result.flags || {};
result.result.flags.new_window = true;
self.do_action(result.result);
@ -472,6 +483,9 @@ openerp.base.Sidebar = openerp.base.Widget.extend({
openerp.base.TranslateDialog = openerp.base.Dialog.extend({
dialog_title: _t("Translations"),
init: function(view) {
// TODO fme: should add the language to fields_view_get because between the fields view get
// and the moment the user opens the translation dialog, the user language could have been changed
this.view_language = view.session.user_context.lang;
this['on_button' + _t("Save")] = this.on_button_Save;
this['on_button' + _t("Close")] = this.on_button_Close;
this._super(view, {
@ -500,6 +514,9 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({
self.select_tab('view');
}
self.$fields_form = self.$element.find('.oe_translation_form');
self.$fields_form.find('.oe_trad_field').change(function() {
$(this).toggleClass('touched', ($(this).val() != $(this).attr('data-value')));
});
});
return this;
},
@ -514,19 +531,27 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({
_.each(self.languages, function(lg) {
var deff = $.Deferred();
deffered.push(deff);
self.rpc('/base/dataset/get', {
model: self.view.dataset.model,
ids: [self.view.datarecord.id],
fields: self.translatable_fields_keys,
context: self.view.dataset.get_context({
'lang': lg.code
})
}, function(values) {
var callback = function(values) {
_.each(self.translatable_fields_keys, function(f) {
self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || '');
self.$fields_form.find('.oe_trad_field[name="' + lg.code + '-' + f + '"]').val(values[0][f] || '').attr('data-value', values[0][f] || '');
});
deff.resolve();
});
}
if (lg.code === self.view_language) {
var values = {};
_.each(self.translatable_fields_keys, function(field) {
values[field] = self.view.fields[field].get_value();
});
callback([values]);
} else {
self.rpc('/base/dataset/get', {
model: self.view.dataset.model,
ids: [self.view.datarecord.id],
fields: self.translatable_fields_keys,
context: self.view.dataset.get_context({
'lang': lg.code
})}, callback);
}
});
$.when.apply(null, deffered).then(callback);
},
@ -562,6 +587,24 @@ openerp.base.TranslateDialog = openerp.base.Dialog.extend({
});
},
on_button_Save: function() {
var trads = {},
self = this;
self.$fields_form.find('.oe_trad_field.touched').each(function() {
var field = $(this).attr('name').split('-');
if (!trads[field[0]]) {
trads[field[0]] = {};
}
trads[field[0]][field[1]] = $(this).val();
});
_.each(trads, function(data, code) {
if (code === self.view_language) {
_.each(data, function(value, field) {
self.view.fields[field].set_value(value);
});
} else {
self.view.dataset.write(self.view.datarecord.id, data, { 'lang': code });
}
});
this.close();
},
on_button_Close: function() {
@ -667,7 +710,7 @@ openerp.base.View = openerp.base.Widget.extend({
}, {
label: "Translate",
callback: this.on_sidebar_translate,
classname: 'oe_sidebar_translate'
classname: 'oe_sidebar_translate oe_hide'
}, {
label: "View Log",
callback: this.on_sidebar_view_log,

View File

@ -326,15 +326,19 @@
</div>
</t>
<t t-name="Header">
<a t-att-href="'/' + qs" class="company_logo_link">
<div class="company_logo" />
</a>
<h1 class="header_title" t-if="session.session_is_valid()">
<span class="database"><t t-esc="session.db"/></span> - <t t-esc="session.login"/> <br/>
<small class="username">rpc_session_id: <t t-esc="session.session_id"/></small>
<div>
<a t-att-href="'/' + widget.qs" class="company_logo_link">
<div class="company_logo" />
</a>
</div>
</t>
<t t-name="Header-content">
<h1 class="header_title">
<span class="database"><t t-esc="widget.session.db"/></span> - <t t-esc="widget.session.login"/> <br/>
<small class="username">rpc_session_id: <t t-esc="widget.session.session_id"/></small>
</h1>
<div class="header_corner">
<ul class="block" t-if="session.session_is_valid()">
<ul class="block">
<li>
<a href="#home" title="Home" class="home"><img src="/base/static/src/img/header-home.png" width="16" height="16" border="0"/></a>
</li>
@ -474,8 +478,8 @@
<label class="oe_form_label"><t t-esc="field.string"/>:</label>
</td>
<td t-foreach="widget.languages" t-as="lg" class="oe_form_frame_cell">
<input t-if="field.type == 'char'" type="text" t-attf-name="#{lg.code}-#{field.name}" value="" class="oe_trad_field" style="width: 100%"/>
<textarea t-if="field.type == 'text'" t-attf-name="#{lg.code}-#{field.name}" class="oe_trad_field" style="width: 100%"></textarea>
<input t-if="field.type == 'char'" type="text" t-attf-name="#{lg.code}-#{field.name}" value="" data-value="" class="oe_trad_field" style="width: 100%"/>
<textarea t-if="field.type == 'text'" t-attf-name="#{lg.code}-#{field.name}" data-value="" class="oe_trad_field" style="width: 100%"></textarea>
</td>
</tr>
</table>

View File

@ -1,5 +1,6 @@
import base.common as openerpweb
from base.controllers.main import View
import openerpweb
class CalendarView(View):
_cp_path = "/base_calendar/calendarview"

View File

@ -251,7 +251,7 @@ openerp.base_calendar.CalendarView = openerp.base.View.extend({
do_save_event: function(event_id, event_obj) {
var self = this,
data = this.get_event_data(event_obj);
this.dataset.write(parseInt(event_id, 10), data, function() {
this.dataset.write(parseInt(event_id, 10), data, {}, function() {
self.refresh_minical();
});
},

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
import openerpweb
import base.common as openerpweb
WIDGET_CONTENT_PATTERN = """<!DOCTYPE html>
<html>
@ -18,7 +18,7 @@ WIDGET_CONTENT_PATTERN = """<!DOCTYPE html>
</body>
</html>
"""
class Widgets(openerpweb.openerpweb.Controller):
class Widgets(openerpweb.Controller):
_cp_path = '/base_dashboard/widgets'
@openerpweb.httprequest

View File

@ -327,7 +327,7 @@ openerp.base_dashboard.ConfigOverview = openerp.base.View.extend({
e.stopImmediatePropagation();
var new_state = this.checked ? 'done' : 'open',
todo_id = parseInt($(this).val(), 10);
self.dataset.write(todo_id, {state: new_state}, function () {
self.dataset.write(todo_id, {state: new_state}, {}, function () {
self.start();
});
})

View File

@ -1,5 +1,5 @@
import base.common as openerpweb
from base.controllers.main import View
import openerpweb
class DiagramView(View):
_cp_path = "/base_diagram/diagram"

View File

@ -1,4 +1,4 @@
import openerpweb
import base.common as openerpweb
from base.controllers.main import View
class GanttView(View):

View File

@ -459,7 +459,7 @@ init: function(parent, element_id, dataset, view_id) {
}else{
data[this.date_delay] = task.getDuration();
}
this.dataset.write(event_id, data, function(result) {});
this.dataset.write(event_id, data, {}, function(result) {});
},

View File

@ -1,5 +1,5 @@
from base.controllers.main import View
import openerpweb
import base.common as openerpweb
class GraphView(View):
_cp_path = "/base_graph/graphview"
@ -8,4 +8,4 @@ class GraphView(View):
def load(self, req, model, view_id):
fields_view = self.fields_view_get(req, model, view_id, 'graph')
all_fields = req.session.model(model).fields_get()
return {'fields_view': fields_view, 'all_fields':all_fields}
return {'fields_view': fields_view, 'all_fields':all_fields}

View File

@ -4,7 +4,7 @@ import cherrypy
import simplejson
import random
import openerpweb
import base.common as openerpweb
#----------------------------------------------------------
# OpenERP Web ajaxim Controllers

View File

@ -1,12 +1,12 @@
# -*- coding: utf-8 -*-
import glob, os
import pprint
import simplejson
import openerpweb
import openerpweb.ast
import openerpweb.nonliterals
import cherrypy
#import glob, os
#import pprint
#
#import simplejson
#
#import openerpweb
#import openerpweb.ast
#import openerpweb.nonliterals
#
#import cherrypy
#

View File

@ -1,7 +1,20 @@
#!/usr/bin/env python
import sys
import os,sys
import openerpweb
path_root = os.path.dirname(os.path.abspath(__file__))
path_addons = os.path.join(path_root, 'addons')
if path_addons not in sys.path:
sys.path.insert(0, path_addons)
import base
def main():
# TODO move the code of base.common.main here !
# change the code to configure a simple werzug server -> base.common.Root()
base.common.main(sys.argv)
if __name__ == "__main__":
openerpweb.main(sys.argv)
main()

View File

@ -1,2 +0,0 @@
#!/usr/bin/python
from openerpweb import *