Merge lp:~fabien-morin/unifield-web/fm-us-2925 into lp:unifield-web

Proposed by jftempo
Status: Merged
Merged at revision: 4883
Proposed branch: lp:~fabien-morin/unifield-web/fm-us-2925
Merge into: lp:unifield-web
Diff against target: 615 lines (+460/-5)
6 files modified
addons/openerp/controllers/database.py (+272/-3)
addons/openerp/controllers/templates/auto_create.mako (+70/-0)
addons/openerp/controllers/templates/auto_create_progress.mako (+80/-0)
addons/openerp/controllers/utils.py (+12/-0)
addons/openerp/po/messages/fr.po (+2/-2)
addons/openerp/static/css/database.css (+24/-0)
To merge this branch: bzr merge lp:~fabien-morin/unifield-web/fm-us-2925
Reviewer Review Type Date Requested Status
UniField Dev Team Pending
Review via email: mp+334060@code.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'addons/openerp/controllers/database.py'
--- addons/openerp/controllers/database.py 2017-07-11 12:19:46 +0000
+++ addons/openerp/controllers/database.py 2017-11-21 17:05:56 +0000
@@ -22,10 +22,12 @@
22import re22import re
23import time23import time
24import os24import os
25import sys
2526
26import cherrypy27import cherrypy
27import formencode28import formencode
2829
30from openobject import paths
29from openobject.controllers import BaseController31from openobject.controllers import BaseController
30from openobject.tools import url, expose, redirect, validate, error_handler32from openobject.tools import url, expose, redirect, validate, error_handler
31import openobject33import openobject
@@ -35,6 +37,9 @@
35from openerp.utils import rpc, get_server_version, is_server_local, serve_file37from openerp.utils import rpc, get_server_version, is_server_local, serve_file
36from tempfile import NamedTemporaryFile38from tempfile import NamedTemporaryFile
37import shutil39import shutil
40import ConfigParser
41from ConfigParser import NoOptionError, NoSectionError
42import threading
3843
39def get_lang_list():44def get_lang_list():
40 langs = [('en_US', 'English (US)')]45 langs = [('en_US', 'English (US)')]
@@ -50,6 +55,8 @@
50 except:55 except:
51 return []56 return []
5257
58class DatabaseExist(Exception): pass
59
53class ReplacePasswordField(openobject.widgets.PasswordField):60class ReplacePasswordField(openobject.widgets.PasswordField):
54 params = {61 params = {
55 'autocomplete': 'Autocomplete field',62 'autocomplete': 'Autocomplete field',
@@ -116,6 +123,23 @@
116 validator = openobject.validators.Schema(chained_validators=[formencode.validators.FieldsMatch("admin_password","confirm_password")])123 validator = openobject.validators.Schema(chained_validators=[formencode.validators.FieldsMatch("admin_password","confirm_password")])
117124
118125
126class FormAutoCreate(DBForm):
127 name = "auto_create"
128 string = _('Instance Auto Creation')
129 action = '/openerp/database/do_auto_create'
130 submit_text = _('Start auto creation')
131 #form_attrs = {'onsubmit': 'return window.confirm(_("Do you really want to drop the selected database?"))'}
132 fields = [
133 ReplacePasswordField(name='password', label=_('Super admin password:')),
134 ]
135
136
137class AutoCreateProgress(DBForm):
138 name = "get_auto_create_progress"
139 string = _('Auto Creation Progress')
140 action = '/openerp/database/get_auto_create_progress'
141
142
119class FormDrop(DBForm):143class FormDrop(DBForm):
120 name = "drop"144 name = "drop"
121 string = _('Drop database')145 string = _('Drop database')
@@ -127,6 +151,7 @@
127 ReplacePasswordField(name='password', label=_('Drop password:')),151 ReplacePasswordField(name='password', label=_('Drop password:')),
128 ]152 ]
129153
154
130class FormBackup(DBForm):155class FormBackup(DBForm):
131 name = "backup"156 name = "backup"
132 string = _('Backup database')157 string = _('Backup database')
@@ -137,10 +162,12 @@
137 ReplacePasswordField(name='password', label=_('Backup password:')),162 ReplacePasswordField(name='password', label=_('Backup password:')),
138 ]163 ]
139164
165
140class FileField(openobject.widgets.FileField):166class FileField(openobject.widgets.FileField):
141 def adjust_value(self, value, **params):167 def adjust_value(self, value, **params):
142 return False168 return False
143169
170
144class FormRestore(DBForm):171class FormRestore(DBForm):
145 name = "restore"172 name = "restore"
146 string = _('Restore database')173 string = _('Restore database')
@@ -169,6 +196,7 @@
169196
170197
171_FORMS = {198_FORMS = {
199 'auto_create': FormAutoCreate(),
172 'create': FormCreate(),200 'create': FormCreate(),
173 'drop': FormDrop(),201 'drop': FormDrop(),
174 'backup': FormBackup(),202 'backup': FormBackup(),
@@ -176,9 +204,13 @@
176 'password': FormPassword()204 'password': FormPassword()
177}205}
178206
207
179class DatabaseCreationError(Exception): pass208class DatabaseCreationError(Exception): pass
209
210
180class DatabaseCreationCrash(DatabaseCreationError): pass211class DatabaseCreationCrash(DatabaseCreationError): pass
181212
213
182class Database(BaseController):214class Database(BaseController):
183215
184 _cp_path = "/openerp/database"216 _cp_path = "/openerp/database"
@@ -248,7 +280,7 @@
248 break280 break
249 else:281 else:
250 time.sleep(1)282 time.sleep(1)
251 except:283 except Exception as e:
252 raise DatabaseCreationCrash()284 raise DatabaseCreationCrash()
253 except DatabaseCreationCrash:285 except DatabaseCreationCrash:
254 self.msg = {'message': (_("The server crashed during installation.\nWe suggest you to drop this database.")),286 self.msg = {'message': (_("The server crashed during installation.\nWe suggest you to drop this database.")),
@@ -258,15 +290,252 @@
258 self.msg = {'message': _('Bad super admin password'),290 self.msg = {'message': _('Bad super admin password'),
259 'title' : e.title}291 'title' : e.title}
260 return self.create()292 return self.create()
261 except Exception:293 except Exception as e:
262 self.msg = {'message':_("Could not create database.")}294 self.msg = {'message':_("Could not create database.")}
263
264 return self.create()295 return self.create()
265296
266 if ok:297 if ok:
267 raise redirect('/openerp/menu', {'next': '/openerp/home'})298 raise redirect('/openerp/menu', {'next': '/openerp/home'})
268 raise redirect('/openerp/login', db=dbname)299 raise redirect('/openerp/login', db=dbname)
269300
301 @expose(template="/openerp/controllers/templates/auto_create.mako")
302 def auto_create(self, tg_errors=None, **kw):
303 form = _FORMS['auto_create']
304 error = self.msg
305 self.msg = {}
306 return dict(form=form, error=error)
307
308 @expose()
309 def get_auto_create_progress(self, **kw):
310 config_file_name = 'uf_auto_install.conf'
311 if sys.platform == 'win32':
312 config_file_path = os.path.join(paths.root(), '..', 'UFautoInstall', config_file_name)
313 else:
314 config_file_path = os.path.join(paths.root(), '..', 'unifield-server', 'UFautoInstall', config_file_name)
315 if not os.path.exists(config_file_path):
316 return False
317 config = ConfigParser.ConfigParser()
318 config.read(config_file_path)
319 dbname = config.get('instance', 'db_name')
320 self.resume, self.progress, self.state, self.error, monitor_status = rpc.session.execute_db('creation_get_resume_progress', dbname)
321 my_dict = {
322 'resume': self.resume,
323 'progress': self.progress,
324 'state': self.state,
325 'error': self.error,
326 'monitor_status': monitor_status,
327 }
328 import json
329 return json.dumps(my_dict)
330
331 @expose(template="/openerp/controllers/templates/auto_create_progress.mako")
332 def auto_create_progress(self, tg_errors=None, **kw):
333 finish = ""
334 finished = "False"
335 data_collected = "False"
336 return dict(finish=finish, percent=self.progress, resume=self.resume, total=finished,
337 data_collected=data_collected)
338
339 def check_not_empty_string(self, config, section, option):
340 if not config.has_option(section, option) or not config.get(section, option):
341 self.msg = {'message': ustr(_('The option \'%s\' from section \'[%s]\' cannot be empty, please set a value.') % (option, section)),
342 'title': ustr(_('Empty option'))}
343
344 def check_mandatory_int(self, config, section, option):
345 try:
346 value = config.getint(section, option)
347 except ValueError:
348 self.msg = {'message': ustr(_('The option \'%s\' from section \'[%s]\' have to be a int.') % (option, section)),
349 'title': ustr(_('Wrong option value'))}
350 return
351 if not value:
352 self.msg = {'message': ustr(_('The option \'%s\' from section \'[%s]\' cannot be empty, please set a value.') % (option, section)),
353 'title': ustr(_('Empty option'))}
354
355 def check_possible_value(self, config, section, option, possible_values):
356 value = config.get(section, option)
357 if value not in possible_values:
358 self.msg = {'message': ustr(_('The option \'%s\' from section \'[%s]\' have to be one of those values: %r. (currently it is \'%s\').') % (option, section, possible_values, value)),
359 'title': ustr(_('Wrong option'))}
360
361 def check_config_file(self, file_path):
362 '''
363 perform some basic checks to avoid crashing later
364 '''
365 if not os.path.exists(file_path):
366 self.msg = {'message': ustr(_("The auto creation config file '%s' does not exists.") % file_path),
367 'title': ustr(_('Auto creation file not found'))}
368
369 config = ConfigParser.ConfigParser()
370 config.read(file_path)
371 try:
372 db_name = config.get('instance', 'db_name')
373 if not re.match('^[a-zA-Z][a-zA-Z0-9_-]+$', db_name):
374 self.msg = {'message': ustr(_("You must avoid all accents, space or special characters.")),
375 'title': ustr(_('Bad database name'))}
376 return
377
378 admin_password = config.get('instance', 'admin_password')
379 res = rpc.session.execute_db('check_super_password_validity', admin_password)
380 if res is not True:
381 self.msg = {'message': res,
382 'title': ustr(_('Bad admin password'))}
383 return
384
385 # check the mandatory string fields have a value
386 not_empty_string_option_list = (
387 ('instance', 'oc'),
388 ('instance', 'admin_password'),
389 ('instance', 'sync_user'),
390 ('instance', 'sync_pwd'),
391 ('instance', 'instance_level'),
392 ('instance', 'parent_instance'),
393 ('instance', 'lang'),
394 ('backup', 'auto_bck_path'),
395 ('reconfigure', 'prop_instance_code'),
396 ('reconfigure', 'address_contact_name'),
397 ('reconfigure', 'address_street'),
398 ('reconfigure', 'address_street2'),
399 ('reconfigure', 'address_zip'),
400 ('reconfigure', 'address_city'),
401 ('reconfigure', 'address_country'),
402 ('reconfigure', 'address_phone'),
403 ('reconfigure', 'address_email'),
404 ('reconfigure', 'delivery_process'),
405 ('reconfigure', 'functional_currency'),
406 )
407 for section, option in not_empty_string_option_list:
408 self.check_not_empty_string(config, section, option)
409 if self.msg:
410 return
411
412 # check mandatory integer values
413 not_empty_int_option_list = (
414 ('backup', 'auto_bck_interval_nb'),
415 ('partner', 'external_account_receivable'),
416 ('partner', 'external_account_payable'),
417 ('partner', 'internal_account_receivable'),
418 ('partner', 'internal_account_payable'),
419 ('company', 'default_counterpart'),
420 ('company', 'salaries_default_account'),
421 ('company', 'rebilling_intersection_account'),
422 ('company', 'intermission_counterpart'),
423 ('company', 'counterpart_bs_debit_balance'),
424 ('company', 'counterpart_bs_crebit_balance'),
425 ('company', 'debit_account_pl_positive'),
426 ('company', 'credit_account_pl_negative'),
427 ('company', 'scheduler_range_days'),
428 )
429 for section, option in not_empty_int_option_list:
430 self.check_mandatory_int(config, section, option)
431 if self.msg:
432 return
433
434 # check value is in possibles values
435 possible_value_list = (
436 ('instance', 'instance_level', ('coordo', 'project')),
437 ('instance', 'lang', ('fr_MF', 'es_MF', 'en_MF')),
438 ('backup', 'auto_bck_interval_unit', ('minutes', 'hours', 'work_days', 'days', 'weeks', 'months')),
439 ('reconfigure', 'delivery_process', ('complex', 'simple')),
440 )
441
442 for section, option, possible_values in possible_value_list:
443 self.check_possible_value(config, section, option, possible_values)
444 if self.msg:
445 return
446
447 except NoOptionError as e:
448 self.msg = {'message': ustr(_('No option \'%s\' found for the section \'[%s]\' in the config file \'%s\'') % (e.option, e.section, file_path)),
449 'title': ustr(_('Option missing in configuration file'))}
450 return
451 except NoSectionError as e:
452 self.msg = {'message': ustr(_('No section \'%s\' found in the config file \'%s\'') % (e.section, file_path)),
453 'title': ustr(_('Option missing in configuration file'))}
454 return
455
456 def database_creation(self, password, dbname, admin_password):
457 try:
458 res = rpc.session.execute_db('create', password, dbname, False, 'en_US', admin_password)
459 while True:
460 try:
461 progress, users = rpc.session.execute_db('get_progress', password, res)
462 if progress == 1.0:
463 for x in users:
464 if x['login'] == 'admin':
465 rpc.session.login(dbname, 'admin', x['password'])
466 ok = True
467 break
468 else:
469 time.sleep(1)
470 except Exception as e:
471 raise DatabaseCreationCrash()
472 except DatabaseCreationCrash:
473 self.msg = {'message': (_("The server crashed during installation.\nWe suggest you to drop this database.")),
474 'title': (_('Error during database creation'))}
475 except openobject.errors.AccessDenied, e:
476 self.msg = {'message': _('Bad super admin password'),
477 'title' : e.title}
478
479 def background_auto_creation(self, password, dbname, db_exists, config_dict):
480 if not db_exists:
481 # create database
482 self.database_creation(password, dbname, config_dict['instance'].get('admin_password'))
483
484 rpc.session.execute_db('instance_auto_creation', password, dbname)
485 self.resume, self.progress, self.state, self.error, monitor_status = rpc.session.execute_db('creation_get_resume_progress', dbname)
486
487 @expose()
488 @validate(form=_FORMS['auto_create'])
489 @error_handler(auto_create)
490 def do_auto_create(self, password, **kw):
491 self.msg = {}
492 self.progress = 0.03
493 self.state = 'draft'
494 try:
495 config_file_name = 'uf_auto_install.conf'
496 if sys.platform == 'win32':
497 config_file_path = os.path.join(paths.root(), '..', 'UFautoInstall', config_file_name)
498 else:
499 config_file_path = os.path.join(paths.root(), '..', 'unifield-server', 'UFautoInstall', config_file_name)
500
501 self.check_config_file(config_file_path)
502 if self.msg:
503 return self.auto_create()
504 config = ConfigParser.ConfigParser()
505 config.read(config_file_path)
506
507 config_dict = {x:dict(config.items(x)) for x in config.sections()}
508 dbname = config_dict['instance'].get('db_name')
509 db_exists = False
510
511 # check the database not already exists
512 if dbname in get_db_list():
513 db_exists = True
514 self.resume = _('Database with this name exists, resume from the last point...\n')
515 else:
516 self.resume = _('Empty database creation in progress...\n')
517 #raise DatabaseExist
518
519 create_thread = threading.Thread(target=self.background_auto_creation,
520 args=(password, dbname, db_exists,
521 config_dict))
522 create_thread.start()
523 create_thread.join(0.5)
524
525 except openobject.errors.AccessDenied, e:
526 self.msg = {'message': _('Wrong password'),
527 'title' : e.title}
528 except DatabaseExist:
529 pass
530 #self.msg = {'message': ustr(_('The database already exist')),
531 # 'title': 'Database exist'}
532 except Exception as e:
533 self.msg = {'message' : _("Could not auto create database: %s") % e}
534
535 if self.msg:
536 return self.auto_create()
537 return self.auto_create_progress()
538
270 @expose(template="/openerp/controllers/templates/database.mako")539 @expose(template="/openerp/controllers/templates/database.mako")
271 def drop(self, tg_errors=None, **kw):540 def drop(self, tg_errors=None, **kw):
272 form = _FORMS['drop']541 form = _FORMS['drop']
273542
=== added file 'addons/openerp/controllers/templates/auto_create.mako'
--- addons/openerp/controllers/templates/auto_create.mako 1970-01-01 00:00:00 +0000
+++ addons/openerp/controllers/templates/auto_create.mako 2017-11-21 17:05:56 +0000
@@ -0,0 +1,70 @@
1<%inherit file="/openerp/controllers/templates/base_dispatch.mako"/>
2<%def name="current_for(name)"><%
3 if form.name == name: context.write('current')
4%></%def>
5<%def name="header()">
6 <title>${form.string}</title>
7
8 <script type="text/javascript" src="/openerp/static/javascript/openerp/openerp.ui.waitbox.js"></script>
9 <link rel="stylesheet" type="text/css" href="/openerp/static/css/waitbox.css"/>
10 <link rel="stylesheet" type="text/css" href="/openerp/static/css/database.css"/>
11 <script type="text/javascript">
12 function on_create() {
13 new openerp.ui.WaitBox().showAfter(2000);
14 return true;
15 }
16 </script>
17 % if error:
18 <script type="text/javascript">
19 var $error_tbl = jQuery('<table class="errorbox">');
20 $error_tbl.append('<tr><td style="padding: 4px 2px;" width="10%"><img src="/openerp/static/images/warning.png"></td><td class="error_message_content">${error["message"]}</td></tr>');
21 $error_tbl.append('<tr><td style="padding: 0 8px 5px 0; vertical-align:top;" align="right" colspan="2"><a class="button-a" id="error_btn" onclick="$error_tbl.dialog(\'close\');">OK</a></td></tr>');
22
23 jQuery(document).ready(function () {
24 jQuery(document.body).append($error_tbl);
25 var error_dialog_options = {
26 modal: true,
27 resizable: false,
28 title: '<div class="error_message_header">${error.get("title", "Warning")}</div>'
29 };
30 % if error.get('redirect_to'):
31 error_dialog_options['close'] = function( event, ui ) {
32 $(location).attr('href','${error['redirect_to']}');
33 };
34 % endif
35 $error_tbl.dialog(error_dialog_options);
36 })
37 </script>
38 % endif
39</%def>
40
41<%def name="content()">
42 <table width="100%">
43 <tr><%include file="header.mako"/></tr>
44 </table>
45 <div class="db-form">
46 <h1>Automated instance creation detected</h1>
47
48 <div class='auto_instance_text'>
49 <p>If you have checked the following points, you can start the
50process of instance auto creation by login with the Super admin password. Points to check:
51 <ul>
52 <li>A Folder 'UFautoInstall' is present in Unifield/Server folder.</li>
53 <li>This folder contain a file 'uf_auto_install.conf'</li>
54 <li>This file is correct (required fields, correct values)</li>
55 <li>The folder also contain an 'import' directory
56(Unifield/Server/UFautoInstall/import)</li>
57 <li>This 'import' directory contain files where the name of
58the file is the model to import and the extension is csv (typically,
59'account.analytic.journal.csv' and 'account.journal.csv')</li>
60 <li>The connexion to the SYNC_SERVER is ok (credentials,
61address, port, ...)</li>
62 <li>The parents instance (HQ, and Coordo if it is a
63project) exists and are present as instance in the SYNC_SERVER</li>
64 </ul>
65 </p>
66 </div>
67 <div>${form.display()}</div>
68 </div>
69<%include file="footer.mako"/>
70</%def>
071
=== added file 'addons/openerp/controllers/templates/auto_create_progress.mako'
--- addons/openerp/controllers/templates/auto_create_progress.mako 1970-01-01 00:00:00 +0000
+++ addons/openerp/controllers/templates/auto_create_progress.mako 2017-11-21 17:05:56 +0000
@@ -0,0 +1,80 @@
1<%inherit file="/openerp/controllers/templates/base_dispatch.mako"/>
2<%def name="header()">
3 <title>Instance creation progression</title>
4
5 <script type="text/javascript" src="/openerp/static/javascript/openerp/openerp.ui.waitbox.js"></script>
6 <script type="text/javascript">
7 $(document).ready(function(){
8 interval = setInterval(function()
9 {
10 $.ajax({
11 type: 'get',
12 dataType: "json",
13 url: 'get_auto_create_progress',
14 success: function (data) {
15
16 if (data){
17 if (data.error){
18 clearInterval(interval);
19 var $error_tbl = jQuery('<table class="errorbox">');
20 $error_tbl.append('<tr><td style="padding: 4px 2px;" width="10%"><img src="/openerp/static/images/warning.png"></td><td class="error_message_content">' + data.error + '</td></tr>');
21 $error_tbl.append('<tr><td style="padding: 0 8px 5px 0; vertical-align:top;" align="right" colspan="2"><a class="button-a" id="error_btn" onclick="$error_tbl.dialog(\'close\');">OK</a></td></tr>');
22
23 jQuery(document).ready(function () {
24 jQuery(document.body).append($error_tbl);
25 var error_dialog_options = {
26 modal: true,
27 resizable: false,
28 title: '<div class="error_message_header">Error</div>'
29 };
30 $error_tbl.dialog(error_dialog_options);
31 })
32
33 };
34 $("div.auto_creation_resume textarea").val(data.resume);
35 $("div.progressbar").text((data.progress*100).toPrecision(3)+'%');
36 $("div.progressbar").css({"width":(data.progress*100).toPrecision(3)+'%'});
37 $("div.my_state").text(data.state);
38 if (data.state === 'done') {
39 clearInterval(interval);
40 };
41 if (data.monitor_status) {
42 $("div.my_monitor_status").text(data.monitor_status);
43 };
44 }
45 },
46 error: function (xhr, status, error) {
47 }
48 });
49 }, 3000)
50 });
51 </script>
52
53 <link rel="stylesheet" type="text/css" href="/openerp/static/css/waitbox.css"/>
54 <link rel="stylesheet" type="text/css" href="/openerp/static/css/database.css"/>
55
56</%def>
57
58<%def name="content()">
59 <table width="100%">
60 <tr><%include file="header.mako"/></tr>
61 </table>
62
63
64
65 <div class="db-form">
66 <h1>Automated instance creation in progress...</h1>
67
68 <div class="my_state"></div>
69 <div class="my_monitor_status"></div>
70
71 <div class="instance_creation_progress">
72 <div class="progressbar" style="width:${'%d'%(percent*100)}%">${'%d'%(percent*100)}%</div>
73 </div>
74
75 <div class="auto_creation_resume">
76 <textarea rows="20" cols="80">${resume}</textarea>
77 </div>
78 </div>
79<%include file="footer.mako"/>
80</%def>
081
=== modified file 'addons/openerp/controllers/utils.py'
--- addons/openerp/controllers/utils.py 2016-11-17 15:29:41 +0000
+++ addons/openerp/controllers/utils.py 2017-11-21 17:05:56 +0000
@@ -20,11 +20,13 @@
20###############################################################################20###############################################################################
21import re21import re
22import os22import os
23import sys
2324
24import cherrypy25import cherrypy
25from openerp.utils import rpc26from openerp.utils import rpc
2627
27from openobject import tools28from openobject import tools
29from openobject import paths
28from openobject.tools import expose, redirect30from openobject.tools import expose, redirect
29import openobject31import openobject
3032
@@ -94,6 +96,16 @@
94 url = rpc.session.connection_string96 url = rpc.session.connection_string
95 url = str(url[:-1])97 url = str(url[:-1])
9698
99 config_file_name = 'uf_auto_install.conf'
100 if sys.platform == 'win32':
101 config_file_path = os.path.join(paths.root(), '..', 'UFautoInstall', config_file_name)
102 else:
103 config_file_path = os.path.join(paths.root(), '..', 'unifield-server', 'UFautoInstall', config_file_name)
104 if os.path.exists(config_file_path):
105 raise redirect('/openerp/database/auto_create')
106 return auto_install(target, db, user, password, action, message,
107 origArgs, url)
108
97 result = get_db_list()109 result = get_db_list()
98 dblist = result['dblist']110 dblist = result['dblist']
99 bad_regional = result['bad_regional']111 bad_regional = result['bad_regional']
100112
=== modified file 'addons/openerp/po/messages/fr.po'
--- addons/openerp/po/messages/fr.po 2017-10-27 14:32:19 +0000
+++ addons/openerp/po/messages/fr.po 2017-11-21 17:05:56 +0000
@@ -275,7 +275,7 @@
275275
276#: controllers/database.py:173276#: controllers/database.py:173
277msgid "You must avoid all accents, space or special characters."277msgid "You must avoid all accents, space or special characters."
278msgstr "Les accents , espaces et caractères spéciaux ne sont pas autorisés ."278msgstr "Les accents, espaces et caractères spéciaux ne sont pas autorisés ."
279279
280#: controllers/database.py:174280#: controllers/database.py:174
281msgid "Bad database name"281msgid "Bad database name"
@@ -648,7 +648,7 @@
648"données. Il met en relation, améliore et\n"648"données. Il met en relation, améliore et\n"
649" gère les processus dans les domaines des ventes, de la "649" gère les processus dans les domaines des ventes, de la "
650"finance, de la logistique,\n"650"finance, de la logistique,\n"
651" de la gestion de projets , la production, les services, "651" de la gestion de projets, la production, les services, "
652"la gestion de la relation client, etc.\n"652"la gestion de la relation client, etc.\n"
653" "653" "
654654
655655
=== modified file 'addons/openerp/static/css/database.css'
--- addons/openerp/static/css/database.css 2012-11-15 08:31:02 +0000
+++ addons/openerp/static/css/database.css 2017-11-21 17:05:56 +0000
@@ -69,3 +69,27 @@
69 text-align: right;69 text-align: right;
70 padding: 0 5px 0 0;70 padding: 0 5px 0 0;
71}71}
72
73.instance_creation_progress {
74 width: 20%;
75 margin-left: 40%;
76 margin-top: 2em;
77 margin-bottom: 2em;
78 border: solid 1px lightslategrey;
79}
80
81.instance_creation_progress .progressbar {
82 background-color: #4CAF50;
83 text-align: center;
84 font-size: 15px;
85 line-height: 2;
86}
87
88.auto_creation_resume {
89 text-align: center;
90}
91
92.auto_instance_text {
93 font-size: 1.5em;
94 margin: 3em;
95}

Subscribers

People subscribed via source and target branches