From 1ff851b10841175f8cc772ef42a2b8d82dabd74c Mon Sep 17 00:00:00 2001 From: Arnaud Fontaine <arnaud.fontaine@nexedi.com> Date: Tue, 24 Dec 2019 17:40:33 +0900 Subject: [PATCH] ZODB Components: Preparation of erp5_base migration from FS: Fix pylint bad-indentation warnings. --- product/ERP5/Document/AgentPrivilege.py | 34 +- product/ERP5/Document/Assignment.py | 34 +- product/ERP5/Document/BankAccount.py | 52 +-- product/ERP5/Document/Career.py | 40 +-- product/ERP5/Document/Coordinate.py | 350 ++++++++++---------- product/ERP5/Document/Image.py | 10 +- product/ERP5/Document/Organisation.py | 38 +-- product/ERP5/Document/Person.py | 336 ++++++++++---------- product/ERP5/Document/RoleDefinition.py | 56 ++-- product/ERP5/Document/SupplyCell.py | 80 ++--- product/ERP5/Document/SupplyLine.py | 404 ++++++++++++------------ product/ERP5/mixin/builder.py | 6 +- 12 files changed, 719 insertions(+), 721 deletions(-) diff --git a/product/ERP5/Document/AgentPrivilege.py b/product/ERP5/Document/AgentPrivilege.py index 9cee24d19c..486aa922a6 100644 --- a/product/ERP5/Document/AgentPrivilege.py +++ b/product/ERP5/Document/AgentPrivilege.py @@ -32,22 +32,22 @@ from Products.ERP5Type.XMLObject import XMLObject class AgentPrivilege(XMLObject): - """ - An Agent Privilege allow the Bank Account owner to give permissions to an Agent for a given period of time, for a maximum amount of money. - """ - # CMF Type Definition - meta_type = 'ERP5 Agent Privilege' - portal_type = 'Agent Privilege' + """ + An Agent Privilege allow the Bank Account owner to give permissions to an Agent for a given period of time, for a maximum amount of money. + """ + # CMF Type Definition + meta_type = 'ERP5 Agent Privilege' + portal_type = 'Agent Privilege' - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) - # Default Properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore - , PropertySheet.Task - , PropertySheet.AgentPrivilege - ) + # Default Properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Task + , PropertySheet.AgentPrivilege + ) diff --git a/product/ERP5/Document/Assignment.py b/product/ERP5/Document/Assignment.py index 76f8ad09da..fd8925eec3 100644 --- a/product/ERP5/Document/Assignment.py +++ b/product/ERP5/Document/Assignment.py @@ -33,22 +33,22 @@ from Products.ERP5.Document.Path import Path class Assignment(Path): - # CMF Type Definition - meta_type = 'ERP5 Assignment' - portal_type = 'Assignment' - add_permission = Permissions.AddPortalContent + # CMF Type Definition + meta_type = 'ERP5 Assignment' + portal_type = 'Assignment' + add_permission = Permissions.AddPortalContent - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) - # Default Properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore - , PropertySheet.Task - , PropertySheet.Arrow - , PropertySheet.Path - , PropertySheet.Assignment - ) + # Default Properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Task + , PropertySheet.Arrow + , PropertySheet.Path + , PropertySheet.Assignment + ) diff --git a/product/ERP5/Document/BankAccount.py b/product/ERP5/Document/BankAccount.py index f6f844388f..0e3dadf976 100644 --- a/product/ERP5/Document/BankAccount.py +++ b/product/ERP5/Document/BankAccount.py @@ -34,43 +34,43 @@ from Products.ERP5.Document.Node import Node from Products.ERP5.Document.Coordinate import Coordinate class BankAccount(Node, Coordinate): - """ + """ A bank account number holds a collection of numbers and codes (ex. SWIFT, RIB, etc.) which may be used to identify a bank account. A Bank Account is owned by a Person or an Organisation. A Bank Account contain Agents with Agent Privileges used by the owner to delegate the management of the bank account to trusted third-party Persons. - """ + """ - meta_type = 'ERP5 Bank Account' - portal_type = 'Bank Account' - add_permission = Permissions.AddPortalContent + meta_type = 'ERP5 Bank Account' + portal_type = 'Bank Account' + add_permission = Permissions.AddPortalContent - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) - # Declarative properties - property_sheets = ( PropertySheet.CategoryCore - , PropertySheet.Task - , PropertySheet.Resource - , PropertySheet.Reference - , PropertySheet.BankAccount - ) + # Declarative properties + property_sheets = ( PropertySheet.CategoryCore + , PropertySheet.Task + , PropertySheet.Resource + , PropertySheet.Reference + , PropertySheet.BankAccount + ) - security.declareProtected(Permissions.AccessContentsInformation, 'getReference') - def getReference(self, *args, **kw): - """reference depends on the site configuration. - """ - value = self._baseGetReference(*args, **kw) - if value in (None, ''): - # Try to get a skin from type name - method = self._getTypeBasedMethod('getReference') - if method is not None: - return method(*args, **kw) - return value + security.declareProtected(Permissions.AccessContentsInformation, 'getReference') + def getReference(self, *args, **kw): + """reference depends on the site configuration. + """ + value = self._baseGetReference(*args, **kw) + if value in (None, ''): + # Try to get a skin from type name + method = self._getTypeBasedMethod('getReference') + if method is not None: + return method(*args, **kw) + return value # XXX The following "helper methods" have been commented out, and kept in the # code as an example. diff --git a/product/ERP5/Document/Career.py b/product/ERP5/Document/Career.py index f839f00b18..a7033012bf 100644 --- a/product/ERP5/Document/Career.py +++ b/product/ERP5/Document/Career.py @@ -33,27 +33,27 @@ from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5.Document.Path import Path class Career(Path): - """ + """ Contains information about abilities, salary, grade, role... of a Person at a certain career step. - """ - # CMF Type Definition - meta_type = 'ERP5 Career' - portal_type = 'Career' - add_permission = Permissions.AddPortalContent + """ + # CMF Type Definition + meta_type = 'ERP5 Career' + portal_type = 'Career' + add_permission = Permissions.AddPortalContent - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) - # Default Properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore - , PropertySheet.Task - , PropertySheet.Arrow - , PropertySheet.Path - , PropertySheet.Reference - , PropertySheet.Assignment - ) + # Default Properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Task + , PropertySheet.Arrow + , PropertySheet.Path + , PropertySheet.Reference + , PropertySheet.Assignment + ) diff --git a/product/ERP5/Document/Coordinate.py b/product/ERP5/Document/Coordinate.py index 8b1dce0ebb..f60aac09d4 100644 --- a/product/ERP5/Document/Coordinate.py +++ b/product/ERP5/Document/Coordinate.py @@ -38,7 +38,7 @@ import re _marker = object() class Coordinate(Base): - """ + """ Coordinates is a mix-in class which is used to store elementary coordinates of an Entity (ex. Person, Organisation) @@ -75,179 +75,177 @@ class Coordinate(Base): In order to be able to list all coordinates of an Entity, a list of Coordinate metatypes has to be defined and stored somewhere. (TODO) - """ - - meta_type = 'ERP5 Coordinate' - portal_type = 'Coordinate' - add_permission = Permissions.AddPortalContent - - # Declarative interface - zope.interface.implements(interfaces.ICoordinate, ) - - # Declarative security (replaces __ac_permissions__) - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) - - # Declarative properties - property_sheets = ( PropertySheet.Base - , PropertySheet.SimpleItem - , PropertySheet.Coordinate - ) - - ### helper methods - security.declareProtected( Permissions.AccessContentsInformation, - 'getRegularExpressionFindAll') - def getRegularExpressionFindAll(self, regular_expression, string): - """ - allows call of re.findall in a python script used for Coordinate - """ - return re.findall(regular_expression, string) - - security.declareProtected( Permissions.AccessContentsInformation, - 'getRegularExpressionGroups') - def getRegularExpressionGroups(self, regular_expression, string): - """ - allows call of re.search.groups in a python script used for Coordinate - """ - match = re.search(regular_expression, string) - if match is None: - return () - return re.search(regular_expression, string).groups() - - ### Mix-in methods - security.declareProtected( Permissions.AccessContentsInformation, - 'asText' ) - def asText(self): - """ - returns the coordinate as a text string - """ - script = self._getTypeBasedMethod('asText') - if script is not None: - return script() - - security.declareProtected( Permissions.AccessContentsInformation, - 'getText') - def getText(self): - """ - calls asText - """ - return self.asText() - - security.declareProtected( Permissions.AccessContentsInformation, - 'hasText') - def hasText(self): - """ - calls asText - """ - return bool(self.asText()) - - security.declareProtected(Permissions.AccessContentsInformation, 'getCoordinateText') - def getCoordinateText(self, default=_marker): - """Fallback on splitted values (old API) - """ - if not self.hasCoordinateText() and self.isDetailed(): - # Display old values (parsed ones) - # empty value is None, not '' - value = self.asText() - if value: - return value - if default is _marker: - return None - else: - return default + """ + + meta_type = 'ERP5 Coordinate' + portal_type = 'Coordinate' + add_permission = Permissions.AddPortalContent + + # Declarative interface + zope.interface.implements(interfaces.ICoordinate, ) + + # Declarative security (replaces __ac_permissions__) + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.SimpleItem + , PropertySheet.Coordinate + ) + + ### helper methods + security.declareProtected( Permissions.AccessContentsInformation, + 'getRegularExpressionFindAll') + def getRegularExpressionFindAll(self, regular_expression, string): + """ + allows call of re.findall in a python script used for Coordinate + """ + return re.findall(regular_expression, string) + + security.declareProtected( Permissions.AccessContentsInformation, + 'getRegularExpressionGroups') + def getRegularExpressionGroups(self, regular_expression, string): + """ + allows call of re.search.groups in a python script used for Coordinate + """ + match = re.search(regular_expression, string) + if match is None: + return () + return re.search(regular_expression, string).groups() + + ### Mix-in methods + security.declareProtected( Permissions.AccessContentsInformation, + 'asText' ) + def asText(self): + """ + returns the coordinate as a text string + """ + script = self._getTypeBasedMethod('asText') + if script is not None: + return script() + + security.declareProtected( Permissions.AccessContentsInformation, + 'getText') + def getText(self): + """ + calls asText + """ + return self.asText() + + security.declareProtected( Permissions.AccessContentsInformation, + 'hasText') + def hasText(self): + """ + calls asText + """ + return bool(self.asText()) + + security.declareProtected(Permissions.AccessContentsInformation, 'getCoordinateText') + def getCoordinateText(self, default=_marker): + """Fallback on splitted values (old API) + """ + if not self.hasCoordinateText() and self.isDetailed(): + # Display old values (parsed ones) + # empty value is None, not '' + value = self.asText() + if value: + return value if default is _marker: - return self._baseGetCoordinateText() - return self._baseGetCoordinateText(default) - - security.declareProtected( Permissions.ModifyPortalContent, 'fromText' ) - @deprecated - def fromText(self, coordinate_text): - """ - modifies the coordinate according to the input text - must be implemented by subclasses - """ - script = self._getTypeBasedMethod('fromText') - if script is not None: - return script(text=coordinate_text) - - security.declareProtected(Permissions.ModifyPortalContent, '_setText') - def _setText(self, value): - """ - calls fromText - """ - return self.fromText(value) - - security.declareProtected( Permissions.AccessContentsInformation, - 'standardTextFormat') - def standardTextFormat(self): - """ - Returns the standard text formats for telephone numbers - """ - pass - - security.declareProtected(Permissions.AccessContentsInformation, 'isDetailed') - def isDetailed(self): - return False - - security.declarePrivate( '_writeFromPUT' ) - def _writeFromPUT( self, body ): - headers = {} - headers, body = parseHeadersBody(body, headers) - lines = body.split( '\n' ) - self.edit( lines[0] ) - headers['Format'] = self.COORDINATE_FORMAT - new_subject = keywordsplitter(headers) - headers['Subject'] = new_subject or self.Subject() - haveheader = headers.has_key - for key, value in self.getMetadataHeaders(): - if key != 'Format' and not haveheader(key): - headers[key] = value - - self._editMetadata(title=headers['Title'], - subject=headers['Subject'], - description=headers['Description'], - contributors=headers['Contributors'], - effective_date=headers['Effective_date'], - expiration_date=headers['Expiration_date'], - format=headers['Format'], - language=headers['Language'], - rights=headers['Rights'], - ) - - ## FTP handlers - security.declareProtected( Permissions.ModifyPortalContent, 'PUT') - def PUT(self, REQUEST, RESPONSE): - """ - Handle HTTP / WebDAV / FTP PUT requests. - """ - self.dav__init(REQUEST, RESPONSE) - self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) - if REQUEST.environ['REQUEST_METHOD'] != 'PUT': - raise Forbidden, 'REQUEST_METHOD should be PUT.' - body = REQUEST.get('BODY', '') - try: - self._writeFromPUT( body ) - RESPONSE.setStatus(204) - return RESPONSE - except ResourceLockedError: - get_transaction().abort() - RESPONSE.setStatus(423) - return RESPONSE - - security.declareProtected( Permissions.View, 'manage_FTPget' ) - def manage_FTPget(self): - """ - Get the coordinate as text for WebDAV src / FTP download. - """ - hdrlist = self.getMetadataHeaders() - hdrtext = formatRFC822Headers( hdrlist ) - bodytext = '%s\n\n%s' % ( hdrtext, self.asText() ) - - return bodytext - - security.declareProtected( Permissions.View, 'get_size' ) - def get_size( self ): - """ - Used for FTP and apparently the ZMI now too - """ - return len(self.manage_FTPget()) + return None + else: + return default + if default is _marker: + return self._baseGetCoordinateText() + return self._baseGetCoordinateText(default) + + security.declareProtected( Permissions.ModifyPortalContent, 'fromText' ) + @deprecated + def fromText(self, coordinate_text): + """ + modifies the coordinate according to the input text + must be implemented by subclasses + """ + script = self._getTypeBasedMethod('fromText') + if script is not None: + return script(text=coordinate_text) + + security.declareProtected(Permissions.ModifyPortalContent, '_setText') + def _setText(self, value): + """ + calls fromText + """ + return self.fromText(value) + + security.declareProtected( Permissions.AccessContentsInformation, + 'standardTextFormat') + def standardTextFormat(self): + """ + Returns the standard text formats for telephone numbers + """ + pass + + security.declareProtected(Permissions.AccessContentsInformation, 'isDetailed') + def isDetailed(self): + return False + + security.declarePrivate( '_writeFromPUT' ) + def _writeFromPUT( self, body ): + headers, body = parseHeadersBody(body, headers) + lines = body.split( '\n' ) + self.edit( lines[0] ) + headers['Format'] = self.COORDINATE_FORMAT + new_subject = keywordsplitter(headers) + headers['Subject'] = new_subject or self.Subject() + haveheader = headers.has_key + for key, value in self.getMetadataHeaders(): + if key != 'Format' and not haveheader(key): + headers[key] = value + self._editMetadata(title=headers['Title'], + subject=headers['Subject'], + description=headers['Description'], + contributors=headers['Contributors'], + effective_date=headers['Effective_date'], + expiration_date=headers['Expiration_date'], + format=headers['Format'], + language=headers['Language'], + rights=headers['Rights'], + ) + + ## FTP handlers + security.declareProtected( Permissions.ModifyPortalContent, 'PUT') + def PUT(self, REQUEST, RESPONSE): + """ + Handle HTTP / WebDAV / FTP PUT requests. + """ + self.dav__init(REQUEST, RESPONSE) + self.dav__simpleifhandler(REQUEST, RESPONSE, refresh=1) + if REQUEST.environ['REQUEST_METHOD'] != 'PUT': + raise Forbidden, 'REQUEST_METHOD should be PUT.' + body = REQUEST.get('BODY', '') + try: + self._writeFromPUT( body ) + RESPONSE.setStatus(204) + return RESPONSE + except ResourceLockedError: + get_transaction().abort() + RESPONSE.setStatus(423) + return RESPONSE + + security.declareProtected( Permissions.View, 'manage_FTPget' ) + def manage_FTPget(self): + """ + Get the coordinate as text for WebDAV src / FTP download. + """ + hdrlist = self.getMetadataHeaders() + hdrtext = formatRFC822Headers( hdrlist ) + bodytext = '%s\n\n%s' % ( hdrtext, self.asText() ) + + return bodytext + + security.declareProtected( Permissions.View, 'get_size' ) + def get_size( self ): + """ + Used for FTP and apparently the ZMI now too + """ + return len(self.manage_FTPget()) diff --git a/product/ERP5/Document/Image.py b/product/ERP5/Document/Image.py index b17073a735..19b30869ba 100644 --- a/product/ERP5/Document/Image.py +++ b/product/ERP5/Document/Image.py @@ -204,7 +204,7 @@ class Image(TextConvertableMixin, File, OFSImage): """Return list of HTML <a> tags for displays.""" links = [] for display in self.displayIds(exclude): - links.append('<a href="%s?display=%s">%s</a>' % (self.REQUEST['URL'], display, display)) + links.append('<a href="%s?display=%s">%s</a>' % (self.REQUEST['URL'], display, display)) return links security.declareProtected(Permissions.AccessContentsInformation, 'displayMap') @@ -367,11 +367,11 @@ class Image(TextConvertableMixin, File, OFSImage): cwd='/', close_fds=True) try: - # XXX: The only portable way is to pass what stdin.write can accept, - # which is a string for PIPE. - image, err = process.communicate(data) + # XXX: The only portable way is to pass what stdin.write can accept, + # which is a string for PIPE. + image, err = process.communicate(data) finally: - del process + del process if image: return StringIO(image) raise ConversionError('Image conversion failed (%s).' % err) diff --git a/product/ERP5/Document/Organisation.py b/product/ERP5/Document/Organisation.py index 4b9b7783aa..db876acb4b 100644 --- a/product/ERP5/Document/Organisation.py +++ b/product/ERP5/Document/Organisation.py @@ -33,7 +33,7 @@ from Products.ERP5Type import Permissions, PropertySheet, interfaces from Products.ERP5.Document.Node import Node class Organisation(Node): - """ + """ An Organisation object holds the information about an organisation (ex. a division in a company, a company, a service in a public administration). @@ -46,27 +46,27 @@ class Organisation(Node): Organisation objects inherit from the MetaNode base class (one of the 5 base classes in the ERP5 universal business model) - """ + """ - meta_type = 'ERP5 Organisation' - portal_type = 'Organisation' - add_permission = Permissions.AddPortalContent + meta_type = 'ERP5 Organisation' + portal_type = 'Organisation' + add_permission = Permissions.AddPortalContent - zope.interface.implements(interfaces.INode) + zope.interface.implements(interfaces.INode) - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) - # Declarative properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore - , PropertySheet.Organisation - , PropertySheet.Mapping - , PropertySheet.Task - , PropertySheet.Reference - ) + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Organisation + , PropertySheet.Mapping + , PropertySheet.Task + , PropertySheet.Reference + ) diff --git a/product/ERP5/Document/Person.py b/product/ERP5/Document/Person.py index 5faf138739..eb21bbb2ef 100644 --- a/product/ERP5/Document/Person.py +++ b/product/ERP5/Document/Person.py @@ -50,7 +50,7 @@ class UserExistsError(ValidationFailed): super(UserExistsError, self).__init__('user id %s already exists' % (user_id, )) class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin, ERP5UserMixin): - """ + """ An Person object holds the information about an person (ex. you, me, someone in the company, someone outside of the company, a member of the portal, @@ -64,194 +64,194 @@ class Person(Node, LoginAccountProviderMixin, EncryptedPasswordMixin, ERP5UserMi Person objects inherit from the Node base class (one of the 5 base classes in the ERP5 universal business model) - """ + """ - meta_type = 'ERP5 Person' - portal_type = 'Person' - add_permission = Permissions.AddPortalContent + meta_type = 'ERP5 Person' + portal_type = 'Person' + add_permission = Permissions.AddPortalContent - zope.interface.implements(interfaces.INode) + zope.interface.implements(interfaces.INode) - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) - # Declarative properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore - , PropertySheet.Reference - , PropertySheet.Person - , PropertySheet.Login - , PropertySheet.Mapping - , PropertySheet.Task - ) + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Reference + , PropertySheet.Person + , PropertySheet.Login + , PropertySheet.Mapping + , PropertySheet.Task + ) - security.declareProtected(Permissions.AccessContentsInformation, - 'getTitle') - def getTitle(self, **kw): - """ - Returns the title if it exists or a combination of - first name, middle name and last name - """ - title = ' '.join([x for x in (self.getFirstName(), - self.getMiddleName(), - self.getLastName()) if x]) - if title: - return title - return super(Person, self).getTitle(**kw) + security.declareProtected(Permissions.AccessContentsInformation, + 'getTitle') + def getTitle(self, **kw): + """ + Returns the title if it exists or a combination of + first name, middle name and last name + """ + title = ' '.join([x for x in (self.getFirstName(), + self.getMiddleName(), + self.getLastName()) if x]) + if title: + return title + return super(Person, self).getTitle(**kw) - security.declareProtected(Permissions.AccessContentsInformation, - 'getTranslatedTitle') - def getTranslatedTitle(self, **kw): - """ - Returns the title if it exists or a combination of - first name, middle name and last name - """ - title = ' '.join([x for x in (self.getTranslatedFirstName(**kw), - self.getTranslatedMiddleName(**kw), - self.getTranslatedLastName(**kw)) if x]) - if title: - return title - return super(Person, self).getTranslatedTitle(**kw) + security.declareProtected(Permissions.AccessContentsInformation, + 'getTranslatedTitle') + def getTranslatedTitle(self, **kw): + """ + Returns the title if it exists or a combination of + first name, middle name and last name + """ + title = ' '.join([x for x in (self.getTranslatedFirstName(**kw), + self.getTranslatedMiddleName(**kw), + self.getTranslatedLastName(**kw)) if x]) + if title: + return title + return super(Person, self).getTranslatedTitle(**kw) - security.declareProtected(Permissions.AccessContentsInformation, - 'title_or_id') - def title_or_id(self): - return self.getTitleOrId() + security.declareProtected(Permissions.AccessContentsInformation, + 'title_or_id') + def title_or_id(self): + return self.getTitleOrId() - security.declareProtected(Permissions.AccessContentsInformation, - 'hasTitle') - def hasTitle(self): - return self.hasFirstName() or \ - self.hasLastName() or \ - self.hasMiddleName() or \ - self._baseHasTitle() + security.declareProtected(Permissions.AccessContentsInformation, + 'hasTitle') + def hasTitle(self): + return self.hasFirstName() or \ + self.hasLastName() or \ + self.hasMiddleName() or \ + self._baseHasTitle() - def __checkUserIdAvailability(self, pas_plugin_class, user_id=None, login=None): - # Encode reference to hex to prevent uppercase/lowercase conflict in - # activity table (when calling countMessageWithTag) - if user_id: - tag = 'set_userid_' + user_id.encode('hex') + def __checkUserIdAvailability(self, pas_plugin_class, user_id=None, login=None): + # Encode reference to hex to prevent uppercase/lowercase conflict in + # activity table (when calling countMessageWithTag) + if user_id: + tag = 'set_userid_' + user_id.encode('hex') + else: + tag = 'set_login_' + login.encode('hex') + # Check that there no existing user + acl_users = getattr(self, 'acl_users', None) + if PluggableAuthService is not None and isinstance(acl_users, + PluggableAuthService.PluggableAuthService.PluggableAuthService): + plugin_name_set = { + plugin_name for plugin_name, plugin_value in acl_users.plugins.listPlugins( + PluggableAuthService.interfaces.plugins.IUserEnumerationPlugin, + ) if isinstance(plugin_value, pas_plugin_class) + } + if plugin_name_set: + if any( + user['pluginid'] in plugin_name_set + for user in acl_users.searchUsers( + id=user_id, + login=login, + exact_match=True, + ) + ): + raise UserExistsError(user_id) else: - tag = 'set_login_' + login.encode('hex') - # Check that there no existing user - acl_users = getattr(self, 'acl_users', None) - if PluggableAuthService is not None and isinstance(acl_users, - PluggableAuthService.PluggableAuthService.PluggableAuthService): - plugin_name_set = { - plugin_name for plugin_name, plugin_value in acl_users.plugins.listPlugins( - PluggableAuthService.interfaces.plugins.IUserEnumerationPlugin, - ) if isinstance(plugin_value, pas_plugin_class) - } - if plugin_name_set: - if any( - user['pluginid'] in plugin_name_set - for user in acl_users.searchUsers( - id=user_id, - login=login, - exact_match=True, - ) - ): - raise UserExistsError(user_id) - else: - # PAS is used, without expected enumeration plugin: property has no - # effect on user enumeration, skip checks. - # XXX: what if desired plugin becomes active later ? - return - # Check that there is no reindexation related to reference indexation - if self.getPortalObject().portal_activities.countMessageWithTag(tag): - raise UserExistsError(user_id) + # PAS is used, without expected enumeration plugin: property has no + # effect on user enumeration, skip checks. + # XXX: what if desired plugin becomes active later ? + return + # Check that there is no reindexation related to reference indexation + if self.getPortalObject().portal_activities.countMessageWithTag(tag): + raise UserExistsError(user_id) - # Prevent concurrent transaction to set the same reference on 2 - # different persons - # XXX: person_module is rather large because of all permission - # declarations, it would be better to find a smaller document to use - # here. - self.getParentValue().serialize() - # Prevent to set the same reference on 2 different persons during the - # same transaction - transactional_variable = getTransactionalVariable() - if tag in transactional_variable: - raise UserExistsError(user_id) - else: - transactional_variable[tag] = None - self.reindexObject(activate_kw={'tag': tag}) + # Prevent concurrent transaction to set the same reference on 2 + # different persons + # XXX: person_module is rather large because of all permission + # declarations, it would be better to find a smaller document to use + # here. + self.getParentValue().serialize() + # Prevent to set the same reference on 2 different persons during the + # same transaction + transactional_variable = getTransactionalVariable() + if tag in transactional_variable: + raise UserExistsError(user_id) + else: + transactional_variable[tag] = None + self.reindexObject(activate_kw={'tag': tag}) - def _setReference(self, value): - """ - Set the user id. This method is defined explicitly, because - we want to prevent duplicated user ids, but only when - PAS _AND_ ERP5UserManager are used - """ - if value != self.getReference(): - if value: - self.__checkUserIdAvailability( - pas_plugin_class=ERP5UserManager, - login=value, - ) - self._baseSetReference(value) - # invalid the cache for ERP5Security - self.getPortalObject().portal_caches.clearCache(cache_factory_list=('erp5_content_short', )) + def _setReference(self, value): + """ + Set the user id. This method is defined explicitly, because + we want to prevent duplicated user ids, but only when + PAS _AND_ ERP5UserManager are used + """ + if value != self.getReference(): + if value: + self.__checkUserIdAvailability( + pas_plugin_class=ERP5UserManager, + login=value, + ) + self._baseSetReference(value) + # invalid the cache for ERP5Security + self.getPortalObject().portal_caches.clearCache(cache_factory_list=('erp5_content_short', )) - def _setUserId(self, value): - """ - Set the user id. This method is defined explicitly, because: + def _setUserId(self, value): + """ + Set the user id. This method is defined explicitly, because: - - we want to apply a different permission + - we want to apply a different permission - - we want to prevent duplicated user ids, but only when - PAS _AND_ ERP5LoginUserManager are used - """ - if value != self.getUserId(): - if value: - self.__checkUserIdAvailability( - pas_plugin_class=ERP5LoginUserManager, - user_id=value, - ) - self._baseSetUserId(value) + - we want to prevent duplicated user ids, but only when + PAS _AND_ ERP5LoginUserManager are used + """ + if value != self.getUserId(): + if value: + self.__checkUserIdAvailability( + pas_plugin_class=ERP5LoginUserManager, + user_id=value, + ) + self._baseSetUserId(value) - # Time management - security.declareProtected(Permissions.AccessContentsInformation, - 'getAvailableTime') - def getAvailableTime(self, *args, **kw): - """ - Calculate available time for a person + # Time management + security.declareProtected(Permissions.AccessContentsInformation, + 'getAvailableTime') + def getAvailableTime(self, *args, **kw): + """ + Calculate available time for a person - See SimulationTool.getAvailableTime - """ - kw['node'] = [self.getUid()] + See SimulationTool.getAvailableTime + """ + kw['node'] = [self.getUid()] - portal_simulation = self.getPortalObject().portal_simulation - return portal_simulation.getAvailableTime(*args, **kw) + portal_simulation = self.getPortalObject().portal_simulation + return portal_simulation.getAvailableTime(*args, **kw) - security.declareProtected(Permissions.AccessContentsInformation, - 'getAvailableTimeSequence') - def getAvailableTimeSequence(self, *args, **kw): - """ - Calculate available time for a person in a sequence + security.declareProtected(Permissions.AccessContentsInformation, + 'getAvailableTimeSequence') + def getAvailableTimeSequence(self, *args, **kw): + """ + Calculate available time for a person in a sequence - See SimulationTool.getAvailableTimeSequence - """ - kw['node'] = [self.getUid()] + See SimulationTool.getAvailableTimeSequence + """ + kw['node'] = [self.getUid()] - portal_simulation = self.getPortalObject().portal_simulation - return portal_simulation.getAvailableTimeSequence(*args, **kw) + portal_simulation = self.getPortalObject().portal_simulation + return portal_simulation.getAvailableTimeSequence(*args, **kw) - # Notifiation API - security.declareProtected(Permissions.AccessContentsInformation, - 'notifyMessage') - def notifyMessage(self, message): - """ - This method can only be called with proxy roles. + # Notifiation API + security.declareProtected(Permissions.AccessContentsInformation, + 'notifyMessage') + def notifyMessage(self, message): + """ + This method can only be called with proxy roles. - A per user preference allows for deciding how to be notified. - - by email - - by SMS (if meaningful) - - daily - - weekly - - instantly + A per user preference allows for deciding how to be notified. + - by email + - by SMS (if meaningful) + - daily + - weekly + - instantly - notification is handled as an activity - """ + notification is handled as an activity + """ diff --git a/product/ERP5/Document/RoleDefinition.py b/product/ERP5/Document/RoleDefinition.py index 3cb735096c..837720856b 100644 --- a/product/ERP5/Document/RoleDefinition.py +++ b/product/ERP5/Document/RoleDefinition.py @@ -33,36 +33,36 @@ from Products.ERP5Type.ERP5Type \ import ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT class RoleDefinition(XMLObject): - # CMF Type Definition - meta_type = 'ERP5 Role Definition' - portal_type = 'Role Definition' - add_permission = Permissions.ChangeLocalRoles + # CMF Type Definition + meta_type = 'ERP5 Role Definition' + portal_type = 'Role Definition' + add_permission = Permissions.ChangeLocalRoles - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) - zope.interface.implements(interfaces.ILocalRoleGenerator) + zope.interface.implements(interfaces.ILocalRoleGenerator) - # Default Properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore - , PropertySheet.RoleDefinition - ) + # Default Properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.RoleDefinition + ) - def _setRoleName(self, value): - if value and value not in \ - zip(*self.RoleDefinition_getRoleNameItemList())[1]: - raise Unauthorized("You are not allowed to give %s role" % value) - self._baseSetRoleName(value) + def _setRoleName(self, value): + if value and value not in \ + zip(*self.RoleDefinition_getRoleNameItemList())[1]: + raise Unauthorized("You are not allowed to give %s role" % value) + self._baseSetRoleName(value) - security.declarePrivate("getLocalRolesFor") - def getLocalRolesFor(self, ob, user_name=None): - group_id_generator = getattr(ob, - ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT) - role_list = self.getRoleName(), - return {group_id: role_list - for group_id in group_id_generator(category_order=('agent',), - agent=self.getAgentList())} + security.declarePrivate("getLocalRolesFor") + def getLocalRolesFor(self, ob, user_name=None): + group_id_generator = getattr(ob, + ERP5TYPE_SECURITY_GROUP_ID_GENERATION_SCRIPT) + role_list = self.getRoleName(), + return {group_id: role_list + for group_id in group_id_generator(category_order=('agent',), + agent=self.getAgentList())} diff --git a/product/ERP5/Document/SupplyCell.py b/product/ERP5/Document/SupplyCell.py index 67dfabf69a..e5ce572f71 100644 --- a/product/ERP5/Document/SupplyCell.py +++ b/product/ERP5/Document/SupplyCell.py @@ -32,49 +32,49 @@ from Products.ERP5Type import Permissions, PropertySheet from Products.ERP5.Document.Path import Path class SupplyCell(Path): - """A Supply Cell is used for different variations in a supply line. - """ + """A Supply Cell is used for different variations in a supply line. + """ - meta_type = 'ERP5 Supply Cell' - portal_type = 'Supply Cell' - add_permission = Permissions.AddPortalContent + meta_type = 'ERP5 Supply Cell' + portal_type = 'Supply Cell' + add_permission = Permissions.AddPortalContent - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) - # Declarative properties - property_sheets = ( PropertySheet.Base - , PropertySheet.CategoryCore - , PropertySheet.Amount - , PropertySheet.Task - , PropertySheet.Movement - , PropertySheet.Price - , PropertySheet.SupplyLine - , PropertySheet.Discount - , PropertySheet.Path - , PropertySheet.FlowCapacity - , PropertySheet.Predicate - , PropertySheet.MappedValue - , PropertySheet.Reference - ) + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.CategoryCore + , PropertySheet.Amount + , PropertySheet.Task + , PropertySheet.Movement + , PropertySheet.Price + , PropertySheet.SupplyLine + , PropertySheet.Discount + , PropertySheet.Path + , PropertySheet.FlowCapacity + , PropertySheet.Predicate + , PropertySheet.MappedValue + , PropertySheet.Reference + ) - security.declareProtected( Permissions.AccessContentsInformation, - 'hasCellContent' ) - def hasCellContent(self, base_id='movement'): - """A cell cannot have cell content itself. - """ - return 0 + security.declareProtected( Permissions.AccessContentsInformation, + 'hasCellContent' ) + def hasCellContent(self, base_id='movement'): + """A cell cannot have cell content itself. + """ + return 0 - # Override getQuantityUnitXXX to negate same methods defined in - # Amount class. Because cell must acquire quantity unit from line - # not from resource. - security.declareProtected( Permissions.AccessContentsInformation, - 'getQuantityUnitValue') - def getQuantityUnitValue(self): - return self.getParentValue().getQuantityUnitValue() + # Override getQuantityUnitXXX to negate same methods defined in + # Amount class. Because cell must acquire quantity unit from line + # not from resource. + security.declareProtected( Permissions.AccessContentsInformation, + 'getQuantityUnitValue') + def getQuantityUnitValue(self): + return self.getParentValue().getQuantityUnitValue() - security.declareProtected( Permissions.AccessContentsInformation, - 'getQuantityUnit') - def getQuantityUnit(self, checked_permission=None): - return self.getParentValue().getQuantityUnit(checked_permission=checked_permission) + security.declareProtected( Permissions.AccessContentsInformation, + 'getQuantityUnit') + def getQuantityUnit(self, checked_permission=None): + return self.getParentValue().getQuantityUnit(checked_permission=checked_permission) diff --git a/product/ERP5/Document/SupplyLine.py b/product/ERP5/Document/SupplyLine.py index 49d1f7f545..fb03b50f4a 100644 --- a/product/ERP5/Document/SupplyLine.py +++ b/product/ERP5/Document/SupplyLine.py @@ -37,208 +37,208 @@ from Products.ERP5Type.Utils import convertToUpperCase class SupplyLine(Path, Amount, XMLMatrix): - """A Supply Line is a path to define price - """ - - meta_type = 'ERP5 Supply Line' - portal_type = 'Supply Line' - add_permission = Permissions.AddPortalContent - isPredicate = ConstantGetter('isPredicate', value=True) - - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) - - # Declarative properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.Amount - , PropertySheet.Task - , PropertySheet.Arrow - , PropertySheet.Movement - , PropertySheet.Price - , PropertySheet.SupplyLine - , PropertySheet.VariationRange - , PropertySheet.Path - , PropertySheet.FlowCapacity - , PropertySheet.Predicate - , PropertySheet.Comment - , PropertySheet.Reference - ) - - ############################################# - # Pricing methods - ############################################# - security.declareProtected(Permissions.AccessContentsInformation, - 'getPrice') - def getPrice(self): - # FIXME: this have to be done in an interaction wf - if getattr(self, 'price', None) is None: - self.price = 0.0 - # Return the price - return self.price - - security.declareProtected(Permissions.AccessContentsInformation, - 'getTotalPrice') - def getTotalPrice(self): - """ - Returns the totals price for this line - """ - quantity = self.getQuantity() or 0.0 - price = self.getPrice() or 0.0 - return quantity * price - - def _getPrice(self, context): - return 0.0 - - def _getTotalPrice(self, context): - return 0.0 - - security.declareProtected(Permissions.AccessContentsInformation, - 'isAccountable') - def isAccountable(self): - """Supply Line are not accounted. - """ - return 0 - - ############################################# - # Predicate method - ############################################# - asPredicate = Path.asPredicate - - ############################################# - # XMLMatrix methods - # XXX to be removed if possible - ############################################# - security.declareProtected(Permissions.AccessContentsInformation, - 'hasCellContent') - def hasCellContent(self, base_id='path'): - """ - This method can be overriden - """ - return XMLMatrix.hasCellContent(self, base_id=base_id) - - security.declareProtected(Permissions.AccessContentsInformation, - 'getCellValueList' ) - def getCellValueList(self, base_id='path'): - """ - This method can be overriden - """ - return XMLMatrix.getCellValueList(self, base_id=base_id) - - security.declareProtected(Permissions.AccessContentsInformation, 'getCell') - def getCell(self, *kw , **kwd): - """ - This method can be overriden - """ - kwd.setdefault('base_id', 'path') - return XMLMatrix.getCell(self, *kw, **kwd) - - security.declareProtected(Permissions.ModifyPortalContent, 'newCell') - def newCell(self, *kw, **kwd): - """ - This method creates a new cell - """ - kwd.setdefault('base_id', 'path') - return XMLMatrix.newCell(self, *kw, **kwd) - - ############################################################ - # Quantity predicate API - ############################################################ - security.declareProtected(Permissions.AccessContentsInformation, - 'getQuantityPredicateIdList') - def getQuantityPredicateIdList(self, price_parameter): - """ - Return predicate id related to a price parameter. - """ - predicate_id_start_with = "quantity_range_" - if price_parameter not in ("base_price", "slice_base_price"): - predicate_id_start_with = "%s_%s" % \ - (price_parameter, predicate_id_start_with) - # XXX Hardcoded portal type name - predicate_list = self.objectValues(portal_type='Predicate', - sort_on=('int_index', 'id')) - predicate_list.sort(key=lambda p: p.getIntIndex() or p.getId()) - predicate_id_list = [x.getId() for x in predicate_list] - result = [x for x in predicate_id_list \ + """A Supply Line is a path to define price + """ + + meta_type = 'ERP5 Supply Line' + portal_type = 'Supply Line' + add_permission = Permissions.AddPortalContent + isPredicate = ConstantGetter('isPredicate', value=True) + + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + # Declarative properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.Amount + , PropertySheet.Task + , PropertySheet.Arrow + , PropertySheet.Movement + , PropertySheet.Price + , PropertySheet.SupplyLine + , PropertySheet.VariationRange + , PropertySheet.Path + , PropertySheet.FlowCapacity + , PropertySheet.Predicate + , PropertySheet.Comment + , PropertySheet.Reference + ) + + ############################################# + # Pricing methods + ############################################# + security.declareProtected(Permissions.AccessContentsInformation, + 'getPrice') + def getPrice(self): + # FIXME: this have to be done in an interaction wf + if getattr(self, 'price', None) is None: + self.price = 0.0 + # Return the price + return self.price + + security.declareProtected(Permissions.AccessContentsInformation, + 'getTotalPrice') + def getTotalPrice(self): + """ + Returns the totals price for this line + """ + quantity = self.getQuantity() or 0.0 + price = self.getPrice() or 0.0 + return quantity * price + + def _getPrice(self, context): + return 0.0 + + def _getTotalPrice(self, context): + return 0.0 + + security.declareProtected(Permissions.AccessContentsInformation, + 'isAccountable') + def isAccountable(self): + """Supply Line are not accounted. + """ + return 0 + + ############################################# + # Predicate method + ############################################# + asPredicate = Path.asPredicate + + ############################################# + # XMLMatrix methods + # XXX to be removed if possible + ############################################# + security.declareProtected(Permissions.AccessContentsInformation, + 'hasCellContent') + def hasCellContent(self, base_id='path'): + """ + This method can be overriden + """ + return XMLMatrix.hasCellContent(self, base_id=base_id) + + security.declareProtected(Permissions.AccessContentsInformation, + 'getCellValueList' ) + def getCellValueList(self, base_id='path'): + """ + This method can be overriden + """ + return XMLMatrix.getCellValueList(self, base_id=base_id) + + security.declareProtected(Permissions.AccessContentsInformation, 'getCell') + def getCell(self, *kw , **kwd): + """ + This method can be overriden + """ + kwd.setdefault('base_id', 'path') + return XMLMatrix.getCell(self, *kw, **kwd) + + security.declareProtected(Permissions.ModifyPortalContent, 'newCell') + def newCell(self, *kw, **kwd): + """ + This method creates a new cell + """ + kwd.setdefault('base_id', 'path') + return XMLMatrix.newCell(self, *kw, **kwd) + + ############################################################ + # Quantity predicate API + ############################################################ + security.declareProtected(Permissions.AccessContentsInformation, + 'getQuantityPredicateIdList') + def getQuantityPredicateIdList(self, price_parameter): + """ + Return predicate id related to a price parameter. + """ + predicate_id_start_with = "quantity_range_" + if price_parameter not in ("base_price", "slice_base_price"): + predicate_id_start_with = "%s_%s" % \ + (price_parameter, predicate_id_start_with) + # XXX Hardcoded portal type name + predicate_list = self.objectValues(portal_type='Predicate', + sort_on=('int_index', 'id')) + predicate_list.sort(key=lambda p: p.getIntIndex() or p.getId()) + predicate_id_list = [x.getId() for x in predicate_list] + result = [x for x in predicate_id_list \ if x.startswith(predicate_id_start_with)] - return result - - security.declareProtected(Permissions.AccessContentsInformation, - 'getQuantityPredicateValueList') - def getQuantityPredicateValueList(self, price_parameter): - """ - Return predicate related to a price parameter. - """ - result = [self[x] for x in \ - self.getQuantityPredicateIdList(price_parameter)] - return result - - security.declareProtected(Permissions.AccessContentsInformation, - 'getQuantityStepList') - def getQuantityStepList(self, *args, **kw): - """ - Return predicate step related to a price_parameter - """ - # We need to keep compatibility with generated accessor - price_parameter = kw.get('price_parameter', "base_price") - if price_parameter in ("base_price", "slice_base_price"): - method_name = "_baseGetQuantityStepList" - else: - method_name = 'get%sList' % \ - convertToUpperCase("%s_quantity_step" % price_parameter) - return getattr(self, method_name)() or [] - - security.declareProtected(Permissions.ModifyPortalContent, - 'updateQuantityPredicate') - def updateQuantityPredicate(self, price_parameter): - """ - Update the quantity predicate for this price parameter - """ - quantity_step_list = self.getQuantityStepList(price_parameter=price_parameter) - unused_predicate_id_set = self.getQuantityPredicateIdList(price_parameter) - if quantity_step_list: - quantity_step_list.sort() - quantity_step_list = [None] + quantity_step_list + [None] - getTitle = getattr( - self, - 'SupplyLine_getTitle', - lambda min, max: ( - ( - '' if min is None else '%s <= ' % (min, ) - ) + 'quantity' + ( - '' if max is None else ' < %s' % (max, ) - ) - ), - ) - predicate_id_start_with = "quantity_range" - if price_parameter not in ("base_price", "slice_base_price"): - predicate_id_start_with = "%s_%s" % ( - price_parameter, - predicate_id_start_with, + return result + + security.declareProtected(Permissions.AccessContentsInformation, + 'getQuantityPredicateValueList') + def getQuantityPredicateValueList(self, price_parameter): + """ + Return predicate related to a price parameter. + """ + result = [self[x] for x in \ + self.getQuantityPredicateIdList(price_parameter)] + return result + + security.declareProtected(Permissions.AccessContentsInformation, + 'getQuantityStepList') + def getQuantityStepList(self, *args, **kw): + """ + Return predicate step related to a price_parameter + """ + # We need to keep compatibility with generated accessor + price_parameter = kw.get('price_parameter', "base_price") + if price_parameter in ("base_price", "slice_base_price"): + method_name = "_baseGetQuantityStepList" + else: + method_name = 'get%sList' % \ + convertToUpperCase("%s_quantity_step" % price_parameter) + return getattr(self, method_name)() or [] + + security.declareProtected(Permissions.ModifyPortalContent, + 'updateQuantityPredicate') + def updateQuantityPredicate(self, price_parameter): + """ + Update the quantity predicate for this price parameter + """ + quantity_step_list = self.getQuantityStepList(price_parameter=price_parameter) + unused_predicate_id_set = self.getQuantityPredicateIdList(price_parameter) + if quantity_step_list: + quantity_step_list.sort() + quantity_step_list = [None] + quantity_step_list + [None] + getTitle = getattr( + self, + 'SupplyLine_getTitle', + lambda min, max: ( + ( + '' if min is None else '%s <= ' % (min, ) + ) + 'quantity' + ( + '' if max is None else ' < %s' % (max, ) ) - for i in range(len(quantity_step_list) - 1): - min_quantity = quantity_step_list[i] - max_quantity = quantity_step_list[i + 1] - predicate_id = '%s_%s' % (predicate_id_start_with, i) - try: - predicate_value = self[predicate_id] - except KeyError: - # XXX Hardcoded portal type name - predicate_value = self.newContent( - id='%s_%s' % (predicate_id_start_with, i), - portal_type='Predicate', - int_index=i + 1, - ) - else: - unused_predicate_id_set.remove(predicate_id) - predicate_value.setTitle(getTitle(min=min_quantity, max=max_quantity)) - predicate_value.setCriterionPropertyList(('quantity', )) - predicate_value.setCriterion( - 'quantity', - min=min_quantity, - max=(None if price_parameter == 'slice_base_price' else max_quantity), + ), + ) + predicate_id_start_with = "quantity_range" + if price_parameter not in ("base_price", "slice_base_price"): + predicate_id_start_with = "%s_%s" % ( + price_parameter, + predicate_id_start_with, + ) + for i in range(len(quantity_step_list) - 1): + min_quantity = quantity_step_list[i] + max_quantity = quantity_step_list[i + 1] + predicate_id = '%s_%s' % (predicate_id_start_with, i) + try: + predicate_value = self[predicate_id] + except KeyError: + # XXX Hardcoded portal type name + predicate_value = self.newContent( + id='%s_%s' % (predicate_id_start_with, i), + portal_type='Predicate', + int_index=i + 1, ) - if unused_predicate_id_set: - self.deleteContent(unused_predicate_id_set) + else: + unused_predicate_id_set.remove(predicate_id) + predicate_value.setTitle(getTitle(min=min_quantity, max=max_quantity)) + predicate_value.setCriterionPropertyList(('quantity', )) + predicate_value.setCriterion( + 'quantity', + min=min_quantity, + max=(None if price_parameter == 'slice_base_price' else max_quantity), + ) + if unused_predicate_id_set: + self.deleteContent(unused_predicate_id_set) diff --git a/product/ERP5/mixin/builder.py b/product/ERP5/mixin/builder.py index 7667120ffe..a1df524fca 100644 --- a/product/ERP5/mixin/builder.py +++ b/product/ERP5/mixin/builder.py @@ -791,9 +791,9 @@ class BuilderMixin(XMLObject, Amount, Predicate): category_index_dict[i.getId()] = i.getIntIndex() def sort_movement_group(a, b): - return cmp(category_index_dict.get(a.getCollectOrderGroup()), - category_index_dict.get(b.getCollectOrderGroup())) or \ - cmp(a.getIntIndex(), b.getIntIndex()) + return cmp(category_index_dict.get(a.getCollectOrderGroup()), + category_index_dict.get(b.getCollectOrderGroup())) or \ + cmp(a.getIntIndex(), b.getIntIndex()) if portal_type is None: portal_type = self.getPortalMovementGroupTypeList() movement_group_list = [x for x in self.contentValues(filter={'portal_type': portal_type}) \ -- 2.30.9