2

I'm trying to login to SAPGUI with Python in order to create a script to run a transaction automatically and I'm running into an issue. Whenever I try to login I get a <class 'pywintypes.com_error'> error. I'm not sure why I'm getting this error. This is my first time trying to navigate into SAP GUI so I'm not sure if I am missing an important line to establish a successful logon or not.

We've utilized VBA previously but my coworkers have expressed interest into possibly moving our automation scripts from Excel to Python and since I'm the most experience with Python I've been tasked in getting it working.

# Importing the Libraries
import win32com.client
import sys
import subprocess
import time


# This function will Login to SAP from the SAP Logon window

def saplogin():

    try:

        path = r"C:\Program Files (x86)\SAP\FrontEnd\SAPgui\saplogon.exe"
        subprocess.Popen(path)
        time.sleep(10)


        SapGuiAuto = win32com.client.GetObject("SAPGUI")
        if not type(SapGuiAuto) == win32com.client.CDispatch:
            return

        application = SapGuiAuto.GetScriptingEngine
        if not type(application) == win32com.client.CDispatch:
            SapGuiAuto = None
            return

        connection = application.Children(0)
        if not type(connection) == win32com.client.CDispatch:
            application = None
            SapGuiAuto = None
            return

        session = connection.Children(1)
        if not type(session) == win32com.client.CDispatch:
            connection = None
            application = None
            SapGuiAuto = None
            return

        session.findById("wnd[0]/usr/txtRSYST-BNAME").text = "USER"
        session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = "PASS"
        session.findById("wnd[0]").sendVKey(0)

    except:
        print(sys.exc_info()[0])

    finally:
        session = None
        connection = None
        application = None
        SapGuiAuto = None


saplogin()

2 Answers 2

3

Probably I'll answer more than one question. I assume that people automate SAP for long repeatable operations. Anyway the information below will be useful. Tested on SAP Client 7.20 and 7.50, Python 3.8.3.

First, you may use a config.py:

import os  # for path join

SAP_SID = 'SID'
SAP_MANDANT = '1000'
SAP_USER = 'login'
SAP_PASS = 'secret'
SAP_EXE = "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\sapshcut.exe"

# minimize SAP window, enable it after debugging is completed; unfortunately small windows still appear with this setting
ICONIFY = False

# screenshots for debug and visual logging
SCR_ERR = os.path.join('path', 'err_screen.png')

Second, the main script, which performs a connection, then opens a transations:

import config
import pyautogui as pya  # for screenshots
import time  # for count seconds for approx. measuring
import subprocess
import win32com.client
from win32gui import GetWindowText, GetForegroundWindow


def saplogin():
    try:
        # 1.1. Connect to SAP
        subprocess.check_call([config.SAP_EXE,
                               '-user=%s' % config.SAP_USER,
                               '-pw=%s' % config.SAP_PASS,
                               '-system=%s' % config.SAP_SID,
                               '-client=%s' % config.SAP_MANDANT])

        time.sleep(10)  # need to ensure SAP created a session

        # Get session
        sap_gui_auto = win32com.client.GetObject('SAPGUI').GetScriptingEngine
        session = sap_gui_auto.findById("con[0]/ses[0]")  # 1 - to run the second session comment this line and uncomment the next, with con[1] and so on; probably it may work with a param stored in config
        # session = sap_gui_auto.findById("con[1]/ses[0]")  # 2
        # session = sap_gui_auto.findById("con[2]/ses[0]")  # 3
        # session = sap_gui_auto.findById("con[3]/ses[0]")  # 4

        # 1.2. Check if dialog window appears
        if session.children.count > 1:
            try:
                # 1.2.1 License window (this code was written for different PCs with the same ses[0]; 
                # to run this code on the same machine it shoild be modified by adding a check for ses[1] and so on)
                # Open new session if the title equals to <your title>
                if (GetWindowText(GetForegroundWindow())) == "<Информация по лицензии при многократной регистрации>":
                    print("Title: %s" % session.children(1).text)  # you may use this instead of GetWindowText in the line above
                    
                    # Choose an option to create additional session
                    try:
                        session.findById("wnd[1]/usr/radMULTI_LOGON_OPT2").select()
                        session.findById("wnd[1]/usr/radMULTI_LOGON_OPT2").setFocus()
                        session.findById("wnd[0]").sendVKey(0)

                    except Exception as ex:
                        print("Cannot perform an operation (%s)" % ex)
                        pya.screenshot(config.SCR_ERR)
                        exit(1)

                time.sleep(1)  # for case if new dialog window appears

                try:
                    # Now we are about to be logged. Often at this moment the system message is shown 
                    if session.children(1).text == "<Системные сообщения>":  # replace to your text
                        print("Title: %s" % session.children(1).text)
                        # in my case this window always has two lines of text; you may safely delete these two lines of code
                        print("%s | %s" % (session.findById("wnd[1]/usr/lbl[4,1]").text,
                                                       session.findById("wnd[1]/usr/lbl[17,1]").text))
                        print("%s | %s" % (session.findById("wnd[1]/usr/lbl[4,3]").text,
                                                       session.findById("wnd[1]/usr/lbl[17,3]").text))
                        
                        print("The window is closed '%s', please wait..." % session.children(1).text)
                        session.findById("wnd[1]").sendVKey(0)
                    else:
                        # Exit if the window has unknown title
                        print("Title: %s. Exit." % session.children(1).text)
                        pya.screenshot(config.SCR_ERR)
                        exit(1)

                except Exception as ex:
                    # Exit for unknown window
                    print("Unknown window: %s. Exit (%s)" % (session.children(1).text, ex))
                    pya.screenshot(config.SCR_ERR)
                    exit(1)

            except Exception as ex:
                # Finally, exit for unknown reason
                print("Unknown error: %s. Exit (%s)" % (session.children(1).text, ex))
                pya.screenshot(config.SCR_ERR)
                exit(1)

        print("Logged to SAP.")
        return session

    except Exception as ex:
        print("Error. Cannot create session. Exit (%s)" % ex)
        pya.screenshot(config.SCR_ERR)
        exit(1)


def export_npp(session, params):
    # 2.1. Start counter (for those who cares about statistics and measuring)
    start = time.time()

    if config.ICONIFY:
        # minimize main window
        session.findById("wnd[0]").iconify()
    else:
        # or resize it
        session.findById("wnd[0]").resizeWorkingPane(84, 40, 0)

    # 2.2. Open transation
    session.findById("wnd[0]/tbar[0]/okcd").text = 'transaction'
    session.findById("wnd[0]").sendVKey(0)

    """
    startx = time.time()
    'doing some repeatable stuff'
    finish = time.time()
    total_time = finish - startx
    print("Time %02d seconds added to dict" % total_time)
    """
    total_finish = time.time()
    total_time = total_finish - start
    print("Total: %02d seconds" % total_time)


# Begin, start session
ses = saplogin()

# Use params of session to use it in transaction 'export_npp' and so on
npp = export_npp(ses, params)
Sign up to request clarification or add additional context in comments.

Comments

2

Answering to your question about login automation, it is done like this:

import subprocess
subprocess.check_call(['C:\Program Files (x86)\SAP\FrontEnd\SAPgui\\sapshcut.exe', '-system=DCG210', '-client=100', '-user=USERNAME', '-pw=PASSWORD'])

where DG210 - name of SAP system already setup in SAPGui

6 Comments

If possible, do you know how after I log in I can run a transaction? so if I have a transaction called dd_01 how would I run that after logging in? @Suncatcher
AFAIK, the only way is gui scripting like you tried, it is described here, but it is buggy and undebuggable. The better way is to find equivalent BAPI for this transaction and to use PyRFC to execute it.
Dang, How would I find out the equivalent BAPI of my transaction(s)? I might try gui-scripting again but I'm not sure where to start w/ finding a BAPI.
what is dd_01? i didn't find it among the standard transactions. What SAP module do you run?
dd_01 was an example, I'm not entirely sure what module we run as no one really knows much about SAP on my team (me included) and I've had to learn a lot about it via 2nd hand knowledge and trial and error. The transaction we normally use is zc_rtng
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.