From 182b9a7182400fe43ec966f74563a5acfceda49f Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 24 Jan 2012 16:34:19 +0100 Subject: [PATCH 001/703] [IMP] document_webdav.webdav_server: remove the so called `uniform log handling` of the HttpLogHandler class. bzr revid: vmt@openerp.com-20120124153419-w6oed6z1ui8mouo7 --- addons/document_webdav/webdav_server.py | 37 +++++++++++-------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/addons/document_webdav/webdav_server.py b/addons/document_webdav/webdav_server.py index 81435a72137..ac7f87933ef 100644 --- a/addons/document_webdav/webdav_server.py +++ b/addons/document_webdav/webdav_server.py @@ -55,6 +55,8 @@ from DAV.propfind import PROPFIND from xml.dom import minidom from redirect import RedirectHTTPHandler +_logger = logging.getLogger(__name__) + khtml_re = re.compile(r' KHTML/([0-9\.]+) ') def OpenDAVConfig(**kw): @@ -73,7 +75,6 @@ def OpenDAVConfig(**kw): class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): verbose = False - _logger = logging.getLogger('webdav') protocol_version = 'HTTP/1.1' _HTTP_OPTIONS= { 'DAV' : ['1', '2'], 'Allow' : [ 'GET', 'HEAD', 'COPY', 'MOVE', 'POST', 'PUT', @@ -85,7 +86,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): return False def _log(self, message): - self._logger.debug(message) + _logger.debug(message) def handle(self): self._init_buffer() @@ -106,7 +107,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): if hasattr(self.request, 'getsockname'): addr, port = self.request.getsockname() except Exception, e: - self.log_error("Cannot calculate own address: %s" , e) + _logger.warning("Cannot calculate own address: %s", e) # Too early here to use self.headers self.baseuri = "%s://%s:%d/"% (server_proto, addr, port) self.IFACE_CLASS = openerp_dav_handler(self, self.verbose) @@ -126,12 +127,6 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): def get_davpath(self): return self.davpath - def log_message(self, format, *args): - self._logger.log(netsvc.logging.DEBUG_RPC,format % args) - - def log_error(self, format, *args): - self._logger.warning(format % args) - def _prep_OPTIONS(self, opts): ret = opts dc=self.IFACE_CLASS @@ -142,7 +137,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): except DAV_Error, (ec,dd): pass except Exception,e: - self.log_error("Error at options: %s", str(e)) + _logger.warning("Error at options: %s", str(e)) raise return ret @@ -245,7 +240,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): try: location = dc.put(uri, body, ct) except DAV_Error, (ec,dd): - self.log_error("Cannot PUT to %s: %s", uri, dd) + _logger.warning("Cannot PUT to %s: %s", uri, dd) return self.send_status(ec) headers = {} @@ -284,7 +279,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): """ Unlocks given resource """ dc = self.IFACE_CLASS - self.log_message('UNLOCKing resource %s' % self.headers) + _logger.log(netsvc.logging.DEBUG_RPC, 'UNLOCKing resource %s' % self.headers) uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) @@ -318,7 +313,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): dc = self.IFACE_CLASS lock_data = {} - self.log_message('LOCKing resource %s' % self.headers) + _logger.log(netsvc.logging.DEBUG_RPC, 'LOCKing resource %s' % self.headers) body = None if self.headers.has_key('Content-Length'): @@ -329,7 +324,7 @@ class DAVHandler(HttpOptions, FixSendError, DAVRequestHandler): uri = urlparse.urljoin(self.get_baseuri(dc), self.path) uri = urllib.unquote(uri) - self.log_message('do_LOCK: uri = %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'do_LOCK: uri = %s' % uri) ifheader = self.headers.get('If') @@ -477,7 +472,7 @@ class dummy_dav_interface(object): uri2 = uri.split('/') if len(uri2) < 3: return True - logging.getLogger('webdav').debug("Requested uri: %s", uri) + _logger.debug("Requested uri: %s", uri) return None # no def is_collection(self, uri): @@ -532,7 +527,7 @@ class DAVStaticHandler(http_server.StaticHTTPHandler): except DAV_Error, (ec,dd): return self.send_error(ec,dd) except Exception: - self.log_exception("Cannot PROPFIND") + _logger.exception("Cannot PROPFIND") raise # work around MSIE DAV bug for creation and modified date @@ -573,7 +568,7 @@ try: conf = OpenDAVConfig(**_dc) handler._config = conf reg_http_service(directory, DAVHandler, DAVAuthProvider) - logging.getLogger('webdav').info("WebDAV service registered at path: %s/ "% directory) + _logger.info("WebDAV service registered at path: %s/ ", directory) if not (config.get_misc('webdav', 'no_root_hack', False)): # Now, replace the static http handler with the dav-enabled one. @@ -595,7 +590,7 @@ try: reg_http_service('/', DAVStaticHandler) except Exception, e: - logging.getLogger('webdav').error('Cannot launch webdav: %s' % e) + _logger.error('Cannot launch webdav: %s', e) def init_well_known(): @@ -639,9 +634,9 @@ def init_principals_redirect(): if dbname: PrincipalsRedirect.redirect_paths[''] = '/webdav/%s/principals' % dbname reg_http_service('/principals', PrincipalsRedirect) - logging.getLogger("web-services").info( - "Registered HTTP redirect handler for /principals to the %s db.", - dbname) + _logger.info( + "Registered HTTP redirect handler for /principals to the %s db.", + dbname) init_principals_redirect() From 85f0ad1ea87f017a375d187d6d92cbdfffba61c7 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 24 Jan 2012 16:57:59 +0100 Subject: [PATCH 002/703] [IMP] document_webdav.webdav_server: remove the so called `uniform log handling` of the HttpLogHandler class. bzr revid: vmt@openerp.com-20120124155759-6g40dmhz6ywk9xe9 --- addons/document_webdav/dav_fs.py | 57 +++++++++++++++--------------- addons/document_webdav/redirect.py | 10 +++--- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/addons/document_webdav/dav_fs.py b/addons/document_webdav/dav_fs.py index 772b7600f20..a292019eeab 100644 --- a/addons/document_webdav/dav_fs.py +++ b/addons/document_webdav/dav_fs.py @@ -175,7 +175,7 @@ class openerp_dav_handler(dav_interface): def get_propnames(self, uri): props = self.PROPS - self.parent.log_message('get propnames: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'get propnames: %s' % uri) cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() @@ -203,21 +203,21 @@ class openerp_dav_handler(dav_interface): except NotImplementedError, e: if cr: cr.close() import traceback - self.parent.log_error("Cannot %s: %s", opname, str(e)) - self.parent.log_message("Exc: %s",traceback.format_exc()) + _logger.warning("Cannot %s: %s", opname, str(e)) + _logger.log(netsvc.logging.DEBUG_RPC, "Exc: %s" % traceback.format_exc()) # see par 9.3.1 of rfc raise DAV_Error(403, str(e) or 'Not supported at this path') except EnvironmentError, err: if cr: cr.close() import traceback - self.parent.log_error("Cannot %s: %s", opname, err.strerror) - self.parent.log_message("Exc: %s",traceback.format_exc()) + _logger.warning("Cannot %s: %s", opname, err.strerror) + _logger.log(netsvc.logging.DEBUG_RPC, "Exc: %s" % traceback.format_exc()) raise default_exc(err.strerror) except Exception, e: import traceback if cr: cr.close() - self.parent.log_error("Cannot %s: %s", opname, str(e)) - self.parent.log_message("Exc: %s",traceback.format_exc()) + _logger.warning("Cannot %s: %s", opname, str(e)) + _logger.log(netsvc.logging.DEBUG_RPC, "Exc: %s" % traceback.format_exc()) raise default_exc("Operation failed") def _get_dav_lockdiscovery(self, uri): @@ -245,7 +245,7 @@ class openerp_dav_handler(dav_interface): def prep_http_options(self, uri, opts): """see HttpOptions._prep_OPTIONS """ - self.parent.log_message('get options: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'get options: %s' % uri) cr, uid, pool, dbname, uri2 = self.get_cr(uri, allow_last=True) if not dbname: @@ -268,7 +268,7 @@ class openerp_dav_handler(dav_interface): ret[key] = [] ret[key].extend(val) - self.parent.log_message('options: %s' % ret) + _logger.log(netsvc.logging.DEBUG_RPC, 'options: %s' % ret) else: ret = opts cr.close() @@ -369,7 +369,7 @@ class openerp_dav_handler(dav_interface): if res and len(res): self.db_name_list.append(db_name) except Exception, e: - self.parent.log_error("Exception in db list: %s" % e) + _logger.warning("Exception in db list: %s", e) finally: if cr: cr.close() @@ -377,7 +377,7 @@ class openerp_dav_handler(dav_interface): def get_childs(self,uri, filters=None): """ return the child objects as self.baseuris for the given URI """ - self.parent.log_message('get children: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'get children: %s' % uri) cr, uid, pool, dbname, uri2 = self.get_cr(uri, allow_last=True) if not dbname: @@ -394,7 +394,7 @@ class openerp_dav_handler(dav_interface): fp = node.full_path() if fp and len(fp): fp = '/'.join(fp) - self.parent.log_message('children for: %s' % fp) + _logger.log(netsvc.logging.DEBUG_RPC, 'children for: %s' % fp) else: fp = None domain = None @@ -420,13 +420,13 @@ class openerp_dav_handler(dav_interface): if turi.startswith(ul): result.append( turi[len(self.parent.davpath):]) else: - self.parent.log_error("ignore href %s because it is not under request path %s", turi, ul) + _logger.warning("ignore href %s because it is not under request path %s", turi, ul) return result # We don't want to continue with the children found below # Note the exceptions and that 'finally' will close the # cursor for d in node.children(cr, domain): - self.parent.log_message('child: %s' % d.path) + _logger.log(netsvc.logging.DEBUG_RPC, 'child: %s' % d.path) if fp: result.append( self.urijoin(dbname,fp,d.path) ) else: @@ -434,7 +434,7 @@ class openerp_dav_handler(dav_interface): except DAV_Error: raise except Exception, e: - self.parent.log_error("cannot get_children: "+ str(e)) + _logger.warning("cannot get_children: "+ str(e)) raise finally: if cr: cr.close() @@ -479,7 +479,7 @@ class openerp_dav_handler(dav_interface): return pool.get('document.directory').get_object(cr, uid, uri, context=context) def get_data(self,uri, rrange=None): - self.parent.log_message('GET: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'GET: %s' % uri) cr, uid, pool, dbname, uri2 = self.get_cr(uri) try: if not dbname: @@ -499,7 +499,7 @@ class openerp_dav_handler(dav_interface): start = 0 assert start >= 0 if end and end < start: - self.parent.log_error("Invalid range for data: %s-%s" %(start, end)) + _logger.warning("Invalid range for data: %s-%s" %(start, end)) raise DAV_Error(416, "Invalid range for data") if end: if end >= res.size(): @@ -514,12 +514,12 @@ class openerp_dav_handler(dav_interface): # says we'd better just return 200 OK with empty data return '' except IndexError,e : - self.parent.log_error("GET IndexError: %s", str(e)) + _logger.warning("GET IndexError: %s", str(e)) raise DAV_NotFound2(uri2) except Exception,e: import traceback - self.parent.log_error("GET exception: %s",str(e)) - self.parent.log_message("Exc: %s", traceback.format_exc()) + _logger.warning("GET exception: %s",str(e)) + _logger.log(netsvc.logging.DEBUG_RPC, "Exc: %s" % traceback.format_exc()) raise DAV_Error, 409 return res finally: @@ -528,7 +528,7 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def _get_dav_resourcetype(self, uri): """ return type of object """ - self.parent.log_message('get RT: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'get RT: %s' % uri) cr, uid, pool, dbname, uri2 = self.get_cr(uri) try: if not dbname: @@ -546,7 +546,7 @@ class openerp_dav_handler(dav_interface): if cr: cr.close() def _get_dav_displayname(self,uri): - self.parent.log_message('get DN: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'get DN: %s' % uri) cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() @@ -565,7 +565,7 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def _get_dav_getcontentlength(self, uri): """ return the content length of an object """ - self.parent.log_message('get length: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'get length: %s' % uri) result = 0 cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: @@ -582,7 +582,7 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def _get_dav_getetag(self,uri): """ return the ETag of an object """ - self.parent.log_message('get etag: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'get etag: %s' % uri) result = 0 cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: @@ -638,7 +638,7 @@ class openerp_dav_handler(dav_interface): @memoize(CACHE_SIZE) def _get_dav_getcontenttype(self,uri): - self.parent.log_message('get contenttype: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'get contenttype: %s' % uri) cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() @@ -657,7 +657,7 @@ class openerp_dav_handler(dav_interface): """ create a new collection see par. 9.3 of rfc4918 """ - self.parent.log_message('MKCOL: %s' % uri) + _logger.log(netsvc.logging.DEBUG_RPC, 'MKCOL: %s' % uri) cr, uid, pool, dbname, uri2 = self.get_cr(uri) if not uri2[-1]: if cr: cr.close() @@ -681,7 +681,8 @@ class openerp_dav_handler(dav_interface): def put(self, uri, data, content_type=None): """ put the object into the filesystem """ - self.parent.log_message('Putting %s (%d), %s'%( misc.ustr(uri), data and len(data) or 0, content_type)) + _logger.log(netsvc.logging.DEBUG_RPC, 'Putting %s (%d), %s' % \ + (misc.ustr(uri), data and len(data) or 0, content_type)) cr, uid, pool,dbname, uri2 = self.get_cr(uri) if not dbname: if cr: cr.close() @@ -723,7 +724,7 @@ class openerp_dav_handler(dav_interface): try: etag = str(newchild.get_etag(cr)) except Exception, e: - self.parent.log_error("Cannot get etag for node: %s" % e) + _logger.warning("Cannot get etag for node: %s", e) ret = (str(hurl), etag) else: self._try_function(node.set_data, (cr, data), "save %s" % objname, cr=cr) diff --git a/addons/document_webdav/redirect.py b/addons/document_webdav/redirect.py index 7bc0883f9e8..7d04ffb51f5 100644 --- a/addons/document_webdav/redirect.py +++ b/addons/document_webdav/redirect.py @@ -23,10 +23,10 @@ import logging import urlparse from service.websrv_lib import FixSendError, HTTPHandler, HttpOptions -from service.http_server import HttpLogHandler -class RedirectHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler): - _logger = logging.getLogger('httpd.well-known') +_logger = logging.getLogger(__name__) + +class RedirectHTTPHandler(FixSendError, HttpOptions, HTTPHandler): _HTTP_OPTIONS = { 'Allow': ['OPTIONS', 'GET', 'HEAD', 'PROPFIND'] } redirect_paths = {} @@ -62,7 +62,7 @@ class RedirectHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler try: addr, port = self.request.getsockname() except Exception, e: - self.log_error("Cannot calculate own address:" , e) + _logger.error("Cannot calculate own address:", e) if self.headers.has_key('Host'): uparts = list(urlparse.urlparse("%s://%s:%d"% (server_proto, addr,port))) @@ -80,7 +80,7 @@ class RedirectHTTPHandler(HttpLogHandler, FixSendError, HttpOptions, HTTPHandler self.send_header("Content-Length", 0) self.end_headers() # Do we need a Cache-content: header here? - self._logger.debug("redirecting %s to %s", self.path, redir_path) + _logger.debug("redirecting %s to %s", self.path, redir_path) return None def do_PROPFIND(self): From 7c4e08eb46a20e37ac490e6c2d4b916d56b8f63b Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Tue, 24 Jan 2012 17:28:50 +0100 Subject: [PATCH 003/703] [IMP] account,document: changed from class __logger to module _logger. bzr revid: vmt@openerp.com-20120124162850-qr1or3piq9f91c7u --- addons/account/installer.py | 5 +++-- addons/document/content_index.py | 16 ++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/addons/account/installer.py b/addons/account/installer.py index d1b19ef4319..a9122adf488 100644 --- a/addons/account/installer.py +++ b/addons/account/installer.py @@ -31,10 +31,11 @@ from osv import fields, osv import netsvc import tools +_logger = logging.getLogger(__name__) + class account_installer(osv.osv_memory): _name = 'account.installer' _inherit = 'res.config.installer' - __logger = logging.getLogger(_name) def _get_charts(self, cr, uid, context=None): modules = self.pool.get('ir.module.module') @@ -142,7 +143,7 @@ class account_installer(osv.osv_memory): cr, uid, ids, context=context) chart = self.read(cr, uid, ids, ['charts'], context=context)[0]['charts'] - self.__logger.debug('Installing chart of accounts %s', chart) + _logger.debug('Installing chart of accounts %s', chart) return modules | set([chart]) account_installer() diff --git a/addons/document/content_index.py b/addons/document/content_index.py index 64b480ee736..3cb408428c9 100644 --- a/addons/document/content_index.py +++ b/addons/document/content_index.py @@ -23,10 +23,11 @@ import os import tempfile from subprocess import Popen, PIPE +_logger = logging.getLogger(__name__) + class NhException(Exception): pass - class indexer(object): """ An indexer knows how to parse the content of some file. @@ -116,7 +117,6 @@ def mime_match(mime, mdict): return (None, None) class contentIndex(object): - __logger = logging.getLogger('addons.document.content_index') def __init__(self): self.mimes = {} self.exts = {} @@ -132,7 +132,7 @@ class contentIndex(object): f = True if f: - self.__logger.debug('Register content indexer: %r', obj) + _logger.debug('Register content indexer: %r', obj) if not f: raise Exception("Your indexer should at least suport a mimetype or extension") @@ -169,22 +169,22 @@ class contentIndex(object): (result, _) = pop.communicate() mime2 = result.split(';')[0] - self.__logger.debug('File gave us: %s', mime2) + _logger.debug('File gave us: %s', mime2) # Note that the temporary file still exists now. mime,fobj = mime_match(mime2, self.mimes) if not mime: mime = mime2 except Exception: - self.__logger.exception('Cannot determine mime type') + _logger.exception('Cannot determine mime type') try: if fobj: res = (mime, fobj.indexContent(content,filename,fname or realfname) ) else: - self.__logger.debug("Have no object, return (%s, None)", mime) + _logger.debug("Have no object, return (%s, None)", mime) res = (mime, None ) except Exception: - self.__logger.exception("Could not index file %s (%s)", + _logger.exception("Could not index file %s (%s)", filename, fname or realfname) res = None @@ -193,7 +193,7 @@ class contentIndex(object): try: os.unlink(fname) except Exception: - self.__logger.exception("Could not unlink %s", fname) + _logger.exception("Could not unlink %s", fname) return res From 57b41aae43f0f2626f08e3e212aad4bab0394d42 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 25 Jan 2012 10:44:51 +0100 Subject: [PATCH 004/703] [IMP] logging: use logging instead of netsvc, use module __name__ instead of something else. bzr revid: vmt@openerp.com-20120125094451-a6mejmnaxa2vp1bu --- addons/account/account.py | 20 +- .../report/bank_statement_balance_report.py | 4 - addons/account_coda/account_coda.py | 5 +- .../wizard/account_coda_import.py | 26 +- addons/account_payment/account_payment.py | 7 +- .../wizard/wizard_tech_guide_rst.py | 25 +- .../base_module_quality.py | 21 +- addons/document/document.py | 6 +- addons/document/document_directory.py | 7 +- addons/document/document_storage.py | 63 ++- addons/document/nodes.py | 24 +- addons/document/std_index.py | 7 +- addons/document_ftp/ftpserver/__init__.py | 10 +- addons/edi/__init__.py | 2 +- addons/edi/edi_service.py | 2 +- addons/edi/models/edi.py | 6 +- addons/edi/models/res_partner.py | 6 +- addons/fetchmail/fetchmail.py | 14 +- addons/import_base/import_framework.py | 15 +- addons/l10n_be_invoice_bba/invoice.py | 433 +++++++++--------- addons/l10n_be_invoice_bba/partner.py | 5 +- addons/l10n_multilang/l10n_multilang.py | 13 +- addons/mail/mail_message.py | 2 +- addons/mail/mail_thread.py | 3 - addons/project_messages/project_messages.py | 2 - addons/report_webkit/webkit_report.py | 11 +- addons/stock/stock.py | 6 +- 27 files changed, 369 insertions(+), 376 deletions(-) diff --git a/addons/account/account.py b/addons/account/account.py index 432a90a653e..2b1834002e7 100644 --- a/addons/account/account.py +++ b/addons/account/account.py @@ -19,17 +19,19 @@ # ############################################################################## -import time from datetime import datetime from dateutil.relativedelta import relativedelta +import logging from operator import itemgetter +import time -import netsvc -import pooler -from osv import fields, osv import decimal_precision as dp +from osv import fields, osv +import pooler from tools.translate import _ +_logger = logging.getLogger(__name__) + def check_cycle(self, cr, uid, ids, context=None): """ climbs the ``self._table.parent_id`` chains for 100 levels or until it can't find any more parent(s) @@ -212,7 +214,6 @@ class account_account(osv.osv): _name = "account.account" _description = "Account" _parent_store = True - logger = netsvc.Logger() def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): @@ -295,8 +296,7 @@ class account_account(osv.osv): if aml_query.strip(): wheres.append(aml_query.strip()) filters = " AND ".join(wheres) - self.logger.notifyChannel('addons.'+self._name, netsvc.LOG_DEBUG, - 'Filters: %s'%filters) + _logger.debug('Filters: %s', filters) # IN might not work ideally in case there are too many # children_and_consolidated, in that case join on a # values() e.g.: @@ -312,8 +312,7 @@ class account_account(osv.osv): " GROUP BY l.account_id") params = (tuple(children_and_consolidated),) + query_params cr.execute(request, params) - self.logger.notifyChannel('addons.'+self._name, netsvc.LOG_DEBUG, - 'Status: %s'%cr.statusmessage) + _logger.debug('Status: %s', cr.statusmessage) for res in cr.dictfetchall(): accounts[res['id']] = res @@ -2083,8 +2082,7 @@ class account_tax(osv.osv): } def compute(self, cr, uid, taxes, price_unit, quantity, address_id=None, product=None, partner=None): - logger = netsvc.Logger() - logger.notifyChannel("warning", netsvc.LOG_WARNING, + _logger.warning( "Deprecated, use compute_all(...)['taxes'] instead of compute(...) to manage prices with tax included") return self._compute(cr, uid, taxes, price_unit, quantity, address_id, product, partner) diff --git a/addons/account_bank_statement_extensions/report/bank_statement_balance_report.py b/addons/account_bank_statement_extensions/report/bank_statement_balance_report.py index 8e1e4b09e47..50b5bcd8d36 100644 --- a/addons/account_bank_statement_extensions/report/bank_statement_balance_report.py +++ b/addons/account_bank_statement_extensions/report/bank_statement_balance_report.py @@ -22,14 +22,10 @@ import time from report import report_sxw -import pooler -import netsvc -logger=netsvc.Logger() class bank_statement_balance_report(report_sxw.rml_parse): def set_context(self, objects, data, ids, report_type=None): - #logger.notifyChannel('addons.'+__name__, netsvc.LOG_WARNING, 'set_context, objects = %s, data = %s, ids = %s' % (objects, data, ids)) cr = self.cr uid = self.uid context = self.context diff --git a/addons/account_coda/account_coda.py b/addons/account_coda/account_coda.py index f967669b98e..b4723794578 100644 --- a/addons/account_coda/account_coda.py +++ b/addons/account_coda/account_coda.py @@ -21,11 +21,10 @@ ############################################################################## import time -from osv import osv, fields + import decimal_precision as dp -import netsvc +from osv import osv, fields from tools.translate import _ -logger=netsvc.Logger() class coda_bank_account(osv.osv): _name= 'coda.bank.account' diff --git a/addons/account_coda/wizard/account_coda_import.py b/addons/account_coda/wizard/account_coda_import.py index 02e72bc3562..ac9a623e2fc 100644 --- a/addons/account_coda/wizard/account_coda_import.py +++ b/addons/account_coda/wizard/account_coda_import.py @@ -20,15 +20,16 @@ # ############################################################################## -import time import base64 +import re +from sys import exc_info +import time +from traceback import format_exception + from osv import fields,osv from tools.translate import _ -import netsvc -import re -from traceback import format_exception -from sys import exc_info -logger=netsvc.Logger() + +_logger = logging.getLogger(__name__) class account_coda_import(osv.osv_memory): _name = 'account.coda.import' @@ -816,7 +817,6 @@ class account_coda_import(osv.osv_memory): ttype = line['type'] == 'supplier' and 'payment' or 'receipt', date = line['val_date'], context = context) - #logger.notifyChannel('addons.'+self._name, netsvc.LOG_WARNING, 'voucher_dict = %s' % voucher_dict) voucher_line_vals = False if voucher_dict['value']['line_ids']: for line_dict in voucher_dict['value']['line_ids']: @@ -889,22 +889,22 @@ class account_coda_import(osv.osv_memory): nb_err += 1 err_string += _('\nError ! ') + str(e) tb = ''.join(format_exception(*exc_info())) - logger.notifyChannel('addons.'+self._name, netsvc.LOG_ERROR, - 'Application Error while processing Statement %s\n%s' % (statement.get('name', '/'),tb)) + _logger.error('Application Error while processing Statement %s\n%s', + statement.get('name', '/'), tb) except Exception, e: cr.rollback() nb_err += 1 err_string += _('\nSystem Error : ') + str(e) tb = ''.join(format_exception(*exc_info())) - logger.notifyChannel('addons.'+self._name, netsvc.LOG_ERROR, - 'System Error while processing Statement %s\n%s' % (statement.get('name', '/'),tb)) + _logger.error('System Error while processing Statement %s\n%s', + statement.get('name', '/'), tb) except : cr.rollback() nb_err += 1 err_string = _('\nUnknown Error : ') + str(e) tb = ''.join(format_exception(*exc_info())) - logger.notifyChannel('addons.'+self._name, netsvc.LOG_ERROR, - 'Unknown Error while processing Statement %s\n%s' % (statement.get('name', '/'),tb)) + _logger.error('Unknown Error while processing Statement %s\n%s', + statement.get('name', '/'), tb) # end 'for statement in coda_statements' diff --git a/addons/account_payment/account_payment.py b/addons/account_payment/account_payment.py index 1de715dc777..11d4f98af8f 100644 --- a/addons/account_payment/account_payment.py +++ b/addons/account_payment/account_payment.py @@ -19,11 +19,14 @@ # ############################################################################## +import logging import time from osv import osv, fields import netsvc +_logger = logging.getLogger(__name__) + class payment_mode(osv.osv): _name= 'payment.mode' _description= 'Payment Mode' @@ -70,9 +73,7 @@ class payment_order(osv.osv): #dead code def get_wizard(self, type): - logger = netsvc.Logger() - logger.notifyChannel("warning", netsvc.LOG_WARNING, - "No wizard found for the payment type '%s'." % type) + _logger.warning("No wizard found for the payment type '%s'.", type) return None def _total(self, cursor, user, ids, name, args, context=None): diff --git a/addons/base_module_doc_rst/wizard/wizard_tech_guide_rst.py b/addons/base_module_doc_rst/wizard/wizard_tech_guide_rst.py index 39933c39a3e..9f4c75918b9 100644 --- a/addons/base_module_doc_rst/wizard/wizard_tech_guide_rst.py +++ b/addons/base_module_doc_rst/wizard/wizard_tech_guide_rst.py @@ -18,17 +18,18 @@ # along with this program. If not, see . # ############################################################################## -from os.path import join import base64 -import tempfile -import tarfile import httplib +import logging +import os +from os.path import join +import tarfile +import tempfile -import netsvc import wizard import pooler -import os -import tools + +_logger = logging.getLogger(__name__) choose_file_form = '''
@@ -99,9 +100,8 @@ class RstDoc(object): if res.status in (200, ): status_good = True except (Exception, ), e: - logger = netsvc.Logger() msg = "error connecting to server '%s' with link '%s'. Error message: %s" % (server, link, str(e)) - logger.notifyChannel("base_module_doc_rst", netsvc.LOG_ERROR, msg) + _logger.error(msg) status_good = False return status_good @@ -241,9 +241,8 @@ class RstDoc(object): def _write_objects(self): def write_field(field_def): if not isinstance(field_def, tuple): - logger = netsvc.Logger() msg = "Error on Object %s: field_def: %s [type: %s]" % (obj_name.encode('utf8'), field_def.encode('utf8'), type(field_def)) - logger.notifyChannel("base_module_doc_rst", netsvc.LOG_ERROR, msg) + _logger.error(msg) return "" field_name = field_def[0] @@ -392,9 +391,8 @@ class wizard_tech_guide_rst(wizard.interface): try: os.unlink(tgz_tmp_filename) except Exception, e: - logger = netsvc.Logger() msg = "Temporary file %s could not be deleted. (%s)" % (tgz_tmp_filename, e) - logger.notifyChannel("warning", netsvc.LOG_WARNING, msg) + _logger.warning(msg) return { 'rst_file': base64.encodestring(out), @@ -483,9 +481,8 @@ class wizard_tech_guide_rst(wizard.interface): res = modobj.fields_get(cr, uid).items() return res else: - logger = netsvc.Logger() msg = "Object %s not found" % (obj) - logger.notifyChannel("base_module_doc_rst", netsvc.LOG_ERROR, msg) + _logger.error(msg) return "" states = { diff --git a/addons/base_module_quality/base_module_quality.py b/addons/base_module_quality/base_module_quality.py index bbe20bc0b4f..76a9214c10d 100644 --- a/addons/base_module_quality/base_module_quality.py +++ b/addons/base_module_quality/base_module_quality.py @@ -25,6 +25,9 @@ from tools.translate import _ from osv import osv, fields import logging import addons + +_logger = logging.getLogger(__name__) + class abstract_quality_check(object): ''' This Class is abstract class for all test @@ -78,7 +81,6 @@ class abstract_quality_check(object): #This variable used to give message if test result is good or not self.message = '' - self.log = logging.getLogger('module.quality') #The tests have to subscribe itselfs in this list, that contains #all the test that have to be performed. @@ -108,11 +110,11 @@ class abstract_quality_check(object): model_data = pool.get('ir.model.data').browse(cr, uid, ids2) for model in model_data: model_list.append(model.res_id) - self.log.debug('get_objects() model_list: %s', ','.join(map(str, model_list))) + _logger.debug('get_objects() model_list: %s', ','.join(map(str, model_list))) obj_list = [] for mod in pool.get('ir.model').browse(cr, uid, model_list): obj_list.append(str(mod.model)) - self.log.debug('get_objects() obj_list: %s', ','.join(obj_list)) + _logger.debug('get_objects() obj_list: %s', ','.join(obj_list)) return obj_list def get_model_ids(self, cr, uid, models=[]): @@ -120,7 +122,7 @@ class abstract_quality_check(object): if not models: return [] pool = pooler.get_pool(cr.dbname) - self.log.debug('get_model_ids([%s])', ', '.join(models)) + _logger.debug('get_model_ids([%s])', ', '.join(models)) return pool.get('ir.model').search(cr, uid, [('model', 'in', models)]) def get_ids(self, cr, uid, object_list): @@ -211,7 +213,6 @@ class module_quality_check(osv.osv): So here the detail result is in html format and summary will be in text_wiki format. ''' pool = pooler.get_pool(cr.dbname) - log = logging.getLogger('module.quality') obj_module = pool.get('ir.module.module') if not module_state: module_id = obj_module.search(cr, uid, [('name', '=', module_name)]) @@ -223,14 +224,14 @@ class module_quality_check(osv.osv): ponderation_sum = 0.0 create_ids = [] module_path = addons.get_module_path(module_name) - log.info('Performing quality tests for %s', module_name) + _logger.info('Performing quality tests for %s', module_name) for test in abstract_obj.tests: val = test.quality_test() if not val.active: - log.info('Skipping inactive step %s for %s', val.name, module_name) + _logger.info('Skipping inactive step %s for %s', val.name, module_name) continue - log.info('Performing step %s for %s', val.name, module_name) + _logger.info('Performing step %s for %s', val.name, module_name) # Get a separate cursor per test, so that an SQL error in one # will not block the others. cr2 = pooler.get_db(cr.dbname).cursor() @@ -269,9 +270,9 @@ class module_quality_check(osv.osv): 'summary': _("The module has to be installed before running this test.") } create_ids.append((0, 0, data)) - log.info('Finished quality test step') + _logger.info('Finished quality test step') except Exception, e: - log.exception("Could not finish test step %s due to %s", val.name, e) + _logger.exception("Could not finish test step %s due to %s", val.name, e) finally: cr2.rollback() cr2.close() diff --git a/addons/document/document.py b/addons/document/document.py index 9ea7f97a321..e6fe4cde13d 100644 --- a/addons/document/document.py +++ b/addons/document/document.py @@ -30,6 +30,8 @@ from tools.translate import _ import nodes import logging +_logger = logging.getLogger(__name__) + DMS_ROOT_PATH = tools.config.get('document_path', os.path.join(tools.config['root_path'], 'filestore')) class document_file(osv.osv): @@ -54,7 +56,7 @@ class document_file(osv.osv): parent_id = self.pool.get('document.directory')._get_root_directory(cr,uid) if not parent_id: - logging.getLogger('document').warning("at _attach_parent_id(), still not able to set the parent!") + _logger.warning("at _attach_parent_id(), still not able to set the parent!") return False if ids is not None: @@ -339,7 +341,7 @@ class document_file(osv.osv): if r: unres.append(r) else: - logging.getLogger('document').warning("Unlinking attachment #%s %s that has no storage", + _logger.warning("Unlinking attachment #%s %s that has no storage", f.id, f.name) res = super(document_file, self).unlink(cr, uid, ids, context) stor.do_unlink(cr, uid, unres) diff --git a/addons/document/document_directory.py b/addons/document/document_directory.py index d09d2cc86d5..787888cd4ee 100644 --- a/addons/document/document_directory.py +++ b/addons/document/document_directory.py @@ -19,6 +19,7 @@ # ############################################################################## +import logging from osv import osv, fields from osv.orm import except_orm @@ -26,6 +27,8 @@ from osv.orm import except_orm import nodes from tools.translate import _ +_logger = logging.getLogger(__name__) + class document_directory(osv.osv): _name = 'document.directory' _description = 'Directory' @@ -78,9 +81,7 @@ class document_directory(osv.osv): root_id = objid.read(cr, uid, mid, ['res_id'])['res_id'] return root_id except Exception, e: - import netsvc - logger = netsvc.Logger() - logger.notifyChannel("document", netsvc.LOG_WARNING, 'Cannot set directory root:'+ str(e)) + _logger.warning('Cannot set directory root:' + str(e)) return False return objid.browse(cr, uid, mid, context=context).res_id diff --git a/addons/document/document_storage.py b/addons/document/document_storage.py index fe757e7876d..577ea84f112 100644 --- a/addons/document/document_storage.py +++ b/addons/document/document_storage.py @@ -41,6 +41,8 @@ import pooler import nodes from content_index import cntIndex +_logger = logging.getLogger(__name__) + DMS_ROOT_PATH = tools.config.get('document_path', os.path.join(tools.config.get('root_path'), 'filestore')) @@ -130,7 +132,7 @@ class nodefd_file(nodes.node_descriptor): mime, icont = cntIndex.doIndex(None, filename=filename, content_type=None, realfname=fname) except Exception: - logging.getLogger('document.storage').debug('Cannot index file:', exc_info=True) + _logger.debug('Cannot index file:', exc_info=True) pass try: @@ -150,7 +152,7 @@ class nodefd_file(nodes.node_descriptor): cr.commit() cr.close() except Exception: - logging.getLogger('document.storage').warning('Cannot save file indexed content:', exc_info=True) + _logger.warning('Cannot save file indexed content:', exc_info=True) elif self.mode in ('a', 'a+' ): try: @@ -164,7 +166,7 @@ class nodefd_file(nodes.node_descriptor): cr.commit() cr.close() except Exception: - logging.getLogger('document.storage').warning('Cannot save file appended content:', exc_info=True) + _logger.warning('Cannot save file appended content:', exc_info=True) @@ -191,7 +193,7 @@ class nodefd_db(StringIO, nodes.node_descriptor): elif mode == 'a': StringIO.__init__(self, None) else: - logging.getLogger('document.storage').error("Incorrect mode %s specified", mode) + _logger.error("Incorrect mode %s specified", mode) raise IOError(errno.EINVAL, "Invalid file mode") self.mode = mode @@ -217,7 +219,7 @@ class nodefd_db(StringIO, nodes.node_descriptor): mime, icont = cntIndex.doIndex(data, filename=filename, content_type=None, realfname=None) except Exception: - logging.getLogger('document.storage').debug('Cannot index file:', exc_info=True) + _logger.debug('Cannot index file:', exc_info=True) pass try: @@ -241,7 +243,7 @@ class nodefd_db(StringIO, nodes.node_descriptor): (out, len(data), par.file_id)) cr.commit() except Exception: - logging.getLogger('document.storage').exception('Cannot update db file #%d for close:', par.file_id) + _logger.exception('Cannot update db file #%d for close:', par.file_id) raise finally: cr.close() @@ -271,7 +273,7 @@ class nodefd_db64(StringIO, nodes.node_descriptor): elif mode == 'a': StringIO.__init__(self, None) else: - logging.getLogger('document.storage').error("Incorrect mode %s specified", mode) + _logger.error("Incorrect mode %s specified", mode) raise IOError(errno.EINVAL, "Invalid file mode") self.mode = mode @@ -297,7 +299,7 @@ class nodefd_db64(StringIO, nodes.node_descriptor): mime, icont = cntIndex.doIndex(data, filename=filename, content_type=None, realfname=None) except Exception: - logging.getLogger('document.storage').debug('Cannot index file:', exc_info=True) + _logger.debug('Cannot index file:', exc_info=True) pass try: @@ -320,7 +322,7 @@ class nodefd_db64(StringIO, nodes.node_descriptor): (base64.encodestring(data), len(data), par.file_id)) cr.commit() except Exception: - logging.getLogger('document.storage').exception('Cannot update db file #%d for close:', par.file_id) + _logger.exception('Cannot update db file #%d for close:', par.file_id) raise finally: cr.close() @@ -339,7 +341,6 @@ class document_storage(osv.osv): """ _name = 'document.storage' _description = 'Storage Media' - _doclog = logging.getLogger('document') _columns = { 'name': fields.char('Name', size=64, required=True, select=1), @@ -401,8 +402,6 @@ class document_storage(osv.osv): # npath may contain empty elements, for root directory etc. npath = filter(lambda x: x is not None, npath) - # if self._debug: - # self._doclog.debug('Npath: %s', npath) for n in npath: if n == '..': raise ValueError("Invalid '..' element in path") @@ -413,7 +412,7 @@ class document_storage(osv.osv): dpath += npath[:-1] path = os.path.join(*dpath) if not os.path.isdir(path): - self._doclog.debug("Create dirs: %s", path) + _logger.debug("Create dirs: %s", path) os.makedirs(path) return path, npath @@ -451,7 +450,7 @@ class document_storage(osv.osv): # try to fix their directory. if mode in ('r','r+'): if ira.file_size: - self._doclog.warning( "ir.attachment #%d does not have a filename, but is at filestore, fix it!" % ira.id) + _logger.warning( "ir.attachment #%d does not have a filename, but is at filestore, fix it!" % ira.id) raise IOError(errno.ENOENT, 'No file can be located') else: store_fname = self.__get_random_fname(boo.path) @@ -493,7 +492,7 @@ class document_storage(osv.osv): # On a migrated db, some files may have the wrong storage type # try to fix their directory. if ira.file_size: - self._doclog.warning( "ir.attachment #%d does not have a filename, but is at filestore, fix it!" % ira.id) + _logger.warning( "ir.attachment #%d does not have a filename, but is at filestore, fix it!" % ira.id) return None fpath = os.path.join(boo.path, ira.store_fname) return file(fpath, 'rb').read() @@ -517,7 +516,7 @@ class document_storage(osv.osv): # On a migrated db, some files may have the wrong storage type # try to fix their directory. if ira.file_size: - self._doclog.warning("ir.attachment #%d does not have a filename, trying the name." %ira.id) + _logger.warning("ir.attachment #%d does not have a filename, trying the name." %ira.id) # sfname = ira.name fpath = os.path.join(boo.path,ira.store_fname or ira.name) if os.path.exists(fpath): @@ -550,7 +549,7 @@ class document_storage(osv.osv): if boo.readonly: raise IOError(errno.EPERM, "Readonly medium") - self._doclog.debug( "Store data for ir.attachment #%d" % ira.id) + _logger.debug( "Store data for ir.attachment #%d" % ira.id) store_fname = None fname = None if boo.type == 'filestore': @@ -563,13 +562,13 @@ class document_storage(osv.osv): fp.write(data) finally: fp.close() - self._doclog.debug( "Saved data to %s" % fname) + _logger.debug( "Saved data to %s" % fname) filesize = len(data) # os.stat(fname).st_size # TODO Here, an old file would be left hanging. except Exception, e: - self._doclog.warning( "Couldn't save data to %s", path, exc_info=True) + _logger.warning( "Couldn't save data to %s", path, exc_info=True) raise except_orm(_('Error!'), str(e)) elif boo.type == 'db': filesize = len(data) @@ -592,12 +591,12 @@ class document_storage(osv.osv): fp.write(data) finally: fp.close() - self._doclog.debug("Saved data to %s", fname) + _logger.debug("Saved data to %s", fname) filesize = len(data) # os.stat(fname).st_size store_fname = os.path.join(*npath) # TODO Here, an old file would be left hanging. except Exception,e : - self._doclog.warning("Couldn't save data:", exc_info=True) + _logger.warning("Couldn't save data:", exc_info=True) raise except_orm(_('Error!'), str(e)) elif boo.type == 'virtual': @@ -616,7 +615,7 @@ class document_storage(osv.osv): mime, icont = cntIndex.doIndex(data, ira.datas_fname, ira.file_type or None, fname) except Exception: - self._doclog.debug('Cannot index file:', exc_info=True) + _logger.debug('Cannot index file:', exc_info=True) pass try: @@ -633,7 +632,7 @@ class document_storage(osv.osv): file_node.content_type = mime return True except Exception, e : - self._doclog.warning("Couldn't save data:", exc_info=True) + _logger.warning("Couldn't save data:", exc_info=True) # should we really rollback once we have written the actual data? # at the db case (only), that rollback would be safe raise except_orm(_('Error at doc write!'), str(e)) @@ -671,9 +670,9 @@ class document_storage(osv.osv): try: os.unlink(fname) except Exception: - self._doclog.warning("Could not remove file %s, please remove manually.", fname, exc_info=True) + _logger.warning("Could not remove file %s, please remove manually.", fname, exc_info=True) else: - self._doclog.warning("Unknown unlink key %s" % ktype) + _logger.warning("Unknown unlink key %s" % ktype) return True @@ -703,9 +702,9 @@ class document_storage(osv.osv): fname = ira.store_fname if not fname: - self._doclog.warning("Trying to rename a non-stored file") + _logger.warning("Trying to rename a non-stored file") if fname != os.path.join(*npath): - self._doclog.warning("inconsistency in realstore: %s != %s" , fname, repr(npath)) + _logger.warning("inconsistency in realstore: %s != %s" , fname, repr(npath)) oldpath = os.path.join(path, npath[-1]) newpath = os.path.join(path, new_name) @@ -743,7 +742,7 @@ class document_storage(osv.osv): break par = par.parent_id if file_node.storage_id != psto: - self._doclog.debug('Cannot move file %r from %r to %r', file_node, file_node.parent, ndir_bro.name) + _logger.debug('Cannot move file %r from %r to %r', file_node, file_node.parent, ndir_bro.name) raise NotImplementedError('Cannot move files between storage media') if sbro.type in ('filestore', 'db', 'db64'): @@ -756,9 +755,9 @@ class document_storage(osv.osv): fname = ira.store_fname if not fname: - self._doclog.warning("Trying to rename a non-stored file") + _logger.warning("Trying to rename a non-stored file") if fname != os.path.join(*opath): - self._doclog.warning("inconsistency in realstore: %s != %s" , fname, repr(opath)) + _logger.warning("inconsistency in realstore: %s != %s" , fname, repr(opath)) oldpath = os.path.join(path, opath[-1]) @@ -766,12 +765,12 @@ class document_storage(osv.osv): npath = filter(lambda x: x is not None, npath) newdir = os.path.join(*npath) if not os.path.isdir(newdir): - self._doclog.debug("Must create dir %s", newdir) + _logger.debug("Must create dir %s", newdir) os.makedirs(newdir) npath.append(opath[-1]) newpath = os.path.join(*npath) - self._doclog.debug("Going to move %s from %s to %s", opath[-1], oldpath, newpath) + _logger.debug("Going to move %s from %s to %s", opath[-1], oldpath, newpath) shutil.move(oldpath, newpath) store_path = npath[1:] + [opath[-1],] diff --git a/addons/document/nodes.py b/addons/document/nodes.py index ee89f3d4c6c..15d23f11760 100644 --- a/addons/document/nodes.py +++ b/addons/document/nodes.py @@ -42,7 +42,7 @@ from StringIO import StringIO # root: if we are at the first directory of a ressource # -logger = logging.getLogger('doc2.nodes') +_logger = logging.getLogger(__name__) def _str2time(cre): """ Convert a string with time representation (from db) into time (float) @@ -328,7 +328,7 @@ class node_class(object): if self.DAV_M_NS.has_key(ns): prefix = self.DAV_M_NS[ns] else: - logger.debug('No namespace: %s ("%s")',ns, prop) + _logger.debug('No namespace: %s ("%s")',ns, prop) return None mname = prefix + "_" + prop.replace('-','_') @@ -341,7 +341,7 @@ class node_class(object): r = m(cr) return r except AttributeError: - logger.debug('Property %s not supported' % prop, exc_info=True) + _logger.debug('Property %s not supported' % prop, exc_info=True) return None def get_dav_resourcetype(self, cr): @@ -384,13 +384,13 @@ class node_class(object): def create_child(self, cr, path, data=None): """ Create a regular file under this node """ - logger.warning("Attempted to create a file under %r, not possible.", self) + _logger.warning("Attempted to create a file under %r, not possible.", self) raise IOError(errno.EPERM, "Not allowed to create files here") def create_child_collection(self, cr, objname): """ Create a child collection (directory) under self """ - logger.warning("Attempted to create a collection under %r, not possible.", self) + _logger.warning("Attempted to create a collection under %r, not possible.", self) raise IOError(errno.EPERM, "Not allowed to create folders here") def rm(self, cr): @@ -725,7 +725,7 @@ class node_dir(node_database): assert self.parent if self.parent != ndir_node: - logger.debug('Cannot move dir %r from %r to %r', self, self.parent, ndir_node) + _logger.debug('Cannot move dir %r from %r to %r', self, self.parent, ndir_node) raise NotImplementedError('Cannot move dir to another dir') ret = {} @@ -998,7 +998,7 @@ class node_res_obj(node_class): def get_dav_eprop_DEPR(self, cr, ns, prop): # Deprecated! if ns != 'http://groupdav.org/' or prop != 'resourcetype': - logger.warning("Who asked for %s:%s?" % (ns, prop)) + _logger.warning("Who asked for %s:%s?" % (ns, prop)) return None cntobj = self.context._dirobj.pool.get('document.directory.content') uid = self.context.uid @@ -1328,7 +1328,7 @@ class node_file(node_class): ret = {} if ndir_node and self.parent != ndir_node: if not (isinstance(self.parent, node_dir) and isinstance(ndir_node, node_dir)): - logger.debug('Cannot move file %r from %r to %r', self, self.parent, ndir_node) + _logger.debug('Cannot move file %r from %r to %r', self, self.parent, ndir_node) raise NotImplementedError('Cannot move files between dynamic folders') if not ndir_obj: @@ -1473,7 +1473,7 @@ class nodefd_content(StringIO, node_descriptor): elif mode == 'a': StringIO.__init__(self, None) else: - logging.getLogger('document.content').error("Incorrect mode %s specified", mode) + _logger.error("Incorrect mode %s specified", mode) raise IOError(errno.EINVAL, "Invalid file mode") self.mode = mode @@ -1499,7 +1499,7 @@ class nodefd_content(StringIO, node_descriptor): raise NotImplementedError cr.commit() except Exception: - logging.getLogger('document.content').exception('Cannot update db content #%d for close:', par.cnt_id) + _logger.exception('Cannot update db content #%d for close:', par.cnt_id) raise finally: cr.close() @@ -1526,7 +1526,7 @@ class nodefd_static(StringIO, node_descriptor): elif mode == 'a': StringIO.__init__(self, None) else: - logging.getLogger('document.nodes').error("Incorrect mode %s specified", mode) + _logger.error("Incorrect mode %s specified", mode) raise IOError(errno.EINVAL, "Invalid file mode") self.mode = mode @@ -1551,7 +1551,7 @@ class nodefd_static(StringIO, node_descriptor): raise NotImplementedError cr.commit() except Exception: - logging.getLogger('document.nodes').exception('Cannot update db content #%d for close:', par.cnt_id) + _logger.exception('Cannot update db content #%d for close:', par.cnt_id) raise finally: cr.close() diff --git a/addons/document/std_index.py b/addons/document/std_index.py index e153d018bf0..a3059bd8a76 100644 --- a/addons/document/std_index.py +++ b/addons/document/std_index.py @@ -26,6 +26,8 @@ import odt2txt import sys, zipfile, xml.dom.minidom import logging +_logger = logging.getLogger(__name__) + def _to_unicode(s): try: return s.decode('utf-8') @@ -101,9 +103,8 @@ class DocIndex(indexer): (data, _) = pop.communicate() return _to_unicode(data) except OSError: - logger = logging.getLogger('document.DocIndex') - logger.warn("Failed attempt to execute antiword (MS Word reader). Antiword is necessary to index the file %s of MIME type %s. Detailed error available at DEBUG level.", fname, self._getMimeTypes()[0]) - logger.debug("Trace of the failed file indexing attempt: ", exc_info=True) + _logger.warning("Failed attempt to execute antiword (MS Word reader). Antiword is necessary to index the file %s of MIME type %s. Detailed error available at DEBUG level.", fname, self._getMimeTypes()[0]) + _logger.debug("Trace of the failed file indexing attempt: ", exc_info=True) return False cntIndex.register(DocIndex()) diff --git a/addons/document_ftp/ftpserver/__init__.py b/addons/document_ftp/ftpserver/__init__.py index 2e09a938a05..11b041e074b 100644 --- a/addons/document_ftp/ftpserver/__init__.py +++ b/addons/document_ftp/ftpserver/__init__.py @@ -19,6 +19,7 @@ # ############################################################################## +import logging import threading import ftpserver import authorizer @@ -26,6 +27,8 @@ import abstracted_fs import netsvc from tools import config +_logger = logging.getLogger(__name__) + def start_server(): HOST = config.get('ftp_server_host', '127.0.0.1') PORT = int(config.get('ftp_server_port', '8021')) @@ -36,8 +39,7 @@ def start_server(): class ftp_server(threading.Thread): def log(self, level, message): - logger = netsvc.Logger() - logger.notifyChannel('FTP', level, message) + _logger.log(level, message) def run(self): autho = authorizer.authorizer() @@ -56,9 +58,9 @@ def start_server(): ftpd.serve_forever() if HOST.lower() == 'none': - netsvc.Logger().notifyChannel("FTP", netsvc.LOG_INFO, "\n Server FTP Not Started\n") + _logger.info("\n Server FTP Not Started\n") else: - netsvc.Logger().notifyChannel("FTP", netsvc.LOG_INFO, "\n Serving FTP on %s:%s\n" % (HOST, PORT)) + _logger.info(\n Serving FTP on %s:%s\n", HOST, PORT) ds = ftp_server() ds.daemon = True ds.start() diff --git a/addons/edi/__init__.py b/addons/edi/__init__.py index b4a80c0f1dd..70723aea361 100644 --- a/addons/edi/__init__.py +++ b/addons/edi/__init__.py @@ -28,7 +28,7 @@ from models.edi import EDIMixin, edi_document try: import controllers except ImportError: - logging.getLogger('init.load').warn( + logging.getLogger(__name__).warning( """Could not load openerp-web section of EDI, EDI will not behave correctly To fix, launch openerp-web in embedded mode""") diff --git a/addons/edi/edi_service.py b/addons/edi/edi_service.py index 074720a03e9..f48cc60950a 100644 --- a/addons/edi/edi_service.py +++ b/addons/edi/edi_service.py @@ -23,7 +23,7 @@ import logging import netsvc import openerp -_logger = logging.getLogger('edi.service') +_logger = logging.getLogger(__name__) class edi(netsvc.ExportService): diff --git a/addons/edi/models/edi.py b/addons/edi/models/edi.py index c573115618e..6f5a69af470 100644 --- a/addons/edi/models/edi.py +++ b/addons/edi/models/edi.py @@ -36,6 +36,8 @@ from osv import osv,fields,orm from tools.translate import _ from tools.safe_eval import safe_eval as eval +_logger = logging.getLogger(__name__) + EXTERNAL_ID_PATTERN = re.compile(r'^([^.:]+)(?::([^.]+))?\.(\S+)$') EDI_VIEW_WEB_URL = '%s/edi/view?debug=1&db=%s&token=%s' EDI_PROTOCOL_VERSION = 1 # arbitrary ever-increasing version number @@ -72,8 +74,6 @@ def last_update_for(record): return record_log.get('write_date') or record_log.get('create_date') or False return False -_logger = logging.getLogger('edi') - class edi_document(osv.osv): _name = 'edi.document' _description = 'EDI Document' @@ -682,4 +682,4 @@ class EDIMixin(object): return record_id -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/edi/models/res_partner.py b/addons/edi/models/res_partner.py index 7c40a5c7354..6ec511269b3 100644 --- a/addons/edi/models/res_partner.py +++ b/addons/edi/models/res_partner.py @@ -25,6 +25,8 @@ from edi import EDIMixin from openerp import SUPERUSER_ID from tools.translate import _ +_logger = logging.getLogger(__name__) + RES_PARTNER_ADDRESS_EDI_STRUCT = { 'name': True, 'email': True, @@ -72,7 +74,7 @@ class res_partner_address(osv.osv, EDIMixin): code, label = 'edi_generic', 'Generic Bank Type (auto-created for EDI)' bank_code_ids = res_partner_bank_type.search(cr, uid, [('code','=',code)], context=context) if not bank_code_ids: - logging.getLogger('edi.res_partner').info('Normal bank account type is missing, creating ' + _logger.info('Normal bank account type is missing, creating ' 'a generic bank account type for EDI.') self.res_partner_bank_type.create(cr, SUPERUSER_ID, {'name': label, 'code': label}) @@ -98,7 +100,7 @@ class res_partner_address(osv.osv, EDIMixin): bank_name, ext_bank_id, context=import_ctx) except osv.except_osv: # failed to import it, try again with unrestricted default type - logging.getLogger('edi.res_partner').warning('Failed to import bank account using' + _logger.warning('Failed to import bank account using' 'bank type: %s, ignoring', import_ctx['default_state'], exc_info=True) return address_id diff --git a/addons/fetchmail/fetchmail.py b/addons/fetchmail/fetchmail.py index d1e23f49166..51c6f147cff 100644 --- a/addons/fetchmail/fetchmail.py +++ b/addons/fetchmail/fetchmail.py @@ -39,7 +39,7 @@ from osv import osv, fields import tools from tools.translate import _ -logger = logging.getLogger('fetchmail') +_logger = logging.getLogger(__name__) class fetchmail_server(osv.osv): """Incoming POP/IMAP mail server account""" @@ -151,7 +151,7 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS connection = server.connect() server.write({'state':'done'}) except Exception, e: - logger.exception("Failed to connect to %s server %s", server.type, server.name) + _logger.exception("Failed to connect to %s server %s", server.type, server.name) raise osv.except_osv(_("Connection test failed!"), _("Here is what we got instead:\n %s") % tools.ustr(e)) finally: try: @@ -177,7 +177,7 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS mail_thread = self.pool.get('mail.thread') action_pool = self.pool.get('ir.actions.server') for server in self.browse(cr, uid, ids, context=context): - logger.info('start checking for new emails on %s server %s', server.type, server.name) + _logger.info('start checking for new emails on %s server %s', server.type, server.name) context.update({'fetchmail_server_id': server.id, 'server_type': server.type}) count = 0 if server.type == 'imap': @@ -196,9 +196,9 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS imap_server.store(num, '+FLAGS', '\\Seen') cr.commit() count += 1 - logger.info("fetched/processed %s email(s) on %s server %s", count, server.type, server.name) + _logger.info("fetched/processed %s email(s) on %s server %s", count, server.type, server.name) except Exception, e: - logger.exception("Failed to fetch mail from %s server %s", server.type, server.name) + _logger.exception("Failed to fetch mail from %s server %s", server.type, server.name) finally: if imap_server: imap_server.close() @@ -220,9 +220,9 @@ openerp_mailgate.py -u %(uid)d -p PASSWORD -o %(model)s -d %(dbname)s --host=HOS action_pool.run(cr, uid, [server.action_id.id], {'active_id': res_id, 'active_ids':[res_id]}) pop_server.dele(num) cr.commit() - logger.info("fetched/processed %s email(s) on %s server %s", numMsgs, server.type, server.name) + _logger.info("fetched/processed %s email(s) on %s server %s", numMsgs, server.type, server.name) except Exception, e: - logger.exception("Failed to fetch mail from %s server %s", server.type, server.name) + _logger.exception("Failed to fetch mail from %s server %s", server.type, server.name) finally: if pop_server: pop_server.quit() diff --git a/addons/import_base/import_framework.py b/addons/import_base/import_framework.py index 44243aa952c..2ae51fde6b5 100644 --- a/addons/import_base/import_framework.py +++ b/addons/import_base/import_framework.py @@ -29,11 +29,11 @@ import datetime import logging import StringIO import traceback + +_logger = logging.getLogger(__name__) + pp = pprint.PrettyPrinter(indent=4) - - - class import_framework(Thread): """ This class should be extends, @@ -60,7 +60,6 @@ class import_framework(Thread): self.context = context or {} self.email = email_to_notify self.table_list = [] - self.logger = logging.getLogger(module_name) self.initialize() """ @@ -165,7 +164,7 @@ class import_framework(Thread): data_i is a map external field_name => value and each data_i have a external id => in data_id['id'] """ - self.logger.info(' Importing %s into %s' % (table, model)) + _logger.info(' Importing %s into %s', table, model) if not datas: return (0, 'No data found') mapping['id'] = 'id_new' @@ -188,7 +187,7 @@ class import_framework(Thread): model_obj = self.obj.pool.get(model) if not model_obj: raise ValueError(_("%s is not a valid model name") % model) - self.logger.debug(_(" fields imported : ") + str(fields)) + _logger.debug(_(" fields imported : ") + str(fields)) (p, r, warning, s) = model_obj.import_data(self.cr, self.uid, fields, res, mode='update', current_module=self.module_name, noupdate=True, context=self.context) for (field, field_name) in self_dependencies: self._import_self_dependencies(model_obj, field, datas) @@ -431,9 +430,9 @@ class import_framework(Thread): 'auto_delete' : True}) email_obj.send(self.cr, self.uid, [email_id]) if error: - self.logger.error(_("Import failed due to an unexpected error")) + _logger.error(_("Import failed due to an unexpected error")) else: - self.logger.info(_("Import finished, notification email sended")) + _logger.info(_("Import finished, notification email sended")) def get_email_subject(self, result, error=False): """ diff --git a/addons/l10n_be_invoice_bba/invoice.py b/addons/l10n_be_invoice_bba/invoice.py index 997036c0cec..937e49e83a8 100644 --- a/addons/l10n_be_invoice_bba/invoice.py +++ b/addons/l10n_be_invoice_bba/invoice.py @@ -1,219 +1,218 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# -# Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved. -# -# 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 . -# -############################################################################## - -import re, time, random -from osv import fields, osv -from tools.translate import _ -import netsvc -logger=netsvc.Logger() - -""" -account.invoice object: - - Add support for Belgian structured communication - - Rename 'reference' field labels to 'Communication' -""" - -class account_invoice(osv.osv): - _inherit = 'account.invoice' - - def _get_reference_type(self, cursor, user, context=None): - """Add BBA Structured Communication Type and change labels from 'reference' into 'communication' """ - res = super(account_invoice, self)._get_reference_type(cursor, user, - context=context) - res[[i for i,x in enumerate(res) if x[0] == 'none'][0]] = ('none', 'Free Communication') - res.append(('bba', 'BBA Structured Communication')) - #logger.notifyChannel('addons.'+self._name, netsvc.LOG_WARNING, 'reference_type = %s' %res ) - return res - - def check_bbacomm(self, val): - supported_chars = '0-9+*/ ' - pattern = re.compile('[^' + supported_chars + ']') - if pattern.findall(val or ''): - return False - bbacomm = re.sub('\D', '', val or '') - if len(bbacomm) == 12: - base = int(bbacomm[:10]) - mod = base % 97 or 97 - if mod == int(bbacomm[-2:]): - return True - return False - - def _check_communication(self, cr, uid, ids): - for inv in self.browse(cr, uid, ids): - if inv.reference_type == 'bba': - return self.check_bbacomm(inv.reference) - return True - - def onchange_partner_id(self, cr, uid, ids, type, partner_id, - date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False): - result = super(account_invoice, self).onchange_partner_id(cr, uid, ids, type, partner_id, - date_invoice, payment_term, partner_bank_id, company_id) -# reference_type = self.default_get(cr, uid, ['reference_type'])['reference_type'] -# logger.notifyChannel('addons.'+self._name, netsvc.LOG_WARNING, 'partner_id %s' % partner_id) - reference = False - reference_type = 'none' - if partner_id: - if (type == 'out_invoice'): - reference_type = self.pool.get('res.partner').browse(cr, uid, partner_id).out_inv_comm_type - if reference_type: - algorithm = self.pool.get('res.partner').browse(cr, uid, partner_id).out_inv_comm_algorithm - if not algorithm: - algorithm = 'random' - reference = self.generate_bbacomm(cr, uid, ids, type, reference_type, algorithm, partner_id, '')['value']['reference'] - res_update = { - 'reference_type': reference_type or 'none', - 'reference': reference, - } - result['value'].update(res_update) - return result - - def generate_bbacomm(self, cr, uid, ids, type, reference_type, algorithm, partner_id, reference): - partner_obj = self.pool.get('res.partner') - reference = reference or '' - if (type == 'out_invoice'): - if reference_type == 'bba': - if not algorithm: - if partner_id: - algorithm = partner_obj.browse(cr, uid, partner_id).out_inv_comm_algorithm - if not algorithm: - if not algorithm: - algorithm = 'random' - if algorithm == 'date': - if not self.check_bbacomm(reference): - doy = time.strftime('%j') - year = time.strftime('%Y') - seq = '001' - seq_ids = self.search(cr, uid, - [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'), - ('reference', 'like', '+++%s/%s/%%' % (doy, year))], order='reference') - if seq_ids: - prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15]) - if prev_seq < 999: - seq = '%03d' % (prev_seq + 1) - else: - raise osv.except_osv(_('Warning!'), - _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \ - '\nPlease create manually a unique BBA Structured Communication.')) - bbacomm = doy + year + seq - base = int(bbacomm) - mod = base % 97 or 97 - reference = '+++%s/%s/%s%02d+++' % (doy, year, seq, mod) - elif algorithm == 'partner_ref': - if not self.check_bbacomm(reference): - partner_ref = self.pool.get('res.partner').browse(cr, uid, partner_id).ref - partner_ref_nr = re.sub('\D', '', partner_ref or '') - if (len(partner_ref_nr) < 3) or (len(partner_ref_nr) > 7): - raise osv.except_osv(_('Warning!'), - _('The Partner should have a 3-7 digit Reference Number for the generation of BBA Structured Communications!' \ - '\nPlease correct the Partner record.')) - else: - partner_ref_nr = partner_ref_nr.ljust(7, '0') - seq = '001' - seq_ids = self.search(cr, uid, - [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'), - ('reference', 'like', '+++%s/%s/%%' % (partner_ref_nr[:3], partner_ref_nr[3:]))], order='reference') - if seq_ids: - prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15]) - if prev_seq < 999: - seq = '%03d' % (prev_seq + 1) - else: - raise osv.except_osv(_('Warning!'), - _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \ - '\nPlease create manually a unique BBA Structured Communication.')) - bbacomm = partner_ref_nr + seq - base = int(bbacomm) - mod = base % 97 or 97 - reference = '+++%s/%s/%s%02d+++' % (partner_ref_nr[:3], partner_ref_nr[3:], seq, mod) - elif algorithm == 'random': - if not self.check_bbacomm(reference): - base = random.randint(1, 9999999999) - bbacomm = str(base).rjust(7, '0') - base = int(bbacomm) - mod = base % 97 or 97 - mod = str(mod).rjust(2, '0') - reference = '+++%s/%s/%s%s+++' % (bbacomm[:3], bbacomm[3:7], bbacomm[7:], mod) - else: - raise osv.except_osv(_('Error!'), - _("Unsupported Structured Communication Type Algorithm '%s' !" \ - "\nPlease contact your OpenERP support channel.") % algorithm) - return {'value': {'reference': reference}} - - def create(self, cr, uid, vals, context=None): - if vals.has_key('reference_type'): - reference_type = vals['reference_type'] - if reference_type == 'bba': - if vals.has_key('reference'): - bbacomm = vals['reference'] - else: - raise osv.except_osv(_('Warning!'), - _('Empty BBA Structured Communication!' \ - '\nPlease fill in a unique BBA Structured Communication.')) - if self.check_bbacomm(bbacomm): - reference = re.sub('\D', '', bbacomm) - vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++' - same_ids = self.search(cr, uid, - [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'), - ('reference', '=', vals['reference'])]) - if same_ids: - raise osv.except_osv(_('Warning!'), - _('The BBA Structured Communication has already been used!' \ - '\nPlease create manually a unique BBA Structured Communication.')) - return super(account_invoice, self).create(cr, uid, vals, context=context) - - def write(self, cr, uid, ids, vals, context={}): - if isinstance(ids, (int, long)): - ids = [ids] - for inv in self.browse(cr, uid, ids, context): - if vals.has_key('reference_type'): - reference_type = vals['reference_type'] - else: - reference_type = inv.reference_type or '' - if reference_type == 'bba': - if vals.has_key('reference'): - bbacomm = vals['reference'] - else: - bbacomm = inv.reference or '' - if self.check_bbacomm(bbacomm): - reference = re.sub('\D', '', bbacomm) - vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++' - same_ids = self.search(cr, uid, - [('id', '!=', inv.id), ('type', '=', 'out_invoice'), - ('reference_type', '=', 'bba'), ('reference', '=', vals['reference'])]) - if same_ids: - raise osv.except_osv(_('Warning!'), - _('The BBA Structured Communication has already been used!' \ - '\nPlease create manually a unique BBA Structured Communication.')) - return super(account_invoice, self).write(cr, uid, ids, vals, context) - - _columns = { - 'reference': fields.char('Communication', size=64, help="The partner reference of this invoice."), - 'reference_type': fields.selection(_get_reference_type, 'Communication Type', - required=True), - } - - _constraints = [ - (_check_communication, 'Invalid BBA Structured Communication !', ['Communication']), - ] - -account_invoice() +# -*- encoding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# +# Copyright (c) 2011 Noviat nv/sa (www.noviat.be). All rights reserved. +# +# 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 . +# +############################################################################## + +import random +import re +import time + +from osv import fields, osv +from tools.translate import _ + +""" +account.invoice object: + - Add support for Belgian structured communication + - Rename 'reference' field labels to 'Communication' +""" + +class account_invoice(osv.osv): + _inherit = 'account.invoice' + + def _get_reference_type(self, cursor, user, context=None): + """Add BBA Structured Communication Type and change labels from 'reference' into 'communication' """ + res = super(account_invoice, self)._get_reference_type(cursor, user, + context=context) + res[[i for i,x in enumerate(res) if x[0] == 'none'][0]] = ('none', 'Free Communication') + res.append(('bba', 'BBA Structured Communication')) + return res + + def check_bbacomm(self, val): + supported_chars = '0-9+*/ ' + pattern = re.compile('[^' + supported_chars + ']') + if pattern.findall(val or ''): + return False + bbacomm = re.sub('\D', '', val or '') + if len(bbacomm) == 12: + base = int(bbacomm[:10]) + mod = base % 97 or 97 + if mod == int(bbacomm[-2:]): + return True + return False + + def _check_communication(self, cr, uid, ids): + for inv in self.browse(cr, uid, ids): + if inv.reference_type == 'bba': + return self.check_bbacomm(inv.reference) + return True + + def onchange_partner_id(self, cr, uid, ids, type, partner_id, + date_invoice=False, payment_term=False, partner_bank_id=False, company_id=False): + result = super(account_invoice, self).onchange_partner_id(cr, uid, ids, type, partner_id, + date_invoice, payment_term, partner_bank_id, company_id) +# reference_type = self.default_get(cr, uid, ['reference_type'])['reference_type'] + reference = False + reference_type = 'none' + if partner_id: + if (type == 'out_invoice'): + reference_type = self.pool.get('res.partner').browse(cr, uid, partner_id).out_inv_comm_type + if reference_type: + algorithm = self.pool.get('res.partner').browse(cr, uid, partner_id).out_inv_comm_algorithm + if not algorithm: + algorithm = 'random' + reference = self.generate_bbacomm(cr, uid, ids, type, reference_type, algorithm, partner_id, '')['value']['reference'] + res_update = { + 'reference_type': reference_type or 'none', + 'reference': reference, + } + result['value'].update(res_update) + return result + + def generate_bbacomm(self, cr, uid, ids, type, reference_type, algorithm, partner_id, reference): + partner_obj = self.pool.get('res.partner') + reference = reference or '' + if (type == 'out_invoice'): + if reference_type == 'bba': + if not algorithm: + if partner_id: + algorithm = partner_obj.browse(cr, uid, partner_id).out_inv_comm_algorithm + if not algorithm: + if not algorithm: + algorithm = 'random' + if algorithm == 'date': + if not self.check_bbacomm(reference): + doy = time.strftime('%j') + year = time.strftime('%Y') + seq = '001' + seq_ids = self.search(cr, uid, + [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'), + ('reference', 'like', '+++%s/%s/%%' % (doy, year))], order='reference') + if seq_ids: + prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15]) + if prev_seq < 999: + seq = '%03d' % (prev_seq + 1) + else: + raise osv.except_osv(_('Warning!'), + _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \ + '\nPlease create manually a unique BBA Structured Communication.')) + bbacomm = doy + year + seq + base = int(bbacomm) + mod = base % 97 or 97 + reference = '+++%s/%s/%s%02d+++' % (doy, year, seq, mod) + elif algorithm == 'partner_ref': + if not self.check_bbacomm(reference): + partner_ref = self.pool.get('res.partner').browse(cr, uid, partner_id).ref + partner_ref_nr = re.sub('\D', '', partner_ref or '') + if (len(partner_ref_nr) < 3) or (len(partner_ref_nr) > 7): + raise osv.except_osv(_('Warning!'), + _('The Partner should have a 3-7 digit Reference Number for the generation of BBA Structured Communications!' \ + '\nPlease correct the Partner record.')) + else: + partner_ref_nr = partner_ref_nr.ljust(7, '0') + seq = '001' + seq_ids = self.search(cr, uid, + [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'), + ('reference', 'like', '+++%s/%s/%%' % (partner_ref_nr[:3], partner_ref_nr[3:]))], order='reference') + if seq_ids: + prev_seq = int(self.browse(cr, uid, seq_ids[-1]).reference[12:15]) + if prev_seq < 999: + seq = '%03d' % (prev_seq + 1) + else: + raise osv.except_osv(_('Warning!'), + _('The daily maximum of outgoing invoices with an automatically generated BBA Structured Communications has been exceeded!' \ + '\nPlease create manually a unique BBA Structured Communication.')) + bbacomm = partner_ref_nr + seq + base = int(bbacomm) + mod = base % 97 or 97 + reference = '+++%s/%s/%s%02d+++' % (partner_ref_nr[:3], partner_ref_nr[3:], seq, mod) + elif algorithm == 'random': + if not self.check_bbacomm(reference): + base = random.randint(1, 9999999999) + bbacomm = str(base).rjust(7, '0') + base = int(bbacomm) + mod = base % 97 or 97 + mod = str(mod).rjust(2, '0') + reference = '+++%s/%s/%s%s+++' % (bbacomm[:3], bbacomm[3:7], bbacomm[7:], mod) + else: + raise osv.except_osv(_('Error!'), + _("Unsupported Structured Communication Type Algorithm '%s' !" \ + "\nPlease contact your OpenERP support channel.") % algorithm) + return {'value': {'reference': reference}} + + def create(self, cr, uid, vals, context=None): + if vals.has_key('reference_type'): + reference_type = vals['reference_type'] + if reference_type == 'bba': + if vals.has_key('reference'): + bbacomm = vals['reference'] + else: + raise osv.except_osv(_('Warning!'), + _('Empty BBA Structured Communication!' \ + '\nPlease fill in a unique BBA Structured Communication.')) + if self.check_bbacomm(bbacomm): + reference = re.sub('\D', '', bbacomm) + vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++' + same_ids = self.search(cr, uid, + [('type', '=', 'out_invoice'), ('reference_type', '=', 'bba'), + ('reference', '=', vals['reference'])]) + if same_ids: + raise osv.except_osv(_('Warning!'), + _('The BBA Structured Communication has already been used!' \ + '\nPlease create manually a unique BBA Structured Communication.')) + return super(account_invoice, self).create(cr, uid, vals, context=context) + + def write(self, cr, uid, ids, vals, context={}): + if isinstance(ids, (int, long)): + ids = [ids] + for inv in self.browse(cr, uid, ids, context): + if vals.has_key('reference_type'): + reference_type = vals['reference_type'] + else: + reference_type = inv.reference_type or '' + if reference_type == 'bba': + if vals.has_key('reference'): + bbacomm = vals['reference'] + else: + bbacomm = inv.reference or '' + if self.check_bbacomm(bbacomm): + reference = re.sub('\D', '', bbacomm) + vals['reference'] = '+++' + reference[0:3] + '/' + reference[3:7] + '/' + reference[7:] + '+++' + same_ids = self.search(cr, uid, + [('id', '!=', inv.id), ('type', '=', 'out_invoice'), + ('reference_type', '=', 'bba'), ('reference', '=', vals['reference'])]) + if same_ids: + raise osv.except_osv(_('Warning!'), + _('The BBA Structured Communication has already been used!' \ + '\nPlease create manually a unique BBA Structured Communication.')) + return super(account_invoice, self).write(cr, uid, ids, vals, context) + + _columns = { + 'reference': fields.char('Communication', size=64, help="The partner reference of this invoice."), + 'reference_type': fields.selection(_get_reference_type, 'Communication Type', + required=True), + } + + _constraints = [ + (_check_communication, 'Invalid BBA Structured Communication !', ['Communication']), + ] + +account_invoice() # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/l10n_be_invoice_bba/partner.py b/addons/l10n_be_invoice_bba/partner.py index 04a51c3a6ab..4cb6079e0a2 100644 --- a/addons/l10n_be_invoice_bba/partner.py +++ b/addons/l10n_be_invoice_bba/partner.py @@ -21,11 +21,10 @@ # ############################################################################## -from osv import fields, osv import time + +from osv import fields, osv from tools.translate import _ -import netsvc -logger=netsvc.Logger() class res_partner(osv.osv): """ add field to indicate default 'Communication Type' on customer invoices """ diff --git a/addons/l10n_multilang/l10n_multilang.py b/addons/l10n_multilang/l10n_multilang.py index c4130f2761d..331ec12d76f 100644 --- a/addons/l10n_multilang/l10n_multilang.py +++ b/addons/l10n_multilang/l10n_multilang.py @@ -19,11 +19,13 @@ # ############################################################################## -from osv import fields, osv +import logging import os + +from osv import fields, osv from tools.translate import _ -import netsvc -logger=netsvc.Logger() + +_logger = logging.getLogger(__name__) class wizard_multi_charts_accounts(osv.osv_memory): """ @@ -80,8 +82,9 @@ class wizard_multi_charts_accounts(osv.osv_memory): if context.get('lang') == lang: self.pool.get(out_obj._name).write(cr, uid, out_ids[j], {in_field: value[in_id]}) else: - logger.notifyChannel('addons.'+self._name, netsvc.LOG_WARNING, - 'Language: %s. Translation from template: there is no translation available for %s!' %(lang, src[in_id]))#out_obj._name)) + _logger.warning( + 'Language: %s. Translation from template: there is no translation available for %s!', + lang, src[in_id]) return True def execute(self, cr, uid, ids, context=None): diff --git a/addons/mail/mail_message.py b/addons/mail/mail_message.py index 1693397f6fa..b2fcd93c779 100644 --- a/addons/mail/mail_message.py +++ b/addons/mail/mail_message.py @@ -34,7 +34,7 @@ from osv import osv from osv import fields from tools.translate import _ -_logger = logging.getLogger('mail') +_logger = logging.getLogger(__name__) def format_date_tz(date, tz=None): if not date: diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index 70b536296bf..7317f954066 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -25,14 +25,11 @@ import base64 import email from email.utils import parsedate -import logging import xmlrpclib from osv import osv, fields from tools.translate import _ from mail_message import decode, to_email -_logger = logging.getLogger('mail') - class mail_thread(osv.osv): '''Mixin model, meant to be inherited by any model that needs to act as a discussion topic on which messages can be attached. diff --git a/addons/project_messages/project_messages.py b/addons/project_messages/project_messages.py index 93f83d62f4a..fa0b34a0c47 100644 --- a/addons/project_messages/project_messages.py +++ b/addons/project_messages/project_messages.py @@ -20,14 +20,12 @@ ############################################################################## from osv import fields, osv -import netsvc class messages(osv.osv): """ Message from one user to another within a project """ _name = 'project.messages' - logger = netsvc.Logger() _columns = { 'create_date': fields.datetime('Creation Date', readonly=True), diff --git a/addons/report_webkit/webkit_report.py b/addons/report_webkit/webkit_report.py index d3057e5a1ee..a535e54d005 100644 --- a/addons/report_webkit/webkit_report.py +++ b/addons/report_webkit/webkit_report.py @@ -41,7 +41,6 @@ from mako.template import Template from mako.lookup import TemplateLookup from mako import exceptions -import netsvc import pooler from report_helper import WebKitHelper from report.report_sxw import * @@ -50,7 +49,7 @@ import tools from tools.translate import _ from osv.osv import except_osv -logger = logging.getLogger('report_webkit') +_logger = logging.getLogger(__name__) def mako_template(text): """Build a Mako template. @@ -248,7 +247,7 @@ class WebKitParser(report_sxw): htmls.append(html) except Exception, e: msg = exceptions.text_error_template().render() - logger.error(msg) + _logger.error(msg) raise except_osv(_('Webkit render'), msg) else: try : @@ -259,7 +258,7 @@ class WebKitParser(report_sxw): htmls.append(html) except Exception, e: msg = exceptions.text_error_template().render() - logger.error(msg) + _logger.error(msg) raise except_osv(_('Webkit render'), msg) head_mako_tpl = mako_template(header) try : @@ -281,7 +280,7 @@ class WebKitParser(report_sxw): **self.parser_instance.localcontext) except: msg = exceptions.text_error_template().render() - logger.error(msg) + _logger.error(msg) raise except_osv(_('Webkit render'), msg) if report_xml.webkit_debug : try : @@ -292,7 +291,7 @@ class WebKitParser(report_sxw): **self.parser_instance.localcontext) except Exception, e: msg = exceptions.text_error_template().render() - logger.error(msg) + _logger.error(msg) raise except_osv(_('Webkit render'), msg) return (deb, 'html') bin = self.get_lib(cursor, uid, company.id) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index e9928eb0aa7..24467199fc1 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -31,6 +31,7 @@ import tools import decimal_precision as dp import logging +_logger = logging.getLogger(__name__) #---------------------------------------------------------- # Incoterms @@ -408,9 +409,8 @@ class stock_location(osv.osv): # so we ROLLBACK to the SAVEPOINT to restore the transaction to its earlier # state, we return False as if the products were not available, and log it: cr.execute("ROLLBACK TO stock_location_product_reserve") - logger = logging.getLogger('stock.location') - logger.warn("Failed attempt to reserve %s x product %s, likely due to another transaction already in progress. Next attempt is likely to work. Detailed error available at DEBUG level.", product_qty, product_id) - logger.debug("Trace of the failed product reservation attempt: ", exc_info=True) + _logger.warning("Failed attempt to reserve %s x product %s, likely due to another transaction already in progress. Next attempt is likely to work. Detailed error available at DEBUG level.", product_qty, product_id) + _logger.debug("Trace of the failed product reservation attempt: ", exc_info=True) return False # XXX TODO: rewrite this with one single query, possibly even the quantity conversion From 7b45ea1d88dfe415abcc41345a103acd65ab1450 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 25 Jan 2012 11:06:08 +0100 Subject: [PATCH 005/703] [FIX] account_code: forgot import logging. bzr revid: vmt@openerp.com-20120125100608-ny79sc3tp1d9sak2 --- addons/account_coda/wizard/account_coda_import.py | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/account_coda/wizard/account_coda_import.py b/addons/account_coda/wizard/account_coda_import.py index ac9a623e2fc..b7e7eb5eb10 100644 --- a/addons/account_coda/wizard/account_coda_import.py +++ b/addons/account_coda/wizard/account_coda_import.py @@ -21,6 +21,7 @@ ############################################################################## import base64 +import logging import re from sys import exc_info import time From e582a6a893a96e5ce29e6057ee6467b7c63be482 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 25 Jan 2012 13:45:26 +0100 Subject: [PATCH 006/703] [IMP] logging: use logging instead of netsvc, use module __name__ instead of something else. bzr revid: vmt@openerp.com-20120125124526-nqaaw1rfmy8qa9of --- addons/auth_openid/controllers/main.py | 6 +-- addons/base_crypt/crypt.py | 6 ++- .../pylint_test/pylint_test.py | 7 ++- .../speed_test/speed_test.py | 8 ++- .../workflow_test/workflow_test.py | 9 ++-- addons/base_vat/base_vat.py | 4 +- addons/caldav/caldav_node.py | 17 +++--- addons/caldav/calendar.py | 9 ++-- addons/caldav/calendar_collection.py | 5 +- addons/crm/crm_meeting.py | 4 +- .../document_ftp/ftpserver/abstracted_fs.py | 16 +++--- addons/document_webdav/test_davclient.py | 52 +++++++++---------- addons/email_template/email_template.py | 6 ++- addons/hr/hr.py | 4 +- addons/import_sugarcrm/sugar.py | 4 +- addons/portal/ir_ui_menu.py | 5 +- addons/portal/wizard/portal_wizard.py | 4 +- addons/portal/wizard/share_wizard.py | 10 ++-- addons/share/wizard/share_wizard.py | 29 ++++++----- addons/stock_planning/stock_planning.py | 3 +- addons/users_ldap/users_ldap.py | 13 +++-- 21 files changed, 121 insertions(+), 100 deletions(-) diff --git a/addons/auth_openid/controllers/main.py b/addons/auth_openid/controllers/main.py index c95189b7736..dc7c7b21ccd 100644 --- a/addons/auth_openid/controllers/main.py +++ b/addons/auth_openid/controllers/main.py @@ -39,11 +39,7 @@ from openid.extensions import ax, sreg from .. import utils - - -_logger = logging.getLogger('web.auth_openid') -oidutil.log = logging.getLogger('openid').debug - +oidutil.log = logging.getLogger(__name__ + '(oidutil)').debug class GoogleAppsAwareConsumer(consumer.GenericConsumer): def complete(self, message, endpoint, return_to): diff --git a/addons/base_crypt/crypt.py b/addons/base_crypt/crypt.py index c2fd0a25ef8..6d74e482044 100644 --- a/addons/base_crypt/crypt.py +++ b/addons/base_crypt/crypt.py @@ -36,6 +36,7 @@ # Boston, MA 02111-1307 # USA. +import logging from random import seed, sample from string import ascii_letters, digits from osv import fields,osv @@ -43,6 +44,8 @@ import pooler from tools.translate import _ from service import security +_logger = logging.getLogger(__name__) + magic_md5 = '$1$' def gen_salt( length=8, symbols=ascii_letters + digits ): @@ -179,8 +182,7 @@ class users(osv.osv): cr = pooler.get_db(db).cursor() return self._login(cr, db, login, password) except Exception: - import logging - logging.getLogger('netsvc').exception('Could not authenticate') + _logger.exception('Could not authenticate') return Exception('Access Denied') finally: if cr is not None: diff --git a/addons/base_module_quality/pylint_test/pylint_test.py b/addons/base_module_quality/pylint_test/pylint_test.py index 102f93c469e..bfa9e7d1f16 100644 --- a/addons/base_module_quality/pylint_test/pylint_test.py +++ b/addons/base_module_quality/pylint_test/pylint_test.py @@ -19,11 +19,14 @@ # ############################################################################## +import logging import os import addons from tools.translate import _ from base_module_quality import base_module_quality +_logger = logging.getLogger(__name__) + class quality_test(base_module_quality.abstract_quality_check): def __init__(self): @@ -57,7 +60,7 @@ class quality_test(base_module_quality.abstract_quality_check): res = os.popen('pylint --rcfile=' + config_file_path + ' ' + file_path).read() except Exception: self.error = True - self.log.exception("Cannot run pylint test for %s", file_path) + _logger.exception("Cannot run pylint test for %s", file_path) self.result += _("Error. Is pylint correctly installed? (http://pypi.python.org/pypi/pylint)")+"\n" return None count += 1 @@ -66,7 +69,7 @@ class quality_test(base_module_quality.abstract_quality_check): score += float(scr) dict_py[file_py] = [file_py, scr] except Exception: - self.log.warning("Cannot parse pylint result", exc_info=True) + _logger.warning("Cannot parse pylint result", exc_info=True) score += 0 dict_py[file_py] = [file_py, _("Unable to parse the result. Check the details.")] replace_string = '' diff --git a/addons/base_module_quality/speed_test/speed_test.py b/addons/base_module_quality/speed_test/speed_test.py index 21ddee92ea1..26f3ea176b1 100644 --- a/addons/base_module_quality/speed_test/speed_test.py +++ b/addons/base_module_quality/speed_test/speed_test.py @@ -19,9 +19,13 @@ # ############################################################################## +import logging + from tools.translate import _ import pooler +_logger = logging.getLogger(__name__) + from base_module_quality import base_module_quality class CounterCursor(object): @@ -77,7 +81,7 @@ This test checks the speed of the module. Note that at least 5 demo data is need try: obj_ids = self.get_ids(cr, uid, obj_list) except Exception,e: - self.log.warning("Cannot get ids:", exc_info=True) + _logger.warning("Cannot get ids:", exc_info=True) obj_ids= {} self.result_details += e.message result_dict = {} @@ -111,7 +115,7 @@ This test checks the speed of the module. Note that at least 5 demo data is need code_size_complexity = ccr.count except Exception, e: - self.log.warning('Error in read method', exc_info=True) + _logger.warning('Error in read method', exc_info=True) list2 = [obj, _("Error in Read method")] speed_list = [obj, size, code_base_complexity, code_half_complexity, code_size_complexity, _("Error in Read method: %s") % e] else: diff --git a/addons/base_module_quality/workflow_test/workflow_test.py b/addons/base_module_quality/workflow_test/workflow_test.py index 11f7bcf12c3..1ce3f56b83a 100644 --- a/addons/base_module_quality/workflow_test/workflow_test.py +++ b/addons/base_module_quality/workflow_test/workflow_test.py @@ -19,6 +19,7 @@ # ############################################################################## +import loggging import xml.dom.minidom import tools @@ -26,6 +27,8 @@ from tools.translate import _ from base_module_quality import base_module_quality import pooler +_logger = logging.getLogger(__name__) + class quality_test(base_module_quality.abstract_quality_check): def __init__(self): @@ -80,8 +83,8 @@ class quality_test(base_module_quality.abstract_quality_check): #Activity of workflow checking... activity_ids = wkf_activity_obj.search(cr, uid, [('wkf_id', 'in', wkf_ids)]) activities = wkf_activity_obj.browse(cr, uid, activity_ids) - self.log.debug("quality test: wkf_ids = %r", wkf_ids) - self.log.debug("quality test: activity_ids = %r", activity_ids) + _logger.debug("quality test: wkf_ids = %r", wkf_ids) + _logger.debug("quality test: activity_ids = %r", activity_ids) for activity in activities: if activity.flow_start: activity_chk[activity.wkf_id.osv]['start'] = 'ok' @@ -155,4 +158,4 @@ class quality_test(base_module_quality.abstract_quality_check): count = self.count_button(node, count) return count -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: \ No newline at end of file +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/base_vat/base_vat.py b/addons/base_vat/base_vat.py index 02471f67442..8b9b9fd26c1 100644 --- a/addons/base_vat/base_vat.py +++ b/addons/base_vat/base_vat.py @@ -19,7 +19,6 @@ # ############################################################################## -import logging import string import datetime import re @@ -27,7 +26,8 @@ import re try: import vatnumber except ImportError: - logging.getLogger('base_vat').warning("VAT validation partially unavailable because the `vatnumber` Python library cannot be found. " + import logging + logging.getLogger(__name__).warning("VAT validation partially unavailable because the `vatnumber` Python library cannot be found. " "Install it to support more countries, for example with `easy_install vatnumber`.") vatnumber = None diff --git a/addons/caldav/caldav_node.py b/addons/caldav/caldav_node.py index 71e9bdc2468..edd0a742467 100644 --- a/addons/caldav/caldav_node.py +++ b/addons/caldav/caldav_node.py @@ -29,6 +29,8 @@ try: except ImportError: from document.dict_tools import dict_merge2 +_logger = logging.getLogger(__name__) + # TODO: implement DAV-aware errors, inherit from IOError # Assuming that we have set global properties right, we mark *all* @@ -223,7 +225,6 @@ class node_calendar(nodes.node_class): res = [] if not filters: return res - _log = logging.getLogger('caldav.query') if filters.localName == 'calendar-query': res = [] for filter_child in filters.childNodes: @@ -245,27 +246,27 @@ class node_calendar(nodes.node_class): for cfe in vevent_filter.childNodes: if cfe.localName == 'time-range': if cfe.getAttribute('start'): - _log.warning("Ignore start.. ") + _logger.warning("Ignore start.. ") # No, it won't work in this API #val = cfe.getAttribute('start') #res += [('dtstart','=', cfe)] elif cfe.getAttribute('end'): - _log.warning("Ignore end.. ") + _logger.warning("Ignore end.. ") else: - _log.debug("Unknown comp-filter: %s", cfe.localName) + _logger.debug("Unknown comp-filter: %s", cfe.localName) else: - _log.debug("Unknown comp-filter: %s", vevent_filter.localName) + _logger.debug("Unknown comp-filter: %s", vevent_filter.localName) else: - _log.debug("Unknown filter element: %s", vcalendar_filter.localName) + _logger.debug("Unknown filter element: %s", vcalendar_filter.localName) else: - _log.debug("Unknown calendar-query element: %s", filter_child.localName) + _logger.debug("Unknown calendar-query element: %s", filter_child.localName) return res elif filters.localName == 'calendar-multiget': # this is not the place to process, as it wouldn't support multi-level # hrefs. So, the code is moved to document_webdav/dav_fs.py pass else: - _log.debug("Unknown element in REPORT: %s", filters.localName) + _logger.debug("Unknown element in REPORT: %s", filters.localName) return res def children(self, cr, domain=None): diff --git a/addons/caldav/calendar.py b/addons/caldav/calendar.py index 94d28e4ad37..770865175cd 100644 --- a/addons/caldav/calendar.py +++ b/addons/caldav/calendar.py @@ -40,6 +40,8 @@ try: except ImportError: raise osv.except_osv(_('vobject Import Error!'), _('Please install python-vobject from http://vobject.skyhouseconsulting.com/')) +_logger = logging.getLogger(__name__) + # O-1 Optional and can come only once # O-n Optional and can come more than once # R-1 Required and can come only once @@ -240,7 +242,6 @@ def map_data(cr, uid, obj, context=None): class CalDAV(object): __attribute__ = {} - _logger = logging.getLogger('document.caldav') def ical_set(self, name, value, type): """ set calendar Attribute @@ -725,13 +726,13 @@ class Calendar(CalDAV, osv.osv): objs.append(cal_children[child.name.lower()]) elif child.name.upper() == 'CALSCALE': if child.value.upper() != 'GREGORIAN': - self._logger.warning('How do I handle %s calendars?',child.value) + _logger.warning('How do I handle %s calendars?',child.value) elif child.name.upper() in ('PRODID', 'VERSION'): pass elif child.name.upper().startswith('X-'): - self._logger.debug("skipping custom node %s", child.name) + _logger.debug("skipping custom node %s", child.name) else: - self._logger.debug("skipping node %s", child.name) + _logger.debug("skipping node %s", child.name) res = [] for obj_name in list(set(objs)): diff --git a/addons/caldav/calendar_collection.py b/addons/caldav/calendar_collection.py index 1abbf573ef0..8c845aff5e6 100644 --- a/addons/caldav/calendar_collection.py +++ b/addons/caldav/calendar_collection.py @@ -24,6 +24,8 @@ from tools.translate import _ import caldav_node import logging +_logger = logging.getLogger(__name__) + class calendar_collection(osv.osv): _inherit = 'document.directory' _columns = { @@ -44,8 +46,7 @@ class calendar_collection(osv.osv): root_cal_dir = self.browse(cr,uid, root_id, context=context) return root_cal_dir.name except Exception: - logger = logging.getLogger('document') - logger.warning('Cannot set root directory for Calendars:', exc_info=True) + _logger.warning('Cannot set root directory for Calendars:', exc_info=True) return False return False diff --git a/addons/crm/crm_meeting.py b/addons/crm/crm_meeting.py index 40ba8662f13..f28212051eb 100644 --- a/addons/crm/crm_meeting.py +++ b/addons/crm/crm_meeting.py @@ -25,6 +25,8 @@ from osv import fields, osv from tools.translate import _ import logging +_logger = logging.getLogger(__name__) + class crm_lead(crm_case, osv.osv): """ CRM Leads """ _name = 'crm.lead' @@ -149,7 +151,7 @@ class res_users(osv.osv): 'user_id': user_id}, context=context) except: # Tolerate a missing shortcut. See product/product.py for similar code. - logging.getLogger('orm').debug('Skipped meetings shortcut for user "%s"', data.get('name','", cnod, node.tagName) + _logger.debug("Found %r inside <%s>", cnod, node.tagName) continue if namespaces and (cnod.namespaceURI not in namespaces): - log.debug("Ignoring <%s> in <%s>", cnod.tagName, node.localName) + _logger.debug("Ignoring <%s> in <%s>", cnod.tagName, node.localName) continue yield cnod @@ -533,10 +533,10 @@ class DAVClient(object): assert htver == 'HTTP/1.1' rstatus = int(sta) else: - log.debug("What is <%s> inside a ?", pno.tagName) + _logger.debug("What is <%s> inside a ?", pno.tagName) else: - log.debug("Unknown node: %s", cno.tagName) + _logger.debug("Unknown node: %s", cno.tagName) res.setdefault(href,[]).append((status, res_nss)) @@ -637,7 +637,7 @@ class DAVClient(object): if lsp[1] in davprops: lsline[lsp[0]] = lsp[2] else: - log.debug("Strange status: %s", st) + _logger.debug("Strange status: %s", st) res.append(lsline) diff --git a/addons/email_template/email_template.py b/addons/email_template/email_template.py index 90eda625759..4d64dd1a4c6 100644 --- a/addons/email_template/email_template.py +++ b/addons/email_template/email_template.py @@ -30,10 +30,12 @@ import tools from tools.translate import _ from urllib import quote as quote +_logger = logging.getLogger(__name__) + try: from mako.template import Template as MakoTemplate except ImportError: - logging.getLogger('init').warning("email_template: mako templates not available, templating features will not work!") + _logger.warning("email_template: mako templates not available, templating features will not work!") class email_template(osv.osv): "Templates for sending email" @@ -73,7 +75,7 @@ class email_template(osv.osv): result = u'' return result except Exception: - logging.exception("failed to render mako template value %r", template) + _logger.exception("failed to render mako template value %r", template) return u"" def get_email_template(self, cr, uid, template_id=False, record_id=None, context=None): diff --git a/addons/hr/hr.py b/addons/hr/hr.py index 76f9295a829..2dfd018eec1 100644 --- a/addons/hr/hr.py +++ b/addons/hr/hr.py @@ -23,6 +23,8 @@ from osv import fields, osv import logging import addons +_logger = logging.getLogger(__name__) + class hr_employee_category(osv.osv): def name_get(self, cr, uid, ids, context=None): @@ -270,7 +272,7 @@ class res_users(osv.osv): 'user_id': user_id}, context=context) except: # Tolerate a missing shortcut. See product/product.py for similar code. - logging.getLogger('orm').debug('Skipped meetings shortcut for user "%s"', data.get('name',' 1: - log = logging.getLogger('ir.ui.menu') - log.warning('User %s belongs to several portals', str(uid)) + _logger.warning('User %s belongs to several portals', str(uid)) p = portal_obj.browse(cr, uid, portal_ids[0]) # if the portal overrides the menu, use its domain if p.menu_action_id: diff --git a/addons/portal/wizard/portal_wizard.py b/addons/portal/wizard/portal_wizard.py index 706d6fd4a7f..f0790cb9bd9 100644 --- a/addons/portal/wizard/portal_wizard.py +++ b/addons/portal/wizard/portal_wizard.py @@ -28,7 +28,7 @@ from tools.translate import _ from base.res.res_users import _lang_get - +_logger = logging.getLogger(__name__) # welcome email sent to new portal users (note that calling tools.translate._ # has no effect except exporting those strings for translation) @@ -178,7 +178,7 @@ class wizard(osv.osv_memory): body = _(WELCOME_EMAIL_BODY) % data res = mail_message_obj.schedule_with_attach(cr, uid, email_from , [email_to], subject, body, context=context) if not res: - logging.getLogger('res.portal.wizard').warning( + _logger.warning( 'Failed to send email from %s to %s', email_from, email_to) return {'type': 'ir.actions.act_window_close'} diff --git a/addons/portal/wizard/share_wizard.py b/addons/portal/wizard/share_wizard.py index b5c9d165cc6..4236206a6fd 100644 --- a/addons/portal/wizard/share_wizard.py +++ b/addons/portal/wizard/share_wizard.py @@ -19,9 +19,13 @@ # ############################################################################## +import logging + from osv import osv, fields from tools.translate import _ +_logger = logging.getLogger(__name__) + UID_ROOT = 1 SHARED_DOCS_MENU = "Documents" SHARED_DOCS_CHILD_MENU = "Shared Documents" @@ -164,19 +168,19 @@ class share_wizard_portal(osv.osv_memory): # v6.1, the algorithm for combining them will OR the rules, hence # extending the visible data. Rules.write(cr, UID_ROOT, share_rule_ids, {'groups': [(4,target_group.id)]}) - self._logger.debug("Linked sharing rules from temporary sharing group to group %s", target_group) + _logger.debug("Linked sharing rules from temporary sharing group to group %s", target_group) # Copy the access rights. This is appropriate too because # groups have the UNION of all permissions granted by their # access right lines. for access_line in share_group.model_access: Rights.copy(cr, UID_ROOT, access_line.id, default={'group_id': target_group.id}) - self._logger.debug("Copied access rights from temporary sharing group to group %s", target_group) + _logger.debug("Copied access rights from temporary sharing group to group %s", target_group) # finally, delete it after removing its users Groups.write(cr, UID_ROOT, [share_group_id], {'users': [(6,0,[])]}) Groups.unlink(cr, UID_ROOT, [share_group_id]) - self._logger.debug("Deleted temporary sharing group %s", share_group_id) + _logger.debug("Deleted temporary sharing group %s", share_group_id) def _finish_result_lines(self, cr, uid, wizard_data, share_group_id, context=None): super(share_wizard_portal,self)._finish_result_lines(cr, uid, wizard_data, share_group_id, context=context) diff --git a/addons/share/wizard/share_wizard.py b/addons/share/wizard/share_wizard.py index 80a0b12f8b2..5ed07142367 100644 --- a/addons/share/wizard/share_wizard.py +++ b/addons/share/wizard/share_wizard.py @@ -33,6 +33,8 @@ from tools.translate import _ from tools.safe_eval import safe_eval import openerp +_logger = logging.getLogger(__name__) + FULL_ACCESS = ('perm_read', 'perm_write', 'perm_create', 'perm_unlink') READ_WRITE_ACCESS = ('perm_read', 'perm_write') READ_ONLY_ACCESS = ('perm_read',) @@ -48,7 +50,6 @@ def generate_random_pass(): return ''.join(random.sample(RANDOM_PASS_CHARACTERS,10)) class share_wizard(osv.osv_memory): - _logger = logging.getLogger('share.wizard') _name = 'share.wizard' _description = 'Share Wizard' @@ -322,7 +323,7 @@ class share_wizard(osv.osv_memory): except Exception: # Note: must catch all exceptions, as UnquoteEvalContext may cause many # different exceptions, as it shadows builtins. - self._logger.debug("Failed to cleanup action context as it does not parse server-side", exc_info=True) + _logger.debug("Failed to cleanup action context as it does not parse server-side", exc_info=True) result = context_str return result @@ -483,8 +484,8 @@ class share_wizard(osv.osv_memory): [x.id for x in current_user.groups_id], target_model_ids, context=context) group_access_map = self._get_access_map_for_groups_and_models(cr, uid, [group_id], target_model_ids, context=context) - self._logger.debug("Current user access matrix: %r", current_user_access_map) - self._logger.debug("New group current access matrix: %r", group_access_map) + _logger.debug("Current user access matrix: %r", current_user_access_map) + _logger.debug("New group current access matrix: %r", group_access_map) # Create required rights if allowed by current user rights and not # already granted @@ -505,7 +506,7 @@ class share_wizard(osv.osv_memory): need_creation = True if need_creation: model_access_obj.create(cr, UID_ROOT, values) - self._logger.debug("Creating access right for model %s with values: %r", model.model, values) + _logger.debug("Creating access right for model %s with values: %r", model.model, values) def _link_or_copy_current_user_rules(self, cr, current_user, group_id, fields_relations, context=None): rule_obj = self.pool.get('ir.rule') @@ -527,13 +528,13 @@ class share_wizard(osv.osv_memory): 'groups': [(6,0,[group_id])], 'domain_force': rule.domain, # evaluated version! }) - self._logger.debug("Copying rule %s (%s) on model %s with domain: %s", rule.name, rule.id, model.model, rule.domain_force) + _logger.debug("Copying rule %s (%s) on model %s with domain: %s", rule.name, rule.id, model.model, rule.domain_force) else: # otherwise we can simply link the rule to keep it dynamic rule_obj.write(cr, 1, [rule.id], { 'groups': [(4,group_id)] }) - self._logger.debug("Linking rule %s (%s) on model %s with domain: %s", rule.name, rule.id, model.model, rule.domain_force) + _logger.debug("Linking rule %s (%s) on model %s with domain: %s", rule.name, rule.id, model.model, rule.domain_force) def _check_personal_rule_or_duplicate(self, cr, group_id, rule, context=None): """Verifies that the given rule only belongs to the given group_id, otherwise @@ -552,7 +553,7 @@ class share_wizard(osv.osv_memory): 'groups': [(6,0,[group_id])], 'domain_force': rule.domain_force, # non evaluated! }) - self._logger.debug("Duplicating rule %s (%s) (domain: %s) for modified access ", rule.name, rule.id, rule.domain_force) + _logger.debug("Duplicating rule %s (%s) (domain: %s) for modified access ", rule.name, rule.id, rule.domain_force) # then disconnect from group_id: rule.write({'groups':[(3,group_id)]}) # disconnects, does not delete! return rule_obj.browse(cr, UID_ROOT, new_id, context=context) @@ -587,7 +588,7 @@ class share_wizard(osv.osv_memory): if restrict: continue else: - self._logger.debug("Ignoring sharing rule on model %s with domain: %s the same rule exists already", model_id, domain) + _logger.debug("Ignoring sharing rule on model %s with domain: %s the same rule exists already", model_id, domain) return if restrict: # restricting existing rules is done by adding the clause @@ -599,7 +600,7 @@ class share_wizard(osv.osv_memory): new_clause = expression.normalize(eval(domain, eval_ctx)) combined_domain = expression.AND([new_clause, org_domain]) rule.write({'domain_force': combined_domain, 'name': rule.name + _('(Modified)')}) - self._logger.debug("Combining sharing rule %s on model %s with domain: %s", rule.id, model_id, domain) + _logger.debug("Combining sharing rule %s on model %s with domain: %s", rule.id, model_id, domain) if not restrict: # Adding the new rule in the group is ok for normal cases, because rules # in the same group and for the same model will be combined with OR @@ -610,7 +611,7 @@ class share_wizard(osv.osv_memory): 'domain_force': domain, 'groups': [(4,group_id)] }) - self._logger.debug("Created sharing rule on model %s with domain: %s", model_id, domain) + _logger.debug("Created sharing rule on model %s with domain: %s", model_id, domain) def _create_indirect_sharing_rules(self, cr, current_user, wizard_data, group_id, fields_relations, context=None): rule_name = _('Indirect sharing filter created by user %s (%s) for group %s') % \ @@ -631,7 +632,7 @@ class share_wizard(osv.osv_memory): group_id, model_id=model.id, domain=str(related_domain), rule_name=rule_name, restrict=True, context=context) except Exception: - self._logger.exception('Failed to create share access') + _logger.exception('Failed to create share access') raise osv.except_osv(_('Sharing access could not be created'), _('Sorry, the current screen and filter you are trying to share are not supported at the moment.\nYou may want to try a simpler filter.')) @@ -749,7 +750,7 @@ class share_wizard(osv.osv_memory): } def send_emails(self, cr, uid, wizard_data, context=None): - self._logger.info('Sending share notifications by email...') + _logger.info('Sending share notifications by email...') mail_message = self.pool.get('mail.message') user = self.pool.get('res.users').browse(cr, UID_ROOT, uid) @@ -795,7 +796,7 @@ class share_wizard(osv.osv_memory): context=context)) # force direct delivery, as users expect instant notification mail_message.send(cr, uid, msg_ids, context=context) - self._logger.info('%d share notification(s) sent.', len(msg_ids)) + _logger.info('%d share notification(s) sent.', len(msg_ids)) def onchange_embed_options(self, cr, uid, ids, opt_title, opt_search, context=None): wizard = self.browse(cr, uid, ids[0], context) diff --git a/addons/stock_planning/stock_planning.py b/addons/stock_planning/stock_planning.py index d104d57c62b..0b9f95deb7e 100644 --- a/addons/stock_planning/stock_planning.py +++ b/addons/stock_planning/stock_planning.py @@ -29,8 +29,7 @@ from tools.translate import _ import logging import decimal_precision as dp -_logger = logging.getLogger('mps') - +_logger = logging.getLogger(__name__) def rounding(fl, round_value): if not round_value: diff --git a/addons/users_ldap/users_ldap.py b/addons/users_ldap/users_ldap.py index 1ad1b2df104..c32d120b298 100644 --- a/addons/users_ldap/users_ldap.py +++ b/addons/users_ldap/users_ldap.py @@ -28,6 +28,8 @@ import tools from osv import fields, osv from openerp import SUPERUSER_ID +_logger = logging.getLogger(__name__) + class CompanyLDAP(osv.osv): _name = 'res.company.ldap' _order = 'sequence' @@ -107,8 +109,7 @@ class CompanyLDAP(osv.osv): except ldap.INVALID_CREDENTIALS: return False except ldap.LDAPError, e: - logger = logging.getLogger('orm.ldap') - logger.error('An LDAP exception occurred: %s', e) + _logger.error('An LDAP exception occurred: %s', e) return entry def query(self, conf, filter, retrieve_attributes=None): @@ -135,7 +136,6 @@ class CompanyLDAP(osv.osv): """ results = [] - logger = logging.getLogger('orm.ldap') try: conn = self.connect(conf) conn.simple_bind_s(conf['ldap_binddn'] or '', @@ -144,9 +144,9 @@ class CompanyLDAP(osv.osv): filter, retrieve_attributes, timeout=60) conn.unbind() except ldap.INVALID_CREDENTIALS: - logger.error('LDAP bind failed.') + _logger.error('LDAP bind failed.') except ldap.LDAPError, e: - logger.error('An LDAP exception occurred: %s', e) + _logger.error('An LDAP exception occurred: %s', e) return results def map_ldap_attributes(self, cr, uid, conf, login, ldap_entry): @@ -188,8 +188,7 @@ class CompanyLDAP(osv.osv): if res[1]: user_id = res[0] elif conf['create_user']: - logger = logging.getLogger('orm.ldap') - logger.debug("Creating new OpenERP user \"%s\" from LDAP" % login) + _logger.debug("Creating new OpenERP user \"%s\" from LDAP" % login) user_obj = self.pool.get('res.users') values = self.map_ldap_attributes(cr, uid, conf, login, ldap_entry) if conf['user']: From bf6d569d75f8e4217773ea6f58d231160f32b557 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Wed, 25 Jan 2012 14:00:11 +0100 Subject: [PATCH 007/703] [IMP] logging: use logging instead of netsvc. bzr revid: vmt@openerp.com-20120125130011-yxfhry0h881k64cn --- addons/document_ftp/ftpserver/__init__.py | 6 ++---- addons/l10n_be/wizard/l10n_be_partner_vat_listing.py | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/addons/document_ftp/ftpserver/__init__.py b/addons/document_ftp/ftpserver/__init__.py index 11b041e074b..dd5ec255704 100644 --- a/addons/document_ftp/ftpserver/__init__.py +++ b/addons/document_ftp/ftpserver/__init__.py @@ -38,8 +38,6 @@ def start_server(): PASSIVE_PORTS = int(pps[0]), int(pps[1]) class ftp_server(threading.Thread): - def log(self, level, message): - _logger.log(level, message) def run(self): autho = authorizer.authorizer() @@ -50,9 +48,9 @@ def start_server(): if PASSIVE_PORTS: ftpserver.FTPHandler.passive_ports = PASSIVE_PORTS - ftpserver.log = lambda msg: self.log(netsvc.LOG_INFO, msg) + ftpserver.log = _logger.info ftpserver.logline = lambda msg: None - ftpserver.logerror = lambda msg: self.log(netsvc.LOG_ERROR, msg) + ftpserver.logerror = _logger.error ftpd = ftpserver.FTPServer((HOST, PORT), ftpserver.FTPHandler) ftpd.serve_forever() diff --git a/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py b/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py index e43dbfecf2b..7e7cba15c78 100644 --- a/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py +++ b/addons/l10n_be/wizard/l10n_be_partner_vat_listing.py @@ -45,7 +45,6 @@ class partner_vat_13(osv.osv_memory): period = obj_period.search(cursor, user, [('date_start' ,'>=', date_start), ('date_stop','<=',date_stop)]) if not period: raise osv.except_osv(_('Data Insufficient!'), _('No data for the selected Year.')) - #logger.notifyChannel('addons.'+self._name, netsvc.LOG_WARNING, 'period = %s' %period ) p_id_list = obj_partner.search(cursor, user, [('vat_subjected', '!=', False)], context=context) if not p_id_list: From 82f492bc2c5bbca8b02168075b5d5356f1b35951 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Fri, 9 Mar 2012 16:29:38 +0100 Subject: [PATCH 008/703] [FIX] related fields: fix and simplify search (was wrong with a single indirection) bzr revid: rco@openerp.com-20120309152938-n467ap8hnw406rau --- openerp/osv/fields.py | 18 +++-------- openerp/tests/__init__.py | 2 ++ openerp/tests/test_fields.py | 59 ++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 openerp/tests/test_fields.py diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 7c1761a4aec..fdbd6a6f7cc 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1153,20 +1153,10 @@ class related(function): """ def _fnct_search(self, tobj, cr, uid, obj=None, name=None, domain=None, context=None): - self._field_get2(cr, uid, obj, context) - i = len(self._arg)-1 - sarg = name - while i>0: - if type(sarg) in [type([]), type( (1,) )]: - where = [(self._arg[i], 'in', sarg)] - else: - where = [(self._arg[i], '=', sarg)] - if domain: - where = map(lambda x: (self._arg[i],x[1], x[2]), domain) - domain = [] - sarg = obj.pool.get(self._relations[i]['object']).search(cr, uid, where, context=context) - i -= 1 - return [(self._arg[0], 'in', sarg)] + # assume self._arg = ('foo', 'bar', 'baz') + # domain = [(name, op, val)] => search [('foo.bar.baz', op, val)] + field = '.'.join(self._arg) + return map(lambda x: (field, x[1], x[2]), domain) def _fnct_write(self,obj,cr, uid, ids, field_name, values, args, context=None): self._field_get2(cr, uid, obj, context=context) diff --git a/openerp/tests/__init__.py b/openerp/tests/__init__.py index 5fccb07a082..e02a7d7042c 100644 --- a/openerp/tests/__init__.py +++ b/openerp/tests/__init__.py @@ -11,6 +11,7 @@ See the :ref:`test-framework` section in the :ref:`features` list. import test_expression import test_ir_sequence import test_orm +import test_fields fast_suite = [ test_ir_sequence, @@ -19,6 +20,7 @@ fast_suite = [ checks = [ test_expression, test_orm, + test_fields, ] # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/tests/test_fields.py b/openerp/tests/test_fields.py new file mode 100644 index 00000000000..c049a43fc97 --- /dev/null +++ b/openerp/tests/test_fields.py @@ -0,0 +1,59 @@ +# +# test cases for fields access, etc. +# + +import unittest2 +import common + +import openerp +from openerp.osv import fields + +class TestRelatedField(common.TransactionCase): + + def setUp(self): + super(TestRelatedField, self).setUp() + self.partner = self.registry('res.partner') + + def do_test_company_field(self, field): + # get a partner with a non-null company_id + ids = self.partner.search(self.cr, self.uid, [('company_id', '!=', False)], limit=1) + partner = self.partner.browse(self.cr, self.uid, ids[0]) + + # check reading related field + self.assertEqual(partner[field], partner.company_id) + + # check that search on related field is equivalent to original field + ids1 = self.partner.search(self.cr, self.uid, [('company_id', '=', partner.company_id.id)]) + ids2 = self.partner.search(self.cr, self.uid, [(field, '=', partner.company_id.id)]) + self.assertEqual(ids1, ids2) + + def test_1_single_related(self): + """ test a related field with a single indirection like fields.related('foo') """ + # add a related field test_related_company_id on res.partner + old_columns = self.partner._columns + self.partner._columns = dict(old_columns) + self.partner._columns.update({ + 'single_related_company_id': fields.related('company_id', type='many2one', obj='res.company'), + }) + + self.do_test_company_field('single_related_company_id') + + # restore res.partner fields + self.partner._columns = old_columns + + def test_2_related_related(self): + """ test a related field referring to a related field """ + # add a related field on a related field on res.partner + old_columns = self.partner._columns + self.partner._columns = dict(old_columns) + self.partner._columns.update({ + 'single_related_company_id': fields.related('company_id', type='many2one', obj='res.company'), + 'related_related_company_id': fields.related('single_related_company_id', type='many2one', obj='res.company'), + }) + + self.do_test_company_field('related_related_company_id') + + # restore res.partner fields + self.partner._columns = old_columns + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 8f8b5497d124fd553e6a44a21fca1eccca42d0f8 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Fri, 9 Mar 2012 17:15:47 +0100 Subject: [PATCH 009/703] [IMP] tests: add test on related fields bzr revid: rco@openerp.com-20120309161547-um53k5rqqts9flz6 --- openerp/tests/test_fields.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/openerp/tests/test_fields.py b/openerp/tests/test_fields.py index c049a43fc97..73f57ac8bbe 100644 --- a/openerp/tests/test_fields.py +++ b/openerp/tests/test_fields.py @@ -13,6 +13,29 @@ class TestRelatedField(common.TransactionCase): def setUp(self): super(TestRelatedField, self).setUp() self.partner = self.registry('res.partner') + self.company = self.registry('res.company') + + def test_0_related(self): + """ test an usual related field """ + # add a related field test_related_company_id on res.partner + old_columns = self.partner._columns + self.partner._columns = dict(old_columns) + self.partner._columns.update({ + 'related_company_partner_id': fields.related('company_id', 'partner_id', type='many2one', obj='res.partner'), + }) + + # find a company with a non-null partner_id + ids = self.company.search(self.cr, self.uid, [('partner_id', '!=', False)], limit=1) + id = ids[0] + + # find partners that satisfy [('partner_id.company_id', '=', id)] + company_ids = self.company.search(self.cr, self.uid, [('partner_id', '=', id)]) + partner_ids1 = self.partner.search(self.cr, self.uid, [('company_id', 'in', company_ids)]) + partner_ids2 = self.partner.search(self.cr, self.uid, [('related_company_partner_id', '=', id)]) + self.assertEqual(partner_ids1, partner_ids2) + + # restore res.partner fields + self.partner._columns = old_columns def do_test_company_field(self, field): # get a partner with a non-null company_id From 052c5f8eeb92570db295bedec4162225835f86e0 Mon Sep 17 00:00:00 2001 From: "Ajay Chauhan (OpenERP)" Date: Mon, 4 Jun 2012 17:03:50 +0530 Subject: [PATCH 010/703] [FIX] account_asset: change the calculation of field depreciated_value lp bug: https://launchpad.net/bugs/997141 fixed bzr revid: cha@tinyerp.com-20120604113350-sdzv1lr0zcf5l5wr --- addons/account_asset/account_asset.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py index 0799a59a423..362fcce1982 100644 --- a/addons/account_asset/account_asset.py +++ b/addons/account_asset/account_asset.py @@ -141,7 +141,6 @@ class account_asset_asset(osv.osv): old_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_id', '=', False)]) if old_depreciation_line_ids: depreciation_lin_obj.unlink(cr, uid, old_depreciation_line_ids, context=context) - amount_to_depr = residual_amount = asset.value_residual if asset.prorata: depreciation_date = datetime.strptime(self._get_last_depreciation_date(cr, uid, [asset.id], context)[asset.id], '%Y-%m-%d') @@ -159,13 +158,21 @@ class account_asset_asset(osv.osv): i = x + 1 amount = self._compute_board_amount(cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context) residual_amount -= amount + + if posted_depreciation_line_ids: + if x == range(len(posted_depreciation_line_ids), undone_dotation_number)[0] : + depreciated_value = depreciation_lin_obj.browse(cr, uid, posted_depreciation_line_ids[0], context=context).amount + else: + depreciated_value = depreciated_value + amount + else: + depreciated_value = (asset.purchase_value - asset.salvage_value) - (residual_amount + amount) vals = { 'amount': amount, 'asset_id': asset.id, 'sequence': i, 'name': str(asset.id) +'/' + str(i), 'remaining_value': residual_amount, - 'depreciated_value': (asset.purchase_value - asset.salvage_value) - (residual_amount + amount), + 'depreciated_value': depreciated_value, 'depreciation_date': depreciation_date.strftime('%Y-%m-%d'), } depreciation_lin_obj.create(cr, uid, vals, context=context) From 63702d6064d6dd457ccd82aa56ac44d375fe001c Mon Sep 17 00:00:00 2001 From: "Vidhin Mehta (OpenERP)" Date: Tue, 14 Aug 2012 14:20:41 +0530 Subject: [PATCH 011/703] [IMP]minor fix to view editor. bzr revid: vme@tinyerp.com-20120814085041-s0lkqzcnyks0ukdn --- addons/web_view_editor/static/src/css/view_editor.css | 4 ++++ addons/web_view_editor/static/src/js/view_editor.js | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/addons/web_view_editor/static/src/css/view_editor.css b/addons/web_view_editor/static/src/css/view_editor.css index e80e15a4c17..2f2b5860cf6 100644 --- a/addons/web_view_editor/static/src/css/view_editor.css +++ b/addons/web_view_editor/static/src/css/view_editor.css @@ -19,3 +19,7 @@ .openerp .oe_view_editor tr:hover { background-color: #ecebf2; } +.openerp .oe_view_editor_field a{ + font-size : 12px; + color : #404040; +} \ No newline at end of file diff --git a/addons/web_view_editor/static/src/js/view_editor.js b/addons/web_view_editor/static/src/js/view_editor.js index cfdd5d6bfea..770d32b2e56 100644 --- a/addons/web_view_editor/static/src/js/view_editor.js +++ b/addons/web_view_editor/static/src/js/view_editor.js @@ -73,8 +73,7 @@ instance.web_view_editor.ViewEditor = instance.web.OldWidget.extend({ $.when(this.action_manager.do_action(action)).then(function() { var viewmanager = self.action_manager.inner_widget, controller = viewmanager.views[viewmanager.active_view].controller; - self.action_manager.appendTo(self.view_edit_dialog.$element); - self.action_manager.renderElement(self.view_edit_dialog); + self.action_manager.$element.appendTo(self.view_edit_dialog.$element); controller.on_loaded.add_last(function(){ $(controller.groups).bind({ 'selected': function(e, ids, records) { From 987e362d7f9f507a00aabbedc24790580aa4b7a8 Mon Sep 17 00:00:00 2001 From: "Ajay Chauhan (OpenERP)" Date: Fri, 24 Aug 2012 10:47:06 +0530 Subject: [PATCH 012/703] [IMP] account_asset: revert old changes bzr revid: cha@tinyerp.com-20120824051706-16pn120zdtxfve49 --- addons/account_asset/account_asset.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py index 362fcce1982..c4c1db0dec2 100644 --- a/addons/account_asset/account_asset.py +++ b/addons/account_asset/account_asset.py @@ -141,6 +141,7 @@ class account_asset_asset(osv.osv): old_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_id', '=', False)]) if old_depreciation_line_ids: depreciation_lin_obj.unlink(cr, uid, old_depreciation_line_ids, context=context) + amount_to_depr = residual_amount = asset.value_residual if asset.prorata: depreciation_date = datetime.strptime(self._get_last_depreciation_date(cr, uid, [asset.id], context)[asset.id], '%Y-%m-%d') @@ -158,21 +159,13 @@ class account_asset_asset(osv.osv): i = x + 1 amount = self._compute_board_amount(cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context) residual_amount -= amount - - if posted_depreciation_line_ids: - if x == range(len(posted_depreciation_line_ids), undone_dotation_number)[0] : - depreciated_value = depreciation_lin_obj.browse(cr, uid, posted_depreciation_line_ids[0], context=context).amount - else: - depreciated_value = depreciated_value + amount - else: - depreciated_value = (asset.purchase_value - asset.salvage_value) - (residual_amount + amount) vals = { 'amount': amount, 'asset_id': asset.id, 'sequence': i, 'name': str(asset.id) +'/' + str(i), 'remaining_value': residual_amount, - 'depreciated_value': depreciated_value, + 'depreciated_value': (asset.purchase_value - asset.salvage_value) - (residual_amount + amount), 'depreciation_date': depreciation_date.strftime('%Y-%m-%d'), } depreciation_lin_obj.create(cr, uid, vals, context=context) From 87e7926a14aef3841ef401b7cd32ea45b5718642 Mon Sep 17 00:00:00 2001 From: "Ajay Chauhan (OpenERP)" Date: Fri, 24 Aug 2012 11:17:47 +0530 Subject: [PATCH 013/703] [IMP] account_asset: fixed depriciation board calculation problem bzr revid: cha@tinyerp.com-20120824054747-vgfv4e3xv7h7ao0r --- addons/account_asset/account_asset.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py index 2dc95e832e6..bbad438f1db 100644 --- a/addons/account_asset/account_asset.py +++ b/addons/account_asset/account_asset.py @@ -141,7 +141,7 @@ class account_asset_asset(osv.osv): old_depreciation_line_ids = depreciation_lin_obj.search(cr, uid, [('asset_id', '=', asset.id), ('move_id', '=', False)]) if old_depreciation_line_ids: depreciation_lin_obj.unlink(cr, uid, old_depreciation_line_ids, context=context) - + amount_to_depr = residual_amount = asset.value_residual if asset.prorata: depreciation_date = datetime.strptime(self._get_last_depreciation_date(cr, uid, [asset.id], context)[asset.id], '%Y-%m-%d') @@ -189,7 +189,7 @@ class account_asset_asset(osv.osv): def _amount_residual(self, cr, uid, ids, name, args, context=None): cr.execute("""SELECT - l.asset_id as id, round(SUM(abs(l.debit-l.credit))) AS amount + l.asset_id as id, SUM(abs(l.debit-l.credit)) AS amount FROM account_move_line l WHERE From 151552cfdfe4af85ac2e6921a63738bdc5518a8b Mon Sep 17 00:00:00 2001 From: "Ajay Chauhan (OpenERP)" Date: Tue, 28 Aug 2012 14:52:32 +0530 Subject: [PATCH 014/703] [IMP] account_asset: fix the issue of residual value bzr revid: cha@tinyerp.com-20120828092232-7a8t9ntuto0eubhb --- addons/account_asset/account_asset.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/addons/account_asset/account_asset.py b/addons/account_asset/account_asset.py index bbad438f1db..3ea38ef9aa2 100644 --- a/addons/account_asset/account_asset.py +++ b/addons/account_asset/account_asset.py @@ -134,6 +134,7 @@ class account_asset_asset(osv.osv): def compute_depreciation_board(self, cr, uid, ids, context=None): depreciation_lin_obj = self.pool.get('account.asset.depreciation.line') + currency_obj = self.pool.get('res.currency') for asset in self.browse(cr, uid, ids, context=context): if asset.value_residual == 0.0: continue @@ -158,6 +159,9 @@ class account_asset_asset(osv.osv): for x in range(len(posted_depreciation_line_ids), undone_dotation_number): i = x + 1 amount = self._compute_board_amount(cr, uid, asset, i, residual_amount, amount_to_depr, undone_dotation_number, posted_depreciation_line_ids, total_days, depreciation_date, context=context) + company_currency = asset.company_id.currency_id.id + current_currency = asset.currency_id.id + amount = currency_obj.compute(cr, uid, current_currency, company_currency, amount, context=context) residual_amount -= amount vals = { 'amount': amount, @@ -347,8 +351,8 @@ class account_asset_depreciation_line(osv.osv): 'sequence': fields.integer('Sequence', required=True), 'asset_id': fields.many2one('account.asset.asset', 'Asset', required=True), 'parent_state': fields.related('asset_id', 'state', type='char', string='State of Asset'), - 'amount': fields.float('Depreciation Amount', required=True), - 'remaining_value': fields.float('Amount to Depreciate', required=True), + 'amount': fields.float('Depreciation Amount', digits_compute=dp.get_precision('Account'), required=True), + 'remaining_value': fields.float('Amount to Depreciate', digits_compute=dp.get_precision('Account'),required=True), 'depreciated_value': fields.float('Amount Already Depreciated', required=True), 'depreciation_date': fields.char('Depreciation Date', size=64, select=1), 'move_id': fields.many2one('account.move', 'Depreciation Entry'), From 112e96cc202bc46e7ec19e750316420a9a45f465 Mon Sep 17 00:00:00 2001 From: "Mayur Maheshwari (OpenERP)" Date: Fri, 7 Sep 2012 18:52:42 +0530 Subject: [PATCH 015/703] [FIX]mrp_repair:set a proper attrs on button lp bug: https://launchpad.net/bugs/1047365 fixed bzr revid: mma@tinyerp.com-20120907132242-w9oabs4jecp3auo8 --- addons/mrp_repair/mrp_repair_view.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/mrp_repair/mrp_repair_view.xml b/addons/mrp_repair/mrp_repair_view.xml index 55cbe49c75b..e343f5b25ce 100644 --- a/addons/mrp_repair/mrp_repair_view.xml +++ b/addons/mrp_repair/mrp_repair_view.xml @@ -34,8 +34,9 @@ - or - Cancel + + or Cancel From a10c6c4dfdab8d7a8a1f722333d4a9c9b654f0c6 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Thu, 25 Oct 2012 10:36:31 +0200 Subject: [PATCH 328/703] [IMP] mail: change message_post_api (method py return id); class indented in DOM for expandable & compose bzr revid: chm@openerp.com-20121025083631-ze0x0rmnj7catsmu --- addons/mail/mail_thread.py | 3 +- addons/mail/static/src/js/mail.js | 71 ++++++++++++++--------------- addons/mail/static/src/xml/mail.xml | 6 +-- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/addons/mail/mail_thread.py b/addons/mail/mail_thread.py index af4818bcbcd..7d3f48b0f3d 100644 --- a/addons/mail/mail_thread.py +++ b/addons/mail/mail_thread.py @@ -708,8 +708,7 @@ class mail_thread(osv.AbstractModel): ir_attachment.write(cr, SUPERUSER_ID, attachment_ids, {'res_model': self._name, 'res_id': thread_id}, context=context) mail_message.write(cr, SUPERUSER_ID, [new_message_id], {'attachment_ids': [(6, 0, [pid for pid in attachment_ids])]}, context=context) - new_message = self.pool.get('mail.message').message_read(cr, uid, [new_message_id], context=context) - return new_message + return new_message_id #------------------------------------------------------ # Followers API diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 6ba893339fc..f30255d209c 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -155,6 +155,7 @@ openerp.mail = function(session) { this.is_private = datasets.is_private || false; this.partner_ids = datasets.partner_ids || []; this.avatar = mail.ChatterUtils.get_image(this.session, 'res.users', 'image_small', this.session.uid); + this.thread_level = datasets.thread_level; this.parent_thread= parent.messages!= undefined ? parent : false; this.ds_attachment = new session.web.DataSetSearch(this, 'ir.attachment'); @@ -372,10 +373,9 @@ openerp.mail = function(session) { 'mail.mt_comment', this.context.default_parent_id, attachments, - // (this.options.display_indented_thread - this.thread_level), this.parent_thread.context - ]).then(function(records) { - self.parent_thread.switch_new_message(records); + ]).then(function(message_id) { + self.parent_thread.message_fetch([['id', '=', message_id]]); self.on_cancel(); //session.web.unblockUI(); }); @@ -457,13 +457,14 @@ openerp.mail = function(session) { mail.ThreadExpandable = session.web.Widget.extend({ template: 'mail.thread.expandable', - init: function(parent, datasets, options) { + init: function(parent, datasets, context) { this._super(parent); - this.domain = options.domain || []; + this.domain = datasets.domain || []; + this.options = datasets.options; this.context = _.extend({ default_model: 'mail.thread', default_res_id: 0, - default_parent_id: false }, options.context || {}); + default_parent_id: false }, context || {}); // data of this expandable message this.id = datasets.id || -1, @@ -474,7 +475,7 @@ openerp.mail = function(session) { this.type = 'expandable', this.max_limit = this.id < 0 || false, this.flag_used = false, - this.parent_thread= parent.messages!= undefined ? parent : options.options._parents[0]; + this.parent_thread= parent.messages!= undefined ? parent : this.options._parents[0]; }, @@ -572,9 +573,19 @@ openerp.mail = function(session) { *... @param {int} [show_reply_button] number thread level to display the reply button *... @param {int} [show_read_unread_button] number thread level to display the read/unread button */ - init: function(parent, datasets, options) { + init: function(parent, datasets, context) { this._super(parent); + // record domain and context + this.domain = datasets.domain || []; + this.context = _.extend({ + default_model: 'mail.thread', + default_res_id: 0, + default_parent_id: false }, context || {}); + + // record options + this.options = datasets.options; + // data of this message this.id = datasets.id || -1, this.model = datasets.model || false, @@ -596,21 +607,12 @@ openerp.mail = function(session) { this.attachment_ids = datasets.attachment_ids || [], this._date = datasets.date; - // record domain and context - this.domain = options.domain || []; - this.context = _.extend({ - default_model: 'mail.thread', - default_res_id: 0, - default_parent_id: false }, options.context || {}); - - // record options - this.options = options.options; this.show_reply_button = this.options.show_compose_message && this.options.show_reply_button > this.thread_level; this.show_read_unread_button = this.options.show_read_unread_button > this.thread_level; // record options and data - this.parent_thread= parent.messages!= undefined ? parent : options.options._parents[0]; + this.parent_thread= parent.messages!= undefined ? parent : this.options._parents[0]; this.thread = false; if( this.id > 0 ) { @@ -1167,22 +1169,20 @@ openerp.mail = function(session) { create_message_object: function (data) { var self = this; + var data = _.extend(data, {'thread_level': data.thread_level ? data.thread_level : self.thread_level}); + data.options = _.extend(self.options, data.options); + if(data.type=='expandable'){ var message = new mail.ThreadExpandable(self, data, { - '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.id }, + 'default_model': data.model || self.context.default_model, + 'default_res_id': data.res_id || self.context.default_res_id, + 'default_parent_id': self.id, }); } else { - var message = new mail.ThreadMessage(self, _.extend(data, {'thread_level': data.thread_level ? data.thread_level : self.thread_level}), { - 'domain': data.domain, - 'context': { - 'default_model': data.model, - 'default_res_id': data.res_id, - 'default_parent_id': data.id }, - 'options': _.extend(self.options, data.options) + var message = new mail.ThreadMessage(self, data, { + 'default_model': data.model, + 'default_res_id': data.res_id, + 'default_parent_id': data.id, }); } @@ -1368,13 +1368,12 @@ openerp.mail = function(session) { 'ancestor_id': message.ancestor_id, 'nb_messages': 1, 'thread_level': message.thread_level, - 'ancestor_id': message.ancestor_id - }, { + 'ancestor_id': message.ancestor_id, 'domain': message_dom, - 'context': { - 'default_model': message.model || this.context.default_model, - 'default_res_id': message.res_id || this.context.default_res_id, - 'default_parent_id': this.id }, + }, { + 'default_model': message.model || this.context.default_model, + 'default_res_id': message.res_id || this.context.default_res_id, + 'default_parent_id': this.id, }); // add object on array and DOM diff --git a/addons/mail/static/src/xml/mail.xml b/addons/mail/static/src/xml/mail.xml index e806cf93a22..0f0362e84ce 100644 --- a/addons/mail/static/src/xml/mail.xml +++ b/addons/mail/static/src/xml/mail.xml @@ -15,7 +15,7 @@ for main thread composition form in document form view. --> -
+
User img
@@ -40,7 +40,7 @@ mail.compose_message when focus on textarea --> -
+
+
+ "},set_value:function(a,b){a.innerHTML=b||""},get_value:function(a){return a.innerHTML||""},focus:function(){}},textarea:{render:function(a){var b=(a.height||"130")+"px";return"
"},set_value:function(a,b){a.firstChild.value=b||""},get_value:function(a){return a.firstChild.value}, -focus:function(a){var b=a.firstChild;b.select();b.focus()}},select:{render:function(a){for(var b=(a.height||"23")+"px",c="
";return c},set_value:function(a,b,c,d){var e=a.firstChild;if(!e._dhx_onchange&&d.onchange)e.onchange=d.onchange,e._dhx_onchange=!0;if(typeof b=="undefined")b=(e.options[0]||{}).value; -e.value=b||""},get_value:function(a){return a.firstChild.value},focus:function(a){var b=a.firstChild;b.select&&b.select();b.focus()}},time:{render:function(a){var b=scheduler.config,c=this.date.date_part(new Date),d=1440,e=0;scheduler.config.limit_time_select&&(d=60*b.last_hour+1,e=60*b.first_hour,c.setHours(b.first_hour));var f=" ";return"
"+ -f+"  –  "+f+"
"},set_value:function(a,b,c,d){function e(a,b,c){for(var e=d._time_values,f=c.getHours()*60+c.getMinutes(),g=f,h=!1,i=0;i";scheduler.config.wide_form||(h=a.previousSibling.innerHTML+h);a.previousSibling.innerHTML=h;a._full_day=!0}var k=a.previousSibling.getElementsByTagName("input")[0];k.checked=scheduler.date.time_part(c.start_date)===0&&scheduler.date.time_part(c.end_date)===0;g[0].disabled=k.checked;g[g.length/2].disabled=k.checked;k.onclick=function(){if(k.checked){var b={};scheduler.form_blocks.time.get_value(a,b);var d=scheduler.date.date_part(b.start_date), -f=scheduler.date.date_part(b.end_date);if(+f==+d||+f>=+d&&(c.end_date.getHours()!=0||c.end_date.getMinutes()!=0))f=scheduler.date.add(f,1,"day")}g[0].disabled=k.checked;g[g.length/2].disabled=k.checked;e(g,0,d||c.start_date);e(g,4,f||c.end_date)}}if(f.auto_end_date&&f.event_duration)for(var i=function(){var a=new Date(g[3].value,g[2].value,g[1].value,0,g[0].value),b=new Date(a.getTime()+scheduler.config.event_duration*6E4);e(g,4,b)},j=0;j<4;j++)g[j].onchange=i;e(g,0,c.start_date);e(g,4,c.end_date)}, -get_value:function(a,b){s=a.getElementsByTagName("select");b.start_date=new Date(s[3].value,s[2].value,s[1].value,0,s[0].value);b.end_date=new Date(s[7].value,s[6].value,s[5].value,0,s[4].value);if(b.end_date<=b.start_date)b.end_date=scheduler.date.add(b.start_date,scheduler.config.time_step,"minute");return{start_date:new Date(b.start_date),end_date:new Date(b.end_date)}},focus:function(a){a.getElementsByTagName("select")[0].focus()}}}; -scheduler.showCover=function(a){if(a){a.style.display="block";var b=window.pageYOffset||document.body.scrollTop||document.documentElement.scrollTop,c=window.pageXOffset||document.body.scrollLeft||document.documentElement.scrollLeft,d=window.innerHeight||document.documentElement.clientHeight;a.style.top=b?Math.round(b+Math.max((d-a.offsetHeight)/2,0))+"px":Math.round(Math.max((d-a.offsetHeight)/2,0)+9)+"px";a.style.left=document.documentElement.scrollWidth>document.body.offsetWidth?Math.round(c+(document.body.offsetWidth- -a.offsetWidth)/2)+"px":Math.round((document.body.offsetWidth-a.offsetWidth)/2)+"px"}this.show_cover()};scheduler.showLightbox=function(a){if(a)if(this.callEvent("onBeforeLightbox",[a])){var b=this.getLightbox();this.showCover(b);this._fill_lightbox(a,b);this.callEvent("onLightbox",[a])}else if(this._new_event)this._new_event=null}; -scheduler._fill_lightbox=function(a,b){var c=this.getEvent(a),d=b.getElementsByTagName("span");scheduler.templates.lightbox_header?(d[1].innerHTML="",d[2].innerHTML=scheduler.templates.lightbox_header(c.start_date,c.end_date,c)):(d[1].innerHTML=this.templates.event_header(c.start_date,c.end_date,c),d[2].innerHTML=(this.templates.event_bar_text(c.start_date,c.end_date,c)||"").substr(0,70));for(var e=this.config.lightbox.sections,f=0;f
"+scheduler.locale.labels[c[d]]+"
";c=this.config.buttons_right;for(d=0;d
"+scheduler.locale.labels[c[d]]+"
";b+="
";a.innerHTML=b;if(scheduler.config.drag_lightbox)a.firstChild.onmousedown=scheduler._ready_to_dnd,a.firstChild.onselectstart=function(){return!1},a.firstChild.style.cursor="pointer",scheduler._init_dnd_events(); -document.body.insertBefore(a,document.body.firstChild);this._lightbox=a;for(var e=this.config.lightbox.sections,b="",d=0;d
"+this.locale.labels["button_"+e[d].button]+"
");this.config.wide_form&&(b+="
");b+="
"+ -g+this.locale.labels["section_"+e[d].name]+"
"+f.render.call(this,e[d]);b+="
"}}for(var h=a.getElementsByTagName("div"),d=0;d"+e(a)+""};var f=scheduler.templates.week_scale_date;scheduler.templates.week_scale_date=function(a){return""+f(a)+""};dhtmlxEvent(this._obj,"click",function(a){var b=a.target||event.srcElement, -c=b.getAttribute("jump_to");if(c)return scheduler.setCurrentView(d(c),scheduler.config.active_link_view),a&&a.preventDefault&&a.preventDefault(),!1})}); diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_agenda_view.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_agenda_view.js deleted file mode 100644 index 2871439cc68..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_agenda_view.js +++ /dev/null @@ -1,11 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.date.add_agenda=function(a){return scheduler.date.add(a,1,"year")};scheduler.templates.agenda_time=function(a,d,c){return c._timed?this.day_date(c.start_date,c.end_date,c)+" "+this.event_date(a):scheduler.templates.day_date(a)+" – "+scheduler.templates.day_date(d)};scheduler.templates.agenda_text=function(a,d,c){return c.text};scheduler.templates.agenda_date=function(){return""};scheduler.date.agenda_start=function(){return scheduler.date.date_part(new Date)}; -scheduler.attachEvent("onTemplatesReady",function(){function a(c){if(c){var a=scheduler.locale.labels;scheduler._els.dhx_cal_header[0].innerHTML="
"+a.date+"
"+a.description+"
";scheduler._table_view=!0;scheduler.set_sizes()}}function d(){var c=scheduler._date,a=scheduler.get_visible_events();a.sort(function(b,a){return b.start_date>a.start_date?1:-1});for(var d="
",e=0;e
"+scheduler.templates.agenda_time(b.start_date,b.end_date,b)+"
";d+="
 
";d+=""+scheduler.templates.agenda_text(b.start_date,b.end_date,b)+"
"}d+= -"
";scheduler._els.dhx_cal_data[0].innerHTML=d;scheduler._els.dhx_cal_data[0].childNodes[0].scrollTop=scheduler._agendaScrollTop||0;var f=scheduler._els.dhx_cal_data[0].childNodes[0],k=f.childNodes[f.childNodes.length-1];k.style.height=f.offsetHeight=24)},j=scheduler._pre_render_events_line;scheduler._pre_render_events_line=function(a,f){if(!this.config.all_timed)return j.call(this,a,f);for(var c=0;cthis._min_date&&b.start_dateb.end_date&&a.splice(c--,1);var e=this._lame_copy({},d);e.end_date=new Date(e.end_date);e.start_date=e.start_date=i&&(l=!1)}else a.length>=i&&(l=!1);if(!l){var p=!scheduler.callEvent("onEventCollision",[b,a]);p||(b[k]=n||b[k]);return p}return l}var n,d;scheduler.config.collision_limit=1;scheduler.attachEvent("onBeforeDrag", -function(b){h(b);return!0});scheduler.attachEvent("onBeforeLightbox",function(b){var a=scheduler.getEvent(b);d=[a.start_date,a.end_date];h(b);return!0});scheduler.attachEvent("onEventChanged",function(b){if(!b)return!0;var a=scheduler.getEvent(b);if(!g(a)){if(!d)return!1;a.start_date=d[0];a.end_date=d[1];a._timed=this.is_one_day_event(a)}return!0});scheduler.attachEvent("onBeforeEventChanged",function(b){return g(b)});scheduler.attachEvent("onEventSave",function(b,a){a=scheduler._lame_clone(a);a.id= -b;a.rec_type&&scheduler._roll_back_dates(data_copy);return g(a)})})(); diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_cookie.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_cookie.js deleted file mode 100644 index 774a629f8cb..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_cookie.js +++ /dev/null @@ -1,6 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -(function(){function g(e,b,a){var c=e+"="+a+(b?"; "+b:"");document.cookie=c}function h(e){var b=e+"=";if(document.cookie.length>0){var a=document.cookie.indexOf(b);if(a!=-1){a+=b.length;var c=document.cookie.indexOf(";",a);if(c==-1)c=document.cookie.length;return document.cookie.substring(a,c)}}return""}var f=!0;scheduler.attachEvent("onBeforeViewChange",function(e,b,a,c){if(f){f=!1;var d=h("scheduler_settings");if(d)return d=unescape(d).split("@"),d[0]=this.templates.xml_date(d[0]),window.setTimeout(function(){scheduler.setCurrentView(d[0], -d[1])},1),!1}var i=escape(this.templates.xml_format(c||b)+"@"+(a||e));g("scheduler_settings","expires=Sun, 31 Jan 9999 22:00:00 GMT",i);return!0})})(); diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_dhx_terrace.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_dhx_terrace.js deleted file mode 100644 index 89e7d1b16f8..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_dhx_terrace.js +++ /dev/null @@ -1,8 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -(function(){scheduler.config.fix_tab_position=!0;scheduler.config.use_select_menu_space=!0;scheduler.config.hour_size_px=44;scheduler.xy.nav_height=59;scheduler.xy.bar_height=24;scheduler.config.wide_form=!0;scheduler.xy.lightbox_additional_height=90;scheduler.config.displayed_event_color="#ff4a4a";scheduler.config.displayed_event_text_color="#ffef80";scheduler.templates.event_bar_date=function(c){return"\u2022 "+scheduler.templates.event_date(c)+" "};scheduler.attachEvent("onLightbox",function(){for(var c= -scheduler.getLightbox(),d=c.getElementsByTagName("div"),b=0;b 
";scheduler.attachEvent("onTemplatesReady",function(){var c=scheduler.date.date_to_str("%d"), -d=scheduler.templates.month_day;scheduler.templates.month_day=function(a){if(this._mode=="month"){var b=c(a);a.getDate()==1&&(b=scheduler.locale.date.month_full[a.getMonth()]+" "+b);+a==+scheduler.date.date_part(new Date)&&(b=scheduler.locale.labels.dhx_cal_today_button+" "+b);return b}else return d.call(this,a)};if(scheduler.config.fix_tab_position)for(var b=scheduler._els.dhx_cal_navline[0].getElementsByTagName("div"),e=[],f=211,g=0;g";return d},set_value:function(b,d,c,a){b._combo&&b._combo.destructor();window.dhx_globalImgPath=a.image_path||"/";b._combo=new dhtmlXCombo(b,a.name,b.offsetWidth-8);a.options_height&&b._combo.setOptionHeight(a.options_height);var e=b._combo;e.enableFilteringMode(!!a.filtering,a.script_path||null,!!a.cache);if(a.script_path){var f= -c[a.map_to];f?a.cached_options[f]?(e.addOption(f,a.cached_options[f]),e.disable(1),e.selectOption(0),e.disable(0)):dhtmlxAjax.get(a.script_path+"?id="+f+"&uid="+scheduler.uid(),function(b){var c=b.doXPath("//option")[0],d=c.childNodes[0].nodeValue;a.cached_options[f]=d;e.addOption(f,d);e.disable(1);e.selectOption(0);e.disable(0)}):e.setComboValue(null)}else{for(var g=[],h=0;h";for(var c=0;c";b.vertical&&(d+="
")}d+="";return d},set_value:function(b,d,c,a){for(var e=b.getElementsByTagName("input"),f=0;f':""},set_value:function(b,d,c,a){var b=document.getElementById(a.id),e=scheduler.uid(),f=typeof a.checked_value!="undefined"?c[a.map_to]==a.checked_value:!!d;b.className+=" dhx_cal_checkbox";var g="",h=""; -scheduler.config.wide_form?(b.innerHTML=h,b.nextSibling.innerHTML=g):b.innerHTML=g+h;if(a.handler){var i=b.getElementsByTagName("input")[0];i.onclick=a.handler}},get_value:function(b,d,c){var b=document.getElementById(c.id),a=b.getElementsByTagName("input")[0];a||(a=b.nextSibling.getElementsByTagName("input")[0]);return a.checked?c.checked_value||!0:c.unchecked_value||!1},focus:function(){}}; diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_expand.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_expand.js deleted file mode 100644 index fdc64711b59..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_expand.js +++ /dev/null @@ -1,8 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.expand=function(){var a=scheduler._obj;do a._position=a.style.position||"",a.style.position="static";while((a=a.parentNode)&&a.style);a=scheduler._obj;a.style.position="absolute";a._width=a.style.width;a._height=a.style.height;a.style.width=a.style.height="100%";a.style.top=a.style.left="0px";var b=document.body;b.scrollTop=0;if(b=b.parentNode)b.scrollTop=0;document.body._overflow=document.body.style.overflow||"";document.body.style.overflow="hidden";scheduler._maximize()}; -scheduler.collapse=function(){var a=scheduler._obj;do a.style.position=a._position;while((a=a.parentNode)&&a.style);a=scheduler._obj;a.style.width=a._width;a.style.height=a._height;document.body.style.overflow=document.body._overflow;scheduler._maximize()};scheduler.attachEvent("onTemplatesReady",function(){var a=document.createElement("DIV");a.className="dhx_expand_icon";scheduler.toggleIcon=a;scheduler._obj.appendChild(a);a.onclick=function(){scheduler.expanded?scheduler.collapse():scheduler.expand()}}); -scheduler._maximize=function(){this.expanded=!this.expanded;this.toggleIcon.style.backgroundPosition="0px "+(this.expanded?"0":"18")+"px";for(var a=["left","top"],b=0;bnew Date(0)&&scheduler._max_date "; -b.innerHTML+=a};scheduler.grid.sort_grid=function(b){var b=b||{dir:"desc",value:function(a){return a.start_date},rule:scheduler.grid.sort_rules.date},d=scheduler.get_visible_events();b.dir=="desc"?d.sort(function(a,c){return b.rule(a,c,b.value)}):d.sort(function(a,c){return-b.rule(a,c,b.value)});return d};scheduler.grid.set_full_view=function(b){if(b){var d=scheduler.locale.labels,a=scheduler.grid._print_grid_header(b);scheduler._els.dhx_cal_header[0].innerHTML=a;scheduler._table_view=!0;scheduler.set_sizes()}}; -scheduler.grid._calcPadding=function(b,d){var a=(b.paddingLeft!==void 0?1*b.paddingLeft:scheduler[d].defPadding)+(b.paddingRight!==void 0?1*b.paddingRight:scheduler[d].defPadding);return a}; -scheduler.grid._getStyles=function(b,d){for(var a=[],c="",e=0;d[e];e++)switch(c=d[e]+":",d[e]){case "text-align":b.align&&a.push(c+b.align);break;case "vertical-align":b.valign&&a.push(c+b.valign);break;case "padding-left":b.paddingLeft!=void 0&&a.push(c+(b.paddingLeft||"0")+"px");break;case "padding-left":b.paddingRight!=void 0&&a.push(c+(b.paddingRight||"0")+"px")}return a}; -scheduler.grid._fill_grid_tab=function(b,d){for(var a=scheduler._date,c=scheduler.grid.sort_grid(d),e=scheduler[b].columns,f="
",i=-2,g=0;g
")}f+="";f+="
";for(g=0;g";scheduler._els.dhx_cal_data[0].innerHTML=f;scheduler._els.dhx_cal_data[0].scrollTop= -scheduler.grid._gridScrollTop||0;var h=scheduler._els.dhx_cal_data[0].getElementsByTagName("tr");scheduler._rendered=[];for(g=0;g",g=scheduler.grid._getViewName(d),k=["text-align", -"vertical-align","padding-left","padding-right"],h=0;h"+j+""}i+= -"";return i}; -scheduler.grid._print_grid_header=function(b){for(var d="
",a=scheduler[b].columns,c=[],e=a.length,f=scheduler._obj.clientWidth-2*a.length-20,i=0;i"+(a[j].label===void 0?a[j].id:a[j].label)+"
"}d+="";return d}; diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_html_templates.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_html_templates.js deleted file mode 100644 index da1bccf0da9..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_html_templates.js +++ /dev/null @@ -1,5 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.attachEvent("onTemplatesReady",function(){for(var c=document.body.getElementsByTagName("DIV"),b=0;bscheduler.config.limit_end.valueOf()||this.date.add(d,1,c)<=scheduler.config.limit_start.valueOf())?(setTimeout(function(){scheduler.setCurrentView(scheduler._date,c)},1),!1):!0});var x=function(b,a,c){var d=c[a]&&c[a][s]?c[a][s]:c[b]&&c[b][s]?c[b][s]:[];return d},t=function(b){if(!b)return!0;if(!scheduler.config.check_limits)return!0;for(var a=scheduler,c=a._mode,d=scheduler._marked_timespans,e=a.config,h=[],h=b.rec_type? -scheduler.getRecDates(b):[b],g=!0,i=0;i=e.limit_start.valueOf()&&f.end_date.valueOf()<=e.limit_end.valueOf():!0)for(var j=new Date(f.start_date.valueOf()),p=scheduler.date.add(j,1,"day");jp||f.end_date.getDate()!=j.getDate()?1440:scheduler._get_zone_minutes(f.end_date);if(k)for(l=0;lC){if(C<=w&&C>=z){if(w==1440||y=z&&yw)if(f._timed&&a._drag_id&&a._drag_mode=="new-size")f.end_date.setHours(0),f.end_date.setMinutes(z);else{g=!1;break}}}}if(!g)a._drag_id=null,a._drag_mode=null,g=a.checkEvent("onLimitViolation")?a.callEvent("onLimitViolation",[f.id,f]):g}return g};scheduler.attachEvent("onMouseDown", -function(b){return!(b=s)});scheduler.attachEvent("onBeforeDrag",function(b){return!b?!0:t(scheduler.getEvent(b))});scheduler.attachEvent("onClick",function(b){return t(scheduler.getEvent(b))});scheduler.attachEvent("onBeforeLightbox",function(b){var a=scheduler.getEvent(b);u=[a.start_date,a.end_date];return t(a)});scheduler.attachEvent("onEventSave",function(b,a){if(a.rec_type){var c=scheduler._lame_clone(a);scheduler._roll_back_dates(c)}return t(a)});scheduler.attachEvent("onEventAdded",function(b){if(!b)return!0; -var a=scheduler.getEvent(b);if(!t(a)&&scheduler.config.limit_start&&scheduler.config.limit_end){if(a.start_date=scheduler.config.limit_end.valueOf())a.start_date=this.date.add(scheduler.config.limit_end,-1,"day");if(a.end_date=scheduler.config.limit_end.valueOf())a.end_date=this.date.add(scheduler.config.limit_end, --1,"day");if(a.start_date.valueOf()>=a.end_date.valueOf())a.end_date=this.date.add(a.start_date,this.config.event_duration||this.config.time_step,"minute");a._timed=this.is_one_day_event(a)}return!0});scheduler.attachEvent("onEventChanged",function(b){if(!b)return!0;var a=scheduler.getEvent(b);if(!t(a)){if(!u)return!1;a.start_date=u[0];a.end_date=u[1];a._timed=this.is_one_day_event(a)}return!0});scheduler.attachEvent("onBeforeEventChanged",function(b){return t(b)});scheduler.attachEvent("onBeforeEventCreated", -function(b){var a=scheduler.getActionData(b).date,c={_timed:!0,start_date:a,end_date:scheduler.date.add(a,scheduler.config.time_step,"minute")};return t(c)});scheduler.attachEvent("onViewChange",function(){scheduler.markNow()});scheduler.attachEvent("onSchedulerResize",function(){window.setTimeout(function(){scheduler.markNow()},1);return!0});scheduler.attachEvent("onTemplatesReady",function(){scheduler._mark_now_timer=window.setInterval(function(){scheduler.markNow()},6E4)});scheduler.markNow=function(b){var a= -"dhx_now_time";this._els[a]||(this._els[a]=[]);var c=scheduler.config.now_date||new Date,d=this.config;scheduler._remove_mark_now();if(!b&&d.mark_now&&cthis._min_date&&c.getHours()>=d.first_hour&&c.getHours()b.start_date||b.days!==void 0&&b.zones))return a; -var g=0,i=1440;if(b.zones=="fullday")b.zones=[g,i];if(b.zones&&b.invert_zones)b.zones=scheduler.invertZones(b.zones);b.id=scheduler.uid();b.css=b.css||"";b.type=b.type||"default";var f=b.sections;if(f)for(var j in f){if(f.hasOwnProperty(j)){var p=f[j];p instanceof Array||(p=[p]);for(e=0;er?scheduler._get_zone_minutes(m):g,s=q>v||q.getDate()!=r.getDate()?i:scheduler._get_zone_minutes(q);n.zones=[l,s];a.push(n);r=v;v=scheduler.date.add(v,1,"day")}else{if(k.days instanceof Date)k.days=scheduler.date.date_part(k.days).valueOf();k.zones=b.zones.slice();a.push(k)}}return a};scheduler._get_dates_by_index=function(b,a,c){for(var d=[],a=a||scheduler._min_date, -c=c||scheduler._max_date,e=a.getDay(),h=b-e>=0?b-e:7-a.getDay()+b,g=scheduler.date.add(a,h,"day");g=+f&&+h<=+f))return d;var j=f.getDay(),c=scheduler.config.start_on_monday?j==0?6:j-1:j}var p=b.zones,n=scheduler._get_css_classes_by_config(b);if(scheduler._table_view&&scheduler._mode=="month"){var o=[],k=[];if(a)o.push(a),k.push(c);else for(var k=i?[i]:scheduler._get_dates_by_index(c),m=0;mh&&f<=h||f=e)c[d]=Math.min(e,f),c[d+1]=Math.max(h,j),d-=2;else{if(!g)continue;var p=e>f?0:2;c.splice(d+p,0,f,j)}a.splice(i--,2);break}return c};scheduler._subtract_timespan_zones=function(b,a){for(var c=b.slice(),d=0;de&&i=i&&h<=f&&c.splice(d,2);ef&&c.splice(j?d+2:d,j?0:2,f,h);d-=2;break}}return c};scheduler.invertZones=function(b){return scheduler._subtract_timespan_zones([0,1440],b.slice())};scheduler._delete_marked_timespan_by_id=function(b){var a=scheduler._marked_timespans_ids[b];if(a)for(var c=0;c"+e.text+"

"+(e.event_location||"")+"

"+scheduler.templates.marker_date(f)+" - "+scheduler.templates.marker_date(g)+""}; -scheduler.dblclick_dhx_map_area=function(){!this.config.readonly&&this.config.dblclick_create&&this.addEventNow({start_date:scheduler._date,end_date:scheduler.date.add(scheduler._date,scheduler.config.time_step,"minute")})};scheduler.templates.map_time=function(f,g,e){return e._timed?this.day_date(e.start_date,e.end_date,e)+" "+this.event_date(f):scheduler.templates.day_date(f)+" – "+scheduler.templates.day_date(g)};scheduler.templates.map_text=function(f,g,e){return e.text}; -scheduler.date.map_start=function(f){return f};scheduler.date.add_map=function(f){return new Date(f.valueOf())};scheduler.templates.map_date=function(){return""};scheduler._latLngUpdate=!1; -scheduler.attachEvent("onSchedulerReady",function(){function f(a){if(a){var c=scheduler.locale.labels;scheduler._els.dhx_cal_header[0].innerHTML="
"+c.date+"
"+c.description+"
";scheduler._table_view=!0; -scheduler.set_sizes()}}function g(){scheduler._selected_event_id=null;scheduler.map._infowindow.close();var a=scheduler.map._markers,c;for(c in a)a.hasOwnProperty(c)&&(a[c].setMap(null),delete scheduler.map._markers[c],scheduler.map._infowindows_content[c]&&delete scheduler.map._infowindows_content[c])}function e(){var a=scheduler.get_visible_events();a.sort(function(a,b){return a.start_date.valueOf()==b.start_date.valueOf()?a.id>b.id?1:-1:a.start_date>b.start_date?1:-1});for(var c="
", -d=0;d
"+scheduler.templates.map_time(b.start_date,b.end_date,b)+"
";c+="
 
"; -c+="
"+scheduler.templates.map_text(b.start_date,b.end_date,b)+"
"}c+="
";scheduler._els.dhx_cal_data[0].scrollTop=0;scheduler._els.dhx_cal_data[0].innerHTML=c;scheduler._els.dhx_cal_data[0].style.width=scheduler.xy.map_date_width+scheduler.xy.map_description_width+ -1+"px";var g=scheduler._els.dhx_cal_data[0].firstChild.childNodes;scheduler._els.dhx_cal_date[0].innerHTML=scheduler.templates[scheduler._mode+"_date"](scheduler._min_date,scheduler._max_date,scheduler._mode);scheduler._rendered=[];for(d=0;dscheduler._min_date||c.start_datescheduler._max_date||c.start_date.valueOf()>=scheduler._min_date&&c.end_date.valueOf()<=scheduler._max_date? -(scheduler.map._markers[a]&&scheduler.map._markers[a].setMap(null),j(c)):(scheduler._selected_event_id=null,scheduler.map._infowindow.close(),scheduler.map._markers[a]&&scheduler.map._markers[a].setMap(null))}return!0});scheduler.attachEvent("onEventIdChange",function(a,c){var d=scheduler.getEvent(c);if(d.start_datescheduler._min_date||d.start_datescheduler._max_date||d.start_date.valueOf()>=scheduler._min_date&&d.end_date.valueOf()<= -scheduler._max_date)scheduler.map._markers[a]&&(scheduler.map._markers[a].setMap(null),delete scheduler.map._markers[a]),scheduler.map._infowindows_content[a]&&delete scheduler.map._infowindows_content[a],j(d);return!0});scheduler.attachEvent("onEventAdded",function(a,c){if(!scheduler._dataprocessor&&(c.start_datescheduler._min_date||c.start_datescheduler._max_date||c.start_date.valueOf()>=scheduler._min_date&&c.end_date.valueOf()<= -scheduler._max_date))scheduler.map._markers[a]&&scheduler.map._markers[a].setMap(null),j(c);return!0});scheduler.attachEvent("onBeforeEventDelete",function(a){scheduler.map._markers[a]&&scheduler.map._markers[a].setMap(null);scheduler._selected_event_id=null;scheduler.map._infowindow.close();return!0});scheduler._event_resolve_delay=1500;scheduler.attachEvent("onEventLoading",function(a){scheduler.config.map_resolve_event_location&&a.event_location&&!a.lat&&!a.lng&&(scheduler._event_resolve_delay+= -1500,o(n,this,[a],scheduler._event_resolve_delay));return!0});scheduler.attachEvent("onEventCancel",function(a,c){c&&(scheduler.map._markers[a]&&scheduler.map._markers[a].setMap(null),scheduler.map._infowindow.close());return!0})}); diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_minical.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_minical.js deleted file mode 100644 index 7dcf3b45bd7..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_minical.js +++ /dev/null @@ -1,26 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.templates.calendar_month=scheduler.date.date_to_str("%F %Y");scheduler.templates.calendar_scale_date=scheduler.date.date_to_str("%D");scheduler.templates.calendar_date=scheduler.date.date_to_str("%d");scheduler.config.minicalendar={mark_events:!0};scheduler._synced_minicalendars=[]; -scheduler.renderCalendar=function(a,b,c){var d=null,f=a.date||new Date;typeof f=="string"&&(f=this.templates.api_date(f));if(b)d=this._render_calendar(b.parentNode,f,a,b),scheduler.unmarkCalendar(d);else{var e=a.container,h=a.position;typeof e=="string"&&(e=document.getElementById(e));typeof h=="string"&&(h=document.getElementById(h));if(h&&typeof h.left=="undefined")var k=getOffset(h),h={top:k.top+h.offsetHeight,left:k.left};e||(e=scheduler._get_def_cont(h));d=this._render_calendar(e,f,a);d.onclick= -function(a){var a=a||event,b=a.target||a.srcElement;if(b.className.indexOf("dhx_month_head")!=-1){var c=b.parentNode.className;if(c.indexOf("dhx_after")==-1&&c.indexOf("dhx_before")==-1){var d=scheduler.templates.xml_date(this.getAttribute("date"));d.setDate(parseInt(b.innerHTML,10));scheduler.unmarkCalendar(this);scheduler.markCalendar(this,d,"dhx_calendar_click");this._last_date=d;this.conf.handler&&this.conf.handler.call(scheduler,d,this)}}}}if(scheduler.config.minicalendar.mark_events)for(var j= -scheduler.date.month_start(f),n=scheduler.date.add(j,1,"month"),l=this.getEvents(j,n),s=this["filter_"+this._mode],p=0;p=n.valueOf())break}}this._markCalendarCurrentDate(d);d.conf=a;a.sync&&!c&&this._synced_minicalendars.push(d);return d}; -scheduler._get_def_cont=function(a){if(!this._def_count)this._def_count=document.createElement("DIV"),this._def_count.className="dhx_minical_popup",this._def_count.onclick=function(a){(a||event).cancelBubble=!0},document.body.appendChild(this._def_count);this._def_count.style.left=a.left+"px";this._def_count.style.top=a.top+"px";this._def_count._created=new Date;return this._def_count}; -scheduler._locateCalendar=function(a,b){var c=a.childNodes[2].childNodes[0];typeof b=="string"&&(b=scheduler.templates.api_date(b));var d=a.week_start+b.getDate()-1;return c.rows[Math.floor(d/7)].cells[d%7].firstChild};scheduler.markCalendar=function(a,b,c){this._locateCalendar(a,b).className+=" "+c};scheduler.unmarkCalendar=function(a,b,c){b=b||a._last_date;c=c||"dhx_calendar_click";if(b){var d=this._locateCalendar(a,b);d.className=(d.className||"").replace(RegExp(c,"g"))}}; -scheduler._week_template=function(a){for(var b=a||250,c=0,d=document.createElement("div"),f=this.date.week_start(new Date),e=0;e<7;e++)this._cols[e]=Math.floor(b/(7-e)),this._render_x_header(e,c,f,d),f=this.date.add(f,1,"day"),b-=this._cols[e],c+=this._cols[e];d.lastChild.className+=" dhx_scale_bar_last";return d};scheduler.updateCalendar=function(a,b){a.conf.date=b;this.renderCalendar(a.conf,a,!0)};scheduler._mini_cal_arrows=[" "," "]; -scheduler._render_calendar=function(a,b,c,d){var f=scheduler.templates,e=this._cols;this._cols=[];var h=this._mode;this._mode="calendar";var k=this._colsS;this._colsS={height:0};var j=new Date(this._min_date),n=new Date(this._max_date),l=new Date(scheduler._date),s=f.month_day;f.month_day=f.calendar_date;var b=this.date.month_start(b),p=this._week_template(a.offsetWidth-1),g;d?g=d:(g=document.createElement("DIV"),g.className="dhx_cal_container dhx_mini_calendar");g.setAttribute("date",this.templates.xml_format(b)); -g.innerHTML="
"+p.innerHTML+"
";g.childNodes[0].innerHTML=this.templates.calendar_month(b);if(c.navigation)for(var i=function(a,b){var c=scheduler.date.add(a._date,b,"month");scheduler.updateCalendar(a,c);scheduler._date.getMonth()==a._date.getMonth()&&scheduler._date.getFullYear()==a._date.getFullYear()&&scheduler._markCalendarCurrentDate(a)},w=["dhx_cal_prev_button","dhx_cal_next_button"],x=["left:1px;top:2px;position:absolute;", -"left:auto; right:1px;top:2px;position:absolute;"],y=[-1,1],z=function(a){return function(){if(c.sync)for(var b=scheduler._synced_minicalendars,d=0;d500))a=this._def_count.firstChild;if(a&&(a.onclick=null,a.innerHTML="",a.parentNode&&a.parentNode.removeChild(a),this._def_count))this._def_count.style.top="-1000px"}; -scheduler.isCalendarVisible=function(){return this._def_count&&parseInt(this._def_count.style.top,10)>0?this._def_count:!1};scheduler.attachEvent("onTemplatesReady",function(){dhtmlxEvent(document.body,"click",function(){scheduler.destroyCalendar()})});scheduler.templates.calendar_time=scheduler.date.date_to_str("%d-%m-%Y"); -scheduler.form_blocks.calendar_time={render:function(){var a="",b=scheduler.config,c=this.date.date_part(new Date),d=1440,f=0;b.limit_time_select&&(f=60*b.first_hour,d=60*b.last_hour+1);c.setHours(f/60);a+=" ";var k=scheduler.config.full_day;return"
"+ -a+"  –  "+a+"
"},set_value:function(a,b,c){function d(a,b,c){h(a,b,c);a.value=scheduler.templates.calendar_time(b);a._date=scheduler.date.date_part(new Date(b))}var f=a.getElementsByTagName("input"),e=a.getElementsByTagName("select"),h=function(a,b,c){a.onclick=function(){scheduler.destroyCalendar(null,!0);scheduler.renderCalendar({position:a,date:new Date(this._date),navigation:!0,handler:function(b){a.value=scheduler.templates.calendar_time(b); -a._date=new Date(b);scheduler.destroyCalendar();scheduler.config.event_duration&&scheduler.config.auto_end_date&&c==0&&l()}})}};if(scheduler.config.full_day){if(!a._full_day){var k="";scheduler.config.wide_form||(k=a.previousSibling.innerHTML+k);a.previousSibling.innerHTML=k;a._full_day=!0}var j=a.previousSibling.getElementsByTagName("input")[0],n=scheduler.date.time_part(c.start_date)== -0&&scheduler.date.time_part(c.end_date)==0;j.checked=n;e[0].disabled=j.checked;e[1].disabled=j.checked;j.onclick=function(){if(j.checked==!0){var b={};scheduler.form_blocks.calendar_time.get_value(a,b);var h=scheduler.date.date_part(b.start_date),g=scheduler.date.date_part(b.end_date);if(+g==+h||+g>=+h&&(c.end_date.getHours()!=0||c.end_date.getMinutes()!=0))g=scheduler.date.add(g,1,"day")}var i=h||c.start_date,k=g||c.end_date;d(f[0],i);d(f[1],k);e[0].value=i.getHours()*60+i.getMinutes();e[1].value= -k.getHours()*60+k.getMinutes();e[0].disabled=j.checked;e[1].disabled=j.checked}}if(scheduler.config.event_duration&&scheduler.config.auto_end_date){var l=function(){start_date=scheduler.date.add(f[0]._date,e[0].value,"minute");end_date=new Date(start_date.getTime()+scheduler.config.event_duration*6E4);f[1].value=scheduler.templates.calendar_time(end_date);f[1]._date=scheduler.date.date_part(new Date(end_date));e[1].value=end_date.getHours()*60+end_date.getMinutes()};e[0].onchange=l}d(f[0],c.start_date, -0);d(f[1],c.end_date,1);h=function(){};e[0].value=c.start_date.getHours()*60+c.start_date.getMinutes();e[1].value=c.end_date.getHours()*60+c.end_date.getMinutes()},get_value:function(a,b){var c=a.getElementsByTagName("input"),d=a.getElementsByTagName("select");b.start_date=scheduler.date.add(c[0]._date,d[0].value,"minute");b.end_date=scheduler.date.add(c[1]._date,d[1].value,"minute");if(b.end_date<=b.start_date)b.end_date=scheduler.date.add(b.start_date,scheduler.config.time_step,"minute")},focus:function(){}}; -scheduler.linkCalendar=function(a,b){var c=function(){var c=scheduler._date,f=new Date(c.valueOf());b&&(f=b(f));f.setDate(1);scheduler.updateCalendar(a,f);return!0};scheduler.attachEvent("onViewChange",c);scheduler.attachEvent("onXLE",c);scheduler.attachEvent("onEventAdded",c);scheduler.attachEvent("onEventChanged",c);scheduler.attachEvent("onAfterEventDelete",c);c()}; -scheduler._markCalendarCurrentDate=function(a){var b=scheduler._date,c=scheduler._mode,d=scheduler.date.month_start(new Date(a._date)),f=scheduler.date.add(d,1,"month");if(c=="day"||this._props&&this._props[c])d.valueOf()<=b.valueOf()&&f>b&&scheduler.markCalendar(a,b,"dhx_calendar_click");else if(c=="week")for(var e=scheduler.date.week_start(new Date(b.valueOf())),h=0;h<7;h++)d.valueOf()<=e.valueOf()&&f>e&&scheduler.markCalendar(a,e,"dhx_calendar_click"),e=scheduler.date.add(e,1,"day")}; -scheduler.attachEvent("onEventCancel",function(){scheduler.destroyCalendar(null,!0)}); diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_multiselect.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_multiselect.js deleted file mode 100644 index fd8fa20b857..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_multiselect.js +++ /dev/null @@ -1,7 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.form_blocks.multiselect={render:function(d){for(var a="
",b=0;b"+d.options[b].label+"",convertStringToBoolean(d.vertical)&&(a+="
");a+="
";return a},set_value:function(d,a,b,c){function h(b){for(var c=d.getElementsByTagName("input"),a=0;a";q=d[0].offsetWidth; -if(b)for(var f=0,e=d[0].offsetWidth,h=1,c=0;c",f+=b[c].offsetWidth,f>=e&&(e+=d[h]?d[h].offsetWidth:0,h++),q=b[0].offsetWidth;return a}function B(d,a){for(var b=parseInt(d.style.left,10),c=0;cb)return c;return a} -function z(d){for(var a="",b=d.firstChild.rows,c=0;c";n=d.firstChild.rows[0].cells[0].offsetHeight}return a}function D(d){var a="";if(scheduler._mode=="week_agenda")for(var c=scheduler._els.dhx_cal_data[0].getElementsByTagName("DIV"),f=0;f"+g(c[f].innerHTML)+"");else if(scheduler._mode=="agenda"||scheduler._mode=="map")c=scheduler._els.dhx_cal_header[0].childNodes[0].childNodes,a+=""+g(c[0].innerHTML)+""+g(c[1].innerHTML)+""; -else if(scheduler._mode=="year"){c=scheduler._els.dhx_cal_data[0].childNodes;for(f=0;f",a+=v(c[f].childNodes[1].childNodes),a+=z(c[f].childNodes[2]),a+=""}else{a+="";c=scheduler._els.dhx_cal_header[0].childNodes;a+=v(c);a+="";var e=scheduler._els.dhx_cal_data[0];if(scheduler.matrix&&scheduler.matrix[scheduler._mode]){a+="";for(f=0;f"}a+="";n=e.firstChild.rows[0].cells[0].offsetHeight}else if(e.firstChild.tagName=="TABLE")a+=z(e);else{for(e=e.childNodes[e.childNodes.length-1];e.className.indexOf("dhx_scale_holder")==-1;)e=e.previousSibling;e=e.childNodes;a+="";for(f=0;f";a+="";n=e[0].offsetHeight}}a+="";return a}function l(d,a){return(window.getComputedStyle?window.getComputedStyle(d,null)[a]:d.currentStyle?d.currentStyle[a]:null)|| -""}function E(){var d="",a=scheduler._rendered;if(scheduler._mode=="agenda"||scheduler._mode=="map")for(var b=0;b"+g(a[b].childNodes[0].innerHTML)+""+g(a[b].childNodes[2].innerHTML)+"";else if(scheduler._mode=="week_agenda")for(b=0;b"+g(a[b].innerHTML)+"";else if(scheduler._mode=="year"){a=scheduler.get_visible_events();for(b=0;b";c=scheduler.date.add(c,1,"day");if(c.valueOf()>= -scheduler._max_date.valueOf())break}}}else{var k=scheduler.matrix&&scheduler.matrix[scheduler._mode];if(k&&k.render=="cell"){a=scheduler._els.dhx_cal_data[0].getElementsByTagName("TD");for(b=0;b"}else for(b=0;b";p=="event"?(d+="
",h=j?l(a[b].childNodes[2],"color"):"",o=j?l(a[b].childNodes[2],"backgroundColor"):"",d+=""):(h=j?l(a[b],"color"):"",o=j?l(a[b],"backgroundColor"):"",d+="");d+=""}}}}return d}function F(){var d="
";return d}var q=0,n=0,j=!1;k=="fullcolor"&&(j=!0,k="color");k=k||"color";html_regexp=RegExp("<[^>]*>","g");newline_regexp=RegExp("]*>","g");var p=(new Date).valueOf(),i=document.createElement("div");i.style.display= -"none";document.body.appendChild(i);i.innerHTML='
';document.getElementById(p).firstChild.value=encodeURIComponent(D(k).replace("\u2013","-")+E()+F());document.getElementById(p).submit();i.parentNode.removeChild(i);grid=null}; diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_readonly.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_readonly.js deleted file mode 100644 index 0cb1e926595..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_readonly.js +++ /dev/null @@ -1,9 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.attachEvent("onTemplatesReady",function(){function c(e,b,a,h){for(var i=b.getElementsByTagName(e),g=a.getElementsByTagName(e),f=g.length-1;f>=0;f--)if(a=g[f],h){var d=document.createElement("SPAN");d.className="dhx_text_disabled";d.innerHTML=h(i[f]);a.parentNode.insertBefore(d,a);a.parentNode.removeChild(a)}else a.disabled=!0}var r=scheduler.config.lightbox.sections,k=null,n=scheduler.config.buttons_left.slice(),o=scheduler.config.buttons_right.slice();scheduler.attachEvent("onBeforeLightbox", -function(e){if(this.config.readonly_form||this.getEvent(e).readonly){this.config.readonly_active=!0;for(var b=0;be)return a.setDate(a.getDate()+b[h]*1-e-(d?c:f));this.transpose_day_week(a,b,c+d,null,c)}; -scheduler.transpose_type=function(a){var b="transpose_"+a;if(!this.date[b]){var c=a.split("_"),d=864E5,f="add_"+a,e=this.transponse_size[c[0]]*c[1];if(c[0]=="day"||c[0]=="week"){var h=null;if(c[4]&&(h=c[4].split(","),scheduler.config.start_on_monday)){for(var i=0;i0&&a.setDate(a.getDate()+c*e);h&&scheduler.transpose_day_week(a,h,1,e)};this.date[f]=function(a,b){var c=new Date(a.valueOf()); -if(h)for(var d=0;d=0&&a.setMonth(a.getMonth()+d*e);c[3]&&scheduler.date.day_week(a,c[2],c[3])},this.date[f]=function(a,b){var d=new Date(a.valueOf());d.setMonth(d.getMonth()+b*e);c[3]&&scheduler.date.day_week(d,c[2],c[3]);return d}}}; -scheduler.repeat_date=function(a,b,c,d,f){var d=d||this._min_date,f=f||this._max_date,e=new Date(a.start_date.valueOf());if(!a.rec_pattern&&a.rec_type)a.rec_pattern=a.rec_type.split("#")[0];this.transpose_type(a.rec_pattern);for(scheduler.date["transpose_"+a.rec_pattern](e,d);e0?new Date(d.valueOf()+c.event_length*1E3-e*6E4):new Date(b.valueOf()-e*6E4):new Date(f.valueOf())}; -scheduler.getRecDates=function(a,b){var c=typeof a=="object"?a:scheduler.getEvent(a),d=0,f=[],b=b||100,e=new Date(c.start_date.valueOf()),h=new Date(e.valueOf());if(!c.rec_type)return[{start_date:c.start_date,end_date:c.end_date}];if(c.rec_type=="none")return[];this.transpose_type(c.rec_pattern);for(scheduler.date["transpose_"+c.rec_pattern](e,h);ea)if(f.rec_pattern){if(f.rec_pattern!="none"){var e=[];this.repeat_date(f,e,!0,a,b);for(var h=0;ha&&!this._rec_markers[e[h].id]&&c.push(e[h])}}else f.id.toString().indexOf("#")==-1&&c.push(f)}return c};scheduler.config.repeat_date="%m.%d.%Y"; -scheduler.config.lightbox.sections=[{name:"description",height:130,map_to:"text",type:"textarea",focus:!0},{name:"recurring",type:"recurring",map_to:"rec_type",button:"recurring"},{name:"time",height:72,type:"time",map_to:"auto"}];scheduler._copy_dummy=function(){var a=new Date(this.start_date),b=new Date(this.end_date);this.start_date=a;this.end_date=b;this.event_length=this.event_pid=this.rec_pattern=this.rec_type=null};scheduler.config.include_end_by=!1;scheduler.config.lightbox_recurring="ask"; -scheduler.__recurring_template='








day everymonth
everymonth

occurrences

'; diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_serialize.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_serialize.js deleted file mode 100644 index dafc552292a..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_serialize.js +++ /dev/null @@ -1,9 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.data_attributes=function(){var g=[],c=scheduler.templates.xml_format,b;for(b in this._events){var e=this._events[b],d;for(d in e)d.substr(0,1)!="_"&&g.push([d,d=="start_date"||d=="end_date"?c:null]);break}return g}; -scheduler.toXML=function(g){var c=[],b=this.data_attributes(),e;for(e in this._events){var d=this._events[e];if(d.id.toString().indexOf("#")==-1){c.push("");for(var a=0;a");c.push("")}}return(g||"")+""+c.join("\n")+""}; -scheduler.toJSON=function(){var g=[],c=this.data_attributes(),b;for(b in this._events){var e=this._events[b];if(e.id.toString().indexOf("#")==-1){for(var e=this._events[b],d=[],a=0;a=this._trace_x[f+1];)f++;for(;this._trace_x[f]&&a[b].end_date>this._trace_x[f];)c[e][f]||(c[e][f]=[]),c[e][f].push(a[b]),f++}return c}function t(a,c,b){var e=0,f=c?a.end_date:a.start_date;if(f.valueOf()>scheduler._max_date.valueOf())f=scheduler._max_date;var g=f-scheduler._min_date_timeline; -if(g<0)k=0;else{var i=Math.round(g/(b*scheduler._cols[0]));if(i>scheduler._cols.length)i=scheduler._cols.length;for(var d=0;db.id?1:-1:a.start_date>b.start_date? -1:-1});for(var b=[],e=a.length,f=0;fh)h=b[m]._sorder;g._sorder=h+1;g._inner=!1}else g._sorder=0;b.push(g);b.length>(b.max_count||0)?(b.max_count=b.length,g._count=b.length):g._count=g._count?g._count:1}for(var n=0;nh.height?m:h.height;h.style_height="height:"+h.height+"px;";this._section_height[this.y_unit[d].key]=h.height}c+= -""+h.td_content+"";if(this.render=="cell")for(f=0;f
"+scheduler.templates[this.name+"_cell_value"](b[d][f])+"
"; -else{c+="
";c+=l;c+="";for(f=0;f
";c+="
"; -c+="
"}c+=""}c+="";this._matrix=b;a.innerHTML=c;scheduler._rendered=[];for(var n=scheduler._obj.getElementsByTagName("DIV"),d=0;d";if(this.second_scale){for(var j=this.second_scale.x_unit,k=[this._trace_x[0]],h=[],l=[this.dx,this.dx],m=0,n=0;n
";var u=a.firstChild;u.style.height=b+"px";var s=a.lastChild;s.style.position="relative";for(var v=0;vb.start_date?1:-1});if(scheduler._tooltip){if(scheduler._tooltip.date==e)return;scheduler._tooltip.innerHTML=""}else{var g=scheduler._tooltip=document.createElement("DIV");g.className="dhx_tooltip";document.body.appendChild(g);g.onclick=scheduler._click.dhx_cal_data}for(var i="",d=0;d";i+="
"+(f[d]._timed?scheduler.templates.event_date(f[d].start_date):"")+"
";i+="
 
";i+=scheduler.templates[a.name+"_tooltip"](f[d].start_date,f[d].end_date,f[d])+""}scheduler._tooltip.style.display="";scheduler._tooltip.style.top="0px";scheduler._tooltip.style.left= -document.body.offsetWidth-b.left-scheduler._tooltip.offsetWidth<0?b.left-scheduler._tooltip.offsetWidth+"px":b.left+c.src.offsetWidth+"px";scheduler._tooltip.date=e;scheduler._tooltip.innerHTML=i;scheduler._tooltip.style.top=document.body.offsetHeight-b.top-scheduler._tooltip.offsetHeight<0?b.top-scheduler._tooltip.offsetHeight+c.src.offsetHeight+"px":b.top+"px"}}function C(){dhtmlxEvent(scheduler._els.dhx_cal_data[0],"mouseover",function(a){var c=scheduler.matrix[scheduler._mode];if(c&&c.render== -"cell"){if(c){var b=scheduler._locate_cell_timeline(a),a=a||event,e=a.target||a.srcElement;if(b)return J(c,b,getOffset(b.src))}D()}});C=function(){}}function K(a){for(var c=a.parentNode.childNodes,b=0;bb.x){var h=(b.x-(e-k))/k,h=h<0?0:h;break}}for(e=0;j< -this._colsS.heights.length;j++)if(e+=this._colsS.heights[j],e>b.y)break;b.fields={};a.y_unit[j]||(j=a.y_unit.length-1);if(j>=0&&a.y_unit[j]&&(b.section=b.fields[a.y_property]=a.y_unit[j].key,c))c[a.y_property]=b.section;b.x=0;var l;if(d>=a._trace_x.length)l=scheduler.date.add(a._trace_x[a._trace_x.length-1],a.x_step,a.x_unit);else{var m=a._trace_x[d+1]?a._trace_x[d+1]:scheduler.date.add(a._trace_x[a._trace_x.length-1],a.x_step,a.x_unit),n=Math.ceil(h*(m-a._trace_x[d]));l=new Date(+a._trace_x[d]+n)}if(this._drag_mode== -"move"&&this._drag_id&&this._drag_event){var c=this.getEvent(this._drag_id),o=this._drag_event;if(!o._move_delta)o._move_delta=(c.start_date-l)/6E4;l=scheduler.date.add(l,o._move_delta,"minute")}if(this._drag_mode=="resize"&&c)b.resize_from_start=!!(Math.abs(c.start_date-l)';if(scheduler.config.drag_resize){var p="dhx_event_resize";o+="
"}o+=n+"";if(c){var r=document.createElement("DIV");r.innerHTML=o;var u=this.order[b],s=scheduler._els.dhx_cal_data[0].firstChild.rows[u].cells[1].firstChild;scheduler._rendered.push(r.firstChild);s.appendChild(r.firstChild)}else return o};scheduler.renderMatrix=function(a,c){if(!c)scheduler._els.dhx_cal_data[0].scrollTop=0;scheduler._min_date=scheduler.date[this.name+"_start"](scheduler._date);scheduler._max_date=scheduler.date.add(scheduler._min_date, -this.x_size*this.x_step,this.x_unit);scheduler._table_view=!0;if(this.second_scale){if(a&&!this._header_resized)this._header_resized=scheduler.xy.scale_height,scheduler.xy.scale_height*=2,scheduler._els.dhx_cal_header[0].className+=" dhx_second_cal_header";if(!a&&this._header_resized){scheduler.xy.scale_height/=2;this._header_resized=!1;var b=scheduler._els.dhx_cal_header[0];b.className=b.className.replace(/ dhx_second_cal_header/gi,"")}}I.call(this,a)};scheduler._locate_cell_timeline=function(a){for(var a= -a||event,c=a.target?a.target:a.srcElement,b={},e=scheduler.matrix[scheduler._mode],f=scheduler.getActionData(a),g=0;g6){var m=new Date(a.days);scheduler.date.date_part(new Date(k))<=+m&&+h>=+m&&l.push(m)}else l.push.apply(l,scheduler._get_dates_by_index(a.days));for(var n=a.zones,o=scheduler._get_css_classes_by_config(a), -p=0;px){var q=scheduler._get_block_by_config(a);q.className=o;var y=t({start_date:x},!1,e._step)-1,A=t({start_date:w},!1,e._step)-1,B=A-y-1,C=e._section_height[b]-1;q.style.cssText="height: "+C+"px; left: "+y+"px; width: "+B+"px; top: 0;";c.insertBefore(q,c.firstChild);f.push(q)}}return f}}else return M.apply(scheduler, -[a,c,b])};var N=scheduler._append_mark_now;scheduler._append_mark_now=function(a){if(scheduler.matrix&&scheduler.matrix[scheduler._mode]){var c=new Date,b=scheduler._get_zone_minutes(c),e={days:+scheduler.date.date_part(c),zones:[b,b+1],css:"dhx_matrix_now_time",type:"dhx_now_time"};return scheduler._render_marked_timespan(e)}else return N.apply(scheduler,[a])};scheduler.attachEvent("onViewChange",function(a,c){scheduler.matrix&&scheduler.matrix[c]&&scheduler.markNow&&scheduler.markNow()});scheduler.attachEvent("onScaleAdd", -function(a,c){var b=scheduler._marked_timespans;if(b&&scheduler.matrix&&scheduler.matrix[scheduler._mode])for(var e=scheduler._mode,f=scheduler._min_date,g=scheduler._max_date,i=b.global,d=scheduler.date.date_part(new Date(f));dEvent: "+c.text+"
Start date: "+scheduler.templates.tooltip_date_format(b)+"
End date: "+scheduler.templates.tooltip_date_format(d)}; diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_treetimeline.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_treetimeline.js deleted file mode 100644 index 986ce0fa3e3..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_treetimeline.js +++ /dev/null @@ -1,19 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.attachEvent("onTimelineCreated",function(a){if(a.render=="tree")a.y_unit_original=a.y_unit,a.y_unit=scheduler._getArrayToDisplay(a.y_unit_original),scheduler.attachEvent("onOptionsLoadStart",function(){a.y_unit=scheduler._getArrayToDisplay(a.y_unit_original)}),scheduler.form_blocks[a.name]={render:function(b){var c="
";return c},set_value:function(b,c,e,f){var d=scheduler._getArrayForSelect(scheduler.matrix[f.type].y_unit_original, -f.type);b.innerHTML="";var a=document.createElement("select");b.appendChild(a);for(var h=b.getElementsByTagName("select")[0],i=0;i",g=c.folder_events_available?"dhx_data_table folder_events":"dhx_data_table folder"):(f=c.dy,d="dhx_row_item",h="dhx_matrix_scell item",i="",g="dhx_data_table");td_content="
"+i+"
"+(scheduler.templates[c.name+"_scale_label"](b.key,b.label,b)||b.label)+"
";e={height:f,style_height:j,tr_className:d,td_className:h,td_content:td_content,table_className:g}}return e});var section_id_before; -scheduler.attachEvent("onBeforeEventChanged",function(a,b,c){if(scheduler._isRender("tree")){var e=scheduler.getSection(a[scheduler.matrix[scheduler._mode].y_property]);if(e&&typeof e.children!="undefined"&&!scheduler.matrix[scheduler._mode].folder_events_available)return c||(a[scheduler.matrix[scheduler._mode].y_property]=section_id_before),!1}return!0}); -scheduler.attachEvent("onBeforeDrag",function(a,b,c){if(scheduler._isRender("tree")){var e=scheduler._locate_cell_timeline(c);if(e){var f=scheduler.matrix[scheduler._mode].y_unit[e.y].key;if(typeof scheduler.matrix[scheduler._mode].y_unit[e.y].children!="undefined"&&!scheduler.matrix[scheduler._mode].folder_events_available)return!1}var d=scheduler.getEvent(a);section_id_before=f||d[scheduler.matrix[scheduler._mode].y_property]}return!0}); -scheduler._getArrayToDisplay=function(a){var b=[],c=function(e,f){for(var d=f||0,a=0;ascheduler._props[a].options.length)scheduler._props[a]._original_size=f,f=0;scheduler._props[a].size=f;scheduler._props[a].skip_incorrect=l||!1;scheduler.date[a+"_start"]=scheduler.date.day_start;scheduler.templates[a+"_date"]=function(a){return scheduler.templates.day_date(a)};scheduler.templates[a+ -"_scale_date"]=function(c){var h=scheduler._props[a].options;if(!h.length)return"";var g=(scheduler._props[a].position||0)+Math.floor((scheduler._correct_shift(c.valueOf(),1)-scheduler._min_date.valueOf())/864E5);return h[g].css?""+h[g].label+"":h[g].label};scheduler.date["add_"+a]=function(a,g){return scheduler.date.add(a,g,"day")};scheduler.date["get_"+a+"_end"]=function(c){return scheduler.date.add(c,scheduler._props[a].size||scheduler._props[a].options.length, -"day")};scheduler.attachEvent("onOptionsLoad",function(){for(var c=scheduler._props[a],g=c.order={},f=c.options,i=0;if.length?(c._original_size=c.size,c.size=0):c.size=c._original_size||c.size;scheduler._date&&scheduler._mode==a&&scheduler.setCurrentView(scheduler._date,scheduler._mode)});scheduler.callEvent("onOptionsLoad",[])}; -scheduler.scrollUnit=function(a){var g=scheduler._props[this._mode];if(g)g.position=Math.min(Math.max(0,g.position+a),g.options.length-g.size),this.update_view()}; -(function(){var a=function(b){var d=scheduler._props[scheduler._mode];if(d&&d.order&&d.skip_incorrect){for(var a=[],e=0;e=a.size+a.position)return!1}}return d};scheduler._reset_scale=function(){var b= -scheduler._props[this._mode],a=k.apply(this,arguments);if(b){this._max_date=this.date.add(this._min_date,1,"day");for(var c=this._els.dhx_cal_data[0].childNodes,e=0;ed.order[b[d.map_to]]?1:-1}):i.apply(this,arguments)};scheduler.attachEvent("onEventAdded",function(a,d){if(this._loading)return!0;for(var c in scheduler._props){var e=scheduler._props[c];if(typeof d[e.map_to]=="undefined")d[e.map_to]=e.options[0].key}return!0});scheduler.attachEvent("onEventCreated",function(a,c){var g= -scheduler._props[this._mode];if(g&&c){var e=this.getEvent(a);this._mouse_coords(c);f(g,e);this.event_updated(e)}return!0})})(); diff --git a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_url.js b/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_url.js deleted file mode 100644 index d0241636ec9..00000000000 --- a/addons/web_calendar/static/lib/dhtmlxScheduler/codebase/ext/dhtmlxscheduler_url.js +++ /dev/null @@ -1,6 +0,0 @@ -/* -This software is allowed to use under GPL or you need to obtain Commercial or Enterise License -to use it in non-GPL project. Please contact sales@dhtmlx.com for details -*/ -scheduler.attachEvent("onTemplatesReady",function(){var d=!0,e=scheduler.date.str_to_date("%Y-%m-%d"),h=scheduler.date.date_to_str("%Y-%m-%d");scheduler.attachEvent("onBeforeViewChange",function(i,j,f,k){if(d){d=!1;for(var a={},g=(document.location.hash||"").replace("#","").split(","),b=0;b";for(var e=0;e
"}b+= -""}scheduler._els.dhx_cal_date[0].innerHTML=scheduler.templates[scheduler._mode+"_date"](scheduler._min_date,scheduler._max_date,scheduler._mode);scheduler._els.dhx_cal_data[0].innerHTML=b;for(var l=scheduler._els.dhx_cal_data[0].getElementsByTagName("div"),o=[],a=0;ai&&p.push(s)}p.sort(function(a,b){return a.start_date.valueOf()==b.start_date.valueOf()?a.id>b.id?1:-1:a.start_date>b.start_date?1:-1});for(e=0;e=i.valueOf()&&d.start_date.valueOf()<=n.valueOf()&&(q="start"),d.end_date.valueOf()>=i.valueOf()&& -d.end_date.valueOf()<=n.valueOf()&&(q="end"));f.innerHTML=scheduler.templates.week_agenda_event_text(d.start_date,d.end_date,d,i,q);f.setAttribute("event_id",d.id);w.appendChild(f)}i=scheduler.date.add(i,1,"day");n=scheduler.date.add(n,1,"day")}};scheduler.week_agenda_view=function(b){scheduler._min_date=scheduler.date.week_start(scheduler._date);scheduler._max_date=scheduler.date.add(scheduler._min_date,1,"week");scheduler.set_sizes();if(b)scheduler._table_view=scheduler._allow_dnd=!0,scheduler._wa._prev_data_border= -scheduler._els.dhx_cal_data[0].style.borderTop,scheduler._els.dhx_cal_data[0].style.borderTop=0,scheduler._els.dhx_cal_data[0].style.overflowY="hidden",scheduler._els.dhx_cal_date[0].innerHTML="",scheduler._els.dhx_cal_data[0].style.top=parseInt(scheduler._els.dhx_cal_data[0].style.top)-scheduler.xy.bar_height-1+"px",scheduler._els.dhx_cal_data[0].style.height=parseInt(scheduler._els.dhx_cal_data[0].style.height)+scheduler.xy.bar_height+1+"px",scheduler._els.dhx_cal_header[0].style.display="none", -h();else{scheduler._table_view=scheduler._allow_dnd=!1;if(scheduler._wa._prev_data_border)scheduler._els.dhx_cal_data[0].style.borderTop=scheduler._wa._prev_data_border;scheduler._els.dhx_cal_data[0].style.overflowY="auto";scheduler._els.dhx_cal_data[0].style.top=parseInt(scheduler._els.dhx_cal_data[0].style.top)+scheduler.xy.bar_height+"px";scheduler._els.dhx_cal_data[0].style.height=parseInt(scheduler._els.dhx_cal_data[0].style.height)-scheduler.xy.bar_height+"px";scheduler._els.dhx_cal_header[0].style.display= -"block"}};scheduler.mouse_week_agenda=function(b){for(var a=b.ev,c=a.srcElement||a.target;c.parentNode;){if(c._date)var g=c._date;c=c.parentNode}if(!g)return b;b.x=0;var e=g.valueOf()-scheduler._min_date.valueOf();b.y=Math.ceil(e/6E4/this.config.time_step);if(this._drag_mode=="move"){this._drag_event._dhx_changed=!0;this._select_id=this._drag_id;for(var j=0;j";c+="
"+(h[e]._timed?this.templates.event_date(h[e].start_date):"")+"
";c+="
 
";c+=this.templates.year_tooltip(h[e].start_date,h[e].end_date,h[e])+""}this._tooltip.style.display= -"";this._tooltip.style.top="0px";this._tooltip.style.left=document.body.offsetWidth-a.left-this._tooltip.offsetWidth<0?a.left-this._tooltip.offsetWidth+"px":a.left+k.offsetWidth+"px";this._tooltip.date=b;this._tooltip.innerHTML=c;this._tooltip.style.top=document.body.offsetHeight-a.top-this._tooltip.offsetHeight<0?a.top-this._tooltip.offsetHeight+k.offsetHeight+"px":a.top+"px"};scheduler._init_year_tooltip=function(){dhtmlxEvent(scheduler._els.dhx_cal_data[0],"mouseover",function(b){if(c()){var b= -b||event,a=b.target||b.srcElement;if(a.tagName.toLowerCase()=="a")a=a.parentNode;(a.className||"").indexOf("dhx_year_event")!=-1?scheduler.showToolTip(w(a.getAttribute("date")),getOffset(a),b,a):scheduler.hideToolTip()}});this._init_year_tooltip=function(){}};scheduler.attachEvent("onSchedulerResize",function(){return c()?(this.year_view(!0),!1):!0});scheduler._get_year_cell=function(b){var a=b.getMonth()+12*(b.getFullYear()-this._min_date.getFullYear())-this.week_starts._month,j=this._els.dhx_cal_data[0].childNodes[a], -b=this.week_starts[a]+b.getDate()-1;return j.childNodes[2].firstChild.rows[Math.floor(b/7)].cells[b%7].firstChild};var l={};scheduler._mark_year_date=function(b,a){var j=v(b),c=this._get_year_cell(b),g=this.templates.event_class(a.start_date,a.end_date,a);if(!l[j])c.className="dhx_month_head dhx_year_event",c.setAttribute("date",j),l[j]=c;c.className+=g?" "+g:""};scheduler._unmark_year_date=function(b){this._get_year_cell(b).className="dhx_month_head"};scheduler._year_render_event=function(b){for(var a= -b.start_date,a=a.valueOf()=this._max_date.valueOf())break};scheduler.year_view=function(b){if(b){var a=scheduler.xy.scale_height;scheduler.xy.scale_height=-1}scheduler._els.dhx_cal_header[0].style.display=b?"none":"";scheduler.set_sizes();if(b)scheduler.xy.scale_height=a;scheduler._table_view=b;if(!this._load_mode||!this._load())if(b){scheduler._init_year_tooltip(); -scheduler._reset_year_scale();if(scheduler._load_mode&&scheduler._load())return scheduler._render_wait=!0;scheduler.render_view_data()}else scheduler.hideToolTip()};scheduler._reset_year_scale=function(){this._cols=[];this._colsS={};var b=[],a=this._els.dhx_cal_data[0],c=this.config;a.scrollTop=0;a.innerHTML="";var k=Math.floor(parseInt(a.style.width)/c.year_x),g=Math.floor((parseInt(a.style.height)-scheduler.xy.year_top)/c.year_y);g<190&&(g=190,k=Math.floor((parseInt(a.style.width)-scheduler.xy.scroll_width)/ -c.year_x));for(var h=k-11,l=0,e=document.createElement("div"),m=this.date.week_start(new Date),d=0;d<7;d++)this._cols[d]=Math.floor(h/(7-d)),this._render_x_header(d,l,m,e),m=this.date.add(m,1,"day"),h-=this._cols[d],l+=this._cols[d];e.lastChild.className+=" dhx_scale_bar_last";for(var f=this.date[this._mode+"_start"](this.date.copy(this._date)),n=f,d=0;d
";i.childNodes[0].innerHTML=this.templates.year_month(f);for(var q=this.date.week_start(f),t=this._reset_month_scale(i.childNodes[2],f,q),o=i.childNodes[2].firstChild.rows,p=o.length;p<6;p++){o[0].parentNode.appendChild(o[0].cloneNode(!0));for(var s=0;s Date: Sat, 3 Nov 2012 16:25:04 +0100 Subject: [PATCH 637/703] [FIX] POS bzr revid: fp@openerp.com-20121103152504-f3o6ce0e833hdibj --- addons/point_of_sale/point_of_sale.py | 40 +++++++++++----------- addons/point_of_sale/wizard/pos_payment.py | 2 -- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index e4d0512540b..9a4711e5f6b 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -493,17 +493,26 @@ class pos_order(osv.osv): self.add_payment(cr, uid, order_id, { 'amount': payment['amount'] or 0.0, 'payment_date': payment['name'], + 'statement_id': payment['statement_id'], 'payment_name': payment.get('note', False), 'journal': payment['journal_id'] }, context=context) if order['amount_return']: session = self.pool.get('pos.session').browse(cr, uid, order['pos_session_id'], context=context) + cash_journal = session.cash_journal_id + cash_statement = False + if not cash_journal: + cash_journal_ids = filter(lambda st: st.journal_id.type=='cash', session.statement_ids) + if not len(cash_journal_ids): + raise osv.except_osv( _('error!'), + _("No cash statement found for this session. Unable to record returned cash.")) + cash_journal = cash_journal_ids[0].journal_id self.add_payment(cr, uid, order_id, { 'amount': -order['amount_return'], 'payment_date': time.strftime('%Y-%m-%d %H:%M:%S'), 'payment_name': _('return'), - 'journal': session.cash_journal_id.id + 'journal': cash_journal.id, }, context=context) order_ids.append(order_id) wf_service = netsvc.LocalService("workflow") @@ -703,21 +712,15 @@ class pos_order(osv.osv): """Create a new payment for the order""" if not context: context = {} - statement_obj = self.pool.get('account.bank.statement') statement_line_obj = self.pool.get('account.bank.statement.line') - prod_obj = self.pool.get('product.product') property_obj = self.pool.get('ir.property') - curr_c = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id - curr_company = curr_c.id order = self.browse(cr, uid, order_id, context=context) args = { 'amount': data['amount'], + 'date': data.get('payment_date', time.strftime('%Y-%m-%d')), + 'name': order.name + ': ' + (data.get('payment_name', '') or ''), } - if 'payment_date' in data: - args['date'] = data['payment_date'] - args['name'] = order.name - if data.get('payment_name', False): - args['name'] = args['name'] + ': ' + data['payment_name'] + account_def = property_obj.get(cr, uid, 'property_account_receivable', 'res.partner', context=context) args['account_id'] = (order.partner_id and order.partner_id.property_account_receivable \ and order.partner_id.property_account_receivable.id) or (account_def and account_def.id) or False @@ -732,14 +735,15 @@ class pos_order(osv.osv): context.pop('pos_session_id', False) - try: - journal_id = long(data['journal']) - except Exception: - journal_id = False + journal_id = data.get('journal', False) + statement_id = data.get('statement_id', False) + assert journal_id or statement_id, "No statement_id or journal_id passed to the method!" - statement_id = False for statement in order.session_id.statement_ids: - if statement.journal_id.id == journal_id: + if statement.id == statement_id: + journal_id = statement.journal_id.id + break + elif statement.journal_id.id == journal_id: statement_id = statement.id break @@ -756,10 +760,6 @@ class pos_order(osv.osv): statement_line_obj.create(cr, uid, args, context=context) - wf_service = netsvc.LocalService("workflow") - wf_service.trg_validate(uid, 'pos.order', order_id, 'paid', cr) - wf_service.trg_write(uid, 'pos.order', order_id, cr) - return statement_id def refund(self, cr, uid, ids, context=None): diff --git a/addons/point_of_sale/wizard/pos_payment.py b/addons/point_of_sale/wizard/pos_payment.py index ca9331012b7..9511aed6331 100644 --- a/addons/point_of_sale/wizard/pos_payment.py +++ b/addons/point_of_sale/wizard/pos_payment.py @@ -43,8 +43,6 @@ class account_journal(osv.osv): return super(account_journal, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count) -account_journal() - class pos_make_payment(osv.osv_memory): _name = 'pos.make.payment' _description = 'Point of Sale Payment' From 74476c8e22be456bd404eff611e63fa4c2d35438 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sat, 3 Nov 2012 18:12:25 +0100 Subject: [PATCH 638/703] [FIX] POS close session without cash register bzr revid: fp@openerp.com-20121103171225-nlp53s0aenamdhcg --- addons/account/account_cash_statement.py | 2 +- addons/point_of_sale/point_of_sale.py | 80 ++++++++++--------- .../point_of_sale/point_of_sale_workflow.xml | 10 ++- 3 files changed, 52 insertions(+), 40 deletions(-) diff --git a/addons/account/account_cash_statement.py b/addons/account/account_cash_statement.py index 17fa05d5f24..9a5eb93286f 100644 --- a/addons/account/account_cash_statement.py +++ b/addons/account/account_cash_statement.py @@ -78,7 +78,7 @@ class account_cash_statement(osv.osv): """ res = {} for statement in self.browse(cr, uid, ids, context=context): - if statement.journal_id.type not in ('cash',): + if (statement.journal_id.type not in ('cash',)) or (not statement.journal_id.cash_control): continue start = end = 0 for line in statement.details_ids: diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index 9a4711e5f6b..39c98c9faa7 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -296,49 +296,53 @@ class pos_session(osv.osv): ] def create(self, cr, uid, values, context=None): - config_id = values.get('config_id', False) or False - if config_id: - # journal_id is not required on the pos_config because it does not - # exists at the installation. If nothing is configured at the - # installation we do the minimal configuration. Impossible to do in - # the .xml files as the CoA is not yet installed. - jobj = self.pool.get('pos.config') - pos_config = jobj.browse(cr, uid, config_id, context=context) - if not pos_config.journal_id: - jid = jobj.default_get(cr, uid, ['journal_id'], context=context)['journal_id'] - if jid: - jobj.write(cr, uid, [pos_config.id], {'journal_id': jid}, context=context) - else: - raise osv.except_osv( _('error!'), - _("Unable to open the session. You have to assign a sale journal to your point of sale.")) + context = context or {} + config_id = values.get('config_id', False) or context.get('default_config_id', False) + if not config_id: + raise osv.except_osv( _('Error!'), + _("You should assign a Point of Sale to your session.")) - # define some cash journal if no payment method exists - if not pos_config.journal_ids: - journal_proxy = self.pool.get('account.journal') - cashids = journal_proxy.search(cr, uid, [('journal_user', '=', True), ('type','=','cash')], context=context) + # journal_id is not required on the pos_config because it does not + # exists at the installation. If nothing is configured at the + # installation we do the minimal configuration. Impossible to do in + # the .xml files as the CoA is not yet installed. + jobj = self.pool.get('pos.config') + pos_config = jobj.browse(cr, uid, config_id, context=context) + if not pos_config.journal_id: + jid = jobj.default_get(cr, uid, ['journal_id'], context=context)['journal_id'] + if jid: + jobj.write(cr, uid, [pos_config.id], {'journal_id': jid}, context=context) + else: + raise osv.except_osv( _('error!'), + _("Unable to open the session. You have to assign a sale journal to your point of sale.")) + + # define some cash journal if no payment method exists + if not pos_config.journal_ids: + journal_proxy = self.pool.get('account.journal') + cashids = journal_proxy.search(cr, uid, [('journal_user', '=', True), ('type','=','cash')], context=context) + if not cashids: + cashids = journal_proxy.search(cr, uid, [('type', '=', 'cash')], context=context) if not cashids: - cashids = journal_proxy.search(cr, uid, [('type', '=', 'cash')], context=context) - if not cashids: - cashids = journal_proxy.search(cr, uid, [('journal_user','=',True)], context=context) + cashids = journal_proxy.search(cr, uid, [('journal_user','=',True)], context=context) - jobj.write(cr, uid, [pos_config.id], {'journal_ids': [(6,0, cashids)]}) + jobj.write(cr, uid, [pos_config.id], {'journal_ids': [(6,0, cashids)]}) - pos_config = jobj.browse(cr, uid, config_id, context=context) - bank_statement_ids = [] - for journal in pos_config.journal_ids: - bank_values = { - 'journal_id' : journal.id, - 'user_id' : uid, - } - statement_id = self.pool.get('account.bank.statement').create(cr, uid, bank_values, context=context) - bank_statement_ids.append(statement_id) + pos_config = jobj.browse(cr, uid, config_id, context=context) + bank_statement_ids = [] + for journal in pos_config.journal_ids: + bank_values = { + 'journal_id' : journal.id, + 'user_id' : uid, + } + statement_id = self.pool.get('account.bank.statement').create(cr, uid, bank_values, context=context) + bank_statement_ids.append(statement_id) - values.update({ - 'name' : pos_config.sequence_id._next(), - 'statement_ids' : [(6, 0, bank_statement_ids)], - 'config_id': config_id - }) + values.update({ + 'name' : pos_config.sequence_id._next(), + 'statement_ids' : [(6, 0, bank_statement_ids)], + 'config_id': config_id + }) return super(pos_session, self).create(cr, uid, values, context=context) @@ -390,7 +394,7 @@ class pos_session(osv.osv): def wkf_action_closing_control(self, cr, uid, ids, context=None): for session in self.browse(cr, uid, ids, context=context): for statement in session.statement_ids: - if statement != session.cash_register_id and statement.balance_end != statement.balance_end_real: + if (statement != session.cash_register_id) and (statement.balance_end != statement.balance_end_real): self.pool.get('account.bank.statement').write(cr, uid, [statement.id], {'balance_end_real': statement.balance_end}) return self.write(cr, uid, ids, {'state' : 'closing_control', 'stop_at' : time.strftime('%Y-%m-%d %H:%M:%S')}, context=context) diff --git a/addons/point_of_sale/point_of_sale_workflow.xml b/addons/point_of_sale/point_of_sale_workflow.xml index 601fbae4d23..ad7b149f6bc 100644 --- a/addons/point_of_sale/point_of_sale_workflow.xml +++ b/addons/point_of_sale/point_of_sale_workflow.xml @@ -152,7 +152,7 @@ - + close cash_control == False @@ -163,5 +163,13 @@ close + + + + cash_control == False + + + + From 4a15e55895c9165043fb527ed186f4fa90cdc8b0 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Sat, 3 Nov 2012 18:16:27 +0100 Subject: [PATCH 639/703] [FIX] bug pos bzr revid: fp@openerp.com-20121103171627-7mvvn13494ofbbh0 --- addons/account/account_cash_statement.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/account/account_cash_statement.py b/addons/account/account_cash_statement.py index 9a5eb93286f..c1f30824461 100644 --- a/addons/account/account_cash_statement.py +++ b/addons/account/account_cash_statement.py @@ -289,13 +289,13 @@ class account_cash_statement(osv.osv): super(account_cash_statement, self).button_confirm_bank(cr, uid, ids, context=context) absl_proxy = self.pool.get('account.bank.statement.line') - TABLES = (('Profit', 'profit_account_id'), ('Loss', 'loss_account_id'),) + TABLES = ((_('Profit'), 'profit_account_id'), (_('Loss'), 'loss_account_id'),) for obj in self.browse(cr, uid, ids, context=context): if obj.difference == 0.0: continue - for item_label, item_account in TALBES: + for item_label, item_account in TABLES: if getattr(obj.journal_id, item_account): raise osv.except_osv(_('Error!'), _('There is no %s Account on the journal %s.') % (item_label, obj.journal_id.name,)) From 29fffbc97d8970513114b7b76763f002aa73e395 Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Sun, 4 Nov 2012 04:55:54 +0000 Subject: [PATCH 640/703] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20121104045554-ygf95bxx3xy44tm1 --- addons/l10n_be_coda/i18n/zh_CN.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/l10n_be_coda/i18n/zh_CN.po b/addons/l10n_be_coda/i18n/zh_CN.po index a762dd056b8..c18ff96e735 100644 --- a/addons/l10n_be_coda/i18n/zh_CN.po +++ b/addons/l10n_be_coda/i18n/zh_CN.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-11-03 05:04+0000\n" +"X-Launchpad-Export-Date: 2012-11-04 04:55+0000\n" "X-Generator: Launchpad (build 16218)\n" #. module: account_coda From 958edad9656ccfda7578af0c9d52c1abd8a7fee3 Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Mon, 5 Nov 2012 04:40:53 +0000 Subject: [PATCH 641/703] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20121105044053-iwdfmabj0neffc9o --- openerp/addons/base/i18n/es_EC.po | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/openerp/addons/base/i18n/es_EC.po b/openerp/addons/base/i18n/es_EC.po index 70227777a1f..284b4de49c8 100644 --- a/openerp/addons/base/i18n/es_EC.po +++ b/openerp/addons/base/i18n/es_EC.po @@ -7,14 +7,14 @@ msgstr "" "Project-Id-Version: OpenERP Server 6.0.0-rc1\n" "Report-Msgid-Bugs-To: support@openerp.com\n" "POT-Creation-Date: 2012-02-08 00:44+0000\n" -"PO-Revision-Date: 2011-01-18 05:32+0000\n" +"PO-Revision-Date: 2012-11-05 00:42+0000\n" "Last-Translator: Cristian Salamea (Gnuthink) \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-10-20 05:06+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-05 04:40+0000\n" +"X-Generator: Launchpad (build 16232)\n" #. module: base #: model:res.country,name:base.sh @@ -655,6 +655,26 @@ msgid "" " Accounting/Reporting/Generic Reporting/Partners/Follow-ups Sent\n" "\n" msgstr "" +"\n" +"Modulo para automatizar cartas para facturas no pagadas, con recordatorios " +"multi-nivel\n" +"==========================================================================\n" +"\n" +"Pueden definirse múltiples niveles de recordatorios a través del menú:\n" +" Contabilidad/Configuración/Varios/Seguimientos\n" +"\n" +"Una vez definidos, pueden imprimirse automáticamente recordatorios cada día, " +"simplemente haciendo clic en el menú: \n" +" Contabilidad/Procesamiento periódico/Facturación/Enviar seguimientos\n" +"\n" +"Se generará un PDF con todas las cartas de acuerdo con los diferentes \n" +"niveles de recordatorio definidos. Se pueden definir diferentes políticas\n" +"para las distintas compañías . También se puede enviar correo al cliente.\n" +"\n" +"Debe denotarse que si se quiere revisar el nivel de seguimiento de una " +"empresa/cuenta determinada, se puede realizar en el menú:\n" +" Contabilidad/Informes/Informes genéricos/Empresas/Seguimientos enviados\n" +"\n" #. module: base #: field:res.country,name:0 From db13e8591a5c622f25ea9adf65e9810a569f8915 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 5 Nov 2012 09:22:59 +0100 Subject: [PATCH 642/703] [FIX] fields.related._fnct_write: handle the case where ids is a single id bzr revid: rco@openerp.com-20121105082259-rcmcjs5n1eimtcpl --- openerp/osv/fields.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index c67df5a70b4..56e7f790a9e 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1158,6 +1158,8 @@ class related(function): return map(lambda x: (field, x[1], x[2]), domain) def _fnct_write(self,obj,cr, uid, ids, field_name, values, args, context=None): + if isinstance(ids, (int, long)): + ids = [ids] for record in obj.browse(cr, uid, ids, context=context): # traverse all fields except the last one for field in self.arg[:-1]: From 52c29ae1c0055621d39f8d46b288ace068841777 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 5 Nov 2012 10:49:29 +0100 Subject: [PATCH 643/703] [FIX] fields.related._fnct_read: fix handling of type many2one bzr revid: rco@openerp.com-20121105094929-oz7trjzwlqw90499 --- openerp/osv/fields.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 56e7f790a9e..3086e8925b4 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1186,13 +1186,12 @@ class related(function): res[record.id] = value if self._type == 'many2one': - # res[id] is a browse_record or False; convert it to (id, name) or False - res = dict((id, value and value.id) for id, value in res.iteritems()) - value_ids = filter(None, res.itervalues()) - # name_get as root, as seeing the name of a related object depends on + # res[id] is a browse_record or False; convert it to (id, name) or False. + # Perform name_get as root, as seeing the name of a related object depends on # access right of source document, not target, so user may not have access. + value_ids = [value.id for id, value in res.iteritems() if value] value_name = dict(obj.pool.get(self._obj).name_get(cr, SUPERUSER_ID, value_ids, context=context)) - res = dict((id, value_id and value_name[value_id]) for id, value_id in res.iteritems()) + res = dict((id, value and (value.id, value_name[value.id])) for id, value in res.iteritems()) elif self._type in ('one2many', 'many2many'): # res[id] is a list of browse_record or False; convert it to a list of ids From 00a28c4b3d9a4e5ec2af6ad229a56d74a3030937 Mon Sep 17 00:00:00 2001 From: "Sanjay Gohel (Open ERP)" Date: Mon, 5 Nov 2012 16:13:57 +0530 Subject: [PATCH 644/703] [IMP]pos does not calculate tax and touch screen does not gives actually quantity bzr revid: sgo@tinyerp.com-20121105104357-6r59u4g20ojg0hlw --- addons/point_of_sale/static/src/js/models.js | 2 +- addons/point_of_sale/static/src/js/widgets.js | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/addons/point_of_sale/static/src/js/models.js b/addons/point_of_sale/static/src/js/models.js index 360f88b715b..d7d6d3181f1 100644 --- a/addons/point_of_sale/static/src/js/models.js +++ b/addons/point_of_sale/static/src/js/models.js @@ -465,7 +465,7 @@ function openerp_pos_models(instance, module){ //module is instance.point_of_sal var product_list = this.pos.get('product_list'); var product = this.get_product(); - var taxes_ids = product.taxes_id; + var taxes_ids = product.get('taxes_id');; var taxes = self.pos.get('taxes'); var taxtotal = 0; _.each(taxes_ids, function(el) { diff --git a/addons/point_of_sale/static/src/js/widgets.js b/addons/point_of_sale/static/src/js/widgets.js index 28ab79c65b2..ed9b1fd060a 100644 --- a/addons/point_of_sale/static/src/js/widgets.js +++ b/addons/point_of_sale/static/src/js/widgets.js @@ -202,12 +202,8 @@ function openerp_pos_widgets(instance, module){ //module is instance.point_of_sa this.currentOrderLines.bind('remove', this.renderElement, this); }, update_numpad: function() { - var reset = false; - if (this.selected_line !== this.pos.get('selectedOrder').getSelectedLine()) { - reset = true; - } this.selected_line = this.pos.get('selectedOrder').getSelectedLine(); - if (reset && this.numpadState) + if (this.numpadState) this.numpadState.reset(); }, renderElement: function() { From 6f57449dcd48714ff9df5ff37dfbc0882610020e Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 5 Nov 2012 14:00:53 +0100 Subject: [PATCH 645/703] [IMP] Client actions now takes the action as argument. Use action.params for options. bzr revid: fme@openerp.com-20121105130053-6gdklt6ok4lst6ba --- addons/web/static/src/js/chrome.js | 13 +++++++------ addons/web/static/src/js/views.js | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 6cf35a14e92..08ef8c4f9bf 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -504,13 +504,13 @@ instance.web.Login = instance.web.Widget.extend({ template: "Login", remember_credentials: true, - init: function(parent, params) { + init: function(parent, action) { this._super(parent); this.has_local_storage = typeof(localStorage) != 'undefined'; this.db_list = null; this.selected_db = null; this.selected_login = null; - this.params = params || {}; + this.params = action.params || {}; if (this.params.login_successful) { this.on('login_successful', this, this.params.login_successful); @@ -616,8 +616,9 @@ instance.web.client_actions.add("login", "instance.web.Login"); * Client action to reload the whole interface. * If params has an entry 'menu_id', it opens the given menu entry. */ -instance.web.Reload = function(parent, params) { - var menu_id = (params && params.menu_id) || false; +instance.web.Reload = function(parent, action) { + var params = action.params || {}; + var menu_id = params.menu_id || false; var l = window.location; var sobj = $.deparam(l.search.substr(1)); @@ -638,7 +639,7 @@ instance.web.client_actions.add("reload", "instance.web.Reload"); * Client action to go back in breadcrumb history. * If can't go back in history stack, will go back to home. */ -instance.web.HistoryBack = function(parent, params) { +instance.web.HistoryBack = function(parent) { if (!parent.history_back()) { window.location = '/' + (window.location.search || ''); } @@ -649,7 +650,7 @@ instance.web.client_actions.add("history_back", "instance.web.HistoryBack"); * Client action to go back home. */ instance.web.Home = instance.web.Widget.extend({ - init: function(parent, params) { + init: function(parent) { window.location = '/' + (window.location.search || ''); } }); diff --git a/addons/web/static/src/js/views.js b/addons/web/static/src/js/views.js index ebc7c326724..a4fe86c516d 100644 --- a/addons/web/static/src/js/views.js +++ b/addons/web/static/src/js/views.js @@ -247,7 +247,7 @@ instance.web.ActionManager = instance.web.Widget.extend({ action_menu_id: null, }); if (_.isString(action) && instance.web.client_actions.contains(action)) { - var action_client = { type: "ir.actions.client", tag: action }; + var action_client = { type: "ir.actions.client", tag: action, params: {} }; return this.do_action(action_client, options); } else if (_.isNumber(action) || _.isString(action)) { var self = this; @@ -346,14 +346,14 @@ instance.web.ActionManager = instance.web.Widget.extend({ if (!(ClientWidget.prototype instanceof instance.web.Widget)) { var next; - if (next = ClientWidget(this, action.params)) { + if (next = ClientWidget(this, action)) { return this.do_action(next, options); } return $.when(); } return this.ir_actions_common({ - widget: function () { return new ClientWidget(self, action.params); }, + widget: function () { return new ClientWidget(self, action); }, action: action, klass: 'oe_act_client', post_process: function(widget) { From cbbd4dcee3b3dc8500fe7b2887eb965978b75b5e Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 5 Nov 2012 14:01:30 +0100 Subject: [PATCH 646/703] [IMP] Client actions now takes the action as argument. Use action.params for options. bzr revid: fme@openerp.com-20121105130130-dwkn8124zc6yq933 --- addons/base_import/static/src/js/import.js | 4 ++-- addons/mail/static/src/js/mail.js | 16 +++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 407d38dacd7..510afaaead8 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -123,10 +123,10 @@ openerp.base_import = function (instance) { this.exit(); } }, - init: function (parent, params) { + init: function (parent, action) { var self = this; this._super.apply(this, arguments); - this.res_model = params.model; + this.res_model = action.params.model; // import object id this.id = null; this.Import = new instance.web.Model('base_import.import'); diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 9133e5de257..bfda31119f2 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -1385,7 +1385,8 @@ openerp.mail = function (session) { * When you use this option, the domain is not used for the fetch root. * @param {String} [no_message] Message to display when there are no message */ - init: function (parent, options) { + init: function (parent, action) { + var options = action.params || {}; this._super(parent); this.domain = options.domain || []; this.context = options.context || {}; @@ -1513,7 +1514,7 @@ openerp.mail = function (session) { this.root.destroy(); } // create and render Thread widget - this.root = new mail.Widget(this, { + this.root = new mail.Widget(this, { params: { 'domain' : domain, 'context' : this.options.context, 'typeof_thread': this.options.context['typeof_thread'] || 'other', @@ -1524,7 +1525,7 @@ openerp.mail = function (session) { 'message_ids': message_ids, 'show_compact_message': true, 'no_message': this.node.attrs.help - } + }} ); return this.root.replace(this.$('.oe_mail-placeholder')); @@ -1552,9 +1553,10 @@ openerp.mail = function (session) { * @param {Object} [options.context] context, is an object. It should * contain default_model, default_res_id, to give it to the threads. */ - init: function (parent, options) { + init: function (parent, action) { this._super(parent); - this.options = options || {}; + var options = action.params || {}; + this.options = options; this.options.domain = options.domain || []; this.options.context = options.context || {}; this.search_results = {'domain': [], 'context': {}, 'groupby': {}} @@ -1611,7 +1613,7 @@ openerp.mail = function (session) { message_render: function (search) { 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, { + this.root = new mail.Widget(this, { params: { 'domain' : domain, 'context' : context, 'typeof_thread': context['typeof_thread'] || 'other', @@ -1620,7 +1622,7 @@ openerp.mail = function (session) { 'show_read_unread_button': 11, 'show_compose_message': true, 'show_compact_message': false, - } + }} ); return this.root.replace(this.$('.oe_mail-placeholder')); From 750ef9d931b19a184b4cb161ce44018d9f574b77 Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 5 Nov 2012 14:17:12 +0100 Subject: [PATCH 647/703] [IMP] fields.related._fnct_read: small improvements bzr revid: rco@openerp.com-20121105131712-sc70thn3wpyq6o7y --- openerp/osv/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/osv/fields.py b/openerp/osv/fields.py index 3086e8925b4..2d51ad7d6db 100644 --- a/openerp/osv/fields.py +++ b/openerp/osv/fields.py @@ -1189,7 +1189,7 @@ class related(function): # res[id] is a browse_record or False; convert it to (id, name) or False. # Perform name_get as root, as seeing the name of a related object depends on # access right of source document, not target, so user may not have access. - value_ids = [value.id for id, value in res.iteritems() if value] + value_ids = list(set(value.id for value in res.itervalues() if value)) value_name = dict(obj.pool.get(self._obj).name_get(cr, SUPERUSER_ID, value_ids, context=context)) res = dict((id, value and (value.id, value_name[value.id])) for id, value in res.iteritems()) From cf4f0a1021db1380022d37d9ed6035b14a65cda8 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Mon, 5 Nov 2012 14:32:29 +0100 Subject: [PATCH 648/703] [WIP] better management of start and end dates bzr revid: abo@openerp.com-20121105133229-e3qge2pid9j6u4ck --- addons/hr_holidays/hr_holidays.py | 47 ++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index cad7fc30beb..7181f836bb5 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -207,30 +207,49 @@ class hr_holidays(osv.osv): return super(hr_holidays, self).unlink(cr, uid, ids, context) def onchange_date_from(self, cr, uid, ids, date_to, date_from): - result = {} + """ + If there are no date set for date_to, automatically set one 8 hours later than + the date_from. + Also update the number_of_days. + """ + # date_to has to be greater than date_from + if (date_from and date_to) and (date_from > date_to): + raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.')) + + result = {'value': {}} DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" # No date_to set so far: automatically compute one 8 hours later if date_from and not date_to: - date_to = datetime.datetime.strptime(date_from, DATETIME_FORMAT) + datetime.timedelta(hours=8) - result['value'] = {'date_to': str(date_to)} - # date_from is greater than date_to: throw an exception - elif (date_from and date_to) and (date_from > date_to): - raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.')) + date_to_with_delta = datetime.datetime.strptime(date_from, DATETIME_FORMAT) + datetime.timedelta(hours=8) + result['value']['date_to'] = str(date_to_with_delta) + + # Compute and update the number of days + if (date_to and date_from) and (date_from <= date_to): + diff_day = self._get_number_of_days(date_from, date_to) + result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1 + else: + result['value']['number_of_days_temp'] = 0 return result def onchange_date_to(self, cr, uid, ids, date_to, date_from): - result = {} - if date_to and date_from: + """ + Update the number_of_days. + """ + + # date_to has to be greater than date_from + if (date_from and date_to) and (date_from > date_to): + raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.')) + + result = {'value': {}} + + # Compute and update the number of days + if (date_to and date_from) and (date_from <= date_to): diff_day = self._get_number_of_days(date_from, date_to) - result['value'] = { - 'number_of_days_temp': round(math.floor(diff_day))+1 - } + result['value']['number_of_days_temp'] = round(math.floor(diff_day))+1 else: - result['value'] = { - 'number_of_days_temp': 0, - } + result['value']['number_of_days_temp'] = 0 return result From 2e4cb3a69a188579492cd9e2939c0c299f0c32ec Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Mon, 5 Nov 2012 16:04:12 +0100 Subject: [PATCH 649/703] [FIX] Dirty workaround for dhtmlxscheduler bug bzr revid: fme@openerp.com-20121105150412-7x0ah1mfuvffsipe --- addons/web_calendar/static/src/js/calendar.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/web_calendar/static/src/js/calendar.js b/addons/web_calendar/static/src/js/calendar.js index 986b239bb1b..36e37219bf8 100644 --- a/addons/web_calendar/static/src/js/calendar.js +++ b/addons/web_calendar/static/src/js/calendar.js @@ -185,6 +185,7 @@ instance.web_calendar.CalendarView = instance.web.View.extend({ } }); scheduler.attachEvent('onEmptyClick', function(start_date, mouse_event) { + scheduler._loading = false; // Dirty workaround for a dhtmleditor bug I couln't track if (!self.$el.find('.dhx_cal_editor').length) { var end_date = new Date(start_date); end_date.addHours(1); @@ -451,7 +452,7 @@ instance.web_calendar.CalendarView = instance.web.View.extend({ scheduler.addEvent({ start_date: event_obj.start_date, end_date: event_obj.end_date, - text: event_obj.text + ' fix', + text: event_obj.text, _force_slow_create: true, }); } else { From 88f06c467cfd8625ab58b556a2529c4ab4291c11 Mon Sep 17 00:00:00 2001 From: Antonin Bourguignon Date: Mon, 5 Nov 2012 18:03:18 +0100 Subject: [PATCH 650/703] [IMP] use tools.DEFAULT_SERVER_DATETIME_FORMAT bzr revid: abo@openerp.com-20121105170318-fmq31jsjf1xriqnh --- addons/hr_holidays/hr_holidays.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/hr_holidays/hr_holidays.py b/addons/hr_holidays/hr_holidays.py index 7181f836bb5..f315f3d4ef3 100644 --- a/addons/hr_holidays/hr_holidays.py +++ b/addons/hr_holidays/hr_holidays.py @@ -27,6 +27,7 @@ from operator import itemgetter import math import netsvc +import tools from osv import fields, osv from tools.translate import _ @@ -217,11 +218,10 @@ class hr_holidays(osv.osv): raise osv.except_osv(_('Warning!'),_('The start date must be anterior to the end date.')) result = {'value': {}} - DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S" # No date_to set so far: automatically compute one 8 hours later if date_from and not date_to: - date_to_with_delta = datetime.datetime.strptime(date_from, DATETIME_FORMAT) + datetime.timedelta(hours=8) + date_to_with_delta = datetime.datetime.strptime(date_from, tools.DEFAULT_SERVER_DATETIME_FORMAT) + datetime.timedelta(hours=8) result['value']['date_to'] = str(date_to_with_delta) # Compute and update the number of days From c1d04e00d6efcead56f005d023f61ef120a7ba51 Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Tue, 6 Nov 2012 04:50:08 +0000 Subject: [PATCH 651/703] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20121106045008-xngylwi17dh211vm --- openerp/addons/base/i18n/es_EC.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/addons/base/i18n/es_EC.po b/openerp/addons/base/i18n/es_EC.po index 284b4de49c8..b71c0857970 100644 --- a/openerp/addons/base/i18n/es_EC.po +++ b/openerp/addons/base/i18n/es_EC.po @@ -13,7 +13,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-11-05 04:40+0000\n" +"X-Launchpad-Export-Date: 2012-11-06 04:50+0000\n" "X-Generator: Launchpad (build 16232)\n" #. module: base From f02c4266d67b8f0b6f6932e56b604b33d518fe15 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Mon, 5 Nov 2012 11:07:17 +0100 Subject: [PATCH 652/703] [IMP] better logging during import failure bzr revid: xmo@openerp.com-20121105100717-pqexs7j710s2ea2i --- openerp/osv/orm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 8d83e1058bc..a866b843582 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1352,9 +1352,11 @@ class BaseModel(object): noupdate=noupdate, res_id=id, context=context)) cr.execute('RELEASE SAVEPOINT model_load_save') except psycopg2.Warning, e: + _logger.exception('Failed to import record %s', record) cr.execute('ROLLBACK TO SAVEPOINT model_load_save') messages.append(dict(info, type='warning', message=str(e))) except psycopg2.Error, e: + _logger.exception('Failed to import record %s', record) # Failed to write, log to messages, rollback savepoint (to # avoid broken transaction) and keep going cr.execute('ROLLBACK TO SAVEPOINT model_load_save') From 4dbe51e8bd5bb0dd55de3a043dc30c7ccf745f2f Mon Sep 17 00:00:00 2001 From: Arnaud Pineux Date: Mon, 5 Nov 2012 12:01:47 +0100 Subject: [PATCH 653/703] Lunch bzr revid: api@openerp.com-20121105110147-mts2pt2b0vr29kfh --- addons/lunch/__openerp__.py | 1 - addons/lunch/lunch.py | 150 +++++++++++++++++++------------ addons/lunch/lunch_view.xml | 2 +- addons/lunch/tests/__init__.py | 27 ++++++ addons/lunch/tests/test_lunch.py | 83 +++++++++++++++++ 5 files changed, 204 insertions(+), 59 deletions(-) create mode 100644 addons/lunch/tests/__init__.py create mode 100644 addons/lunch/tests/test_lunch.py diff --git a/addons/lunch/__openerp__.py b/addons/lunch/__openerp__.py index becf1786e43..5f01d3202da 100644 --- a/addons/lunch/__openerp__.py +++ b/addons/lunch/__openerp__.py @@ -45,7 +45,6 @@ If you want to save your employees' time and avoid them to always have coins in 'security/ir.model.access.csv',], 'css':['static/src/css/lunch.css'], 'demo': ['lunch_demo.xml',], - 'test': [], 'installable': True, 'application' : True, 'certificate' : '001292377792581874189', diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index eb22c3133ce..cc41f051471 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -29,32 +29,39 @@ from lxml import etree from tools.translate import _ class lunch_order(osv.Model): - """ lunch order """ + """ + lunch order (contains one or more lunch order line(s)) + """ _name = 'lunch.order' _description = 'Lunch Order' def _price_get(self, cr, uid, ids, name, arg, context=None): - """ get and sum the order lines' price""" - result={} + """ + get and sum the order lines' price + """ + result = dict.fromkeys(ids, 0) for order in self.browse(cr, uid, ids, context=context): - value = 0.0 - for orderline in order.order_line_ids: - value += orderline.product_id.price - result[order.id]=value + result[order.id] = sum(order_line.product_id.price + for order_line in order.order_line_ids) return result def _compute_total(self, cr, uid, ids, name, context=None): - """ compute total""" - result= {} + """ + compute total + """ + result = set() for order_line in self.browse(cr, uid, ids, context=context): - result[order_line.order_id.id] = True - return result.keys() + if order_line.order_id: + result.add(order_line.order_id.id) + return list(result) def add_preference(self, cr, uid, ids, pref_id, context=None): - """ create a new order line based on the preference selected (pref_id)""" + """ + create a new order line based on the preference selected (pref_id) + """ orderline_ref = self.pool.get('lunch.order.line') prod_ref = self.pool.get('lunch.product') - order = self.browse(cr,uid,ids,context=context)[0] + order = self.browse(cr,uid,ids[0],context=context) pref = orderline_ref.browse(cr,uid,pref_id,context=context) new_order_line = { 'date': order.date, @@ -68,7 +75,9 @@ class lunch_order(osv.Model): return orderline_ref.create(cr,uid,new_order_line) def _alerts_get(self, cr, uid, ids, name, arg, context=None): - """ get the alerts to display on the order form """ + """ + get the alerts to display on the order form + """ orders = self.browse(cr,uid,ids,context=context) result={} alert_msg= self._default_alerts_get(cr,uid,arg,context=context) @@ -78,29 +87,21 @@ class lunch_order(osv.Model): return result def check_day(self, alert): - """ This method is used by can_display_alert to - to check if the alert day corresponds - to the current day + """ + This method is used by can_display_alert + to check if the alert day corresponds + to the current day """ today = datetime.now().isoweekday() - if today == 1: - return alert.monday - if today == 2: - return alert.tuesday - if today == 3: - return alert.wednesday - if today == 4: - return alert.thursday - if today == 5: - return alert.friday - if today == 6: - return alert.saturday - if today == 7: - return alert.sunday - assert "today should be between 1 and 7" + assert 1 <= today <= 7, "Should be between 1 and 7" + mapping = dict((idx, name) for idx, name in enumerate('monday tuestday wednesday thursday friday saturday sunday'.split())) + if today in mapping: + return mapping[today] def can_display_alert(self, alert): - """ This method check if the alert can be displayed today """ + """ + This method check if the alert can be displayed today + """ if alert.day=='specific': #the alert is only activated a specific day return alert.specific==fields.datetime.now()[:10] @@ -111,7 +112,9 @@ class lunch_order(osv.Model): # code to improve def _default_alerts_get(self,cr,uid,arg,context=None): - """ get the alerts to display on the order form """ + """ + get the alerts to display on the order form + """ alert_ref = self.pool.get('lunch.alert') alert_ids = alert_ref.search(cr,uid,[],context=context) alert_msg = [] @@ -134,7 +137,9 @@ class lunch_order(osv.Model): return '\n'.join(alert_msg) def onchange_price(self,cr,uid,ids,order_line_ids,context=None): - """ Onchange methode that refresh the total price of order""" + """ + Onchange methode that refresh the total price of order + """ res = {'value':{'total':0.0}} order_line_ids= self.resolve_o2m_commands_to_record_dicts(cr, uid, "order_line_ids", order_line_ids, ["price"], context) if order_line_ids: @@ -149,9 +154,11 @@ class lunch_order(osv.Model): return res def __getattr__(self, attr): - """ this method catch unexisting method call and if starts with - add_preference_'n' we execute the add_preference method with - 'n' as parameter """ + """ + this method catch unexisting method call and if starts with + add_preference_'n' we execute the add_preference method with + 'n' as parameter + """ if attr.startswith('add_preference_'): pref_id = int(attr[15:]) def specific_function(cr, uid, ids, context=None): @@ -160,7 +167,9 @@ class lunch_order(osv.Model): return super(lunch_order,self).__getattr__(self,attr) def fields_view_get(self, cr, uid, view_id=None, view_type=False, context=None, toolbar=False, submenu=False): - """ Add preferences in the form view of order.line """ + """ + Add preferences in the form view of order.line + """ res = super(lunch_order,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu) line_ref = self.pool.get("lunch.order.line") if view_type == 'form': @@ -239,7 +248,6 @@ class lunch_order(osv.Model): }), 'state': fields.selection([('new', 'New'),('confirmed','Confirmed'), ('cancelled','Cancelled'), ('partially','Partially Confirmed')],'Status', readonly=True, select=True), #TODO: parcially? #TODO: the labels are confusing. confirmed=='received' or 'delivered'... 'alerts': fields.function(_alerts_get, string="Alerts", type='text'), - 'company_id': fields.many2one('res.company', 'Company', required=True), } _defaults = { @@ -251,31 +259,49 @@ class lunch_order(osv.Model): class lunch_order_line(osv.Model): - """ lunch order line : one lunch order can have many order lines""" + """ + lunch order line : one lunch order can have many order lines + """ _name = 'lunch.order.line' _description = 'lunch order line' def onchange_price(self,cr,uid,ids,product_id,context=None): if product_id: - price = self.pool.get('lunch.product').read(cr, uid, product_id, ['price'])['price'] + price = self.pool.get('lunch.product').browse(cr, uid, product_id).price return {'value': {'price': price}} return {'value': {'price': 0.0}} def order(self,cr,uid,ids,context=None): - for order_line in self.browse(cr,uid,ids,context=context): - self.write(cr,uid,[order_line.id],{'state':'ordered'},context) - return {} + """ + The order_line is ordered to the supplier but isn't received yet + """ + for order_line in self.browse(cr, uid, ids, context=context): + order_line.write({'state' : 'ordered'}) + return self._update_order_lines(cr, uid, ids, context) def confirm(self,cr,uid,ids,context=None): - """ confirm one or more order line, update order status and create new cashmove """ + """ + confirm one or more order line, update order status and create new cashmove + """ cashmove_ref = self.pool.get('lunch.cashmove') for order_line in self.browse(cr,uid,ids,context=context): if order_line.state!='confirmed': - new_id = cashmove_ref.create(cr,uid,{'user_id': order_line.user_id.id, 'amount':-order_line.price,'description':order_line.product_id.name, 'order_id':order_line.id, 'state':'order', 'date':order_line.date}) - self.write(cr,uid,[order_line.id],{'state':'confirmed'},context) + values = { + 'user_id' : order_line.user_id.id, + 'amount' : -order_line.price, + 'description': order_line.product_id.name, + 'order_id' : order_line.id, + 'state' : 'order', + 'date': order_line.date, + } + cashmove_ref.create(cr, uid, values, context=context) + order_line.write({'state' : 'confirmed'}) return self._update_order_lines(cr, uid, ids, context) def _update_order_lines(self, cr, uid, ids, context=None): + """ + Update the state of lunch.order based on its orderlines + """ orders_ref = self.pool.get('lunch.order') orders = [] for order_line in self.browse(cr,uid,ids,context=context): @@ -287,16 +313,18 @@ class lunch_order_line(osv.Model): isconfirmed = False if orderline.state == 'cancelled': isconfirmed = False - orders_ref.write(cr,uid,[order.id],{'state':'partially'},context=context) + order.write({'state':'partially'}) if isconfirmed: - orders_ref.write(cr,uid,[order.id],{'state':'confirmed'},context=context) + order.write({'state':'confirmed'}) return {} def cancel(self,cr,uid,ids,context=None): - """ confirm one or more order.line, update order status and create new cashmove """ + """ + confirm one or more order.line, update order status and create new cashmove + """ cashmove_ref = self.pool.get('lunch.cashmove') for order_line in self.browse(cr,uid,ids,context=context): - self.write(cr,uid,[order_line.id],{'state':'cancelled'},context) + order_line.write({'state':'cancelled'}) for cash in order_line.cashmove: cashmove_ref.unlink(cr,uid,cash.id,context) return self._update_order_lines(cr, uid, ids, context) @@ -313,7 +341,7 @@ class lunch_order_line(osv.Model): 'state': fields.selection([('new', 'New'),('confirmed','Received'), ('ordered','Ordered'), ('cancelled','Cancelled')], \ 'Status', readonly=True, select=True), #new confirmed and cancelled are the convention 'cashmove': fields.one2many('lunch.cashmove','order_id','Cash Move',ondelete='cascade'), - + } _defaults = { 'state': 'new', @@ -321,7 +349,9 @@ class lunch_order_line(osv.Model): class lunch_product(osv.Model): - """ lunch product """ + """ + lunch product + """ _name = 'lunch.product' _description = 'lunch product' _columns = { @@ -333,7 +363,9 @@ class lunch_product(osv.Model): } class lunch_product_category(osv.Model): - """ lunch product category """ + """ + lunch product category + """ _name = 'lunch.product.category' _description = 'lunch product category' _columns = { @@ -341,7 +373,9 @@ class lunch_product_category(osv.Model): } class lunch_cashmove(osv.Model): - """ lunch cashmove => order or payment """ + """ + lunch cashmove => order or payment + """ _name = 'lunch.cashmove' _description = 'lunch cashmove' _columns = { @@ -359,7 +393,9 @@ class lunch_cashmove(osv.Model): } class lunch_alert(osv.Model): - """ lunch alert """ + """ + lunch alert + """ _name = 'lunch.alert' _description = 'lunch alert' _columns = { diff --git a/addons/lunch/lunch_view.xml b/addons/lunch/lunch_view.xml index 4f2c3f0892b..3cdab20cb9c 100644 --- a/addons/lunch/lunch_view.xml +++ b/addons/lunch/lunch_view.xml @@ -345,7 +345,7 @@
- + diff --git a/addons/lunch/tests/__init__.py b/addons/lunch/tests/__init__.py new file mode 100644 index 00000000000..194888974b0 --- /dev/null +++ b/addons/lunch/tests/__init__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2012-TODAY OpenERP S.A. +# +# 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 . import test_lunch + +checks = [ + test_lunch, +] + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/lunch/tests/test_lunch.py b/addons/lunch/tests/test_lunch.py new file mode 100644 index 00000000000..d2bfb9eef0f --- /dev/null +++ b/addons/lunch/tests/test_lunch.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Business Applications +# Copyright (c) 2012-TODAY OpenERP S.A. +# +# 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 . +# +############################################################################## + +import tools +from openerp.tests import common + +class Test_Lunch(common.TransactionCase): + + def setUp(self): + """*****setUp*****""" + super(Test_Lunch, self).setUp() + cr, uid = self.cr, self.uid + + self.res_users = self.registry('res.users') + self.lunch_order = self.registry('lunch.order') + self.lunch_order_line = self.registry('lunch.order.line') + self.lunch_cashmove = self.registry('lunch.cashmove') + self.lunch_product = self.registry('lunch.product') + self.lunch_alert = self.registry('lunch.alert') + self.lunch_product_category = self.registry('lunch.product.category') + + self.demo_id = self.res_users.search(cr, uid, [('name', '=', 'Demo User')]) + self.product_bolognese_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'lunch', 'product_Bolognese') + self.product_Bolognese_id = self.product_bolognese_ref and self.product_bolognese_ref[1] or False + self.new_id_order = self.lunch_order.create(cr,uid,{ + 'user_id': self.demo_id[0], + 'order_line_ids':'[]', + },context=None) + self.new_id_order_line = self.lunch_order_line.create(cr,uid,{ + 'order_id':self.new_id_order, + 'product_id':self.product_Bolognese_id, + 'note': '+Emmental', + 'cashmove': [], + 'price': self.lunch_product.browse(cr,uid,self.product_Bolognese_id,context=None).price, + }) + + def test_00_lunch_order(self): + """Change the state of an order line from 'new' to 'ordered' + Check that there are no cashmove linked to that order line""" + cr, uid = self.cr, self.uid + self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None) + #we check that our order_line is a 'new' one and that there are no cashmove linked to that order_line: + self.assertEqual(self.order_one.state,'new') + self.assertEqual(self.order_one.cashmove, []) + #we order that orderline so it's state will be 'ordered' + self.order_one.order() + self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None) + #we check that our order_line is a 'ordered' one and that there are no cashmove linked to that order_line: + self.assertEqual(self.order_one.state,'ordered') + self.assertEqual(self.order_one.cashmove, []) + + def test_01_lunch_order(self): + """Change the state of an order line from 'new' to 'ordered' then to 'confirmed' + Check that there is a cashmove linked to the order line""" + cr, uid = self.cr, self.uid + self.test_00_lunch_order() + #We receive the order so we confirm the order line so it's state will be 'confirmed' + #A cashmove will be created and we will test that the cashmove amount equals the order line price + self.order_one.confirm() + self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None) + #we check that our order_line is a 'confirmed' one and that there are a cashmove linked to that order_line with an amount equals to the order line price: + self.assertEqual(self.order_one.state,'confirmed') + self.assertTrue(self.order_one.cashmove!=[]) + self.assertTrue(self.order_one.cashmove[0].amount==-self.order_one.price) + From 48937ea6afb023fd612b3499c46644fc53337068 Mon Sep 17 00:00:00 2001 From: Arnaud Pineux Date: Mon, 5 Nov 2012 14:47:01 +0100 Subject: [PATCH 654/703] Lunch bzr revid: api@openerp.com-20121105134701-0aiqbddpzd2zqsdd --- addons/lunch/lunch.py | 214 ++++++++++++++++++++++++++---------------- 1 file changed, 135 insertions(+), 79 deletions(-) diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index cc41f051471..5d44859fc77 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -59,10 +59,11 @@ class lunch_order(osv.Model): """ create a new order line based on the preference selected (pref_id) """ + assert len(ids) == 1 orderline_ref = self.pool.get('lunch.order.line') prod_ref = self.pool.get('lunch.product') - order = self.browse(cr,uid,ids[0],context=context) - pref = orderline_ref.browse(cr,uid,pref_id,context=context) + order = self.browse(cr, uid, ids[0], context=context) + pref = orderline_ref.browse(cr, uid, pref_id, context=context) new_order_line = { 'date': order.date, 'user_id': uid, @@ -72,15 +73,15 @@ class lunch_order(osv.Model): 'price': pref.product_id.price, 'supplier': pref.product_id.supplier.id } - return orderline_ref.create(cr,uid,new_order_line) + return orderline_ref.create(cr, uid, new_order_line,context=context) def _alerts_get(self, cr, uid, ids, name, arg, context=None): """ get the alerts to display on the order form """ - orders = self.browse(cr,uid,ids,context=context) + orders = self.browse(cr, uid, ids, context=context) result={} - alert_msg= self._default_alerts_get(cr,uid,arg,context=context) + alert_msg= self._default_alerts_get(cr, uid, arg, context=context) for order in orders: if order.state=='new': result[order.id]=alert_msg @@ -111,14 +112,14 @@ class lunch_order(osv.Model): return True # code to improve - def _default_alerts_get(self,cr,uid,arg,context=None): + def _default_alerts_get(self, cr, uid, arg, context=None): """ get the alerts to display on the order form """ alert_ref = self.pool.get('lunch.alert') - alert_ids = alert_ref.search(cr,uid,[],context=context) + alert_ids = alert_ref.search(cr, uid, [], context=context) alert_msg = [] - for alert in alert_ref.browse(cr,uid,alert_ids,context=context): + for alert in alert_ref.browse(cr, uid, alert_ids, context=context): if self.can_display_alert(alert): #the alert is executing from ... to ... now = datetime.utcnow() @@ -136,18 +137,18 @@ class lunch_order(osv.Model): alert_msg.append(alert.message) return '\n'.join(alert_msg) - def onchange_price(self,cr,uid,ids,order_line_ids,context=None): + def onchange_price(self, cr, uid, ids, order_line_ids, context=None): """ Onchange methode that refresh the total price of order """ res = {'value':{'total':0.0}} - order_line_ids= self.resolve_o2m_commands_to_record_dicts(cr, uid, "order_line_ids", order_line_ids, ["price"], context) + order_line_ids= self.resolve_o2m_commands_to_record_dicts(cr, uid, "order_line_ids", order_line_ids, ["price"], context=context) if order_line_ids: tot = 0.0 product_ref = self.pool.get("lunch.product") for prod in order_line_ids: if 'product_id' in prod: - tot += product_ref.browse(cr,uid,prod['product_id'],context=context).price + tot += product_ref.browse(cr, uid, prod['product_id'], context=context).price else: tot += prod['price'] res = {'value':{'total':tot}} @@ -173,80 +174,129 @@ class lunch_order(osv.Model): res = super(lunch_order,self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type, context=context, toolbar=toolbar, submenu=submenu) line_ref = self.pool.get("lunch.order.line") if view_type == 'form': - pref_ids = line_ref.search(cr,uid,[('user_id','=',uid)],context=context) - text_xml = "
" + doc = etree.XML(res['arch']) + pref_ids = line_ref.search(cr, uid, [('user_id','=',uid)], order='create_date desc', context=context) + xml_start = etree.Element("div") + #If there are no preference (it's the first time for the user) if len(pref_ids)==0: - text_xml+=""" -
-

%s

-

- %s -

- %s -

- %s -

-
- """ % (_("This is the first time you order a meal"), - _("Select a product and put your order comments on the note."), - _("Your favorite meals will be created based on your last orders."), - _("Don't forget the alerts displayed in the reddish area")) + #create Elements + xml_no_pref_1 = etree.Element("div") + xml_no_pref_1.set('class','oe_inline oe_lunch_intro') + xml_no_pref_2 = etree.Element("h3") + xml_no_pref_2.text = _("This is the first time you order a meal") + xml_no_pref_3 = etree.Element("p") + xml_no_pref_3.set('class','oe_grey') + xml_no_pref_3.text = _("Select a product and put your order comments on the note.") + xml_no_pref_4 = etree.Element("p") + xml_no_pref_4.set('class','oe_grey') + xml_no_pref_4.text = _("Your favorite meals will be created based on your last orders.") + xml_no_pref_5 = etree.Element("p") + xml_no_pref_5.set('class','oe_grey') + xml_no_pref_5.text = _("Don't forget the alerts displayed in the reddish area") + #structure Elements + xml_start.append(xml_no_pref_1) + xml_no_pref_1.append(xml_no_pref_2) + xml_no_pref_1.append(xml_no_pref_3) + xml_no_pref_1.append(xml_no_pref_4) + xml_no_pref_1.append(xml_no_pref_5) + #Else : the user already have preferences so we display them else: - preferences = line_ref.browse(cr,uid,pref_ids,context=context) + preferences = line_ref.browse(cr, uid, pref_ids,context=context) categories = {} #store the different categories of products in preference + count = 0 for pref in preferences: + #For each preference categories.setdefault(pref.product_id.category_id.name, {}) - if pref.product_id.id not in categories[pref.product_id.category_id.name]: - categories[pref.product_id.category_id.name][pref.product_id.id] = pref + #if this product has already been added to the categories dictionnary + if pref.product_id.id in categories[pref.product_id.category_id.name]: + #we check if for the same product the note has already been added + if pref.note not in categories[pref.product_id.category_id.name][pref.product_id.id]: + #if it's not the case then we add this to preferences + categories[pref.product_id.category_id.name][pref.product_id.id][pref.note] = pref + #if this product is not in the dictionnay, we add it + else: + categories[pref.product_id.category_id.name][pref.product_id.id] = {} + categories[pref.product_id.category_id.name][pref.product_id.id][pref.note] = pref currency = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id.currency_id + #For each preferences that we get, we will create the XML structure for key,value in categories.items(): - value = value.values() - text_xml+=""" -
-

%s

- """ % (key,) + xml_pref_1 = etree.Element("div") + xml_pref_1.set('class','oe_lunch_30pc') + xml_pref_2 = etree.Element("h2") + xml_pref_2.text = key + xml_pref_1.append(xml_pref_2) i = 0 + value = value.values() for val in value: - if i==5 : break - i+=1 - function_name = "add_preference_"+str(val.id) - text_xml+= ''' -
- - - -
-
- %s - %.2f %s -
-
-
- %s -
-
- ''' % (function_name, function_name,_("Add"), escape(val.product_id.name), val.product_id.price or 0.0, currency.name or '', escape(val.note or '')) - text_xml+= '''
''' - # ADD into ARCH xml - text_xml += "
" - doc = etree.XML(res['arch']) - node = doc.xpath("//div[@name='preferences']") - to_add = etree.fromstring(text_xml) - if node and len(node)>0: - node[0].append(to_add) + for pref in val.values(): + #We only show 5 preferences per category (or it will be too long) + if i==5: break + i+=1 + xml_pref_3 = etree.Element("div") + xml_pref_3.set('class','oe_lunch_vignette') + xml_pref_1.append(xml_pref_3) + + xml_pref_4 = etree.Element("span") + xml_pref_4.set('class','oe_lunch_button') + xml_pref_3.append(xml_pref_4) + + xml_pref_5 = etree.Element("button") + xml_pref_5.set('name',"add_preference_"+str(pref.id)) + xml_pref_5.set('class','oe_link oe_i oe_button_plus') + xml_pref_5.set('type','object') + xml_pref_5.set('string','+') + xml_pref_4.append(xml_pref_5) + + xml_pref_6 = etree.Element("button") + xml_pref_6.set('name',"add_preference_"+str(pref.id)) + xml_pref_6.set('class','oe_link oe_button_add') + xml_pref_6.set('type','object') + xml_pref_6.set('string',_("Add")) + xml_pref_4.append(xml_pref_6) + + xml_pref_7 = etree.Element("div") + xml_pref_7.set('class','oe_group_text_button') + xml_pref_3.append(xml_pref_7) + + xml_pref_8 = etree.Element("div") + xml_pref_8.set('class','oe_lunch_text') + xml_pref_8.text = escape(pref.product_id.name) + xml_pref_7.append(xml_pref_8) + + price = pref.product_id.price or 0.0 + cur = currency.name or '' + xml_pref_9 = etree.Element("span") + xml_pref_9.set('class','oe_tag') + xml_pref_9.text = str(price)+" "+cur + xml_pref_8.append(xml_pref_9) + + xml_pref_10 = etree.Element("div") + xml_pref_10.set('class','oe_grey') + xml_pref_10.text = escape(pref.note or '') + xml_pref_3.append(xml_pref_10) + + xml_start.append(xml_pref_1) + + first_node = doc.xpath("//div[@name='preferences']") + if first_node and len(first_node)>0: + first_node[0].append(xml_start) res['arch'] = etree.tostring(doc) return res _columns = { 'user_id' : fields.many2one('res.users','User Name',required=True,readonly=True, states={'new':[('readonly', False)]}), 'date': fields.date('Date', required=True,readonly=True, states={'new':[('readonly', False)]}), - 'order_line_ids' : fields.one2many('lunch.order.line','order_id','Products',ondelete="cascade",readonly=True,states={'new':[('readonly', False)]}), #TODO: a good naming convention is to finish your field names with `_ids´ for *2many fields. BTW, the field name should reflect more it's nature: `order_line_ids´ for example + 'order_line_ids' : fields.one2many('lunch.order.line','order_id','Products',ondelete="cascade",readonly=True,states={'new':[('readonly', False)]}), 'total' : fields.function(_price_get, string="Total",store={ 'lunch.order.line': (_compute_total, ['product_id','order_id'], 20), }), - 'state': fields.selection([('new', 'New'),('confirmed','Confirmed'), ('cancelled','Cancelled'), ('partially','Partially Confirmed')],'Status', readonly=True, select=True), #TODO: parcially? #TODO: the labels are confusing. confirmed=='received' or 'delivered'... + 'state': fields.selection([('new', 'New'), \ + ('confirmed','Confirmed'), \ + ('cancelled','Cancelled'), \ + ('partially','Partially Confirmed')] \ + ,'Status', readonly=True, select=True), 'alerts': fields.function(_alerts_get, string="Alerts", type='text'), } @@ -265,13 +315,13 @@ class lunch_order_line(osv.Model): _name = 'lunch.order.line' _description = 'lunch order line' - def onchange_price(self,cr,uid,ids,product_id,context=None): + def onchange_price(self, cr, uid, ids, product_id, context=None): if product_id: - price = self.pool.get('lunch.product').browse(cr, uid, product_id).price + price = self.pool.get('lunch.product').browse(cr, uid, product_id, context=context).price return {'value': {'price': price}} return {'value': {'price': 0.0}} - def order(self,cr,uid,ids,context=None): + def order(self, cr, uid, ids, context=None): """ The order_line is ordered to the supplier but isn't received yet """ @@ -279,12 +329,12 @@ class lunch_order_line(osv.Model): order_line.write({'state' : 'ordered'}) return self._update_order_lines(cr, uid, ids, context) - def confirm(self,cr,uid,ids,context=None): + def confirm(self, cr, uid, ids, context=None): """ confirm one or more order line, update order status and create new cashmove """ cashmove_ref = self.pool.get('lunch.cashmove') - for order_line in self.browse(cr,uid,ids,context=context): + for order_line in self.browse(cr, uid, ids, context=context): if order_line.state!='confirmed': values = { 'user_id' : order_line.user_id.id, @@ -296,7 +346,7 @@ class lunch_order_line(osv.Model): } cashmove_ref.create(cr, uid, values, context=context) order_line.write({'state' : 'confirmed'}) - return self._update_order_lines(cr, uid, ids, context) + return self._update_order_lines(cr, uid, ids, context=context) def _update_order_lines(self, cr, uid, ids, context=None): """ @@ -304,7 +354,7 @@ class lunch_order_line(osv.Model): """ orders_ref = self.pool.get('lunch.order') orders = [] - for order_line in self.browse(cr,uid,ids,context=context): + for order_line in self.browse(cr, uid, ids, context=context): orders.append(order_line.order_id) for order in set(orders): isconfirmed = True @@ -318,16 +368,16 @@ class lunch_order_line(osv.Model): order.write({'state':'confirmed'}) return {} - def cancel(self,cr,uid,ids,context=None): + def cancel(self, cr, uid, ids, context=None): """ confirm one or more order.line, update order status and create new cashmove """ cashmove_ref = self.pool.get('lunch.cashmove') - for order_line in self.browse(cr,uid,ids,context=context): + for order_line in self.browse(cr, uid, ids, context=context): order_line.write({'state':'cancelled'}) for cash in order_line.cashmove: - cashmove_ref.unlink(cr,uid,cash.id,context) - return self._update_order_lines(cr, uid, ids, context) + cashmove_ref.unlink(cr, uid, cash.id, context=context) + return self._update_order_lines(cr, uid, ids, context=context) _columns = { 'name' : fields.related('product_id','name',readonly=True), @@ -338,8 +388,11 @@ class lunch_order_line(osv.Model): 'user_id' : fields.related('order_id', 'user_id', type='many2one', relation='res.users', string='User', readonly=True, store=True), 'note' : fields.text('Note',size=256,required=False), 'price' : fields.float("Price"), - 'state': fields.selection([('new', 'New'),('confirmed','Received'), ('ordered','Ordered'), ('cancelled','Cancelled')], \ - 'Status', readonly=True, select=True), #new confirmed and cancelled are the convention + 'state': fields.selection([('new', 'New'), \ + ('confirmed','Received'), \ + ('ordered','Ordered'), \ + ('cancelled','Cancelled')], \ + 'Status', readonly=True, select=True), 'cashmove': fields.one2many('lunch.cashmove','order_id','Cash Move',ondelete='cascade'), } @@ -400,7 +453,10 @@ class lunch_alert(osv.Model): _description = 'lunch alert' _columns = { 'message' : fields.text('Message',size=256, required=True), - 'day' : fields.selection([('specific','Specific day'), ('week','Every Week'), ('days','Every Day')], string='Recurrency', required=True,select=True), + 'day' : fields.selection([('specific','Specific day'), \ + ('week','Every Week'), \ + ('days','Every Day')], \ + string='Recurrency', required=True,select=True), 'specific' : fields.date('Day'), 'monday' : fields.boolean('Monday'), 'tuesday' : fields.boolean('Tuesday'), From 276e70e3ba6cb90c19c03fa27786340db5dcce65 Mon Sep 17 00:00:00 2001 From: Arnaud Pineux Date: Mon, 5 Nov 2012 14:55:48 +0100 Subject: [PATCH 655/703] Lunch bzr revid: api@openerp.com-20121105135548-nfrnj63a01tz61y9 --- addons/lunch/tests/test_lunch.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/addons/lunch/tests/test_lunch.py b/addons/lunch/tests/test_lunch.py index d2bfb9eef0f..128e4796611 100644 --- a/addons/lunch/tests/test_lunch.py +++ b/addons/lunch/tests/test_lunch.py @@ -53,8 +53,7 @@ class Test_Lunch(common.TransactionCase): }) def test_00_lunch_order(self): - """Change the state of an order line from 'new' to 'ordered' - Check that there are no cashmove linked to that order line""" + """Change the state of an order line from 'new' to 'ordered'. Check that there are no cashmove linked to that order line""" cr, uid = self.cr, self.uid self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None) #we check that our order_line is a 'new' one and that there are no cashmove linked to that order_line: @@ -68,8 +67,7 @@ class Test_Lunch(common.TransactionCase): self.assertEqual(self.order_one.cashmove, []) def test_01_lunch_order(self): - """Change the state of an order line from 'new' to 'ordered' then to 'confirmed' - Check that there is a cashmove linked to the order line""" + """Change the state of an order line from 'new' to 'ordered' then to 'confirmed'. Check that there is a cashmove linked to the order line""" cr, uid = self.cr, self.uid self.test_00_lunch_order() #We receive the order so we confirm the order line so it's state will be 'confirmed' @@ -81,3 +79,14 @@ class Test_Lunch(common.TransactionCase): self.assertTrue(self.order_one.cashmove!=[]) self.assertTrue(self.order_one.cashmove[0].amount==-self.order_one.price) + def test_02_lunch_order(self): + """Change the state of an order line from 'confirmed' to 'cancelled' and check that the cashmove linked to that order line will be deleted""" + cr, uid = self.cr, self.uid + self.test_01_lunch_order() + #We have a confirmed order with its associate cashmove + #We execute the cancel function + self.order_one.cancel() + self.order_one = self.lunch_order_line.browse(cr,uid,self.new_id_order_line,context=None) + #We check that the state is cancelled and that the cashmove has been deleted + self.assertEqual(self.order_one.state,'cancelled') + self.assertTrue(self.order_one.cashmove==[]) \ No newline at end of file From 3d3873339e28bbd47caa855547db86c0c71d82b3 Mon Sep 17 00:00:00 2001 From: Arnaud Pineux Date: Mon, 5 Nov 2012 17:05:41 +0100 Subject: [PATCH 656/703] [Lunch] bzr revid: api@openerp.com-20121105160541-t8x8t7de2fjt0sq3 --- addons/lunch/lunch.py | 4 ++-- addons/lunch/static/src/css/lunch.css | 3 +++ addons/lunch/static/src/css/lunch.sass | 2 ++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index 5d44859fc77..c44e18fc023 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -262,14 +262,14 @@ class lunch_order(osv.Model): xml_pref_8 = etree.Element("div") xml_pref_8.set('class','oe_lunch_text') - xml_pref_8.text = escape(pref.product_id.name) + xml_pref_8.text = escape(pref.product_id.name)+str(" ") xml_pref_7.append(xml_pref_8) price = pref.product_id.price or 0.0 cur = currency.name or '' xml_pref_9 = etree.Element("span") xml_pref_9.set('class','oe_tag') - xml_pref_9.text = str(price)+" "+cur + xml_pref_9.text = str(price)+str(" ")+cur xml_pref_8.append(xml_pref_9) xml_pref_10 = etree.Element("div") diff --git a/addons/lunch/static/src/css/lunch.css b/addons/lunch/static/src/css/lunch.css index 151e2a1bdbc..96e39c53fa6 100644 --- a/addons/lunch/static/src/css/lunch.css +++ b/addons/lunch/static/src/css/lunch.css @@ -35,6 +35,9 @@ padding-top: 5px; padding-bottom: 5px; } +.openerp .oe_lunch .oe_lunch_vignette:last-child { + border: none; +} .openerp .oe_lunch .oe_group_text_button { margin-bottom: 3px; } diff --git a/addons/lunch/static/src/css/lunch.sass b/addons/lunch/static/src/css/lunch.sass index 4d27c026ec8..9612b5fdd3d 100644 --- a/addons/lunch/static/src/css/lunch.sass +++ b/addons/lunch/static/src/css/lunch.sass @@ -30,5 +30,7 @@ border-bottom: 1px solid #dddddd padding-top: 5px padding-bottom: 5px + .oe_lunch_vignette:last-child + border: none .oe_group_text_button margin-bottom: 3px From 88772682abae69ce82b6eeef271424795848e09a Mon Sep 17 00:00:00 2001 From: Arnaud Pineux Date: Mon, 5 Nov 2012 17:25:39 +0100 Subject: [PATCH 657/703] [Lunch] bzr revid: api@openerp.com-20121105162539-vramkfv3hq68tudk --- addons/lunch/lunch_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/lunch/lunch_view.xml b/addons/lunch/lunch_view.xml index 3cdab20cb9c..2512cfd6757 100644 --- a/addons/lunch/lunch_view.xml +++ b/addons/lunch/lunch_view.xml @@ -342,7 +342,7 @@ - +
From 3440046852430f21c0aea89b2da3f532e31f059d Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Mon, 5 Nov 2012 19:18:14 +0100 Subject: [PATCH 658/703] [REF] lunch: code cleaning/refactoring made during code review bzr revid: qdp-launchpad@openerp.com-20121105181814-s1kn2bkt9pxoildx --- addons/lunch/lunch.py | 147 ++++++++++++++++++------------------ addons/lunch/lunch_view.xml | 8 +- 2 files changed, 76 insertions(+), 79 deletions(-) diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index c44e18fc023..410221a4adb 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -1,4 +1,3 @@ - # -*- encoding: utf-8 -*- ############################################################################## # @@ -24,7 +23,7 @@ from xml.sax.saxutils import escape import pytz import time from osv import osv, fields -from datetime import datetime, timedelta +from datetime import datetime from lxml import etree from tools.translate import _ @@ -79,12 +78,11 @@ class lunch_order(osv.Model): """ get the alerts to display on the order form """ - orders = self.browse(cr, uid, ids, context=context) - result={} - alert_msg= self._default_alerts_get(cr, uid, arg, context=context) - for order in orders: - if order.state=='new': - result[order.id]=alert_msg + result = {} + alert_msg = self._default_alerts_get(cr, uid, arg, context=context) + for order in self.browse(cr, uid, ids, context=context): + if order.state == 'new': + result[order.id] = alert_msg return result def check_day(self, alert): @@ -103,13 +101,12 @@ class lunch_order(osv.Model): """ This method check if the alert can be displayed today """ - if alert.day=='specific': - #the alert is only activated a specific day - return alert.specific==fields.datetime.now()[:10] - elif alert.day=='week': + if alert.alter_type == 'specific': + #the alert is only activated on a specific day + return alert.specific == fields.datetime.now()[:10] + elif alert.alter_type == 'week': #the alert is activated during some days of the week return self.check_day(alert) - return True # code to improve def _default_alerts_get(self, cr, uid, arg, context=None): @@ -138,11 +135,11 @@ class lunch_order(osv.Model): return '\n'.join(alert_msg) def onchange_price(self, cr, uid, ids, order_line_ids, context=None): - """ + """ Onchange methode that refresh the total price of order """ - res = {'value':{'total':0.0}} - order_line_ids= self.resolve_o2m_commands_to_record_dicts(cr, uid, "order_line_ids", order_line_ids, ["price"], context=context) + res = {'value': {'total': 0.0}} + order_line_ids = self.resolve_o2m_commands_to_record_dicts(cr, uid, "order_line_ids", order_line_ids, ["price"], context=context) if order_line_ids: tot = 0.0 product_ref = self.pool.get("lunch.product") @@ -151,7 +148,7 @@ class lunch_order(osv.Model): tot += product_ref.browse(cr, uid, prod['product_id'], context=context).price else: tot += prod['price'] - res = {'value':{'total':tot}} + res = {'value': {'total': tot}} return res def __getattr__(self, attr): @@ -199,7 +196,7 @@ class lunch_order(osv.Model): xml_no_pref_1.append(xml_no_pref_3) xml_no_pref_1.append(xml_no_pref_4) xml_no_pref_1.append(xml_no_pref_5) - #Else : the user already have preferences so we display them + #Else: the user already have preferences so we display them else: preferences = line_ref.browse(cr, uid, pref_ids,context=context) categories = {} #store the different categories of products in preference @@ -286,10 +283,10 @@ class lunch_order(osv.Model): return res _columns = { - 'user_id' : fields.many2one('res.users','User Name',required=True,readonly=True, states={'new':[('readonly', False)]}), - 'date': fields.date('Date', required=True,readonly=True, states={'new':[('readonly', False)]}), - 'order_line_ids' : fields.one2many('lunch.order.line','order_id','Products',ondelete="cascade",readonly=True,states={'new':[('readonly', False)]}), - 'total' : fields.function(_price_get, string="Total",store={ + 'user_id': fields.many2one('res.users', 'User Name', required=True, readonly=True, states={'new':[('readonly', False)]}), + 'date': fields.date('Date', required=True, readonly=True, states={'new':[('readonly', False)]}), + 'order_line_ids': fields.one2many('lunch.order.line', 'order_id', 'Products', ondelete="cascade", readonly=True, states={'new':[('readonly', False)]}), + 'total': fields.function(_price_get, string="Total", store={ 'lunch.order.line': (_compute_total, ['product_id','order_id'], 20), }), 'state': fields.selection([('new', 'New'), \ @@ -310,7 +307,7 @@ class lunch_order(osv.Model): class lunch_order_line(osv.Model): """ - lunch order line : one lunch order can have many order lines + lunch order line: one lunch order can have many order lines """ _name = 'lunch.order.line' _description = 'lunch order line' @@ -326,8 +323,8 @@ class lunch_order_line(osv.Model): The order_line is ordered to the supplier but isn't received yet """ for order_line in self.browse(cr, uid, ids, context=context): - order_line.write({'state' : 'ordered'}) - return self._update_order_lines(cr, uid, ids, context) + order_line.write({'state': 'ordered'}, context=context) + return self._update_order_lines(cr, uid, ids, context=context) def confirm(self, cr, uid, ids, context=None): """ @@ -337,15 +334,15 @@ class lunch_order_line(osv.Model): for order_line in self.browse(cr, uid, ids, context=context): if order_line.state!='confirmed': values = { - 'user_id' : order_line.user_id.id, - 'amount' : -order_line.price, + 'user_id': order_line.user_id.id, + 'amount': -order_line.price, 'description': order_line.product_id.name, - 'order_id' : order_line.id, - 'state' : 'order', + 'order_id': order_line.id, + 'state': 'order', 'date': order_line.date, } cashmove_ref.create(cr, uid, values, context=context) - order_line.write({'state' : 'confirmed'}) + order_line.write({'state': 'confirmed'}, context=context) return self._update_order_lines(cr, uid, ids, context=context) def _update_order_lines(self, cr, uid, ids, context=None): @@ -374,27 +371,27 @@ class lunch_order_line(osv.Model): """ cashmove_ref = self.pool.get('lunch.cashmove') for order_line in self.browse(cr, uid, ids, context=context): - order_line.write({'state':'cancelled'}) + order_line.write({'state':'cancelled'}, context=context) for cash in order_line.cashmove: cashmove_ref.unlink(cr, uid, cash.id, context=context) return self._update_order_lines(cr, uid, ids, context=context) _columns = { - 'name' : fields.related('product_id','name',readonly=True), - 'order_id' : fields.many2one('lunch.order','Order',ondelete='cascade'), - 'product_id' : fields.many2one('lunch.product','Product',required=True), - 'date' : fields.related('order_id','date',type='date', string="Date", readonly=True,store=True), - 'supplier' : fields.related('product_id','supplier',type='many2one',relation='res.partner',string="Supplier",readonly=True,store=True), - 'user_id' : fields.related('order_id', 'user_id', type='many2one', relation='res.users', string='User', readonly=True, store=True), - 'note' : fields.text('Note',size=256,required=False), - 'price' : fields.float("Price"), + 'name': fields.related('product_id', 'name', readonly=True), + 'order_id': fields.many2one('lunch.order', 'Order', ondelete='cascade'), + 'product_id': fields.many2one('lunch.product', 'Product', required=True), + 'date': fields.related('order_id', 'date', type='date', string="Date", readonly=True, store=True), + 'supplier': fields.related('product_id', 'supplier', type='many2one', relation='res.partner', string="Supplier", readonly=True, store=True), + 'user_id': fields.related('order_id', 'user_id', type='many2one', relation='res.users', string='User', readonly=True, store=True), + 'note': fields.text('Note'), + 'price': fields.float("Price"), 'state': fields.selection([('new', 'New'), \ - ('confirmed','Received'), \ - ('ordered','Ordered'), \ - ('cancelled','Cancelled')], \ + ('confirmed', 'Received'), \ + ('ordered', 'Ordered'), \ + ('cancelled', 'Cancelled')], \ 'Status', readonly=True, select=True), - 'cashmove': fields.one2many('lunch.cashmove','order_id','Cash Move',ondelete='cascade'), - + 'cashmove': fields.one2many('lunch.cashmove', 'order_id', 'Cash Move', ondelete='cascade'), + } _defaults = { 'state': 'new', @@ -408,11 +405,11 @@ class lunch_product(osv.Model): _name = 'lunch.product' _description = 'lunch product' _columns = { - 'name' : fields.char('Product',required=True, size=64), + 'name': fields.char('Product', required=True, size=64), 'category_id': fields.many2one('lunch.product.category', 'Category', required=True), - 'description': fields.text('Description', size=256, required=False), - 'price': fields.float('Price', digits=(16,2)), - 'supplier' : fields.many2one('res.partner', 'Supplier'), + 'description': fields.text('Description', size=256), + 'price': fields.float('Price', digits=(16,2)), #TODO: use decimal precision of 'Account', move it from product to decimal_precision + 'supplier': fields.many2one('res.partner', 'Supplier'), } class lunch_product_category(osv.Model): @@ -422,7 +419,7 @@ class lunch_product_category(osv.Model): _name = 'lunch.product.category' _description = 'lunch product category' _columns = { - 'name' : fields.char('Category', required=True), #such as PIZZA, SANDWICH, PASTA, CHINESE, BURGER, ... + 'name': fields.char('Category', required=True), #such as PIZZA, SANDWICH, PASTA, CHINESE, BURGER, ... } class lunch_cashmove(osv.Model): @@ -432,17 +429,17 @@ class lunch_cashmove(osv.Model): _name = 'lunch.cashmove' _description = 'lunch cashmove' _columns = { - 'user_id' : fields.many2one('res.users','User Name',required=True), - 'date' : fields.date('Date', required=True), - 'amount' : fields.float('Amount', required=True), #depending on the kind of cashmove, the amount will be positive or negative - 'description' : fields.text('Description'), #the description can be an order or a payment - 'order_id' : fields.many2one('lunch.order.line','Order',required=False,ondelete='cascade'), - 'state' : fields.selection([('order','Order'),('payment','Payment')],'Is an order or a Payment'), + 'user_id': fields.many2one('res.users', 'User Name', required=True), + 'date': fields.date('Date', required=True), + 'amount': fields.float('Amount', required=True), #depending on the kind of cashmove, the amount will be positive or negative + 'description': fields.text('Description'), #the description can be an order or a payment + 'order_id': fields.many2one('lunch.order.line', 'Order', ondelete='cascade'), + 'state': fields.selection([('order','Order'), ('payment','Payment')], 'Is an order or a Payment'), } _defaults = { 'user_id': lambda self, cr, uid, context: uid, 'date': fields.date.context_today, - 'state': lambda self, cr, uid, context: 'payment', + 'state': 'payment', } class lunch_alert(osv.Model): @@ -450,27 +447,27 @@ class lunch_alert(osv.Model): lunch alert """ _name = 'lunch.alert' - _description = 'lunch alert' + _description = 'Lunch Alert' _columns = { - 'message' : fields.text('Message',size=256, required=True), - 'day' : fields.selection([('specific','Specific day'), \ - ('week','Every Week'), \ - ('days','Every Day')], \ - string='Recurrency', required=True,select=True), - 'specific' : fields.date('Day'), - 'monday' : fields.boolean('Monday'), - 'tuesday' : fields.boolean('Tuesday'), - 'wednesday' : fields.boolean('Wednesday'), - 'thursday' : fields.boolean('Thursday'), - 'friday' : fields.boolean('Friday'), - 'saturday' : fields.boolean('Saturday'), - 'sunday' : fields.boolean('Sunday'), - 'active_from': fields.float('Between',required=True), - 'active_to': fields.float('And',required=True), + 'message': fields.text('Message', size=256, required=True), + 'alter_type': fields.selection([('specific', 'Specific Day'), \ + ('week', 'Every Week'), \ + ('days', 'Every Day')], \ + string='Recurrency', required=True, select=True), + 'specific': fields.date('Day'), + 'monday': fields.boolean('Monday'), + 'tuesday': fields.boolean('Tuesday'), + 'wednesday': fields.boolean('Wednesday'), + 'thursday': fields.boolean('Thursday'), + 'friday': fields.boolean('Friday'), + 'saturday': fields.boolean('Saturday'), + 'sunday': fields.boolean('Sunday'), + 'active_from': fields.float('Between', required=True), + 'active_to': fields.float('And', required=True), } _defaults = { - 'day': lambda self, cr, uid, context: 'specific', - 'specific': lambda self, cr, uid, context: time.strftime('%Y-%m-%d'), + 'alter_type': 'specific', + 'specific': fields.date.context_today, 'active_from': 7, 'active_to': 23, - } \ No newline at end of file + } diff --git a/addons/lunch/lunch_view.xml b/addons/lunch/lunch_view.xml index 2512cfd6757..a30da818c65 100644 --- a/addons/lunch/lunch_view.xml +++ b/addons/lunch/lunch_view.xml @@ -444,7 +444,7 @@ - + @@ -460,11 +460,11 @@ - - + + - + From df41b0ef2de67eb2934bada604f47d772769ae0b Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Tue, 6 Nov 2012 05:12:57 +0000 Subject: [PATCH 659/703] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20121106051257-ux0x5d6sa0vn0eha --- addons/web/i18n/zh_CN.po | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/addons/web/i18n/zh_CN.po b/addons/web/i18n/zh_CN.po index 69cd72339ae..d90ed916ffd 100644 --- a/addons/web/i18n/zh_CN.po +++ b/addons/web/i18n/zh_CN.po @@ -8,14 +8,14 @@ msgstr "" "Project-Id-Version: openerp-web\n" "Report-Msgid-Bugs-To: FULL NAME \n" "POT-Creation-Date: 2012-07-02 09:06+0200\n" -"PO-Revision-Date: 2012-02-17 07:29+0000\n" -"Last-Translator: Jeff Wang \n" +"PO-Revision-Date: 2012-11-06 04:40+0000\n" +"Last-Translator: Wei \"oldrev\" Li \n" "Language-Team: Chinese (Simplified) \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-21 05:03+0000\n" -"X-Generator: Launchpad (build 16165)\n" +"X-Launchpad-Export-Date: 2012-11-06 05:12+0000\n" +"X-Generator: Launchpad (build 16232)\n" #. openerp-web #: addons/web/static/src/js/chrome.js:176 @@ -129,56 +129,56 @@ msgstr "OpenERP社区支持版" #. openerp-web #: addons/web/static/src/js/coresetup.js:619 msgid "less than a minute ago" -msgstr "" +msgstr "一分钟内" #. openerp-web #: addons/web/static/src/js/coresetup.js:620 msgid "about a minute ago" -msgstr "" +msgstr "大约一分钟" #. openerp-web #: addons/web/static/src/js/coresetup.js:621 #, python-format msgid "%d minutes ago" -msgstr "" +msgstr "%d 分钟之前" #. openerp-web #: addons/web/static/src/js/coresetup.js:622 msgid "about an hour ago" -msgstr "" +msgstr "大约一小时前" #. openerp-web #: addons/web/static/src/js/coresetup.js:623 #, python-format msgid "%d hours ago" -msgstr "" +msgstr "%d 小时前" #. openerp-web #: addons/web/static/src/js/coresetup.js:624 msgid "a day ago" -msgstr "" +msgstr "一天前" #. openerp-web #: addons/web/static/src/js/coresetup.js:625 #, python-format msgid "%d days ago" -msgstr "" +msgstr "%d 天前" #. openerp-web #: addons/web/static/src/js/coresetup.js:626 msgid "about a month ago" -msgstr "" +msgstr "大约一月前" #. openerp-web #: addons/web/static/src/js/coresetup.js:627 #, python-format msgid "%d months ago" -msgstr "" +msgstr "%d 月前" #. openerp-web #: addons/web/static/src/js/coresetup.js:628 msgid "about a year ago" -msgstr "" +msgstr "大约一年前" #. openerp-web #: addons/web/static/src/js/coresetup.js:629 @@ -247,13 +247,13 @@ msgstr "" #. openerp-web #: addons/web/static/src/js/data_import.js:386 msgid "*Required Fields are not selected :" -msgstr "" +msgstr "*没有选择必须的字段:" #. openerp-web #: addons/web/static/src/js/formats.js:139 #, python-format msgid "(%d records)" -msgstr "" +msgstr "(%d 条记录)" #. openerp-web #: addons/web/static/src/js/formats.js:325 From 27462480b2aabee79496a54a4efdf6095808f440 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 6 Nov 2012 09:19:04 +0100 Subject: [PATCH 660/703] [REF] lunch: code refactoring and improvements made during code review bzr revid: qdp-launchpad@openerp.com-20121106081904-07wdsbas8grh4tz8 --- addons/lunch/lunch.py | 62 +++++++++++++++++-------------------- addons/lunch/lunch_view.xml | 2 +- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index 410221a4adb..9ae44b9d152 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -20,11 +20,11 @@ ############################################################################## from xml.sax.saxutils import escape -import pytz import time from osv import osv, fields from datetime import datetime from lxml import etree +import tools from tools.translate import _ class lunch_order(osv.Model): @@ -44,9 +44,9 @@ class lunch_order(osv.Model): for order_line in order.order_line_ids) return result - def _compute_total(self, cr, uid, ids, name, context=None): + def _fetch_orders_from_lines(self, cr, uid, ids, name, context=None): """ - compute total + return the list of lunch orders to which belong the order lines `ids´ """ result = set() for order_line in self.browse(cr, uid, ids, context=context): @@ -72,7 +72,7 @@ class lunch_order(osv.Model): 'price': pref.product_id.price, 'supplier': pref.product_id.supplier.id } - return orderline_ref.create(cr, uid, new_order_line,context=context) + return orderline_ref.create(cr, uid, new_order_line, context=context) def _alerts_get(self, cr, uid, ids, name, arg, context=None): """ @@ -99,38 +99,34 @@ class lunch_order(osv.Model): def can_display_alert(self, alert): """ - This method check if the alert can be displayed today + This method check if the alert can be displayed today """ if alert.alter_type == 'specific': #the alert is only activated on a specific day - return alert.specific == fields.datetime.now()[:10] + return alert.specific_day == time.strftime(tools.DEFAULT_SERVER_DATE_FORMAT) elif alert.alter_type == 'week': #the alert is activated during some days of the week return self.check_day(alert) - # code to improve def _default_alerts_get(self, cr, uid, arg, context=None): """ - get the alerts to display on the order form + get the alerts to display on the order form """ alert_ref = self.pool.get('lunch.alert') - alert_ids = alert_ref.search(cr, uid, [], context=context) + alert_ids = alert_ref.search(cr, uid, [], context=context) alert_msg = [] for alert in alert_ref.browse(cr, uid, alert_ids, context=context): + #check if the address must be displayed today if self.can_display_alert(alert): - #the alert is executing from ... to ... - now = datetime.utcnow() - user = self.pool.get('res.users').browse(cr, uid, uid, context=context) - tz = pytz.timezone(user.tz) if user.tz else pytz.utc - tzoffset=tz.utcoffset(now) - mynow = now+tzoffset + #display the address only during its active time + mynow = fields.datetime.context_timestamp(cr, uid, datetime.datetime.now(), context=context) hour_to = int(alert.active_to) - min_to = int((alert.active_to-hour_to)*60) - to_alert = datetime.strptime(str(hour_to)+":"+str(min_to),"%H:%M") + min_to = int((alert.active_to - hour_to) * 60) + to_alert = datetime.strptime(str(hour_to) + ":" + str(min_to), "%H:%M") hour_from = int(alert.active_from) - min_from = int((alert.active_from-hour_from)*60) - from_alert = datetime.strptime(str(hour_from)+":"+str(min_from),"%H:%M") - if mynow.time()>=from_alert.time() and mynow.time()<=to_alert.time(): + min_from = int((alert.active_from - hour_from) * 60) + from_alert = datetime.strptime(str(hour_from) + ":" + str(min_from), "%H:%M") + if mynow.time() >= from_alert.time() and mynow.time() <= to_alert.time(): alert_msg.append(alert.message) return '\n'.join(alert_msg) @@ -153,7 +149,7 @@ class lunch_order(osv.Model): def __getattr__(self, attr): """ - this method catch unexisting method call and if starts with + this method catch unexisting method call and if it starts with add_preference_'n' we execute the add_preference method with 'n' as parameter """ @@ -172,7 +168,7 @@ class lunch_order(osv.Model): line_ref = self.pool.get("lunch.order.line") if view_type == 'form': doc = etree.XML(res['arch']) - pref_ids = line_ref.search(cr, uid, [('user_id','=',uid)], order='create_date desc', context=context) + pref_ids = line_ref.search(cr, uid, [('user_id', '=', uid)], order='create_date desc', context=context) xml_start = etree.Element("div") #If there are no preference (it's the first time for the user) if len(pref_ids)==0: @@ -198,7 +194,7 @@ class lunch_order(osv.Model): xml_no_pref_1.append(xml_no_pref_5) #Else: the user already have preferences so we display them else: - preferences = line_ref.browse(cr, uid, pref_ids,context=context) + preferences = line_ref.browse(cr, uid, pref_ids, context=context) categories = {} #store the different categories of products in preference count = 0 for pref in preferences: @@ -287,7 +283,7 @@ class lunch_order(osv.Model): 'date': fields.date('Date', required=True, readonly=True, states={'new':[('readonly', False)]}), 'order_line_ids': fields.one2many('lunch.order.line', 'order_id', 'Products', ondelete="cascade", readonly=True, states={'new':[('readonly', False)]}), 'total': fields.function(_price_get, string="Total", store={ - 'lunch.order.line': (_compute_total, ['product_id','order_id'], 20), + 'lunch.order.line': (_fetch_orders_from_lines, ['product_id','order_id'], 20), }), 'state': fields.selection([('new', 'New'), \ ('confirmed','Confirmed'), \ @@ -332,7 +328,7 @@ class lunch_order_line(osv.Model): """ cashmove_ref = self.pool.get('lunch.cashmove') for order_line in self.browse(cr, uid, ids, context=context): - if order_line.state!='confirmed': + if order_line.state != 'confirmed': values = { 'user_id': order_line.user_id.id, 'amount': -order_line.price, @@ -360,20 +356,20 @@ class lunch_order_line(osv.Model): isconfirmed = False if orderline.state == 'cancelled': isconfirmed = False - order.write({'state':'partially'}) + order_ref.write(cr, uid, [order.id], {'state': 'partially'}, context=context) if isconfirmed: - order.write({'state':'confirmed'}) + order_ref.write(cr, uid, [order.id], {'state': 'confirmed'}, context=context) return {} def cancel(self, cr, uid, ids, context=None): - """ - confirm one or more order.line, update order status and create new cashmove + """ + cancel one or more order.line, update order status and unlink existing cashmoves """ cashmove_ref = self.pool.get('lunch.cashmove') for order_line in self.browse(cr, uid, ids, context=context): order_line.write({'state':'cancelled'}, context=context) - for cash in order_line.cashmove: - cashmove_ref.unlink(cr, uid, cash.id, context=context) + cash_ids = [cash.id for cash in order_line.cashmove] + cashmove_ref.unlink(cr, uid, cash_ids, context=context) return self._update_order_lines(cr, uid, ids, context=context) _columns = { @@ -454,7 +450,7 @@ class lunch_alert(osv.Model): ('week', 'Every Week'), \ ('days', 'Every Day')], \ string='Recurrency', required=True, select=True), - 'specific': fields.date('Day'), + 'specific_day': fields.date('Day'), 'monday': fields.boolean('Monday'), 'tuesday': fields.boolean('Tuesday'), 'wednesday': fields.boolean('Wednesday'), @@ -467,7 +463,7 @@ class lunch_alert(osv.Model): } _defaults = { 'alter_type': 'specific', - 'specific': fields.date.context_today, + 'specific_day': fields.date.context_today, 'active_from': 7, 'active_to': 23, } diff --git a/addons/lunch/lunch_view.xml b/addons/lunch/lunch_view.xml index a30da818c65..9f816d06b11 100644 --- a/addons/lunch/lunch_view.xml +++ b/addons/lunch/lunch_view.xml @@ -461,7 +461,7 @@ - + From ee11122aeb4d2af8861c9a5f2232b0ac208f6115 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 6 Nov 2012 09:20:47 +0100 Subject: [PATCH 661/703] [FIX] lunch: fixed bug introduced during code review, in previous revision bzr revid: qdp-launchpad@openerp.com-20121106082047-ob2e8k26dp0xthdi --- addons/lunch/lunch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index 9ae44b9d152..ffc3e3e8da1 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -119,7 +119,7 @@ class lunch_order(osv.Model): #check if the address must be displayed today if self.can_display_alert(alert): #display the address only during its active time - mynow = fields.datetime.context_timestamp(cr, uid, datetime.datetime.now(), context=context) + mynow = fields.datetime.context_timestamp(cr, uid, datetime.now(), context=context) hour_to = int(alert.active_to) min_to = int((alert.active_to - hour_to) * 60) to_alert = datetime.strptime(str(hour_to) + ":" + str(min_to), "%H:%M") From 7c11bb3d8e9cac1623aca3cfe408d1f4f71875f7 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 6 Nov 2012 09:26:33 +0100 Subject: [PATCH 662/703] [FIX] lunch: fixed bug introduced during code review, in previous revision bzr revid: qdp-launchpad@openerp.com-20121106082633-5sysljeo47opkshj --- addons/lunch/lunch.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index ffc3e3e8da1..496cbcdb8dc 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -356,9 +356,9 @@ class lunch_order_line(osv.Model): isconfirmed = False if orderline.state == 'cancelled': isconfirmed = False - order_ref.write(cr, uid, [order.id], {'state': 'partially'}, context=context) + orders_ref.write(cr, uid, [order.id], {'state': 'partially'}, context=context) if isconfirmed: - order_ref.write(cr, uid, [order.id], {'state': 'confirmed'}, context=context) + orders_ref.write(cr, uid, [order.id], {'state': 'confirmed'}, context=context) return {} def cancel(self, cr, uid, ids, context=None): From 18f885b10fbf3c77cd833ca55bb53ac2ba83e988 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 09:42:06 +0100 Subject: [PATCH 663/703] [FIX] recursive conversion of o2ms in import added new test cases from gkr bzr revid: xmo@openerp.com-20121106084206-1cckepflh9h4g1yv --- openerp/addons/base/ir/ir_fields.py | 68 ++++++++++++++++++- openerp/osv/orm.py | 35 +++------- openerp/tests/addons/test_impex/models.py | 9 +++ .../addons/test_impex/tests/contacts.json | 1 + .../addons/test_impex/tests/test_load.py | 47 ++++++++++++- 5 files changed, 129 insertions(+), 31 deletions(-) create mode 100644 openerp/tests/addons/test_impex/tests/contacts.json diff --git a/openerp/addons/base/ir/ir_fields.py b/openerp/addons/base/ir/ir_fields.py index 94a0be9e86c..105176bbd9c 100644 --- a/openerp/addons/base/ir/ir_fields.py +++ b/openerp/addons/base/ir/ir_fields.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +import collections import datetime import functools import operator @@ -31,9 +32,70 @@ REPLACE_WITH = lambda ids: (6, False, ids) class ConversionNotFound(ValueError): pass +class ColumnWrapper(object): + def __init__(self, column, cr, uid, pool, fromtype, context=None): + self._converter = None + self._column = column + if column._obj: + self._pool = pool + self._converter_args = { + 'cr': cr, + 'uid': uid, + 'model': pool[column._obj], + 'fromtype': fromtype, + 'context': context + } + @property + def converter(self): + if not self._converter: + self._converter = self._pool['ir.fields.converter'].for_model( + **self._converter_args) + return self._converter + + def __getattr__(self, item): + return getattr(self._column, item) + class ir_fields_converter(orm.Model): _name = 'ir.fields.converter' + def for_model(self, cr, uid, model, fromtype=str, context=None): + """ Returns a converter object for the model. A converter is a + callable taking a record-ish (a dictionary representing an openerp + record with values of typetag ``fromtype``) and returning a converted + records matching what :meth:`openerp.osv.orm.Model.write` expects. + + :param model: :class:`openerp.osv.orm.Model` for the conversion base + :returns: a converter callable + :rtype: (record: dict, logger: (field, error) -> None) -> dict + """ + columns = dict( + (k, ColumnWrapper(v.column, cr, uid, self.pool, fromtype, context)) + for k, v in model._all_columns.iteritems()) + converters = dict( + (k, self.to_field(cr, uid, model, column, fromtype, context)) + for k, column in columns.iteritems()) + + def fn(record, log): + converted = {} + for field, value in record.iteritems(): + if field in (None, 'id', '.id'): continue + if not value: + converted[field] = False + continue + try: + converted[field], ws = converters[field](value) + for w in ws: + if isinstance(w, basestring): + # wrap warning string in an ImportWarning for + # uniform handling + w = ImportWarning(w) + log(field, w) + except ValueError, e: + log(field, e) + + return converted + return fn + def to_field(self, cr, uid, model, column, fromtype=str, context=None): """ Fetches a converter for the provided column object, from the specified type. @@ -343,6 +405,10 @@ class ir_fields_converter(orm.Model): # [{subfield:ref1},{subfield:ref2},{subfield:ref3}] records = ({subfield:item} for item in record[subfield].split(',')) + def log(_, e): + if not isinstance(e, Warning): + raise e + warnings.append(e) for record in records: id = None refs = only_ref_fields(record) @@ -355,7 +421,7 @@ class ir_fields_converter(orm.Model): cr, uid, model, column, subfield, reference, context=context) warnings.extend(w2) - writable = exclude_ref_fields(record) + writable = column.converter(exclude_ref_fields(record), log) if id: commands.append(LINK_TO(id)) commands.append(UPDATE(id, writable)) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index a866b843582..910e08b3a69 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -1460,15 +1460,16 @@ class BaseModel(object): field_names = dict( (f, (Translation._get_source(cr, uid, self._name + ',' + f, 'field', context.get('lang')) - or column.string or f)) + or column.string)) for f, column in columns.iteritems()) - converters = dict( - (k, Converter.to_field(cr, uid, self, column, context=context)) - for k, column in columns.iteritems()) + + convert = Converter.for_model(cr, uid, self, context=context) def _log(base, field, exception): type = 'warning' if isinstance(exception, Warning) else 'error' - record = dict(base, field=field, type=type, + # logs the logical (not human-readable) field name for automated + # processing of response, but injects human readable in message + record = dict(base, type=type, field=field, message=unicode(exception.args[0]) % base) if len(exception.args) > 1 and exception.args[1]: record.update(exception.args[1]) @@ -1478,7 +1479,6 @@ class BaseModel(object): for record, extras in stream: dbid = False xid = False - converted = {} # name_get/name_create if None in record: pass # xid @@ -1499,27 +1499,8 @@ class BaseModel(object): message=_(u"Unknown database identifier '%s'") % dbid)) dbid = False - for field, strvalue in record.iteritems(): - if field in (None, 'id', '.id'): continue - if not strvalue: - converted[field] = False - continue - - # In warnings and error messages, use translated string as - # field name - message_base = dict( - extras, record=stream.index, field=field_names[field]) - try: - converted[field], ws = converters[field](strvalue) - - for w in ws: - if isinstance(w, basestring): - # wrap warning string in an ImportWarning for - # uniform handling - w = ImportWarning(w) - _log(message_base, field, w) - except ValueError, e: - _log(message_base, field, e) + converted = convert(record, lambda field, err:\ + _log(dict(extras, record=stream.index, field=field_names[field]), field, err)) yield dbid, xid, converted, dict(extras, record=stream.index) diff --git a/openerp/tests/addons/test_impex/models.py b/openerp/tests/addons/test_impex/models.py index 48bd9948a0f..95a7f90bda8 100644 --- a/openerp/tests/addons/test_impex/models.py +++ b/openerp/tests/addons/test_impex/models.py @@ -79,6 +79,7 @@ class One2ManyMultiple(orm.Model): _name = 'export.one2many.multiple' _columns = { + 'parent_id': fields.many2one('export.one2many.recursive'), 'const': fields.integer(), 'child1': fields.one2many('export.one2many.child.1', 'parent_id'), 'child2': fields.one2many('export.one2many.child.2', 'parent_id'), @@ -135,3 +136,11 @@ class SelectionWithDefault(orm.Model): 'const': 4, 'value': 2, } + +class RecO2M(orm.Model): + _name = 'export.one2many.recursive' + + _columns = { + 'value': fields.integer(), + 'child': fields.one2many('export.one2many.multiple', 'parent_id') + } diff --git a/openerp/tests/addons/test_impex/tests/contacts.json b/openerp/tests/addons/test_impex/tests/contacts.json new file mode 100644 index 00000000000..f9f185c141f --- /dev/null +++ b/openerp/tests/addons/test_impex/tests/contacts.json @@ -0,0 +1 @@ +[["Wood y Wood Pecker", "", "Snow Street, 25", "Kainuu", "Finland", "Supplier", "1", "0", "1", ""], ["Roger Pecker", "Default", "Snow Street, 27", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Sharon Pecker", "Shipping", "Snow Street, 28", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Thomas Pecker", "Contact", "Snow Street, 27", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Vicking Direct", "", "Atonium Street, 45a", "Brussels", "Belgium", "Supplier", "1", "0", "1", ""], ["Yvan Holiday", "Invoice", "Atonium Street, 45b", "Brussels", "Belgium", "Supplier", "1", "0", "0", "Vicking Direct"], ["Jack Unsworth", "Contact", "Atonium Street, 45a", "Brussels", "Belgium", "Supplier", "1", "0", "0", "Vicking Direct"]] diff --git a/openerp/tests/addons/test_impex/tests/test_load.py b/openerp/tests/addons/test_impex/tests/test_load.py index 8dac916b0d0..9ef2a43dec9 100644 --- a/openerp/tests/addons/test_impex/tests/test_load.py +++ b/openerp/tests/addons/test_impex/tests/test_load.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import json import pkgutil +import unittest2 import openerp.modules.registry import openerp @@ -246,7 +247,7 @@ class test_integer_field(ImporterCase): -1, -42, -(2**31 - 1), -(2**31), -12345678 ], values(self.read())) - @mute_logger('openerp.sql_db') + @mute_logger('openerp.sql_db', 'openerp.osv.orm') def test_out_of_range(self): result = self.import_(['value'], [[str(2**31)]]) self.assertIs(result['ids'], False) @@ -388,14 +389,14 @@ class test_unbound_string_field(ImporterCase): class test_required_string_field(ImporterCase): model_name = 'export.string.required' - @mute_logger('openerp.sql_db') + @mute_logger('openerp.sql_db', 'openerp.osv.orm') def test_empty(self): result = self.import_(['value'], [[]]) self.assertEqual(result['messages'], [message( u"Missing required value for the field 'unknown'")]) self.assertIs(result['ids'], False) - @mute_logger('openerp.sql_db') + @mute_logger('openerp.sql_db', 'openerp.osv.orm') def test_not_provided(self): result = self.import_(['const'], [['12']]) self.assertEqual(result['messages'], [message( @@ -1007,6 +1008,46 @@ class test_realworld(common.TransactionCase): self.assertFalse(result['messages']) self.assertEqual(len(result['ids']), len(data)) + def test_backlink(self): + data = json.loads(pkgutil.get_data(self.__module__, 'contacts.json')) + result = self.registry('res.partner').load( + self.cr, openerp.SUPERUSER_ID, + ["name", "type", "street", "city", "country_id", "category_id", + "supplier", "customer", "is_company", "parent_id"], + data) + self.assertFalse(result['messages']) + self.assertEqual(len(result['ids']), len(data)) + + def test_recursive_o2m(self): + """ The content of the o2m field's dict needs to go through conversion + as it may be composed of convertables or other relational fields + """ + self.registry('ir.model.data').clear_caches() + Model = self.registry('export.one2many.recursive') + result = Model.load(self.cr, openerp.SUPERUSER_ID, + ['value', 'child/const', 'child/child1/str', 'child/child2/value'], + [ + ['4', '42', 'foo', '55'], + ['', '43', 'bar', '56'], + ['', '', 'baz', ''], + ['', '55', 'qux', '57'], + ['5', '99', 'wheee', ''], + ['', '98', '', '12'], + ], + context=None) + + self.assertFalse(result['messages']) + self.assertEqual(len(result['ids']), 2) + + b = Model.browse(self.cr, openerp.SUPERUSER_ID, result['ids'], context=None) + self.assertEqual((b[0].value, b[1].value), (4, 5)) + + self.assertEqual([child.str for child in b[0].child[1].child1], + ['bar', 'baz']) + self.assertFalse(len(b[1].child[1].child1)) + self.assertEqual([child.value for child in b[1].child[1].child2], + [12]) + class test_date(ImporterCase): model_name = 'export.date' From 53cae5dccb6103e7f3f025c792519069480f0de7 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 6 Nov 2012 09:43:21 +0100 Subject: [PATCH 664/703] [IMP] lunch: usability bzr revid: qdp-launchpad@openerp.com-20121106084321-04w7l72f8ocoeubw --- addons/lunch/lunch_view.xml | 35 ++++++++++++----------------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/addons/lunch/lunch_view.xml b/addons/lunch/lunch_view.xml index 9f816d06b11..31540c63e14 100644 --- a/addons/lunch/lunch_view.xml +++ b/addons/lunch/lunch_view.xml @@ -8,35 +8,24 @@ - - + + Search lunch.order.line search - - + - - - - - - - - lunch order list - lunch.order.line - - - - - - - - + + + + + + + @@ -143,7 +132,7 @@ Orders by Supplier lunch.order.line tree - + {"search_default_group_by_supplier":1, "search_default_today":1}

@@ -163,7 +152,7 @@ Control Suppliers lunch.order.line tree - + {"search_default_group_by_date":1, "search_default_group_by_supplier":1}

From aabb0f38fa51ccde3e60ab1517e1b21eecf511ab Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 09:43:53 +0100 Subject: [PATCH 665/703] [FIX] base_import: only allow reloading the current file if there *is* a current file loaded bzr revid: xmo@openerp.com-20121106084353-npwkbkg6r0wkwdrg --- addons/base_import/static/src/js/import.js | 10 +++++++--- addons/base_import/static/src/xml/import.xml | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/addons/base_import/static/src/js/import.js b/addons/base_import/static/src/js/import.js index 510afaaead8..1f11b3c1e86 100644 --- a/addons/base_import/static/src/js/import.js +++ b/addons/base_import/static/src/js/import.js @@ -179,7 +179,8 @@ openerp.base_import = function (instance) { //- File & settings change section onfile_loaded: function () { - this.$('.oe_import_button').prop('disabled', true); + this.$('.oe_import_button, .oe_import_file_reload') + .prop('disabled', true); if (!this.$('input.oe_import_file').val()) { return; } this.$el.removeClass('oe_import_preview oe_import_error'); @@ -189,7 +190,8 @@ openerp.base_import = function (instance) { }, onpreviewing: function () { var self = this; - this.$('.oe_import_button').prop('disabled', true); + this.$('.oe_import_button, .oe_import_file_reload') + .prop('disabled', true); this.$el.addClass('oe_import_with_file'); // TODO: test that write // succeeded? this.$el.removeClass('oe_import_preview_error oe_import_error'); @@ -205,6 +207,7 @@ openerp.base_import = function (instance) { }, onpreview_error: function (event, from, to, result) { this.$('.oe_import_options').show(); + this.$('.oe_import_file_reload').prop('disabled', false); this.$el.addClass('oe_import_preview_error oe_import_error'); this.$('.oe_import_error_report').html( QWeb.render('ImportView.preview.error', result)); @@ -212,7 +215,8 @@ openerp.base_import = function (instance) { 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.$('.oe_import_button, .oe_import_file_reload') + .prop('disabled', false); this.$el.addClass('oe_import_preview'); this.$('table').html(QWeb.render('ImportView.preview', result)); diff --git a/addons/base_import/static/src/xml/import.xml b/addons/base_import/static/src/xml/import.xml index a121c15f8c8..0da75eb69b9 100644 --- a/addons/base_import/static/src/xml/import.xml +++ b/addons/base_import/static/src/xml/import.xml @@ -30,7 +30,9 @@ -

From 0f062a4fe88375379bc4b7c640a976f00175f566 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 6 Nov 2012 09:52:41 +0100 Subject: [PATCH 666/703] [FIX] lunch: extra argument removed in _default method bzr revid: qdp-launchpad@openerp.com-20121106085241-vfo8mhmf20chwil8 --- addons/lunch/lunch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index 496cbcdb8dc..6aef154ad0a 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -108,7 +108,7 @@ class lunch_order(osv.Model): #the alert is activated during some days of the week return self.check_day(alert) - def _default_alerts_get(self, cr, uid, arg, context=None): + def _default_alerts_get(self, cr, uid, context=None): """ get the alerts to display on the order form """ From f5fc4532f2f3c6193913b5845fe2760cececa207 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 6 Nov 2012 10:03:00 +0100 Subject: [PATCH 667/703] [IMP] lunch: code review. usability / fixes bzr revid: qdp-launchpad@openerp.com-20121106090300-bk9up9ugprfcyqn4 --- addons/lunch/lunch.py | 2 +- addons/lunch/lunch_view.xml | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/addons/lunch/lunch.py b/addons/lunch/lunch.py index 6aef154ad0a..0d224ef3a8e 100644 --- a/addons/lunch/lunch.py +++ b/addons/lunch/lunch.py @@ -79,7 +79,7 @@ class lunch_order(osv.Model): get the alerts to display on the order form """ result = {} - alert_msg = self._default_alerts_get(cr, uid, arg, context=context) + alert_msg = self._default_alerts_get(cr, uid, context=context) for order in self.browse(cr, uid, ids, context=context): if order.state == 'new': result[order.id] = alert_msg diff --git a/addons/lunch/lunch_view.xml b/addons/lunch/lunch_view.xml index 31540c63e14..32b978dfab0 100644 --- a/addons/lunch/lunch_view.xml +++ b/addons/lunch/lunch_view.xml @@ -37,9 +37,10 @@ search - + + @@ -51,9 +52,11 @@ search - - + + + + @@ -86,11 +89,11 @@ - Your Order + New Order lunch.order form - + Your Orders From addbb40195fc7b8fb712df21354c593a6541d72a Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 6 Nov 2012 10:08:25 +0100 Subject: [PATCH 668/703] [IMP] lunch: demo data bzr revid: qdp-launchpad@openerp.com-20121106090825-ebpcmfc8cpl0gkbn --- addons/lunch/lunch_demo.xml | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/lunch/lunch_demo.xml b/addons/lunch/lunch_demo.xml index 3caa0d1b81e..dedd6af8fed 100644 --- a/addons/lunch/lunch_demo.xml +++ b/addons/lunch/lunch_demo.xml @@ -173,8 +173,6 @@ Lunch must be ordered before 10h30 am days - 0 - 0 From 9037ca44802a75353c1a4a4bf63b91e060ea9c23 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 10:32:37 +0100 Subject: [PATCH 669/703] [FIX] test data: duplicating existing demo data crimps my style bzr revid: xmo@openerp.com-20121106093237-vsbo2l5pjup42frp --- openerp/tests/addons/test_impex/tests/contacts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/tests/addons/test_impex/tests/contacts.json b/openerp/tests/addons/test_impex/tests/contacts.json index f9f185c141f..4f065037188 100644 --- a/openerp/tests/addons/test_impex/tests/contacts.json +++ b/openerp/tests/addons/test_impex/tests/contacts.json @@ -1 +1 @@ -[["Wood y Wood Pecker", "", "Snow Street, 25", "Kainuu", "Finland", "Supplier", "1", "0", "1", ""], ["Roger Pecker", "Default", "Snow Street, 27", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Sharon Pecker", "Shipping", "Snow Street, 28", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Thomas Pecker", "Contact", "Snow Street, 27", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Vicking Direct", "", "Atonium Street, 45a", "Brussels", "Belgium", "Supplier", "1", "0", "1", ""], ["Yvan Holiday", "Invoice", "Atonium Street, 45b", "Brussels", "Belgium", "Supplier", "1", "0", "0", "Vicking Direct"], ["Jack Unsworth", "Contact", "Atonium Street, 45a", "Brussels", "Belgium", "Supplier", "1", "0", "0", "Vicking Direct"]] +[["Wood y Wood Pecker", "", "Snow Street, 25", "Kainuu", "Finland", "Supplier", "1", "0", "1", ""], ["Roger Pecker", "Default", "Snow Street, 27", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Sharon Pecker", "Shipping", "Snow Street, 28", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Thomas Pecker", "Contact", "Snow Street, 27", "Kainuu", "Finland", "Supplier", "1", "0", "0", "Wood y Wood Pecker"], ["Norseman Roundabout", "", "Atonium Street, 45a", "Brussels", "Belgium", "Supplier", "1", "0", "1", ""], ["Yvan Holiday", "Invoice", "Atonium Street, 45b", "Brussels", "Belgium", "Supplier", "1", "0", "0", "Norseman Roundabout"], ["Jack Unsworth", "Contact", "Atonium Street, 45a", "Brussels", "Belgium", "Supplier", "1", "0", "0", "Norseman Roundabout"]] From 63a89701122c0457d019848ba1564337b793a3b3 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Tue, 6 Nov 2012 10:56:19 +0100 Subject: [PATCH 670/703] [IMP] web: field many2many_tags_email moved to mail addon bzr revid: chm@openerp.com-20121106095619-bl7xg1bhubweetpo --- addons/mail/__openerp__.py | 1 + addons/mail/static/src/js/mail.js | 39 ++++++++++++++++++------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/addons/mail/__openerp__.py b/addons/mail/__openerp__.py index 0c32ba27d6f..9ad3232d396 100644 --- a/addons/mail/__openerp__.py +++ b/addons/mail/__openerp__.py @@ -89,6 +89,7 @@ Main Features 'static/lib/jquery.expander/jquery.expander.js', 'static/src/js/mail.js', 'static/src/js/mail_followers.js', + 'static/src/js/many2many_tags_email.js', ], 'qweb': [ 'static/src/xml/mail.xml', diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index 9133e5de257..60a55e79393 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -5,6 +5,7 @@ openerp.mail = function (session) { var mail = session.mail = {}; openerp_mail_followers(session, mail); // import mail_followers.js + openerp_FieldMany2ManyTagsEmail(session); // import manyy2many_tags_email.js /** * ------------------------------------------------------------ @@ -1628,7 +1629,24 @@ openerp.mail = function (session) { bind_events: function () { var self=this; - this.$(".oe_write_full").click(function(){ self.root.thread.compose_message.on_compose_fullmail(); }); + this.$(".oe_write_full").click(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: { + 'default_model': '', + 'default_res_id': false, + 'default_content_subtype': 'html', + }, + }; + session.client.action_manager.do_action(action); + }); this.$(".oe_write_onwall").click(function(){ self.root.thread.on_compose_message(); }); } }); @@ -1644,17 +1662,6 @@ openerp.mail = function (session) { 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_model': false, - 'default_res_id': 0, - 'default_content_subtype': 'html', - }; - }, - start: function (parent, params) { var self = this; this.$el.on('click', 'button', self.on_compose_message ); @@ -1671,11 +1678,11 @@ openerp.mail = function (session) { action_from: 'mail.ThreadComposeMessage', views: [[false, 'form']], target: 'new', - context: _.extend(this.options.context, { - 'default_model': this.context.default_model, - 'default_res_id': this.context.default_res_id, + context: { + 'default_model': '', + 'default_res_id': false, 'default_content_subtype': 'html', - }), + }, }; session.client.action_manager.do_action(action); }, From d3e5d953b1384e92e61fa51ad7b7a75d9c76c913 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Tue, 6 Nov 2012 10:57:00 +0100 Subject: [PATCH 671/703] [IMP] web: field many2many_tags_email moved to mail addon bzr revid: chm@openerp.com-20121106095700-q5gtxandi7o0jn6o --- addons/web/static/src/js/view_form.js | 35 --------------------------- 1 file changed, 35 deletions(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index e8d05296625..5ecad26e5df 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3955,40 +3955,6 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in }, }); - -/** - * Extend of FieldMany2ManyTags widget method. - * When the user add a partner and the partner don't have an email, open a popup to purpose to add an email. - * The user can choose to add an email or cancel and close the popup. - */ -instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags.extend({ - add_id: function(id) { - var self = this; - new instance.web.Model('res.partner').call("read", [id, ["email", "notification_email_send"]], {context: this.build_context()}) - .pipe(function (dict) { - if (!dict.email && (dict.notification_email_send == 'all' || dict.notification_email_send == 'comment')) { - var pop = new instance.web.form.FormOpenPopup(self); - pop.show_element( - 'res.partner', - dict.id, - self.build_context(), - { - title: _t("Please complete partner's informations and Email"), - } - ); - pop.on('write_completed', self, function () { - self._add_id(dict.id) - }); - } else { - self._add_id(dict.id); - } - }); - }, - _add_id: function (id) { - this.set({'value': _.uniq(this.get('value').concat([id]))}); - } -}); - /** widget options: - reload_on_button: Reload the whole form view if click on a button in a list view. @@ -5175,7 +5141,6 @@ instance.web.form.widgets = new instance.web.Registry({ 'many2one' : 'instance.web.form.FieldMany2One', 'many2many' : 'instance.web.form.FieldMany2Many', 'many2many_tags' : 'instance.web.form.FieldMany2ManyTags', - 'many2many_tags_email' : 'instance.web.form.FieldMany2ManyTagsEmail', 'many2many_kanban' : 'instance.web.form.FieldMany2ManyKanban', 'one2many' : 'instance.web.form.FieldOne2Many', 'one2many_list' : 'instance.web.form.FieldOne2Many', From 1795a342911991517e251ed94e8f3e620624558a Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Tue, 6 Nov 2012 13:37:59 +0100 Subject: [PATCH 672/703] [FIX] account_voucher: using pay invoice wizard on customer refund was creating wrong entries bzr revid: qdp-launchpad@openerp.com-20121106123759-rli58yp8lwyub59o --- addons/account_voucher/account_voucher.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/account_voucher/account_voucher.py b/addons/account_voucher/account_voucher.py index e1caf190316..8bd9a48b1f4 100644 --- a/addons/account_voucher/account_voucher.py +++ b/addons/account_voucher/account_voucher.py @@ -712,14 +712,14 @@ class account_voucher(osv.osv): 'move_line_id':line.id, 'account_id':line.account_id.id, 'amount_original': amount_original, - 'amount': (move_line_found == line.id) and min(price, amount_unreconciled) or 0.0, + 'amount': (move_line_found == line.id) and min(abs(price), amount_unreconciled) or 0.0, 'date_original':line.date, 'date_due':line.date_maturity, 'amount_unreconciled': amount_unreconciled, 'currency_id': line_currency_id, } - - #split voucher amount by most old first, but only for lines in the same currency + #in case a corresponding move_line hasn't been found, we now try to assign the voucher amount + #on existing invoices: we split voucher amount by most old first, but only for lines in the same currency if not move_line_found: if currency_id == line_currency_id: if line.credit: From 065600fe2527112894392a0da95a28560c2a5a07 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Tue, 6 Nov 2012 13:51:33 +0100 Subject: [PATCH 673/703] [IMP] web: FieldMany2ManyTagsEmail check id partner on change value. File inside mail addons folder bzr revid: chm@openerp.com-20121106125133-udq68eyek9fhsw83 --- .../static/src/js/many2many_tags_email.js | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 addons/mail/static/src/js/many2many_tags_email.js diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js new file mode 100644 index 00000000000..2e449bd410a --- /dev/null +++ b/addons/mail/static/src/js/many2many_tags_email.js @@ -0,0 +1,87 @@ +openerp_FieldMany2ManyTagsEmail = function(instance) { +var _t = instance.web._t; + +/** + * Extend of FieldMany2ManyTags widget method. + * When the user add a partner and the partner don't have an email, open a popup to purpose to add an email. + * The user can choose to add an email or cancel and close the popup. + */ +instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags.extend({ + + start: function() { + this.values = []; + this.values_checking = []; + + this.on("change:value", this, this.on_change_value_check); + this.trigger("change:value"); + + this._super.apply(this, arguments); + }, + + on_change_value_check : function () { + var self = this; + // filter for removed values + var values_removed = _.difference(self.values, self.get('value')); + + if (values_removed.length) { + self.values = _.difference(self.values, values_removed); + this.set({'value': self.values}); + return false; + } + + // find not checked values + var not_checked = _.difference(self.get('value'), self.values); + + // find not checked values and not on checking + var not_checked = _.difference(not_checked, self.values_checking); + + _.each(not_checked, function (val, key) { + self.values_checking.push(val); + self._check_email_popup(val); + }); + }, + + _check_email_popup: function (id) { + var self = this; + new instance.web.Model('res.partner').call("read", [id, ["email", "notification_email_send"]], {context: this.build_context()}) + .pipe(function (dict) { + if (!dict.email && (dict.notification_email_send == 'all' || dict.notification_email_send == 'comment')) { + var pop = new instance.web.form.FormOpenPopup(self); + pop.show_element( + 'res.partner', + dict.id, + self.build_context(), + { + title: _t("Please complete partner's informations and Email"), + } + ); + pop.on('write_completed', self, function () { + self._checked(dict.id, true); + }); + pop.on('closing', self, function () { + self._checked(dict.id, false); + }); + } else { + self._checked(dict.id, true); + } + }); + }, + + _checked: function (id, access) { + if (access) { + this.values.push(id); + } + this.values_checking = _.without(this.values_checking, id); + this.set({'value': this.values}); + }, +}); + + +/** + * Registry of form fields + */ +instance.web.form.widgets = instance.web.form.widgets.extend({ + 'many2many_tags_email' : 'instance.web.form.FieldMany2ManyTagsEmail', +}); + +}; \ No newline at end of file From af2c38f4c9a7da9ae0de7652ca098910cbaee09e Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Tue, 6 Nov 2012 13:52:06 +0100 Subject: [PATCH 674/703] [IMP] web: trigger closing for popup bzr revid: chm@openerp.com-20121106125206-icm2s8fvb13m40w9 --- addons/web/static/src/js/view_form.js | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 5ecad26e5df..435384bfe60 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -4427,6 +4427,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({ this.destroy(); }, destroy: function () { + this.trigger('closing'); this.$el.dialog('close'); this._super(); }, From 4f52103aa03d3ad1d1464699b562684ea6cd73f2 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 15:05:19 +0100 Subject: [PATCH 675/703] [FIX] double html-escaping of group titles in grouped lists (eg analysis) bzr revid: xmo@openerp.com-20121106140519-0qnq934rr44l6kgt --- addons/web/static/src/js/view_list.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/js/view_list.js b/addons/web/static/src/js/view_list.js index fd74fd8922b..f1fd26eed4d 100644 --- a/addons/web/static/src/js/view_list.js +++ b/addons/web/static/src/js/view_list.js @@ -1306,9 +1306,11 @@ instance.web.ListView.Groups = instance.web.Class.extend( /** @lends instance.we process_modifiers: false }); } catch (e) { - group_label = row_data[group_column.id].value; + group_label = _.str.escapeHTML(row_data[group_column.id].value); } - $group_column.text(_.str.sprintf("%s (%d)", + // group_label is html-clean (through format or explicit + // escaping if format failed), can inject straight into HTML + $group_column.html(_.str.sprintf("%s (%d)", group_label, group.length)); if (group.length && group.openable) { From 9304ac6594eb13cb911ccebbea60f0d7b35f91ee Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 15:18:35 +0100 Subject: [PATCH 676/703] [FIX] width of progress bars in list view bzr revid: xmo@openerp.com-20121106141835-fd8spbm93h3etjps --- addons/web/static/src/css/base.css | 3 +++ addons/web/static/src/css/base.sass | 2 ++ 2 files changed, 5 insertions(+) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index b030d0712f0..c97b59ec6fe 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -2777,6 +2777,9 @@ content: "}"; color: #e0e0e0; } +.openerp .oe_list_content .oe_list_field_progressbar progress { + width: 100%; +} .openerp .tree_header { background-color: #f0f0f0; border-bottom: 1px solid #cacaca; diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 79a688cf823..18451352370 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -2193,6 +2193,8 @@ $sheet-padding: 16px .oe_list_handle @include text-to-entypo-icon("}",#E0E0E0,18px) margin-right: 7px + .oe_list_field_progressbar progress + width: 100% // }}} // Tree view {{{ .tree_header From 2ebaa6f666ac9f8ec30db92c0bf9ca68864e4289 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 15:47:36 +0100 Subject: [PATCH 677/703] [FIX] searchview drawer closing when clicking advanced proposition handler for "global click filtered by whether click target is outside of search view" executed after prop deletion handler has executed => the whole proposition has already been removed from the document and thus isn't a descendent of the searchview anymore => test matches and drawer closes. Altered handler to stop propagation so does not reach global handler. bzr revid: xmo@openerp.com-20121106144736-l0pde7phf3nake4t --- addons/web/static/src/js/search.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 520dcd9169f..256e94f23ae 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1699,6 +1699,13 @@ instance.web.search.Advanced = instance.web.search.Input.extend({ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @lends instance.web.search.ExtendedSearchProposition# */{ template: 'SearchView.extended_search.proposition', + events: { + 'change .searchview_extended_prop_field': 'changed', + 'click .searchview_extended_delete_prop': function (e) { + e.stopPropagation(); + this.destroy(); + } + }, /** * @constructs instance.web.search.ExtendedSearchProposition * @extends instance.web.Widget @@ -1716,13 +1723,6 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @ this.value = null; }, start: function () { - var _this = this; - this.$el.find(".searchview_extended_prop_field").change(function() { - _this.changed(); - }); - this.$el.find('.searchview_extended_delete_prop').click(function () { - _this.destroy(); - }); this.changed(); }, changed: function() { From a006b078ed4fa9fa668ee3a4b25b926e56e1b09a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 6 Nov 2012 15:59:40 +0100 Subject: [PATCH 678/703] [REVIEW] trigger closing -> trigger closed, to match the code guidelines. bzr revid: tde@openerp.com-20121106145940-cji6varovqtgneiz --- addons/web/static/src/js/view_form.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 6447c2241cf..6a853c4bef9 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -4420,7 +4420,7 @@ instance.web.form.AbstractFormPopup = instance.web.Widget.extend({ this.destroy(); }, destroy: function () { - this.trigger('closing'); + this.trigger('closed'); this.$el.dialog('close'); this._super(); }, From 44284ca4a46da5211927f416743129c97259110e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 6 Nov 2012 15:59:58 +0100 Subject: [PATCH 679/703] [REVIEW] trigger closing -> closed, to match the code guidelines. bzr revid: tde@openerp.com-20121106145958-zg11plyzeo5rz6ao --- addons/mail/static/src/js/many2many_tags_email.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js index 2e449bd410a..ae239f3644e 100644 --- a/addons/mail/static/src/js/many2many_tags_email.js +++ b/addons/mail/static/src/js/many2many_tags_email.js @@ -58,7 +58,7 @@ instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags pop.on('write_completed', self, function () { self._checked(dict.id, true); }); - pop.on('closing', self, function () { + pop.on('closed', self, function () { self._checked(dict.id, false); }); } else { From a501903c23e639623f41471660b20ba64817aab8 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 16:04:49 +0100 Subject: [PATCH 680/703] [IMP] convert searchview to DOM events hash bzr revid: xmo@openerp.com-20121106150449-1sxybk8jml7xa2ji --- addons/web/static/src/js/search.js | 155 ++++++++++++++--------------- 1 file changed, 73 insertions(+), 82 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 256e94f23ae..55ffab0f7a7 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -124,19 +124,10 @@ function assert(condition, message) { } my.InputView = instance.web.Widget.extend({ template: 'SearchView.InputView', - start: function () { - var p = this._super.apply(this, arguments); - this.$el.on('focus', this.proxy('onFocus')); - this.$el.on('blur', this.proxy('onBlur')); - this.$el.on('keydown', this.proxy('onKeydown')); - return p; - }, - onFocus: function () { - this.trigger('focused', this); - }, - onBlur: function () { - this.$el.text(''); - this.trigger('blurred', this); + events: { + focus: function () { this.trigger('focused', this); }, + blur: function () { this.$el.text(''); this.trigger('blurred', this); }, + keydown: 'onKeydown' }, getSelection: function () { // get Text node @@ -212,6 +203,27 @@ my.InputView = instance.web.Widget.extend({ }); my.FacetView = instance.web.Widget.extend({ template: 'SearchView.FacetView', + events: { + 'focus': function () { this.trigger('focused', this); }, + 'blur': function () { this.trigger('blurred', this); }, + 'click': function (e) { + if ($(e.target).is('.oe_facet_remove')) { + this.model.destroy(); + return false; + } + this.$el.focus(); + e.stopPropagation(); + }, + 'keydown': function (e) { + var keys = $.ui.keyCode; + switch (e.which) { + case keys.BACKSPACE: + case keys.DELETE: + this.model.destroy(); + return false; + } + } + }, init: function (parent, model) { this._super(parent); this.model = model; @@ -223,33 +235,11 @@ my.FacetView = instance.web.Widget.extend({ }, start: function () { var self = this; - this.$el.on('focus', function () { self.trigger('focused', self); }); - this.$el.on('blur', function () { self.trigger('blurred', self); }); - this.$el.on('click', function (e) { - if ($(e.target).is('.oe_facet_remove')) { - self.model.destroy(); - return false; - } - self.$el.focus(); - e.stopPropagation(); - }); - this.$el.on('keydown', function (e) { - var keys = $.ui.keyCode; - switch (e.which) { - case keys.BACKSPACE: - case keys.DELETE: - self.model.destroy(); - return false; - } - }); var $e = self.$el.find('> span:last-child'); - var q = $.when(this._super()); - return q.pipe(function () { - var values = self.model.values.map(function (value) { + return $.when(this._super()).pipe(function () { + return $.when.apply(null, self.model.values.map(function (value) { return new my.FacetValueView(self, value).appendTo($e); - }); - - return $.when.apply(null, values); + })); }); }, model_changed: function () { @@ -274,6 +264,48 @@ my.FacetValueView = instance.web.Widget.extend({ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.SearchView# */{ template: "SearchView", + events: { + // focus last input if view itself is clicked + 'click': function (e) { + if (e.target === this.$el.find('.oe_searchview_facets')[0]) { + this.$el.find('.oe_searchview_input:last').focus(); + } + }, + // when the completion list opens/refreshes, automatically select the + // first completion item so if the user just hits [RETURN] or [TAB] it + // automatically selects it + 'autocompleteopen': function () { + var menu = this.$el.data('autocomplete').menu; + menu.activate( + $.Event({ type: "mouseenter" }), + menu.element.children().first()); + }, + // search button + 'click button.oe_searchview_search': function (e) { + e.stopImmediatePropagation(); + this.do_search(); + }, + 'click .oe_searchview_clear': function (e) { + e.stopImmediatePropagation(); + this.query.reset(); + }, + 'click .oe_searchview_unfold_drawer': function (e) { + e.stopImmediatePropagation(); + this.$el.toggleClass('oe_searchview_open_drawer'); + }, + 'keydown .oe_searchview_input, .oe_searchview_facet': function (e) { + switch(e.which) { + case $.ui.keyCode.LEFT: + this.focusPreceding(this); + e.preventDefault(); + break; + case $.ui.keyCode.RIGHT: + this.focusFollowing(this); + e.preventDefault(); + break; + } + } + }, /** * @constructs instance.web.SearchView * @extends instance.web.Widget @@ -331,55 +363,11 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea }); } - // Launch a search on clicking the oe_searchview_search button - this.$el.on('click', 'button.oe_searchview_search', function (e) { - e.stopImmediatePropagation(); - self.do_search(); - }); - - this.$el.on('keydown', - '.oe_searchview_input, .oe_searchview_facet', function (e) { - switch(e.which) { - case $.ui.keyCode.LEFT: - self.focusPreceding(this); - e.preventDefault(); - break; - case $.ui.keyCode.RIGHT: - self.focusFollowing(this); - e.preventDefault(); - break; - } - }); - - this.$el.on('click', '.oe_searchview_clear', function (e) { - e.stopImmediatePropagation(); - self.query.reset(); - }); - this.$el.on('click', '.oe_searchview_unfold_drawer', function (e) { - e.stopImmediatePropagation(); - self.$el.toggleClass('oe_searchview_open_drawer'); - }); instance.web.bus.on('click', this, function(ev) { if ($(ev.target).parents('.oe_searchview').length === 0) { self.$el.removeClass('oe_searchview_open_drawer'); } }); - // Focus last input if the view itself is clicked (empty section of - // facets element) - this.$el.on('click', function (e) { - if (e.target === self.$el.find('.oe_searchview_facets')[0]) { - self.$el.find('.oe_searchview_input:last').focus(); - } - }); - // when the completion list opens/refreshes, automatically select the - // first completion item so if the user just hits [RETURN] or [TAB] it - // automatically selects it - this.$el.on('autocompleteopen', function () { - var menu = self.$el.data('autocomplete').menu; - menu.activate( - $.Event({ type: "mouseenter" }), - menu.element.children().first()); - }); return $.when(p, this.ready); }, @@ -736,6 +724,9 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea * * If at least one field failed its validation, triggers * :js:func:`instance.web.SearchView.on_invalid` instead. + * + * @param [_query] + * @param {Object} [options] */ do_search: function (_query, options) { if (options && options.preventSearch) { From e3e54b0e7a906d4fdce243b88be83798dd71d041 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 16:21:48 +0100 Subject: [PATCH 681/703] [IMP] port searchview to helpers bzr revid: xmo@openerp.com-20121106152148-33ctafxz5iy53nl1 --- addons/web/static/src/js/search.js | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index 55ffab0f7a7..b2ded00c105 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -235,7 +235,7 @@ my.FacetView = instance.web.Widget.extend({ }, start: function () { var self = this; - var $e = self.$el.find('> span:last-child'); + var $e = this.$('> span:last-child'); return $.when(this._super()).pipe(function () { return $.when.apply(null, self.model.values.map(function (value) { return new my.FacetValueView(self, value).appendTo($e); @@ -267,8 +267,8 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea events: { // focus last input if view itself is clicked 'click': function (e) { - if (e.target === this.$el.find('.oe_searchview_facets')[0]) { - this.$el.find('.oe_searchview_input:last').focus(); + if (e.target === this.$('.oe_searchview_facets')[0]) { + this.$('.oe_searchview_input:last').focus(); } }, // when the completion list opens/refreshes, automatically select the @@ -468,7 +468,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea * div[contenteditable].oe_searchview_input) */ currentInputValue: function () { - return this.$el.find('div.oe_searchview_input:focus').text(); + return this.$('div.oe_searchview_input:focus').text(); }, /** * Provide auto-completion result for req.term (an array to `resp`) @@ -498,7 +498,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea var input_index = _(this.input_subviews).indexOf( this.subviewForRoot( - this.$el.find('div.oe_searchview_input:focus')[0])); + this.$('div.oe_searchview_input:focus')[0])); this.query.add(ui.item.facet, {at: input_index / 2}); }, childFocused: function () { @@ -527,7 +527,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea // _2: undefined if event=change, otherwise model var self = this; var started = []; - var $e = this.$el.find('div.oe_searchview_facets'); + var $e = this.$('div.oe_searchview_facets'); _.invoke(this.input_subviews, 'destroy'); this.input_subviews = []; @@ -652,7 +652,7 @@ instance.web.SearchView = instance.web.Widget.extend(/** @lends instance.web.Sea // build drawer var drawer_started = $.when.apply( null, _(this.select_for_drawer()).invoke( - 'appendTo', this.$el.find('.oe_searchview_drawer'))); + 'appendTo', this.$('.oe_searchview_drawer'))); // load defaults var defaults_fetched = $.when.apply(null, _(this.inputs).invoke( @@ -952,7 +952,7 @@ instance.web.search.FilterGroup = instance.web.search.Input.extend(/** @lends in */ search_change: function () { var self = this; - var $filters = this.$el.find('> li').removeClass('oe_selected'); + var $filters = this.$('> li').removeClass('oe_selected'); var facet = this.view.query.find(_.bind(this.match_facet, this)); if (!facet) { return; } facet.values.each(function (v) { @@ -1503,7 +1503,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({ }).pipe(this.proxy('set_filters')); }, clear_selection: function () { - this.$el.find('li.oe_selected').removeClass('oe_selected'); + this.$('li.oe_selected').removeClass('oe_selected'); }, append_filter: function (filter) { var self = this; @@ -1515,7 +1515,7 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({ } else { var id = filter.id; $filter = this.filters[key] = $('
  • ') - .appendTo(this.$el.find('.oe_searchview_custom_list')) + .appendTo(this.$('.oe_searchview_custom_list')) .addClass(filter.user_id ? 'oe_searchview_custom_private' : 'oe_searchview_custom_public') .text(filter.name); @@ -1550,8 +1550,8 @@ instance.web.search.CustomFilters = instance.web.search.Input.extend({ }, save_current: function () { var self = this; - var $name = this.$el.find('input:first'); - var private_filter = !this.$el.find('input:last').prop('checked'); + var $name = this.$('input:first'); + var private_filter = !this.$('input:last').prop('checked'); var search = this.view.build_search_data(); this.rpc('/web/session/eval_domain_and_context', { @@ -1657,7 +1657,7 @@ instance.web.search.Advanced = instance.web.search.Input.extend({ }, append_proposition: function () { return (new instance.web.search.ExtendedSearchProposition(this, this.fields)) - .appendTo(this.$el.find('ul')); + .appendTo(this.$('ul')); }, commit_search: function () { var self = this; @@ -1717,7 +1717,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @ this.changed(); }, changed: function() { - var nval = this.$el.find(".searchview_extended_prop_field").val(); + var nval = this.$(".searchview_extended_prop_field").val(); if(this.attrs.selected == null || nval != this.attrs.selected.name) { this.select_field(_.detect(this.fields, function(x) {return x.name == nval;})); } @@ -1732,7 +1732,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @ if(this.attrs.selected != null) { this.value.destroy(); this.value = null; - this.$el.find('.searchview_extended_prop_op').html(''); + this.$('.searchview_extended_prop_op').html(''); } this.attrs.selected = field; if(field == null) { @@ -1748,9 +1748,9 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @ _.each(this.value.operators, function(operator) { $('
    - - Club + + Cheese And Ham 3.30 - Jambon, Fromage, Salade, Tomates, comcombres, oeufs + Cheese, Ham, Salad, Tomatoes, cucumbers, eggs - - Le Campagnard + + The Country 3.30 - Brie, Miel, Cerneaux de noix + Brie, Honey, Walnut Kernels - - Le Pâté Crème + + Tuna 2.50 - + Tuna, Mayonnaise - Fromage Gouda + Gouda Cheese 2.50 - + - - Poulet Curry + + Chicken Curry 2.60 - + @@ -71,7 +71,7 @@ 6.90 - Tomates, Mozzarella + Tomatoes, Mozzarella @@ -79,23 +79,23 @@ 7.40 - Tomates fraiches, Basilic, Mozzarella + Fresh Tomatoes, Basil, Mozzarella - Pâtes Bolognese + Bolognese Pasta 7.70 - + - Pâtes Napoli + Napoli Pasta 7.70 - Tomates, Basilic + Tomatoes, Basil @@ -138,7 +138,7 @@ confirmed - +Champignons + +Mushrooms @@ -148,7 +148,7 @@ cancelled - +Salade +Tomates +Comcombres + +Salad +Tomatoes +Cucumbers diff --git a/addons/lunch/report/groups.xml b/addons/lunch/report/groups.xml new file mode 100644 index 00000000000..75ab0836b12 --- /dev/null +++ b/addons/lunch/report/groups.xml @@ -0,0 +1,11 @@ + + + + + Lunch / Manager + + + Lunch / User + + + diff --git a/addons/lunch/report/order.rml b/addons/lunch/report/order.rml index b09b59bb96b..1ab52a88bda 100644 --- a/addons/lunch/report/order.rml +++ b/addons/lunch/report/order.rml @@ -149,10 +149,10 @@ [[ formatLang(lines.date,date='True') ]] - [[ (lines.product and lines.product.name) or '' ]] + [[ (lines.product_id and lines.product_id.name) or '' ]] - [[ lines.descript]] + [[ lines.note]] [[ lines.price ]] [[ (o.company_id and o.company_id.currency_id and o.company_id.currency_id.symbol) or '' ]] diff --git a/addons/lunch/report/report_lunch_order_view.xml b/addons/lunch/report/report_lunch_order_view.xml index b916cab79f9..f7bfdcd7395 100644 --- a/addons/lunch/report/report_lunch_order_view.xml +++ b/addons/lunch/report/report_lunch_order_view.xml @@ -2,47 +2,6 @@ - - report.lunch.order.tree - report.lunch.order.line - - - - - - - - - - - - - - - report.lunch.order.search - report.lunch.order.line - - - - - - - - - - - - - - - - Lunch Order Analysis - report.lunch.order.line - form - tree - - {'search_default_month':1,'search_default_User':1} - diff --git a/addons/lunch/security/groups.xml b/addons/lunch/security/groups.xml deleted file mode 100644 index bf6fb63ad30..00000000000 --- a/addons/lunch/security/groups.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - Lunch / Manager - - - Lunch / User - - - - - lunch orders - - - - - - - - - lunch orders - - - - - - - - - lunch order lines - - - - - - - - - lunch order lines - - - - - - - - - lunch cashmoves - - - - - - - - - lunch cashmoves - - - - - - - - - lunch products - - - - - - - - - lunch products - - - - - - - - - lunch products - - - - - - - - - lunch products - - - - - - - - - lunch alerts - - - - - - - - - lunch alerts - - - - - - - From 7b5d0af159ba9cf33f121e56f0cd68521250787e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 6 Nov 2012 16:57:02 +0100 Subject: [PATCH 686/703] [CLEAN] mail.js: removed unnecessary default values in context. bzr revid: tde@openerp.com-20121106155702-bq5xg7z6qmwqjema --- addons/mail/static/src/js/mail.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/addons/mail/static/src/js/mail.js b/addons/mail/static/src/js/mail.js index a9783c32049..1eb3c29e556 100644 --- a/addons/mail/static/src/js/mail.js +++ b/addons/mail/static/src/js/mail.js @@ -1642,8 +1642,6 @@ openerp.mail = function (session) { views: [[false, 'form']], target: 'new', context: { - 'default_model': '', - 'default_res_id': false, 'default_content_subtype': 'html', }, }; From 56f04649cc9ea8896d5d6df1f5695d4558d21294 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 6 Nov 2012 16:58:13 +0100 Subject: [PATCH 687/703] [REVIEW] Some code cleaning in js. bzr revid: tde@openerp.com-20121106155813-h2zswqc16z6ev2k9 --- addons/mail/static/src/js/many2many_tags_email.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js index 234dc504682..52dcbf7aeb5 100644 --- a/addons/mail/static/src/js/many2many_tags_email.js +++ b/addons/mail/static/src/js/many2many_tags_email.js @@ -23,20 +23,15 @@ instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags // filter for removed values var values_removed = _.difference(this.values, this.get('value')); - if (values_removed.length) { this.values = _.difference(this.values, values_removed); this.set({'value': this.values}); return false; } - // find not checked values - var not_checked = _.difference(this.get('value'), this.values); - - // find not checked values and not on checking - var not_checked = _.difference(not_checked, this.values_checking); - - if(not_checked.length) { + // find not checked values that are not currently on checking + var not_checked = _.difference(this.get('value'), this.values, this.values_checking); + if (not_checked.length) { // remember values on checking for cheked only one time this.values_checking = this.values_checking.concat(not_checked); // check values @@ -58,7 +53,7 @@ instance.web.form.FieldMany2ManyTagsEmail = instance.web.form.FieldMany2ManyTags self.values_checking = _.difference(self.values_checking, valid_partner); // unvalid partner - _.each(record_ids, function(id) { + _.each(record_ids, function (id) { var pop = new instance.web.form.FormOpenPopup(self); pop.show_element( 'res.partner', @@ -90,4 +85,4 @@ instance.web.form.widgets = instance.web.form.widgets.extend({ 'many2many_tags_email' : 'instance.web.form.FieldMany2ManyTagsEmail', }); -}; \ No newline at end of file +}; From 2a9779045fdceb7281a16fac5dc3b5ebab9123a6 Mon Sep 17 00:00:00 2001 From: niv-openerp Date: Tue, 6 Nov 2012 17:25:25 +0100 Subject: [PATCH 688/703] [FIX] rare problem in m2mtags, when the form view is destroyed just after a reload lp bug: https://launchpad.net/bugs/1075543 fixed bzr revid: nicolas.vanhoren@openerp.com-20121106162525-c835kdpjpj66e714 --- addons/web/static/src/js/view_form.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 6a853c4bef9..90ec530ca62 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -3922,6 +3922,8 @@ instance.web.form.FieldMany2ManyTags = instance.web.form.AbstractField.extend(in var dataset = new instance.web.DataSetStatic(this, this.field.relation, self.build_context()); var values = self.get("value") var handle_names = function(data) { + if (self.isDestroyed()) + return; var indexed = {}; _.each(data, function(el) { indexed[el[0]] = el; From 1c721d43c5afbca1f3550409bfaa48940b38ac64 Mon Sep 17 00:00:00 2001 From: Xavier Morel Date: Tue, 6 Nov 2012 17:17:15 +0100 Subject: [PATCH 689/703] [FIX] disable advanced search apply button in search view when there are no propositions avoids locking up the browser by entering an infinite loop when unshifting ors on domains bzr revid: xmo@openerp.com-20121106161715-7vc55kps8gi8h3lb --- addons/web/static/src/js/search.js | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/addons/web/static/src/js/search.js b/addons/web/static/src/js/search.js index b2ded00c105..d005c79e9b2 100644 --- a/addons/web/static/src/js/search.js +++ b/addons/web/static/src/js/search.js @@ -1656,11 +1656,20 @@ instance.web.search.Advanced = instance.web.search.Input.extend({ }); }, append_proposition: function () { + var self = this; return (new instance.web.search.ExtendedSearchProposition(this, this.fields)) - .appendTo(this.$('ul')); + .appendTo(this.$('ul')).then(function () { + self.$('button.oe_apply').prop('disabled', false); + }); + }, + remove_proposition: function (prop) { + // removing last proposition, disable apply button + if (this.getChildren().length <= 1) { + this.$('button.oe_apply').prop('disabled', true); + } + prop.destroy(); }, commit_search: function () { - var self = this; // Get domain sections from all propositions var children = this.getChildren(); var propositions = _.invoke(children, 'get_proposition'); @@ -1694,7 +1703,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @ 'change .searchview_extended_prop_field': 'changed', 'click .searchview_extended_delete_prop': function (e) { e.stopPropagation(); - this.destroy(); + this.getParent().remove_proposition(this); } }, /** @@ -1714,7 +1723,7 @@ instance.web.search.ExtendedSearchProposition = instance.web.Widget.extend(/** @ this.value = null; }, start: function () { - this.changed(); + return this._super().then(this.proxy('changed')); }, changed: function() { var nval = this.$(".searchview_extended_prop_field").val(); From c71ce60400be36cfeda35b2a959e027509c271fa Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 6 Nov 2012 17:27:53 +0100 Subject: [PATCH 690/703] [IMP] ir.translation, raise exception when trying to translate fields when no extra language is installed. bzr revid: fme@openerp.com-20121106162753-6eqbhnwqhjgeun78 --- openerp/addons/base/ir/ir_translation.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openerp/addons/base/ir/ir_translation.py b/openerp/addons/base/ir/ir_translation.py index 8f05c30e20b..f3985045fb2 100644 --- a/openerp/addons/base/ir/ir_translation.py +++ b/openerp/addons/base/ir/ir_translation.py @@ -24,6 +24,7 @@ import logging import openerp.modules from openerp.osv import fields, osv +from tools.translate import _ _logger = logging.getLogger(__name__) @@ -336,6 +337,8 @@ class ir_translation(osv.osv): trans_model = self.pool.get(model) domain = ['&', ('res_id', '=', id), ('name', '=like', model + ',%')] langs_ids = self.pool.get('res.lang').search(cr, uid, [('code', '!=', 'en_US')], context=context) + if not langs_ids: + raise osv.except_osv(_('Error'), _("Translation features are unavailable until you install an extra OpenERP translation.")) langs = [lg.code for lg in self.pool.get('res.lang').browse(cr, uid, langs_ids, context=context)] main_lang = 'en_US' translatable_fields = [] From 2a13ed633827e0b9440263ab99888a7248c85657 Mon Sep 17 00:00:00 2001 From: Arnaud Pineux Date: Tue, 6 Nov 2012 17:29:07 +0100 Subject: [PATCH 691/703] [REF]English demo, fix report, clear security bzr revid: api@openerp.com-20121106162907-ir7ujoxowlrqouyt --- addons/lunch/lunch_demo.xml | 3 +++ addons/lunch/report/report_lunch_order.py | 2 +- addons/lunch/{report => security}/groups.xml | 0 3 files changed, 4 insertions(+), 1 deletion(-) rename addons/lunch/{report => security}/groups.xml (100%) diff --git a/addons/lunch/lunch_demo.xml b/addons/lunch/lunch_demo.xml index 4f38760b64a..a9b03137bf2 100644 --- a/addons/lunch/lunch_demo.xml +++ b/addons/lunch/lunch_demo.xml @@ -5,6 +5,9 @@ + + + Sandwich diff --git a/addons/lunch/report/report_lunch_order.py b/addons/lunch/report/report_lunch_order.py index 2d89e2196e7..3a0875c1cd1 100644 --- a/addons/lunch/report/report_lunch_order.py +++ b/addons/lunch/report/report_lunch_order.py @@ -45,11 +45,11 @@ class report_lunch_order(osv.osv): create or replace view report_lunch_order_line as ( select min(lo.id) as id, + lo.user_id as user_id, lo.date as date, to_char(lo.date, 'YYYY') as year, to_char(lo.date, 'MM') as month, to_char(lo.date, 'YYYY-MM-DD') as day, - lo.user_id, lo.note as note, sum(lp.price) as price_total diff --git a/addons/lunch/report/groups.xml b/addons/lunch/security/groups.xml similarity index 100% rename from addons/lunch/report/groups.xml rename to addons/lunch/security/groups.xml From 86d9b7be0ca3d9c9e4002bb4e6e000f56a6dd47b Mon Sep 17 00:00:00 2001 From: Fabien Meghazi Date: Tue, 6 Nov 2012 18:20:36 +0100 Subject: [PATCH 692/703] [IMP] Binary Image: warn user when selected image could not be displayed. Also use placeholder bzr revid: fme@openerp.com-20121106172036-d9jkebo9mj45thft --- addons/web/static/src/js/view_form.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/addons/web/static/src/js/view_form.js b/addons/web/static/src/js/view_form.js index 90ec530ca62..bbb2234e3bd 100644 --- a/addons/web/static/src/js/view_form.js +++ b/addons/web/static/src/js/view_form.js @@ -4826,6 +4826,7 @@ instance.web.form.FieldBinaryFile = instance.web.form.FieldBinary.extend({ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ template: 'FieldBinaryImage', + placeholder: "/web/static/src/img/placeholder.png", render_value: function() { var self = this; var url; @@ -4839,7 +4840,7 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ url = '/web/binary/image?session_id=' + this.session.session_id + '&model=' + this.view.dataset.model +'&id=' + id + '&field=' + field + '&t=' + (new Date().getTime()); } else { - url = "/web/static/src/img/placeholder.png"; + url = this.placeholder; } var $img = $(QWeb.render("FieldBinaryImage-img", { widget: this, url: url })); this.$el.find('> img').remove(); @@ -4852,6 +4853,10 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({ $img.css("margin-left", "" + (self.options.size[0] - $img.width()) / 2 + "px"); $img.css("margin-top", "" + (self.options.size[1] - $img.height()) / 2 + "px"); }); + $img.on('error', function() { + $img.attr('src', self.placeholder); + instance.webclient.notification.warn(_t("Image"), _t("Could not display the selected image.")); + }); }, on_file_change: function() { this.render_value(); From 4ba1696ce2e1bad704e39a5544e6f358c53e8058 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 6 Nov 2012 19:15:02 +0100 Subject: [PATCH 693/703] [FIX] res.partner: read image files in binary mode lp bug: https://launchpad.net/bugs/1048040 fixed bzr revid: odo@openerp.com-20121106181502-tzqmrhs0u8odngvz --- openerp/addons/base/res/res_partner.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/openerp/addons/base/res/res_partner.py b/openerp/addons/base/res/res_partner.py index 9d798d8a636..df42bb81521 100644 --- a/openerp/addons/base/res/res_partner.py +++ b/openerp/addons/base/res/res_partner.py @@ -264,10 +264,15 @@ class res_partner(osv.osv, format_address): return False def _get_default_image(self, cr, uid, is_company, context=None, colorize=False): - if is_company: - image = open(openerp.modules.get_module_resource('base', 'static/src/img', 'company_image.png')).read() - else: - image = tools.image_colorize(open(openerp.modules.get_module_resource('base', 'static/src/img', 'avatar.png')).read()) + img_path = openerp.modules.get_module_resource('base', 'static/src/img', + ('company_image.png' if is_company else 'avatar.png')) + with open(img_path, 'rb') as f: + image = f.read() + + # colorize user avatars + if not is_company: + image = tools.image_colorize(image) + return tools.image_resize_image_big(image.encode('base64')) def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False): From 0357fddc6175b1d01eb46835bc567fc0cb825586 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 6 Nov 2012 19:15:07 +0100 Subject: [PATCH 694/703] [FIX] orm,web_services: properly return results of workflow triggers bzr revid: odo@openerp.com-20121106181507-ss1w425c1omsn3sb --- openerp/osv/orm.py | 6 ++++-- openerp/osv/osv.py | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 910e08b3a69..ae0eb0f8bff 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -3861,10 +3861,12 @@ class BaseModel(object): getattr(wf_service, trigger)(uid, self._name, res_id, cr) def _workflow_signal(self, cr, uid, ids, signal, context=None): - """Send given workflow signal""" + """Send given workflow signal and return a dict mapping ids to workflow results""" wf_service = netsvc.LocalService("workflow") + result = {} for res_id in ids: - wf_service.trg_validate(uid, self._name, res_id, signal, cr) + result[res_id] = wf_service.trg_validate(uid, self._name, res_id, signal, cr) + return result def unlink(self, cr, uid, ids, context=None): """ diff --git a/openerp/osv/osv.py b/openerp/osv/osv.py index 94f179c7897..7703406ec96 100644 --- a/openerp/osv/osv.py +++ b/openerp/osv/osv.py @@ -188,7 +188,8 @@ class object_proxy(object): object = pooler.get_pool(cr.dbname).get(obj) if not object: raise except_osv('Object Error', 'Object %s doesn\'t exist' % str(obj)) - return object._workflow_signal(cr, uid, [args[0]], signal) + res_id = args[0] + return object._workflow_signal(cr, uid, [res_id], signal)[res_id] @check def exec_workflow(self, db, uid, obj, signal, *args): From ab24e719d6d96bd7a24deec8b58734d21cf5a212 Mon Sep 17 00:00:00 2001 From: Olivier Dony Date: Tue, 6 Nov 2012 19:16:36 +0100 Subject: [PATCH 695/703] [FIX] l10n_*: ensure install wizard triggers are in `noupdate` blocks, to avoid spurious wizards at update bzr revid: odo@openerp.com-20121106181636-i3oqcyg10ysxf012 --- addons/l10n_ar/l10n_ar_wizard.xml | 2 +- addons/l10n_at/l10n_chart_at_wizard.xml | 2 +- addons/l10n_ca/l10n_ca_wizard.xml | 2 +- addons/l10n_ch/wizard.xml | 2 +- addons/l10n_cl/l10n_cl_wizard.xml | 2 +- addons/l10n_cn/l10n_chart_cn_wizard.xml | 2 +- addons/l10n_de/l10n_de_wizard.xml | 2 +- addons/l10n_ec/l10n_chart_ec_wizard.xml | 2 +- addons/l10n_fr/l10n_fr_wizard.xml | 2 +- addons/l10n_gr/l10n_gr_wizard.xml | 2 +- addons/l10n_in/l10n_in_wizard.xml | 2 +- addons/l10n_it/l10n_chart_it_generic.xml | 2 +- addons/l10n_lu/l10n_lu_wizard.xml | 2 +- addons/l10n_ma/l10n_ma_wizard.xml | 2 +- addons/l10n_mx/l10n_chart_mx_wizard.xml | 2 +- addons/l10n_nl/l10n_nl_wizard.xml | 2 +- addons/l10n_pe/l10n_pe_wizard.xml | 2 +- addons/l10n_pl/l10n_chart_pl_wizard.xml | 2 +- addons/l10n_ro/l10n_chart_ro_wizard.xml | 2 +- addons/l10n_syscohada/l10n_syscohada_wizard.xml | 2 +- addons/l10n_th/account_data.xml | 5 +++-- addons/l10n_tr/l10n_tr_wizard.xml | 2 +- addons/l10n_uk/l10n_uk_wizard.xml | 2 +- addons/l10n_us/l10n_us_wizard.xml | 2 +- addons/l10n_uy/l10n_uy_wizard.xml | 2 +- addons/l10n_ve/l10n_chart_ve_wizard.xml | 2 +- 26 files changed, 28 insertions(+), 27 deletions(-) diff --git a/addons/l10n_ar/l10n_ar_wizard.xml b/addons/l10n_ar/l10n_ar_wizard.xml index 3c94d3db7a8..82e7671b4d3 100644 --- a/addons/l10n_ar/l10n_ar_wizard.xml +++ b/addons/l10n_ar/l10n_ar_wizard.xml @@ -1,6 +1,6 @@ - + open diff --git a/addons/l10n_at/l10n_chart_at_wizard.xml b/addons/l10n_at/l10n_chart_at_wizard.xml index efc68ce13e9..19d27fb47c7 100644 --- a/addons/l10n_at/l10n_chart_at_wizard.xml +++ b/addons/l10n_at/l10n_chart_at_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_ca/l10n_ca_wizard.xml b/addons/l10n_ca/l10n_ca_wizard.xml index efc68ce13e9..19d27fb47c7 100644 --- a/addons/l10n_ca/l10n_ca_wizard.xml +++ b/addons/l10n_ca/l10n_ca_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_ch/wizard.xml b/addons/l10n_ch/wizard.xml index 792bd21a2fc..dde7a77516a 100644 --- a/addons/l10n_ch/wizard.xml +++ b/addons/l10n_ch/wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_cl/l10n_cl_wizard.xml b/addons/l10n_cl/l10n_cl_wizard.xml index bcbd9a43f27..704ac4daf38 100644 --- a/addons/l10n_cl/l10n_cl_wizard.xml +++ b/addons/l10n_cl/l10n_cl_wizard.xml @@ -1,6 +1,6 @@ - + open diff --git a/addons/l10n_cn/l10n_chart_cn_wizard.xml b/addons/l10n_cn/l10n_chart_cn_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_cn/l10n_chart_cn_wizard.xml +++ b/addons/l10n_cn/l10n_chart_cn_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_de/l10n_de_wizard.xml b/addons/l10n_de/l10n_de_wizard.xml index efc68ce13e9..19d27fb47c7 100644 --- a/addons/l10n_de/l10n_de_wizard.xml +++ b/addons/l10n_de/l10n_de_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_ec/l10n_chart_ec_wizard.xml b/addons/l10n_ec/l10n_chart_ec_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_ec/l10n_chart_ec_wizard.xml +++ b/addons/l10n_ec/l10n_chart_ec_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_fr/l10n_fr_wizard.xml b/addons/l10n_fr/l10n_fr_wizard.xml index bcbd9a43f27..704ac4daf38 100644 --- a/addons/l10n_fr/l10n_fr_wizard.xml +++ b/addons/l10n_fr/l10n_fr_wizard.xml @@ -1,6 +1,6 @@ - + open diff --git a/addons/l10n_gr/l10n_gr_wizard.xml b/addons/l10n_gr/l10n_gr_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_gr/l10n_gr_wizard.xml +++ b/addons/l10n_gr/l10n_gr_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_in/l10n_in_wizard.xml b/addons/l10n_in/l10n_in_wizard.xml index bcbd9a43f27..704ac4daf38 100644 --- a/addons/l10n_in/l10n_in_wizard.xml +++ b/addons/l10n_in/l10n_in_wizard.xml @@ -1,6 +1,6 @@ - + open diff --git a/addons/l10n_it/l10n_chart_it_generic.xml b/addons/l10n_it/l10n_chart_it_generic.xml index 792bd21a2fc..dde7a77516a 100644 --- a/addons/l10n_it/l10n_chart_it_generic.xml +++ b/addons/l10n_it/l10n_chart_it_generic.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_lu/l10n_lu_wizard.xml b/addons/l10n_lu/l10n_lu_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_lu/l10n_lu_wizard.xml +++ b/addons/l10n_lu/l10n_lu_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_ma/l10n_ma_wizard.xml b/addons/l10n_ma/l10n_ma_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_ma/l10n_ma_wizard.xml +++ b/addons/l10n_ma/l10n_ma_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_mx/l10n_chart_mx_wizard.xml b/addons/l10n_mx/l10n_chart_mx_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_mx/l10n_chart_mx_wizard.xml +++ b/addons/l10n_mx/l10n_chart_mx_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_nl/l10n_nl_wizard.xml b/addons/l10n_nl/l10n_nl_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_nl/l10n_nl_wizard.xml +++ b/addons/l10n_nl/l10n_nl_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_pe/l10n_pe_wizard.xml b/addons/l10n_pe/l10n_pe_wizard.xml index 3c94d3db7a8..82e7671b4d3 100644 --- a/addons/l10n_pe/l10n_pe_wizard.xml +++ b/addons/l10n_pe/l10n_pe_wizard.xml @@ -1,6 +1,6 @@ - + open diff --git a/addons/l10n_pl/l10n_chart_pl_wizard.xml b/addons/l10n_pl/l10n_chart_pl_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_pl/l10n_chart_pl_wizard.xml +++ b/addons/l10n_pl/l10n_chart_pl_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_ro/l10n_chart_ro_wizard.xml b/addons/l10n_ro/l10n_chart_ro_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_ro/l10n_chart_ro_wizard.xml +++ b/addons/l10n_ro/l10n_chart_ro_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_syscohada/l10n_syscohada_wizard.xml b/addons/l10n_syscohada/l10n_syscohada_wizard.xml index 792bd21a2fc..dde7a77516a 100644 --- a/addons/l10n_syscohada/l10n_syscohada_wizard.xml +++ b/addons/l10n_syscohada/l10n_syscohada_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_th/account_data.xml b/addons/l10n_th/account_data.xml index d730caa8404..9ae3d9e3364 100644 --- a/addons/l10n_th/account_data.xml +++ b/addons/l10n_th/account_data.xml @@ -641,11 +641,12 @@ sale + - + + open - diff --git a/addons/l10n_tr/l10n_tr_wizard.xml b/addons/l10n_tr/l10n_tr_wizard.xml index 59668347bed..66b9d37221b 100644 --- a/addons/l10n_tr/l10n_tr_wizard.xml +++ b/addons/l10n_tr/l10n_tr_wizard.xml @@ -1,6 +1,6 @@ - + open diff --git a/addons/l10n_uk/l10n_uk_wizard.xml b/addons/l10n_uk/l10n_uk_wizard.xml index 1b8d528c0e8..8a6f1a5a83c 100644 --- a/addons/l10n_uk/l10n_uk_wizard.xml +++ b/addons/l10n_uk/l10n_uk_wizard.xml @@ -1,6 +1,6 @@ - + open diff --git a/addons/l10n_us/l10n_us_wizard.xml b/addons/l10n_us/l10n_us_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_us/l10n_us_wizard.xml +++ b/addons/l10n_us/l10n_us_wizard.xml @@ -1,5 +1,5 @@ - + open diff --git a/addons/l10n_uy/l10n_uy_wizard.xml b/addons/l10n_uy/l10n_uy_wizard.xml index 49cbeca89f9..3dea57dc5c2 100644 --- a/addons/l10n_uy/l10n_uy_wizard.xml +++ b/addons/l10n_uy/l10n_uy_wizard.xml @@ -1,6 +1,6 @@ - + open diff --git a/addons/l10n_ve/l10n_chart_ve_wizard.xml b/addons/l10n_ve/l10n_chart_ve_wizard.xml index 6919eb199b6..52aaa88fdab 100644 --- a/addons/l10n_ve/l10n_chart_ve_wizard.xml +++ b/addons/l10n_ve/l10n_chart_ve_wizard.xml @@ -1,5 +1,5 @@ - + open From b1a02e0b153ee21b9069646c9f9c0222b446617e Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 6 Nov 2012 22:28:18 +0100 Subject: [PATCH 696/703] [IMP] Expenses configuration menu simplified bzr revid: fp@openerp.com-20121106212818-hlq7s697ww3y3kbq --- addons/hr_expense/hr_expense_view.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/hr_expense/hr_expense_view.xml b/addons/hr_expense/hr_expense_view.xml index fbaa4c1f87e..74b77009aae 100644 --- a/addons/hr_expense/hr_expense_view.xml +++ b/addons/hr_expense/hr_expense_view.xml @@ -211,8 +211,7 @@ - - + From 3d1f9eacc5e419c9bc74d7ae78c14afb7eecac4f Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 6 Nov 2012 23:05:08 +0100 Subject: [PATCH 697/703] [IMP] typo bzr revid: fp@openerp.com-20121106220508-2fojaq6021v2i2jt --- addons/hr_holidays/hr_holidays_view.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/hr_holidays/hr_holidays_view.xml b/addons/hr_holidays/hr_holidays_view.xml index 4691f7ebd71..ef300741139 100644 --- a/addons/hr_holidays/hr_holidays_view.xml +++ b/addons/hr_holidays/hr_holidays_view.xml @@ -466,7 +466,7 @@ - Leave Type + Leave Types ir.actions.act_window hr.holidays.status form From 75ef7f2a9983cdcfe2b7a043f607ce8e94af43ab Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Tue, 6 Nov 2012 23:39:12 +0100 Subject: [PATCH 698/703] [FIX] css bzr revid: fp@openerp.com-20121106223912-yz8yyjpbd6d1kjn0 --- addons/web_kanban/static/src/css/kanban.css | 6 +++++- addons/web_kanban/static/src/css/kanban.sass | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/addons/web_kanban/static/src/css/kanban.css b/addons/web_kanban/static/src/css/kanban.css index 837d11949bc..f968364c987 100644 --- a/addons/web_kanban/static/src/css/kanban.css +++ b/addons/web_kanban/static/src/css/kanban.css @@ -144,8 +144,13 @@ margin-left: 4px; cursor: pointer; position: relative; +} +.openerp .oe_kanban_view .oe_kanban_add { top: -8px; } +.openerp .oe_kanban_view .oe_kanban_header .oe_dropdown_toggle { + top: -2px; +} .openerp .oe_kanban_view .oe_kanban_card, .openerp .oe_kanban_view .oe_dropdown_toggle { cursor: pointer; display: inline-block; @@ -481,7 +486,6 @@ } .openerp .oe_kanban_view .oe_dropdown_kanban { float: right; - clear: both; cursor: pointer; margin-top: -6px; } diff --git a/addons/web_kanban/static/src/css/kanban.sass b/addons/web_kanban/static/src/css/kanban.sass index aea5d6bc8c0..459fc56092d 100644 --- a/addons/web_kanban/static/src/css/kanban.sass +++ b/addons/web_kanban/static/src/css/kanban.sass @@ -168,7 +168,10 @@ margin-left: 4px cursor: pointer position: relative + .oe_kanban_add top: -8px + .oe_kanban_header .oe_dropdown_toggle + top: -2px .oe_kanban_card, .oe_dropdown_toggle cursor: pointer display: inline-block @@ -414,7 +417,6 @@ // KanbanDropDown {{{ .oe_dropdown_kanban float: right - clear: both cursor: pointer margin-top: -6px &:hover From 92cce486cde5e52065869f65f86d3078352f5ae4 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 7 Nov 2012 00:04:16 +0100 Subject: [PATCH 699/703] [IMP] note CSS bzr revid: fp@openerp.com-20121106230416-xi6ddk7ll02wii7i --- addons/note/note_view.xml | 10 +++++----- addons/note/static/src/css/note.css | 2 +- addons/note/static/src/css/note.sass | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/addons/note/note_view.xml b/addons/note/note_view.xml index 5c3a77b7626..18a3ec840a9 100644 --- a/addons/note/note_view.xml +++ b/addons/note/note_view.xml @@ -59,18 +59,18 @@
    - - W - W - -
    + í
    diff --git a/addons/note/static/src/css/note.css b/addons/note/static/src/css/note.css index 43bc455e04a..1b7e9315e74 100644 --- a/addons/note/static/src/css/note.css +++ b/addons/note/static/src/css/note.css @@ -46,7 +46,7 @@ .openerp .oe_kanban_record .oe_kanban_card_fancy { text-shadow: none; border-radius: 2px; - padding: 12px; + padding: 8px; margin-left: 3px; margin-right: 3px; padding-bottom: 16px; diff --git a/addons/note/static/src/css/note.sass b/addons/note/static/src/css/note.sass index ff39ce8708c..b5bc28a2593 100644 --- a/addons/note/static/src/css/note.sass +++ b/addons/note/static/src/css/note.sass @@ -50,7 +50,7 @@ .oe_kanban_card_fancy text-shadow: none border-radius: 2px - padding: 12px + padding: 8px margin-left: 3px margin-right: 3px padding-bottom: 16px From d07f7e0d995f61d3b435898b0c75eec2d6339d50 Mon Sep 17 00:00:00 2001 From: Fabien Pinckaers Date: Wed, 7 Nov 2012 00:05:28 +0100 Subject: [PATCH 700/703] [IMP] CSS small improvement bzr revid: fp@openerp.com-20121106230528-1rq72g0n0okde870 --- addons/web/static/src/css/base.css | 3 ++- addons/web/static/src/css/base.sass | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/addons/web/static/src/css/base.css b/addons/web/static/src/css/base.css index c97b59ec6fe..30fe4d415cf 100644 --- a/addons/web/static/src/css/base.css +++ b/addons/web/static/src/css/base.css @@ -25,6 +25,7 @@ display: none !important; } } + .openerp.openerp_webclient_container { height: 100%; } @@ -659,7 +660,7 @@ cursor: pointer; } .openerp .oe_dropdown_toggle { - color: rgba(0, 0, 0, 0.5); + color: rgba(0, 0, 0, 0.3); font-weight: normal; } .openerp .oe_dropdown_hover:hover .oe_dropdown_menu, .openerp .oe_dropdown_menu.oe_opened { diff --git a/addons/web/static/src/css/base.sass b/addons/web/static/src/css/base.sass index 18451352370..e388ad16727 100644 --- a/addons/web/static/src/css/base.sass +++ b/addons/web/static/src/css/base.sass @@ -569,7 +569,7 @@ $sheet-padding: 16px position: relative cursor: pointer .oe_dropdown_toggle - color: rgba(0,0,0,0.5) + color: rgba(0,0,0,0.3) font-weight: normal .oe_dropdown_hover:hover .oe_dropdown_menu, .oe_dropdown_menu.oe_opened display: block From e77725eb892022793e575bbfdbdcde7331e79128 Mon Sep 17 00:00:00 2001 From: Antony Lesuisse Date: Wed, 7 Nov 2012 02:57:08 +0100 Subject: [PATCH 701/703] [IMP] improve experience on for openerp developers on windows, notes in setup.py and fix some imports bzr revid: al@openerp.com-20121107015708-o9l893ll9f32wjcy --- README | 26 +++---- openerp/service/__init__.py | 2 +- openerp/service/workers.py | 13 ++-- setup.py | 139 ++++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 26 deletions(-) create mode 100755 setup.py diff --git a/README b/README index e7639e08fed..9449819d766 100644 --- a/README +++ b/README @@ -6,17 +6,9 @@ Customer Relationship Management software. More info at: http://www.openerp.com -Installation on Debian Ubuntu +Installation on Debian/Ubuntu ----------------------------- -Download the deb file and type: - - $ sudo dpkg -i - $ sudo apt-get install install -f - -Installation on Debian Ubuntu from nightly build ------------------------------------------------- - Add the the apt repository deb http://nightly.openerp.com/6.1/deb/ ./ @@ -26,6 +18,11 @@ in your source.list and type: $ sudo apt-get update $ sudo apt-get install openerp +Or download the deb file and type: + + $ sudo dpkg -i + $ sudo apt-get install install -f + Installation on RedHat, Fedora, CentOS -------------------------------------- @@ -42,6 +39,8 @@ Install the openerp rpm Installation on Windows ----------------------- + Check the notes in setup.py + Installation on MacOSX ----------------------- @@ -54,14 +53,7 @@ default master password is "admin". Detailed System Requirements ---------------------------- -You need the following software installed: - - postgresql-client, python-dateutil, python-feedparser, python-gdata, - python-ldap, python-libxslt1, python-lxml, python-mako, python-openid, - python-psycopg2, python-pybabel, python-pychart, python-pydot, - python-pyparsing, python-reportlab, python-simplejson, python-tz, - python-vatnumber, python-vobject, python-webdav, python-werkzeug, python-xlwt, - python-yaml, python-zsi +The dependencies are listed in setup.py For Luxembourg localization, you also need: diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py index a1c19914268..491af631202 100644 --- a/openerp/service/__init__.py +++ b/openerp/service/__init__.py @@ -34,7 +34,6 @@ import openerp.netsvc import openerp.osv import openerp.tools import openerp.service.wsgi_server -import openerp.service.workers #.apidoc title: RPC Services @@ -119,6 +118,7 @@ def stop_services(): openerp.modules.registry.RegistryManager.delete_all() def start_services_workers(): + import openerp.service.workers openerp.multi_process = True # Nah! openerp.service.workers.Multicorn(openerp.service.wsgi_server.application).run() diff --git a/openerp/service/workers.py b/openerp/service/workers.py index eae1b2839a8..7bdf45c079f 100644 --- a/openerp/service/workers.py +++ b/openerp/service/workers.py @@ -3,20 +3,17 @@ # TODO rename class: Multicorn -> Arbiter ? #----------------------------------------------------------- import errno -try: - import fcntl -except ImportError: - fcntl = None +import fcntl +import logging +import os import psutil import random import resource import select -import socket -import time -import logging -import os import signal +import socket import sys +import time import werkzeug.serving diff --git a/setup.py b/setup.py new file mode 100755 index 00000000000..45f19ea7a7d --- /dev/null +++ b/setup.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2004-2010 Tiny SPRL (). +# +# 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 . +# +############################################################################## + +import glob, os, re, setuptools, sys +from os.path import join, isfile + +# List all data files +def data(): + files = [] + for root, dirnames, filenames in os.walk('openerp'): + for filename in filenames: + if not re.match(r'.*(\.pyc|\.pyo|\~)$',filename): + files.append(os.path.join(root, filename)) + d = {} + for v in files: + k=os.path.dirname(v) + if k in d: + d[k].append(v) + else: + d[k]=[v] + r = d.items() + if os.name == 'nt': + r.append(("Microsoft.VC90.CRT", glob.glob('C:\Microsoft.VC90.CRT\*.*'))) + + import babel + r.append(("localedata", + glob.glob(os.path.join(os.path.dirname(babel.__file__), "localedata" , '*')))) + + return r + +def gen_manifest(): + file_list="\n".join(data()) + open('MANIFEST','w').write(file_list) + +if os.name == 'nt': + sys.path.append("C:\Microsoft.VC90.CRT") + +def py2exe_options(): + if os.name == 'nt': + import py2exe + return { + "console" : [ { "script": "openerp-server", "icon_resources": [(1, join("install","openerp-icon.ico"))], }], + 'options' : { + "py2exe": { + "skip_archive": 1, + "optimize": 2, + "dist_dir": 'dist', + "packages": [ "DAV", "HTMLParser", "PIL", "asynchat", "asyncore", "commands", "dateutil", "decimal", "email", "encodings", "imaplib", "lxml", "lxml._elementpath", "lxml.builder", "lxml.etree", "lxml.objectify", "mako", "openerp", "poplib", "pychart", "pydot", "pyparsing", "reportlab", "select", "simplejson", "smtplib", "uuid", "vatnumber", "vobject", "xml", "xml.dom", "yaml", ], + "excludes" : ["Tkconstants","Tkinter","tcl"], + } + } + } + else: + return {} + +execfile(join(os.path.dirname(__file__), 'openerp', 'release.py')) + +# Notes for OpenERP developer on windows: +# +# To setup a windows developer evironement install python2.7 then pip and use +# "pip install " for every dependency listed below. +# +# Dependecies that requires DLLs are not installable with pip install, for +# them we added comments with links where you can find the installers. +# +# OpenERP on windows also require the pywin32, the binary can be found at +# http://pywin32.sf.net +# +# Both python2.7 32bits and 64bits are known to work. + +setuptools.setup( + name = 'openerp', + version = version, + description = description, + long_description = long_desc, + url = url, + author = author, + author_email = author_email, + classifiers = filter(None, classifiers.split("\n")), + license = license, + scripts = ['openerp-server'], + data_files = data(), + packages = setuptools.find_packages(), + dependency_links = ['http://download.gna.org/pychart/'], + #include_package_data = True, + install_requires = [ + 'pychart', # not on pypi, use: pip install http://download.gna.org/pychart/PyChart-1.39.tar.gz + 'babel', + 'docutils', + 'feedparser', + 'gdata', + 'lxml < 3', # windows binary http://www.lfd.uci.edu/~gohlke/pythonlibs/ + 'mako', + 'PIL', # windows binary http://www.lfd.uci.edu/~gohlke/pythonlibs/ + 'psutil', # windows binary code.google.com/p/psutil/downloads/list + 'psycopg2', + 'pydot', + 'python-dateutil < 2', + 'python-ldap', # optional + 'python-openid', + 'pytz', + 'pywebdav', + 'pyyaml', + 'reportlab', # windows binary pypi.python.org/pypi/reportlab + 'simplejson', + 'vatnumber', + 'vobject', + 'werkzeug', + 'xlwt', + 'zsi', # optional + ], + extras_require = { + 'SSL' : ['pyopenssl'], + }, + tests_require = ['unittest2'], + **py2exe_options() +) + + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From 1c5e8da2765e51b2c8bb49c6d1bf3c6b55c95dbf Mon Sep 17 00:00:00 2001 From: Launchpad Translations on behalf of openerp <> Date: Wed, 7 Nov 2012 04:55:49 +0000 Subject: [PATCH 702/703] Launchpad automatic translations update. bzr revid: launchpad_translations_on_behalf_of_openerp-20121107043841-l0evnkldw3r700x5 bzr revid: launchpad_translations_on_behalf_of_openerp-20121107045549-xo24icru3zmufl8e --- addons/crm_todo/i18n/es.po | 96 ++++++++++++++++++++++++++++++++++++++ addons/stock/i18n/zh_CN.po | 10 ++-- addons/web/i18n/zh_CN.po | 2 +- 3 files changed, 102 insertions(+), 6 deletions(-) create mode 100644 addons/crm_todo/i18n/es.po diff --git a/addons/crm_todo/i18n/es.po b/addons/crm_todo/i18n/es.po new file mode 100644 index 00000000000..0749835649b --- /dev/null +++ b/addons/crm_todo/i18n/es.po @@ -0,0 +1,96 @@ +# Spanish 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-11-06 15:26+0000\n" +"Last-Translator: FULL NAME \n" +"Language-Team: Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2012-11-07 04:38+0000\n" +"X-Generator: Launchpad (build 16232)\n" + +#. module: crm_todo +#: model:ir.model,name:crm_todo.model_project_task +msgid "Task" +msgstr "Tarea" + +#. module: crm_todo +#: view:crm.lead:0 +msgid "Timebox" +msgstr "Periodo de tiempo" + +#. module: crm_todo +#: view:crm.lead:0 +msgid "For cancelling the task" +msgstr "Para cancelar la tarea" + +#. module: crm_todo +#: constraint:project.task:0 +msgid "Error ! Task end-date must be greater then task start-date" +msgstr "" +"¡ Error ! La fecha final de la tarea debe ser mayor que la fecha de inicio" + +#. module: crm_todo +#: model:ir.model,name:crm_todo.model_crm_lead +msgid "crm.lead" +msgstr "crm.iniciativa" + +#. module: crm_todo +#: view:crm.lead:0 +msgid "Next" +msgstr "Siguiente" + +#. module: crm_todo +#: model:ir.actions.act_window,name:crm_todo.crm_todo_action +#: model:ir.ui.menu,name:crm_todo.menu_crm_todo +msgid "My Tasks" +msgstr "Mis tareas" + +#. module: crm_todo +#: view:crm.lead:0 +#: field:crm.lead,task_ids:0 +msgid "Tasks" +msgstr "Tareas" + +#. module: crm_todo +#: view:crm.lead:0 +msgid "Done" +msgstr "Realizado" + +#. module: crm_todo +#: constraint:project.task:0 +msgid "Error ! You cannot create recursive tasks." +msgstr "¡Error! No se pueden crear tareas recursivas." + +#. module: crm_todo +#: view:crm.lead:0 +msgid "Cancel" +msgstr "Cancelar" + +#. module: crm_todo +#: view:crm.lead:0 +msgid "Extra Info" +msgstr "Información extra" + +#. module: crm_todo +#: field:project.task,lead_id:0 +msgid "Lead / Opportunity" +msgstr "Iniciativa / Oportunidad" + +#. module: crm_todo +#: view:crm.lead:0 +msgid "For changing to done state" +msgstr "Para cambiar a estado 'Realizada'" + +#. module: crm_todo +#: view:crm.lead:0 +msgid "Previous" +msgstr "Anterior" diff --git a/addons/stock/i18n/zh_CN.po b/addons/stock/i18n/zh_CN.po index 9610ef7dc1d..64a500b1cca 100644 --- a/addons/stock/i18n/zh_CN.po +++ b/addons/stock/i18n/zh_CN.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 01:37+0100\n" -"PO-Revision-Date: 2012-06-20 09:34+0000\n" -"Last-Translator: openerp-china.black-jack \n" +"PO-Revision-Date: 2012-11-06 14:21+0000\n" +"Last-Translator: Wei \"oldrev\" Li \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-10-30 04:48+0000\n" -"X-Generator: Launchpad (build 16206)\n" +"X-Launchpad-Export-Date: 2012-11-07 04:38+0000\n" +"X-Generator: Launchpad (build 16232)\n" #. module: stock #: field:product.product,track_outgoing:0 @@ -940,7 +940,7 @@ msgstr "如果您需要在成品库位生产请留空.如在固定地点生产 #. module: stock #: view:res.partner:0 msgid "Inventory Properties" -msgstr "盘点表属性" +msgstr "库存属性" #. module: stock #: field:report.stock.move,day_diff:0 diff --git a/addons/web/i18n/zh_CN.po b/addons/web/i18n/zh_CN.po index d90ed916ffd..09a7d041b88 100644 --- a/addons/web/i18n/zh_CN.po +++ b/addons/web/i18n/zh_CN.po @@ -14,7 +14,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Launchpad-Export-Date: 2012-11-06 05:12+0000\n" +"X-Launchpad-Export-Date: 2012-11-07 04:55+0000\n" "X-Generator: Launchpad (build 16232)\n" #. openerp-web From 385bf30ae34914c06459bd731839867f0d9510dd Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 7 Nov 2012 11:43:48 +0100 Subject: [PATCH 703/703] [REN] lunch: renamed security/groups.xml to meet OpenERP standards and conventions bzr revid: qdp-launchpad@openerp.com-20121107104348-9xkt13jmscamgy34 --- addons/lunch/__openerp__.py | 2 +- addons/lunch/security/{groups.xml => lunch_security.xml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename addons/lunch/security/{groups.xml => lunch_security.xml} (100%) diff --git a/addons/lunch/__openerp__.py b/addons/lunch/__openerp__.py index 5f01d3202da..a70f6d82f9e 100644 --- a/addons/lunch/__openerp__.py +++ b/addons/lunch/__openerp__.py @@ -40,7 +40,7 @@ In addition to a full meal and supplier management, this module offers the possi If you want to save your employees' time and avoid them to always have coins in their pockets, this module is essential. """, - 'data': ['security/groups.xml','lunch_view.xml','wizard/lunch_order_view.xml','wizard/lunch_validation_view.xml','wizard/lunch_cancel_view.xml','lunch_report.xml', + 'data': ['security/lunch_security.xml','lunch_view.xml','wizard/lunch_order_view.xml','wizard/lunch_validation_view.xml','wizard/lunch_cancel_view.xml','lunch_report.xml', 'report/report_lunch_order_view.xml', 'security/ir.model.access.csv',], 'css':['static/src/css/lunch.css'], diff --git a/addons/lunch/security/groups.xml b/addons/lunch/security/lunch_security.xml similarity index 100% rename from addons/lunch/security/groups.xml rename to addons/lunch/security/lunch_security.xml