SAP interface: easy access to SAP results. Bugfix in search method.
This commit is contained in:
		
							parent
							
								
									e89eda4838
								
							
						
					
					
						commit
						2ff08258bc
					
				
					 6 changed files with 61 additions and 10 deletions
				
			
		| 
						 | 
					@ -194,6 +194,7 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
        # field is invisible; we will display it ourselves (like for Ref fields)
 | 
					        # field is invisible; we will display it ourselves (like for Ref fields)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    alwaysAValidatorFor = ('Ref', 'Integer', 'Float')
 | 
					    alwaysAValidatorFor = ('Ref', 'Integer', 'Float')
 | 
				
			||||||
 | 
					    notToValidateFields = ('Info', 'Computed', 'Action')
 | 
				
			||||||
    def walkAppyType(self):
 | 
					    def walkAppyType(self):
 | 
				
			||||||
        '''Walks into the Appy type definition and gathers data about the
 | 
					        '''Walks into the Appy type definition and gathers data about the
 | 
				
			||||||
           Archetype elements to generate.'''
 | 
					           Archetype elements to generate.'''
 | 
				
			||||||
| 
						 | 
					@ -233,13 +234,15 @@ class ArchetypeFieldDescriptor:
 | 
				
			||||||
        # - slaves ?
 | 
					        # - slaves ?
 | 
				
			||||||
        if self.appyType.slaves: self.widgetParams['visible'] = False
 | 
					        if self.appyType.slaves: self.widgetParams['visible'] = False
 | 
				
			||||||
        # Archetypes will believe the field is invisible; we will display it
 | 
					        # Archetypes will believe the field is invisible; we will display it
 | 
				
			||||||
        # ourselves (like for Ref fields)
 | 
					        # ourselves (like for Ref fields).
 | 
				
			||||||
        # - need to generate a field validator?
 | 
					        # - need to generate a field validator?
 | 
				
			||||||
        # In all cases, add an i18n message for the validation error for this
 | 
					        # In all cases excepted for "immutable" fields, add an i18n message for
 | 
				
			||||||
        # field.
 | 
					        # the validation error for this field.
 | 
				
			||||||
 | 
					        if self.appyType.type not in self.notToValidateFields:
 | 
				
			||||||
            label = '%s_%s_valid' % (self.classDescr.name, self.fieldName)
 | 
					            label = '%s_%s_valid' % (self.classDescr.name, self.fieldName)
 | 
				
			||||||
            poMsg = PoMessage(label, '', PoMessage.DEFAULT_VALID_ERROR)
 | 
					            poMsg = PoMessage(label, '', PoMessage.DEFAULT_VALID_ERROR)
 | 
				
			||||||
            self.generator.labels.append(poMsg)
 | 
					            self.generator.labels.append(poMsg)
 | 
				
			||||||
 | 
					        # Generate a validator for the field if needed.
 | 
				
			||||||
        if (type(self.appyType.validator) == types.FunctionType) or \
 | 
					        if (type(self.appyType.validator) == types.FunctionType) or \
 | 
				
			||||||
           (type(self.appyType.validator) == type(String.EMAIL)) or \
 | 
					           (type(self.appyType.validator) == type(String.EMAIL)) or \
 | 
				
			||||||
           (self.appyType.type in self.alwaysAValidatorFor):
 | 
					           (self.appyType.type in self.alwaysAValidatorFor):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,7 +124,8 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
           useful for some usages like knowing the number of objects without
 | 
					           useful for some usages like knowing the number of objects without
 | 
				
			||||||
           needing to get information about them). If no p_maxResults is
 | 
					           needing to get information about them). If no p_maxResults is
 | 
				
			||||||
           specified, the method returns maximum
 | 
					           specified, the method returns maximum
 | 
				
			||||||
           self.getNumberOfResultsPerPage(). p_maxResults is ignored if
 | 
					           self.getNumberOfResultsPerPage(). The method returns all objects if
 | 
				
			||||||
 | 
					           p_maxResults equals string "NO_LIMIT". p_maxResults is ignored if
 | 
				
			||||||
           p_brainsOnly is True.'''
 | 
					           p_brainsOnly is True.'''
 | 
				
			||||||
        # Is there one or several content types ?
 | 
					        # Is there one or several content types ?
 | 
				
			||||||
        if contentType.find(',') != -1:
 | 
					        if contentType.find(',') != -1:
 | 
				
			||||||
| 
						 | 
					@ -164,6 +165,7 @@ class ToolMixin(AbstractMixin):
 | 
				
			||||||
        brains = self.portal_catalog.searchResults(**params)
 | 
					        brains = self.portal_catalog.searchResults(**params)
 | 
				
			||||||
        if brainsOnly: return brains
 | 
					        if brainsOnly: return brains
 | 
				
			||||||
        if not maxResults: maxResults = self.getNumberOfResultsPerPage()
 | 
					        if not maxResults: maxResults = self.getNumberOfResultsPerPage()
 | 
				
			||||||
 | 
					        elif maxResults == 'NO_LIMIT': maxResults = None
 | 
				
			||||||
        res = SomeObjects(brains, maxResults, startNumber)
 | 
					        res = SomeObjects(brains, maxResults, startNumber)
 | 
				
			||||||
        res.brainsToObjects()
 | 
					        res.brainsToObjects()
 | 
				
			||||||
        # In some cases (p_remember=True), we need to keep some information
 | 
					        # In some cases (p_remember=True), we need to keep some information
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -197,7 +197,14 @@ class AbstractMixin:
 | 
				
			||||||
           history, for example).'''
 | 
					           history, for example).'''
 | 
				
			||||||
        # Which value will we use ?
 | 
					        # Which value will we use ?
 | 
				
			||||||
        if useParamValue: v = value
 | 
					        if useParamValue: v = value
 | 
				
			||||||
        else: v = eval('self.%s' % name)
 | 
					        else:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                v = eval('self.%s' % name)
 | 
				
			||||||
 | 
					            except AttributeError:
 | 
				
			||||||
 | 
					                # Probably a newly created attribute.
 | 
				
			||||||
 | 
					                # In this case, return the default value.
 | 
				
			||||||
 | 
					                v = None
 | 
				
			||||||
 | 
					                if appyType: v = appyType['default']
 | 
				
			||||||
        if not appyType: return v
 | 
					        if not appyType: return v
 | 
				
			||||||
        if (v == None) or (v == ''): return v
 | 
					        if (v == None) or (v == ''): return v
 | 
				
			||||||
        vType = appyType['type']
 | 
					        vType = appyType['type']
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -98,7 +98,7 @@
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div metal:define-macro="showInfoField">
 | 
					<div metal:define-macro="showInfoField">
 | 
				
			||||||
  <span class="appyLabel" tal:content="label"></span>
 | 
					  <span class="appyLabel" tal:content="structure label"></span>
 | 
				
			||||||
  <span tal:content="structure description"></span>
 | 
					  <span tal:content="structure description"></span>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -102,6 +102,9 @@ class AbstractWrapper:
 | 
				
			||||||
        key = self.o.workflow_history.keys()[0]
 | 
					        key = self.o.workflow_history.keys()[0]
 | 
				
			||||||
        return self.o.workflow_history[key]
 | 
					        return self.o.workflow_history[key]
 | 
				
			||||||
    history = property(get_history)
 | 
					    history = property(get_history)
 | 
				
			||||||
 | 
					    def get_user(self):
 | 
				
			||||||
 | 
					        return self.o.portal_membership.getAuthenticatedMember()
 | 
				
			||||||
 | 
					    user = property(get_user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def link(self, fieldName, obj):
 | 
					    def link(self, fieldName, obj):
 | 
				
			||||||
        '''This method links p_obj to this one through reference field
 | 
					        '''This method links p_obj to this one through reference field
 | 
				
			||||||
| 
						 | 
					@ -270,6 +273,10 @@ class AbstractWrapper:
 | 
				
			||||||
        contentType = flavour.o.getPortalType(klass)
 | 
					        contentType = flavour.o.getPortalType(klass)
 | 
				
			||||||
        # Create the Search object
 | 
					        # Create the Search object
 | 
				
			||||||
        search = Search('customSearch', sortBy=sortBy, **fields)
 | 
					        search = Search('customSearch', sortBy=sortBy, **fields)
 | 
				
			||||||
 | 
					        if not maxResults:
 | 
				
			||||||
 | 
					            maxResults = 'NO_LIMIT'
 | 
				
			||||||
 | 
					            # If I let maxResults=None, only a subset of the results will be
 | 
				
			||||||
 | 
					            # returned by method executeResult.
 | 
				
			||||||
        res = self.tool.o.executeQuery(contentType,flavour.number,search=search,
 | 
					        res = self.tool.o.executeQuery(contentType,flavour.number,search=search,
 | 
				
			||||||
            maxResults=maxResults)
 | 
					            maxResults=maxResults)
 | 
				
			||||||
        return [o.appy() for o in res['objects']]
 | 
					        return [o.appy() for o in res['objects']]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -32,6 +32,27 @@ try:
 | 
				
			||||||
except ImportError:
 | 
					except ImportError:
 | 
				
			||||||
    hasSap = False
 | 
					    hasSap = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class SapResult:
 | 
				
			||||||
 | 
					    '''Represents a result as returned by SAP. It defines a __getattr__ method
 | 
				
			||||||
 | 
					       that allows to retrieve SAP "output" parameters (export, tables) by their
 | 
				
			||||||
 | 
					       name (as if they were attributes of this class), in a Python format
 | 
				
			||||||
 | 
					       (list, dict, simple value).'''
 | 
				
			||||||
 | 
					    def __init__(self, function):
 | 
				
			||||||
 | 
					        # The pysap function obj that was called and that produced this result.
 | 
				
			||||||
 | 
					        self.function = function
 | 
				
			||||||
 | 
					    def __getattr__(self, name):
 | 
				
			||||||
 | 
					        '''Allows a smart access to self.function's results.'''
 | 
				
			||||||
 | 
					        if name.startswith('__'): raise AttributeError
 | 
				
			||||||
 | 
					        paramValue = self.function[name]
 | 
				
			||||||
 | 
					        paramType = paramValue.__class__.__name__
 | 
				
			||||||
 | 
					        if paramType == 'ItTable':
 | 
				
			||||||
 | 
					            return paramValue.to_list()
 | 
				
			||||||
 | 
					        elif paramType == 'STRUCT':
 | 
				
			||||||
 | 
					            return paramValue.to_dict()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return paramValue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class Sap:
 | 
					class Sap:
 | 
				
			||||||
    '''Represents a remote SAP system. This class allows to connect to a distant
 | 
					    '''Represents a remote SAP system. This class allows to connect to a distant
 | 
				
			||||||
| 
						 | 
					@ -43,6 +64,7 @@ class Sap:
 | 
				
			||||||
        self.user = user
 | 
					        self.user = user
 | 
				
			||||||
        self.password = password
 | 
					        self.password = password
 | 
				
			||||||
        self.sap = None # Will hold the handler to the SAP distant system.
 | 
					        self.sap = None # Will hold the handler to the SAP distant system.
 | 
				
			||||||
 | 
					        self.functionName = None # The name of the next function to call.
 | 
				
			||||||
        if not hasSap: raise SapError(SAP_MODULE_ERROR)
 | 
					        if not hasSap: raise SapError(SAP_MODULE_ERROR)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def connect(self):
 | 
					    def connect(self):
 | 
				
			||||||
| 
						 | 
					@ -84,9 +106,11 @@ class Sap:
 | 
				
			||||||
            res[name.lower()] = v
 | 
					            res[name.lower()] = v
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def call(self, functionName, **params):
 | 
					    def call(self, functionName=None, **params):
 | 
				
			||||||
        '''Calls a function on the SAP server.'''
 | 
					        '''Calls a function on the SAP server.'''
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
 | 
					            if not functionName:
 | 
				
			||||||
 | 
					                functionName = self.functionName
 | 
				
			||||||
            function = self.sap.get_interface(functionName)
 | 
					            function = self.sap.get_interface(functionName)
 | 
				
			||||||
            # Specify the parameters
 | 
					            # Specify the parameters
 | 
				
			||||||
            for name, value in params.iteritems():
 | 
					            for name, value in params.iteritems():
 | 
				
			||||||
| 
						 | 
					@ -118,6 +142,14 @@ class Sap:
 | 
				
			||||||
            function()
 | 
					            function()
 | 
				
			||||||
        except pysap.BaseSapRfcError, se:
 | 
					        except pysap.BaseSapRfcError, se:
 | 
				
			||||||
            raise SapError(SAP_FUNCTION_ERROR % (functionName, str(se)))
 | 
					            raise SapError(SAP_FUNCTION_ERROR % (functionName, str(se)))
 | 
				
			||||||
 | 
					        return SapResult(function)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __getattr__(self, name):
 | 
				
			||||||
 | 
					        '''The user can directly call self.<sapFunctionName>(params) instead of
 | 
				
			||||||
 | 
					           calling self.call(<sapFunctionName>, params).'''
 | 
				
			||||||
 | 
					        if name.startswith('__'): raise AttributeError
 | 
				
			||||||
 | 
					        self.functionName = name
 | 
				
			||||||
 | 
					        return self.call
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getTypeInfo(self, typeName):
 | 
					    def getTypeInfo(self, typeName):
 | 
				
			||||||
        '''Returns information about the type (structure) named p_typeName.'''
 | 
					        '''Returns information about the type (structure) named p_typeName.'''
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue