栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Python

【SAP自动化】(1)自动登录

Python 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【SAP自动化】(1)自动登录

点下面,不迷路
  • 前言
  • 实用函数
  • 总结

前言

最近,接触的项目需要自动化操作SAP,所以对SAP的自动化脚本进行调查了。整理了一些有用函,用于创建SAP Session和自动化登录。

实用函数

项目中使用的是Python语言,如果需要其他语言的版本可参考这里的函数。

import logging
import time
from contextlib import contextmanager

import pythoncom
import pywintypes
import win32com.client as client

import ZZK1LFI1122P0008A

LANGUAGES_WINDOW_TITLES = {
    "EN": {
        "MULTIPLE_LOGONS": "License Information for Multiple Logons",
        "COPYRIGHT": "Copyright"
    },
    "ZH": {
        "MULTIPLE_LOGONS": "多次登录许可证信息",
        "Copyright": "Copyright"
    },
    "JA": {
        "MULTIPLE_LOGONS": "多重ログオンに関するライセンス情報",
        "COPYRIGHT": "Copyright"
    }
}

LOGGER = logging.getLogger(__name__)


def create_sap_session(description, *, mandt="", name="", password="", language="EN"):
    """
    创建一个新的SAP客户端窗口。

    :param description: 登录描述字符串
    :param mandt: 集团
    :param name: 用户名
    :param password: 密码
    :param language: 客户端语言
    :return: 返回SAP GuiSession对象
    """
    try:
        sap_gui_auto = client.GetObject("SAPGUI")
    except pywintypes.com_error as _:
        raise RuntimeError("检测到SAP客户端没有启动, 请启动SAP客户端后重试。")
    application = sap_gui_auto.GetScriptingEngine
    connection = application.OpenConnection(description)
    # 使用第一个未登录的Session创建一个登录的Session
    session = connection.Sessions(0)
    session.findById("wnd[0]/usr/txtRSYST-MANDT").text = mandt
    session.findById("wnd[0]/usr/txtRSYST-BNAME").text = name
    session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = password
    session.findById("wnd[0]/usr/txtRSYST-LANGU").text = language
    session.findById("wnd[0]").sendVKey(0)

    # 有模态窗口
    if session.Children.Count > 1:
        wnd1 = session.findById("wnd[1]")
        if wnd1.Text == LANGUAGES_WINDOW_TITLES[language]["MULTIPLE_LOGONS"]:
            # 多用户登录是的确认选择。
            session.findById("wnd[1]/usr/radMULTI_LOGON_OPT2").select()
            session.findById("wnd[1]/tbar[0]/btn[0]").press()

    # 有模态窗口
    if session.Children.Count > 1:
        wnd1 = session.findById("wnd[1]")
        if wnd1.Text == LANGUAGES_WINDOW_TITLES[language]["COPYRIGHT"]:
            session.findById("wnd[1]/tbar[0]/btn[0]").press()

    return session


def remove_sap_session(session):
    """
    关闭SAP客户端窗口。

    :param index: 客户端的索引
    """
    if session:
        connection = session.Parent
        # session.UnlockSessionUI()
        connection.CloseSession(session.Id)


def get_sap_session():
    """
    获取SAP操作Session。

    使用第一个连接的创建脚本执行的Session,如果Session的数据大于一个时,表示有脚本正在执行。
    如果是用户打开有多个Session或由于执行失败导致多个Session残留时,需手动关闭多余的Session。

    也可以提供接口,关闭多余的Session。

    这里一个Session就是一个SAP客户端窗口。
    :param index: 客户端的索引
    :return: 返回SAP GuiSession对象
    """
    try:
        sap_gui_auto = client.GetObject("SAPGUI")
    except pywintypes.com_error as _:
        raise RuntimeError("检测到SAP客户端没有启动, 请启动SAP客户端后重试。")
    application = sap_gui_auto.GetScriptingEngine

    # 连接数等于0时,表示没有用户登录SAP客户端
    # 即index对应的连接上没有用户登录。
    if application.Connections.Count < 1:
        session = None
    else:
        # 每个连接都仅返回第一个Session。
        session_count = application.Connections(0).Sessions.Count
        # 使用第一个Session创建一个新的Session,用于执行脚本
        # 如果Session数量大于一则表明有脚本正在执行(后面在尝试是否可以开更多的脚本)
        if session_count > 1:
            # session = application.Connections(index).Sessions(1)
            # timeout = 3
            # while timeout > 0 and session.Busy:
            #     print("The session is Busy.")
            #     time.sleep(0.5)
            #     timeout -= 0.5
            # if timeout > 0:
            #     pass
            # else:
            raise ValueError("有脚本正在执行,请稍后重试。n如果确认没有脚本在执行,请关闭多余的窗口后重试。")
        else:
            application.Connections(0).Sessions(0).CreateSession()
            # 等待新创建的Session可以访问。
            # 设置超时时间
            timeout = 3
            while timeout > 0 and application.Connections(0).Sessions.Count <= 1:
                time.sleep(0.1)
                timeout -= 0.1
            if timeout > 0:
                session = application.Connections(0).Sessions(1)
            else:
                TimeoutError("创建执行脚本的Session失败")
    return session


@contextmanager
def sap_session_context():
    session = None
    try:
        pythoncom.CoInitialize()
        session = get_sap_session()
        if session is None:
            # 未登录是自动登录
            from login_info import LOGIN_INFO
            session = create_sap_session("RPA-SAP", **LOGIN_INFO)
        # session = get_sap_session()
        # session.SuppressBackendPopups = True # 没有这个属性
        # 最大化新创建的Session的主窗口
        # session.LockSessionUI() # 这个不是一直锁住整个Session,没什么作用。
        session.ActiveWindow.Maximize()

        yield session
    # 捕获异常可以明确判断出错原因
    # except Exception as ex:
    #     print(ex)
    finally:
        if session:
            connection = session.Parent
            # session.UnlockSessionUI()
            connection.CloseSession(session.Id)
        pythoncom.CoUninitialize()


@contextmanager
def sap_transaction_context(session, transaction_code):
    try:
        session.StartTransaction(transaction_code)
        yield
    finally:
        session.EndTransaction()


def sap_executor(handler):
    def wrapper(*args, **kwargs):
        with sap_session_context() as session:
            return handler(session, *args, ** kwargs)
    return wrapper


@sap_executor
def do_sap_task1(session, *args, **kwargs):
    result = 0
    # t1
    ZZK1LFI1122P0008A(*args, **kwargs).get_data_with_context(session)
    # ... 其他事务操作
    return result

# 下面时sap_executor装饰器的使用示例
# 这里比较奇怪的是函数(do_sap_task1)声明有session参数,但是在调用时不能传递,
# 其实也没有可用的session参数值。


def do_task1(*args, **kwargs):
    do_sap_task1(*args, **kwargs)


def do_task2(*args, **kwargs):
    @sap_executor
    def executor(session, *args, **kwargs):
        result = 0
        # t2
        ZZK1LFI1122P0008A(*args, **kwargs).get_data_with_context(session)
        # ... 其他事务操作
        return result
    return executor(*args, **kwargs)


@sap_executor
def do_login(session):
    pass


if __name__ == '__main__':
    # do_task1()
    # do_task2()
    do_login()
总结

使用上的函数方便测试和其他SAP脚本的作成。

仅供参考,如有帮助不胜荣幸,请关注,点赞。
如需转载请注明出处。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/976824.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号