質問

私は自分のWebサービス・インターフェースを使用してセイジCRMのためのPythonの消費者を記述しようとしています。私は(それまで結婚しない、Ubuntuでインストールが簡単だったので一緒に行きました)のPython SOAPライブラリとしてSOAPpyを使用しています。

プロキシを使用してWSDLを取得するために管理及びセイジ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'}

今、私は、データを照会するセイジ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を使用して、ヘッダーにこれを追加しないためにどのように任意のアイデア?

任意のポインタを大幅に理解されるであろう。

役に立ちましたか?

解決

まず、ちょうど他の石鹸ライブラリ対SOAPpyにコメントを投稿... SOAPpyは、伝統的に複雑なデータ構造をサポートしていませんでした、使いやすいライブラリーとなっています。それはあなたのケースのために働くのであれば、あなたはオフに優れています。 WSDLで、より複雑なデータ構造のためには、ZSIを移動する必要があると思います。

とにかく、SourceForgeのプロジェクトのドキュメントのリンクが壊れているようですので、私はちょうどいくつかのマイナーな書式設定の変更で、ここでヘッダー文書を貼り付け+カットます:

使用ヘッダ

SOAPpyは、SOAPメッセージのヘッダのデータを保持するためのヘッダー・クラスを有しています。 各ヘッダのインスタンスは、mustUnderstand属性を取得/設定するためのメソッドを持っており、 俳優の属性を取得/設定します。

メソッド 各サーバーメソッドができるように、

SOAPpyもSOAPContextクラスを有しています それは接続するクライアントのコンテキストを取得するように実装。 これは一般的なSOAP情報と接続情報の両方を含んでいる(参照します 例えば以下)。

クライアントの例

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へのmustUnderstandセットでこのクライアントに有効なヘッダーを構築します そして、このヘッダとSOAPを送信します。

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へのmustUnderstandを設定し、 サーバは、おそらく送信する前に理解していますメッセージの。

他のヒント

は、あまりにもこれを考え出すています。私はこのコアはいえ行っているので、これはこれを必要とする他の誰のために物事をスピードアップするはず!私は他のセージ・サブシステムが同じように動作すると仮定しています(しかし、私はまだ知らない)ので、私はその可能性を考慮してみました。

まず、あなたは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