[[ line['blocked'] and 'X' or '' ]]
@@ -241,7 +236,7 @@
[[ formatLang((reduce(lambda x, y: x + ((y['account_id']['type'] == 'receivable' and y['credit'] or 0) or (y['account_id']['type'] == 'payable' and y['debit'] * -1 or 0)), getLines(o), 0))) ]]
-
+
+
-
+
-
+
-
+
diff --git a/addons/anonymization/i18n/lv.po b/addons/anonymization/i18n/lv.po
new file mode 100644
index 00000000000..34a9fe41f7b
--- /dev/null
+++ b/addons/anonymization/i18n/lv.po
@@ -0,0 +1,213 @@
+# Latvian translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-02-08 00:35+0000\n"
+"PO-Revision-Date: 2012-10-16 20:21+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Latvian \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-10-17 04:36+0000\n"
+"X-Generator: Launchpad (build 16152)\n"
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymize_wizard
+msgid "ir.model.fields.anonymize.wizard"
+msgstr "ir.model.fields.anonymize.wizard"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,field_name:0
+msgid "Field Name"
+msgstr "Lauka Nosaukums"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,field_id:0
+msgid "Field"
+msgstr "Lauks"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,state:0
+#: field:ir.model.fields.anonymize.wizard,state:0
+msgid "State"
+msgstr "Stāvoklis"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,file_import:0
+msgid "Import"
+msgstr "Importēt"
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization
+msgid "ir.model.fields.anonymization"
+msgstr "ir.model.fields.anonymization"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,direction:0
+msgid "Direction"
+msgstr "Virziens"
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_tree
+#: view:ir.model.fields.anonymization:0
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_fields
+msgid "Anonymized Fields"
+msgstr "Anonimizēti Lauki"
+
+#. module: anonymization
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization
+msgid "Database anonymization"
+msgstr "Datubāzes anonimizācija"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,direction:0
+msgid "clear -> anonymized"
+msgstr "tīrs -> anonimizēts"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Anonymized"
+msgstr "Anonimizēta"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,state:0
+msgid "unknown"
+msgstr "nezināms"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,model_id:0
+msgid "Object"
+msgstr "Objekts"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,filepath:0
+msgid "File path"
+msgstr "Ceļš uz failu"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization.history,date:0
+msgid "Date"
+msgstr "Datums"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,file_export:0
+msgid "Export"
+msgstr "Eksportēt"
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Reverse the Database Anonymization"
+msgstr "Atgriezt Datubāzes Anonimizāciju"
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Database Anonymization"
+msgstr "Datubāzes Anonimizācija"
+
+#. module: anonymization
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_wizard
+msgid "Anonymize database"
+msgstr "Anonimizēt datubāzi"
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization.history:0
+#: field:ir.model.fields.anonymization.history,field_ids:0
+msgid "Fields"
+msgstr "Lauki"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Clear"
+msgstr "Notīrīt"
+
+#. module: anonymization
+#: view:ir.model.fields.anonymize.wizard:0
+#: field:ir.model.fields.anonymize.wizard,summary:0
+msgid "Summary"
+msgstr "Kopsavilkums"
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization:0
+msgid "Anonymized Field"
+msgstr "Anonimizēts lauks"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Unstable"
+msgstr "Nestabīls"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Exception occured"
+msgstr "Notikusī kļūda"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization,state:0
+#: selection:ir.model.fields.anonymize.wizard,state:0
+msgid "Not Existing"
+msgstr "Neeksistē"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymization,model_name:0
+msgid "Object Name"
+msgstr "Objekta nosaukums"
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymization_history_tree
+#: view:ir.model.fields.anonymization.history:0
+#: model:ir.ui.menu,name:anonymization.menu_administration_anonymization_history
+msgid "Anonymization History"
+msgstr "Anonimizācijas Vēsture"
+
+#. module: anonymization
+#: model:ir.model,name:anonymization.model_ir_model_fields_anonymization_history
+msgid "ir.model.fields.anonymization.history"
+msgstr "ir.model.fields.anonymization.history"
+
+#. module: anonymization
+#: model:ir.actions.act_window,name:anonymization.action_ir_model_fields_anonymize_wizard
+#: view:ir.model.fields.anonymize.wizard:0
+msgid "Anonymize Database"
+msgstr "Anonimizēt Datubāzi"
+
+#. module: anonymization
+#: field:ir.model.fields.anonymize.wizard,name:0
+msgid "File Name"
+msgstr "Faila nosaukums"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,direction:0
+msgid "anonymized -> clear"
+msgstr "anonimizēts -> tīrs"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Started"
+msgstr "Iesākta"
+
+#. module: anonymization
+#: selection:ir.model.fields.anonymization.history,state:0
+msgid "Done"
+msgstr "Izdarīts"
+
+#. module: anonymization
+#: view:ir.model.fields.anonymization.history:0
+#: field:ir.model.fields.anonymization.history,msg:0
+#: field:ir.model.fields.anonymize.wizard,msg:0
+msgid "Message"
+msgstr "Ziņojums"
+
+#. module: anonymization
+#: code:addons/anonymization/anonymization.py:55
+#: sql_constraint:ir.model.fields.anonymization:0
+#, python-format
+msgid "You cannot have two fields with the same name on the same object!"
+msgstr "Nevar būt divi lauki ar vienādiem nosaukumiem vienam objektam!"
diff --git a/addons/audittrail/audittrail_view.xml b/addons/audittrail/audittrail_view.xml
index b041329f6bd..c26e1b5b570 100644
--- a/addons/audittrail/audittrail_view.xml
+++ b/addons/audittrail/audittrail_view.xml
@@ -145,7 +145,7 @@
audittrail.log.treeaudittrail.log
-
+
diff --git a/addons/auth_oauth/controllers/main.py b/addons/auth_oauth/controllers/main.py
index ae01df5f6f7..26016f3f0a1 100644
--- a/addons/auth_oauth/controllers/main.py
+++ b/addons/auth_oauth/controllers/main.py
@@ -4,28 +4,25 @@ import simplejson
import werkzeug.urls
import werkzeug.utils
-import openerp.modules.registry
-import openerp.addons.web.controllers.main
-import openerp.addons.web.common.http as openerpweb
-from openerp import SUPERUSER_ID
+import openerp
_logger = logging.getLogger(__name__)
-class OAuthController(openerpweb.Controller):
+class OAuthController(openerp.addons.web.http.Controller):
_cp_path = '/auth_oauth'
- @openerpweb.jsonrequest
+ @openerp.addons.web.http.jsonrequest
def list_providers(self, req, dbname):
try:
registry = openerp.modules.registry.RegistryManager.get(dbname)
with registry.cursor() as cr:
providers = registry.get('auth.oauth.provider')
- l = providers.read(cr, SUPERUSER_ID, providers.search(cr, SUPERUSER_ID, [('enabled','=',True)]))
+ l = providers.read(cr, openerp.SUPERUSER_ID, providers.search(cr, openerp.SUPERUSER_ID, [('enabled','=',True)]))
except Exception:
l = []
return l
- @openerpweb.httprequest
+ @openerp.addons.web.http.httprequest
def signin(self, req, **kw):
state = simplejson.loads(kw['state'])
dbname = state['d']
@@ -34,7 +31,7 @@ class OAuthController(openerpweb.Controller):
with registry.cursor() as cr:
try:
u = registry.get('res.users')
- credentials = u.auth_oauth(cr, SUPERUSER_ID, provider, kw)
+ credentials = u.auth_oauth(cr, openerp.SUPERUSER_ID, provider, kw)
cr.commit()
return openerp.addons.web.controllers.main.login_and_redirect(req, *credentials)
except AttributeError:
@@ -43,7 +40,7 @@ class OAuthController(openerpweb.Controller):
url = "/#action=login&oauth_error=1"
except Exception,e:
# signup error
- _logger.exception('oops')
+ _logger.exception("OAuth2: %s" % str(e))
url = "/#action=login&oauth_error=2"
return openerp.addons.web.controllers.main.set_cookie_and_redirect(req, url)
diff --git a/addons/auth_oauth/res_users.py b/addons/auth_oauth/res_users.py
index fd26e89c2e3..115e3136f00 100644
--- a/addons/auth_oauth/res_users.py
+++ b/addons/auth_oauth/res_users.py
@@ -15,13 +15,17 @@ class res_users(osv.Model):
_inherit = 'res.users'
_columns = {
- 'oauth_provider_id': fields.many2one('auth.oauth.provider','OAuth Provider'),
+ 'oauth_provider_id': fields.many2one('auth.oauth.provider', 'OAuth Provider'),
'oauth_uid': fields.char('OAuth User ID', help="Oauth Provider user_id"),
- 'oauth_access_token': fields.char('OAuth Token', readonly=True),
+ 'oauth_access_token': fields.char('OAuth Access Token', readonly=True),
}
+ _sql_constraints = [
+ ('uniq_users_oauth_provider_oauth_uid', 'unique(oauth_provider_id, oauth_uid)', 'OAuth UID must be unique per provider'),
+ ]
+
def auth_oauth_rpc(self, cr, uid, endpoint, access_token, context=None):
- params = urllib.urlencode({ 'access_token': access_token })
+ params = urllib.urlencode({'access_token': access_token})
if urlparse.urlparse(endpoint)[4]:
url = endpoint + '&' + params
else:
@@ -41,22 +45,26 @@ class res_users(osv.Model):
validation = self.auth_oauth_rpc(cr, uid, p.validation_endpoint, access_token)
if validation.get("error"):
- raise openerp.exceptions.AccessDenied
+ raise Exception(validation['error'])
if p.data_endpoint:
data = self.auth_oauth_rpc(cr, uid, p.data_endpoint, access_token)
validation.update(data)
# required
oauth_uid = validation['user_id']
if not oauth_uid:
- raise openerp.exceptions.AccessDenied
+ raise openerp.exceptions.AccessDenied()
email = validation.get('email', 'provider_%d_user_%d' % (p.id, oauth_uid))
# optional
name = validation.get('name', email)
- res = self.search(cr, uid, [("oauth_uid", "=", oauth_uid)])
+ res = self.search(cr, uid, [("oauth_uid", "=", oauth_uid), ('oauth_provider_id', '=', provider)])
if res:
- self.write(cr, uid, res[0], { 'oauth_access_token': access_token })
+ assert len(res) == 1
+ self.write(cr, uid, res[0], {'oauth_access_token': access_token})
else:
- # New user
+ # New user if signup module available
+ if not hasattr(self, '_signup_create_user'):
+ raise openerp.exceptions.AccessDenied()
+
new_user = {
'name': name,
'login': email,
@@ -66,7 +74,9 @@ class res_users(osv.Model):
'oauth_access_token': access_token,
'active': True,
}
- self.auth_signup_create(cr, uid, new_user)
+ # TODO pass signup token to allow attach new user to right partner
+ self._signup_create_user(cr, uid, new_user)
+
credentials = (cr.dbname, email, access_token)
return credentials
@@ -74,7 +84,7 @@ class res_users(osv.Model):
try:
return super(res_users, self).check_credentials(cr, uid, password)
except openerp.exceptions.AccessDenied:
- res = self.search(cr, SUPERUSER_ID, [('id','=',uid),('oauth_access_token','=',password)])
+ res = self.search(cr, SUPERUSER_ID, [('id', '=', uid), ('oauth_access_token', '=', password)])
if not res:
raise
diff --git a/addons/auth_openid/controllers/main.py b/addons/auth_openid/controllers/main.py
index ebcaab4bf25..7ee562d4d29 100644
--- a/addons/auth_openid/controllers/main.py
+++ b/addons/auth_openid/controllers/main.py
@@ -23,24 +23,21 @@ import logging
import os
import tempfile
import urllib
-from openerp import SUPERUSER_ID
import werkzeug.urls
import werkzeug.exceptions
-from openerp.modules.registry import RegistryManager
-from openerp.addons.web.controllers.main import login_and_redirect, set_cookie_and_redirect
-try:
- import openerp.addons.web.common.http as openerpweb
-except ImportError:
- import web.common.http as openerpweb # noqa
-
from openid import oidutil
from openid.store import filestore
from openid.consumer import consumer
from openid.cryptutil import randomString
from openid.extensions import ax, sreg
+import openerp
+from openerp import SUPERUSER_ID
+from openerp.modules.registry import RegistryManager
+from openerp.addons.web.controllers.main import login_and_redirect, set_cookie_and_redirect
+
from .. import utils
_logger = logging.getLogger(__name__)
@@ -70,7 +67,7 @@ class GoogleAppsAwareConsumer(consumer.GenericConsumer):
return super(GoogleAppsAwareConsumer, self).complete(message, endpoint, return_to)
-class OpenIDController(openerpweb.Controller):
+class OpenIDController(openerp.addons.web.http.Controller):
_cp_path = '/auth_openid/login'
_store = filestore.FileOpenIDStore(_storedir)
@@ -118,7 +115,7 @@ class OpenIDController(openerpweb.Controller):
def _get_realm(self, req):
return req.httprequest.host_url
- @openerpweb.httprequest
+ @openerp.addons.web.http.httprequest
def verify_direct(self, req, db, url):
result = self._verify(req, db, url)
if 'error' in result:
@@ -127,7 +124,7 @@ class OpenIDController(openerpweb.Controller):
return werkzeug.utils.redirect(result['value'])
return result['value']
- @openerpweb.jsonrequest
+ @openerp.addons.web.http.jsonrequest
def verify(self, req, db, url):
return self._verify(req, db, url)
@@ -157,7 +154,7 @@ class OpenIDController(openerpweb.Controller):
form_html = request.htmlMarkup(realm, redirect_to)
return {'action': 'post', 'value': form_html, 'session_id': req.session_id}
- @openerpweb.httprequest
+ @openerp.addons.web.http.httprequest
def process(self, req, **kw):
session = getattr(req.session, 'openid_session', None)
if not session:
@@ -225,7 +222,7 @@ class OpenIDController(openerpweb.Controller):
return set_cookie_and_redirect(req, '/#action=login&loginerror=1')
- @openerpweb.jsonrequest
+ @openerp.addons.web.http.jsonrequest
def status(self, req):
session = getattr(req.session, 'openid_session', {})
return {'status': session.get('status'), 'message': session.get('message')}
diff --git a/addons/auth_openid/static/src/js/auth_openid.js b/addons/auth_openid/static/src/js/auth_openid.js
index 70739e056ed..56ec5b57d3f 100644
--- a/addons/auth_openid/static/src/js/auth_openid.js
+++ b/addons/auth_openid/static/src/js/auth_openid.js
@@ -69,7 +69,7 @@ instance.web.Login = instance.web.Login.extend({
_check_error: function() {
var self = this;
if (this.params.loginerror !== undefined) {
- this.rpc('/auth_openid/login/status', {}, function(result) {
+ this.rpc('/auth_openid/login/status', {}).then(function(result) {
if (_.contains(['success', 'failure'], result.status) && result.message) {
self.do_warn('Invalid OpenID Login', result.message);
}
@@ -106,7 +106,7 @@ instance.web.Login = instance.web.Login.extend({
do_openid_login: function(db, openid_url) {
var self = this;
- this.rpc('/auth_openid/login/verify', {'db': db, 'url': openid_url}, function(result) {
+ this.rpc('/auth_openid/login/verify', {'db': db, 'url': openid_url}).then(function(result) {
if (result.error) {
self.do_warn(result.title, result.error);
return;
diff --git a/addons/auth_reset_password/controllers/main.py b/addons/auth_reset_password/controllers/main.py
index 5185a65c3ce..639945cfc09 100644
--- a/addons/auth_reset_password/controllers/main.py
+++ b/addons/auth_reset_password/controllers/main.py
@@ -18,20 +18,20 @@
# along with this program. If not, see
#
##############################################################################
-
-from openerp import SUPERUSER_ID
-from openerp.modules.registry import RegistryManager
-import openerp.addons.web.common.http as openerpweb
+import logging
import werkzeug
-import logging
+import openerp
+from openerp import SUPERUSER_ID
+from openerp.modules.registry import RegistryManager
+
_logger = logging.getLogger(__name__)
-class Controller(openerpweb.Controller):
+class Controller(openerp.addons.web.http.Controller):
_cp_path = '/auth_reset_password'
- @openerpweb.httprequest
+ @openerp.addons.web.http.httprequest
def reset_password(self, req, dbname, login):
""" retrieve user, and perform reset password """
url = '/'
diff --git a/addons/auth_signup/controllers/main.py b/addons/auth_signup/controllers/main.py
index 56e5e910212..54dcc5b4362 100644
--- a/addons/auth_signup/controllers/main.py
+++ b/addons/auth_signup/controllers/main.py
@@ -18,32 +18,31 @@
# along with this program. If not, see
#
##############################################################################
-
-from openerp import SUPERUSER_ID
-from openerp.modules.registry import RegistryManager
-from openerp.addons.web.controllers.main import login_and_redirect
-import openerp.addons.web.common.http as openerpweb
+import logging
import werkzeug
-import logging
+import openerp
+from openerp.modules.registry import RegistryManager
+from openerp.addons.web.controllers.main import login_and_redirect
+
_logger = logging.getLogger(__name__)
-class Controller(openerpweb.Controller):
+class Controller(openerp.addons.web.http.Controller):
_cp_path = '/auth_signup'
- @openerpweb.jsonrequest
+ @openerp.addons.web.http.jsonrequest
def retrieve(self, req, dbname, token):
""" retrieve the user info (name, login or email) corresponding to a signup token """
registry = RegistryManager.get(dbname)
user_info = None
with registry.cursor() as cr:
res_partner = registry.get('res.partner')
- user_info = res_partner.signup_retrieve_info(cr, SUPERUSER_ID, token)
+ user_info = res_partner.signup_retrieve_info(cr, openerp.SUPERUSER_ID, token)
return user_info
- @openerpweb.httprequest
- def signup(self, req, dbname, token, name, login, password):
+ @openerp.addons.web.http.httprequest
+ def signup(self, req, dbname, token, name, login, password, state=''):
""" sign up a user (new or existing), and log it in """
url = '/'
registry = RegistryManager.get(dbname)
@@ -51,9 +50,9 @@ class Controller(openerpweb.Controller):
try:
res_users = registry.get('res.users')
values = {'name': name, 'login': login, 'password': password}
- credentials = res_users.signup(cr, SUPERUSER_ID, values, token)
+ credentials = res_users.signup(cr, openerp.SUPERUSER_ID, values, token)
cr.commit()
- return login_and_redirect(req, *credentials)
+ return login_and_redirect(req, *credentials, redirect_url='/#%s'%state)
except Exception as e:
# signup error
_logger.exception('error when signup')
diff --git a/addons/auth_signup/res_users.py b/addons/auth_signup/res_users.py
index 7b663bd0e33..59196c4da87 100644
--- a/addons/auth_signup/res_users.py
+++ b/addons/auth_signup/res_users.py
@@ -18,6 +18,10 @@
# along with this program. If not, see
#
##############################################################################
+import random
+import time
+import urllib
+import urlparse
import openerp
from openerp.osv import osv, fields
@@ -25,11 +29,6 @@ from openerp import SUPERUSER_ID
from openerp.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT
from openerp.tools.safe_eval import safe_eval
-import time
-import random
-import urllib
-import urlparse
-
def random_token():
# the token has an entropy of about 120 bits (6 bits/char * 20 chars)
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
@@ -38,7 +37,6 @@ def random_token():
def now():
return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
-
class res_partner(osv.Model):
_inherit = 'res.partner'
@@ -132,8 +130,6 @@ class res_partner(osv.Model):
res['email'] = partner.email or ''
return res
-
-
class res_users(osv.Model):
_inherit = 'res.users'
diff --git a/addons/auth_signup/static/src/js/auth_signup.js b/addons/auth_signup/static/src/js/auth_signup.js
index 509fafa35cc..0974b73292d 100644
--- a/addons/auth_signup/static/src/js/auth_signup.js
+++ b/addons/auth_signup/static/src/js/auth_signup.js
@@ -90,6 +90,7 @@ openerp.auth_signup = function(instance) {
name: name,
login: login,
password: password,
+ state: $.param(this.params)
};
var url = "/auth_signup/signup?" + $.param(params);
window.location = url;
diff --git a/addons/base_crypt/i18n/lv.po b/addons/base_crypt/i18n/lv.po
new file mode 100644
index 00000000000..71e5a3f0e6d
--- /dev/null
+++ b/addons/base_crypt/i18n/lv.po
@@ -0,0 +1,45 @@
+# Latvian translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-02-08 00:36+0000\n"
+"PO-Revision-Date: 2012-10-16 16:11+0000\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: Latvian \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-10-17 04:36+0000\n"
+"X-Generator: Launchpad (build 16152)\n"
+
+#. module: base_crypt
+#: model:ir.model,name:base_crypt.model_res_users
+msgid "res.users"
+msgstr "res.users"
+
+#. module: base_crypt
+#: sql_constraint:res.users:0
+msgid "You can not have two users with the same login !"
+msgstr "Nevar būt divi lietotāji ar vienādu pieteikuma vārdu!"
+
+#. module: base_crypt
+#: constraint:res.users:0
+msgid "The chosen company is not in the allowed companies for this user"
+msgstr "Izvēlētais uzņēmums nav šim lietotājam atļauto uzņēmumu sarakstā"
+
+#. module: base_crypt
+#: code:addons/base_crypt/crypt.py:140
+#, python-format
+msgid "Please specify the password !"
+msgstr "Lūdzu norādiet paroli!"
+
+#. module: base_crypt
+#: code:addons/base_crypt/crypt.py:140
+#, python-format
+msgid "Error"
+msgstr "Kļūda"
diff --git a/addons/base_import/__openerp__.py b/addons/base_import/__openerp__.py
index eff20bc90ab..f5a707650d8 100644
--- a/addons/base_import/__openerp__.py
+++ b/addons/base_import/__openerp__.py
@@ -26,13 +26,14 @@ Re-implement openerp's file import system:
'author': 'OpenERP SA',
'depends': ['base'],
'installable': True,
- 'auto_install': False, # set to true and allow uninstall?
+ 'auto_install': True,
'css': [
'static/lib/select2/select2.css',
'static/src/css/import.css',
],
'js': [
'static/lib/select2/select2.js',
+ 'static/lib/javascript-state-machine/state-machine.js',
'static/src/js/import.js',
],
'qweb': ['static/src/xml/import.xml'],
diff --git a/addons/base_import/controllers.py b/addons/base_import/controllers.py
index 85ff993e92e..c831ffd229d 100644
--- a/addons/base_import/controllers.py
+++ b/addons/base_import/controllers.py
@@ -1,15 +1,12 @@
# -*- coding: utf-8 -*-
import simplejson
-try:
- import openerp.addons.web.common.http as openerpweb
-except ImportError:
- import web.common.http as openerpweb
+import openerp
-class ImportController(openerpweb.Controller):
+class ImportController(openerp.addons.web.http.Controller):
_cp_path = '/base_import'
- @openerpweb.httprequest
+ @openerp.addons.web.http.httprequest
def set_file(self, req, file, import_id, jsonp='callback'):
import_id = int(import_id)
diff --git a/addons/base_import/models.py b/addons/base_import/models.py
index 1e5ad002b84..996dbf7964d 100644
--- a/addons/base_import/models.py
+++ b/addons/base_import/models.py
@@ -83,6 +83,10 @@ class ir_import(orm.TransientModel):
}]
fields_got = self.pool[model].fields_get(cr, uid, context=context)
for name, field in fields_got.iteritems():
+ # an empty string means the field is deprecated, @deprecated must
+ # be absent or False to mean not-deprecated
+ if field.get('deprecated', False) is not False:
+ continue
if field.get('readonly'):
states = field.get('states')
if not states:
@@ -97,7 +101,7 @@ class ir_import(orm.TransientModel):
'id': name,
'name': name,
'string': field['string'],
- # Y U NO ALWAYS HAVE REQUIRED
+ # Y U NO ALWAYS HAS REQUIRED
'required': bool(field.get('required')),
'fields': [],
}
@@ -124,8 +128,8 @@ class ir_import(orm.TransientModel):
"""
csv_iterator = csv.reader(
StringIO(record.file),
- quotechar=options['quoting'],
- delimiter=options['separator'])
+ quotechar=str(options['quoting']),
+ delimiter=str(options['separator']))
csv_nonempty = itertools.ifilter(None, csv_iterator)
# TODO: guess encoding with chardet? Or https://github.com/aadsm/jschardet
encoding = options.get('encoding', 'utf-8')
@@ -307,22 +311,14 @@ class ir_import(orm.TransientModel):
except ValueError, e:
return [{
'type': 'error',
- 'message': str(e),
+ 'message': unicode(e),
'record': False,
}]
- try:
- _logger.info('importing %d rows...', len(data))
- (code, record, message, _wat) = self.pool[record.res_model].import_data(
- cr, uid, import_fields, data, context=context)
- _logger.info('done')
-
- except Exception, e:
- _logger.exception("Import failed")
- # TODO: remove when exceptions stop being an "expected"
- # behavior of import_data on some (most) invalid
- # input.
- code, record, message = -1, None, str(e)
+ _logger.info('importing %d rows...', len(data))
+ import_result = self.pool[record.res_model].load(
+ cr, uid, import_fields, data, context=context)
+ _logger.info('done')
# If transaction aborted, RELEASE SAVEPOINT is going to raise
# an InternalError (ROLLBACK should work, maybe). Ignore that.
@@ -339,14 +335,4 @@ class ir_import(orm.TransientModel):
except psycopg2.InternalError:
pass
- if code != -1:
- return []
-
- # TODO: add key for error location?
- # TODO: error not within normal preview, how to display? Re-preview
- # with higher ``count``?
- return [{
- 'type': 'error',
- 'message': message,
- 'record': record or False
- }]
+ return import_result['messages']
diff --git a/addons/base_import/static/lib/javascript-state-machine/LICENSE b/addons/base_import/static/lib/javascript-state-machine/LICENSE
new file mode 100644
index 00000000000..8ad703ca4ef
--- /dev/null
+++ b/addons/base_import/static/lib/javascript-state-machine/LICENSE
@@ -0,0 +1,20 @@
+Copyright (c) 2012 Jake Gordon and contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/addons/base_import/static/lib/javascript-state-machine/README.md b/addons/base_import/static/lib/javascript-state-machine/README.md
new file mode 100644
index 00000000000..64c045e69d7
--- /dev/null
+++ b/addons/base_import/static/lib/javascript-state-machine/README.md
@@ -0,0 +1,327 @@
+Javascript Finite State Machine (v2.1.0)
+========================================
+
+This standalone javascript micro-framework provides a finite state machine for your pleasure.
+
+ * You can find the [code here](https://github.com/jakesgordon/javascript-state-machine)
+ * You can find a [description here](http://codeincomplete.com/posts/2011/8/19/javascript_state_machine_v2/)
+ * You can find a [working demo here](http://codeincomplete.com/posts/2011/8/19/javascript_state_machine_v2/example/)
+
+Download
+========
+
+You can download [state-machine.js](https://github.com/jakesgordon/javascript-state-machine/raw/master/state-machine.js),
+or the [minified version](https://github.com/jakesgordon/javascript-state-machine/raw/master/state-machine.min.js)
+
+Alternatively:
+
+ git clone git@github.com:jakesgordon/javascript-state-machine
+
+
+ * All code is in state-machine.js
+ * Minified version provided in state-machine.min.js
+ * No 3rd party library is required
+ * Demo can be found in /index.html
+ * QUnit tests can be found in /test/index.html
+
+Usage
+=====
+
+Include `state-machine.min.js` in your application.
+
+In its simplest form, create a standalone state machine using:
+
+ var fsm = StateMachine.create({
+ initial: 'green',
+ events: [
+ { name: 'warn', from: 'green', to: 'yellow' },
+ { name: 'panic', from: 'yellow', to: 'red' },
+ { name: 'calm', from: 'red', to: 'yellow' },
+ { name: 'clear', from: 'yellow', to: 'green' }
+ ]});
+
+... will create an object with a method for each event:
+
+ * fsm.warn() - transition from 'green' to 'yellow'
+ * fsm.panic() - transition from 'yellow' to 'red'
+ * fsm.calm() - transition from 'red' to 'yellow'
+ * fsm.clear() - transition from 'yellow' to 'green'
+
+along with the following members:
+
+ * fsm.current - contains the current state
+ * fsm.is(s) - return true if state `s` is the current state
+ * fsm.can(e) - return true if event `e` can be fired in the current state
+ * fsm.cannot(e) - return true if event `e` cannot be fired in the current state
+
+Multiple 'from' and 'to' states for a single event
+==================================================
+
+If an event is allowed **from** multiple states, and always transitions to the same
+state, then simply provide an array of states in the `from` attribute of an event. However,
+if an event is allowed from multiple states, but should transition **to** a different
+state depending on the current state, then provide multiple event entries with
+the same name:
+
+ var fsm = StateMachine.create({
+ initial: 'hungry',
+ events: [
+ { name: 'eat', from: 'hungry', to: 'satisfied' },
+ { name: 'eat', from: 'satisfied', to: 'full' },
+ { name: 'eat', from: 'full', to: 'sick' },
+ { name: 'rest', from: ['hungry', 'satisfied', 'full', 'sick'], to: 'hungry' },
+ ]});
+
+This example will create an object with 2 event methods:
+
+ * fsm.eat()
+ * fsm.rest()
+
+The `rest` event will always transition to the `hungry` state, while the `eat` event
+will transition to a state that is dependent on the current state.
+
+>> NOTE: The `rest` event could use a wildcard '*' for the 'from' state if it should be
+allowed from any current state.
+
+>> NOTE: The `rest` event in the above example can also be specified as multiple events with
+the same name if you prefer the verbose approach.
+
+Callbacks
+=========
+
+4 callbacks are available if your state machine has methods using the following naming conventions:
+
+ * onbefore**event** - fired before the event
+ * onleave**state** - fired when leaving the old state
+ * onenter**state** - fired when entering the new state
+ * onafter**event** - fired after the event
+
+You can affect the event in 3 ways:
+
+ * return `false` from an `onbeforeevent` handler to cancel the event.
+ * return `false` from an `onleavestate` handler to cancel the event.
+ * return `ASYNC` from an `onleavestate` handler to perform an asynchronous state transition (see next section)
+
+For convenience, the 2 most useful callbacks can be shortened:
+
+ * on**event** - convenience shorthand for onafter**event**
+ * on**state** - convenience shorthand for onenter**state**
+
+In addition, a generic `onchangestate()` callback can be used to call a single function for _all_ state changes:
+
+All callbacks will be passed the same arguments:
+
+ * **event** name
+ * **from** state
+ * **to** state
+ * _(followed by any arguments you passed into the original event method)_
+
+Callbacks can be specified when the state machine is first created:
+
+ var fsm = StateMachine.create({
+ initial: 'green',
+ events: [
+ { name: 'warn', from: 'green', to: 'yellow' },
+ { name: 'panic', from: 'yellow', to: 'red' },
+ { name: 'calm', from: 'red', to: 'yellow' },
+ { name: 'clear', from: 'yellow', to: 'green' }
+ ],
+ callbacks: {
+ onpanic: function(event, from, to, msg) { alert('panic! ' + msg); },
+ onclear: function(event, from, to, msg) { alert('thanks to ' + msg); },
+ ongreen: function(event, from, to) { document.body.className = 'green'; },
+ onyellow: function(event, from, to) { document.body.className = 'yellow'; },
+ onred: function(event, from, to) { document.body.className = 'red'; },
+ }
+ });
+
+ fsm.panic('killer bees');
+ fsm.clear('sedatives in the honey pots');
+ ...
+
+Additionally, they can be added and removed from the state machine at any time:
+
+ fsm.ongreen = null;
+ fsm.onyellow = null;
+ fsm.onred = null;
+ fsm.onchangestate = function(event, from, to) { document.body.className = to; };
+
+Asynchronous State Transitions
+==============================
+
+Sometimes, you need to execute some asynchronous code during a state transition and ensure the
+new state is not entered until your code has completed.
+
+A good example of this is when you transition out of a `menu` state, perhaps you want to gradually
+fade the menu away, or slide it off the screen and don't want to transition to your `game` state
+until after that animation has been performed.
+
+You can now return `StateMachine.ASYNC` from your `onleavestate` handler and the state machine
+will be _'put on hold'_ until you are ready to trigger the transition using the new `transition()`
+method.
+
+For example, using jQuery effects:
+
+ var fsm = StateMachine.create({
+
+ initial: 'menu',
+
+ events: [
+ { name: 'play', from: 'menu', to: 'game' },
+ { name: 'quit', from: 'game', to: 'menu' }
+ ],
+
+ callbacks: {
+
+ onentermenu: function() { $('#menu').show(); },
+ onentergame: function() { $('#game').show(); },
+
+ onleavemenu: function() {
+ $('#menu').fadeOut('fast', function() {
+ fsm.transition();
+ });
+ return StateMachine.ASYNC; // tell StateMachine to defer next state until we call transition (in fadeOut callback above)
+ },
+
+ onleavegame: function() {
+ $('#game').slideDown('slow', function() {
+ fsm.transition();
+ };
+ return StateMachine.ASYNC; // tell StateMachine to defer next state until we call transition (in slideDown callback above)
+ }
+
+ }
+ });
+
+
+State Machine Classes
+=====================
+
+You can also turn all instances of a _class_ into an FSM by applying
+the state machine functionality to the prototype, including your callbacks
+in your prototype, and providing a `startup` event for use when constructing
+instances:
+
+ MyFSM = function() { // my constructor function
+ this.startup();
+ };
+
+ MyFSM.prototype = {
+
+ onpanic: function(event, from, to) { alert('panic'); },
+ onclear: function(event, from, to) { alert('all is clear'); },
+
+ // my other prototype methods
+
+ };
+
+ StateMachine.create({
+ target: MyFSM.prototype,
+ events: [
+ { name: 'startup', from: 'none', to: 'green' },
+ { name: 'warn', from: 'green', to: 'yellow' },
+ { name: 'panic', from: 'yellow', to: 'red' },
+ { name: 'calm', from: 'red', to: 'yellow' },
+ { name: 'clear', from: 'yellow', to: 'green' }
+ ]});
+
+
+This should be easy to adjust to fit your appropriate mechanism for object construction.
+
+Initialization Options
+======================
+
+How the state machine should initialize can depend on your application requirements, so
+the library provides a number of simple options.
+
+By default, if you dont specify any initial state, the state machine will be in the `'none'`
+state and you would need to provide an event to take it out of this state:
+
+ var fsm = StateMachine.create({
+ events: [
+ { name: 'startup', from: 'none', to: 'green' },
+ { name: 'panic', from: 'green', to: 'red' },
+ { name: 'calm', from: 'red', to: 'green' },
+ ]});
+ alert(fsm.current); // "none"
+ fsm.startup();
+ alert(fsm.current); // "green"
+
+If you specify the name of your initial event (as in all the earlier examples), then an
+implicit `startup` event will be created for you and fired when the state machine is constructed.
+
+ var fsm = StateMachine.create({
+ initial: 'green',
+ events: [
+ { name: 'panic', from: 'green', to: 'red' },
+ { name: 'calm', from: 'red', to: 'green' },
+ ]});
+ alert(fsm.current); // "green"
+
+If your object already has a `startup` method you can use a different name for the initial event
+
+ var fsm = StateMachine.create({
+ initial: { state: 'green', event: 'init' },
+ events: [
+ { name: 'panic', from: 'green', to: 'red' },
+ { name: 'calm', from: 'red', to: 'green' },
+ ]});
+ alert(fsm.current); // "green"
+
+Finally, if you want to wait to call the initial state transition event until a later date you
+can `defer` it:
+
+ var fsm = StateMachine.create({
+ initial: { state: 'green', event: 'init', defer: true },
+ events: [
+ { name: 'panic', from: 'green', to: 'red' },
+ { name: 'calm', from: 'red', to: 'green' },
+ ]});
+ alert(fsm.current); // "none"
+ fsm.init();
+ alert(fsm.current); // "green"
+
+Of course, we have now come full circle, this last example is pretty much functionally the
+same as the first example in this section where you simply define your own startup event.
+
+So you have a number of choices available to you when initializing your state machine.
+
+Handling Failures
+======================
+
+By default, if you try to call an event method that is not allowed in the current state, the
+state machine will throw an exception. If you prefer to handle the problem yourself, you can
+define a custom `error` handler:
+
+ var fsm = StateMachine.create({
+ initial: 'green',
+ error: function(eventName, from, to, args, errorCode, errorMessage) {
+ return 'event ' + eventName + ' was naughty :- ' + errorMessage;
+ },
+ events: [
+ { name: 'panic', from: 'green', to: 'red' },
+ { name: 'calm', from: 'red', to: 'green' },
+ ]});
+ alert(fsm.calm()); // "event calm was naughty :- event not allowed in current state green"
+
+Release Notes
+=============
+
+See [RELEASE NOTES](https://github.com/jakesgordon/javascript-state-machine/blob/master/RELEASE_NOTES.md) file.
+
+License
+=======
+
+See [LICENSE](https://github.com/jakesgordon/javascript-state-machine/blob/master/LICENSE) file.
+
+Contact
+=======
+
+If you have any ideas, feedback, requests or bug reports, you can reach me at
+[jake@codeincomplete.com](mailto:jake@codeincomplete.com), or via
+my website: [Code inComplete](http://codeincomplete.com/posts/2011/8/19/javascript_state_machine_v2/)
+
+
+
+
+
diff --git a/addons/base_import/static/lib/javascript-state-machine/RELEASE_NOTES.md b/addons/base_import/static/lib/javascript-state-machine/RELEASE_NOTES.md
new file mode 100644
index 00000000000..06abf402d38
--- /dev/null
+++ b/addons/base_import/static/lib/javascript-state-machine/RELEASE_NOTES.md
@@ -0,0 +1,32 @@
+Version 2.1.0 (January 7th 2012)
+--------------------------------
+
+ * Wrapped in self executing function to be more easily used with loaders like `require.js` or `curl.js` (issue #15)
+ * Allow event to be cancelled by returning `false` from `onleavestate` handler (issue #13) - WARNING: this breaks backward compatibility for async transitions (you now need to return `StateMachine.ASYNC` instead of `false`)
+ * Added explicit return values for event methods (issue #12)
+ * Added support for wildcard events that can be fired 'from' any state (issue #11)
+ * Added support for no-op events that transition 'to' the same state (issue #5)
+ * extended custom error callback to handle any exceptions caused by caller provided callbacks
+ * added custom error callback to override exception when an illegal state transition is attempted (thanks to cboone)
+ * fixed typos (thanks to cboone)
+ * fixed issue #4 - ensure before/after event hooks are called even if the event doesn't result in a state change
+
+Version 2.0.0 (August 19th 2011)
+--------------------------------
+
+ * adding support for asynchronous state transitions (see README) - with lots of qunit tests (see test/async.js).
+ * consistent arguments for ALL callbacks, first 3 args are ALWAYS event name, from state and to state, followed by whatever arguments the user passed to the original event method.
+ * added a generic `onchangestate(event,from,to)` callback to detect all state changes with a single function.
+ * allow callbacks to be declared at creation time (instead of having to attach them afterwards)
+ * renamed 'hooks' => 'callbacks'
+ * [read more...](http://codeincomplete.com/posts/2011/8/19/javascript_state_machine_v2/)
+
+Version 1.2.0 (June 21st 2011)
+------------------------------
+ * allows the same event to transition to different states, depending on the current state (see 'Multiple...' section in README.md)
+ * [read more...](http://codeincomplete.com/posts/2011/6/21/javascript_state_machine_v1_2_0/)
+
+Version 1.0.0 (June 1st 2011)
+-----------------------------
+ * initial version
+ * [read more...](http://codeincomplete.com/posts/2011/6/1/javascript_state_machine/)
diff --git a/addons/base_import/static/lib/javascript-state-machine/Rakefile b/addons/base_import/static/lib/javascript-state-machine/Rakefile
new file mode 100644
index 00000000000..beb8702a7f0
--- /dev/null
+++ b/addons/base_import/static/lib/javascript-state-machine/Rakefile
@@ -0,0 +1,8 @@
+
+desc "create minified version of state-machine.js"
+task :minify do
+ require File.expand_path(File.join(File.dirname(__FILE__), 'minifier/minifier'))
+ Minifier.enabled = true
+ Minifier.minify('state-machine.js')
+end
+
diff --git a/addons/base_import/static/lib/javascript-state-machine/index.html b/addons/base_import/static/lib/javascript-state-machine/index.html
new file mode 100644
index 00000000000..2d6cb62617b
--- /dev/null
+++ b/addons/base_import/static/lib/javascript-state-machine/index.html
@@ -0,0 +1,39 @@
+
+
+
+ Javascript Finite State Machine
+
+
+
+
+
+
+
+
+
Finite State Machine
+
+
+
+
+
+
+
+
+
+
+
+
+ dashed lines are asynchronous state transitions (3 seconds)
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/base_import/static/lib/javascript-state-machine/state-machine.js b/addons/base_import/static/lib/javascript-state-machine/state-machine.js
new file mode 100644
index 00000000000..0d503ee7bdb
--- /dev/null
+++ b/addons/base_import/static/lib/javascript-state-machine/state-machine.js
@@ -0,0 +1,155 @@
+(function (window) {
+
+ StateMachine = {
+
+ //---------------------------------------------------------------------------
+
+ VERSION: "2.1.0",
+
+ //---------------------------------------------------------------------------
+
+ Result: {
+ SUCCEEDED: 1, // the event transitioned successfully from one state to another
+ NOTRANSITION: 2, // the event was successfull but no state transition was necessary
+ CANCELLED: 3, // the event was cancelled by the caller in a beforeEvent callback
+ ASYNC: 4, // the event is asynchronous and the caller is in control of when the transition occurs
+ },
+
+ Error: {
+ INVALID_TRANSITION: 100, // caller tried to fire an event that was innapropriate in the current state
+ PENDING_TRANSITION: 200, // caller tried to fire an event while an async transition was still pending
+ INVALID_CALLBACK: 300, // caller provided callback function threw an exception
+ },
+
+ WILDCARD: '*',
+ ASYNC: 'async',
+
+ //---------------------------------------------------------------------------
+
+ create: function(cfg, target) {
+
+ var initial = (typeof cfg.initial == 'string') ? { state: cfg.initial } : cfg.initial; // allow for a simple string, or an object with { state: 'foo', event: 'setup', defer: true|false }
+ var fsm = target || cfg.target || {};
+ var events = cfg.events || [];
+ var callbacks = cfg.callbacks || {};
+ var map = {};
+
+ var add = function(e) {
+ var from = (e.from instanceof Array) ? e.from : (e.from ? [e.from] : [StateMachine.WILDCARD]); // allow 'wildcard' transition if 'from' is not specified
+ map[e.name] = map[e.name] || {};
+ for (var n = 0 ; n < from.length ; n++)
+ map[e.name][from[n]] = e.to || from[n]; // allow no-op transition if 'to' is not specified
+ };
+
+ if (initial) {
+ initial.event = initial.event || 'startup';
+ add({ name: initial.event, from: 'none', to: initial.state });
+ }
+
+ for(var n = 0 ; n < events.length ; n++)
+ add(events[n]);
+
+ for(var name in map) {
+ if (map.hasOwnProperty(name))
+ fsm[name] = StateMachine.buildEvent(name, map[name]);
+ }
+
+ for(var name in callbacks) {
+ if (callbacks.hasOwnProperty(name))
+ fsm[name] = callbacks[name]
+ }
+
+ fsm.current = 'none';
+ fsm.is = function(state) { return this.current == state; };
+ fsm.can = function(event) { return !this.transition && (map[event].hasOwnProperty(this.current) || map[event].hasOwnProperty(StateMachine.WILDCARD)); }
+ fsm.cannot = function(event) { return !this.can(event); };
+ fsm.error = cfg.error || function(name, from, to, args, error, msg) { throw msg; }; // default behavior when something unexpected happens is to throw an exception, but caller can override this behavior if desired (see github issue #3)
+
+ if (initial && !initial.defer)
+ fsm[initial.event]();
+
+ return fsm;
+
+ },
+
+ //===========================================================================
+
+ doCallback: function(fsm, func, name, from, to, args) {
+ if (func) {
+ try {
+ return func.apply(fsm, [name, from, to].concat(args));
+ }
+ catch(e) {
+ return fsm.error(name, from, to, args, StateMachine.Error.INVALID_CALLBACK, "an exception occurred in a caller-provided callback function");
+ }
+ }
+ },
+
+ beforeEvent: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onbefore' + name], name, from, to, args); },
+ afterEvent: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onafter' + name] || fsm['on' + name], name, from, to, args); },
+ leaveState: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onleave' + from], name, from, to, args); },
+ enterState: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onenter' + to] || fsm['on' + to], name, from, to, args); },
+ changeState: function(fsm, name, from, to, args) { return StateMachine.doCallback(fsm, fsm['onchangestate'], name, from, to, args); },
+
+
+ buildEvent: function(name, map) {
+ return function() {
+
+ var from = this.current;
+ var to = map[from] || map[StateMachine.WILDCARD] || from;
+ var args = Array.prototype.slice.call(arguments); // turn arguments into pure array
+
+ if (this.transition)
+ return this.error(name, from, to, args, StateMachine.Error.PENDING_TRANSITION, "event " + name + " inappropriate because previous transition did not complete");
+
+ if (this.cannot(name))
+ return this.error(name, from, to, args, StateMachine.Error.INVALID_TRANSITION, "event " + name + " inappropriate in current state " + this.current);
+
+ if (false === StateMachine.beforeEvent(this, name, from, to, args))
+ return StateMachine.CANCELLED;
+
+ if (from === to) {
+ StateMachine.afterEvent(this, name, from, to, args);
+ return StateMachine.NOTRANSITION;
+ }
+
+ // prepare a transition method for use EITHER lower down, or by caller if they want an async transition (indicated by an ASYNC return value from leaveState)
+ var fsm = this;
+ this.transition = function() {
+ fsm.transition = null; // this method should only ever be called once
+ fsm.current = to;
+ StateMachine.enterState( fsm, name, from, to, args);
+ StateMachine.changeState(fsm, name, from, to, args);
+ StateMachine.afterEvent( fsm, name, from, to, args);
+ };
+
+ var leave = StateMachine.leaveState(this, name, from, to, args);
+ if (false === leave) {
+ this.transition = null;
+ return StateMachine.CANCELLED;
+ }
+ else if ("async" === leave) {
+ return StateMachine.ASYNC;
+ }
+ else {
+ if (this.transition)
+ this.transition(); // in case user manually called transition() but forgot to return ASYNC
+ return StateMachine.SUCCEEDED;
+ }
+
+ };
+ }
+
+ }; // StateMachine
+
+ //===========================================================================
+
+ if ("function" === typeof define) {
+ define("statemachine", [], function() { return StateMachine; });
+ }
+ else {
+ window.StateMachine = StateMachine;
+ }
+
+}(this));
+
diff --git a/addons/base_import/static/src/css/import.css b/addons/base_import/static/src/css/import.css
index f6258f5aa50..21e598ff707 100644
--- a/addons/base_import/static/src/css/import.css
+++ b/addons/base_import/static/src/css/import.css
@@ -10,7 +10,8 @@
.oe_import .oe_import_grid,
.oe_import .oe_import_error_report,
.oe_import .oe_import_with_file,
-.oe_import .oe_import_noheaders {
+.oe_import .oe_import_noheaders,
+.oe_import .oe_import_report_more {
display: none;
}
@@ -19,7 +20,8 @@
}
.oe_import.oe_import_error .oe_import_error_report,
.oe_import.oe_import_with_file .oe_import_with_file,
-.oe_import.oe_import_noheaders .oe_import_noheaders {
+.oe_import.oe_import_noheaders .oe_import_noheaders,
+.oe_import .oe_import_report_showmore .oe_import_report_more {
display: block;
}
@@ -29,6 +31,9 @@
.oe_import .oe_import_error_report ul .oe_import_report_warning {
background-color: #FEFFD9;
}
+.oe_import .oe_import_error_report ul .oe_import_report_info {
+ background-color: #d3ffd3;
+}
.oe_import .oe_import_noheaders {
color: #888;
@@ -47,7 +52,7 @@
}
.oe_import .oe_import_options label {
display: inline-block;
- width: 10em;
+ width: 8em;
text-align: right;
}
diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js
index c2deb660ff2..33c86e88b2c 100644
--- a/addons/base_import/static/src/js/import.js
+++ b/addons/base_import/static/src/js/import.js
@@ -47,31 +47,35 @@ openerp.base_import = function (instance) {
this._super.apply(this, arguments);
if(add_button) {
this.$buttons.on('click', '.oe_list_button_import', function() {
- new instance.web.DataImport(self, self.dataset).open();
+ self.do_action({
+ type: 'ir.actions.client',
+ tag: 'import',
+ params: {
+ model: self.dataset.model
+ }
+ }, void 0, void 0, function () {
+ self.reload();
+ });
return false;
});
}
}
});
- instance.web.DataImport = instance.web.Dialog.extend({
+ instance.web.client_actions.add(
+ 'import', 'instance.web.DataImport');
+ instance.web.DataImport = instance.web.Widget.extend({
template: 'ImportView',
- dialog_title: _lt("Import Data"),
opts: [
{name: 'encoding', label: _lt("Encoding:"), value: 'utf-8'},
{name: 'separator', label: _lt("Separator:"), value: ','},
{name: 'quoting', label: _lt("Quoting:"), value: '"'}
],
events: {
- 'change .oe_import_grid input': 'import_dryrun',
- 'change input.oe_import_file': 'file_update',
- 'change input.oe_import_has_header, .oe_import_options input': 'settings_updated',
- 'click a.oe_import_csv': function (e) {
- e.preventDefault();
- },
- 'click a.oe_import_export': function (e) {
- e.preventDefault();
- },
+ // 'change .oe_import_grid input': 'import_dryrun',
+ 'change .oe_import_file': 'loaded_file',
+ 'click .oe_import_file_reload': 'loaded_file',
+ 'change input.oe_import_has_header, .oe_import_options input': 'settings_changed',
'click a.oe_import_toggle': function (e) {
e.preventDefault();
var $el = $(e.target);
@@ -79,30 +83,84 @@ openerp.base_import = function (instance) {
? $el.next()
: $el.parent().next())
.toggle();
+ },
+ 'click .oe_import_report a.oe_import_report_count': function (e) {
+ e.preventDefault();
+ $(e.target).parent().toggleClass('oe_import_report_showmore');
+ },
+ 'click .oe_import_moreinfo_action a': function (e) {
+ e.preventDefault();
+ // #data will parse the attribute on its own, we don't like
+ // that sort of things
+ var action = JSON.parse($(e.target).attr('data-action'));
+ // FIXME: when JS-side clean_action
+ action.views = _(action.views).map(function (view) {
+ var id = view[0], type = view[1];
+ return [
+ id,
+ type !== 'tree' ? type
+ : action.view_type === 'form' ? 'list'
+ : 'tree'
+ ];
+ });
+ this.do_action(_.extend(action, {
+ target: 'new',
+ flags: {
+ search_view: true,
+ display_title: true,
+ pager: true,
+ list: {selectable: false}
+ }
+ }));
+ },
+ // buttons
+ 'click .oe_import_validate': 'validate',
+ 'click .oe_import_import': 'import',
+ 'click .oe_import_cancel': function (e) {
+ e.preventDefault();
+ this.exit();
}
},
- init: function (parent, dataset) {
+ init: function (parent, params) {
var self = this;
- this._super(parent, {
- buttons: [
- {text: _t("Import File"), click: function () {
- self.do_import();
- }, 'class': 'oe_import_dialog_button'}
- ]
- });
- this.res_model = parent.model;
+ this._super.apply(this, arguments);
+ this.res_model = params.model;
// import object id
this.id = null;
this.Import = new instance.web.Model('base_import.import');
},
start: function () {
var self = this;
- return this.Import.call('create', [{
- 'res_model': this.res_model
- }]).then(function (id) {
- self.id = id;
- self.$('input[name=import_id]').val(id);
- });
+ this.setup_encoding_picker();
+
+ return $.when(
+ this._super(),
+ this.Import.call('create', [{
+ 'res_model': this.res_model
+ }]).then(function (id) {
+ self.id = id;
+ self.$('input[name=import_id]').val(id);
+ })
+ )
+ },
+ setup_encoding_picker: function () {
+ this.$('input.oe_import_encoding').select2({
+ width: '160px',
+ query: function (q) {
+ var make = function (term) { return {id: term, text: term}; };
+ var suggestions = _.map(
+ ('utf-8 utf-16 windows-1252 latin1 latin2 big5 ' +
+ 'gb18030 shift_jis windows-1251 koir8_r').split(/\s+/),
+ make);
+ if (q.term) {
+ suggestions.unshift(make(q.term));
+ }
+ q.callback({results: suggestions});
+ },
+ initSelection: function (e, c) {
+ return c({id: 'utf-8', text: 'utf-8'});
+ }
+ }).select2('val', 'utf-8');
},
import_options: function () {
@@ -118,34 +176,52 @@ openerp.base_import = function (instance) {
},
//- File & settings change section
- file_update: function (e) {
+ onfile_loaded: function () {
+ this.$('.oe_import_button').prop('disabled', true);
if (!this.$('input.oe_import_file').val()) { return; }
this.$el.removeClass('oe_import_preview oe_import_error');
jsonp(this.$el, {
url: '/base_import/set_file'
- }, this.proxy('settings_updated'));
+ }, this.proxy('settings_changed'));
},
- settings_updated: function () {
+ onpreviewing: function () {
+ var self = this;
+ this.$('.oe_import_button').prop('disabled', true);
this.$el.addClass('oe_import_with_file');
// TODO: test that write // succeeded?
- this.Import.call(
- 'parse_preview', [this.id, this.import_options()])
- .then(this.proxy('preview'));
- },
- preview: function (result) {
+ this.$el.removeClass('oe_import_preview_error oe_import_error');
this.$el.toggleClass(
'oe_import_noheaders',
!this.$('input.oe_import_has_header').prop('checked'));
- if (result.error) {
- this.$el.addClass('oe_import_error');
- this.$('.oe_import_error_report').html(
+ this.Import.call(
+ 'parse_preview', [this.id, this.import_options()])
+ .then(function (result) {
+ var signal = result.error ? 'preview_failed' : 'preview_succeeded';
+ self[signal](result);
+ });
+ },
+ onpreview_error: function (event, from, to, result) {
+ this.$('.oe_import_options').show();
+ this.$el.addClass('oe_import_preview_error oe_import_error');
+ this.$('.oe_import_error_report').html(
QWeb.render('ImportView.preview.error', result));
- return;
- }
+ },
+ onpreview_success: function (event, from, to, result) {
+ this.$('.oe_import_import').removeClass('oe_highlight');
+ this.$('.oe_import_validate').addClass('oe_highlight');
+ this.$('.oe_import_button').prop('disabled', false);
this.$el.addClass('oe_import_preview');
this.$('table').html(QWeb.render('ImportView.preview', result));
+ if (result.headers.length === 1) {
+ this.$('.oe_import_options').show();
+ this.onresults(null, null, null, [{
+ type: 'warning',
+ message: _t("A single column was found in the file, this often means the file separator is incorrect")
+ }]);
+ }
+
var $fields = this.$('.oe_import_fields input');
this.render_fields_matches(result, $fields);
var data = this.generate_fields_completion(result);
@@ -180,7 +256,6 @@ openerp.base_import = function (instance) {
width: 'resolve',
dropdownCssClass: 'oe_import_selector'
});
- this.import_dryrun();
},
generate_fields_completion: function (root) {
var basic = [];
@@ -252,40 +327,116 @@ openerp.base_import = function (instance) {
//- import itself
call_import: function (options) {
- var self = this;
var fields = this.$('.oe_import_fields input.oe_import_match_field').map(function (index, el) {
return $(el).select2('val') || false;
}).get();
return this.Import.call(
'do', [this.id, fields, this.import_options()], options);
},
- import_dryrun: function () {
-// this.call_import({ dryrun: true })
-// .then(this.proxy('render_import_errors'));
+ onvalidate: function () {
+ return this.call_import({ dryrun: true })
+ .then(this.proxy('validated'));
},
- do_import: function () {
+ onimport: function () {
var self = this;
- this.call_import({ dryrun: false }).then(function (errors) {
- if (_.isEmpty(errors)) {
- if (self.getParent().reload_content) {
- self.getParent().reload_content();
- }
- self.close();
+ return this.call_import({ dryrun: false }).then(function (message) {
+ if (!_.any(message, function (message) {
+ return message.type === 'error' })) {
+ self['import_succeeded']();
return;
}
- self.render_import_errors(errors);
+ self['import_failed'](message);
});
},
- render_import_errors: function (errors) {
- if (_.isEmpty(errors)) {
- this.$el.removeClass('oe_import_error');
- return;
+ onimported: function () {
+ this.exit();
+ },
+ exit: function () {
+ this.do_action({
+ type: 'ir.actions.client',
+ tag: 'history_back'
+ });
+ },
+ onresults: function (event, from, to, message) {
+ var no_messages = _.isEmpty(message);
+ this.$('.oe_import_import').toggleClass('oe_highlight', no_messages);
+ this.$('.oe_import_validate').toggleClass('oe_highlight', !no_messages);
+ if (no_messages) {
+ message.push({
+ type: 'info',
+ message: _t("Everything seems valid.")
+ });
}
- // import failed (or maybe just warnings, if we ever get
- // warnings?)
+ // row indexes come back 0-indexed, spreadsheets
+ // display 1-indexed.
+ var offset = 1;
+ // offset more if header
+ if (this.import_options().headers) { offset += 1; }
+
this.$el.addClass('oe_import_error');
this.$('.oe_import_error_report').html(
- QWeb.render('ImportView.error', {errors: errors}));
+ QWeb.render('ImportView.error', {
+ errors: _(message).groupBy('message'),
+ at: function (rows) {
+ var from = rows.from + offset;
+ var to = rows.to + offset;
+ if (from === to) {
+ return _.str.sprintf(_t("at row %d"), from);
+ }
+ return _.str.sprintf(_t("between rows %d and %d"),
+ from, to);
+ },
+ more: function (n) {
+ return _.str.sprintf(_t("(%d more)"), n);
+ },
+ info: function (msg) {
+ if (typeof msg === 'string') {
+ return _.str.sprintf(
+ '
- [[o.employee_id.address_home_id and o.employee_id.address_home_id.name or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.street or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.street2 or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.zip or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.city or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.state_id and o.employee_id.address_home_id.state_id.name or '' ]] [[o.employee_id.address_home_id and o.employee_id.address_home_id.country_id and o.employee_id.address_home_id.country_id.name or '' ]]
+ [[o.employee_id.address_home_id and o.employee_id.address_home_id.name or '' ]]
+ [[o.employee_id.address_home_id and display_address(o.employee_id.address_home_id)]]
@@ -293,7 +294,7 @@
[[ formatLang(p.amount) ]]
- [[ formatLang(p.total) ]] [[o.company_id and o.company_id.currency_id.symbol or '']]
+ [[ formatLang(p.total, currency_obj = o.company_id and o.company_id.currency_id)]]
- [[o.employee_id.address_home_id and o.employee_id.address_home_id.name or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.street or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.street2 or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.zip or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.city or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.state_id and o.employee_id.address_home_id.state_id.name or '' ]] [[o.employee_id.address_home_id and o.employee_id.address_home_id.country_id and o.employee_id.address_home_id.country_id.name or '' ]]
+ [[o.employee_id.address_home_id and o.employee_id.address_home_id.name or '' ]]
+ [[o.employee_id.address_home_id and display_address(o.employee_id.address_home_id)]]
@@ -334,7 +335,7 @@
[[ '..'*h['level'] ]][[ h['rule_category'] ]][[ h['level']!=0 and ( setTag('para','para',{'style':'terp_default_8'})) or removeParentNode('font') ]]
- [[ formatLang(h['total']) ]] [[o.company_id and o.company_id.currency_id.symbol or '']] [[ h['level']==0 and ( setTag('para','para',{'style':'terp_default_10'})) or removeParentNode('font') ]]
+ [[ formatLang(h['total'], currency_obj = o.company_id and o.company_id.currency_id)]] [[ h['level']==0 and ( setTag('para','para',{'style':'terp_default_10'})) or removeParentNode('font') ]]
@@ -391,7 +392,7 @@
[[ formatLang(r['amount']) ]]
- [[ formatLang(r['total']) ]] [[ o.company_id and o.company_id.currency_id.symbol or '']][[ r.get('register_name', False) and ( setTag('para','para',{'style':'terp_default_10'})) or removeParentNode('font')]]
+ [[ formatLang(r['total'], currency_obj = o.company_id and o.company_id.currency_id)]][[ r.get('register_name', False) and ( setTag('para','para',{'style':'terp_default_10'})) or removeParentNode('font')]]
diff --git a/addons/hr_payroll_account/hr_payroll_account.py b/addons/hr_payroll_account/hr_payroll_account.py
index 184f9a06867..94df47f6e44 100644
--- a/addons/hr_payroll_account/hr_payroll_account.py
+++ b/addons/hr_payroll_account/hr_payroll_account.py
@@ -36,7 +36,7 @@ class hr_payslip(osv.osv):
_columns = {
'period_id': fields.many2one('account.period', 'Force Period',states={'draft': [('readonly', False)]}, readonly=True, domain=[('state','<>','done')], help="Keep empty to use the period of the validation(Payslip) date."),
- 'journal_id': fields.many2one('account.journal', 'Expense Journal',states={'draft': [('readonly', False)]}, readonly=True, required=True),
+ 'journal_id': fields.many2one('account.journal', 'Salary Journal',states={'draft': [('readonly', False)]}, readonly=True, required=True),
'move_id': fields.many2one('account.move', 'Accounting Entry', readonly=True),
}
@@ -215,7 +215,7 @@ class hr_payslip_run(osv.osv):
_inherit = 'hr.payslip.run'
_description = 'Payslip Run'
_columns = {
- 'journal_id': fields.many2one('account.journal', 'Expense Journal', states={'draft': [('readonly', False)]}, readonly=True, required=True),
+ 'journal_id': fields.many2one('account.journal', 'Salary Journal', states={'draft': [('readonly', False)]}, readonly=True, required=True),
}
def _get_default_journal(self, cr, uid, context=None):
diff --git a/addons/hr_recruitment/hr_recruitment.py b/addons/hr_recruitment/hr_recruitment.py
index ccfcae0d26e..56c517620e0 100644
--- a/addons/hr_recruitment/hr_recruitment.py
+++ b/addons/hr_recruitment/hr_recruitment.py
@@ -297,7 +297,6 @@ class hr_applicant(base_stage, osv.Model):
res['context'] = {
'default_partner_ids': applicant.partner_id and [applicant.partner_id.id] or False,
'default_user_id': uid,
- 'default_state': 'open',
'default_name': applicant.name,
'default_categ_ids': category and [category.id] or False,
}
diff --git a/addons/hr_recruitment/hr_recruitment_view.xml b/addons/hr_recruitment/hr_recruitment_view.xml
index d48086f5663..d6d04c1b969 100644
--- a/addons/hr_recruitment/hr_recruitment_view.xml
+++ b/addons/hr_recruitment/hr_recruitment_view.xml
@@ -289,7 +289,8 @@
diff --git a/addons/l10n_be_hr_payroll/i18n/pt_BR.po b/addons/l10n_be_hr_payroll/i18n/pt_BR.po
new file mode 100644
index 00000000000..2c4f688842a
--- /dev/null
+++ b/addons/l10n_be_hr_payroll/i18n/pt_BR.po
@@ -0,0 +1,162 @@
+# Brazilian Portuguese translation for openobject-addons
+# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
+# This file is distributed under the same license as the openobject-addons package.
+# FIRST AUTHOR , 2012.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: openobject-addons\n"
+"Report-Msgid-Bugs-To: FULL NAME \n"
+"POT-Creation-Date: 2012-02-08 00:36+0000\n"
+"PO-Revision-Date: 2012-10-16 23:34+0000\n"
+"Last-Translator: Syllas F. de O. Neto \n"
+"Language-Team: Brazilian Portuguese \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2012-10-17 04:36+0000\n"
+"X-Generator: Launchpad (build 16152)\n"
+
+#. module: l10n_be_hr_payroll
+#: help:hr.employee,disabled_spouse_bool:0
+msgid "if recipient spouse is declared disabled by law"
+msgstr "Caso o cônjuge beneficiário seja considerado incapaz perante a lei"
+
+#. module: l10n_be_hr_payroll
+#: help:hr.employee,disabled_children_bool:0
+msgid "if recipient children is/are declared disabled by law"
+msgstr ""
+"Caso o(s) filho(s) beneficiário(s) seja(m) considerado(s) incapaz(es) "
+"perante a lei"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,misc_onss_deduction:0
+msgid "Miscellaneous exempt ONSS "
+msgstr "Outros isentos de INSS "
+
+#. module: l10n_be_hr_payroll
+#: model:ir.model,name:l10n_be_hr_payroll.model_hr_employee
+msgid "Employee"
+msgstr "Empregado"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,disabled_spouse_bool:0
+msgid "Disabled Spouse"
+msgstr "Cõnjuge incapaz"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,retained_net_amount:0
+msgid "Net retained "
+msgstr "Líquido retido "
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,resident_bool:0
+msgid "Nonresident"
+msgstr "Não residente no país local"
+
+#. module: l10n_be_hr_payroll
+#: help:hr.employee,resident_bool:0
+msgid "if recipient lives in a foreign country"
+msgstr "Caso o beneficiário resida em outro país"
+
+#. module: l10n_be_hr_payroll
+#: view:hr.employee:0
+msgid "if spouse has professionnel income or not"
+msgstr "Caso o cônjuge possua renda"
+
+#. module: l10n_be_hr_payroll
+#: view:hr.contract:0
+msgid "Miscellaneous"
+msgstr "Outros"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,insurance_employee_deduction:0
+msgid "Insurance Group - by worker "
+msgstr "Categoria do Seguro - por empregado "
+
+#. module: l10n_be_hr_payroll
+#: selection:hr.employee,spouse_fiscal_status:0
+msgid "With Income"
+msgstr "Com renda"
+
+#. module: l10n_be_hr_payroll
+#: selection:hr.employee,spouse_fiscal_status:0
+msgid "Without Income"
+msgstr "Sem renda"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,disabled_children_number:0
+msgid "Number of disabled children"
+msgstr "Quantidade de filho(s) incapaz(es)"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,additional_net_amount:0
+msgid "Net supplements"
+msgstr "Renda suplementar"
+
+#. module: l10n_be_hr_payroll
+#: constraint:hr.employee:0
+msgid "Error ! You cannot create recursive Hierarchy of Employees."
+msgstr "Erro! Você não pode criar uma Hierarquia de Empregados recursiva."
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,car_company_amount:0
+msgid "Company car employer"
+msgstr "Carro da empresa"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,misc_advantage_amount:0
+msgid "Benefits of various nature "
+msgstr "Benefícios de outras naturezas "
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,car_employee_deduction:0
+msgid "Company Car Deduction for Worker"
+msgstr "Dedução referente ao carro da empresa"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,disabled_children_bool:0
+msgid "Disabled Children"
+msgstr "Filho(s) incapaz(es)"
+
+#. module: l10n_be_hr_payroll
+#: model:ir.model,name:l10n_be_hr_payroll.model_hr_contract
+msgid "Contract"
+msgstr "Contrato"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,meal_voucher_amount:0
+msgid "Check Value Meal "
+msgstr "Vale refeição "
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,travel_reimbursement_amount:0
+msgid "Reimbursement of travel expenses"
+msgstr "Reembolso de despeza de viagem"
+
+#. module: l10n_be_hr_payroll
+#: constraint:hr.contract:0
+msgid "Error! contract start-date must be lower then contract end-date."
+msgstr ""
+"Erro! A data de início do contrato deve ser menor que a data de término do "
+"contrato."
+
+#. module: l10n_be_hr_payroll
+#: field:hr.employee,spouse_fiscal_status:0
+msgid "Tax status for spouse"
+msgstr "Situação fiscal do cônjuge"
+
+#. module: l10n_be_hr_payroll
+#: view:hr.contract:0
+msgid "by Worker"
+msgstr "por Empregado"
+
+#. module: l10n_be_hr_payroll
+#: view:hr.employee:0
+msgid "number of dependent children declared as disabled"
+msgstr "Quantidade de filhos declarados como incapazes"
+
+#. module: l10n_be_hr_payroll
+#: field:hr.contract,meal_voucher_employee_deduction:0
+msgid "Check Value Meal - by worker "
+msgstr "Vale refeição - por empregado "
diff --git a/addons/l10n_ch/sterchi_chart/account.xml b/addons/l10n_ch/sterchi_chart/account.xml
index b04031d42ce..bd848642a97 100644
--- a/addons/l10n_ch/sterchi_chart/account.xml
+++ b/addons/l10n_ch/sterchi_chart/account.xml
@@ -11807,7 +11807,6 @@
-
diff --git a/addons/l10n_cn/account_chart.xml b/addons/l10n_cn/account_chart.xml
index e51a9d70654..afcb3e04b0c 100644
--- a/addons/l10n_cn/account_chart.xml
+++ b/addons/l10n_cn/account_chart.xml
@@ -957,7 +957,6 @@
-
diff --git a/addons/l10n_cn/i18n/pt_BR.po b/addons/l10n_cn/i18n/pt_BR.po
index 68670229801..64e1f8cc066 100644
--- a/addons/l10n_cn/i18n/pt_BR.po
+++ b/addons/l10n_cn/i18n/pt_BR.po
@@ -8,29 +8,29 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2011-12-23 09:56+0000\n"
-"PO-Revision-Date: 2011-03-09 22:08+0000\n"
-"Last-Translator: Emerson \n"
+"PO-Revision-Date: 2012-10-16 23:56+0000\n"
+"Last-Translator: Syllas F. de O. Neto \n"
"Language-Team: Brazilian Portuguese \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-08-28 06:42+0000\n"
-"X-Generator: Launchpad (build 15864)\n"
+"X-Launchpad-Export-Date: 2012-10-17 04:36+0000\n"
+"X-Generator: Launchpad (build 16152)\n"
#. module: l10n_cn
#: model:account.account.type,name:l10n_cn.user_type_profit_and_loss
msgid "损益类"
-msgstr ""
+msgstr "Categoria Lucro ou Prejuízo"
#. module: l10n_cn
#: model:account.account.type,name:l10n_cn.user_type_all
msgid "所有科目"
-msgstr ""
+msgstr "Todos os assuntos"
#. module: l10n_cn
#: model:account.account.type,name:l10n_cn.user_type_equity
msgid "所有者权益类"
-msgstr ""
+msgstr "Capital Próprio"
#. module: l10n_cn
#: model:ir.actions.todo,note:l10n_cn.config_call_account_template_cn_chart
@@ -43,28 +43,28 @@ msgid ""
"Management/Configuration/Financial Accounting/Financial Accounts/Generate "
"Chart of Accounts from a Chart Template."
msgstr ""
-"Generate Chart of Accounts from a Chart Template. You will be asked to pass "
-"the name of the company, the chart template to follow, the no. of digits to "
-"generate the code for your accounts and Bank account, currency to create "
-"Journals. Thus,the pure copy of chart Template is generated.\n"
-"\tThis is the same wizard that runs from Financial "
-"Management/Configuration/Financial Accounting/Financial Accounts/Generate "
-"Chart of Accounts from a Chart Template."
+"Gerar Gráfico de Contas apartir de um modelo. Você deverá informar o nome da "
+"empresa, o gráfico modelo, o número de dígitos para gerar o código para suas "
+"contas, a conta bancária e a moeda para gerar a sequência. Em seguida uma "
+"cópia do gráfico modelo é gerada.\n"
+"Este é o mesmo assistente que é executado a partir de Gerenciamento "
+"Financeiro/Configuração/Contabilidade Financeira/Contas Financeiras/Gerar "
+"Gráfico de Contas a partir de um Gráfico Modelo."
#. module: l10n_cn
#: model:account.account.type,name:l10n_cn.user_type_debt
msgid "负债类"
-msgstr ""
+msgstr "Classe Passivos"
#. module: l10n_cn
#: model:account.account.type,name:l10n_cn.user_type_cost
msgid "成本类"
-msgstr ""
+msgstr "Custo da Classe"
#. module: l10n_cn
#: model:account.account.type,name:l10n_cn.user_type_capital
msgid "资产类"
-msgstr ""
+msgstr "Classe Ativos"
#~ msgid "中国会计科目表"
#~ msgstr "中国会计科目表"
diff --git a/addons/l10n_fr/fr_pcg_taxes.xml b/addons/l10n_fr/fr_pcg_taxes.xml
index b44d04439f0..78b34f2d696 100644
--- a/addons/l10n_fr/fr_pcg_taxes.xml
+++ b/addons/l10n_fr/fr_pcg_taxes.xml
@@ -441,7 +441,6 @@
-
diff --git a/addons/l10n_fr_hr_payroll/report/fiche_paye.rml b/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
index 5221b00c462..76c6eb9dedf 100644
--- a/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
+++ b/addons/l10n_fr_hr_payroll/report/fiche_paye.rml
@@ -290,9 +290,7 @@
[[o.employee_id.name or '_']]
- [[o.employee_id.address_home_id.street or '_' ]]
- [[o.employee_id.address_home_id.street2 or '' ]]
- [[o.employee_id.address_home_id.zip or '_' ]] [[o.employee_id.address_home_id.city or '' ]]
+ [[display_address(o.employee_id.address_home_id) or '_' ]]
- [[o.employee_id.address_home_id and o.employee_id.address_home_id.name or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.street or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.street2 or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.zip or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.city or '' ]],[[o.employee_id.address_home_id and o.employee_id.address_home_id.state_id and o.employee_id.address_home_id.state_id.name or '' ]] [[o.employee_id.address_home_id and o.employee_id.address_home_id.country_id and o.employee_id.address_home_id.country_id.name or '' ]]
+ [[o.employee_id.address_home_id and o.employee_id.address_home_id.name or '' ]],[[o.employee_id.address_home_id and display_address(o.employee_id.address_home_id)]]
@@ -334,7 +334,7 @@
[[ '..'*h['level'] ]][[ h['rule_category'] ]][[ h['level']!=0 and ( setTag('para','para',{'style':'terp_default_8'})) or removeParentNode('font') ]]
- [[ formatLang(h['total']) ]] [[o.company_id and o.company_id.currency_id.symbol or '']] [[ h['level']==0 and ( setTag('para','para',{'style':'terp_default_10'})) or removeParentNode('font') ]]
+ [[ formatLang(h['total'], currency_obj = o.company_id and o.company_id.currency_id)]] [[ h['level']==0 and ( setTag('para','para',{'style':'terp_default_10'})) or removeParentNode('font') ]]
diff --git a/addons/l10n_ma/i18n/pt_BR.po b/addons/l10n_ma/i18n/pt_BR.po
index 71877580cbd..1c57545404c 100644
--- a/addons/l10n_ma/i18n/pt_BR.po
+++ b/addons/l10n_ma/i18n/pt_BR.po
@@ -8,14 +8,14 @@ msgstr ""
"Project-Id-Version: openobject-addons\n"
"Report-Msgid-Bugs-To: FULL NAME \n"
"POT-Creation-Date: 2011-12-23 09:56+0000\n"
-"PO-Revision-Date: 2011-03-10 23:15+0000\n"
-"Last-Translator: Emerson \n"
+"PO-Revision-Date: 2012-10-16 23:59+0000\n"
+"Last-Translator: Syllas F. de O. Neto \n"
"Language-Team: Brazilian Portuguese \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-08-28 06:41+0000\n"
-"X-Generator: Launchpad (build 15864)\n"
+"X-Launchpad-Export-Date: 2012-10-17 04:36+0000\n"
+"X-Generator: Launchpad (build 16152)\n"
#. module: l10n_ma
#: model:account.account.type,name:l10n_ma.cpt_type_imm
@@ -81,7 +81,7 @@ msgstr "Name"
#. module: l10n_ma
#: field:l10n.ma.report,line_ids:0
msgid "Lines"
-msgstr "Lines"
+msgstr "Linhas"
#. module: l10n_ma
#: model:account.account.type,name:l10n_ma.cpt_type_tax
diff --git a/addons/l10n_nl/account_chart_netherlands.xml b/addons/l10n_nl/account_chart_netherlands.xml
index 48cf78f382b..96100d9a442 100644
--- a/addons/l10n_nl/account_chart_netherlands.xml
+++ b/addons/l10n_nl/account_chart_netherlands.xml
@@ -4102,7 +4102,6 @@
-
-
- Inbox
- mail.wall
-
-
-
-
- Archives
- mail.wall
-
-
-
-
- Sent
- mail.wall
-
-
-
+
\ No newline at end of file
diff --git a/addons/mail/mail_star.py b/addons/mail/mail_star.py
new file mode 100644
index 00000000000..00a10c32dc6
--- /dev/null
+++ b/addons/mail/mail_star.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# OpenERP, Open Source Management Solution
+# Copyright (C) 2012-Today OpenERP SA ().
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero 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 Affero General Public License for more details
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see
+#
+##############################################################################
+
+from osv import osv, fields
+
+
+class mail_star(osv.Model):
+ ''' Mail vote feature allow users to select messages and display.
+ This allows for example see in one time all important document
+ for the user. '''
+
+ _name = 'mail.star'
+ _description = 'Mail Star'
+ _columns = {
+ 'message_id': fields.many2one('mail.message', 'Message', select=1,
+ ondelete='cascade', required=True),
+ 'user_id': fields.many2one('res.users', 'User', select=1,
+ ondelete='cascade', required=True),
+ }
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py
index e5b93ac4000..094970156df 100644
--- a/addons/mail/mail_thread.py
+++ b/addons/mail/mail_thread.py
@@ -102,12 +102,12 @@ class mail_thread(osv.AbstractModel):
# find the document followers, update the data
fol_obj = self.pool.get('mail.followers')
- fol_ids = fol_obj.search(cr, uid, [
+ fol_ids = fol_obj.search(cr, SUPERUSER_ID, [
('partner_id', '=', user_pid),
('res_id', 'in', ids),
('res_model', '=', self._name),
], context=context)
- for fol in fol_obj.browse(cr, uid, fol_ids, context=context):
+ for fol in fol_obj.browse(cr, SUPERUSER_ID, fol_ids, context=context):
thread_subtype_dict = res[fol.res_id]['message_subtype_data']
res[fol.res_id]['message_is_follower'] = True
for subtype in fol.subtype_ids:
@@ -221,8 +221,8 @@ class mail_thread(osv.AbstractModel):
def create(self, cr, uid, vals, context=None):
""" Override to subscribe the current user. """
- thread_id = super(mail_thread, self).create(cr, uid, vals, context=context)
- self.message_subscribe_users(cr, uid, [thread_id], [uid], context=context)
+ thread_id = super(mail_thread, self).create(cr, SUPERUSER_ID, vals, context=context)
+ self.message_subscribe_users(cr, SUPERUSER_ID, [thread_id], [uid], context=context)
return thread_id
def unlink(self, cr, uid, ids, context=None):
@@ -682,8 +682,8 @@ class mail_thread(osv.AbstractModel):
# if the parent is private, the message must be private
if parent_id:
msg = messages.browse(cr, uid, parent_id, context=context)
- if msg.is_private:
- values["is_private"] = msg.is_private
+ values["is_private"] = msg.is_private or False
+ values["partner_ids"] = [(4, partner.id) for partner in msg.partner_ids] + [(4, msg.author_id.id)]
# Avoid warnings about non-existing fields
for x in ('from', 'to', 'cc'):
@@ -708,10 +708,10 @@ class mail_thread(osv.AbstractModel):
attachment_ids=[]
if attachments:
ir_attachment = self.pool.get('ir.attachment')
- attachment_ids = ir_attachment.search(cr, 1, [('res_model', '=', ""), ('res_id', '=', ""), ('user_id', '=', uid), ('id', 'in', attachments)], context=context)
+ attachment_ids = ir_attachment.search(cr, SUPERUSER_ID, [('res_model', '=', 'mail.message'), ('res_id', '=', 0), ('create_uid', '=', uid), ('id', 'in', attachments)], context=context)
if attachment_ids:
- self.pool.get('ir.attachment').write(cr, 1, attachment_ids, { 'res_model': self._name, 'res_id': thread_id }, context=context)
- self.pool.get('mail.message').write(cr, 1, [added_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]} )
+ self.pool.get('ir.attachment').write(cr, SUPERUSER_ID, attachment_ids, { 'res_model': self._name, 'res_id': thread_id }, context=context)
+ self.pool.get('mail.message').write(cr, SUPERUSER_ID, [added_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]} )
added_message = self.pool.get('mail.message').message_read(cr, uid, [added_message_id])
return added_message
diff --git a/addons/mail/mail_thread_view.xml b/addons/mail/mail_thread_view.xml
index 696edde0e15..fed0cdde9e3 100644
--- a/addons/mail/mail_thread_view.xml
+++ b/addons/mail/mail_thread_view.xml
@@ -1,35 +1,82 @@
+
+ Inbox
+ mail.wall
+
+
+
+
+ To: me
+ mail.wall
+
+
+
+
+ Favorites
+ mail.wall
+
+
+
+
+ Archives
+ mail.wall
+
+
+
+
+ Sent
+ mail.wall
+
+
+
+
-
-
+
Inbox
-
+
+
+
+ To: me
+
+
+
+
+
+ Favorites
+
+
+ Archives
-
+
-
+ Sent
-
+
-
+
-
-
+
\ No newline at end of file
diff --git a/addons/mail/static/src/css/mail_compose_message.css b/addons/mail/static/src/css/mail_compose_message.css
index e2f136eb755..c706c55bcde 100644
--- a/addons/mail/static/src/css/mail_compose_message.css
+++ b/addons/mail/static/src/css/mail_compose_message.css
@@ -2,11 +2,11 @@
/* Compose Message */
/* ------------------------------ */
-.openerp .oe_mail_msg_content .oe_mail_compose_message_footer {
+.openerp .oe_msg_content .oe_mail_compose_message_footer {
height: 24px;
}
-.openerp .oe_mail_msg_content .oe_mail_compose_message_footer button.oe_mail_compose_message_button_send {
+.openerp .oe_msg_content .oe_mail_compose_message_footer button.oe_mail_compose_message_button_send {
float: left;
}
@@ -98,7 +98,7 @@
font-size: 30px;
}
-.openerp .oe_mail .oe_mail_msg_attachments input {
+.openerp .oe_mail .oe_msg_attachments input {
visibility: hidden;
}
@@ -128,39 +128,39 @@
}
/* form_view: delete white background */
-.openerp .oe_mail_msg_content div.oe_formview {
+.openerp .oe_msg_content div.oe_formview {
background-color: transparent;
}
-.openerp .oe_mail_msg_content div.oe_form_nosheet {
+.openerp .oe_msg_content div.oe_form_nosheet {
margin: 0px;
}
-.openerp .oe_mail_msg_content table.oe_form_group {
+.openerp .oe_msg_content table.oe_form_group {
margin: 0px;
}
-.openerp .oe_mail_msg_content table.oe_form_field,
-.openerp .oe_mail_msg_content div.oe_form_field {
+.openerp .oe_msg_content table.oe_form_field,
+.openerp .oe_msg_content div.oe_form_field {
padding: 0px;
}
-.openerp .oe_mail_msg_content td.oe_form_group_cell {
+.openerp .oe_msg_content td.oe_form_group_cell {
vertical-align: bottom;
}
/* subject: change width */
-.openerp .oe_mail_msg_content .oe_form .oe_form_field input[type='text'] {
+.openerp .oe_msg_content .oe_form .oe_form_field input[type='text'] {
width: 472px;
}
/* body_html: cleditor */
-.openerp .oe_mail_msg_content div.cleditorMain {
+.openerp .oe_msg_content div.cleditorMain {
border: 1px solid #cccccc;
}
/* destination_partner_ids */
-.openerp .oe_mail_msg_content div.text-core {
+.openerp .oe_msg_content div.text-core {
height: 22px !important;
width: 472px;
}
\ No newline at end of file
diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js
index f3bf7e9b9fa..7f18f650dae 100644
--- a/addons/mail/static/src/js/mail.js
+++ b/addons/mail/static/src/js/mail.js
@@ -27,6 +27,7 @@ openerp.mail = function(session) {
if( key!='default_template_id' &&
key!='default_use_template' &&
key!='default_is_private' &&
+ key!='default_partner_ids' &&
key!='default_model' &&
key!='default_res_id' &&
key!='default_subtype' &&
@@ -41,14 +42,11 @@ openerp.mail = function(session) {
};
/* end hack */
- $('.openerp .oe_mail_wall_threads .oe_mail_thread button.oe_mail_wall_button_fetch').click();
-
}
return this._super(action, on_close);
},
});
-
/**
* ------------------------------------------------------------
* ChatterUtils
@@ -108,10 +106,14 @@ openerp.mail = function(session) {
*
* This widget handles the display of a form to compose a new message.
* This form is a mail.compose.message form_view.
- */
+ * On first time : display a compact textarea but is not the compose form.
+ * When the user focus this box, the compose message is intantiate and
+ * with focus on the textarea.
+ */
mail.ThreadComposeMessage = session.web.Widget.extend({
- template: 'mail.compose_message',
+ template: 'mail.compose_message.compact',
+ // expandable view : 'mail.compose_message'
/**
* @param {Object} parent parent
@@ -124,27 +126,26 @@ openerp.mail = function(session) {
init: function (parent, options) {
var self = this;
this._super(parent);
- this.attachment_ids = [];
-
this.context = options.context || {};
- this.id = options.parameters.id;
- this.model = options.parameters.model;
- this.res_id = options.parameters.res_id;
- this.is_private = options.parameters.is_private;
- this.partner_ids = options.parameters.partner_ids;
- this.options={thread:{}};
- this.options.thread.show_header_compose = options.parameters.options.thread.show_header_compose;
- this.options.thread.display_on_flat = options.parameters.options.thread.display_on_flat;
-
- this.attachment_ids = [];
+ this.datasets = {
+ 'attachment_ids' : [],
+ 'id': options.datasets.id,
+ 'model': options.datasets.model,
+ 'res_model': options.datasets.res_model,
+ 'is_private': options.datasets.is_private || false,
+ 'partner_ids': options.datasets.partner_ids || [],
+ 'avatar': mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid),
+ };
+ this.options={};
+ this.options.thread={};
+ this.options.thread.display_on_thread = options.options.thread.display_on_thread;
this.options.thread.show_attachment_delete = true;
- this.options.thread.show_attachment_link = true;
this.parent_thread= parent.messages!= undefined ? parent : false;
-
this.ds_attachment = new session.web.DataSetSearch(this, 'ir.attachment');
+
this.fileupload_id = _.uniqueId('oe_fileupload_temp');
$(window).on(self.fileupload_id, self.on_attachment_loaded);
},
@@ -152,10 +153,6 @@ openerp.mail = function(session) {
start: function(){
this.display_attachments();
this.bind_events();
-
- //load avatar img
- var user_avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid);
- this.$('img.oe_mail_icon').attr('src', user_avatar);
},
/* upload the file on the server, add in the attachments list and reload display
@@ -164,15 +161,18 @@ openerp.mail = function(session) {
var self = this;
var render = $(session.web.qweb.render('mail.thread.message.attachments', {'widget': self}));
if(!this.list_attachment){
- this.$('.oe_mail_compose_attachment_list').replaceWith( render );
+ this.$('.oe_msg_attachment_list').replaceWith( render );
} else {
this.list_attachment.replaceWith( render );
}
- this.list_attachment = this.$("ul.oe_mail_msg_attachments");
+ this.list_attachment = this.$(".oe_msg_attachments");
// event: delete an attachment
this.$el.on('click', '.oe_mail_attachment_delete', self.on_attachment_delete);
},
+
+ /* when a user click on the upload button, send file read on_attachment_loaded
+ */
on_attachment_change: function (event) {
event.stopPropagation();
var self = this;
@@ -183,26 +183,25 @@ openerp.mail = function(session) {
// if the files exits for this answer, delete the file before upload
var attachments=[];
- for(var i in this.attachment_ids){
- if((this.attachment_ids[i].filename || this.attachment_ids[i].name) == filename){
- if(this.attachment_ids[i].upload){
+ for(var i in this.datasets.attachment_ids){
+ if((this.datasets.attachment_ids[i].filename || this.datasets.attachment_ids[i].name) == filename){
+ if(this.datasets.attachment_ids[i].upload){
return false;
}
- this.ds_attachment.unlink([this.attachment_ids[i].id]);
+ this.ds_attachment.unlink([this.datasets.attachment_ids[i].id]);
} else {
- attachments.push(this.attachment_ids[i]);
+ attachments.push(this.datasets.attachment_ids[i]);
}
}
- this.attachment_ids = attachments;
+ this.datasets.attachment_ids = attachments;
// submit file
//session.web.blockUI();
self.$('form.oe_form_binary_form').submit();
- //self.submit_ajax_attachment();
this.$(".oe_attachment_file").hide();
- this.attachment_ids.push({
+ this.datasets.attachment_ids.push({
'id': 0,
'name': filename,
'filename': filename,
@@ -213,57 +212,13 @@ openerp.mail = function(session) {
}
},
- submit_ajax_attachment: function(){
- var self=this;
- var $form = self.$('form.oe_form_binary_form');
- var filename = this.$('input.oe_form_binary_file').val().replace(/.*[\\\/]/,'');
-
- // create form data
- var fomdata = new FormData();
- $.each($form.find('input'), function(i, field) {
- var $field=$(field);
- if($field.attr('type')!='file'){
- fomdata.append($field.attr('name'), $field.val());
- } else {
- fomdata.append($field.attr('name'), field.files[0]);
- }
- });
-
- var progress=function(event) {
- self.$("span[name='"+filename+"'] div:lt("+Math.floor(event.loaded / event.total*5)+")").show();
- };
-
- $.ajax({
- url: $form.attr("action"),
- data: fomdata,
- cache: false,
- contentType: false,
- processData: false,
- type: 'POST',
- enctype: 'multipart/form-data',
- xhr: function() {
- // custom xhr
- myXhr = $.ajaxSettings.xhr();
- if(myXhr.upload){
- // for handling the progress of the upload
- myXhr.upload.addEventListener('progress', progress, false);
- }
- myXhr.addEventListener('progress', progress, false);
- return myXhr;
- },
- success: function(data){
- $iframe=$('').html(data);
- $iframe.appendTo(self.$el);
- $iframe.remove();
- }
- });
- },
-
+ /* when the file is uploaded
+ */
on_attachment_loaded: function (event, result) {
//session.web.unblockUI();
- for(var i in this.attachment_ids){
- if(this.attachment_ids[i].filename == result.filename && this.attachment_ids[i].upload){
- this.attachment_ids[i]={
+ for(var i in this.datasets.attachment_ids){
+ if(this.datasets.attachment_ids[i].filename == result.filename && this.datasets.attachment_ids[i].upload) {
+ this.datasets.attachment_ids[i]={
'id': result.id,
'name': result.name,
'filename': result.filename,
@@ -277,6 +232,7 @@ openerp.mail = function(session) {
$input.after($input.clone(true)).remove();
this.$(".oe_attachment_file").show();
},
+
/* unlink the file on the server and reload display
*/
on_attachment_delete: function (event) {
@@ -284,15 +240,15 @@ openerp.mail = function(session) {
var attachment_id=$(event.target).data("id");
if (attachment_id) {
var attachments=[];
- for(var i in this.attachment_ids){
- if(attachment_id!=this.attachment_ids[i].id){
- attachments.push(this.attachment_ids[i]);
+ for(var i in this.datasets.attachment_ids){
+ if(attachment_id!=this.datasets.attachment_ids[i].id){
+ attachments.push(this.datasets.attachment_ids[i]);
}
else {
this.ds_attachment.unlink([attachment_id]);
}
}
- this.attachment_ids = attachments;
+ this.datasets.attachment_ids = attachments;
this.display_attachments();
}
},
@@ -303,9 +259,9 @@ openerp.mail = function(session) {
set_free_attachments: function(){
var self=this;
this.parent_thread.ds_message.call('user_free_attachment').then(function(attachments){
- this.attachment_ids=[];
+ this.datasets.attachment_ids=[];
for(var i in attachments){
- self.attachment_ids[i]={
+ self.datasets.attachment_ids[i]={
'id': attachments[i].id,
'name': attachments[i].name,
'filename': attachments[i].filename,
@@ -324,13 +280,19 @@ openerp.mail = function(session) {
this.$el.on('click', 'a.oe_cancel', self.on_cancel );
this.$el.on('click', 'button.oe_post', function(){self.on_message_post()} );
this.$el.on('click', 'button.oe_full', function(){self.on_compose_fullmail()} );
+ self.$el.on('focus', 'textarea.oe_compact', self.on_compose_expandable);
},
on_compose_fullmail: function(){
var attachments=[];
- for(var i in this.attachment_ids){
- attachments.push(this.attachment_ids[i].id);
+ for(var i in this.datasets.attachment_ids){
+ attachments.push(this.datasets.attachment_ids[i].id);
}
+ var partner_ids=[];
+ for(var i in this.datasets.partner_ids){
+ partner_ids.push(this.datasets.partner_ids[i][0]);
+ }
+
var action = {
type: 'ir.actions.act_window',
res_model: 'mail.compose.message',
@@ -343,28 +305,28 @@ openerp.mail = function(session) {
'default_res_model': this.context.default_res_model,
'default_res_id': this.context.default_res_id,
'default_content_subtype': 'html',
- 'default_is_private': true,
- 'default_parent_id': this.id,
+ 'default_is_private': this.datasets.is_private,
+ 'default_parent_id': this.datasets.id,
'default_body': mail.ChatterUtils.get_text2html(this.$('textarea').val() || ''),
- 'default_attachment_ids': attachments
+ 'default_attachment_ids': attachments,
+ 'default_partner_ids': partner_ids
},
};
this.do_action(action);
},
- on_cancel: function(){
- event.stopPropagation();
+ on_cancel: function(event){
+ if(event) event.stopPropagation();
this.$('textarea').val("");
this.$('input[data-id]').remove();
//this.attachment_ids=[];
this.display_attachments();
- if(!this.options.thread.show_header_compose || !this.options.thread.display_on_flat){
- this.$el.hide();
- }
+ this.$el.hide();
},
/*post a message and fetch the message*/
on_message_post: function (body) {
+ var self = this;
if (! body) {
var comment_node = this.$('textarea');
@@ -373,12 +335,12 @@ openerp.mail = function(session) {
}
var attachments=[];
- for(var i in this.attachment_ids){
- if(this.attachment_ids[i].upload){
+ for(var i in this.datasets.attachment_ids){
+ if(this.datasets.attachment_ids[i].upload){
session.web.dialog($('
' + session.web.qweb.render('CrashManager.warning', {message: 'Please, wait while the file is uploading.'}) + '
'));
return false;
}
- attachments.push(this.attachment_ids[i].id);
+ attachments.push(this.datasets.attachment_ids[i].id);
}
if(body.match(/\S+/)) {
@@ -389,13 +351,33 @@ openerp.mail = function(session) {
'comment',
false,
this.context.default_parent_id,
- attachments]
- ).then(this.parent_thread.proxy('switch_new_message'));
- this.attachment_ids=[];
- this.on_cancel();
+ attachments,
+ _.extend(this.parent_thread.context, {'message_loaded':[this.datasets.id||0].concat( self.parent_thread.options.thread._parents[0].get_child_ids() )})]
+ ).then(function(records){
+ self.parent_thread.switch_new_message(records);
+ self.datasets.attachment_ids=[];
+ self.on_cancel();
+ });
return true;
}
},
+
+ /* convert the compact mode into the compose message
+ */
+ on_compose_expandable: function(){
+ var $render = $(session.web.qweb.render('mail.compose_message', {'widget': this}));
+ this.$el.replaceWith( $render );
+ this.$el = $render;
+ this.$('textarea').focus();
+ },
+
+ /* convert the compact mode into the compose message
+ */
+ on_compose_compact: function(){
+ var $render = $(session.web.qweb.render('mail.compose_message.compact', {'widget': this}));
+ this.$el.replaceWith( $render );
+ this.$el = $render;
+ },
});
/**
@@ -403,8 +385,7 @@ openerp.mail = function(session) {
* Thread Message Expandable Widget
* ------------------------------------------------------------
*
- * This widget handles the display the expandable message in a thread. The
- * [thread_level] parameter sets the thread level number:
+ * This widget handles the display the expandable message in a thread.
* - thread
* - - visible message
* - - expandable
@@ -420,13 +401,18 @@ openerp.mail = function(session) {
this.domain = options.domain || [];
this.context = _.extend({
default_model: 'mail.thread',
- default_res_id: 0,
+ default_res_id: 0,
default_parent_id: false }, options.context || {});
- this.id = options.parameters.id || -1;
- this.parent_id= options.parameters.parent_id || false;
- this.nb_messages = options.parameters.nb_messages || 0;
- this.type = 'expandable';
+ this.datasets = {
+ 'id' : options.datasets.id || -1,
+ 'model' : options.datasets.model || false,
+ 'parent_id' : options.datasets.parent_id || false,
+ 'nb_messages' : options.datasets.nb_messages || 0,
+ 'type' : 'expandable',
+ 'max_limit' : options.datasets.max_limit || false,
+ 'flag_used' : false,
+ };
// record options and data
this.parent_thread= parent.messages!= undefined ? parent : options.options.thread._parents[0] ;
@@ -443,8 +429,19 @@ openerp.mail = function(session) {
* in the function. */
bind_events: function() {
var self = this;
- // event: click on 'Vote' button
- this.$el.on('click', 'a.oe_mail_fetch_more', self.on_expandable);
+ this.$el.on('click', 'a.oe_msg_fetch_more', self.on_expandable);
+ },
+
+ animated_destroy: function(options) {
+ var self=this;
+ //graphic effects
+ if(options && options.fadeTime) {
+ self.$el.fadeOut(options.fadeTime, function(){
+ self.destroy();
+ });
+ } else {
+ self.destroy();
+ }
},
/*The selected thread and all childs (messages/thread) became read
@@ -452,8 +449,13 @@ openerp.mail = function(session) {
*/
on_expandable: function (event) {
if(event)event.stopPropagation();
+ if(this.datasets.flag_used) {
+ return false
+ }
+ this.datasets.flag_used = true;
+
+ this.animated_destroy({'fadeTime':300});
this.parent_thread.message_fetch(false, this.domain, this.context);
- this.destroy();
return false;
},
});
@@ -468,7 +470,7 @@ openerp.mail = function(session) {
* - record.timerelative: relative time givein by timeago lib
* - record.avatar: image url
* - record.attachment_ids[].url: url of each attachmentThe
- * [thread_level] parameter sets the thread level number:
+ * thread view :
* - root thread
* - - sub message (parent_id = root message)
* - - - sub thread
@@ -495,81 +497,91 @@ openerp.mail = function(session) {
* display before having a "show more" link; note that the text
* will not be truncated if it does not have 110% of the parameter
* @param {Boolean} [show_record_name]
- * @param {Boolean} [show_dd_delete]
- * @param {Boolean} [show_dd_hide]
+ * @param {Array [A,B]} [show_reply] display the reply button on the
+ * message for thread level between A and B. -1 for no begin or no end.
+ * @param {Array [A,B]} [show_read_unread] display the read/unread button on the
+ * message for thread level between A and B. -1 for no begin or no end.
*/
init: function(parent, options) {
this._super(parent);
- // record parameters
- var param = options.parameters;
- for(var i in param){ //FIXME
- this[i] = param[i];
- }
- this.id = param.id || -1;
- this.model = param.model || false;
- this.parent_id= param.parent_id || false;
- this.res_id = param.res_id || false;
- this.type = param.type || false;
- this.is_author = param.is_author || false;
- this.subject = param.subject || false;
- this.name = param.name || false;
- this.record_name = param.record_name || false;
- this.body = param.body || false;
- this.vote_user_ids =param.vote_user_ids || [];
- this.has_voted = param.has_voted || false;
-
- this.vote_user_ids = param.vote_user_ids || [];
-
- this.unread = param.unread || false;
- this._date = param.date;
- this.author_id = param.author_id || [];
- this.attachment_ids = param.attachment_ids || [];
+ // record datasets
+ var param = options.datasets;
+ this.datasets = _.extend({
+ 'id' : -1,
+ 'model' : false,
+ 'parent_id': false,
+ 'res_id' : false,
+ 'type' : false,
+ 'is_author' : false,
+ 'is_private' : false,
+ 'subject' : false,
+ 'name' : false,
+ 'record_name' : false,
+ 'body' : false,
+ 'vote_user_ids' :[],
+ 'has_voted' : false,
+ 'has_stared' : false,
+ 'thread_level' : 0,
+ 'to_read' : true,
+ 'author_id' : [],
+ 'attachment_ids' : [],
+ }, param || {});
+ this.datasets._date = param.date;
// record domain and context
this.domain = options.domain || [];
this.context = _.extend({
default_model: 'mail.thread',
- default_res_id: 0,
+ default_res_id: 0,
default_parent_id: false }, options.context || {});
// record options
this.options={
'thread' : options.options.thread,
'message' : {
- 'message_ids': options.options.message.message_ids || null,
- 'message_data': options.options.message.message_data || null,
- 'show_record_name': options.options.message.show_record_name != undefined ? options.options.message.show_record_name: true,
- 'show_dd_delete': options.options.message.show_dd_delete || false,
- 'show_dd_hide': options.options.message.show_dd_hide || false,
- 'truncate_limit': options.options.message.truncate_limit || 250,
+ 'message_ids': options.options.message.message_ids || null,
+ 'message_data': options.options.message.message_data || null,
+ 'show_record_name': options.options.message.show_record_name != undefined ? options.options.message.show_record_name: true,
+ 'truncate_limit': options.options.message.truncate_limit || 250,
+ 'show_reply': options.options.message.show_reply || [0,-1],
+ 'show_read_unread': options.options.message.show_read_unread || [0,-1],
}
};
+ this.datasets.show_reply = this.options.message.show_reply[0]>=0 &&
+ this.options.message.show_reply[0]<=this.datasets.thread_level &&
+ (this.options.message.show_reply[1]<0 || this.options.message.show_reply[1]>=this.datasets.thread_level);
+
+ this.datasets.show_read_unread = this.options.message.show_read_unread[0]>=0 &&
+ this.options.message.show_read_unread[0]<=this.datasets.thread_level &&
+ (this.options.message.show_read_unread[1]<0 || this.options.message.show_read_unread[1]>=this.datasets.thread_level);
+
// record options and data
this.parent_thread= parent.messages!= undefined ? parent : options.options.thread._parents[0];
this.thread = false;
- if( param.id > 0 ) {
+ if( this.datasets.id > 0 ) {
this.formating_data();
}
this.ds_notification = new session.web.DataSetSearch(this, 'mail.notification');
this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
+ this.ds_follow = new session.web.DataSetSearch(this, 'mail.followers');
},
formating_data: function(){
//formating and add some fields for render
- this.date = session.web.format_value(this._date, {type:"datetime"});
- this.timerelative = $.timeago(this.date);
- if (this.type == 'email') {
- this.avatar = ('/mail/static/src/img/email_icon.png');
+ this.datasets.date = session.web.format_value(this.datasets._date, {type:"datetime"});
+ this.datasets.timerelative = $.timeago(this.datasets.date);
+ if (this.datasets.type == 'email') {
+ this.datasets.avatar = ('/mail/static/src/img/email_icon.png');
} else {
- this.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.author_id[0]);
+ this.datasets.avatar = mail.ChatterUtils.get_image(this.session, 'res.partner', 'image_small', this.datasets.author_id[0]);
}
- for (var l in this.attachment_ids) {
- var attach = this.attachment_ids[l];
+ for (var l in this.datasets.attachment_ids) {
+ var attach = this.datasets.attachment_ids[l];
attach['url'] = mail.ChatterUtils.get_attachment_url(this.session, attach);
}
},
@@ -589,20 +601,22 @@ openerp.mail = function(session) {
var self = this;
// event: click on 'Attachment(s)' in msg
- this.$('a.oe_mail_msg_view_attachments:first').on('click', function (event) {
- self.$('.oe_mail_msg_attachments:first').toggle();
+ this.$('a.oe_msg_view_attachments:first').on('click', function (event) {
+ self.$('.oe_msg_attachments:first').toggle();
});
// event: click on icone 'Read' in header
this.$el.on('click', 'a.oe_read', this.on_message_read_unread);
// event: click on icone 'UnRead' in header
this.$el.on('click', 'a.oe_unread', this.on_message_read_unread);
// event: click on 'Delete' in msg side menu
- this.$el.on('click', 'a.oe_mail_msg_delete', this.on_message_delete);
+ this.$el.on('click', 'a.oe_msg_delete', this.on_message_delete);
// event: click on 'Reply' in msg
this.$el.on('click', 'a.oe_reply', this.on_message_reply);
// event: click on 'Vote' button
- this.$el.on('click', 'button.oe_mail_msg_vote', this.on_vote);
+ this.$el.on('click', 'button.oe_msg_vote', this.on_vote);
+ // event: click on 'Star' button
+ this.$el.on('click', 'button.oe_mail_starbox', this.on_star);
},
on_message_reply:function(event){
@@ -612,11 +626,11 @@ openerp.mail = function(session) {
},
expender: function(){
- this.$('div.oe_mail_msg_body:first').expander({
+ this.$('.oe_msg_body:first').expander({
slicePoint: this.options.truncate_limit,
expandText: 'read more',
userCollapseText: '[^]',
- detailClass: 'oe_mail_msg_tail',
+ detailClass: 'oe_msg_tail',
moreClass: 'oe_mail_expand',
lessClass: 'oe_mail_reduce',
});
@@ -627,24 +641,24 @@ openerp.mail = function(session) {
if(this.thread){
return false;
}
- var param = _.extend(self, {'parent_id': self.id});
+
/*create thread*/
self.thread = new mail.Thread(self, {
'domain': self.domain,
'context':{
- 'default_model': self.model,
- 'default_res_id': self.res_id,
- 'default_parent_id': self.id
+ 'default_model': self.datasets.model,
+ 'default_res_id': self.datasets.res_id,
+ 'default_parent_id': self.datasets.id
},
'options': {
- 'thread' : self.options.thread,
+ 'thread' : self.options.thread,
'message' : self.options.message
},
- 'parameters': param
+ 'datasets': self.datasets
}
);
/*insert thread in parent message*/
- self.thread.replace(self.$('.oe_thread_placeholder'));
+ self.thread.insertAfter(self.$el);
},
animated_destroy: function(options) {
@@ -665,7 +679,7 @@ openerp.mail = function(session) {
this.animated_destroy({fadeTime:250});
// delete this message and his childs
- var ids = [this.id].concat( this.get_child_ids() );
+ var ids = [this.datasets.id].concat( this.get_child_ids() );
this.ds_message.unlink(ids);
this.animated_destroy();
return false;
@@ -676,17 +690,17 @@ openerp.mail = function(session) {
*/
on_message_read_unread: function (event) {
event.stopPropagation();
- if($(event.srcElement).hasClass("oe_read")) this.animated_destroy({fadeTime:250});
// if this message is read, all childs message display is read
- var ids = [this.id].concat( this.get_child_ids() );
-
- if($(event.srcElement).hasClass("oe_read")) {
- this.ds_notification.call('set_message_read', [ids,true]);
- this.$el.removeClass("oe_mail_unread").addClass("oe_mail_read");
- } else {
- this.ds_notification.call('set_message_read', [ids,false]);
- this.$el.removeClass("oe_mail_read").addClass("oe_mail_unread");
+ var ids = [this.datasets.id].concat( this.get_child_ids() );
+ var read = $(event.srcElement).hasClass("oe_read");
+ this.$el.removeClass("oe_mail_" + (read?"un":"") + "read").addClass("oe_mail_" + (read?"":"un") + "read");
+
+ if( (read && this.options.thread.typeof_thread == 'inbox') ||
+ (!read && this.options.thread.typeof_thread == 'archives')) {
+ this.animated_destroy({fadeTime:250});
}
+
+ this.ds_notification.call('set_message_read', [ids,read]);
return false;
},
@@ -707,7 +721,7 @@ openerp.mail = function(session) {
}
}
- if(this.id==options.id)
+ if(this.datasets.id==options.id)
return this;
for(var i in this.thread.messages){
@@ -724,30 +738,29 @@ openerp.mail = function(session) {
*/
get_child_ids: function(){
var res=[]
- if(arguments[0]) res.push(this.id);
+ if(arguments[0]) res.push(this.datasets.id);
if(this.thread){
res = res.concat( this.thread.get_child_ids(true) );
}
return res;
},
-
on_vote: function (event) {
event.stopPropagation();
var self=this;
- return this.ds_message.call('vote_toggle', [[self.id]]).pipe(function(vote){
+ return this.ds_message.call('vote_toggle', [[self.datasets.id]]).pipe(function(vote){
- self.has_voted=vote;
- if (!self.has_voted) {
+ self.datasets.has_voted=vote;
+ if (!self.datasets.has_voted) {
var votes=[];
- for(var i in self.vote_user_ids){
- if(self.vote_user_ids[i][0]!=self.session.uid)
- vote.push(self.vote_user_ids[i]);
+ for(var i in self.datasets.vote_user_ids){
+ if(self.datasets.vote_user_ids[i][0]!=self.session.uid)
+ vote.push(self.datasets.vote_user_ids[i]);
}
- self.vote_user_ids=votes;
+ self.datasets.vote_user_ids=votes;
}
else {
- self.vote_user_ids.push([self.session.uid, 'You']);
+ self.datasets.vote_user_ids.push([self.session.uid, 'You']);
}
self.display_vote();
});
@@ -761,6 +774,26 @@ openerp.mail = function(session) {
self.$(".placeholder-mail-vote:first").empty();
self.$(".placeholder-mail-vote:first").html(vote_element);
},
+
+ // Stared/unstared + Render star.
+ on_star: function (event) {
+ event.stopPropagation();
+ var self=this;
+ var button = self.$('button.oe_mail_starbox:first');
+ return this.ds_message.call('star_toggle', [[self.datasets.id]]).pipe(function(star){
+ self.datasets.has_stared=star;
+ if(self.datasets.has_stared){
+ button.addClass('oe_stared');
+ } else {
+ button.removeClass('oe_stared');
+ if( self.options.thread.typeof_thread == 'stared' ) {
+ self.animated_destroy({fadeTime:250});
+ }
+ }
+ });
+ return false;
+ },
+
});
/**
@@ -769,11 +802,13 @@ openerp.mail = function(session) {
* ------------------------------------------------------------
*
* This widget handles the display of a thread of messages. The
- * [thread_level] parameter sets the thread level number:
- * - root message
+ * thread view:
+ * - root thread
* - - sub message (parent_id = root message)
- * - - - sub sub message (parent id = sub message)
+ * - - - sub thread
+ * - - - - sub sub message (parent id = sub thread)
* - - sub message (parent_id = root message)
+ * - - - sub thread
*/
mail.Thread = session.web.Widget.extend({
template: 'mail.thread',
@@ -787,15 +822,17 @@ openerp.mail = function(session) {
* @param {Object} [options]
* @param {Object} [message] read about mail.ThreadMessage object
* @param {Object} [thread]
- * @param {Number} [thread_level=0] number of thread levels
- * @param {Boolean} [use_composer] use the advanced composer, or
- * the default basic textarea if not set
* @param {Number} [expandable_number=5] number message show
* for each click on "show more message"
* @param {Number} [expandable_default_number=5] number message show
* on begin before the first click on "show more message"
- * @param {Boolean} [display_on_flat] display all thread
- * on the wall thread level (no hierarchy)
+ * @param {Array [A,B]} [display_on_thread] display the threads (hierarchy)
+ * for the thread level between A and B. -1 for no begin or no end.
+ * All thread before A are insert in the root thread.
+ * All thread after B are insert in parent thread on B level.
+ * @param {Select} [typeof_thread] inbox/archives/stared/sent
+ * type of thread and option for user application like animate
+ * destroy for read/unread
* @param {Array} [parents] liked with the parents thread
* use with browse, fetch... [O]= top parent
*/
@@ -804,101 +841,70 @@ openerp.mail = function(session) {
this.domain = options.domain || [];
this.context = _.extend({
default_model: 'mail.thread',
- default_res_id: 0,
+ default_res_id: 0,
default_parent_id: false }, options.context || {});
// options
this.options={
'thread' : {
- 'thread_level': options.options.thread.thread_level || 0,
- 'show_header_compose': (options.options.thread.show_header_compose != undefined ? options.options.thread.show_header_compose: false),
- 'use_composer': options.options.thread.use_composer || false,
- 'expandable_number': options.options.thread.expandable_number || 5,
+ 'expandable_number': options.options.thread.expandable_number || 5,
'expandable_default_number': options.options.thread.expandable_default_number || 5,
- '_expandable_max': options.options.thread.expandable_default_number || 5,
- 'display_on_flat': options.options.thread.display_on_flat || false,
- '_parents': (options.options.thread._parents != undefined ? options.options.thread._parents : []).concat( [this] )
+ '_expandable_max': options.options.thread.expandable_default_number || 5,
+ 'display_on_thread': options.options.thread.display_on_thread || [0,-1],
+ 'typeof_thread': options.options.thread.typeof_thread || 'inbox',
+ '_parents': (options.options.thread._parents != undefined ? options.options.thread._parents : []).concat( [this] )
},
'message' : options.options.message
};
// record options and data
- this.parent_linked_message= parent.thread!= undefined ? parent : false ;
+ this.parent_message= parent.thread!= undefined ? parent : false ;
- var param = options.parameters
+ var param = options.datasets
// datasets and internal vars
- this.id= param.id || false;
- this.model= param.model || false;
- this.parent_id= param.parent_id || false;
- this.is_private = param.is_private || false;
- this.author_id = param.author_id || false;
- this.partner_ids = [];
+ this.datasets = {
+ 'id' : param.id || false,
+ 'model' : param.model || false,
+ 'parent_id' : param.parent_id || false,
+ 'is_private' : param.is_private || false,
+ 'author_id' : param.author_id || false,
+ 'thread_level' : (param.thread_level+1) || 0,
+ 'partner_ids' : []
+ };
+
for(var i in param.partner_ids){
if(param.partner_ids[i][0]!=(param.author_id ? param.author_id[0] : -1)){
- this.partner_ids.push(param.partner_ids[i]);
+ this.datasets.partner_ids.push(param.partner_ids[i]);
}
}
this.messages = [];
+ this.ComposeMessage = false;
- this.ds_thread = new session.web.DataSetSearch(this, this.context.default_model);
+ this.ds_thread = new session.web.DataSetSearch(this, this.context.default_model || 'mail.thread');
this.ds_message = new session.web.DataSetSearch(this, 'mail.message');
},
start: function() {
- // TDE TODO: check for deferred, not sure it is correct
this._super.apply(this, arguments);
-
- this.list_ul=this.$('ul.oe_mail_thread_display:first');
- this.more_msg=this.$(">.oe_mail_msg_more_message:first");
-
- this.display_user_avatar();
- var display_done = compose_done = false;
-
this.instantiate_ComposeMessage();
-
this.bind_events();
-
- if(this.options.thread._parents[0]==this){
- this.on_first_thread();
- }
-
- return display_done && compose_done;
},
instantiate_ComposeMessage: function(){
- // add message composition form view
this.ComposeMessage = new mail.ThreadComposeMessage(this,{
'context': this.context,
- 'parameters': this,
+ 'datasets': this.datasets,
+ 'options': this.options,
'show_attachment_delete': true,
});
- this.ComposeMessage.appendTo(this.$(".oe_mail_thread_action:first"));
- },
- /* this method is runing for first parent thread
- */
- on_first_thread: function(){
- var self=this;
- // fetch and display message, using message_ids if set
- this.message_fetch();
-
- $(document).scroll( self.on_scroll );
- window.setTimeout( self.on_scroll, 500 );
-
- $(session.web.qweb.render('mail.wall_no_message', {})).appendTo(this.$('ul.oe_mail_thread_display'));
-
- if(this.options.thread.show_header_compose){
- this.ComposeMessage.$el.show();
- this.ComposeMessage.set_free_attachments();
+ if(this.datasets.thread_level){
+ this.ComposeMessage.appendTo(this.$el);
+ } else {
+ // root view
+ this.ComposeMessage.prependTo(this.$el);
}
-
- var button_fetch = $('').click(function(event){
- if(event)event.stopPropagation();
- self.message_fetch();
- });
- this.$el.prepend(button_fetch);
- this.$el.addClass("oe_mail_wall_first_thread");
},
/* When the expandable object is visible on screen (with scrolling)
@@ -906,16 +912,17 @@ openerp.mail = function(session) {
*/
on_scroll: function(event){
if(event)event.stopPropagation();
- var last=this.messages[0];
- if(last && last.type=="expandable"){
- var pos = last.$el.position();
+ var message = this.messages[0];
+ if(message && message.datasets.type=="expandable" && message.datasets.max_limit){
+ var pos = message.$el.position();
if(pos.top){
/* bottom of the screen */
- var bottom = $(window).scrollTop()+$(window).height()+100;
+ var bottom = $(window).scrollTop()+$(window).height()+200;
if(bottom - pos.top > 0){
- last.on_expandable();
+ message.on_expandable();
}
}
+
}
},
@@ -924,18 +931,41 @@ openerp.mail = function(session) {
* in the function. */
bind_events: function() {
var self = this;
- self.$('.oe_mail_compose_textarea .oe_more').click(function () { var p=$(this).parent(); p.find('.oe_more_hidden, .oe_hidden').show(); p.find('.oe_more').hide(); });
- self.$('.oe_mail_compose_textarea .oe_more_hidden').click(function () { var p=$(this).parent(); p.find('.oe_more_hidden, .oe_hidden').hide(); p.find('.oe_more').show(); });
+ self.$el.on('click', '.oe_mail_list_recipients .oe_more', self.on_show_recipients);
+ self.$el.on('click', '.oe_mail_compose_textarea .oe_more_hidden', self.on_hide_recipients);
+ },
+
+ on_show_recipients: function(){
+ var p=$(this).parent();
+ p.find('.oe_more_hidden, .oe_hidden').show();
+ p.find('.oe_more').hide();
+ },
+
+ on_hide_recipients: function(){
+ var p=$(this).parent();
+ p.find('.oe_more_hidden, .oe_hidden').hide();
+ p.find('.oe_more').show();
},
/* get all child message/thread id linked
*/
get_child_ids: function(){
var res=[];
- for(var i in this.messages){
- if(this.messages[i].thread){
- res = res.concat( this.messages[i].get_child_ids(true) );
- }
+ _(this.get_childs()).each(function (val, key) { res.push(val.datasets.id); });
+ return res;
+ },
+
+ /* get all child message/thread linked
+ */
+ get_childs: function(nb_thread_level){
+ var res=[];
+ if(arguments[1]) res.push(this);
+ if(isNaN(nb_thread_level) || nb_thread_level>0){
+ _(this.messages).each(function (val, key) {
+ if(val.thread){
+ res = res.concat( val.thread.get_childs((isNaN(nb_thread_level) ? null : nb_thread_level-1), true) )
+ }
+ });
}
return res;
},
@@ -956,7 +986,7 @@ openerp.mail = function(session) {
return this.options.thread._parents[0].browse_thread(options);
}
- if(this.id==options.id){
+ if(this.datasets.id==options.id){
return this;
}
@@ -991,8 +1021,13 @@ openerp.mail = function(session) {
/* this function is launch when a user click on "Reply" button
*/
on_compose_message: function(){
- this.ComposeMessage.$el.toggle();
- return false;
+ this.ComposeMessage.on_compose_expandable();
+ },
+
+ /* display the no message on the thread
+ */
+ no_message: function(){
+ $(session.web.qweb.render('mail.wall_no_message', {})).appendTo(this.$el);
},
/** Fetch messages
@@ -1002,7 +1037,7 @@ openerp.mail = function(session) {
* @param {Array} replace_domain: added to this.domain
* @param {Object} replace_context: added to this.context
*/
- message_fetch: function (initial_mode, replace_domain, replace_context, ids) {
+ message_fetch: function (initial_mode, replace_domain, replace_context, ids, callback) {
var self = this;
// initial mode: try to use message_data or message_ids
@@ -1012,91 +1047,135 @@ openerp.mail = function(session) {
// domain and context: options + additional
fetch_domain = replace_domain ? replace_domain : this.domain;
fetch_context = replace_context ? replace_context : this.context;
- fetch_context.message_loaded= [this.id||0].concat( self.options.thread._parents[0].get_child_ids() );
+ fetch_context.message_loaded= [this.datasets.id||0].concat( self.options.thread._parents[0].get_child_ids() );
- return this.ds_message.call('message_read', [ids, fetch_domain, (this.options.thread.thread_level+1), fetch_context, this.context.default_parent_id || undefined]
- ).then(this.proxy('switch_new_message'));
+ return this.ds_message.call('message_read', [ids, fetch_domain, 0, fetch_context, this.context.default_parent_id || undefined]
+ ).then(function (records) { self.switch_new_message(records); });
},
/* create record object and linked him
*/
- create_message_object: function (message) {
+ create_message_object: function (data) {
var self = this;
+ if(data.type=='expandable'){
+ var message = new mail.ThreadExpandable(self, {
+ 'domain': data.domain,
+ 'context': {
+ 'default_model': data.model || self.context.default_model,
+ 'default_res_id': data.res_id || self.context.default_res_id,
+ 'default_parent_id': self.datasets.id },
+ 'datasets': data
+ });
+ } else {
+ var message = new mail.ThreadMessage(self, {
+ 'domain': data.domain,
+ 'context': {
+ 'default_model': data.model,
+ 'default_res_id': data.res_id,
+ 'default_parent_id': data.id },
+ 'options':{
+ 'thread': self.options.thread,
+ 'message': self.options.message
+ },
+ 'datasets': _.extend(data, {'thread_level': self.datasets.thread_level})
+ });
+ var data = _.extend(data, {'thread_level': self.datasets.thread_level});
+ }
+
// check if the message is already create
- for(var i in this.messages){
- if(this.messages[i].id==message.id){
- this.messages[i].destroy();
- this.messages[i]=self.insert_message(message);
+ for(var i in self.messages){
+ if(self.messages[i].datasets.id == message.datasets.id){
+ self.messages[i].destroy();
+ self.messages[i] = self.insert_message(message);
return true;
}
}
-
self.messages.push( self.insert_message(message) );
-
},
/** Displays a message or an expandable message */
insert_message: function (message) {
var self=this;
- this.$("li.oe_wall_no_message").remove();
+ this.$('.oe_wall_no_message').remove();
- if(message.type=='expandable'){
- var message = new mail.ThreadExpandable(self, {
- 'domain': message.domain,
- 'context': {
- 'default_model': message.model,
- 'default_res_id': message.res_id,
- 'default_parent_id': message.id },
- 'parameters': message
- });
- } else {
- var message = new mail.ThreadMessage(self, { //FIXME
- 'domain': message.domain,
- 'context': {
- 'default_model': message.model,
- 'default_res_id': message.res_id,
- 'default_parent_id': message.id },
- 'options':{
- 'thread': self.options.thread,
- 'message': self.options.message
- },
- 'parameters': message
- });
+ // insert on hierarchy display => insert in self child
+ var thread_messages = self.messages;
+ var thread = self;
+ var flat = false;
+ var hierarchy = self.options.thread.display_on_thread;
+ if( hierarchy[0] < 0 ||
+ hierarchy[0] > self.datasets.thread_level ||
+ (hierarchy[1]>0 && hierarchy[1] < self.datasets.thread_level) ) {
+
+ var flat = true;
+
+ if(hierarchy[0]<0){
+
+ // all is in flat mode
+ thread = self.options.thread._parents[0];
+ var nb_thread_level = null;
+
+ } else if(hierarchy[0] > self.datasets.thread_level) {
+
+ // list all childs messages for flat display before the hierarchy
+ thread = self.options.thread._parents[0];
+ var nb_thread_level = hierarchy[0];
+
+ } else if(hierarchy[1] < self.datasets.thread_level) {
+
+ // list all childs messages for flat display after the hierarchy
+ thread = self.options.thread._parents[hierarchy[1]];
+ var nb_thread_level = hierarchy[1]>0 ? hierarchy[1]-hierarchy[0] : null;
+ } else {
+
+ thread = self.options.thread._parents[0];
+ var nb_thread_level = null;
+ }
+
+ var thread_messages = [];
+ _(thread.get_childs( nb_thread_level )).each(function (val, key) { thread_messages.push(val.parent_message); });
}
- var thread_messages = (self.options.thread.display_on_flat ? self.options.thread._parents[0].messages : []).concat(self.messages);
- var thread = (self.options.thread.display_on_flat ? self.options.thread._parents[0] : self);
-
// check older and newer message for insert
var parent_newer = false;
var parent_older = false;
- for(var i in thread_messages){
- if(thread_messages[i].id > message.id){
- if(!parent_newer || parent_newer.id>=thread_messages[i].id)
- parent_newer = thread_messages[i];
- } else if(thread_messages[i].id>0 && thread_messages[i].id < message.id) {
- if(!parent_older || parent_older.id 0 ){
+ for(var i in thread_messages){
+ if(thread_messages[i].datasets.id > message.datasets.id){
+ if(!parent_newer || parent_newer.datasets.id>=thread_messages[i].datasets.id)
+ parent_newer = thread_messages[i];
+ } else if(thread_messages[i].datasets.id>0 && thread_messages[i].datasets.id < message.datasets.id) {
+ if(!parent_older || parent_older.id=1);
- display_user_avatar: function () {
- var avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid);
- return this.$('img.oe_mail_icon').attr('src', avatar);
+ if(parent_older){
+ if(sort){
+ message.insertBefore(parent_older.$el);
+ } else {
+ message.insertAfter(parent_older.thread ? parent_older.thread.$el : parent_older.$el);
+ }
+ } else if(parent_newer){
+ if(sort){
+ message.insertAfter(parent_newer.thread ? parent_newer.thread.$el : parent_newer.$el);
+ } else {
+ message.insertBefore(parent_newer.$el);
+ }
+ } else {
+ if(sort && message.id > 0){
+ message.prependTo(thread.$el);
+ } else {
+ message.appendTo(thread.$el);
+ }
+ }
+
+ return message
},
/* Send the records to his parent thread */
@@ -1111,6 +1190,92 @@ openerp.mail = function(session) {
},
});
+ /**
+ * ------------------------------------------------------------
+ * mail : root Widget
+ * ------------------------------------------------------------
+ *
+ * This widget handles the display of messages with thread options. Its main
+ * use is to receive a context and a domain, and to delegate the message
+ * fetching and displaying to the Thread widget.
+ */
+ session.web.client_actions.add('mail.Widget', 'session.mail.Widget');
+ mail.Widget = session.web.Widget.extend({
+ template: 'mail.Widget',
+
+ /**
+ * @param {Object} parent parent
+ * @param {Array} [domain]
+ * @param {Object} [context] context of the thread. It should
+ * contain at least default_model, default_res_id. Please refer to
+ * the ComposeMessage widget for more information about it.
+ * ... @param {Select} [typeof_thread=(mail|stared|archives|send|other)]
+ * options for destroy message when the user click on a button
+ * @param {Object} [options]
+ *... @param {Number} [truncate_limit=250] number of character to
+ * display before having a "show more" link; note that the text
+ * will not be truncated if it does not have 110% of the parameter
+ *... @param {Boolean} [show_record_name] display the name and link for do action
+ *... @param {Array [A,B]} [show_reply] display the reply button on the
+ * message for thread level between A and B. -1 for no begin or no end.
+ *... @param {Array [A,B]} [show_read_unread] display the read/unread button on the
+ * message for thread level between A and B. -1 for no begin or no end.
+ *... @param {Array [A,B]} [display_on_thread] display the threads (hierarchy)
+ * for the thread level between A and B. -1 for no begin or no end.
+ * All thread before A are insert in the root thread.
+ * All thread after B are insert in parent thread on B level.
+ */
+ init: function (parent, options) {
+ this._super(parent);
+ this.options = options || {};
+ this.options.domain = options.domain || [];
+ this.options.context = options.context || {};
+ this.search_results = {'domain': [], 'context': {}, 'groupby': {}};
+ },
+
+ start: function (options) {
+ this._super.apply(this, arguments);
+ this.message_render();
+ this.bind_events();
+ },
+
+ /**
+ * Display the threads
+ */
+ message_render: function (search) {
+ this.thread = new mail.Thread(this, {
+ 'domain' : this.options.domain,
+ 'context' : this.options.context,
+ 'options': {
+ 'thread' :{
+ 'typeof_thread': this.options.typeof_thread || 'inbox',
+ 'display_on_thread': this.options.display_on_thread || [0,1]
+ },
+ 'message': {
+ 'show_reply': this.options.show_reply || [0,0],
+ 'show_read_unread': this.options.show_read_unread || [0,-1],
+ 'truncate_limit': this.options.truncate_limit || 250,
+ 'show_record_name': this.options.show_record_name || false,
+ },
+ },
+ 'datasets': {},
+ }
+ );
+
+ this.thread.appendTo( this.$el );
+ this.thread.no_message();
+ this.thread.message_fetch();
+ },
+
+ bind_events: function(){
+ if(this.options.context.typeof_thread!='other'){
+ $(document).scroll( this.thread.on_scroll );
+ $(window).resize( this.thread.on_scroll );
+ window.setTimeout( this.thread.on_scroll, 500 );
+ }
+ }
+ });
+
/**
* ------------------------------------------------------------
@@ -1129,7 +1294,6 @@ openerp.mail = function(session) {
this._super.apply(this, arguments);
this.options.domain = this.options.domain || [];
this.options.context = {'default_model': 'mail.thread', 'default_res_id': false};
- this.options.thread_level = this.options.thread_level || 0;
},
start: function() {
@@ -1142,14 +1306,7 @@ openerp.mail = function(session) {
_check_visibility: function() {
this.$el.toggle(this.view.get("actual_mode") !== "create");
},
-
- /**
- * Reinitialize the widget field and Display the threads
- * @param {Object} new_context: context of the refresh
- */
- set_value: function() {
- var self = this;
- this._super.apply(this, arguments);
+ render_value: function() {
if (! this.view.datarecord.id || session.web.BufferedDataSet.virtual_id_regex.test(this.view.datarecord.id)) {
this.$('oe_mail_thread').hide();
return;
@@ -1157,33 +1314,24 @@ openerp.mail = function(session) {
// update context
_.extend(this.options.context, {
default_res_id: this.view.datarecord.id,
- default_model: this.view.model });
+ default_model: this.view.model,
+ default_is_private: false });
// update domain
var domain = this.options.domain.concat([['model', '=', this.view.model], ['res_id', '=', this.view.datarecord.id]]);
- // create and render Thread widget
- var show_header_compose = this.view.is_action_enabled('edit') ||
- (this.getParent().fields.message_is_follower && this.getParent().fields.message_is_follower.get_value());
-
+
if(this.thread){
this.thread.destroy();
}
this.thread = new mail.Thread(self, {
'domain': domain,
'context': this.options.context,
- 'options':{
- 'thread':{
- 'thread_level': this.options.thread_level,
- 'show_header_compose': show_header_compose,
- 'use_composer': show_header_compose,
- 'display_on_flat':true
- },
- 'message':{
- 'show_dd_delete': true
- }
- },
- 'parameters': {},
+ 'typeof_thread': this.options.context.typeof_thread || 'other',
+ 'display_on_thread':[-1,-1],
+ 'show_reply': [-1,-1],
+ 'show_read_unread': [-1,-1],
}
);
+
return this.thread.appendTo( this.$('.oe_mail_wall_threads:first') );
},
});
@@ -1216,7 +1364,6 @@ openerp.mail = function(session) {
this.options = options || {};
this.options.domain = options.domain || [];
this.options.context = options.context || {};
- this.options.thread_level = options.thread_level || 1;
this.search_results = {'domain': [], 'context': {}, 'groupby': {}}
this.ds_msg = new session.web.DataSetSearch(this, 'mail.message');
},
@@ -1227,7 +1374,7 @@ openerp.mail = function(session) {
var thread_displayed = this.message_render();
this.options.domain = this.options.domain.concat(this.search_results['domain']);
this.bind_events();
- return (searchview_ready && thread_displayed); //FIXME
+ return $.when(searchview_ready, thread_displayed);
},
/**
@@ -1256,7 +1403,7 @@ openerp.mail = function(session) {
domains: domains || [],
contexts: contexts || [],
group_by_seq: groupbys || []
- }, function (results) {
+ }).then(function (results) {
self.search_results['context'] = results.context;
self.search_results['domain'] = results.domain;
self.thread.destroy();
@@ -1269,32 +1416,85 @@ openerp.mail = function(session) {
* Display the threads
*/
message_render: function (search) {
- this.thread = new mail.Thread(this, {
- 'domain' : this.options.domain.concat(this.search_results['domain']),
- 'context' : _.extend(this.options.context, search&&search.search_results['context'] ? search.search_results['context'] : {}),
- 'options': {
- 'thread' :{
- 'thread_level': this.options.thread_level,
- 'use_composer': true,
- 'show_header_compose': true,
- },
- 'message': {
- 'show_reply': this.options.thread_level > 0,
- 'show_dd_hide': true,
- 'show_dd_delete': true,
- },
- },
- 'parameters': {},
+ var domain = this.options.domain.concat(this.search_results['domain']);
+ var context = _.extend(this.options.context, search&&search.search_results['context'] ? search.search_results['context'] : {});
+ this.root = new mail.Widget(this, {
+ 'domain' : domain,
+ 'context' : context,
+ 'typeof_thread': context.typeof_thread || 'other',
+ 'display_on_thread': [0,1],
+ 'show_reply': [0,0],
+ 'show_read_unread': [0,-1],
}
);
- return this.thread.appendTo( this.$('.oe_mail_wall_threads:first') );
-
+ return this.root.appendTo( this.$('.oe_mail_wall_threads:first') );
},
bind_events: function(){
var self=this;
- this.$("button.oe_write_full:first").click(function(){ self.thread.ComposeMessage.on_compose_fullmail(); }); //FIXME
- this.$("button.oe_write_onwall:first").click(function(){ self.thread.ComposeMessage.$el.toggle(); });
+ this.$("button.oe_write_full:first").click(function(){ self.root.thread.ComposeMessage.on_compose_fullmail(); });
+ this.$("button.oe_write_onwall:first").click(function(){ self.root.thread.on_compose_message(); });
}
});
+
+
+ /**
+ * ------------------------------------------------------------
+ * UserMenu
+ * ------------------------------------------------------------
+ *
+ * add a link on the top user bar for write a full mail
+ */
+ session.web.ComposeMessageTopButton = session.web.Widget.extend({
+
+ template:'mail.compose_message.button_top_bar',
+
+ init: function (parent, options) {
+ this._super.apply(this, options);
+ this.options = this.options || {};
+ this.options.domain = this.options.domain || [];
+ this.options.context = {
+ 'default_res_id': 0,
+ 'default_model': 'mail.thread',
+ 'default_is_private': true,
+ 'default_res_model': false,
+ 'default_res_id': 0,
+ 'default_content_subtype': 'html',
+ 'default_is_private': true,
+ 'default_parent_id': 0
+ };
+ },
+
+ start: function(parent, params) {
+ var self = this;
+ this.$el.on('click', 'button', self.on_compose_message );
+ this._super(parent, params);
+ },
+
+ on_compose_message: function(event){
+ event.stopPropagation();
+ var action = {
+ type: 'ir.actions.act_window',
+ res_model: 'mail.compose.message',
+ view_mode: 'form',
+ view_type: 'form',
+ action_from: 'mail.ThreadComposeMessage',
+ views: [[false, 'form']],
+ target: 'new',
+ context: this.options.context,
+ };
+ session.client.action_manager.do_action(action);
+ },
+
+ });
+
+ session.web.UserMenu = session.web.UserMenu.extend({
+ start: function(parent, params) {
+ var render = new session.web.ComposeMessageTopButton();
+ render.insertAfter(this.$el);
+ this._super(parent, params);
+ }
+
+ });
+
};
diff --git a/addons/mail/static/src/js/mail_followers.js b/addons/mail/static/src/js/mail_followers.js
index ab6a63ea6fa..58b7e910cb8 100644
--- a/addons/mail/static/src/js/mail_followers.js
+++ b/addons/mail/static/src/js/mail_followers.js
@@ -40,6 +40,7 @@ openerp_mail_followers = function(session, mail) {
this._check_visibility();
this.reinit();
this.bind_events();
+ this.display_subtypes();
},
_check_visibility: function() {
@@ -53,31 +54,15 @@ openerp_mail_followers = function(session, mail) {
bind_events: function() {
var self = this;
- this.$('div.oe_mouse_subtypes')
- .on('mouseover', function () {
- $(this).removeClass('oe_mouseout').addClass('oe_mouseover');
- self.display_subtypes();
- })
- .on('mouseleave', function () {
- $(this).removeClass('oe_mouseover').addClass('oe_mouseout');
- self.display_subtypes();
- });
-
this.$('button.oe_follower')
.on('click', function () {
if($(this).hasClass('oe_notfollow'))
self.do_follow();
else
self.do_unfollow();
- })
- .on('mouseover', function () {
- $(this).removeClass('oe_mouseout').addClass('oe_mouseover');
- })
- .on('mouseleave', function () {
- $(this).removeClass('oe_mouseover').addClass('oe_mouseout');
});
- this.$el.on('click', 'ul.oe_subtypes input', function () { self.do_update_subscription(); })
+ this.$el.on('click', 'ul.oe_subtypes input', self.do_update_subscription );
this.$el.on('click', 'button.oe_invite', function(event) {
action = {
@@ -89,7 +74,7 @@ openerp_mail_followers = function(session, mail) {
target: 'new',
context: {
'default_res_model': self.view.dataset.model,
- 'default_res_id': self.view.datarecord.id
+ 'default_res_id': self.view.dataset.ids[0]
},
}
self.do_action(action, function() { self.read_value(); });
@@ -98,22 +83,23 @@ openerp_mail_followers = function(session, mail) {
read_value: function() {
var self = this;
- return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).pipe(function (results) {
+ return this.ds_model.read_ids([this.view.dataset.ids[0]], ['message_follower_ids']).pipe(function (results) {
self.set_value(results[0].message_follower_ids);
});
},
- set_value: function(value_) {
+ render_value: function() {
this.reinit();
- return this.fetch_followers(value_ || this.get_value());
+ return this.fetch_followers(this.get("value"));
},
set_is_follower: function(value_) {
for(var i in value_){
- if(value_[i]['user_ids'][0]==this.session.uid)
+ if(value_[i]['user_ids'][0]==this.session.uid){
this.message_is_follower=true;
this.display_buttons();
return true;
+ }
}
this.message_is_follower=false;
this.display_buttons();
@@ -173,7 +159,11 @@ openerp_mail_followers = function(session, mail) {
set_subtypes:function(data){
var self = this;
- var records = data[this.view.datarecord.id].message_subtype_data;
+ if (!data[this.view.dataset.ids[0]]) {
+ return false;
+ }
+ var records = data[this.view.dataset.ids[0]].message_subtype_data;
+
_(records).each(function (record, record_name) {
record.name = record_name;
record.followed = record.followed || undefined;
@@ -182,28 +172,22 @@ openerp_mail_followers = function(session, mail) {
},
/** Display subtypes: {'name': default, followed} */
- display_subtypes: function (visible) {
+ display_subtypes: function () {
var self = this;
var recthread_subtypes = self.$('.oe_recthread_subtypes');
subtype_list_ul = self.$('ul.oe_subtypes');
if(subtype_list_ul.is(":empty")) {
var context = new session.web.CompoundContext(this.build_context(), {});
- this.ds_model.call('get_message_subtypes',[[self.view.datarecord.id], context]).pipe(this.proxy('set_subtypes'));
+ this.ds_model.call('get_message_subtypes',[[self.view.dataset.ids[0]], context]).pipe(this.proxy('set_subtypes'));
}
},
do_follow: function () {
- var self =this;
_(this.$('.oe_msg_subtype_check')).each(function(record){
$(record).attr('checked','checked');
});
- var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], undefined, context]).pipe(function(value_){
- self.read_value(value_);
- if(!self.$('.oe_recthread_subtypes').is(":visible"))
- self.display_subtypes(true);
- });
+ this.do_update_subscription();
},
do_unfollow: function () {
@@ -211,23 +195,28 @@ openerp_mail_followers = function(session, mail) {
$(record).attr('checked',false);
});
var context = new session.web.CompoundContext(this.build_context(), {});
- return this.ds_model.call('message_unsubscribe_users', [[this.view.datarecord.id], [this.session.uid], context]).pipe(this.proxy('read_value'));
+ return this.ds_model.call('message_unsubscribe_users', [[this.view.dataset.ids[0]], [this.session.uid], context]).pipe(this.proxy('read_value'));
},
- do_update_subscription: function () {
- var context = new session.web.CompoundContext(this.build_context(), {});
+ do_update_subscription: function (event) {
var self = this;
var checklist = new Array();
- _(this.$('.oe_msg_subtype_check')).each(function(record){
+ _(this.$('.oe_mail_recthread_actions input[type="checkbox"]')).each(function(record){
if($(record).is(':checked')) {
checklist.push(parseInt($(record).data('id')))}
});
if(!checklist.length)
return this.do_unfollow();
- else
- return this.ds_model.call('message_subscribe_users',[[self.view.datarecord.id], undefined, checklist, context]).pipe(this.proxy('read_value'));
+ else{
+ var context = new session.web.CompoundContext(this.build_context(), {});
+ return this.ds_model.call('message_subscribe_users', [[this.view.dataset.ids[0]], [this.session.uid], undefined, context]).pipe(function(){
+ self.read_value();
+ self.display_subtypes();
+ });
+ }
+
},
});
diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml
index 14e656cc6fe..6a76c7aa323 100644
--- a/addons/mail/static/src/xml/mail.xml
+++ b/addons/mail/static/src/xml/mail.xml
@@ -2,7 +2,7 @@
-
+
When you sell this product, OpenERP will trigger a manufacturing
order using the bill of materials assigned to this product.
The delivery order will be ready once the production is done.
-
+
@@ -1037,6 +1038,7 @@
{'default_product_id': active_id, 'search_default_product_id': active_id}Bill of Materials
+ [('bom_id','=',False)]mrp.bom
@@ -1050,7 +1052,5 @@
-
-
diff --git a/addons/mrp/procurement.py b/addons/mrp/procurement.py
index 795ac5453fb..e2ba45ee230 100644
--- a/addons/mrp/procurement.py
+++ b/addons/mrp/procurement.py
@@ -31,6 +31,7 @@ class procurement_order(osv.osv):
_columns = {
'bom_id': fields.many2one('mrp.bom', 'BoM', ondelete='cascade', select=True),
'property_ids': fields.many2many('mrp.property', 'procurement_property_rel', 'procurement_id','property_id', 'Properties'),
+ 'production_id': fields.many2one('mrp.production', 'Manufacturing Order'),
}
def check_produce_product(self, cr, uid, procurement, context=None):
@@ -95,16 +96,22 @@ class procurement_order(osv.osv):
'move_prod_id': res_id,
'company_id': procurement.company_id.id,
})
+
res[procurement.id] = produce_id
- self.write(cr, uid, [procurement.id], {'state': 'running'})
- self.running_send_note(cr, uid, ids, context=context)
+ self.write(cr, uid, [procurement.id], {'state': 'running', 'production_id': produce_id})
bom_result = production_obj.action_compute(cr, uid,
[produce_id], properties=[x.id for x in procurement.property_ids])
wf_service.trg_validate(uid, 'mrp.production', produce_id, 'button_confirm', cr)
if res_id:
move_obj.write(cr, uid, [res_id],
{'location_id': procurement.location_id.id})
+ self.production_order_create_note(cr, uid, ids, context=context)
return res
+
+ def production_order_create_note(self, cr, uid, ids, context=None):
+ for procurement in self.browse(cr, uid, ids, context=context):
+ body = _("Manufacturing Order %s created.") % ( procurement.production_id.name,)
+ self.message_post(cr, uid, [procurement.id], body=body, context=context)
procurement_order()
diff --git a/addons/mrp_operations/report/mrp_workorder_analysis_view.xml b/addons/mrp_operations/report/mrp_workorder_analysis_view.xml
index cca9a7e3b24..de486face78 100644
--- a/addons/mrp_operations/report/mrp_workorder_analysis_view.xml
+++ b/addons/mrp_operations/report/mrp_workorder_analysis_view.xml
@@ -9,7 +9,7 @@
mrp.workorder.treemrp.workorder
-
+
diff --git a/addons/mrp_repair/i18n/pt_BR.po b/addons/mrp_repair/i18n/pt_BR.po
index cf9c24dd2bd..d194c9c48aa 100644
--- a/addons/mrp_repair/i18n/pt_BR.po
+++ b/addons/mrp_repair/i18n/pt_BR.po
@@ -7,14 +7,14 @@ msgstr ""
"Project-Id-Version: OpenERP Server 6.0dev\n"
"Report-Msgid-Bugs-To: support@openerp.com\n"
"POT-Creation-Date: 2012-02-08 00:36+0000\n"
-"PO-Revision-Date: 2012-05-10 18:03+0000\n"
-"Last-Translator: Adriano Prado \n"
+"PO-Revision-Date: 2012-10-17 00:28+0000\n"
+"Last-Translator: Syllas F. de O. Neto \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"X-Launchpad-Export-Date: 2012-08-28 06:29+0000\n"
-"X-Generator: Launchpad (build 15864)\n"
+"X-Launchpad-Export-Date: 2012-10-17 04:36+0000\n"
+"X-Generator: Launchpad (build 16152)\n"
#. module: mrp_repair
#: view:mrp.repair:0
@@ -35,6 +35,15 @@ msgid ""
"* The 'Done' state is set when repairing is completed. \n"
"* The 'Cancelled' state is used when user cancel repair order."
msgstr ""
+" * 'Provisória' é usada quando um usuário está preparando uma nova ordem de "
+"reparo não confirmada.\n"
+"* 'Confirmada' é usado quando o usuário confirma a ordem de reparo.\n"
+"* 'Pronto para Reparo\" é usado para iniciar o reparo, o usuário pode "
+"começar a reparar somente após a confirmação da ordem de reparo.\n"
+"* 'Faturar' é usado para gerar a fatura antes ou após o reparo feito.\n"
+"* 'Concluído' é definido quando o reparo finalizar.\n"
+"* O 'Cancelado' estado é usado quando o usuário cancelar a ordem de "
+"reparação."
#. module: mrp_repair
#: field:mrp.repair.line,move_id:0
@@ -179,7 +188,7 @@ msgstr "Atenção !"
#. module: mrp_repair
#: report:repair.order:0
msgid "Tax"
-msgstr ""
+msgstr "Imposto"
#. module: mrp_repair
#: view:mrp.repair:0
@@ -312,6 +321,12 @@ msgid ""
" \n"
"* The 'Cancelled' state is set automatically when user cancel repair order."
msgstr ""
+" * 'Provisório' é definido automaticamente, quando a ordem de reparo está em "
+"situação provisória.\n"
+"* 'Confirmado' é definido automaticamente quando a ordem for confirmada.\n"
+"* 'Concluído' é definido automaticamente quando o reparo estiver concluído.\n"
+"* 'Cancelado' é definido automaticamente quando o usuário cancelar a ordem "
+"de reparos."
#. module: mrp_repair
#: report:repair.order:0
diff --git a/addons/mrp_repair/report/order.rml b/addons/mrp_repair/report/order.rml
index be5737d4b85..202ed6e4684 100644
--- a/addons/mrp_repair/report/order.rml
+++ b/addons/mrp_repair/report/order.rml
@@ -312,7 +312,7 @@
[[ formatLang(line.price_unit) ]]
- [[ formatLang(pos_payment_user_total(data['form'])) or removeParentNode('blockTable')]] [[company.currency_id.symbol]]
+ [[ formatLang(pos_payment_user_total(data['form'], currency_obj = company.currency_id)) or removeParentNode('blockTable')]]
diff --git a/addons/point_of_sale/report/pos_receipt.rml b/addons/point_of_sale/report/pos_receipt.rml
index 55873887210..d7b8b08ad29 100644
--- a/addons/point_of_sale/report/pos_receipt.rml
+++ b/addons/point_of_sale/report/pos_receipt.rml
@@ -72,8 +72,7 @@
[[ repeatIn(objects,'o') ]][[o.user_id.company_id.name]]
- [[ address and address.street ]], [[ address and address.zip ]] [[ address and address.city ]]
- [[ address and address.country_id.name ]]
+ [[ address and display_address(address)]]Tel : [[ address and address.phone ]]User : [[ o.user_id.name ]]Shop : [[ o.shop_id.name ]]
@@ -109,7 +108,7 @@
[[o.state=='cancel' and o.statement_ids and '-' or '']][['%.f' % line.qty ]]
- [[o.state=='cancel' and o.statement_ids and '-' or '']][[ '%.2f' % net(line.id) ]] [[company.currency_id.symbol]] [[ line and line.discount == 0.0 and removeParentNode('font') ]] ([[ '%.2f' % line.discount ]]%) [[company.currency_id.symbol]]
+ [[o.state=='cancel' and o.statement_ids and '-' or '']][[ formatLang(net(line.id), currency_obj=company.currency_id) ]] [[ line and line.discount == 0.0 and removeParentNode('font') ]] ([[ formatLang(line.discount, currency_obj=company.currency_id) ]])
@@ -119,7 +118,7 @@
Taxes :
- [[o.state=='cancel' and o.statement_ids and '-' or '']][['%.2f' % o.amount_tax]] [[company.currency_id.symbol]]
+ [[o.state=='cancel' and o.statement_ids and '-' or '']][[formatLang(o.amount_tax, currency_obj=company.currency_id)]]
@@ -129,7 +128,7 @@
Total :
- [[o.state=='cancel' and o.statement_ids and '-' or '']][['%.2f' % o.amount_total]] [[company.currency_id.symbol]]
+ [[o.state=='cancel' and o.statement_ids and '-' or '']][[formatLang(o.amount_total, currency_obj=company.currency_id)]]
@@ -158,7 +157,7 @@
- [[ '%.2f' %(d['amt'] or 0) ]] [[company.currency_id.symbol]]
+ [[ formatLang(d['amt'] or 0, currency_obj=company.currency_id) ]]
diff --git a/addons/process/static/src/js/process.js b/addons/process/static/src/js/process.js
index 386a9653c02..c214dbb0fdf 100644
--- a/addons/process/static/src/js/process.js
+++ b/addons/process/static/src/js/process.js
@@ -216,13 +216,12 @@ instance.web.ViewManager.include({
var dataset = new instance.web.DataSet(this, 'ir.values', this.session.user_context);
var action_manager = new instance.web.ActionManager(self);
dataset.call('get',
- ['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context],
- function(res) {
+ ['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context]).then(function(res) {
var action = res[0][res[0].length - 1];
self.rpc("/web/action/load", {
action_id: action.id,
context: dataset.context
- }, function(result) {
+ }).then(function(result) {
action_manager.replace(self.$el);
action_manager.do_action(result.result);
})
diff --git a/addons/procurement/__openerp__.py b/addons/procurement/__openerp__.py
index a1aed1dfba8..48569fa76c4 100644
--- a/addons/procurement/__openerp__.py
+++ b/addons/procurement/__openerp__.py
@@ -57,7 +57,7 @@ depending on the product's configuration.
'company_view.xml',
'board_mrp_procurement_view.xml',
],
- 'demo': ['stock_orderpoint.xml'],
+ 'demo': ['stock_orderpoint.xml','procurement_demo.xml'],
'test': ['test/procurement.yml'],
'installable': True,
'auto_install': True,
diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py
index 5d81bcbb9ba..b21cef30773 100644
--- a/addons/procurement/procurement.py
+++ b/addons/procurement/procurement.py
@@ -102,7 +102,6 @@ class procurement_order(osv.osv):
'procure_method': fields.selection([('make_to_stock','Make to Stock'),('make_to_order','Make to Order')], 'Procurement Method', states={'draft':[('readonly',False)], 'confirmed':[('readonly',False)]},
readonly=True, required=True, help="If you encode manually a Procurement, you probably want to use" \
" a make to order method."),
-
'note': fields.text('Note'),
'message': fields.char('Latest error', size=124, help="Exception occurred while computing procurement orders."),
'state': fields.selection([
@@ -362,11 +361,10 @@ class procurement_order(osv.osv):
""" Changes procurement state to Running and writes message.
@return: True
"""
- message = _('From stock: products assigned.')
+ message = _('Products reserved from stock.')
self.write(cr, uid, ids, {'state': 'running',
'message': message}, context=context)
self.message_post(cr, uid, ids, body=message, context=context)
- self.running_send_note(cr, uid, ids, context=context)
return True
def _check_make_to_stock_service(self, cr, uid, procurement, context=None):
@@ -390,8 +388,6 @@ class procurement_order(osv.osv):
order_point_id = self.pool.get('stock.warehouse.orderpoint').search(cr, uid, [('product_id', '=', procurement.product_id.id)], context=context)
if not order_point_id and not ok:
message = _("Not enough stock and no minimum orderpoint rule defined.")
- elif not order_point_id:
- message = _("No minimum orderpoint rule defined.")
elif not ok:
message = _("Not enough stock.")
@@ -407,7 +403,6 @@ class procurement_order(osv.osv):
"""
for procurement in self.browse(cr, uid, ids, context=context):
self.write(cr, uid, [procurement.id], {'state': 'running'})
- self.running_send_note(cr, uid, ids, context=None)
return True
def action_produce_assign_product(self, cr, uid, ids, context=None):
@@ -469,7 +464,6 @@ class procurement_order(osv.osv):
@return: True
"""
res = self.write(cr, uid, ids, {'state': 'ready'})
- self.ready_send_note(cr, uid, ids, context=None)
return res
def action_done(self, cr, uid, ids):
@@ -503,12 +497,6 @@ class procurement_order(osv.osv):
def confirm_send_note(self, cr, uid, ids, context=None):
self.message_post(cr, uid, ids, body=_("Procurement confirmed."), context=context)
- def running_send_note(self, cr, uid, ids, context=None):
- self.message_post(cr, uid, ids, body=_("Procurement set to running."), context=context)
-
- def ready_send_note(self, cr, uid, ids, context=None):
- self.message_post(cr, uid, ids, body=_("Procurement set to ready."), context=context)
-
def cancel_send_note(self, cr, uid, ids, context=None):
self.message_post(cr, uid, ids, body=_("Procurement cancelled."), context=context)
@@ -641,7 +629,18 @@ class stock_warehouse_orderpoint(osv.osv):
})
return super(stock_warehouse_orderpoint, self).copy(cr, uid, id, default, context=context)
-stock_warehouse_orderpoint()
+class product_template(osv.osv):
+ _inherit="product.template"
+
+ _columns = {
+ 'type': fields.selection([('product','Stockable Product'),('consu', 'Consumable'),('service','Service')], 'Product Type', required=True, help="Will change the way procurements are processed. Consumable are product where you don't manage stock, a service is a non-material product provided by a company or an individual."),
+ 'procure_method': fields.selection([('make_to_stock','Make to Stock'),('make_to_order','Make to Order')], 'Procurement Method', required=True, help="'Make to Stock': When needed, take from the stock or wait until re-supplying. 'Make to Order': When needed, purchase or produce for the procurement request."),
+ 'supply_method': fields.selection([('produce','Manufacture'),('buy','Buy')], 'Supply Method', required=True, help="Produce will generate production order or tasks, according to the product type. Buy will trigger purchase orders when requested."),
+ }
+ _defaults = {
+ 'procure_method': 'make_to_stock',
+ 'supply_method': 'buy',
+ }
class product_product(osv.osv):
_inherit="product.product"
@@ -649,6 +648,6 @@ class product_product(osv.osv):
'orderpoint_ids': fields.one2many('stock.warehouse.orderpoint', 'product_id', 'Minimum Stock Rules'),
}
-product_product()
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/procurement/procurement_demo.xml b/addons/procurement/procurement_demo.xml
new file mode 100644
index 00000000000..608eb56f3ba
--- /dev/null
+++ b/addons/procurement/procurement_demo.xml
@@ -0,0 +1,204 @@
+
+
+
+
+
+ make_to_order
+ produce
+
+
+
+ make_to_order
+ produce
+
+
+
+ product
+ make_to_order
+ produce
+
+
+
+ product
+ make_to_order
+ produce
+
+
+
+ product
+ make_to_order
+ produce
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+ make_to_order
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+ make_to_order
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+ make_to_order
+ produce
+
+
+
+ product
+
+
+
+ product
+ make_to_order
+ produce
+
+
+
+ product
+ make_to_order
+ produce
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+ make_to_order
+ produce
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+ make_to_order
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+ make_to_order
+
+
+
+ product
+
+
+
+ product
+
+
+
+ make_to_order
+ produce
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+ product
+
+
+
+
+
\ No newline at end of file
diff --git a/addons/procurement/procurement_view.xml b/addons/procurement/procurement_view.xml
index bf73b383216..973a09477fc 100644
--- a/addons/procurement/procurement_view.xml
+++ b/addons/procurement/procurement_view.xml
@@ -294,6 +294,29 @@
stock.warehouse.orderpoint
+
+ product.template.procurement
+ product.template
+
+
+
+
+
+
+
+
+
+
+ product.search.procurment.form
+ product.product
+
+
+
+
+
+
+
+
product.product.procurementproduct.product
@@ -303,6 +326,33 @@
+
+
+
+
+
+
+
+ When you sell this service, nothing special will be triggered
+ to deliver the customer, as you set the procurement method as
+ 'Make to Stock'.
+
+
+ When you sell this product, OpenERP will use the available
+ inventory for the delivery order.
+
+ If there are not enough quantities available, the delivery order
+ will wait for new products. To fulfill the inventory, you should
+ create others rules like orderpoints.
+
+
+ When you sell this product, a delivery order will be created.
+ OpenERP will consider that the required quantities are always
+ available as it's a consumable (as a result of this, the quantity
+ on hand may become negative).
+
+
+
diff --git a/addons/product/product.py b/addons/product/product.py
index d5acee0333b..6c6c5f2650c 100644
--- a/addons/product/product.py
+++ b/addons/product/product.py
@@ -109,8 +109,8 @@ class product_uom(osv.osv):
_order = "name"
_columns = {
- 'name': fields.char('Name', size=64, required=True, translate=True),
- 'category_id': fields.many2one('product.uom.categ', 'Unit of Measure Category', required=True, ondelete='cascade',
+ 'name': fields.char('Unit of Measure', size=64, required=True, translate=True),
+ 'category_id': fields.many2one('product.uom.categ', 'Category', required=True, ondelete='cascade',
help="Quantity conversions may happen automatically between Units of Measure in the same category, according to their respective ratios."),
'factor': fields.float('Ratio', required=True,digits=(12, 12),
help='How many times this Unit of Measure is smaller than the reference Unit of Measure in this category:\n'\
@@ -126,7 +126,7 @@ class product_uom(osv.osv):
'active': fields.boolean('Active', help="By unchecking the active field you can disable a unit of measure without deleting it."),
'uom_type': fields.selection([('bigger','Bigger than the reference Unit of Measure'),
('reference','Reference Unit of Measure for this category'),
- ('smaller','Smaller than the reference Unit of Measure')],'Unit of Measure Type', required=1),
+ ('smaller','Smaller than the reference Unit of Measure')],'Type', required=1),
}
_defaults = {
@@ -280,11 +280,8 @@ class product_template(osv.osv):
'description': fields.text('Description',translate=True),
'description_purchase': fields.text('Purchase Description',translate=True),
'description_sale': fields.text('Sale Description',translate=True),
- 'type': fields.selection([('product','Stockable Product'),('consu', 'Consumable'),('service','Service')], 'Product Type', required=True, help="Will change the way procurements are processed. Consumable are product where you don't manage stock."),
- 'supply_method': fields.selection([('produce','Manufacture'),('buy','Buy')], 'Supply Method', required=True, help="Produce will generate production order or tasks, according to the product type. Buy will trigger purchase orders when requested."),
- 'sale_delay': fields.float('Customer Lead Time', help="This is the average delay in days between the confirmation of the customer order and the delivery of the finished products. It's the time you promise to your customers."),
+ 'type': fields.selection([('consu', 'Consumable'),('service','Service')], 'Product Type', required=True, help="Consumable are product where you don't manage stock, a service is a non-material product provided by a company or an individual."),
'produce_delay': fields.float('Manufacturing Lead Time', help="Average delay in days to produce this product. This is only for the production order and, if it is a multi-level bill of material, it's only for the level of this product. Different lead times will be summed for all levels and purchase orders."),
- 'procure_method': fields.selection([('make_to_stock','Make to Stock'),('make_to_order','Make to Order')], 'Procurement Method', required=True, help="'Make to Stock': When needed, take from the stock or wait until re-supplying. 'Make to Order': When needed, purchase or produce for the procurement request."),
'rental': fields.boolean('Can be Rent'),
'categ_id': fields.many2one('product.category','Category', required=True, change_default=True, domain="[('type','=','normal')]" ,help="Select category for the current product"),
'list_price': fields.float('Sale Price', digits_compute=dp.get_precision('Product Price'), help="Base price for computing the customer price. Sometimes called the catalog price."),
@@ -296,7 +293,6 @@ class product_template(osv.osv):
help="Standard Price: the cost price is fixed and recomputed periodically (usually at the end of the year), Average Price: the cost price is recomputed at each reception of products."),
'warranty': fields.float('Warranty'),
'sale_ok': fields.boolean('Can be Sold', help="Determines if the product can be visible in the list of product within a selection from a sale order line."),
- 'purchase_ok': fields.boolean('Can be Purchased', help="Determine if the product is visible in the list of products within a selection from a purchase order line."),
'state': fields.selection([('',''),
('draft', 'In Development'),
('sellable','Normal'),
@@ -309,11 +305,8 @@ class product_template(osv.osv):
'uos_coeff': fields.float('Unit of Measure -> UOS Coeff', digits_compute= dp.get_precision('Product UoS'),
help='Coefficient to convert Unit of Measure to UOS\n'
' uos = uom * coeff'),
- 'mes_type': fields.selection((('fixed', 'Fixed'), ('variable', 'Variable')), 'Measure Type', required=True),
+ 'mes_type': fields.selection((('fixed', 'Fixed'), ('variable', 'Variable')), 'Measure Type'),
'seller_ids': fields.one2many('product.supplierinfo', 'product_id', 'Partners'),
- 'loc_rack': fields.char('Rack', size=16),
- 'loc_row': fields.char('Row', size=16),
- 'loc_case': fields.char('Case', size=16),
'company_id': fields.many2one('res.company', 'Company', select=1),
}
@@ -351,21 +344,17 @@ class product_template(osv.osv):
_defaults = {
'company_id': lambda s,cr,uid,c: s.pool.get('res.company')._company_default_get(cr, uid, 'product.template', context=c),
- 'list_price': lambda *a: 1,
- 'cost_method': lambda *a: 'standard',
- 'supply_method': lambda *a: 'buy',
- 'standard_price': lambda *a: 0.0,
- 'sale_ok': lambda *a: 1,
- 'sale_delay': lambda *a: 7,
- 'produce_delay': lambda *a: 1,
- 'purchase_ok': lambda *a: 1,
- 'procure_method': lambda *a: 'make_to_stock',
+ 'list_price': 1,
+ 'cost_method': 'standard',
+ 'standard_price': 0.0,
+ 'sale_ok': 1,
+ 'produce_delay': 1,
'uom_id': _get_uom_id,
'uom_po_id': _get_uom_id,
- 'uos_coeff' : lambda *a: 1.0,
- 'mes_type' : lambda *a: 'fixed',
+ 'uos_coeff' : 1.0,
+ 'mes_type' : 'fixed',
'categ_id' : _default_category,
- 'type' : lambda *a: 'consu',
+ 'type' : 'consu',
}
def _check_uom(self, cursor, user, ids, context=None):
diff --git a/addons/product/product_data.xml b/addons/product/product_data.xml
index 1974acc6df2..8e5280d036a 100644
--- a/addons/product/product_data.xml
+++ b/addons/product/product_data.xml
@@ -197,7 +197,6 @@ parameter) will see those record just disappear.
Serviceservice
-
diff --git a/addons/product/product_demo.xml b/addons/product/product_demo.xml
index 66b86fc7b63..14477d2401a 100644
--- a/addons/product/product_demo.xml
+++ b/addons/product/product_demo.xml
@@ -70,8 +70,6 @@
20.530.75service
- make_to_order
- produceThis type of service include basic monitoring of products.
@@ -84,8 +82,6 @@
25.538.25service
- make_to_order
- produceThis type of service include assistance for security questions, system configuration requirements, implementation or special needs.
@@ -97,9 +93,7 @@
450.0300.0
- product
- make_to_order
- produce
+ consu4.0
@@ -115,9 +109,8 @@ HDD SH-1500.0750.0
- product
- make_to_order
- produce
+ consu
+
4.0
@@ -133,9 +126,7 @@ HDD SH-1600.0900.0
- product
- make_to_order
- produce
+ consu7.0
@@ -148,7 +139,7 @@ HDD SH-1800.01200.0
- product
+ consu
@@ -158,7 +149,7 @@ HDD SH-1
880.01350.0
- product
+ consu
@@ -168,7 +159,7 @@ HDD SH-1
10.013.0
- product
+ consu
@@ -178,8 +169,7 @@ HDD SH-1
10.013.0
- product
- make_to_order
+ consu
@@ -189,7 +179,7 @@ HDD SH-1
12.5014
- product
+ consu
@@ -199,7 +189,7 @@ HDD SH-1
1416.50
- product
+ consu
@@ -209,8 +199,7 @@ HDD SH-1
1812.50
- product
- make_to_order
+ consu
@@ -220,7 +209,7 @@ HDD SH-1
78.085.0
- product
+ consu
@@ -230,7 +219,7 @@ HDD SH-1
87.095.0
- product
+ consu
@@ -240,7 +229,7 @@ HDD SH-1
80.085.0
- product
+ consu
@@ -250,9 +239,7 @@ HDD SH-1
20.025.0
- product
- make_to_order
- produce
+ consu
@@ -262,7 +249,7 @@ HDD SH-1
860.0975.0
- product
+ consu
@@ -272,9 +259,7 @@ HDD SH-1
1020.01150.0
- product
- make_to_order
- produce
+ consu
@@ -284,9 +269,7 @@ HDD SH-1
1100.01250.0
- product
- make_to_order
- produce
+ consuOn demand hard-disk having capacity based on requirement.
@@ -297,7 +280,7 @@ HDD SH-1
1700.01950.0
- product
+ consu
@@ -307,7 +290,7 @@ HDD SH-1
1790.02000.0
- product
+ consu
@@ -317,7 +300,7 @@ HDD SH-1
2010.02100.0
- product
+ consu
@@ -327,7 +310,7 @@ HDD SH-1
1910.01980.0
- product
+ consu
@@ -337,7 +320,7 @@ HDD SH-1
876.0885.0
- product
+ consu
@@ -347,7 +330,7 @@ HDD SH-1
2870.02950.0
- product
+ consu17" Monitor
@@ -361,7 +344,7 @@ QWERTY keyboard3000.03245.0
- product
+ consu17" Monitor
@@ -375,9 +358,7 @@ QWERTY keyboard3300.03645.0
- product
- make_to_order
- produce
+ consuCustom Laptop based on customer's requirement.
@@ -388,7 +369,7 @@ QWERTY keyboard
390.0405.0
- product
+ consu
@@ -399,7 +380,7 @@ QWERTY keyboard
90.0100.0
- product
+ consu
@@ -410,7 +391,7 @@ QWERTY keyboard
126.0145.0
- product
+ consu
@@ -420,7 +401,7 @@ QWERTY keyboard
134.0150.0
- product
+ consu.
@@ -431,7 +412,7 @@ QWERTY keyboard
57.062.0
- product
+ consuHands free headset for laptop PC with in-line microphone and headphone plug.
@@ -442,8 +423,7 @@ QWERTY keyboard
60.065.0
- product
- make_to_order
+ consuHeadset for laptop PC with USB connector.
@@ -455,7 +435,7 @@ QWERTY keyboard
38.045.0
- product
+ consu
@@ -466,7 +446,7 @@ QWERTY keyboard
18.4020.0
- product
+ consu
@@ -477,7 +457,7 @@ QWERTY keyboard
21.6024.0
- product
+ consu
@@ -488,8 +468,7 @@ QWERTY keyboard
4258.04410.0
- product
- make_to_order
+ consuAll in one hi-speed printer with fax and scanner.
@@ -501,7 +480,7 @@ QWERTY keyboard
60.065.0
- product
+ consu
@@ -512,7 +491,7 @@ QWERTY keyboard
66.070.0
- product
+ consu
@@ -569,8 +548,6 @@ QWERTY keyboard
155.0173.0consu
- make_to_order
- produceFull featured image editing software.
@@ -582,7 +559,7 @@ QWERTY keyboard
55.060.0
- product
+ consu
@@ -593,7 +570,7 @@ QWERTY keyboard
35.040.0
- product
+ consu
@@ -604,7 +581,7 @@ QWERTY keyboard
55.070.0
- product
+ consu
@@ -615,7 +592,7 @@ QWERTY keyboard
13.018.0
- product
+ consu
diff --git a/addons/product/product_view.xml b/addons/product/product_view.xml
index 8c19aee026f..b7fbcd560f7 100644
--- a/addons/product/product_view.xml
+++ b/addons/product/product_view.xml
@@ -10,12 +10,10 @@
-
+
-
-
-
+
@@ -60,7 +58,7 @@