문제

웹 서비스 인터페이스를 사용하여 SAGE CRM 용 Python 소비자를 작성하려고합니다. 나는 Python Soap Library와 같이 너무 행복하게 사용하고 있습니다 (결혼하지 않았으며 Ubuntu에 설치하기가 쉬웠으므로 함께갔습니다).

프록시를 사용하여 WSDL을 가져오고 SAGE CRM에 노출 된 로그온 방법을 실행했습니다.


from SOAPpy import *
proxy = WSDL.Proxy('http://192.168.0.3/MATE/eware.dll/webservice/webservice.wsdl')

일종의 모양이있는 세션 객체를 반환합니다.

SOAPpy.Types.structType result at 151924492: {'sessionid': '170911104429792'}

이제 Sage CRM의 QueryRecord 메소드를 사용하여 데이터를 쿼리하려고합니다.

Fault SOAP-ENV:Server: No active usersession detected

문서를 읽으면 RECD 세션 ID로 다시 보내야합니다. 각 요청에 따라 다시 로그인했을 때

세이지 문서에 따르면 다시 보내야합니다.


SID = binding.logon("admin", ""); 
binding.SessionHeaderValue = new SessionHeader(); 
binding.SessionHeaderValue.sessionId = SID.sessionid;

너무나도 너무나도이 헤더에 이것을 추가하는 방법은 무엇입니까?

모든 포인터는 크게 감사 할 것입니다.

도움이 되었습니까?

해결책

첫째, Soappy vs. 다른 비누 라이브러리에 대해 언급하기 위해서는 ... 전통적으로 복잡한 데이터 구조를 지원하지 않는 사용하기 쉬운 라이브러리였습니다. 그래서 그것이 당신의 사건에 대해 효과가 있다면 당신은 더 나은 것입니다. WSDL의보다 복잡한 데이터 구조의 경우 ZSI를 이동해야합니다.

어쨌든, SourceForge의 프로젝트에 대한 문서 링크가 깨진 것 같습니다. 따라서 약간의 형식 변경 사항으로 헤더 문서를 여기에 붙여 넣습니다.

헤더 사용

SOPAPY에는 비누 메시지의 헤더에 대한 데이터를 보유 할 헤더 클래스가 있습니다. 각 헤더 인스턴스에는 뮬러 이해 속성을 설정/가져 오는 메소드와 액터 속성을 설정/가져 오는 메소드가 있습니다.

SOPAPY에는 또한 SOAPContext 클래스가있어 각 서버 메소드가 연결 클라이언트의 컨텍스트를 얻을 수 있도록 구현할 수 있습니다. 여기에는 일반적인 비누 정보와 연결 정보가 모두 포함됩니다 (예 : 아래 참조).

클라이언트 예

import SOAPpy
test = 42
server = SOAPpy.SOAPProxy("http://localhost:8888")
server = server._sa ("urn:soapinterop")

hd = SOAPpy.Header()
hd.InteropTestHeader ='This should fault, as you don\'t understand the header.'
hd._setMustUnderstand ('InteropTestHeader', 0)
hd._setActor ('InteropTestHeader','http://schemas.xmlsoap.org/soap/actor/next')
server = server._hd (hd)

print server.echoInteger (test)

성공해야합니다 (서버가 Echointeger를 정의한 경우)은 0으로 설정된 송수신자로 유효한 헤더를 구축 한 다음이 헤더로 비누를 보냅니다.

import SOAPpy
test = 42
server = SOAPpy.SOAPProxy("http://localhost:8888")
server = server._sa ("urn:soapinterop")
#Header
hd = SOAPpy.Header()
hd.InteropTestHeader = 'This should fault,as you don\'t understand the header.'
hd._setMustUnderstand ('InteropTestHeader', 1)
hd._setActor ('InteropTestHeader','http://schemas.xmlsoap.org/soap/actor/next')
server = server._hd (hd)

print server.echoInteger (test)

이 클라이언트에 유효한 헤더를 구축하기 때문에 서버가 'Echointeger'를 정의하더라도 실패하지만 서버가 전송하기 전에 서버가 이해하지 못하는 메시지에 대해 1로 무병을 설정합니다.

다른 팁

이것도 이것을 알아 내고 있습니다. 나는 이것의 핵심을 가지고 있기 때문에, 이것은 이것을 필요로하는 다른 사람에게는 속도를 높여야합니다! 나는 다른 Sage 서브 시스템이 같은 방식으로 작동한다고 가정하고 있지만 아직 모르겠다. 그래서 나는 그 가능성을 설명하려고 노력했다.

먼저 Pysage.py라는이 모듈이 필요합니다. 사용자 정의 사용을 위해 서브 클래스가 필요한 프로세스를 실행하기위한 클래스를 정의합니다.

#----------------------------
#
# pySage.py
#
# Author: BuvinJ
# Created: December, 2015
#
# This module defines the SageProcess class.
# This class handles connecting and disconnecting
# to Sage web services, and provides an object
# through which the web services can be accessed.
#
#----------------------------

# Download SOAPpy from: https://pypi.python.org/pypi/SOAPpy
from SOAPpy import WSDL, Types as soapTypes

from enum import Enum
SageSubsystem = Enum( 'SageSubsystem', 'CRM' )

# Define your sub system connection parameters here.
CRM_WSDL_FILE_URL = "http://CRMservername/CRMinstallname/eWare.dll/webservice/webservice.wsdl"    
CRM_USER          = "admin"
CRM_PASSWORD      = ""
CRM_NAMESPACE     = "http://tempuri.org/type"

#----------------------------
# SageProcess Class

# To use this class:
#
# 1) Create a SageProcess subclass and define the method 
#    body(). 
# 2) Instanitate an instance of the subclass, passing a
#    SageSubsystem enumeration, e.g. SageSubsystem.CRM.
# 3) Invoke the run() method of the process instance.
#    This will in turn invoke body() to execute your 
#    custom actions.
#
# To access the sage web services, use the "sage" member of 
# a SageProcess instance. For help using Sage web service
# objects see: 
# https://community.sagecrm.com/developerhelp/default.htm
#
# You may also invoke the sageHelp() method of a SageProcess 
# instance to view the top level web service object members. 
# Or, recordHelp( sageRecord ) to view the members of the 
# various record objects returned by the web services.
#
#----------------------------
class SageProcess():

    # Construction & service connection methods
    #----------------------------

    def __init__( self, subsystem, verbose=False ):
        """
        @param subsystem: The Sage subsystem on which to run the process. Ex. SageSubsystem.CRM
        @param verbose: If True, details of the SOAP exchange are displayed.
        """        
        self.subsystem = subsystem
        self.verbose = verbose        
        if self.subsystem == SageSubsystem.CRM :
            self.wsdl      = CRM_WSDL_FILE_URL
            self.namespace = CRM_NAMESPACE
            self.username  = CRM_USER
            self.password  = CRM_PASSWORD
        else :
            self.abort( "Unknown subsystem specified!" )   
        self.sessionId = None                    
        self.connect()

    def connect( self ) :               
        try :
            self.sage = WSDL.Proxy( self.wsdl, namespace=self.namespace )            
        except :
            self.abort( "WSDL failure. This is may be caused by access settings. File url: " + CRM_WSDL_FILE_URL )                
        if self.verbose : "Connected to web service."
        self.soapProxy = self.sage.soapproxy        
        if self.verbose : self.sageDebug()

    # Core process methods
    #----------------------------        

    def run( self ) :        
        if not self.logOn( self.username, self.password ) : 
            self.abort( "Log On failed!" )    
        else :
            if self.verbose : 
                print "Logged On. Session Id: " + str( self.sessionId )            
        self.appendSessionHeader()               
        self.body()
        if self.logOff() : 
            if self.verbose : print "Logged Off."

    def logOn( self, username, password ) : 
        try : self.sessionId = self.sage.logon( username, password ).sessionid
        except Exception as e: 
            self.abortOnException( "Log On failure.\n(You may need to enable forced logins.)", e )
        return (self.sessionId is not None)

    def appendSessionHeader( self ) : 
        self.soapProxy = self.soapProxy._sa( "urn:sessionid" )
        soapHeader = soapTypes.headerType()
        soapHeader.SessionHeader = soapTypes.structType( None, "SessionHeader" )
        soapHeader.SessionHeader.sessionId = soapTypes.stringType( self.sessionId )
        self.soapProxy = self.soapProxy._hd( soapHeader )
        self.sage.soapproxy = self.soapProxy

    def body( self ) : 
        """
        You should override this method when you subclass SageProcess. 
        It will be called after logging on, and will be followed by logging off.
        Use self.sage to access the system from within this method.
        """

    def logOff( self ) : 
        success = False
        try : success = self.sage.logoff( self.sessionId )
        except Exception as e: self.abortOnException( "Log off failure.", e )   
        return success

    # Helper methods
    #----------------------------   

    # Immediately exit the program with an indication of success
    def quit( self, msg=None ) :
        if msg is not None: print msg
        import os
        os._exit( 0 )      

    # Immediately exit the program with an error
    def abort( self, msg=None, errorCode=1 ) :        
        if msg is not None: print msg
        print "Process terminated..."
        import os
        os._exit( errorCode )      

    # Immediately exit the program with an Exception error
    def abortOnException( self, e, msg=None, errorCode=1 ) :
        if msg is not None: print msg
        print ""
        print e 
        print ""
        self.abort( None, errorCode )      

    def sageDebug( self, enable=True ) : 
        if enable : self.soapProxy.config.debug = 1
        else :      self.soapProxy.config.debug = 0       

    def sageHelp( self ) : 
        print "\nSage web service methods:\n"        
        self.sage.show_methods()

    def recordHelp( self, record, typeDescr=None ) :         
        if record is None : return
        print ""        
        description = "record object members:\n"
        if typeDescr is not None : 
            description = typeDescr + " " + description
        print description
        print dir( record )
        print ""

그런 다음이 클래스에 클라이언트를 추가하십시오. 다음은 Fetch_company_data_example.py라는 예입니다.

#----------------------------
#
#  fetch_company_data_example.py
#
#----------------------------

from pySage import SageProcess, SageSubsystem

def main() :

    # Get process parameters from the command line
    import sys
    try :
        companyId = sys.argv[1]
    except : 
        abort( "Usage: " + sys.argv[0] + " companyId [-v] [--verbose]" )       
    verbose = False
    try :
        if ( sys.argv[2] == "-v" or 
             sys.argv[2] == "--verbose" ) :
            verbose = True
    except : pass

    # Create & run the custom Sage process
    process = FetchCompanyDataProcess( companyId, verbose )
    process.run()

class FetchCompanyDataProcess( SageProcess ):

    def __init__( self, companyId, verbose ):
        SageProcess.__init__( self, SageSubsystem.CRM, verbose )
        self.companyId = companyId

    def body( self ):   

        # Fetch the company record (exiting if no data is returned)
        companyRecord = self.getCompanyRecord()
        if companyRecord is None: self.quit( "\nNo records found.\n" )                

        # Uncomment for development help...
        #if self.verbose : self.recordHelp( companyRecord, "Company" )        
        #if self.verbose : self.recordHelp( companyRecord.address.records, "Address" )        

        # Print some of the company info 
        print "" 
        print "Company Id: " + self.companyId
        print "Name: " + companyRecord.name
        print "Location: " + self.getCompanyLocation( companyRecord )
        print ""

    def getCompanyRecord( self ) :     
        try : 
            queryentity = self.sage.queryentity( self.companyId, "company" )
        except Exception as e: 
            self.abortOnException( "Get Company Record failure.", e )
        try : return queryentity.records
        except : return None 

    def getCompanyLocation( self, companyRecord ) :     
        try : 
            return (companyRecord.address.records.city + ", " +
                    companyRecord.address.records.state)
        except : return ""

# Entry point        
if __name__ == '__main__' : main()
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top