SAP interface: easy access to SAP results. Bugfix in search method.

This commit is contained in:
Gaetan Delannay 2009-12-21 20:45:29 +01:00
parent e89eda4838
commit 2ff08258bc
6 changed files with 61 additions and 10 deletions

View file

@ -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.
label = '%s_%s_valid' % (self.classDescr.name, self.fieldName) if self.appyType.type not in self.notToValidateFields:
poMsg = PoMessage(label, '', PoMessage.DEFAULT_VALID_ERROR) label = '%s_%s_valid' % (self.classDescr.name, self.fieldName)
self.generator.labels.append(poMsg) poMsg = PoMessage(label, '', PoMessage.DEFAULT_VALID_ERROR)
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):

View file

@ -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

View file

@ -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']

View file

@ -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>

View file

@ -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']]

View file

@ -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.'''